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