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