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