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