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