]> git.vomp.tv Git - vompclient.git/blob - vdr.cc
Start of new live tv
[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 #include "recman.h"
24 #include "tcp.h"
25 #include "log.h"
26 #include "recinfo.h"
27 #include "dsock.h"
28 #include "channel.h"
29 #include "event.h"
30 #include "wol.h"
31 #include "vdrrequestpacket.h"
32 #include "vdrresponsepacket.h"
33
34 VDR* VDR::instance = NULL;
35
36 VDR::VDR()
37 {
38   if (instance) return;
39   instance = this;
40   initted = 0;
41   findingServer = 0;
42   tcp = NULL;
43   connected = false;
44   maxChannelNumber = 0;
45   channelNumberWidth = 1;
46 }
47
48 VDR::~VDR()
49 {
50   instance = NULL;
51   if (initted) shutdown();
52 }
53
54 VDR* VDR::getInstance()
55 {
56   return instance;
57 }
58
59 int VDR::init(int tport)
60 {
61   if (initted) return 0;
62   initted = 1;
63   port = tport;
64   logger = Log::getInstance();
65   return 1;
66 }
67
68 int VDR::shutdown()
69 {
70   if (!initted) return 0;
71   initted = 0;
72   disconnect();
73   return 1;
74 }
75
76 void VDR::findServers(vector<VDRServer>& servers)
77 {
78   Wol* wol = Wol::getInstance();
79   findingServer = 1;
80   char* message = "VOMP";
81
82   DatagramSocket ds(port);
83   int haveAtLeastOne = 0;
84   int retval;
85   int waitType = 1;
86   bool firstloop = true;
87   while(findingServer)
88   {
89     if (waitType == 1)
90     {
91       ds.shutdown();
92       ds.init();
93       logger->log("VDR", Log::NOTICE, "Broadcasting for server");
94       ds.send("255.255.255.255", 3024, message, strlen(message));
95       if(!firstloop) wol->doWakeUp();
96     }
97     retval = ds.waitforMessage(waitType);
98
99     if (retval == 2) // we got a reply
100     {
101       if (!strcmp(ds.getData(), "VOMP")) // echo.....
102       {
103         waitType = 2;
104       }
105       else
106       {
107         VDRServer newServer;
108         newServer.ip = new char[16];
109         strcpy(newServer.ip, ds.getFromIPA());
110
111         if (ds.getDataLength() == 0)
112         {
113           newServer.name = new char[1];
114           newServer.name[0] = '\0';
115         }
116         else
117         {
118           newServer.name = new char[strlen(ds.getData())+1];
119           strcpy(newServer.name, ds.getData());
120         }
121
122         servers.push_back(newServer);
123         waitType = 2;
124         haveAtLeastOne = 1;
125       }
126     }
127     else
128     {
129       if (haveAtLeastOne) break;
130       waitType = 1;
131       firstloop = false;
132     }
133   }
134   sort(servers.begin(), servers.end(), ServerSorter());
135 }
136
137 void VDR::cancelFindingServer()
138 {
139   findingServer = 0;
140 }
141
142 void VDR::setServerIP(char* newIP)
143 {
144   strcpy(serverIP, newIP);
145 }
146
147 int VDR::connect()
148 {
149   maxChannelNumber = 0;
150   channelNumberWidth = 1;
151
152   if (tcp) delete tcp;
153   tcp = new TCP();
154   if (tcp->connectTo(serverIP, 3024))
155   {
156     connected = true;
157     threadStart();
158     return 1;
159   }
160   else
161   {
162     return 0;
163   }
164 }
165
166 void VDR::disconnect()
167 {
168   threadCancel();
169   if (tcp) delete tcp;
170   tcp = NULL;
171   connected = false;
172   Log::getInstance()->log("VDR", Log::DEBUG, "Disconnect");
173 }
174
175 void VDR::setReceiveWindow(size_t size)
176 {
177   if (connected) tcp->setReceiveWindow(size);
178 }
179
180 ///////////////////////////////////////////////////////
181
182 void VDR::threadMethod()
183 {
184   threadSetKillable();
185   
186   ULONG channelID;
187   
188   ULONG requestID;
189   ULONG userDataLength;
190   UCHAR* userData;
191
192   ULONG streamID;
193
194   VDR_ResponsePacket* vresp;
195   
196   while(1) 
197   {  
198     if (!tcp->readData((UCHAR*)&channelID, sizeof(ULONG)))
199     {
200       // Error or timeout.
201       Log::getInstance()->log("VDR", Log::DEBUG, "Net read timeout");
202       
203       // Do timeouts
204       
205       continue;      
206     }
207     
208     vresp = new VDR_ResponsePacket();  
209     
210     if (channelID == CHANNEL_REQUEST_RESPONSE)
211     {
212       if (!tcp->readData((UCHAR*)&requestID, sizeof(ULONG))) break;
213       if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break;
214       if (userDataLength > 5000000) break; // how big can these packets get?
215       if (userDataLength > 0)
216       {
217         userData = (UCHAR*)malloc(userDataLength);
218         if (!userData) break;
219         if (!tcp->readData(userData, userDataLength)) break;
220       }
221       else
222       {
223         userData = NULL;
224       }
225       vresp->setResponse(requestID, userData, userDataLength);
226       Log::getInstance()->log("VDR", Log::DEBUG, "Rxd a response packet, requestID=%lu, len=%lu", requestID, userDataLength);
227     }
228     else if (channelID == CHANNEL_STREAM)
229     {
230       if (!tcp->readData((UCHAR*)&streamID, sizeof(ULONG))) break;
231       if (!tcp->readData((UCHAR*)&userDataLength, sizeof(ULONG))) break; 
232       if (userDataLength > 0)
233       {
234         userData = (UCHAR*)malloc(userDataLength);
235         if (!userData) break;
236         if (!tcp->readData(userData, userDataLength)) break;
237       }
238       else
239       {
240         userData = NULL;
241       }
242       vresp->setStream(streamID, userData, userDataLength);
243       Log::getInstance()->log("VDR", Log::DEBUG, "Rxd a stream packet, streamID=%lu, len=%lu", streamID, userDataLength);
244     }
245     else
246     {
247       Log::getInstance()->log("VDR", Log::ERR, "Rxd a response packet on channel %lu !!", channelID);
248       delete vresp;
249       break;
250     }
251
252     if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() )
253     {
254       // If edFindAndCall returns true, edr was called and vresp was handed off.
255       // else, delete vresp here.
256       delete vresp;
257     }
258     
259     // Who deletes vresp?
260     // If RR, the individual protocol functions must delete vresp.
261     // If stream, the data and length is taken out in ed_cb_call and vresp is deleted there.
262   }
263 }
264
265 bool VDR::ed_cb_find(EDReceiver* edr, void* userTag)
266 {
267   // edr is a VDR_PacketReceiver object made in VDR::RequestResponse
268   // userTag is a VDR_ResponsePacket made in threadMethod
269
270   VDR_PacketReceiver* vdrpr = (VDR_PacketReceiver*)edr;
271   VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag;
272   
273   // Is vresp for vdrpr ?
274   
275   ULONG packetChannel = vresp->getChannelID();
276   if (vdrpr->receiverChannel != packetChannel) return false;
277
278   if (packetChannel == CHANNEL_REQUEST_RESPONSE)
279   {
280     if (vdrpr->requestSerialNumber == vresp->getRequestID()) return true;
281   }
282   else if (packetChannel == CHANNEL_STREAM)
283   {
284     if (vdrpr->streamID == vresp->getStreamID()) return true;
285   }
286  
287   return false;
288 }
289
290 VDR_ResponsePacket* VDR::RequestResponse(VDR_RequestPacket* vrp)
291 {
292   logger->log("VDR", Log::DEBUG, "RR %lu", vrp->getOpcode());
293
294   if (!connected)
295   {
296     VDR_ResponsePacket* vresp = new VDR_ResponsePacket();
297     return vresp; // "no-response" return
298   }
299
300   // ED make new VDR and register
301   // make a VDR_PacketReceiver
302   // - init with serial number of request packet
303
304   VDR_PacketReceiver vdrpr;
305   vdrpr.receiverChannel = VDR::CHANNEL_REQUEST_RESPONSE;
306   vdrpr.requestSerialNumber = vrp->getSerial();
307   edRegister(&vdrpr);
308   
309   edLock();  
310   if ((ULONG)tcp->sendData(vrp->getPtr(), vrp->getLen()) != vrp->getLen())
311   {
312     edUnlock();
313     edUnregister(&vdrpr);
314     VDR_ResponsePacket* vresp = new VDR_ResponsePacket();
315     return vresp; // "no-response" return
316   }
317
318   // Sleep and block this thread. The sleep unlocks the mutex
319   logger->log("VDR", Log::DEBUG, "RR sleep");
320   edSleepThisReceiver(&vdrpr);
321   logger->log("VDR", Log::DEBUG, "RR unsleep");
322     
323   // Woken because a response packet has arrived, mutex will be locked
324   
325   edUnlock();
326   return vdrpr.save_vresp;
327 }
328
329 /////////////////////////////////////////////////////////////////////////////
330
331 // Here VDR takes a break for the VDR_PacketReceiver helper class
332
333 bool VDR_PacketReceiver::call(void* userTag)
334 {
335   if (receiverChannel == VDR::CHANNEL_REQUEST_RESPONSE)
336   {
337     // It's a RR. Save vresp and, signal the waiting thread and return.
338     // VDR::RequestResponse will be blocking waiting for this to happen.
339     // That function has a pointer to this object and can read save_vresp.
340     save_vresp = (VDR_ResponsePacket*)userTag;
341     return true; // Signals ED to remove edr from receivers and wake up edr thread
342   }
343   
344   if (receiverChannel == VDR::CHANNEL_STREAM)
345   {
346     // It's a stream packet.
347     streamReceiver->streamReceive(NULL, 0);
348     delete (VDR_ResponsePacket*)userTag;
349     return false;
350   }
351
352   abort(); // unknown receiverChannel, should not happen
353 }
354
355 /////////////////////////////////////////////////////////////////////////////
356
357 int VDR::doLogin()
358 {
359   VDR_RequestPacket vrp;
360   if (!vrp.init(VDR_LOGIN, true, 6)) return 0;
361
362   char* mactemp[6];
363   tcp->getMAC((char*)mactemp);
364   if (!vrp.copyin((UCHAR*)mactemp, 6)) return 0;
365
366   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
367   if (vresp->noResponse()) { delete vresp; return 0; }
368
369   ULONG vdrTime = vresp->extractULONG();
370   logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
371   long vdrTimeOffset = vresp->extractLONG();
372   logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
373
374   delete vresp;
375
376   // Set the time and zone on the MVP
377
378 #ifndef WIN32
379   struct timespec currentTime;
380   currentTime.tv_sec = vdrTime;
381   currentTime.tv_nsec = 0;
382   int b = clock_settime(CLOCK_REALTIME, &currentTime);
383
384   logger->log("VDR", Log::DEBUG, "set clock = %u", b);
385
386   // now make a TZ variable and set it
387   char sign;
388   int hours;
389   int minutes;
390   if (vdrTimeOffset > 0) sign = '-';
391   else sign = '+';
392
393   vdrTimeOffset = abs(vdrTimeOffset);
394
395   hours = (int)vdrTimeOffset / 3600;
396   minutes = vdrTimeOffset % 3600;
397
398   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
399
400   minutes = (int)minutes / 60;
401
402   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
403
404   char newTZ[30];
405   sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
406   setenv("TZ", newTZ, 1);
407
408   logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
409 #endif
410
411   return 1;
412 }
413
414 bool VDR::getRecordingsList(RecMan* recman)
415 {
416   VDR_RequestPacket vrp;
417   if (!vrp.init(VDR_GETRECORDINGLIST, true, 0)) return false;
418
419   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
420   if (vresp->noResponse()) { delete vresp; return false; }
421   
422   ULONG totalSpace = vresp->extractULONG();
423   ULONG freeSpace = vresp->extractULONG();
424   ULONG percent = vresp->extractULONG();
425   recman->setStats(totalSpace, freeSpace, percent);
426
427   ULONG start;
428   char* name;
429   char* fileName;
430
431   while (!vresp->end())
432   {
433     start = vresp->extractULONG();
434     name = vresp->extractString();
435     fileName = vresp->extractString();
436
437     recman->addEntry(start, name, fileName);
438
439     delete[] name;
440     delete[] fileName;
441   }
442
443   delete vresp;
444
445   return true;
446 }
447
448 int VDR::deleteRecording(char* fileName)
449 {
450   VDR_RequestPacket vrp;
451   if (!vrp.init(VDR_DELETERECORDING, true, strlen(fileName) + 1)) return 0;
452   if (!vrp.addString(fileName)) return 0;
453   
454   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
455   if (vresp->noResponse()) { delete vresp; return 0; }
456   
457   int toReturn = (int)vresp->extractULONG();
458   delete vresp;
459
460   return toReturn;
461 }
462
463 char* VDR::moveRecording(char* fileName, char* newPath)
464 {
465   VDR_RequestPacket vrp;
466   if (!vrp.init(VDR_MOVERECORDING, true, strlen(fileName) + 1 + strlen(newPath) + 1)) return NULL;
467   if (!vrp.addString(fileName)) return NULL;
468   if (!vrp.addString(newPath)) return NULL;
469   
470   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
471   if (vresp->noResponse()) { delete vresp; return NULL; }
472   
473   char* toReturn = NULL;
474   int success = (int)vresp->extractULONG();
475   if (success == 1)
476   {
477     toReturn = vresp->extractString();
478   }
479
480   delete vresp;
481
482   return toReturn;
483 }
484
485 ChannelList* VDR::getChannelsList(ULONG type)
486 {
487   VDR_RequestPacket vrp;
488   if (!vrp.init(VDR_GETCHANNELLIST, true, 0)) return NULL;
489
490   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
491   if (vresp->noResponse()) { delete vresp; return NULL; }
492   
493   ChannelList* chanList = new ChannelList();
494
495   while (!vresp->end())
496   {
497     Channel* chan = new Channel();
498     chan->number = vresp->extractULONG();
499     chan->type = vresp->extractULONG();
500     chan->name = vresp->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       if (chan->number > maxChannelNumber) maxChannelNumber = chan->number;
507     }
508     else
509     {
510       delete chan;
511     }
512   }
513
514   delete vresp;
515
516   if (maxChannelNumber > 99999)
517     channelNumberWidth = 6;
518   else if (maxChannelNumber > 9999)
519     channelNumberWidth = 5;
520   else if (maxChannelNumber > 999)
521     channelNumberWidth = 4;
522   else if (maxChannelNumber > 99)
523     channelNumberWidth = 3;
524   else if (maxChannelNumber > 9)
525     channelNumberWidth = 2;
526   else
527     channelNumberWidth = 1;
528
529   return chanList;
530 }
531
532
533 int VDR::streamChannel(ULONG number)
534 {
535   // FIXME radio
536   return 0;
537 }
538
539 int VDR::streamChannel(ULONG number, StreamReceiver* tstreamReceiver)
540 {
541   VDR_RequestPacket vrp;
542   if (!vrp.init(VDR_STREAMCHANNEL, true, sizeof(ULONG))) return 0;
543   if (!vrp.addULONG(number)) return 0;
544   
545   
546   VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver(); // FIXME - leaked
547   vdrpr->receiverChannel = VDR::CHANNEL_STREAM;
548   vdrpr->streamID = vrp.getSerial();
549   vdrpr->streamReceiver = tstreamReceiver;
550   edRegister(vdrpr);
551   
552   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
553   if (vresp->noResponse())
554   {
555     delete vresp;
556     edUnregister(vdrpr);
557     delete vdrpr;
558     return 0;
559   }
560   
561   int toReturn = (int)vresp->extractULONG();
562   delete vresp;
563
564   return toReturn;
565 }
566
567 int VDR::stopStreaming()
568 {
569   VDR_RequestPacket vrp;
570   if (!vrp.init(VDR_STOPSTREAMING, true, 0)) return 0;
571
572   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
573   if (vresp->noResponse()) { delete vresp; return 0; }
574   
575   int toReturn = (int)vresp->extractULONG();
576   delete vresp;
577
578   return toReturn;
579 }
580
581 UCHAR* VDR::getImageBlock(ULONG position, UINT maxAmount, UINT* amountReceived)
582 {
583   return getBlock(position, maxAmount, amountReceived, VDR_GETIMAGEBLOCK);
584 }
585
586 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
587 {
588   return getBlock(position, maxAmount, amountReceived, VDR_GETBLOCK);
589 }
590
591 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived, ULONG cmd)
592 {
593   VDR_RequestPacket vrp;
594   if (!vrp.init(cmd, true, sizeof(ULLONG) + sizeof(ULONG))) return NULL;
595   if (!vrp.addULLONG(position)) return NULL;
596   if (!vrp.addULONG(maxAmount)) return NULL;
597
598   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
599   if (vresp->noResponse()) { delete vresp; return NULL; }
600
601   if (vresp->serverError())
602   {
603     Log::getInstance()->log("VDR", Log::DEBUG, "Detected getblock 0");
604     delete vresp;
605     return NULL;
606   }
607
608   // Special handling for getblock
609   UCHAR* toReturn = vresp->getBlock_getUserData();
610   *amountReceived = vresp->getUserDataLength();
611   
612   delete vresp;
613   
614   return toReturn;
615 }
616
617 ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames)
618 {
619   VDR_RequestPacket vrp;
620   if (!vrp.init(VDR_STREAMRECORDING, true, strlen(fileName) + 1)) return 0;
621   if (!vrp.addString(fileName)) return 0;
622
623   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
624   if (vresp->noResponse()) { delete vresp; return 0; }
625   
626   ULLONG lengthBytes = vresp->extractULLONG();
627   ULONG lengthFrames = vresp->extractULONG();
628   delete vresp;
629
630   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
631
632   *totalFrames = lengthFrames;
633   return lengthBytes;
634 }
635
636 ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)
637 {
638   VDR_RequestPacket vrp;
639   if (!vrp.init(VDR_POSFROMFRAME, true, sizeof(ULONG))) return 0;
640   if (!vrp.addULONG(frameNumber)) return 0;
641
642   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
643   if (vresp->noResponse()) { delete vresp; return 0; }
644   
645   ULLONG position = vresp->extractULLONG();
646   delete vresp;
647   
648   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);
649
650   return position;
651 }
652
653 ULONG VDR::frameNumberFromPosition(ULLONG position)
654 {
655   VDR_RequestPacket vrp;
656   if (!vrp.init(VDR_FRAMEFROMPOS, true, sizeof(ULLONG))) return 0;
657   if (!vrp.addULLONG(position)) return 0;
658
659   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
660   if (vresp->noResponse()) { delete vresp; return 0; }
661   
662   ULONG framenumber = vresp->extractULONG();
663   delete vresp;
664   
665   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new framenumber is: %u", framenumber);
666
667   return framenumber;
668 }
669
670 bool VDR::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)
671 {
672   VDR_RequestPacket vrp;
673   if (!vrp.init(VDR_GETNEXTIFRAME, true, sizeof(ULONG)*2)) return false;
674   if (!vrp.addULONG(frameNumber)) return false;
675   if (!vrp.addULONG(direction)) return false;
676
677   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
678   if (vresp->noResponse()) { delete vresp; return false; }
679   
680   if (vresp->serverError())
681   {
682     Log::getInstance()->log("VDR", Log::DEBUG, "Detected getNextIFrame error");
683     delete vresp;
684     return false;
685   }
686
687   *rfilePosition = vresp->extractULLONG();
688   *rframeNumber = vresp->extractULONG();
689   *rframeLength = vresp->extractULONG();
690
691   delete vresp;
692
693 //  Log::getInstance()->log("VDR", Log::DEBUG, "VDR GNIF said %llu %lu %lu", *rfilePosition, *rframeNumber, *rframeLength);
694
695   return true;
696 }
697
698 EventList* VDR::getChannelSchedule(ULONG number)
699 {
700   time_t now;
701   time(&now);
702   return getChannelSchedule(number, now, 24 * 60 * 60);
703 }
704
705 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
706 {
707 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
708
709   VDR_RequestPacket vrp;
710   if (!vrp.init(VDR_GETCHANNELSCHEDULE, true, sizeof(ULONG)*3)) return NULL;
711   if (!vrp.addULONG(number)) return NULL;
712   if (!vrp.addULONG(start)) return NULL;
713   if (!vrp.addULONG(duration)) return NULL;
714
715   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
716   if (vresp->noResponse()) { delete vresp; return NULL; }
717   
718   // received a ulong(0) - schedules error in the plugin
719   if (vresp->serverError())
720   {
721     delete vresp;
722     return NULL;
723   }
724
725   EventList* eventList = new EventList();
726
727   while (!vresp->end())
728   {
729     Event* event = new Event();
730     event->id = vresp->extractULONG();
731     event->time = vresp->extractULONG();
732     event->duration = vresp->extractULONG();
733     event->title = vresp->extractString();
734     event->subtitle = vresp->extractString();
735     event->description = vresp->extractString();
736     eventList->push_back(event);
737   }
738
739   delete vresp;
740
741   Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
742   return eventList;
743 }
744
745 int VDR::configSave(const char* section, const char* key, const char* value)
746 {
747   VDR_RequestPacket vrp;
748   if (!vrp.init(VDR_CONFIGSAVE, false, 0)) return 0;
749   if (!vrp.addString(section)) return 0;
750   if (!vrp.addString(key)) return 0;
751   if (!vrp.addString(value)) return 0;
752
753   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
754   if (vresp->noResponse()) { delete vresp; return 0; }
755   
756   int toReturn = (int)vresp->extractULONG();
757   delete vresp;
758
759   return toReturn;
760 }
761
762 char* VDR::configLoad(const char* section, const char* key)
763 {
764   VDR_RequestPacket vrp;
765   if (!vrp.init(VDR_CONFIGLOAD, false, 0)) return NULL;
766   if (!vrp.addString(section)) return NULL;
767   if (!vrp.addString(key)) return NULL;
768
769   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
770   if (vresp->noResponse()) { delete vresp; return NULL; }
771   
772   char* toReturn = vresp->extractString();
773   delete vresp;
774
775   return toReturn;
776 }
777
778 RecTimerList* VDR::getRecTimersList()
779 {
780   VDR_RequestPacket vrp;
781   if (!vrp.init(VDR_GETTIMERS, true, 0)) return NULL;
782
783   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
784   if (vresp->noResponse()) { delete vresp; return NULL; }
785
786   RecTimerList* recTimerList = new RecTimerList();
787
788   ULONG numTimers = vresp->extractULONG();
789   if (numTimers > 0)
790   {
791     RecTimer* newRecTimer;
792     char* tempString;
793
794     while (!vresp->end())
795     {
796       newRecTimer = new RecTimer();
797       newRecTimer->active = vresp->extractULONG();
798       newRecTimer->recording = vresp->extractULONG();
799       newRecTimer->pending = vresp->extractULONG();
800       newRecTimer->priority = vresp->extractULONG();
801       newRecTimer->lifeTime = vresp->extractULONG();
802       newRecTimer->channelNumber = vresp->extractULONG();
803       newRecTimer->startTime = vresp->extractULONG();
804       newRecTimer->stopTime = vresp->extractULONG();
805       newRecTimer->day = vresp->extractULONG();
806       newRecTimer->weekDays = vresp->extractULONG();
807
808       tempString = vresp->extractString();
809       newRecTimer->setFile(tempString);
810       delete[] tempString;
811
812       recTimerList->push_back(newRecTimer);
813       Log::getInstance()->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
814         newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
815         newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
816     }
817   }
818
819   delete vresp;
820
821   sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
822
823   return recTimerList;
824 }
825
826 ULONG VDR::setEventTimer(char* timerString)
827 {
828   VDR_RequestPacket vrp;
829   if (!vrp.init(VDR_SETTIMER, true, strlen(timerString) + 1)) return 0;
830   if (!vrp.addString(timerString)) return 0;
831
832   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
833   if (vresp->noResponse()) { delete vresp; return 0; }
834   
835   ULONG toReturn = vresp->extractULONG();
836   delete vresp;
837
838   return toReturn;
839 }
840
841 RecInfo* VDR::getRecInfo(char* fileName)
842 {
843   VDR_RequestPacket vrp;
844   if (!vrp.init(VDR_GETRECINFO, true, strlen(fileName) + 1)) return NULL;
845   if (!vrp.addString(fileName)) return NULL;
846   
847   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
848   if (vresp->noResponse()) { delete vresp; return NULL; }
849   
850   if (vresp->serverError())
851   {
852     Log::getInstance()->log("VDR", Log::DEBUG, "Could not get rec info");
853     delete vresp;
854     return NULL;
855   }
856
857   RecInfo* recInfo = new RecInfo();
858
859   recInfo->timerStart = vresp->extractULONG();
860   recInfo->timerEnd = vresp->extractULONG();
861   recInfo->resumePoint = vresp->extractULONG();
862   recInfo->summary = vresp->extractString();
863
864   ULONG numComponents = vresp->extractULONG();
865   if (numComponents)
866   {
867     recInfo->setNumComponents(numComponents);
868     for (ULONG i = 0; i < numComponents; i++)
869     {
870       recInfo->streams[i] = vresp->extractUCHAR();
871       recInfo->types[i] = vresp->extractUCHAR();
872       recInfo->languages[i] = vresp->extractString();
873       recInfo->descriptions[i] = vresp->extractString();
874     }
875   }
876
877   recInfo->print();
878
879   delete vresp;
880   return recInfo;
881 }
882
883 // FIXME obselete
884 ULLONG VDR::rescanRecording(ULONG* totalFrames)
885 {
886   VDR_RequestPacket vrp;
887   if (!vrp.init(VDR_RESCANRECORDING, true, 0)) return 0;
888
889   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
890   if (vresp->noResponse()) { delete vresp; return 0; }
891   
892   ULLONG lengthBytes = vresp->extractULLONG();
893   ULONG lengthFrames = vresp->extractULONG();
894   delete vresp;
895   
896   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
897
898   *totalFrames = lengthFrames;
899   return lengthBytes;
900 }
901
902 MarkList* VDR::getMarks(char* fileName)
903 {
904   VDR_RequestPacket vrp;
905   if (!vrp.init(VDR_GETMARKS, true, strlen(fileName) + 1)) return NULL;
906   if (!vrp.addString(fileName)) return NULL;
907
908   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
909   if (vresp->noResponse()) { delete vresp; return NULL; }
910   
911   if (vresp->serverError())
912   {
913     delete vresp;
914     return NULL;
915   }
916
917   MarkList* markList = new MarkList();
918
919   while (!vresp->end())
920   {
921     Mark* mark = new Mark();
922     mark->pos = vresp->extractULONG();
923
924     markList->push_back(mark);
925     Log::getInstance()->log("VDR", Log::DEBUG, "Have added a mark to list. %lu", mark->pos);
926   }
927
928   delete vresp;
929   
930   return markList;
931 }
932
933 void VDR::getChannelPids(Channel* channel)
934 {
935   VDR_RequestPacket vrp;
936   if (!vrp.init(VDR_GETCHANNELPIDS, true, sizeof(ULONG))) return ;
937   if (!vrp.addULONG(channel->number)) return ;
938
939   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
940   if (vresp->noResponse()) { delete vresp; return ; }
941   
942   // Format of response
943   // vpid
944   // number of apids
945   // {
946   //    apid
947   //    lang string
948   // }
949
950   channel->vpid = vresp->extractULONG();
951   channel->numAPids = vresp->extractULONG();
952
953   for (ULONG i = 0; i < channel->numAPids; i++)
954   {
955     apid newapid;
956     newapid.pid = vresp->extractULONG();
957     newapid.name = vresp->extractString();
958     channel->apids.push_back(newapid);
959   }
960
961   delete vresp;
962   
963   return ;
964 }
965
966 /**
967   * media List Request:
968   * 4 flags (currently unused)
969   * n dirname
970   * n+1 0
971   * Media List response:
972   * 4 length
973   * 4 VDR_
974   * 4 numentries
975   * per entry:
976   * 4 media type
977   * 4 time stamp
978   * 4 flags
979   * 4 strlen (incl. 0 Byte)
980   * string
981   * 0
982 */
983 MediaList* VDR::getMediaList(const char* parent,int mediaType)
984 {
985   Log::getInstance()->log("VDR", Log::DEBUG, "getMediaList %s,type=%d", (parent?parent:"NULL"), mediaType);
986
987   VDR_RequestPacket vrp;
988   if (!vrp.init(VDR_GETMEDIALIST, false, 0)) return NULL;
989   if (!vrp.addULONG(0)) return NULL; // unused flags
990
991   //name
992   if (parent) {
993     if (!vrp.addString(parent)) return NULL;
994   }
995     
996   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
997   if (vresp->noResponse()) { delete vresp; return NULL; }
998   
999   if (vresp->serverError())
1000   {
1001     delete vresp;
1002     return NULL;
1003   }
1004   
1005   if (vresp->getUserDataLength() < 12)
1006   {
1007     Log::getInstance()->log("VDR", Log::ERR, "receiveMediaList packet too short, expected 12, got %d", vresp->getUserDataLength());
1008     delete vresp;
1009     return NULL;
1010   }
1011
1012   MediaList* mediaList = new MediaList();
1013   ULONG code=0;
1014   code = vresp->extractULONG();
1015   ULONG numEntries = vresp->extractULONG();
1016   Log::getInstance()->log("VDR", Log::DEBUG, "receiveMediaList with %d entries",numEntries);
1017   while (!vresp->end() && numEntries >0)
1018   {
1019     Media* m = new Media();
1020     ULONG mtype = vresp->extractULONG();
1021     ULONG mtime=vresp->extractULONG();
1022     ULONG flags=0;
1023     flags=vresp->extractULONG();
1024     ULONG stsize=vresp->extractULONG();
1025     char * name=vresp->extractString();
1026     if (! name || stsize != (strlen(name)+1)) {
1027       Log::getInstance()->log("VDR", Log::ERR, "receiveMediaList invalid packet entry, read size %d, strlen %d", stsize, strlen(name)+1);
1028       delete m;
1029       delete mediaList;
1030       delete vresp;
1031       return NULL;
1032       }
1033     //ignore . and .. entries
1034     if (strcmp(name,".") == 0 || strcmp(name,"..")==0) {
1035   delete m;
1036   continue;
1037     }
1038     m->setFileName(name);
1039     m->setTime(mtime);
1040     m->setMediaType(mtype);
1041     mediaList->push_back(m);
1042     Log::getInstance()->log("VDR", Log::DEBUG, "Have added a media to list. %s, type=%d, time=%d", name,mtype,mtime);
1043     numEntries--;
1044   }
1045
1046   delete vresp;
1047   return mediaList;
1048 }
1049
1050 /**
1051   * get image Request:
1052   * 4 flags (currently unused)
1053   * 4 x size
1054   * 4 y size
1055   * n filename
1056   * n+1 0
1057   * get image response:
1058   * 4 length
1059   * 4 VDR_GETIMAGE
1060   * 4 len of image
1061 */
1062 ULONG VDR::loadImage(const char* fileName, ULONG x, ULONG y)
1063 {
1064   VDR_RequestPacket vrp;
1065   if (!vrp.init(VDR_GETIMAGE, false, 0)) return 0;
1066   if (!vrp.addULONG(0)) return 0; // unused flags
1067   if (!vrp.addULONG(x)) return 0;
1068   if (!vrp.addULONG(y)) return 0;
1069   if (!vrp.addString(fileName)) return 0;
1070
1071   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1072   if (vresp->noResponse()) { delete vresp; return 0; }
1073
1074   ULONG cmd = vresp->extractULONG();
1075   ULONG lengthBytes = vresp->extractULONG();
1076   delete vresp;
1077
1078   Log::getInstance()->log("VDR", Log::DEBUG, "getImage %s: cmd=%lu len=%lu", fileName, cmd, lengthBytes);
1079   return lengthBytes;
1080 }
1081
1082 int VDR::deleteTimer(RecTimer* delTimer)
1083 {
1084   Log::getInstance()->log("VDR", Log::DEBUG, "Delete timer called");
1085   
1086   VDR_RequestPacket vrp;
1087   if (!vrp.init(VDR_DELETETIMER, false, 0)) return 0;
1088   if (!vrp.addULONG(delTimer->channelNumber)) return 0;
1089   if (!vrp.addULONG(delTimer->weekDays)) return 0;    
1090   if (!vrp.addULONG(delTimer->day)) return 0;
1091   if (!vrp.addULONG(delTimer->startTime)) return 0;  
1092   if (!vrp.addULONG(delTimer->stopTime)) return 0; 
1093    
1094   VDR_ResponsePacket* vresp = RequestResponse(&vrp);
1095   if (vresp->noResponse()) { delete vresp; return 0; }
1096   
1097   int toReturn = (int)vresp->extractULONG();
1098   delete vresp;
1099
1100   return toReturn;
1101 }
1102