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