]> git.vomp.tv Git - vompclient.git/blob - vdr.cc
EPG & vvideolive clean up (inc new bugs!)
[vompclient.git] / vdr.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "vdr.h"
22
23 VDR* VDR::instance = NULL;
24
25 VDR::VDR()
26 {
27   if (instance) return;
28   instance = this;
29   initted = 0;
30   findingServer = 0;
31   tcp = NULL;
32   pthread_mutex_init(&mutex, NULL);
33   packetLength = 0;
34   packetPos = 0;
35   packet = NULL;
36   connected = false;
37 }
38
39 VDR::~VDR()
40 {
41   instance = NULL;
42   if (initted) shutdown();
43 }
44
45 VDR* VDR::getInstance()
46 {
47   return instance;
48 }
49
50 int VDR::init(int tport)
51 {
52   if (initted) return 0;
53   initted = 1;
54   port = tport;
55   logger = Log::getInstance();
56   return 1;
57 }
58
59 int VDR::shutdown()
60 {
61   if (!initted) return 0;
62   initted = 0;
63   disconnect();
64   return 1;
65 }
66
67 void VDR::findServers(vector<char*>& serverIPs)
68 {
69   findingServer = 1;
70   char* message = "VOMP CLIENT";
71   DatagramSocket ds(port);
72
73   int haveAtLeastOne = 0;
74   char* newIP;
75   int retval;
76   int waitType = 1;
77   while(findingServer)
78   {
79     if (waitType == 1)
80     {
81       logger->log("VDR", Log::NOTICE, "Broadcasting for server");
82       ds.send("255.255.255.255", 3024, message, strlen(message));
83     }
84     retval = ds.waitforMessage(waitType);
85
86     if (retval == 2) // we got a reply
87     {
88       if (strcmp(ds.getData(), "VOMP SERVER")) // echo.....
89       {
90         waitType = 2;
91       }
92       else
93       {
94         newIP = new char[16];
95         strcpy(newIP, ds.getFromIPA());
96         serverIPs.push_back(newIP);
97         waitType = 2;
98         haveAtLeastOne = 1;
99       }
100     }
101     else
102     {
103       if (haveAtLeastOne) break;
104       waitType = 1;
105     }
106   }
107 }
108
109 void VDR::cancelFindingServer()
110 {
111   findingServer = 0;
112 }
113
114 void VDR::setServerIP(char* newIP)
115 {
116   strcpy(serverIP, newIP);
117 }
118
119 int VDR::connect()
120 {
121   if (tcp) delete tcp;
122   tcp = new TCP();
123   if (tcp->connectTo(serverIP, 3024))
124   {
125     connected = true;
126     return 1;
127   }
128   else
129   {
130     return 0;
131   }
132 }
133
134 void VDR::disconnect()
135 {
136   if (tcp) delete tcp;
137   tcp = NULL;
138   connected = false;
139   Log::getInstance()->log("VDR", Log::DEBUG, "Disconnect");
140 }
141
142 ///////////////////////////////////////////////////////
143
144 int VDR::getPacket()
145 {
146   packet = (UCHAR*)tcp->receivePacket();
147   if (!packet) return 0;
148   packetLength = tcp->getDataLength();
149   return 1;
150 }
151
152 void VDR::freePacket()
153 {
154   // Must be called if getPacket return 1, except in getBlock
155   packetLength = 0;
156   packetPos = 0;
157   free(packet);
158   packet = NULL;
159 }
160
161 int VDR::serverError()
162 {
163   if ((packetPos == 0) && (packetLength == 4) && !ntohl(*(ULONG*)packet)) return 1;
164   else return 0;
165 }
166
167 char* VDR::extractString()
168 {
169   if (serverError()) return NULL;
170
171   int length = strlen((char*)&packet[packetPos]);
172   if ((packetPos + length) > packetLength) return NULL;
173   char* str = new char[length + 1];
174   strcpy(str, (char*)&packet[packetPos]);
175   packetPos += length + 1;
176   return str;
177 }
178
179 ULONG VDR::extractULONG()
180 {
181   if ((packetPos + sizeof(ULONG)) > packetLength) return 0;
182   ULONG ul = ntohl(*(ULONG*)&packet[packetPos]);
183   packetPos += sizeof(ULONG);
184   return ul;
185 }
186
187 ULLONG VDR::extractULLONG()
188 {
189   if ((packetPos + sizeof(ULLONG)) > packetLength) return 0;
190   ULLONG ull = ntohll(*(ULLONG*)&packet[packetPos]);
191   packetPos += sizeof(ULLONG);
192   return ull;
193 }
194
195 long VDR::extractLONG()
196 {
197   if ((packetPos + sizeof(long)) > packetLength) return 0;
198   long l = ntohl(*(long*)&packet[packetPos]);
199   packetPos += sizeof(long);
200   return l;
201 }
202
203 /////////////////////////////////////////////////////////////////////////////
204
205 int VDR::doLogin()
206 {
207   if (!connected) return 0;
208
209   UCHAR buffer[8];
210
211   *(unsigned long*)&buffer[0] = htonl(4);
212   *(unsigned long*)&buffer[4] = htonl(VDR_LOGIN);
213
214   pthread_mutex_lock(&mutex);
215   int a = tcp->sendPacket(buffer, 8);
216   if (a != 8)
217   {
218     pthread_mutex_unlock(&mutex);
219     return 0;
220   }
221
222   // reply
223
224   if (!getPacket())
225   {
226     pthread_mutex_unlock(&mutex);
227     return 0;
228   }
229
230   ULONG vdrTime = extractULONG();
231   logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
232   long vdrTimeOffset = extractLONG();
233   logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
234
235   freePacket();
236   pthread_mutex_unlock(&mutex);
237
238
239   struct timespec currentTime;
240   currentTime.tv_sec = vdrTime;
241   currentTime.tv_nsec = 0;
242   int b = clock_settime(CLOCK_REALTIME, &currentTime);
243
244   logger->log("VDR", Log::DEBUG, "set clock = %u", b);
245
246   // now make a TZ variable and set it
247   char sign;
248   int hours;
249   int minutes;
250   if (vdrTimeOffset > 0) sign = '-';
251   else sign = '+';
252
253   vdrTimeOffset = abs(vdrTimeOffset);
254
255   hours = (int)vdrTimeOffset / 3600;
256   minutes = vdrTimeOffset % 3600;
257
258   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
259
260   minutes = (int)minutes / 60;
261
262   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
263
264   char newTZ[30];
265   sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
266   setenv("TZ", newTZ, 1);
267
268   logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
269
270   return 1;
271 }
272
273 Directory* VDR::getRecordingsList()
274 {
275   if (!connected) return 0;
276
277   UCHAR buffer[8];
278
279   *(unsigned long*)&buffer[0] = htonl(4);
280   *(unsigned long*)&buffer[4] = htonl(VDR_GETRECORDINGLIST);
281
282   pthread_mutex_lock(&mutex);
283   int a = tcp->sendPacket(buffer, 8);
284   if (a != 8)
285   {
286     pthread_mutex_unlock(&mutex);
287     return NULL;
288   }
289
290   // reply
291
292   if (!getPacket())
293   {
294     pthread_mutex_unlock(&mutex);
295     return NULL;
296   }
297
298   Directory* recDir = new Directory();
299   recDir->setName("/");
300   recDir->isRoot = 1;
301
302   Directory::totalSpace = extractULONG();
303   Directory::freeSpace = extractULONG();
304   Directory::usedPercent = extractULONG();
305
306   char* string;
307
308   while (packetPos < packetLength)
309   {
310     Recording* rec = new Recording();
311
312     rec->start = extractULONG();
313
314     string = extractString();
315     rec->setName(string);
316     delete[] string;
317
318     rec->fileName = extractString();
319
320     if(rec->isInDir())
321     {
322       char* dirName = rec->getDirName();
323
324       Directory* d = recDir->getDirByName(dirName);
325       if (!d)
326       {
327         d = new Directory();
328         d->setName(dirName);
329         Log::getInstance()->log("VDR", Log::DEBUG, "Added a new directory = %s", d->name);
330         recDir->dirList.push_back(d);
331       }
332
333       d->recList.push_back(rec);
334     }
335     else
336     {
337       recDir->recList.push_back(rec);
338     }
339
340     Log::getInstance()->log("VDR", Log::DEBUG, "%s", rec->fileName);
341   }
342
343   freePacket();
344   pthread_mutex_unlock(&mutex);
345
346   return recDir;
347 }
348
349 int VDR::deleteRecording(char* fileName)
350 {
351   if (!connected) return 0;
352
353   unsigned long totalLength = 8 + strlen(fileName) + 1;
354   UCHAR buffer[totalLength];
355
356   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
357   *(unsigned long*)&buffer[4] = htonl(VDR_DELETERECORDING);
358   strcpy((char*)&buffer[8], fileName);
359
360   pthread_mutex_lock(&mutex);
361   unsigned int a = tcp->sendPacket(buffer, totalLength);
362   if (a != totalLength)
363   {
364     pthread_mutex_unlock(&mutex);
365     return 0;
366   }
367
368   if (!getPacket())
369   {
370     pthread_mutex_unlock(&mutex);
371     return 0;
372   }
373
374   int toReturn = (int)extractULONG();
375   freePacket();
376   pthread_mutex_unlock(&mutex);
377
378   return toReturn;
379 }
380
381 char* VDR::getRecordingSummary(char* fileName)
382 {
383   if (!connected) return 0;
384
385   unsigned long totalLength = 8 + strlen(fileName) + 1;
386   UCHAR buffer[totalLength];
387
388   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
389   *(unsigned long*)&buffer[4] = htonl(VDR_GETSUMMARY);
390   strcpy((char*)&buffer[8], fileName);
391
392   pthread_mutex_lock(&mutex);
393   unsigned int a = tcp->sendPacket(buffer, totalLength);
394   if (a != totalLength)
395   {
396     pthread_mutex_unlock(&mutex);
397     return NULL;
398   }
399
400   if (!getPacket())
401   {
402     pthread_mutex_unlock(&mutex);
403     return NULL;
404   }
405   char* toReturn = extractString();
406   freePacket();
407   pthread_mutex_unlock(&mutex);
408
409   return toReturn;
410 }
411
412 ChannelList* VDR::getChannelsList(ULONG type)
413 {
414   if (!connected) return 0;
415
416   UCHAR buffer[8];
417
418   *(unsigned long*)&buffer[0] = htonl(4);
419   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELLIST);
420
421   pthread_mutex_lock(&mutex);
422   int a = tcp->sendPacket(buffer, 8);
423   if (a != 8)
424   {
425     pthread_mutex_unlock(&mutex);
426     return NULL;
427   }
428
429   // reply
430
431   if (!getPacket())
432   {
433     pthread_mutex_unlock(&mutex);
434     return NULL;
435   }
436
437   ChannelList* chanList = new ChannelList();
438
439   while (packetPos < packetLength)
440   {
441     Channel* chan = new Channel();
442     chan->number = extractULONG();
443     chan->type = extractULONG();
444     chan->name = extractString();
445
446     if (chan->type == type)
447     {
448       chanList->push_back(chan);
449       Log::getInstance()->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
450     }
451     else
452     {
453       delete chan;
454     }
455   }
456
457   freePacket();
458   pthread_mutex_unlock(&mutex);
459
460   return chanList;
461 }
462
463 int VDR::streamChannel(ULONG number)
464 {
465   if (!connected) return 0;
466
467   UCHAR buffer[12];
468
469   *(unsigned long*)&buffer[0] = htonl(8);
470   *(unsigned long*)&buffer[4] = htonl(VDR_STREAMCHANNEL);
471   *(unsigned long*)&buffer[8] = htonl(number);
472
473   pthread_mutex_lock(&mutex);
474   int a = tcp->sendPacket(buffer, 12);
475
476   if (a != 12)
477   {
478     pthread_mutex_unlock(&mutex);
479     return 0;
480   }
481
482   if (!getPacket())
483   {
484     pthread_mutex_unlock(&mutex);
485     return 0;
486   }
487
488   int toReturn = (int)extractULONG();
489   freePacket();
490   pthread_mutex_unlock(&mutex);
491
492   return toReturn;
493 }
494
495 int VDR::stopStreaming()
496 {
497   if (!connected) return 0;
498
499   UCHAR buffer[8];
500
501   *(unsigned long*)&buffer[0] = htonl(4);
502   *(unsigned long*)&buffer[4] = htonl(VDR_STOPSTREAMING);
503
504   pthread_mutex_lock(&mutex);
505   int a = tcp->sendPacket(buffer, 8);
506
507   if (a != 8)
508   {
509     pthread_mutex_unlock(&mutex);
510     return 0;
511   }
512
513   if (!getPacket())
514   {
515     pthread_mutex_unlock(&mutex);
516     return 0;
517   }
518
519   int toReturn = (int)extractULONG();
520   freePacket();
521   pthread_mutex_unlock(&mutex);
522
523   return toReturn;
524 }
525
526 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
527 {
528   if (!connected) return 0;
529
530   UCHAR buffer[20];
531
532   *(unsigned long*)&buffer[0] = htonl(16);
533   *(unsigned long*)&buffer[4] = htonl(VDR_GETBLOCK);
534   *(ULLONG*)&buffer[8]        = htonll(position);
535   *(unsigned long*)&buffer[16] = htonl(maxAmount);
536
537   pthread_mutex_lock(&mutex);
538   int a = tcp->sendPacket(buffer, 20);
539   if (a != 20)
540   {
541     pthread_mutex_unlock(&mutex);
542     return NULL;
543   }
544
545   if (!getPacket())
546   {
547     pthread_mutex_unlock(&mutex);
548     return NULL;
549   }
550
551   UCHAR* toReturn = packet;
552   *amountReceived = packetLength;
553   // Manually clean up instead of running freePacket to keep the block
554   packet = NULL;
555   packetLength = 0;
556   packetPos = 0;
557   pthread_mutex_unlock(&mutex);
558
559   return toReturn;
560 }
561
562 ULLONG VDR::streamRecording(Recording* rec)
563 {
564   if (!connected) return 0;
565
566   unsigned long totalLength = 8 + strlen(rec->fileName) + 1;
567   UCHAR buffer[totalLength];
568
569   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
570   *(unsigned long*)&buffer[4] = htonl(VDR_STREAMRECORDING);
571   strcpy((char*)&buffer[8], rec->fileName);
572
573   pthread_mutex_lock(&mutex);
574   unsigned int a = tcp->sendPacket(buffer, totalLength);
575   if (a != totalLength)
576   {
577     pthread_mutex_unlock(&mutex);
578     return 0;
579   }
580
581   if (!getPacket())
582   {
583     pthread_mutex_unlock(&mutex);
584     return 0;
585   }
586
587   ULLONG recordingLength = extractULLONG();
588   freePacket();
589   pthread_mutex_unlock(&mutex);
590
591   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
592
593   return recordingLength;
594 }
595
596 ULLONG VDR::rescanRecording()
597 {
598   if (!connected) return 0;
599
600   unsigned long totalLength = 8;
601   UCHAR buffer[totalLength];
602
603   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
604   *(unsigned long*)&buffer[4] = htonl(VDR_RESCANRECORDING);
605
606   pthread_mutex_lock(&mutex);
607   unsigned int a = tcp->sendPacket(buffer, totalLength);
608   if (a != totalLength)
609   {
610     pthread_mutex_unlock(&mutex);
611     return 0;
612   }
613
614   if (!getPacket())
615   {
616     pthread_mutex_unlock(&mutex);
617     return 0;
618   }
619
620   ULLONG recordingLength = extractULLONG();
621   freePacket();
622   pthread_mutex_unlock(&mutex);
623
624   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
625
626   return recordingLength;
627 }
628
629 EventList* VDR::getChannelSchedule(ULONG number)
630 {
631   time_t now;
632   time(&now);
633   return getChannelSchedule(number, now, 24 * 60 * 60);
634 }
635
636 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
637
638 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
639   if (!connected) return 0;
640
641   UCHAR buffer[20];
642
643   *(unsigned long*)&buffer[0] = htonl(16);
644   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE);
645   *(unsigned long*)&buffer[8] = htonl(number);
646   *(unsigned long*)&buffer[12] = htonl(start);
647   *(unsigned long*)&buffer[16] = htonl(duration);
648
649   pthread_mutex_lock(&mutex);
650   int a = tcp->sendPacket(buffer, 20);
651
652   if (a != 20)
653   {
654     pthread_mutex_unlock(&mutex);
655     return NULL;
656   }
657
658   if (!getPacket())
659   {
660     pthread_mutex_unlock(&mutex);
661     return NULL;
662   }
663
664   if (serverError())
665   {
666     freePacket();
667     pthread_mutex_unlock(&mutex);
668     return NULL;
669   }
670
671
672   EventList* eventList = new EventList();
673
674   while (packetPos < packetLength)
675   {
676     Event* event = new Event();
677     event->id = extractULONG();
678     event->time = extractULONG();
679     event->duration = extractULONG();
680     event->title = extractString();
681     event->subtitle = extractString();
682     event->description = extractString();
683     eventList->push_back(event);
684 //    eventList->next();
685   }
686
687   freePacket();
688   pthread_mutex_unlock(&mutex);
689
690   Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
691
692
693   // debug
694 /*
695   Log* l = Log::getInstance();
696
697
698   l->log("VDR", Log::DEBUG, "datalength = %i count = %i", dataLength, count);
699
700   Event* currentEvent;
701   for(eventList->reset(); !eventList->eol(); eventList->next())
702   {
703     currentEvent = (Event*)eventList->getCurrent();
704     l->log("VDR", Log::DEBUG, "%lu %lu %lu %s %s %s", currentEvent->id, currentEvent->time, currentEvent->duration, currentEvent->title, currentEvent->subtitle, currentEvent->description);
705   }
706 */
707
708   return eventList;
709 }
710
711 ULLONG VDR::getResumePoint(char* fileName)
712 {
713   if (!connected) return 0;
714
715   char* resumeString = configLoad("ResumeData", fileName);
716   if (!resumeString) return 0;
717
718   ULLONG toReturn = strtoull(resumeString, NULL, 10);
719   delete[] resumeString;
720   return toReturn;
721 }
722
723 int VDR::configSave(char* section, char* key, const char* value)
724 {
725   if (!connected) return 0;
726
727   ULONG totalLength = 8 + strlen(section) + strlen(key) + strlen(value) + 3; // 8 for headers, 3 for nulls
728   UCHAR buffer[totalLength];
729
730   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
731   *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGSAVE);
732
733   int position = 8;
734   strcpy((char*)&buffer[position], section);
735   position += strlen(section) + 1;
736   strcpy((char*)&buffer[position], key);
737   position += strlen(key) + 1;
738   strcpy((char*)&buffer[position], value);
739
740   pthread_mutex_lock(&mutex);
741   unsigned int a = tcp->sendPacket(buffer, totalLength);
742   if (a != totalLength)
743   {
744     pthread_mutex_unlock(&mutex);
745     return 0;
746   }
747
748   if (!getPacket())
749   {
750     pthread_mutex_unlock(&mutex);
751     return 0;
752   }
753
754   int toReturn = (int)extractULONG();
755   freePacket();
756   pthread_mutex_unlock(&mutex);
757
758   return toReturn;
759 }
760
761 char* VDR::configLoad(char* section, char* key)
762 {
763   if (!connected) return 0;
764
765   ULONG totalLength = 8 + strlen(section) + strlen(key) + 2; // 8 for headers, 2 for nulls
766   UCHAR buffer[totalLength];
767
768   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
769   *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGLOAD);
770
771   int position = 8;
772   strcpy((char*)&buffer[position], section);
773   position += strlen(section) + 1;
774   strcpy((char*)&buffer[position], key);
775
776   pthread_mutex_lock(&mutex);
777   unsigned int a = tcp->sendPacket(buffer, totalLength);
778   if (a != totalLength)
779   {
780     pthread_mutex_unlock(&mutex);
781     return NULL;
782   }
783
784   if (!getPacket())
785   {
786     pthread_mutex_unlock(&mutex);
787     return NULL;
788   }
789   char* toReturn = extractString();
790   freePacket();
791   pthread_mutex_unlock(&mutex);
792
793   return toReturn;
794 }