]> git.vomp.tv Git - vompclient.git/blob - vdr.cc
Demuxer::scanForVideo()
[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 }
52
53 VDR::~VDR()
54 {
55 #ifdef WIN32
56   CloseHandle(mutex);
57 #endif
58   instance = NULL;
59   if (initted) shutdown();
60 }
61
62 VDR* VDR::getInstance()
63 {
64   return instance;
65 }
66
67 int VDR::init(int tport)
68 {
69   if (initted) return 0;
70   initted = 1;
71   port = tport;
72   logger = Log::getInstance();
73   return 1;
74 }
75
76 int VDR::shutdown()
77 {
78   if (!initted) return 0;
79   initted = 0;
80   disconnect();
81   return 1;
82 }
83
84 void VDR::findServers(vector<VDRServer>& servers)
85 {
86   findingServer = 1;
87   char* message = "VOMP";
88
89   DatagramSocket ds(port);
90   int haveAtLeastOne = 0;
91   int retval;
92   int waitType = 1;
93   while(findingServer)
94   {
95     if (waitType == 1)
96     {
97       ds.shutdown();
98       ds.init();
99       logger->log("VDR", Log::NOTICE, "Broadcasting for server");
100       ds.send("255.255.255.255", 3024, message, strlen(message));
101     }
102     retval = ds.waitforMessage(waitType);
103
104     if (retval == 2) // we got a reply
105     {
106       if (!strcmp(ds.getData(), "VOMP")) // echo.....
107       {
108         waitType = 2;
109       }
110       else
111       {
112         VDRServer newServer;
113         newServer.ip = new char[16];
114         strcpy(newServer.ip, ds.getFromIPA());
115
116         if (ds.getDataLength() == 0)
117         {
118           newServer.name = new char[1];
119           newServer.name[0] = '\0';
120         }
121         else
122         {
123           newServer.name = new char[strlen(ds.getData())+1];
124           strcpy(newServer.name, ds.getData());
125         }
126
127         servers.push_back(newServer);
128         waitType = 2;
129         haveAtLeastOne = 1;
130       }
131     }
132     else
133     {
134       if (haveAtLeastOne) break;
135       waitType = 1;
136     }
137   }
138   sort(servers.begin(), servers.end(), ServerSorter());
139 }
140
141 void VDR::cancelFindingServer()
142 {
143   findingServer = 0;
144 }
145
146 void VDR::setServerIP(char* newIP)
147 {
148   strcpy(serverIP, newIP);
149 }
150
151 int VDR::connect()
152 {
153   if (tcp) delete tcp;
154   tcp = new TCP();
155   if (tcp->connectTo(serverIP, 3024))
156   {
157     connected = true;
158     return 1;
159   }
160   else
161   {
162     return 0;
163   }
164 }
165
166 void VDR::disconnect()
167 {
168   if (tcp) delete tcp;
169   tcp = NULL;
170   connected = false;
171   Log::getInstance()->log("VDR", Log::DEBUG, "Disconnect");
172 }
173
174 void VDR::setReceiveWindow(size_t size)
175 {
176   if (connected) tcp->setReceiveWindow(size);
177 }
178
179 ///////////////////////////////////////////////////////
180
181 int VDR::getPacket()
182 {
183   packet = (UCHAR*)tcp->receivePacket();
184   if (!packet)
185   {
186     disconnect();
187     return 0;
188   }
189   packetLength = tcp->getDataLength();
190   return 1;
191 }
192
193 void VDR::freePacket()
194 {
195   // Must be called if getPacket return 1, except in getBlock
196   packetLength = 0;
197   packetPos = 0;
198   free(packet);
199   packet = NULL;
200 }
201
202 int VDR::serverError()
203 {
204   if ((packetPos == 0) && (packetLength == 4) && !ntohl(*(ULONG*)packet)) return 1;
205   else return 0;
206 }
207
208 char* VDR::extractString()
209 {
210   if (serverError()) return NULL;
211
212   int length = strlen((char*)&packet[packetPos]);
213   if ((packetPos + length) > packetLength) return NULL;
214   char* str = new char[length + 1];
215   strcpy(str, (char*)&packet[packetPos]);
216   packetPos += length + 1;
217   return str;
218 }
219
220 UCHAR VDR::extractUCHAR()
221 {
222   if ((packetPos + sizeof(UCHAR)) > packetLength) return 0;
223   UCHAR uc = packet[packetPos];
224   packetPos += sizeof(UCHAR);
225   return uc;
226 }
227
228 ULONG VDR::extractULONG()
229 {
230   if ((packetPos + sizeof(ULONG)) > packetLength) return 0;
231   ULONG ul = ntohl(*(ULONG*)&packet[packetPos]);
232   packetPos += sizeof(ULONG);
233   return ul;
234 }
235
236 ULLONG VDR::extractULLONG()
237 {
238   if ((packetPos + sizeof(ULLONG)) > packetLength) return 0;
239   ULLONG ull = ntohll(*(ULLONG*)&packet[packetPos]);
240   packetPos += sizeof(ULLONG);
241   return ull;
242 }
243
244 long VDR::extractLONG()
245 {
246   if ((packetPos + sizeof(long)) > packetLength) return 0;
247   long l = ntohl(*(long*)&packet[packetPos]);
248   packetPos += sizeof(long);
249   return l;
250 }
251
252 /////////////////////////////////////////////////////////////////////////////
253
254 int VDR::doLogin()
255 {
256   UCHAR buffer[14];
257
258   *(unsigned long*)&buffer[0] = htonl(10);
259   *(unsigned long*)&buffer[4] = htonl(VDR_LOGIN);
260
261   tcp->getMAC((char*)&buffer[8]);
262
263
264   MUTEX_LOCK(&mutex);
265   if (!connected)
266   {
267     MUTEX_UNLOCK(&mutex);
268     return 0;
269   }
270
271   int a = tcp->sendPacket(buffer, 14);
272   if (a != 14)
273   {
274     disconnect();
275     MUTEX_UNLOCK(&mutex);
276     return 0;
277   }
278
279   // reply
280
281   if (!getPacket())
282   {
283     MUTEX_UNLOCK(&mutex);
284     return 0;
285   }
286
287   ULONG vdrTime = extractULONG();
288   logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
289   long vdrTimeOffset = extractLONG();
290   logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
291
292   freePacket();
293   MUTEX_UNLOCK(&mutex);
294
295   // Set the time and zone on the MVP
296
297 #ifndef WIN32
298   struct timespec currentTime;
299   currentTime.tv_sec = vdrTime;
300   currentTime.tv_nsec = 0;
301   int b = clock_settime(CLOCK_REALTIME, &currentTime);
302
303   logger->log("VDR", Log::DEBUG, "set clock = %u", b);
304
305   // now make a TZ variable and set it
306   char sign;
307   int hours;
308   int minutes;
309   if (vdrTimeOffset > 0) sign = '-';
310   else sign = '+';
311
312   vdrTimeOffset = abs(vdrTimeOffset);
313
314   hours = (int)vdrTimeOffset / 3600;
315   minutes = vdrTimeOffset % 3600;
316
317   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
318
319   minutes = (int)minutes / 60;
320
321   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
322
323   char newTZ[30];
324   sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
325   setenv("TZ", newTZ, 1);
326
327   logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
328 #endif
329
330   return 1;
331 }
332
333 bool VDR::getRecordingsList(RecMan* recman)
334 {
335   UCHAR buffer[8];
336
337   *(unsigned long*)&buffer[0] = htonl(4);
338   *(unsigned long*)&buffer[4] = htonl(VDR_GETRECORDINGLIST);
339
340   MUTEX_LOCK(&mutex);
341   if (!connected)
342   {
343     MUTEX_UNLOCK(&mutex);
344     return 0;
345   }
346
347   int a = tcp->sendPacket(buffer, 8);
348   if (a != 8)
349   {
350     disconnect();
351     MUTEX_UNLOCK(&mutex);
352     return false;
353   }
354
355   // reply
356
357   if (!getPacket())
358   {
359     MUTEX_UNLOCK(&mutex);
360     return false;
361   }
362
363   ULONG totalSpace = extractULONG();
364   ULONG freeSpace = extractULONG();
365   ULONG percent = extractULONG();
366   recman->setStats(totalSpace, freeSpace, percent);
367
368   ULONG start;
369   char* name;
370   char* fileName;
371
372   while (packetPos < packetLength)
373   {
374     start = extractULONG();
375     name = extractString();
376     fileName = extractString();
377
378     recman->addEntry(start, name, fileName);
379
380     delete[] name;
381     delete[] fileName;
382   }
383
384   freePacket();
385   MUTEX_UNLOCK(&mutex);
386
387   return true;
388 }
389
390 int VDR::deleteRecording(char* fileName)
391 {
392   unsigned long totalLength = 8 + strlen(fileName) + 1;
393   UCHAR* buffer = new UCHAR[totalLength];
394
395   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
396   *(unsigned long*)&buffer[4] = htonl(VDR_DELETERECORDING);
397   strcpy((char*)&buffer[8], fileName);
398
399   MUTEX_LOCK(&mutex);
400   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
401
402   unsigned int a = tcp->sendPacket(buffer, totalLength);
403   delete []buffer;
404
405   if (a != totalLength)
406   {
407     disconnect();
408     MUTEX_UNLOCK(&mutex);
409     return 0;
410   }
411
412   if (!getPacket())
413   {
414     MUTEX_UNLOCK(&mutex);
415     return 0;
416   }
417
418   int toReturn = (int)extractULONG();
419   freePacket();
420   MUTEX_UNLOCK(&mutex);
421
422   return toReturn;
423 }
424
425 char* VDR::moveRecording(char* fileName, char* newPath)
426 {
427   unsigned long totalLength = 8 + strlen(fileName) + 1 + strlen(newPath) + 1;
428   UCHAR* buffer = new UCHAR[totalLength];
429
430   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
431   *(unsigned long*)&buffer[4] = htonl(VDR_MOVERECORDING);
432   strcpy((char*)&buffer[8], fileName);
433   strcpy((char*)&buffer[8 + strlen(fileName) + 1], newPath);
434
435   MUTEX_LOCK(&mutex);
436   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
437
438   unsigned int a = tcp->sendPacket(buffer, totalLength);
439   delete []buffer;
440
441   if (a != totalLength)
442   {
443     disconnect();
444     MUTEX_UNLOCK(&mutex);
445     return 0;
446   }
447
448   if (!getPacket())
449   {
450     MUTEX_UNLOCK(&mutex);
451     return 0;
452   }
453
454   char* toReturn = NULL;
455   int success = (int)extractULONG();
456   if (success == 1)
457   {
458     toReturn = extractString();
459   }
460
461   freePacket();
462   MUTEX_UNLOCK(&mutex);
463
464   return toReturn;
465 }
466
467 ChannelList* VDR::getChannelsList(ULONG type)
468 {
469   UCHAR buffer[8];
470
471   *(unsigned long*)&buffer[0] = htonl(4);
472   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELLIST);
473
474   MUTEX_LOCK(&mutex);
475   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
476
477   int a = tcp->sendPacket(buffer, 8);
478   if (a != 8)
479   {
480     disconnect();
481     MUTEX_UNLOCK(&mutex);
482     return NULL;
483   }
484
485   // reply
486
487   if (!getPacket())
488   {
489     MUTEX_UNLOCK(&mutex);
490     return NULL;
491   }
492
493   ChannelList* chanList = new ChannelList();
494
495   while (packetPos < packetLength)
496   {
497     Channel* chan = new Channel();
498     chan->number = extractULONG();
499     chan->type = extractULONG();
500     chan->name = extractString();
501
502     if (chan->type == type)
503     {
504       chanList->push_back(chan);
505       Log::getInstance()->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
506     }
507     else
508     {
509       delete chan;
510     }
511   }
512
513   freePacket();
514   MUTEX_UNLOCK(&mutex);
515
516   return chanList;
517 }
518
519 int VDR::streamChannel(ULONG number)
520 {
521   UCHAR buffer[12];
522
523   *(unsigned long*)&buffer[0] = htonl(8);
524   *(unsigned long*)&buffer[4] = htonl(VDR_STREAMCHANNEL);
525   *(unsigned long*)&buffer[8] = htonl(number);
526
527   MUTEX_LOCK(&mutex);
528   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
529
530   int a = tcp->sendPacket(buffer, 12);
531
532   if (a != 12)
533   {
534     disconnect();
535     MUTEX_UNLOCK(&mutex);
536     return 0;
537   }
538
539   if (!getPacket())
540   {
541     MUTEX_UNLOCK(&mutex);
542     return 0;
543   }
544
545   int toReturn = (int)extractULONG();
546   freePacket();
547   MUTEX_UNLOCK(&mutex);
548
549   return toReturn;
550 }
551
552 int VDR::stopStreaming()
553 {
554   UCHAR buffer[8];
555
556   *(unsigned long*)&buffer[0] = htonl(4);
557   *(unsigned long*)&buffer[4] = htonl(VDR_STOPSTREAMING);
558
559   MUTEX_LOCK(&mutex);
560   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
561
562   int a = tcp->sendPacket(buffer, 8);
563
564   if (a != 8)
565   {
566     disconnect();
567     MUTEX_UNLOCK(&mutex);
568     return 0;
569   }
570
571   if (!getPacket())
572   {
573     MUTEX_UNLOCK(&mutex);
574     return 0;
575   }
576
577   int toReturn = (int)extractULONG();
578   freePacket();
579   MUTEX_UNLOCK(&mutex);
580
581   return toReturn;
582 }
583
584 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
585 {
586   UCHAR buffer[20];
587
588   *(unsigned long*)&buffer[0] = htonl(16);
589   *(unsigned long*)&buffer[4] = htonl(VDR_GETBLOCK);
590   *(ULLONG*)&buffer[8]        = htonll(position);
591   *(unsigned long*)&buffer[16] = htonl(maxAmount);
592
593   MUTEX_LOCK(&mutex);
594   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
595
596   int a = tcp->sendPacket(buffer, 20);
597   if (a != 20)
598   {
599     disconnect();
600     MUTEX_UNLOCK(&mutex);
601     return NULL;
602   }
603
604   if (!getPacket())
605   {
606     MUTEX_UNLOCK(&mutex);
607     return NULL;
608   }
609
610   if (serverError())
611   {
612     Log::getInstance()->log("VDR", Log::DEBUG, "Detected getblock 0");
613     freePacket();
614     MUTEX_UNLOCK(&mutex);
615     return NULL;
616   }
617
618   UCHAR* toReturn = packet;
619   *amountReceived = packetLength;
620   // Manually clean up instead of running freePacket to keep the block
621   packet = NULL;
622   packetLength = 0;
623   packetPos = 0;
624   MUTEX_UNLOCK(&mutex);
625
626
627   return toReturn;
628 }
629
630 ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames)
631 {
632   unsigned long totalLength = 8 + strlen(fileName) + 1;
633   UCHAR* buffer = new UCHAR[totalLength];
634
635   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
636   *(unsigned long*)&buffer[4] = htonl(VDR_STREAMRECORDING);
637   strcpy((char*)&buffer[8], fileName);
638
639   MUTEX_LOCK(&mutex);
640   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
641
642   unsigned int a = tcp->sendPacket(buffer, totalLength);
643   delete []buffer;
644
645   if (a != totalLength)
646   {
647     disconnect();
648     MUTEX_UNLOCK(&mutex);
649     return 0;
650   }
651
652   if (!getPacket())
653   {
654     MUTEX_UNLOCK(&mutex);
655     return 0;
656   }
657
658   ULLONG lengthBytes = extractULLONG();
659   ULONG lengthFrames = extractULONG();
660   freePacket();
661   MUTEX_UNLOCK(&mutex);
662
663   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
664
665   *totalFrames = lengthFrames;
666   return lengthBytes;
667 }
668
669 ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)
670 {
671   unsigned long totalLength = 12;
672   UCHAR* buffer = new UCHAR[totalLength];
673
674   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
675   *(unsigned long*)&buffer[4] = htonl(VDR_POSFROMFRAME);
676   *(unsigned long*)&buffer[8] = htonl(frameNumber);
677
678   MUTEX_LOCK(&mutex);
679   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
680
681   unsigned int a = tcp->sendPacket(buffer, totalLength);
682   delete []buffer;
683
684   if (a != totalLength)
685   {
686     disconnect();
687     MUTEX_UNLOCK(&mutex);
688     return 0;
689   }
690
691   if (!getPacket())
692   {
693     MUTEX_UNLOCK(&mutex);
694     return 0;
695   }
696
697   ULLONG position = extractULLONG();
698   freePacket();
699   MUTEX_UNLOCK(&mutex);
700
701   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);
702
703   return position;
704 }
705
706 ULONG VDR::frameNumberFromPosition(ULLONG position)
707 {
708   unsigned long totalLength = 16;
709   UCHAR* buffer = new UCHAR[totalLength];
710
711   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
712   *(unsigned long*)&buffer[4] = htonl(VDR_FRAMEFROMPOS);
713   *(ULLONG*)&buffer[8] = htonll(position);
714
715   MUTEX_LOCK(&mutex);
716   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
717
718   unsigned int a = tcp->sendPacket(buffer, totalLength);
719   delete []buffer;
720
721   if (a != totalLength)
722   {
723     disconnect();
724     MUTEX_UNLOCK(&mutex);
725     return 0;
726   }
727
728   if (!getPacket())
729   {
730     MUTEX_UNLOCK(&mutex);
731     return 0;
732   }
733
734   ULONG framenumber = extractULONG();
735   freePacket();
736   MUTEX_UNLOCK(&mutex);
737
738   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new framenumber is: %u", framenumber);
739
740   return framenumber;
741 }
742
743 bool VDR::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)
744 {
745   unsigned long totalLength = 16;
746   UCHAR* buffer = new UCHAR[totalLength];
747
748   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
749   *(unsigned long*)&buffer[4] = htonl(VDR_GETNEXTIFRAME);
750   *(unsigned long*)&buffer[8] = htonl(frameNumber);
751   *(unsigned long*)&buffer[12] = htonl(direction);
752
753   MUTEX_LOCK(&mutex);
754   if (!connected) { MUTEX_UNLOCK(&mutex); return false; }
755
756   unsigned int a = tcp->sendPacket(buffer, totalLength);
757   delete []buffer;
758
759   if (a != totalLength)
760   {
761     disconnect();
762     MUTEX_UNLOCK(&mutex);
763     return false;
764   }
765
766   if (!getPacket())
767   {
768     MUTEX_UNLOCK(&mutex);
769     return false;
770   }
771
772   if (serverError())
773   {
774     Log::getInstance()->log("VDR", Log::DEBUG, "Detected getNextIFrame error");
775     freePacket();
776     MUTEX_UNLOCK(&mutex);
777     return false;
778   }
779
780   *rfilePosition = extractULLONG();
781   *rframeNumber = extractULONG();
782   *rframeLength = extractULONG();
783
784   freePacket();
785   MUTEX_UNLOCK(&mutex);
786
787 //  Log::getInstance()->log("VDR", Log::DEBUG, "VDR GNIF said %llu %lu %lu", *rfilePosition, *rframeNumber, *rframeLength);
788
789   return true;
790 }
791
792 EventList* VDR::getChannelSchedule(ULONG number)
793 {
794   time_t now;
795   time(&now);
796   return getChannelSchedule(number, now, 24 * 60 * 60);
797 }
798
799 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
800 {
801 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
802   UCHAR buffer[20];
803
804   *(unsigned long*)&buffer[0] = htonl(16);
805   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE);
806   *(unsigned long*)&buffer[8] = htonl(number);
807   *(unsigned long*)&buffer[12] = htonl(start);
808   *(unsigned long*)&buffer[16] = htonl(duration);
809
810   MUTEX_LOCK(&mutex);
811   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
812
813   int a = tcp->sendPacket(buffer, 20);
814
815   if (a != 20)
816   {
817     disconnect();
818     MUTEX_UNLOCK(&mutex);
819     return NULL;
820   }
821
822   if (!getPacket())
823   {
824     MUTEX_UNLOCK(&mutex);
825     return NULL;
826   }
827
828   // received a ulong(0) - schedules error in the plugin
829   if (serverError())
830   {
831     freePacket();
832     MUTEX_UNLOCK(&mutex);
833     return NULL;
834   }
835
836   EventList* eventList = new EventList();
837
838   while (packetPos < packetLength)
839   {
840     Event* event = new Event();
841     event->id = extractULONG();
842     event->time = extractULONG();
843     event->duration = extractULONG();
844     event->title = extractString();
845     event->subtitle = extractString();
846     event->description = extractString();
847     eventList->push_back(event);
848   }
849
850   freePacket();
851   MUTEX_UNLOCK(&mutex);
852
853   Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
854   return eventList;
855 }
856
857 int VDR::configSave(char* section, char* key, const char* value)
858 {
859   ULONG totalLength = 8 + strlen(section) + strlen(key) + strlen(value) + 3; // 8 for headers, 3 for nulls
860   UCHAR* buffer = new UCHAR[totalLength];
861
862   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
863   *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGSAVE);
864
865   int position = 8;
866   strcpy((char*)&buffer[position], section);
867   position += strlen(section) + 1;
868   strcpy((char*)&buffer[position], key);
869   position += strlen(key) + 1;
870   strcpy((char*)&buffer[position], value);
871
872   MUTEX_LOCK(&mutex);
873   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
874
875   unsigned int a = tcp->sendPacket(buffer, totalLength);
876   delete[] buffer;
877
878   if (a != totalLength)
879   {
880     disconnect();
881     MUTEX_UNLOCK(&mutex);
882     return 0;
883   }
884
885   if (!getPacket())
886   {
887     MUTEX_UNLOCK(&mutex);
888     return 0;
889   }
890
891   int toReturn = (int)extractULONG();
892   freePacket();
893   MUTEX_UNLOCK(&mutex);
894
895   return toReturn;
896 }
897
898 char* VDR::configLoad(char* section, char* key)
899 {
900   ULONG totalLength = 8 + strlen(section) + strlen(key) + 2; // 8 for headers, 2 for nulls
901   UCHAR* buffer = new UCHAR[totalLength];
902
903   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
904   *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGLOAD);
905
906   int position = 8;
907   strcpy((char*)&buffer[position], section);
908   position += strlen(section) + 1;
909   strcpy((char*)&buffer[position], key);
910
911   MUTEX_LOCK(&mutex);
912   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
913
914   unsigned int a = tcp->sendPacket(buffer, totalLength);
915   delete[] buffer;
916
917   if (a != totalLength)
918   {
919     disconnect();
920     MUTEX_UNLOCK(&mutex);
921     return NULL;
922   }
923
924   if (!getPacket())
925   {
926     MUTEX_UNLOCK(&mutex);
927     return NULL;
928   }
929   char* toReturn = extractString();
930   freePacket();
931   MUTEX_UNLOCK(&mutex);
932
933   return toReturn;
934 }
935
936 RecTimerList* VDR::getRecTimersList()
937 {
938   UCHAR buffer[8];
939
940   *(unsigned long*)&buffer[0] = htonl(4);
941   *(unsigned long*)&buffer[4] = htonl(VDR_GETTIMERS);
942
943   MUTEX_LOCK(&mutex);
944   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
945
946   int a = tcp->sendPacket(buffer, 8);
947   if (a != 8)
948   {
949     disconnect();
950     MUTEX_UNLOCK(&mutex);
951     return NULL;
952   }
953
954   // reply
955
956   if (!getPacket())
957   {
958     MUTEX_UNLOCK(&mutex);
959     return NULL;
960   }
961
962   RecTimerList* recTimerList = new RecTimerList();
963
964   ULONG numTimers = extractULONG();
965   if (numTimers > 0)
966   {
967     RecTimer* newRecTimer;
968     char* tempString;
969
970     while (packetPos < packetLength)
971     {
972       newRecTimer = new RecTimer();
973       newRecTimer->active = extractULONG();
974       newRecTimer->recording = extractULONG();
975       newRecTimer->pending = extractULONG();
976       newRecTimer->priority = extractULONG();
977       newRecTimer->lifeTime = extractULONG();
978       newRecTimer->channelNumber = extractULONG();
979       newRecTimer->startTime = extractULONG();
980       newRecTimer->stopTime = extractULONG();
981
982       tempString = extractString();
983       newRecTimer->setFile(tempString);
984       delete[] tempString;
985
986       recTimerList->push_back(newRecTimer);
987       Log::getInstance()->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
988         newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
989         newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
990     }
991   }
992
993   freePacket();
994   MUTEX_UNLOCK(&mutex);
995
996   sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
997
998   return recTimerList;
999 }
1000
1001 ULONG VDR::setEventTimer(char* timerString)
1002 {
1003   unsigned long totalLength = 8 + strlen(timerString) + 1;
1004   UCHAR* buffer = new UCHAR[totalLength];
1005
1006   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1007   *(unsigned long*)&buffer[4] = htonl(VDR_SETTIMER);
1008   strcpy((char*)&buffer[8], timerString);
1009
1010   MUTEX_LOCK(&mutex);
1011   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1012
1013   unsigned int a = tcp->sendPacket(buffer, totalLength);
1014   delete []buffer;
1015
1016   if (a != totalLength)
1017   {
1018     disconnect();
1019     MUTEX_UNLOCK(&mutex);
1020     return 0;
1021   }
1022
1023   if (!getPacket())
1024   {
1025     MUTEX_UNLOCK(&mutex);
1026     return 0;
1027   }
1028
1029   ULONG toReturn = extractULONG();
1030   freePacket();
1031   MUTEX_UNLOCK(&mutex);
1032
1033   return toReturn;
1034 }
1035
1036 RecInfo* VDR::getRecInfo(char* fileName)
1037 {
1038   unsigned long totalLength = 8 + strlen(fileName) + 1;
1039   UCHAR* buffer = new UCHAR[totalLength];
1040
1041   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1042   *(unsigned long*)&buffer[4] = htonl(VDR_GETRECINFO);
1043   strcpy((char*)&buffer[8], fileName);
1044
1045   MUTEX_LOCK(&mutex);
1046   if (!connected) { MUTEX_UNLOCK(&mutex); return NULL; }
1047
1048   unsigned int a = tcp->sendPacket(buffer, totalLength);
1049   delete []buffer;
1050
1051   if (a != totalLength)
1052   {
1053     disconnect();
1054     MUTEX_UNLOCK(&mutex);
1055     return NULL;
1056   }
1057
1058   if (!getPacket())
1059   {
1060     MUTEX_UNLOCK(&mutex);
1061     return NULL;
1062   }
1063
1064   if (serverError())
1065   {
1066     Log::getInstance()->log("VDR", Log::DEBUG, "Could not get rec info");
1067     freePacket();
1068     MUTEX_UNLOCK(&mutex);
1069     return NULL;
1070   }
1071
1072   TCP::dump(packet, packetLength);
1073
1074   RecInfo* recInfo = new RecInfo();
1075
1076   recInfo->timerStart = extractULONG();
1077   recInfo->timerEnd = extractULONG();
1078   recInfo->resumePoint = extractULONG();
1079   recInfo->summary = extractString();
1080
1081   ULONG numComponents = extractULONG();
1082   if (numComponents)
1083   {
1084     recInfo->setNumComponents(numComponents);
1085     for (ULONG i = 0; i < numComponents; i++)
1086     {
1087       recInfo->streams[i] = extractUCHAR();
1088       recInfo->types[i] = extractUCHAR();
1089       recInfo->languages[i] = extractString();
1090       recInfo->descriptions[i] = extractString();
1091     }
1092   }
1093
1094   recInfo->print();
1095
1096   freePacket();
1097   MUTEX_UNLOCK(&mutex);
1098   return recInfo;
1099 }
1100
1101 // FIXME obselete
1102 ULLONG VDR::rescanRecording(ULONG* totalFrames)
1103 {
1104   unsigned long totalLength = 8;
1105   UCHAR* buffer = new UCHAR[totalLength];
1106
1107   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1108   *(unsigned long*)&buffer[4] = htonl(VDR_RESCANRECORDING);
1109
1110   MUTEX_LOCK(&mutex);
1111   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1112
1113   unsigned int a = tcp->sendPacket(buffer, totalLength);
1114   delete []buffer;
1115
1116   if (a != totalLength)
1117   {
1118     disconnect();
1119     MUTEX_UNLOCK(&mutex);
1120     return 0;
1121   }
1122
1123   if (!getPacket())
1124   {
1125     MUTEX_UNLOCK(&mutex);
1126     return 0;
1127   }
1128
1129   ULLONG lengthBytes = extractULLONG();
1130   ULONG lengthFrames = extractULONG();
1131   freePacket();
1132   MUTEX_UNLOCK(&mutex);
1133
1134   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
1135
1136   *totalFrames = lengthFrames;
1137   return lengthBytes;
1138 }