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