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