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