]> git.vomp.tv Git - vompclient.git/blob - vdr.cc
Return to correct video mode after EPG. UP/DOWN trigger VLB
[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 printf("sent request\n");
514
515   if (!getPacket())
516   {
517     pthread_mutex_unlock(&mutex);
518     return 0;
519   }
520 printf("got reply\n");
521
522
523   int toReturn = (int)extractULONG();
524   freePacket();
525   pthread_mutex_unlock(&mutex);
526
527   return toReturn;
528 }
529
530 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
531 {
532   if (!connected) return 0;
533
534   UCHAR buffer[20];
535
536   *(unsigned long*)&buffer[0] = htonl(16);
537   *(unsigned long*)&buffer[4] = htonl(VDR_GETBLOCK);
538   *(ULLONG*)&buffer[8]        = htonll(position);
539   *(unsigned long*)&buffer[16] = htonl(maxAmount);
540
541   pthread_mutex_lock(&mutex);
542   int a = tcp->sendPacket(buffer, 20);
543   if (a != 20)
544   {
545     pthread_mutex_unlock(&mutex);
546     return NULL;
547   }
548
549   if (!getPacket())
550   {
551     pthread_mutex_unlock(&mutex);
552     return NULL;
553   }
554
555   UCHAR* toReturn = packet;
556   *amountReceived = packetLength;
557   // Manually clean up instead of running freePacket to keep the block
558   packet = NULL;
559   packetLength = 0;
560   packetPos = 0;
561   pthread_mutex_unlock(&mutex);
562
563   return toReturn;
564 }
565
566 ULLONG VDR::streamRecording(Recording* rec)
567 {
568   if (!connected) return 0;
569
570   unsigned long totalLength = 8 + strlen(rec->fileName) + 1;
571   UCHAR buffer[totalLength];
572
573   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
574   *(unsigned long*)&buffer[4] = htonl(VDR_STREAMRECORDING);
575   strcpy((char*)&buffer[8], rec->fileName);
576
577   pthread_mutex_lock(&mutex);
578   unsigned int a = tcp->sendPacket(buffer, totalLength);
579   if (a != totalLength)
580   {
581     pthread_mutex_unlock(&mutex);
582     return 0;
583   }
584
585   if (!getPacket())
586   {
587     pthread_mutex_unlock(&mutex);
588     return 0;
589   }
590
591   ULLONG recordingLength = extractULLONG();
592   freePacket();
593   pthread_mutex_unlock(&mutex);
594
595   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
596
597   return recordingLength;
598 }
599
600 ULLONG VDR::rescanRecording()
601 {
602   if (!connected) return 0;
603
604   unsigned long totalLength = 8;
605   UCHAR buffer[totalLength];
606
607   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
608   *(unsigned long*)&buffer[4] = htonl(VDR_RESCANRECORDING);
609
610   pthread_mutex_lock(&mutex);
611   unsigned int a = tcp->sendPacket(buffer, totalLength);
612   if (a != totalLength)
613   {
614     pthread_mutex_unlock(&mutex);
615     return 0;
616   }
617
618   if (!getPacket())
619   {
620     pthread_mutex_unlock(&mutex);
621     return 0;
622   }
623
624   ULLONG recordingLength = extractULLONG();
625   freePacket();
626   pthread_mutex_unlock(&mutex);
627
628   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
629
630   return recordingLength;
631 }
632
633 EventList* VDR::getChannelSchedule(ULONG number)
634 {
635   time_t now;
636   time(&now);
637   return getChannelSchedule(number, now, 24 * 60 * 60);
638 }
639
640 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
641 {
642 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
643   if (!connected) return 0;
644
645   UCHAR buffer[20];
646
647   *(unsigned long*)&buffer[0] = htonl(16);
648   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE);
649   *(unsigned long*)&buffer[8] = htonl(number);
650   *(unsigned long*)&buffer[12] = htonl(start);
651   *(unsigned long*)&buffer[16] = htonl(duration);
652
653   pthread_mutex_lock(&mutex);
654   int a = tcp->sendPacket(buffer, 20);
655
656   if (a != 20)
657   {
658     pthread_mutex_unlock(&mutex);
659     return NULL;
660   }
661
662   if (!getPacket())
663   {
664     pthread_mutex_unlock(&mutex);
665     return NULL;
666   }
667
668   if (serverError())
669   {
670     freePacket();
671     pthread_mutex_unlock(&mutex);
672     return NULL;
673   }
674
675
676   EventList* eventList = new EventList();
677
678   while (packetPos < packetLength)
679   {
680     Event* event = new Event();
681     event->id = extractULONG();
682     event->time = extractULONG();
683     event->duration = extractULONG();
684     event->title = extractString();
685     event->subtitle = extractString();
686     event->description = extractString();
687     eventList->push_back(event);
688 //    eventList->next();
689   }
690
691   freePacket();
692   pthread_mutex_unlock(&mutex);
693
694   Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
695
696
697   // debug
698 /*
699   Log* l = Log::getInstance();
700
701
702   l->log("VDR", Log::DEBUG, "datalength = %i count = %i", dataLength, count);
703
704   Event* currentEvent;
705   for(eventList->reset(); !eventList->eol(); eventList->next())
706   {
707     currentEvent = (Event*)eventList->getCurrent();
708     l->log("VDR", Log::DEBUG, "%lu %lu %lu %s %s %s", currentEvent->id, currentEvent->time, currentEvent->duration, currentEvent->title, currentEvent->subtitle, currentEvent->description);
709   }
710 */
711
712   return eventList;
713 }
714
715 ULLONG VDR::getResumePoint(char* fileName)
716 {
717   if (!connected) return 0;
718
719   char* resumeString = configLoad("ResumeData", fileName);
720   if (!resumeString) return 0;
721
722   ULLONG toReturn = strtoull(resumeString, NULL, 10);
723   delete[] resumeString;
724   return toReturn;
725 }
726
727 int VDR::configSave(char* section, char* key, const char* value)
728 {
729   if (!connected) return 0;
730
731   ULONG totalLength = 8 + strlen(section) + strlen(key) + strlen(value) + 3; // 8 for headers, 3 for nulls
732   UCHAR buffer[totalLength];
733
734   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
735   *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGSAVE);
736
737   int position = 8;
738   strcpy((char*)&buffer[position], section);
739   position += strlen(section) + 1;
740   strcpy((char*)&buffer[position], key);
741   position += strlen(key) + 1;
742   strcpy((char*)&buffer[position], value);
743
744   pthread_mutex_lock(&mutex);
745   unsigned int a = tcp->sendPacket(buffer, totalLength);
746   if (a != totalLength)
747   {
748     pthread_mutex_unlock(&mutex);
749     return 0;
750   }
751
752   if (!getPacket())
753   {
754     pthread_mutex_unlock(&mutex);
755     return 0;
756   }
757
758   int toReturn = (int)extractULONG();
759   freePacket();
760   pthread_mutex_unlock(&mutex);
761
762   return toReturn;
763 }
764
765 char* VDR::configLoad(char* section, char* key)
766 {
767   if (!connected) return 0;
768
769   ULONG totalLength = 8 + strlen(section) + strlen(key) + 2; // 8 for headers, 2 for nulls
770   UCHAR buffer[totalLength];
771
772   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
773   *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGLOAD);
774
775   int position = 8;
776   strcpy((char*)&buffer[position], section);
777   position += strlen(section) + 1;
778   strcpy((char*)&buffer[position], key);
779
780   pthread_mutex_lock(&mutex);
781   unsigned int a = tcp->sendPacket(buffer, totalLength);
782   if (a != totalLength)
783   {
784     pthread_mutex_unlock(&mutex);
785     return NULL;
786   }
787
788   if (!getPacket())
789   {
790     pthread_mutex_unlock(&mutex);
791     return NULL;
792   }
793   char* toReturn = extractString();
794   freePacket();
795   pthread_mutex_unlock(&mutex);
796
797   return toReturn;
798 }