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