]> git.vomp.tv Git - vompclient.git/blob - vdr.cc
Media Player From Andreas Vogel
[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 #include "recman.h"
23
24 VDR* VDR::instance = NULL;
25
26 #ifndef WIN32
27 #define MUTEX_LOCK(mutex) pthread_mutex_lock(mutex)
28 #define MUTEX_UNLOCK(mutex) pthread_mutex_unlock(mutex)
29 #else
30 #define MUTEX_LOCK(mutex) WaitForSingleObject(*(mutex), INFINITE )
31 #define MUTEX_UNLOCK(mutex) ReleaseMutex(*(mutex))
32 #endif
33
34
35 VDR::VDR()
36 {
37   if (instance) return;
38   instance = this;
39   initted = 0;
40   findingServer = 0;
41   tcp = NULL;
42 #ifndef WIN32
43   pthread_mutex_init(&mutex, NULL);
44 #else
45   mutex=CreateMutex(NULL,FALSE,NULL);
46 #endif
47   packetLength = 0;
48   packetPos = 0;
49   packet = NULL;
50   connected = false;
51   maxChannelNumber = 0;
52   channelNumberWidth = 1;
53 }
54
55 VDR::~VDR()
56 {
57 #ifdef WIN32
58   CloseHandle(mutex);
59 #endif
60   instance = NULL;
61   if (initted) shutdown();
62 }
63
64 VDR* VDR::getInstance()
65 {
66   return instance;
67 }
68
69 int VDR::init(int tport)
70 {
71   if (initted) return 0;
72   initted = 1;
73   port = tport;
74   logger = Log::getInstance();
75   return 1;
76 }
77
78 int VDR::shutdown()
79 {
80   if (!initted) return 0;
81   initted = 0;
82   disconnect();
83   return 1;
84 }
85
86 void VDR::findServers(vector<VDRServer>& servers)
87 {
88   Wol* wol = Wol::getInstance();
89   findingServer = 1;
90   char* message = "VOMP";
91
92   DatagramSocket ds(port);
93   int haveAtLeastOne = 0;
94   int retval;
95   int waitType = 1;
96   bool firstloop = true;
97   while(findingServer)
98   {
99     if (waitType == 1)
100     {
101       ds.shutdown();
102       ds.init();
103       logger->log("VDR", Log::NOTICE, "Broadcasting for server");
104       ds.send("255.255.255.255", 3024, message, strlen(message));
105       if(!firstloop) wol->doWakeUp();
106     }
107     retval = ds.waitforMessage(waitType);
108
109     if (retval == 2) // we got a reply
110     {
111       if (!strcmp(ds.getData(), "VOMP")) // echo.....
112       {
113         waitType = 2;
114       }
115       else
116       {
117         VDRServer newServer;
118         newServer.ip = new char[16];
119         strcpy(newServer.ip, ds.getFromIPA());
120
121         if (ds.getDataLength() == 0)
122         {
123           newServer.name = new char[1];
124           newServer.name[0] = '\0';
125         }
126         else
127         {
128           newServer.name = new char[strlen(ds.getData())+1];
129           strcpy(newServer.name, ds.getData());
130         }
131
132         servers.push_back(newServer);
133         waitType = 2;
134         haveAtLeastOne = 1;
135       }
136     }
137     else
138     {
139       if (haveAtLeastOne) break;
140       waitType = 1;
141       firstloop = false;
142     }
143   }
144   sort(servers.begin(), servers.end(), ServerSorter());
145 }
146
147 void VDR::cancelFindingServer()
148 {
149   findingServer = 0;
150 }
151
152 void VDR::setServerIP(char* newIP)
153 {
154   strcpy(serverIP, newIP);
155 }
156
157 int VDR::connect()
158 {
159   maxChannelNumber = 0;
160   channelNumberWidth = 1;
161
162   if (tcp) delete tcp;
163   tcp = new TCP();
164   if (tcp->connectTo(serverIP, 3024))
165   {
166     connected = true;
167     return 1;
168   }
169   else
170   {
171     return 0;
172   }
173 }
174
175 void VDR::disconnect()
176 {
177   if (tcp) delete tcp;
178   tcp = NULL;
179   connected = false;
180   Log::getInstance()->log("VDR", Log::DEBUG, "Disconnect");
181 }
182
183 void VDR::setReceiveWindow(size_t size)
184 {
185   if (connected) tcp->setReceiveWindow(size);
186 }
187
188 ///////////////////////////////////////////////////////
189
190 int VDR::getPacket()
191 {
192   packet = (UCHAR*)tcp->receivePacket();
193   if (!packet)
194   {
195     disconnect();
196     return 0;
197   }
198   packetLength = tcp->getDataLength();
199   return 1;
200 }
201
202 void VDR::freePacket()
203 {
204   // Must be called if getPacket return 1, except in getBlock
205   packetLength = 0;
206   packetPos = 0;
207   free(packet);
208   packet = NULL;
209 }
210
211 int VDR::serverError()
212 {
213   if ((packetPos == 0) && (packetLength == 4) && !ntohl(*(ULONG*)packet)) return 1;
214   else return 0;
215 }
216
217 char* VDR::extractString()
218 {
219   if (serverError()) return NULL;
220
221   int length = strlen((char*)&packet[packetPos]);
222   if ((packetPos + length) > packetLength) return NULL;
223   char* str = new char[length + 1];
224   strcpy(str, (char*)&packet[packetPos]);
225   packetPos += length + 1;
226   return str;
227 }
228
229 UCHAR VDR::extractUCHAR()
230 {
231   if ((packetPos + sizeof(UCHAR)) > packetLength) return 0;
232   UCHAR uc = packet[packetPos];
233   packetPos += sizeof(UCHAR);
234   return uc;
235 }
236
237 ULONG VDR::extractULONG()
238 {
239   if ((packetPos + sizeof(ULONG)) > packetLength) return 0;
240   ULONG ul = ntohl(*(ULONG*)&packet[packetPos]);
241   packetPos += sizeof(ULONG);
242   return ul;
243 }
244
245 ULLONG VDR::extractULLONG()
246 {
247   if ((packetPos + sizeof(ULLONG)) > packetLength) return 0;
248   ULLONG ull = ntohll(*(ULLONG*)&packet[packetPos]);
249   packetPos += sizeof(ULLONG);
250   return ull;
251 }
252
253 long VDR::extractLONG()
254 {
255   if ((packetPos + sizeof(long)) > packetLength) return 0;
256   long l = ntohl(*(long*)&packet[packetPos]);
257   packetPos += sizeof(long);
258   return l;
259 }
260
261 /////////////////////////////////////////////////////////////////////////////
262
263 int VDR::doLogin()
264 {
265   UCHAR buffer[14];
266
267   *(unsigned long*)&buffer[0] = htonl(10);
268   *(unsigned long*)&buffer[4] = htonl(VDR_LOGIN);
269
270   tcp->getMAC((char*)&buffer[8]);
271
272
273   MUTEX_LOCK(&mutex);
274   if (!connected)
275   {
276     MUTEX_UNLOCK(&mutex);
277     return 0;
278   }
279
280   int a = tcp->sendPacket(buffer, 14);
281   if (a != 14)
282   {
283     disconnect();
284     MUTEX_UNLOCK(&mutex);
285     return 0;
286   }
287
288   // reply
289
290   if (!getPacket())
291   {
292     MUTEX_UNLOCK(&mutex);
293     return 0;
294   }
295
296   ULONG vdrTime = extractULONG();
297   logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
298   long vdrTimeOffset = extractLONG();
299   logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
300
301   freePacket();
302   MUTEX_UNLOCK(&mutex);
303
304   // Set the time and zone on the MVP
305
306 #ifndef WIN32
307   struct timespec currentTime;
308   currentTime.tv_sec = vdrTime;
309   currentTime.tv_nsec = 0;
310   int b = clock_settime(CLOCK_REALTIME, &currentTime);
311
312   logger->log("VDR", Log::DEBUG, "set clock = %u", b);
313
314   // now make a TZ variable and set it
315   char sign;
316   int hours;
317   int minutes;
318   if (vdrTimeOffset > 0) sign = '-';
319   else sign = '+';
320
321   vdrTimeOffset = abs(vdrTimeOffset);
322
323   hours = (int)vdrTimeOffset / 3600;
324   minutes = vdrTimeOffset % 3600;
325
326   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
327
328   minutes = (int)minutes / 60;
329
330   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
331
332   char newTZ[30];
333   sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
334   setenv("TZ", newTZ, 1);
335
336   logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
337 #endif
338
339   return 1;
340 }
341
342 bool VDR::getRecordingsList(RecMan* recman)
343 {
344   UCHAR buffer[8];
345
346   *(unsigned long*)&buffer[0] = htonl(4);
347   *(unsigned long*)&buffer[4] = htonl(VDR_GETRECORDINGLIST);
348
349   MUTEX_LOCK(&mutex);
350   if (!connected)
351   {
352     MUTEX_UNLOCK(&mutex);
353     return 0;
354   }
355
356   int a = tcp->sendPacket(buffer, 8);
357   if (a != 8)
358   {
359     disconnect();
360     MUTEX_UNLOCK(&mutex);
361     return false;
362   }
363
364   // reply
365
366   if (!getPacket())
367   {
368     MUTEX_UNLOCK(&mutex);
369     return false;
370   }
371
372   ULONG totalSpace = extractULONG();
373   ULONG freeSpace = extractULONG();
374   ULONG percent = extractULONG();
375   recman->setStats(totalSpace, freeSpace, percent);
376
377   ULONG start;
378   char* name;
379   char* fileName;
380
381   while (packetPos < packetLength)
382   {
383     start = extractULONG();
384     name = extractString();
385     fileName = extractString();
386
387     recman->addEntry(start, name, fileName);
388
389     delete[] name;
390     delete[] fileName;
391   }
392
393   freePacket();
394   MUTEX_UNLOCK(&mutex);
395
396   return true;
397 }
398
399 int VDR::deleteRecording(char* fileName)
400 {
401   unsigned long totalLength = 8 + strlen(fileName) + 1;
402   UCHAR* buffer = new UCHAR[totalLength];
403
404   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
405   *(unsigned long*)&buffer[4] = htonl(VDR_DELETERECORDING);
406   strcpy((char*)&buffer[8], fileName);
407
408   MUTEX_LOCK(&mutex);
409   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
410
411   unsigned int a = tcp->sendPacket(buffer, totalLength);
412   delete []buffer;
413
414   if (a != totalLength)
415   {
416     disconnect();
417     MUTEX_UNLOCK(&mutex);
418     return 0;
419   }
420
421   if (!getPacket())
422   {
423     MUTEX_UNLOCK(&mutex);
424     return 0;
425   }
426
427   int toReturn = (int)extractULONG();
428   freePacket();
429   MUTEX_UNLOCK(&mutex);
430
431   return toReturn;
432 }
433
434 char* VDR::moveRecording(char* fileName, char* newPath)
435 {
436   unsigned long totalLength = 8 + strlen(fileName) + 1 + strlen(newPath) + 1;
437   UCHAR* buffer = new UCHAR[totalLength];
438
439   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
440   *(unsigned long*)&buffer[4] = htonl(VDR_MOVERECORDING);
441   strcpy((char*)&buffer[8], fileName);
442   strcpy((char*)&buffer[8 + strlen(fileName) + 1], newPath);
443
444   MUTEX_LOCK(&mutex);
445   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
446
447   unsigned int a = tcp->sendPacket(buffer, totalLength);
448   delete []buffer;
449
450   if (a != totalLength)
451   {
452     disconnect();
453     MUTEX_UNLOCK(&mutex);
454     return 0;
455   }
456
457   if (!getPacket())
458   {
459     MUTEX_UNLOCK(&mutex);
460     return 0;
461   }
462
463   char* toReturn = NULL;
464   int success = (int)extractULONG();
465   if (success == 1)
466   {
467     toReturn = extractString();
468   }
469
470   freePacket();
471   MUTEX_UNLOCK(&mutex);
472
473   return toReturn;
474 }
475
476 ChannelList* VDR::getChannelsList(ULONG type)
477 {
478   UCHAR buffer[8];
479
480   *(unsigned long*)&buffer[0] = htonl(4);
481   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELLIST);
482
483   MUTEX_LOCK(&mutex);
484   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
485
486   int a = tcp->sendPacket(buffer, 8);
487   if (a != 8)
488   {
489     disconnect();
490     MUTEX_UNLOCK(&mutex);
491     return NULL;
492   }
493
494   // reply
495
496   if (!getPacket())
497   {
498     MUTEX_UNLOCK(&mutex);
499     return NULL;
500   }
501
502   ChannelList* chanList = new ChannelList();
503
504   while (packetPos < packetLength)
505   {
506     Channel* chan = new Channel();
507     chan->number = extractULONG();
508     chan->type = extractULONG();
509     chan->name = extractString();
510
511     if (chan->type == type)
512     {
513       chanList->push_back(chan);
514       Log::getInstance()->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
515       if (chan->number > maxChannelNumber) maxChannelNumber = chan->number;
516     }
517     else
518     {
519       delete chan;
520     }
521   }
522
523   freePacket();
524   MUTEX_UNLOCK(&mutex);
525
526   if (maxChannelNumber > 99999)
527     channelNumberWidth = 6;
528   else if (maxChannelNumber > 9999)
529     channelNumberWidth = 5;
530   else if (maxChannelNumber > 999)
531     channelNumberWidth = 4;
532   else if (maxChannelNumber > 99)
533     channelNumberWidth = 3;
534   else if (maxChannelNumber > 9)
535     channelNumberWidth = 2;
536   else
537     channelNumberWidth = 1;
538
539   return chanList;
540 }
541
542 int VDR::streamChannel(ULONG number)
543 {
544   UCHAR buffer[12];
545
546   *(unsigned long*)&buffer[0] = htonl(8);
547   *(unsigned long*)&buffer[4] = htonl(VDR_STREAMCHANNEL);
548   *(unsigned long*)&buffer[8] = htonl(number);
549
550   MUTEX_LOCK(&mutex);
551   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
552
553   int a = tcp->sendPacket(buffer, 12);
554
555   if (a != 12)
556   {
557     disconnect();
558     MUTEX_UNLOCK(&mutex);
559     return 0;
560   }
561
562   if (!getPacket())
563   {
564     MUTEX_UNLOCK(&mutex);
565     return 0;
566   }
567
568   int toReturn = (int)extractULONG();
569   freePacket();
570   MUTEX_UNLOCK(&mutex);
571
572   return toReturn;
573 }
574
575 int VDR::stopStreaming()
576 {
577   UCHAR buffer[8];
578
579   *(unsigned long*)&buffer[0] = htonl(4);
580   *(unsigned long*)&buffer[4] = htonl(VDR_STOPSTREAMING);
581
582   MUTEX_LOCK(&mutex);
583   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
584
585   int a = tcp->sendPacket(buffer, 8);
586
587   if (a != 8)
588   {
589     disconnect();
590     MUTEX_UNLOCK(&mutex);
591     return 0;
592   }
593
594   if (!getPacket())
595   {
596     MUTEX_UNLOCK(&mutex);
597     return 0;
598   }
599
600   int toReturn = (int)extractULONG();
601   freePacket();
602   MUTEX_UNLOCK(&mutex);
603
604   return toReturn;
605 }
606
607 UCHAR* VDR::getImageBlock(ULONG position, UINT maxAmount, UINT* amountReceived)
608 {
609   return getBlock(position, maxAmount, amountReceived, VDR_GETIMAGEBLOCK);
610 }
611
612 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
613 {
614   return getBlock(position, maxAmount, amountReceived, VDR_GETBLOCK);
615 }
616
617 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived, ULONG cmd)
618 {
619   UCHAR buffer[20];
620
621   *(unsigned long*)&buffer[0] = htonl(16);
622   *(unsigned long*)&buffer[4] = htonl(cmd);
623   *(ULLONG*)&buffer[8]        = htonll(position);
624   *(unsigned long*)&buffer[16] = htonl(maxAmount);
625
626   MUTEX_LOCK(&mutex);
627   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
628
629   int a = tcp->sendPacket(buffer, 20);
630   if (a != 20)
631   {
632     disconnect();
633     MUTEX_UNLOCK(&mutex);
634     return NULL;
635   }
636
637   if (!getPacket())
638   {
639     MUTEX_UNLOCK(&mutex);
640     return NULL;
641   }
642
643   if (serverError())
644   {
645     Log::getInstance()->log("VDR", Log::DEBUG, "Detected getblock 0");
646     freePacket();
647     MUTEX_UNLOCK(&mutex);
648     return NULL;
649   }
650
651   UCHAR* toReturn = packet;
652   *amountReceived = packetLength;
653   // Manually clean up instead of running freePacket to keep the block
654   packet = NULL;
655   packetLength = 0;
656   packetPos = 0;
657   MUTEX_UNLOCK(&mutex);
658
659
660   return toReturn;
661 }
662
663 ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames)
664 {
665   unsigned long totalLength = 8 + strlen(fileName) + 1;
666   UCHAR* buffer = new UCHAR[totalLength];
667
668   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
669   *(unsigned long*)&buffer[4] = htonl(VDR_STREAMRECORDING);
670   strcpy((char*)&buffer[8], fileName);
671
672   MUTEX_LOCK(&mutex);
673   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
674
675   unsigned int a = tcp->sendPacket(buffer, totalLength);
676   delete []buffer;
677
678   if (a != totalLength)
679   {
680     disconnect();
681     MUTEX_UNLOCK(&mutex);
682     return 0;
683   }
684
685   if (!getPacket())
686   {
687     MUTEX_UNLOCK(&mutex);
688     return 0;
689   }
690
691   ULLONG lengthBytes = extractULLONG();
692   ULONG lengthFrames = extractULONG();
693   freePacket();
694   MUTEX_UNLOCK(&mutex);
695
696   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
697
698   *totalFrames = lengthFrames;
699   return lengthBytes;
700 }
701
702 ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)
703 {
704   unsigned long totalLength = 12;
705   UCHAR* buffer = new UCHAR[totalLength];
706
707   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
708   *(unsigned long*)&buffer[4] = htonl(VDR_POSFROMFRAME);
709   *(unsigned long*)&buffer[8] = htonl(frameNumber);
710
711   MUTEX_LOCK(&mutex);
712   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
713
714   unsigned int a = tcp->sendPacket(buffer, totalLength);
715   delete []buffer;
716
717   if (a != totalLength)
718   {
719     disconnect();
720     MUTEX_UNLOCK(&mutex);
721     return 0;
722   }
723
724   if (!getPacket())
725   {
726     MUTEX_UNLOCK(&mutex);
727     return 0;
728   }
729
730   ULLONG position = extractULLONG();
731   freePacket();
732   MUTEX_UNLOCK(&mutex);
733
734   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);
735
736   return position;
737 }
738
739 ULONG VDR::frameNumberFromPosition(ULLONG position)
740 {
741   unsigned long totalLength = 16;
742   UCHAR* buffer = new UCHAR[totalLength];
743
744   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
745   *(unsigned long*)&buffer[4] = htonl(VDR_FRAMEFROMPOS);
746   *(ULLONG*)&buffer[8] = htonll(position);
747
748   MUTEX_LOCK(&mutex);
749   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
750
751   unsigned int a = tcp->sendPacket(buffer, totalLength);
752   delete []buffer;
753
754   if (a != totalLength)
755   {
756     disconnect();
757     MUTEX_UNLOCK(&mutex);
758     return 0;
759   }
760
761   if (!getPacket())
762   {
763     MUTEX_UNLOCK(&mutex);
764     return 0;
765   }
766
767   ULONG framenumber = extractULONG();
768   freePacket();
769   MUTEX_UNLOCK(&mutex);
770
771   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new framenumber is: %u", framenumber);
772
773   return framenumber;
774 }
775
776 bool VDR::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)
777 {
778   unsigned long totalLength = 16;
779   UCHAR* buffer = new UCHAR[totalLength];
780
781   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
782   *(unsigned long*)&buffer[4] = htonl(VDR_GETNEXTIFRAME);
783   *(unsigned long*)&buffer[8] = htonl(frameNumber);
784   *(unsigned long*)&buffer[12] = htonl(direction);
785
786   MUTEX_LOCK(&mutex);
787   if (!connected) { MUTEX_UNLOCK(&mutex); return false; }
788
789   unsigned int a = tcp->sendPacket(buffer, totalLength);
790   delete []buffer;
791
792   if (a != totalLength)
793   {
794     disconnect();
795     MUTEX_UNLOCK(&mutex);
796     return false;
797   }
798
799   if (!getPacket())
800   {
801     MUTEX_UNLOCK(&mutex);
802     return false;
803   }
804
805   if (serverError())
806   {
807     Log::getInstance()->log("VDR", Log::DEBUG, "Detected getNextIFrame error");
808     freePacket();
809     MUTEX_UNLOCK(&mutex);
810     return false;
811   }
812
813   *rfilePosition = extractULLONG();
814   *rframeNumber = extractULONG();
815   *rframeLength = extractULONG();
816
817   freePacket();
818   MUTEX_UNLOCK(&mutex);
819
820 //  Log::getInstance()->log("VDR", Log::DEBUG, "VDR GNIF said %llu %lu %lu", *rfilePosition, *rframeNumber, *rframeLength);
821
822   return true;
823 }
824
825 EventList* VDR::getChannelSchedule(ULONG number)
826 {
827   time_t now;
828   time(&now);
829   return getChannelSchedule(number, now, 24 * 60 * 60);
830 }
831
832 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
833 {
834 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
835   UCHAR buffer[20];
836
837   *(unsigned long*)&buffer[0] = htonl(16);
838   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE);
839   *(unsigned long*)&buffer[8] = htonl(number);
840   *(unsigned long*)&buffer[12] = htonl(start);
841   *(unsigned long*)&buffer[16] = htonl(duration);
842
843   MUTEX_LOCK(&mutex);
844   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
845
846   int a = tcp->sendPacket(buffer, 20);
847
848   if (a != 20)
849   {
850     disconnect();
851     MUTEX_UNLOCK(&mutex);
852     return NULL;
853   }
854
855   if (!getPacket())
856   {
857     MUTEX_UNLOCK(&mutex);
858     return NULL;
859   }
860
861   // received a ulong(0) - schedules error in the plugin
862   if (serverError())
863   {
864     freePacket();
865     MUTEX_UNLOCK(&mutex);
866     return NULL;
867   }
868
869   EventList* eventList = new EventList();
870
871   while (packetPos < packetLength)
872   {
873     Event* event = new Event();
874     event->id = extractULONG();
875     event->time = extractULONG();
876     event->duration = extractULONG();
877     event->title = extractString();
878     event->subtitle = extractString();
879     event->description = extractString();
880     eventList->push_back(event);
881   }
882
883   freePacket();
884   MUTEX_UNLOCK(&mutex);
885
886   Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
887   return eventList;
888 }
889
890 int VDR::configSave(char* section, char* key, const char* value)
891 {
892   ULONG totalLength = 8 + strlen(section) + strlen(key) + strlen(value) + 3; // 8 for headers, 3 for nulls
893   UCHAR* buffer = new UCHAR[totalLength];
894
895   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
896   *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGSAVE);
897
898   int position = 8;
899   strcpy((char*)&buffer[position], section);
900   position += strlen(section) + 1;
901   strcpy((char*)&buffer[position], key);
902   position += strlen(key) + 1;
903   strcpy((char*)&buffer[position], value);
904
905   MUTEX_LOCK(&mutex);
906   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
907
908   unsigned int a = tcp->sendPacket(buffer, totalLength);
909   delete[] buffer;
910
911   if (a != totalLength)
912   {
913     disconnect();
914     MUTEX_UNLOCK(&mutex);
915     return 0;
916   }
917
918   if (!getPacket())
919   {
920     MUTEX_UNLOCK(&mutex);
921     return 0;
922   }
923
924   int toReturn = (int)extractULONG();
925   freePacket();
926   MUTEX_UNLOCK(&mutex);
927
928   return toReturn;
929 }
930
931 char* VDR::configLoad(char* section, char* key)
932 {
933   ULONG totalLength = 8 + strlen(section) + strlen(key) + 2; // 8 for headers, 2 for nulls
934   UCHAR* buffer = new UCHAR[totalLength];
935
936   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
937   *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGLOAD);
938
939   int position = 8;
940   strcpy((char*)&buffer[position], section);
941   position += strlen(section) + 1;
942   strcpy((char*)&buffer[position], key);
943
944   MUTEX_LOCK(&mutex);
945   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
946
947   unsigned int a = tcp->sendPacket(buffer, totalLength);
948   delete[] buffer;
949
950   if (a != totalLength)
951   {
952     disconnect();
953     MUTEX_UNLOCK(&mutex);
954     return NULL;
955   }
956
957   if (!getPacket())
958   {
959     MUTEX_UNLOCK(&mutex);
960     return NULL;
961   }
962   char* toReturn = extractString();
963   freePacket();
964   MUTEX_UNLOCK(&mutex);
965
966   return toReturn;
967 }
968
969 RecTimerList* VDR::getRecTimersList()
970 {
971   UCHAR buffer[8];
972
973   *(unsigned long*)&buffer[0] = htonl(4);
974   *(unsigned long*)&buffer[4] = htonl(VDR_GETTIMERS);
975
976   MUTEX_LOCK(&mutex);
977   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
978
979   int a = tcp->sendPacket(buffer, 8);
980   if (a != 8)
981   {
982     disconnect();
983     MUTEX_UNLOCK(&mutex);
984     return NULL;
985   }
986
987   // reply
988
989   if (!getPacket())
990   {
991     MUTEX_UNLOCK(&mutex);
992     return NULL;
993   }
994
995   RecTimerList* recTimerList = new RecTimerList();
996
997   ULONG numTimers = extractULONG();
998   if (numTimers > 0)
999   {
1000     RecTimer* newRecTimer;
1001     char* tempString;
1002
1003     while (packetPos < packetLength)
1004     {
1005       newRecTimer = new RecTimer();
1006       newRecTimer->active = extractULONG();
1007       newRecTimer->recording = extractULONG();
1008       newRecTimer->pending = extractULONG();
1009       newRecTimer->priority = extractULONG();
1010       newRecTimer->lifeTime = extractULONG();
1011       newRecTimer->channelNumber = extractULONG();
1012       newRecTimer->startTime = extractULONG();
1013       newRecTimer->stopTime = extractULONG();
1014
1015       tempString = extractString();
1016       newRecTimer->setFile(tempString);
1017       delete[] tempString;
1018
1019       recTimerList->push_back(newRecTimer);
1020       Log::getInstance()->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
1021         newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
1022         newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
1023     }
1024   }
1025
1026   freePacket();
1027   MUTEX_UNLOCK(&mutex);
1028
1029   sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
1030
1031   return recTimerList;
1032 }
1033
1034 ULONG VDR::setEventTimer(char* timerString)
1035 {
1036   unsigned long totalLength = 8 + strlen(timerString) + 1;
1037   UCHAR* buffer = new UCHAR[totalLength];
1038
1039   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1040   *(unsigned long*)&buffer[4] = htonl(VDR_SETTIMER);
1041   strcpy((char*)&buffer[8], timerString);
1042
1043   MUTEX_LOCK(&mutex);
1044   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1045
1046   unsigned int a = tcp->sendPacket(buffer, totalLength);
1047   delete []buffer;
1048
1049   if (a != totalLength)
1050   {
1051     disconnect();
1052     MUTEX_UNLOCK(&mutex);
1053     return 0;
1054   }
1055
1056   if (!getPacket())
1057   {
1058     MUTEX_UNLOCK(&mutex);
1059     return 0;
1060   }
1061
1062   ULONG toReturn = extractULONG();
1063   freePacket();
1064   MUTEX_UNLOCK(&mutex);
1065
1066   return toReturn;
1067 }
1068
1069 RecInfo* VDR::getRecInfo(char* fileName)
1070 {
1071   unsigned long totalLength = 8 + strlen(fileName) + 1;
1072   UCHAR* buffer = new UCHAR[totalLength];
1073
1074   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1075   *(unsigned long*)&buffer[4] = htonl(VDR_GETRECINFO);
1076   strcpy((char*)&buffer[8], fileName);
1077
1078   MUTEX_LOCK(&mutex);
1079   if (!connected) { MUTEX_UNLOCK(&mutex); return NULL; }
1080
1081   unsigned int a = tcp->sendPacket(buffer, totalLength);
1082   delete []buffer;
1083
1084   if (a != totalLength)
1085   {
1086     disconnect();
1087     MUTEX_UNLOCK(&mutex);
1088     return NULL;
1089   }
1090
1091   if (!getPacket())
1092   {
1093     MUTEX_UNLOCK(&mutex);
1094     return NULL;
1095   }
1096
1097   if (serverError())
1098   {
1099     Log::getInstance()->log("VDR", Log::DEBUG, "Could not get rec info");
1100     freePacket();
1101     MUTEX_UNLOCK(&mutex);
1102     return NULL;
1103   }
1104
1105   TCP::dump(packet, packetLength);
1106
1107   RecInfo* recInfo = new RecInfo();
1108
1109   recInfo->timerStart = extractULONG();
1110   recInfo->timerEnd = extractULONG();
1111   recInfo->resumePoint = extractULONG();
1112   recInfo->summary = extractString();
1113
1114   ULONG numComponents = extractULONG();
1115   if (numComponents)
1116   {
1117     recInfo->setNumComponents(numComponents);
1118     for (ULONG i = 0; i < numComponents; i++)
1119     {
1120       recInfo->streams[i] = extractUCHAR();
1121       recInfo->types[i] = extractUCHAR();
1122       recInfo->languages[i] = extractString();
1123       recInfo->descriptions[i] = extractString();
1124     }
1125   }
1126
1127   recInfo->print();
1128
1129   freePacket();
1130   MUTEX_UNLOCK(&mutex);
1131   return recInfo;
1132 }
1133
1134 // FIXME obselete
1135 ULLONG VDR::rescanRecording(ULONG* totalFrames)
1136 {
1137   unsigned long totalLength = 8;
1138   UCHAR* buffer = new UCHAR[totalLength];
1139
1140   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1141   *(unsigned long*)&buffer[4] = htonl(VDR_RESCANRECORDING);
1142
1143   MUTEX_LOCK(&mutex);
1144   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1145
1146   unsigned int a = tcp->sendPacket(buffer, totalLength);
1147   delete []buffer;
1148
1149   if (a != totalLength)
1150   {
1151     disconnect();
1152     MUTEX_UNLOCK(&mutex);
1153     return 0;
1154   }
1155
1156   if (!getPacket())
1157   {
1158     MUTEX_UNLOCK(&mutex);
1159     return 0;
1160   }
1161
1162   ULLONG lengthBytes = extractULLONG();
1163   ULONG lengthFrames = extractULONG();
1164   freePacket();
1165   MUTEX_UNLOCK(&mutex);
1166
1167   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
1168
1169   *totalFrames = lengthFrames;
1170   return lengthBytes;
1171 }
1172
1173 MarkList* VDR::getMarks(char* fileName)
1174 {
1175   unsigned long totalLength = 8 + strlen(fileName) + 1;
1176   UCHAR* buffer = new UCHAR[totalLength];
1177
1178   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1179   *(unsigned long*)&buffer[4] = htonl(VDR_GETMARKS);
1180   strcpy((char*)&buffer[8], fileName);
1181
1182   MUTEX_LOCK(&mutex);
1183   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1184
1185   unsigned int a = tcp->sendPacket(buffer, totalLength);
1186   delete []buffer;
1187
1188   if (a != totalLength)
1189   {
1190     disconnect();
1191     MUTEX_UNLOCK(&mutex);
1192     return NULL;
1193   }
1194
1195   if (!getPacket())
1196   {
1197     MUTEX_UNLOCK(&mutex);
1198     return NULL;
1199   }
1200
1201   if (serverError())
1202   {
1203     MUTEX_UNLOCK(&mutex);
1204     return NULL;
1205   }
1206
1207   MarkList* markList = new MarkList();
1208
1209   while (packetPos < packetLength)
1210   {
1211     Mark* mark = new Mark();
1212     mark->pos = extractULONG();
1213
1214     markList->push_back(mark);
1215     Log::getInstance()->log("VDR", Log::DEBUG, "Have added a mark to list. %lu", mark->pos);
1216   }
1217
1218   freePacket();
1219   MUTEX_UNLOCK(&mutex);
1220
1221   return markList;
1222 }
1223
1224 void VDR::getChannelPids(Channel* channel)
1225 {
1226   UCHAR buffer[12];
1227
1228   *(unsigned long*)&buffer[0] = htonl(8);
1229   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELPIDS);
1230   *(unsigned long*)&buffer[8] = htonl(channel->number);
1231
1232   MUTEX_LOCK(&mutex);
1233   if (!connected) { MUTEX_UNLOCK(&mutex); return ; }
1234
1235   int a = tcp->sendPacket(buffer, 12);
1236
1237   if (a != 12)
1238   {
1239     disconnect();
1240     MUTEX_UNLOCK(&mutex);
1241     return ;
1242   }
1243
1244   if (!getPacket())
1245   {
1246     MUTEX_UNLOCK(&mutex);
1247     return ;
1248   }
1249
1250   // Format of response
1251   // vpid
1252   // number of apids
1253   // {
1254   //    apid
1255   //    lang string
1256   // }
1257
1258   channel->vpid = extractULONG();
1259   channel->numAPids = extractULONG();
1260
1261   for (ULONG i = 0; i < channel->numAPids; i++)
1262   {
1263     apid newapid;
1264     newapid.pid = extractULONG();
1265     newapid.name = extractString();
1266     channel->apids.push_back(newapid);
1267   }
1268
1269   freePacket();
1270   MUTEX_UNLOCK(&mutex);
1271
1272   return ;
1273 }
1274
1275 /**
1276   * media List Request:
1277   * 4 length
1278   * 4 VDR_GETMEDIALIST
1279   * 4 flags (currently unused)
1280   * n dirname
1281   * n+1 0
1282   * Media List response:
1283   * 4 length
1284   * 4 VDR_
1285   * 4 numentries
1286   * per entry:
1287   * 4 media type
1288   * 4 time stamp
1289   * 4 flags
1290   * 4 strlen (incl. 0 Byte)
1291   * string
1292   * 0
1293 */
1294 MediaList* VDR::getMediaList(const char* parent,int mediaType)
1295 {
1296   Log::getInstance()->log("VDR", Log::DEBUG, "getMediaList %s,type=%d",
1297       (parent?parent:"NULL"), mediaType);
1298   unsigned long totalLength = 12;
1299   if (parent) totalLength+=strlen(parent) + 1;
1300   UCHAR* buffer = new UCHAR[totalLength];
1301
1302   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1303   *(unsigned long*)&buffer[4] = htonl(VDR_GETMEDIALIST);
1304   //unused flags
1305   for (int i=8;i<12;i++) buffer[i]=0;
1306   //name
1307   if (parent) {
1308     strcpy((char*)&buffer[12], parent);
1309     buffer[totalLength-1]=0;
1310     }
1311   MUTEX_LOCK(&mutex);
1312   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1313
1314   unsigned int a = tcp->sendPacket(buffer, totalLength);
1315   delete []buffer;
1316
1317   if (a != totalLength)
1318   {
1319     disconnect();
1320     MUTEX_UNLOCK(&mutex);
1321     return NULL;
1322   }
1323
1324   if (!getPacket())
1325   {
1326     MUTEX_UNLOCK(&mutex);
1327     return NULL;
1328   }
1329
1330   if (serverError())
1331   {
1332     MUTEX_UNLOCK(&mutex);
1333     return NULL;
1334   }
1335   if (packetLength < 12) {
1336     Log::getInstance()->log("VDR", Log::ERR, "receiveMediaList packet too short, expected 12, got %d", packetLength);
1337     freePacket();
1338     MUTEX_UNLOCK(&mutex);
1339     return NULL;
1340     }
1341   MediaList* mediaList = new MediaList();
1342   ULONG code=0;
1343   code=extractULONG();
1344   ULONG numEntries=extractULONG();
1345   Log::getInstance()->log("VDR", Log::DEBUG, "receiveMediaList with %d entries",numEntries);
1346   while (packetPos < packetLength && numEntries >0)
1347   {
1348     Media* m = new Media();
1349     ULONG mtype = extractULONG();
1350     ULONG mtime=extractULONG();
1351     ULONG flags=0;
1352     flags=extractULONG();
1353     ULONG stsize=extractULONG();
1354     char * name=extractString();
1355     if (! name || stsize != (strlen(name)+1)) {
1356       Log::getInstance()->log("VDR", Log::ERR, "receiveMediaList invalid packet entry, read size %d, strlen %d", stsize, strlen(name)+1);
1357       delete m;
1358       delete mediaList;
1359       freePacket();
1360       MUTEX_UNLOCK(&mutex);
1361       return NULL;
1362       }
1363     //ignore . and .. entries
1364     if (strcmp(name,".") == 0 || strcmp(name,"..")==0) {
1365   delete m;
1366   continue;
1367     }
1368     m->setFileName(name);
1369     m->setTime(mtime);
1370     m->setMediaType(mtype);
1371     mediaList->push_back(m);
1372     Log::getInstance()->log("VDR", Log::DEBUG, "Have added a media to list. %s, type=%d, time=%d", name,mtype,mtime);
1373     numEntries--;
1374   }
1375
1376   freePacket();
1377   MUTEX_UNLOCK(&mutex);
1378
1379   return mediaList;
1380 }
1381 /**
1382   * get image Request:
1383   * 4 length
1384   * 4 VDR_GETIMAGE
1385   * 4 flags (currently unused)
1386   * 4 x size
1387   * 4 y size
1388   * n filename
1389   * n+1 0
1390   * get image response:
1391   * 4 length
1392   * 4 VDR_GETIMAGE
1393   * 4 len of image
1394 */
1395 ULONG VDR::loadImage(const char* fileName, ULONG x, ULONG y)
1396 {
1397   unsigned long totalLength = 20 + strlen(fileName) + 1;
1398   UCHAR* buffer = new UCHAR[totalLength];
1399
1400   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1401   *(unsigned long*)&buffer[4] = htonl(VDR_GETIMAGE);
1402   *(unsigned long*)&buffer[8] = htonl(0);
1403   *(unsigned long*)&buffer[8] = htonl(x);
1404   *(unsigned long*)&buffer[8] = htonl(y);
1405   strcpy((char*)&buffer[12], fileName);
1406
1407   MUTEX_LOCK(&mutex);
1408   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1409
1410   unsigned int a = tcp->sendPacket(buffer, totalLength);
1411   delete []buffer;
1412
1413   if (a != totalLength)
1414   {
1415     disconnect();
1416     MUTEX_UNLOCK(&mutex);
1417     return 0;
1418   }
1419
1420   if (!getPacket())
1421   {
1422     MUTEX_UNLOCK(&mutex);
1423     return 0;
1424   }
1425   ULONG cmd=0;
1426   cmd=extractULONG();
1427   ULONG lengthBytes = extractULONG();
1428   freePacket();
1429   MUTEX_UNLOCK(&mutex);
1430
1431   Log::getInstance()->log("VDR", Log::DEBUG, "getImage %s: %lu", fileName,lengthBytes);
1432
1433   return lengthBytes;
1434 }