]> git.vomp.tv Git - vompclient.git/blob - vdr.cc
Variable width channel numbers
[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::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
608 {
609   UCHAR buffer[20];
610
611   *(unsigned long*)&buffer[0] = htonl(16);
612   *(unsigned long*)&buffer[4] = htonl(VDR_GETBLOCK);
613   *(ULLONG*)&buffer[8]        = htonll(position);
614   *(unsigned long*)&buffer[16] = htonl(maxAmount);
615
616   MUTEX_LOCK(&mutex);
617   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
618
619   int a = tcp->sendPacket(buffer, 20);
620   if (a != 20)
621   {
622     disconnect();
623     MUTEX_UNLOCK(&mutex);
624     return NULL;
625   }
626
627   if (!getPacket())
628   {
629     MUTEX_UNLOCK(&mutex);
630     return NULL;
631   }
632
633   if (serverError())
634   {
635     Log::getInstance()->log("VDR", Log::DEBUG, "Detected getblock 0");
636     freePacket();
637     MUTEX_UNLOCK(&mutex);
638     return NULL;
639   }
640
641   UCHAR* toReturn = packet;
642   *amountReceived = packetLength;
643   // Manually clean up instead of running freePacket to keep the block
644   packet = NULL;
645   packetLength = 0;
646   packetPos = 0;
647   MUTEX_UNLOCK(&mutex);
648
649
650   return toReturn;
651 }
652
653 ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames)
654 {
655   unsigned long totalLength = 8 + strlen(fileName) + 1;
656   UCHAR* buffer = new UCHAR[totalLength];
657
658   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
659   *(unsigned long*)&buffer[4] = htonl(VDR_STREAMRECORDING);
660   strcpy((char*)&buffer[8], fileName);
661
662   MUTEX_LOCK(&mutex);
663   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
664
665   unsigned int a = tcp->sendPacket(buffer, totalLength);
666   delete []buffer;
667
668   if (a != totalLength)
669   {
670     disconnect();
671     MUTEX_UNLOCK(&mutex);
672     return 0;
673   }
674
675   if (!getPacket())
676   {
677     MUTEX_UNLOCK(&mutex);
678     return 0;
679   }
680
681   ULLONG lengthBytes = extractULLONG();
682   ULONG lengthFrames = extractULONG();
683   freePacket();
684   MUTEX_UNLOCK(&mutex);
685
686   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
687
688   *totalFrames = lengthFrames;
689   return lengthBytes;
690 }
691
692 ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)
693 {
694   unsigned long totalLength = 12;
695   UCHAR* buffer = new UCHAR[totalLength];
696
697   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
698   *(unsigned long*)&buffer[4] = htonl(VDR_POSFROMFRAME);
699   *(unsigned long*)&buffer[8] = htonl(frameNumber);
700
701   MUTEX_LOCK(&mutex);
702   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
703
704   unsigned int a = tcp->sendPacket(buffer, totalLength);
705   delete []buffer;
706
707   if (a != totalLength)
708   {
709     disconnect();
710     MUTEX_UNLOCK(&mutex);
711     return 0;
712   }
713
714   if (!getPacket())
715   {
716     MUTEX_UNLOCK(&mutex);
717     return 0;
718   }
719
720   ULLONG position = extractULLONG();
721   freePacket();
722   MUTEX_UNLOCK(&mutex);
723
724   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);
725
726   return position;
727 }
728
729 ULONG VDR::frameNumberFromPosition(ULLONG position)
730 {
731   unsigned long totalLength = 16;
732   UCHAR* buffer = new UCHAR[totalLength];
733
734   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
735   *(unsigned long*)&buffer[4] = htonl(VDR_FRAMEFROMPOS);
736   *(ULLONG*)&buffer[8] = htonll(position);
737
738   MUTEX_LOCK(&mutex);
739   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
740
741   unsigned int a = tcp->sendPacket(buffer, totalLength);
742   delete []buffer;
743
744   if (a != totalLength)
745   {
746     disconnect();
747     MUTEX_UNLOCK(&mutex);
748     return 0;
749   }
750
751   if (!getPacket())
752   {
753     MUTEX_UNLOCK(&mutex);
754     return 0;
755   }
756
757   ULONG framenumber = extractULONG();
758   freePacket();
759   MUTEX_UNLOCK(&mutex);
760
761   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new framenumber is: %u", framenumber);
762
763   return framenumber;
764 }
765
766 bool VDR::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)
767 {
768   unsigned long totalLength = 16;
769   UCHAR* buffer = new UCHAR[totalLength];
770
771   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
772   *(unsigned long*)&buffer[4] = htonl(VDR_GETNEXTIFRAME);
773   *(unsigned long*)&buffer[8] = htonl(frameNumber);
774   *(unsigned long*)&buffer[12] = htonl(direction);
775
776   MUTEX_LOCK(&mutex);
777   if (!connected) { MUTEX_UNLOCK(&mutex); return false; }
778
779   unsigned int a = tcp->sendPacket(buffer, totalLength);
780   delete []buffer;
781
782   if (a != totalLength)
783   {
784     disconnect();
785     MUTEX_UNLOCK(&mutex);
786     return false;
787   }
788
789   if (!getPacket())
790   {
791     MUTEX_UNLOCK(&mutex);
792     return false;
793   }
794
795   if (serverError())
796   {
797     Log::getInstance()->log("VDR", Log::DEBUG, "Detected getNextIFrame error");
798     freePacket();
799     MUTEX_UNLOCK(&mutex);
800     return false;
801   }
802
803   *rfilePosition = extractULLONG();
804   *rframeNumber = extractULONG();
805   *rframeLength = extractULONG();
806
807   freePacket();
808   MUTEX_UNLOCK(&mutex);
809
810 //  Log::getInstance()->log("VDR", Log::DEBUG, "VDR GNIF said %llu %lu %lu", *rfilePosition, *rframeNumber, *rframeLength);
811
812   return true;
813 }
814
815 EventList* VDR::getChannelSchedule(ULONG number)
816 {
817   time_t now;
818   time(&now);
819   return getChannelSchedule(number, now, 24 * 60 * 60);
820 }
821
822 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
823 {
824 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
825   UCHAR buffer[20];
826
827   *(unsigned long*)&buffer[0] = htonl(16);
828   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE);
829   *(unsigned long*)&buffer[8] = htonl(number);
830   *(unsigned long*)&buffer[12] = htonl(start);
831   *(unsigned long*)&buffer[16] = htonl(duration);
832
833   MUTEX_LOCK(&mutex);
834   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
835
836   int a = tcp->sendPacket(buffer, 20);
837
838   if (a != 20)
839   {
840     disconnect();
841     MUTEX_UNLOCK(&mutex);
842     return NULL;
843   }
844
845   if (!getPacket())
846   {
847     MUTEX_UNLOCK(&mutex);
848     return NULL;
849   }
850
851   // received a ulong(0) - schedules error in the plugin
852   if (serverError())
853   {
854     freePacket();
855     MUTEX_UNLOCK(&mutex);
856     return NULL;
857   }
858
859   EventList* eventList = new EventList();
860
861   while (packetPos < packetLength)
862   {
863     Event* event = new Event();
864     event->id = extractULONG();
865     event->time = extractULONG();
866     event->duration = extractULONG();
867     event->title = extractString();
868     event->subtitle = extractString();
869     event->description = extractString();
870     eventList->push_back(event);
871   }
872
873   freePacket();
874   MUTEX_UNLOCK(&mutex);
875
876   Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
877   return eventList;
878 }
879
880 int VDR::configSave(char* section, char* key, const char* value)
881 {
882   ULONG totalLength = 8 + strlen(section) + strlen(key) + strlen(value) + 3; // 8 for headers, 3 for nulls
883   UCHAR* buffer = new UCHAR[totalLength];
884
885   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
886   *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGSAVE);
887
888   int position = 8;
889   strcpy((char*)&buffer[position], section);
890   position += strlen(section) + 1;
891   strcpy((char*)&buffer[position], key);
892   position += strlen(key) + 1;
893   strcpy((char*)&buffer[position], value);
894
895   MUTEX_LOCK(&mutex);
896   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
897
898   unsigned int a = tcp->sendPacket(buffer, totalLength);
899   delete[] buffer;
900
901   if (a != totalLength)
902   {
903     disconnect();
904     MUTEX_UNLOCK(&mutex);
905     return 0;
906   }
907
908   if (!getPacket())
909   {
910     MUTEX_UNLOCK(&mutex);
911     return 0;
912   }
913
914   int toReturn = (int)extractULONG();
915   freePacket();
916   MUTEX_UNLOCK(&mutex);
917
918   return toReturn;
919 }
920
921 char* VDR::configLoad(char* section, char* key)
922 {
923   ULONG totalLength = 8 + strlen(section) + strlen(key) + 2; // 8 for headers, 2 for nulls
924   UCHAR* buffer = new UCHAR[totalLength];
925
926   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
927   *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGLOAD);
928
929   int position = 8;
930   strcpy((char*)&buffer[position], section);
931   position += strlen(section) + 1;
932   strcpy((char*)&buffer[position], key);
933
934   MUTEX_LOCK(&mutex);
935   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
936
937   unsigned int a = tcp->sendPacket(buffer, totalLength);
938   delete[] buffer;
939
940   if (a != totalLength)
941   {
942     disconnect();
943     MUTEX_UNLOCK(&mutex);
944     return NULL;
945   }
946
947   if (!getPacket())
948   {
949     MUTEX_UNLOCK(&mutex);
950     return NULL;
951   }
952   char* toReturn = extractString();
953   freePacket();
954   MUTEX_UNLOCK(&mutex);
955
956   return toReturn;
957 }
958
959 RecTimerList* VDR::getRecTimersList()
960 {
961   UCHAR buffer[8];
962
963   *(unsigned long*)&buffer[0] = htonl(4);
964   *(unsigned long*)&buffer[4] = htonl(VDR_GETTIMERS);
965
966   MUTEX_LOCK(&mutex);
967   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
968
969   int a = tcp->sendPacket(buffer, 8);
970   if (a != 8)
971   {
972     disconnect();
973     MUTEX_UNLOCK(&mutex);
974     return NULL;
975   }
976
977   // reply
978
979   if (!getPacket())
980   {
981     MUTEX_UNLOCK(&mutex);
982     return NULL;
983   }
984
985   RecTimerList* recTimerList = new RecTimerList();
986
987   ULONG numTimers = extractULONG();
988   if (numTimers > 0)
989   {
990     RecTimer* newRecTimer;
991     char* tempString;
992
993     while (packetPos < packetLength)
994     {
995       newRecTimer = new RecTimer();
996       newRecTimer->active = extractULONG();
997       newRecTimer->recording = extractULONG();
998       newRecTimer->pending = extractULONG();
999       newRecTimer->priority = extractULONG();
1000       newRecTimer->lifeTime = extractULONG();
1001       newRecTimer->channelNumber = extractULONG();
1002       newRecTimer->startTime = extractULONG();
1003       newRecTimer->stopTime = extractULONG();
1004
1005       tempString = extractString();
1006       newRecTimer->setFile(tempString);
1007       delete[] tempString;
1008
1009       recTimerList->push_back(newRecTimer);
1010       Log::getInstance()->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
1011         newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
1012         newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
1013     }
1014   }
1015
1016   freePacket();
1017   MUTEX_UNLOCK(&mutex);
1018
1019   sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
1020
1021   return recTimerList;
1022 }
1023
1024 ULONG VDR::setEventTimer(char* timerString)
1025 {
1026   unsigned long totalLength = 8 + strlen(timerString) + 1;
1027   UCHAR* buffer = new UCHAR[totalLength];
1028
1029   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1030   *(unsigned long*)&buffer[4] = htonl(VDR_SETTIMER);
1031   strcpy((char*)&buffer[8], timerString);
1032
1033   MUTEX_LOCK(&mutex);
1034   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1035
1036   unsigned int a = tcp->sendPacket(buffer, totalLength);
1037   delete []buffer;
1038
1039   if (a != totalLength)
1040   {
1041     disconnect();
1042     MUTEX_UNLOCK(&mutex);
1043     return 0;
1044   }
1045
1046   if (!getPacket())
1047   {
1048     MUTEX_UNLOCK(&mutex);
1049     return 0;
1050   }
1051
1052   ULONG toReturn = extractULONG();
1053   freePacket();
1054   MUTEX_UNLOCK(&mutex);
1055
1056   return toReturn;
1057 }
1058
1059 RecInfo* VDR::getRecInfo(char* fileName)
1060 {
1061   unsigned long totalLength = 8 + strlen(fileName) + 1;
1062   UCHAR* buffer = new UCHAR[totalLength];
1063
1064   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1065   *(unsigned long*)&buffer[4] = htonl(VDR_GETRECINFO);
1066   strcpy((char*)&buffer[8], fileName);
1067
1068   MUTEX_LOCK(&mutex);
1069   if (!connected) { MUTEX_UNLOCK(&mutex); return NULL; }
1070
1071   unsigned int a = tcp->sendPacket(buffer, totalLength);
1072   delete []buffer;
1073
1074   if (a != totalLength)
1075   {
1076     disconnect();
1077     MUTEX_UNLOCK(&mutex);
1078     return NULL;
1079   }
1080
1081   if (!getPacket())
1082   {
1083     MUTEX_UNLOCK(&mutex);
1084     return NULL;
1085   }
1086
1087   if (serverError())
1088   {
1089     Log::getInstance()->log("VDR", Log::DEBUG, "Could not get rec info");
1090     freePacket();
1091     MUTEX_UNLOCK(&mutex);
1092     return NULL;
1093   }
1094
1095   TCP::dump(packet, packetLength);
1096
1097   RecInfo* recInfo = new RecInfo();
1098
1099   recInfo->timerStart = extractULONG();
1100   recInfo->timerEnd = extractULONG();
1101   recInfo->resumePoint = extractULONG();
1102   recInfo->summary = extractString();
1103
1104   ULONG numComponents = extractULONG();
1105   if (numComponents)
1106   {
1107     recInfo->setNumComponents(numComponents);
1108     for (ULONG i = 0; i < numComponents; i++)
1109     {
1110       recInfo->streams[i] = extractUCHAR();
1111       recInfo->types[i] = extractUCHAR();
1112       recInfo->languages[i] = extractString();
1113       recInfo->descriptions[i] = extractString();
1114     }
1115   }
1116
1117   recInfo->print();
1118
1119   freePacket();
1120   MUTEX_UNLOCK(&mutex);
1121   return recInfo;
1122 }
1123
1124 // FIXME obselete
1125 ULLONG VDR::rescanRecording(ULONG* totalFrames)
1126 {
1127   unsigned long totalLength = 8;
1128   UCHAR* buffer = new UCHAR[totalLength];
1129
1130   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1131   *(unsigned long*)&buffer[4] = htonl(VDR_RESCANRECORDING);
1132
1133   MUTEX_LOCK(&mutex);
1134   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1135
1136   unsigned int a = tcp->sendPacket(buffer, totalLength);
1137   delete []buffer;
1138
1139   if (a != totalLength)
1140   {
1141     disconnect();
1142     MUTEX_UNLOCK(&mutex);
1143     return 0;
1144   }
1145
1146   if (!getPacket())
1147   {
1148     MUTEX_UNLOCK(&mutex);
1149     return 0;
1150   }
1151
1152   ULLONG lengthBytes = extractULLONG();
1153   ULONG lengthFrames = extractULONG();
1154   freePacket();
1155   MUTEX_UNLOCK(&mutex);
1156
1157   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
1158
1159   *totalFrames = lengthFrames;
1160   return lengthBytes;
1161 }
1162
1163 MarkList* VDR::getMarks(char* fileName)
1164 {
1165   unsigned long totalLength = 8 + strlen(fileName) + 1;
1166   UCHAR* buffer = new UCHAR[totalLength];
1167
1168   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1169   *(unsigned long*)&buffer[4] = htonl(VDR_GETMARKS);
1170   strcpy((char*)&buffer[8], fileName);
1171
1172   MUTEX_LOCK(&mutex);
1173   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1174
1175   unsigned int a = tcp->sendPacket(buffer, totalLength);
1176   delete []buffer;
1177
1178   if (a != totalLength)
1179   {
1180     disconnect();
1181     MUTEX_UNLOCK(&mutex);
1182     return NULL;
1183   }
1184
1185   if (!getPacket())
1186   {
1187     MUTEX_UNLOCK(&mutex);
1188     return NULL;
1189   }
1190
1191   if (serverError())
1192   {
1193     MUTEX_UNLOCK(&mutex);
1194     return NULL;
1195   }
1196
1197   MarkList* markList = new MarkList();
1198
1199   while (packetPos < packetLength)
1200   {
1201     Mark* mark = new Mark();
1202     mark->pos = extractULONG();
1203
1204     markList->push_back(mark);
1205     Log::getInstance()->log("VDR", Log::DEBUG, "Have added a mark to list. %lu", mark->pos);
1206   }
1207
1208   freePacket();
1209   MUTEX_UNLOCK(&mutex);
1210
1211   return markList;
1212 }
1213
1214 void VDR::getChannelPids(Channel* channel)
1215 {
1216   UCHAR buffer[12];
1217
1218   *(unsigned long*)&buffer[0] = htonl(8);
1219   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELPIDS);
1220   *(unsigned long*)&buffer[8] = htonl(channel->number);
1221
1222   MUTEX_LOCK(&mutex);
1223   if (!connected) { MUTEX_UNLOCK(&mutex); return ; }
1224
1225   int a = tcp->sendPacket(buffer, 12);
1226
1227   if (a != 12)
1228   {
1229     disconnect();
1230     MUTEX_UNLOCK(&mutex);
1231     return ;
1232   }
1233
1234   if (!getPacket())
1235   {
1236     MUTEX_UNLOCK(&mutex);
1237     return ;
1238   }
1239
1240   // Format of response
1241   // vpid
1242   // number of apids
1243   // {
1244   //    apid
1245   //    lang string
1246   // }
1247
1248   channel->vpid = extractULONG();
1249   channel->numAPids = extractULONG();
1250
1251   for (ULONG i = 0; i < channel->numAPids; i++)
1252   {
1253     apid newapid;
1254     newapid.pid = extractULONG();
1255     newapid.name = extractString();
1256     channel->apids.push_back(newapid);
1257   }
1258
1259   freePacket();
1260   MUTEX_UNLOCK(&mutex);
1261
1262   return ;
1263 }