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