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