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