]> git.vomp.tv Git - vompserver.git/blob - vompclientrrproc.c
Raise recording playback get-block limit to 1MB
[vompserver.git] / vompclientrrproc.c
1 /*
2     Copyright 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 <stdlib.h>
22
23 #ifndef VOMPSTANDALONE
24 #include <vdr/recording.h>
25 #include <vdr/channels.h>
26 #include <vdr/videodir.h>
27 #include <vdr/plugin.h>
28 #include <vdr/timers.h>
29 #include <vdr/menu.h>
30 #include <vdr/remote.h>
31 #include "recplayer.h"
32 #include "mvpreceiver.h"
33 #include "services/scraper2vdr.h"
34 #endif
35
36 #include "vompclientrrproc.h"
37 #include "vompclient.h"
38 #include "log.h"
39 #include "media.h"
40 #include "mediaplayer.h"
41 #include "servermediafile.h"
42 #include "i18n.h"
43 #include "vdrcommand.h"
44 #include "picturereader.h"
45
46 bool ResumeIDLock;
47
48 ULONG VompClientRRProc::VOMP_PROTOCOL_VERSION_MIN = 0x00000301;
49 ULONG VompClientRRProc::VOMP_PROTOCOL_VERSION_MAX = 0x00000302;
50 // format is aabbccdd
51 // cc is release protocol version, increase with every release, that changes protocol
52 // dd is development protocol version, set to zero at every release, 
53 // increase for every protocol change in git
54 // bb not equal zero should indicate a non loggytronic protocol
55 // aa is reserved for future use
56 // VOMP_PROTOCOL_VERSION_MIN is the protocol version minimal supported by the server
57 // VOMP_PROTOCOL_VERSION_MAX is the protocol version maximal supported by the server
58 // This allows to run older clients from a new server
59 // Increase the minimal protocol version everytime you break compatibility for a certain 
60 // command. 
61
62 ULONG VompClientRRProc::getProtocolVersionMin()
63 {
64   return VOMP_PROTOCOL_VERSION_MIN;
65 }
66
67 ULONG VompClientRRProc::getProtocolVersionMax()
68 {
69   return VOMP_PROTOCOL_VERSION_MAX;
70 }
71
72 VompClientRRProc::VompClientRRProc(VompClient& x)
73  : x(x)
74 {
75   log = Log::getInstance();
76   req = NULL;
77   resp = NULL;
78 }
79
80 VompClientRRProc::~VompClientRRProc()
81 {
82   threadStop();
83 }
84
85 bool VompClientRRProc::init()
86 {
87   int a = threadStart();
88   sleep(1);
89   return a;
90 }
91
92 bool VompClientRRProc::recvRequest(RequestPacket* newRequest)
93 {
94   /*
95      Accept a new request
96      Now we have a queue system is used,
97      since on rare occasion the client fire two request at once
98      e.g. heavily channel switching 
99      then processing only a single request would cause a deadlock in the client
100      Marten
101   */
102
103   log->log("RRProc", Log::DEBUG, "recvReq");
104   threadLock();
105   req_queue.push(newRequest);
106   threadSignalNoLock();
107   log->log("RRProc", Log::DEBUG, "recvReq set req and signalled");     
108   threadUnlock();
109
110   return true;
111 }
112
113 void VompClientRRProc::threadMethod()
114 {
115   threadLock();
116   log->log("RRProc", Log::DEBUG, "threadMethod startup");     
117
118   if (req_queue.size() != 0)
119   {
120 /*
121 -    log->log("RRProc", Log::ERR, "threadMethod err 1");     
122 -    threadUnlock();
123 -    return;
124
125 That was how the code used to be.
126
127 TODO: Work out why this happens.
128 */  
129   
130     log->log("RRProc", Log::ERR, "threadMethod startup with already queued packets");     
131     while (req_queue.size()) 
132     {
133       //log->log("RRProc", Log::DEBUG, "thread while");
134       req = req_queue.front();
135       req_queue.pop();
136       
137       threadUnlock(); // allow recvRequest to be queuing packets while we are working on this one
138       
139       if (!processPacket())
140       {
141         log->log("RRProc", Log::ERR, "processPacket exited with fail");     
142         return;
143       }
144       
145       threadLock();
146     } 
147     log->log("RRProc", Log::ERR, "threadMethod startup with already queued packets done.");     
148
149   }
150     
151   while(1)  
152   {
153     log->log("RRProc", Log::DEBUG, "threadMethod waiting");     
154     threadWaitForSignal();  // unlocks, waits, relocks
155     if (req_queue.size() == 0)
156     {
157       log->log("RRProc", Log::INFO, "threadMethod err 2 or quit");     
158       threadUnlock();
159       return;
160     }
161     
162     // signalled with something in queue
163     
164     log->log("RRProc", Log::DEBUG, "thread woken with req, queue size: %i", req_queue.size());
165
166     while (req_queue.size()) 
167     {
168       //log->log("RRProc", Log::DEBUG, "thread while");
169       req = req_queue.front();
170       req_queue.pop();
171       
172       threadUnlock(); // allow recvRequest to be queuing packets while we are working on this one
173       
174       if (!processPacket())
175       {
176         log->log("RRProc", Log::ERR, "processPacket exited with fail");     
177         return;
178       }
179       
180       threadLock();
181     } 
182     
183     // locked and run out of packets to process
184   }  
185 }
186
187 bool VompClientRRProc::processPacket()
188 {
189   resp = new ResponsePacket();
190   if (!resp->init(req->requestID))
191   {
192     log->log("RRProc", Log::ERR, "response packet init fail");     
193     delete resp; 
194     
195     if (req->data) free(req->data);
196     delete req;
197     req = NULL;
198
199     return false;
200   }
201     
202   int result = 0;
203
204   switch(req->opcode)
205   {
206     case 1:
207       result = processLogin();
208       break;
209 #ifndef VOMPSTANDALONE        
210     case 2:
211       result = processGetRecordingsList();
212       break;
213     case 3:
214       result = processDeleteRecording();
215       break;
216     case 5:
217       result = processGetChannelsList();
218       break;
219     case 6:
220       result = processStartStreamingChannel();
221       break;
222     case 7:
223       result = processGetBlock();
224       break;
225     case 8:
226       result = processStopStreaming();
227       break;
228     case 9:
229       result = processStartStreamingRecording();
230       break;
231     case 10:
232       result = processGetChannelSchedule();
233       break;
234 #endif     
235     case 11:
236       result = processConfigSave();
237       break;
238     case 12:
239       result = processConfigLoad();
240       break;
241 #ifndef VOMPSTANDALONE        
242     case 13:
243       result = processReScanRecording();         // FIXME obselete
244       break;
245     case 14:
246       result = processGetTimers();
247       break;
248     case 15:
249       result = processSetTimer();
250       break;
251     case 16:
252       result = processPositionFromFrameNumber();
253       break;
254     case 17:
255       result = processFrameNumberFromPosition();
256       break;
257     case 18:
258       result = processMoveRecording();
259       break;
260     case 19:
261       result = processGetIFrame();
262       break;
263     case 20:
264       result = processGetRecInfo();
265       break;
266     case 21:
267       result = processGetMarks();
268       break;
269     case 22:
270       result = processGetChannelPids();
271       break;
272     case 23:
273       result = processDeleteTimer();
274       break;
275     case 666:
276       result = processVDRShutdown();
277       break;
278     case VDR_GETRECSCRAPEREVENTTYPE:
279       result = processGetRecScraperEventType();
280     break;
281     case VDR_GETSCRAPERMOVIEINFO:
282       result = processGetScraperMovieInfo();
283     break;
284     case VDR_GETSCRAPERSERIESINFO:
285       result = processGetScraperSeriesInfo();
286     break;
287     case VDR_LOADTVMEDIA:
288       result = processLoadTvMedia();
289     break;
290     case VDR_LOADTVMEDIARECTHUMB:
291       result = processLoadTvMediaRecThumb();
292     break;
293     case VDR_GETEVENTSCRAPEREVENTTYPE:
294       result = processGetEventScraperEventType();
295     break;
296     case VDR_LOADTVMEDIAEVENTTHUMB:
297       result = processLoadTvMediaEventThumb();
298     break;
299     case VDR_LOADCHANNELLOGO:
300       result = processLoadChannelLogo();
301     break;
302 #endif
303     case VDR_GETMEDIALIST:
304       result = processGetMediaList();
305       break;
306     case VDR_OPENMEDIA:
307       result = processOpenMedia();
308       break;
309     case VDR_GETMEDIABLOCK:
310       result = processGetMediaBlock();
311       break;
312     case 33:
313       result = processGetLanguageList();
314       break;
315     case 34:
316       result = processGetLanguageContent();
317       break;
318     case VDR_GETMEDIAINFO:
319             result = processGetMediaInfo();
320             break;
321     case VDR_CLOSECHANNEL:
322             result = processCloseMediaChannel();
323             break;
324     case 37:
325       result = processSetCharset();
326       break;
327   }
328
329   delete resp;
330   resp = NULL;
331   
332   if (req->data) free(req->data);
333   delete req;
334   req = NULL;
335   
336   if (result) return true;
337   return false;
338 }
339
340
341 int VompClientRRProc::processLogin()
342 {
343   if (req->dataLength != 6) return 0;
344
345   // Open the config
346
347   char configFileName[PATH_MAX];
348   snprintf(configFileName, PATH_MAX, "%s/vomp-%02X-%02X-%02X-%02X-%02X-%02X.conf", x.configDir, req->data[0], req->data[1], req->data[2], req->data[3], req->data[4], req->data[5]);
349   x.config.init(configFileName);
350
351   // Send the login reply
352
353   time_t timeNow = time(NULL);
354   struct tm* timeStruct = localtime(&timeNow);
355   int timeOffset = timeStruct->tm_gmtoff;
356
357   resp->addULONG(timeNow);
358   resp->addLONG(timeOffset);
359   resp->addULONG(VOMP_PROTOCOL_VERSION_MIN);
360   resp->addULONG(VOMP_PROTOCOL_VERSION_MAX);
361   
362   // also send information about languages
363   resp->addULONG(I18nLanguages()->Size());
364   resp->addLONG(Setup.DisplaySubtitles);
365   for (int i=0;i < I18nLanguages()->Size(); i++) {
366     resp->addLONG(Setup.AudioLanguages[i]);
367     resp->addLONG(Setup.SubtitleLanguages[i]);
368     resp->addString(I18nLanguageCode(i));
369   }
370   
371   resp->finalise();
372   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
373   log->log("RRProc", Log::DEBUG, "written login reply len %lu", resp->getLen());
374     
375   x.loggedIn = true;
376   x.netLog(); // safe to run here since the client won't start net logging for a while yet
377   
378   return 1;
379 }
380
381 int VompClientRRProc::processSetCharset()
382 {
383   int charset = ntohl(*(ULONG*)req->data);
384   if (charset>0 && charset<3)
385   {
386     log->log("RRProc", Log::DEBUG, "Set charset to %d", charset);
387     x.setCharset(charset);
388     resp->addULONG(1);
389   }
390   else
391   {
392     log->log("RRProc", Log::DEBUG, "Invalid charset %d", charset);
393     resp->addULONG(0);
394   }
395   resp->finalise();
396   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
397   return 1;
398 }
399
400 int VompClientRRProc::processConfigSave()
401 {
402   char* section = (char*)req->data;
403   char* key = NULL;
404   char* value = NULL;
405
406   for (UINT k = 0; k < req->dataLength; k++)
407   {
408     if (req->data[k] == '\0')
409     {
410       if (!key)
411       {
412         key = (char*)&req->data[k+1];
413       }
414       else
415       {
416         value = (char*)&req->data[k+1];
417         break;
418       }
419     }
420   }
421
422   // if the last string (value) doesnt have null terminator, give up
423   if (req->data[req->dataLength - 1] != '\0') return 0;
424
425   log->log("RRProc", Log::DEBUG, "Config save: %s %s %s", section, key, value);
426   if (x.config.setValueString(section, key, value))
427   {
428     resp->addULONG(1);
429   }
430   else
431   {
432     resp->addULONG(0);
433   }
434
435   resp->finalise();
436   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
437   
438   return 1;
439 }
440
441 int VompClientRRProc::processConfigLoad()
442 {
443   char* section = (char*)req->data;
444   char* key = NULL;
445
446   for (UINT k = 0; k < req->dataLength; k++)
447   {
448     if (req->data[k] == '\0')
449     {
450       key = (char*)&req->data[k+1];
451       break;
452     }
453   }
454
455   char* value = x.config.getValueString(section, key);
456
457   if (value)
458   {
459     resp->addString(value);//client coding, do not touch
460     log->log("RRProc", Log::DEBUG, "Written config load packet");
461     delete[] value;
462   }
463   else
464   {
465     resp->addULONG(0);
466     log->log("RRProc", Log::DEBUG, "Written config load failed packet");
467   }
468
469   resp->finalise();
470   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
471   
472   return 1;
473 }
474
475
476 //helper for sending from a serialize buffer
477 //insert the used len into the first 4 Bytes of the buffer
478 void VompClientRRProc::sendPacket(SerializeBuffer *b) {
479   resp->copyin(b->getStart(),b->getCurrent()-b->getStart());
480   resp->finalise();
481   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
482 }
483
484 /**
485   * media List Request:
486   * Media List response:
487   * flags, mediaList
488 */
489 #define MLISTBUF 500000
490 int VompClientRRProc::processGetMediaList()
491 {
492   SerializeBuffer buffer(req->data,req->dataLength);
493   MediaURI uri(0,NULL,NULL);
494   VDR_GetMediaListRequest request(&uri);
495   if (request.deserialize(&buffer) != 0) {
496     log->log("Client", Log::ERR, "getMediaList unable to deserialize");
497     return 0;
498   }
499   const char *dirname=uri.getName();
500   log->log("Client", Log::DEBUG, "getMediaList for %s", dirname);
501
502   MediaList * ml=NULL;
503   if (dirname == NULL) {
504     ml=x.media->getRootList();
505   } else {
506     ml=x.media->getMediaList(&uri);
507   }
508   if (ml == NULL) {
509      log->log("Client", Log::ERR, "getMediaList returned NULL");
510      return 0;
511   }
512   SerializeBuffer rbuf(MLISTBUF,false,true);
513   ULONG flags=0; //TODO: real error handling by setting flags
514   VDR_GetMediaListResponse response(&flags,ml);
515   if (response.serialize(&rbuf) != 0) {
516      log->log("Client", Log::ERR, "getMediaList returned NULL");
517      delete ml;
518      return 0;
519   }
520   log->log("Client", Log::DEBUG, "getMediaList size  %u", ml->size());
521   delete ml;
522   
523
524   sendPacket(&rbuf);
525   log->log("Client", Log::DEBUG, "Written Media list");
526   return 1;
527 }
528 /**
529   * openMedia Request:
530   * openMedia response:
531 */
532 int VompClientRRProc::processOpenMedia()
533 {
534   SerializeBuffer buffer(req->data,req->dataLength);
535   MediaURI uri(0,NULL,NULL);
536   ULONG channel=0;
537   ULONG xs=0;
538   ULONG ys=0;
539   VDR_OpenMediumRequest request(&channel,&uri,&xs,&ys);
540   if (request.deserialize(&buffer) != 0) {
541     log->log("Client", Log::ERR, "openMediaRequest unable to deserialize");
542     return 0;
543   }
544   const char *name=uri.getName();
545   log->log("Client", Log::DEBUG, "openMediaRequest for %s", name);
546   ULLONG size=0;
547   int rt=x.media->openMedium(channel,&uri,&size,xs,ys);
548   ULONG flags=0;
549   if (rt != 0) {
550     size=0;
551     flags=1;
552     log->log("Client", Log::ERR, "openMediaRequest unable to open");
553   }
554   VDR_OpenMediumResponse response(&flags,&size);
555   SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
556   if (response.serialize(&rbuf) != 0) {
557      log->log("Client", Log::ERR, "openMediaRequest cannot serialize");
558      return 0;
559   }
560   log->log("Client", Log::DEBUG, "openMediaRequest size  %llu", size);
561   sendPacket(&rbuf);
562   return 1;
563 }
564 /**
565   * VDR_GETMEDIABLOCK
566   * resp
567   * packet - no serialized response!
568   */
569 int VompClientRRProc::processGetMediaBlock()
570 {
571   SerializeBuffer buffer(req->data,req->dataLength);
572   ULLONG position = 0;
573   ULONG amount = 0;
574   ULONG channel = 0;
575   VDR_GetMediaBlockRequest request(&channel,&position,&amount);
576   if (request.deserialize(&buffer) != 0) {
577     log->log("Client", Log::ERR, "getMediaBlock unable to deserialize");
578     return 0;
579   }
580   log->log("Client", Log::DEBUG, "getMediaBlock pos = %llu length = %lu,chan=%lu", position, amount,channel);
581
582   UCHAR sendBuffer[amount ];
583   ULONG amountReceived = 0; 
584   UCHAR *rbuf=sendBuffer;
585   int rt=x.media->getMediaBlock(channel,position,amount,&amountReceived,&rbuf);
586   if (!amountReceived || rt != 0)
587   {
588     log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0");
589   }
590   else
591   {
592     if (rbuf != sendBuffer) {
593       //the provider did not use the optimized handling with using my buffer
594       resp->copyin(rbuf,amountReceived);
595       free(rbuf);
596     } else {
597       // the provider did not allocate a new buffer
598       resp->copyin(sendBuffer,amountReceived);
599     }
600   }
601   resp->finalise();
602   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
603   log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
604   return 1;
605 }
606 /**
607   * VDR_GETMEDIAINFO
608   */
609
610 int VompClientRRProc::processGetMediaInfo()
611 {
612   SerializeBuffer buffer(req->data,req->dataLength);
613   ULONG channel=0;
614   VDR_GetMediaInfoRequest request(&channel);
615   if (request.deserialize(&buffer) != 0) {
616     log->log("Client", Log::ERR, "getMediaInfo unable to deserialize");
617     return 0;
618   }
619   log->log("Client", Log::DEBUG, "getMediaInfo chan=%lu", channel);
620   ULONG flags=0;
621   MediaInfo mi;
622   int rt=x.media->getMediaInfo(channel,&mi);
623   if (rt != 0) {
624     flags=1;
625     log->log("Client", Log::ERR, "getMediaInfo unable to get");
626   }
627   VDR_GetMediaInfoResponse response(&flags,&mi);
628   SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
629   if (response.serialize(&rbuf) != 0) {
630      log->log("Client", Log::ERR, "getMediaInfo cannot serialize");
631      return 0;
632   }
633   sendPacket(&rbuf);
634   return 1;
635 }
636
637 /**
638   * VDR_CLOSECHANNEL
639   */
640
641
642 int VompClientRRProc::processCloseMediaChannel()
643 {
644   SerializeBuffer buffer(req->data,req->dataLength);
645   ULONG channel=0;
646   VDR_CloseMediaChannelRequest request(&channel);
647   if (request.deserialize(&buffer) != 0) {
648     log->log("Client", Log::ERR, "closeMediaChannel unable to deserialize");
649     return 0;
650   }
651   ULONG flags=0;
652   log->log("Client", Log::DEBUG, "closeMediaChannel chan=%lu", channel);
653   int rt=x.media->closeMediaChannel(channel);
654   if (rt != 0) {
655     flags=1;
656     log->log("Client", Log::ERR, "closeMediaChannel unable to get");
657   }
658   VDR_CloseMediaChannelResponse response(&flags);
659   SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
660   if (response.serialize(&rbuf) != 0) {
661      log->log("Client", Log::ERR, "closeMediaChannel cannot serialize");
662      return 0;
663   }
664   sendPacket(&rbuf);
665   return 1;
666 }
667
668
669
670 int VompClientRRProc::processGetLanguageList()
671 {
672   x.i18n.findLanguages();
673   const I18n::lang_code_list& languages = x.i18n.getLanguageList();
674   std::string result;
675   I18n::lang_code_list::const_iterator iter;
676   for (iter = languages.begin(); iter != languages.end(); ++iter)
677   {
678     resp->addString(iter->first.c_str()); // Source code is acsii
679     resp->addString(x.charconvutf8->Convert(iter->second.c_str())); //translate string can be any utf-8 character
680   }
681   resp->finalise();
682   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
683   return 1;
684 }
685
686 int VompClientRRProc::processGetLanguageContent()
687 {
688   if (req->dataLength <= 0) return 0;
689   std::string code, result;
690   code.assign((char*)req->data, req->dataLength - 1);
691   x.i18n.findLanguages();
692   I18n::trans_table texts = x.i18n.getLanguageContent(code);
693   I18n::trans_table::const_iterator iter;
694   for (iter = texts.begin(); iter != texts.end(); ++iter)
695   {
696     resp->addString(iter->first.c_str());// source code is acsii since it is english
697     resp->addString(x.charconvutf8->Convert(iter->second.c_str())); // translate text can be any unicode string, it is stored as UTF-8
698   }
699   resp->finalise();
700   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
701   return 1;
702 }
703
704 #ifndef VOMPSTANDALONE
705
706 int VompClientRRProc::processGetRecordingsList()
707 {
708   int FreeMB;
709 #if APIVERSNUM > 20101
710   int Percent = cVideoDirectory::VideoDiskSpace(&FreeMB);
711 #else
712   int Percent = VideoDiskSpace(&FreeMB);
713 #endif
714   int Total = (FreeMB / (100 - Percent)) * 100;
715   
716   resp->addULONG(Total);
717   resp->addULONG(FreeMB);
718   resp->addULONG(Percent);
719   
720   cRecordings Recordings;
721   Recordings.Load();
722
723   for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
724   {
725 #if VDRVERSNUM < 10721
726     resp->addULONG(recording->start);
727 #else
728     resp->addULONG(recording->Start());
729 #endif
730     resp->addUCHAR(recording->IsNew() ? 1 : 0);
731     resp->addString(x.charconvsys->Convert(recording->Name())); //coding of recording name is system dependent
732     resp->addString(recording->FileName());//file name are not  visible by user do not touch
733   }
734
735   resp->finalise();
736   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
737   
738   log->log("RRProc", Log::DEBUG, "Written recordings list");
739
740   return 1;
741 }
742
743 int VompClientRRProc::processDeleteRecording()
744 {
745   // data is a pointer to the fileName string
746
747   cRecordings Recordings;
748   Recordings.Load(); // probably have to do this
749
750   cRecording* recording = Recordings.GetByName((char*)req->data);
751
752   log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
753
754   if (recording)
755   {
756     log->log("RRProc", Log::DEBUG, "deleting recording: %s", recording->Name());
757
758     cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
759     if (!rc)
760     {
761       if (recording->Delete())
762       {
763         // Copy svdrp's way of doing this, see if it works
764 #if VDRVERSNUM > 10300
765         ::Recordings.DelByName(recording->FileName());
766 #endif
767         resp->addULONG(1);
768       }
769       else
770       {
771         resp->addULONG(2);
772       }
773     }
774     else
775     {
776       resp->addULONG(3);
777     }
778   }
779   else
780   {
781     resp->addULONG(4);
782   }
783
784   resp->finalise();
785   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
786   
787   return 1;
788 }
789
790 int VompClientRRProc::processMoveRecording()
791 {
792   log->log("RRProc", Log::DEBUG, "Process move recording");
793   char* fileName = (char*)req->data;
794   char* newPath = NULL;
795
796   for (UINT k = 0; k < req->dataLength; k++)
797   {
798     if (req->data[k] == '\0')
799     {
800       newPath = (char*)&req->data[k+1];
801       break;
802     }
803   }
804   if (!newPath) return 0;
805
806   cRecordings Recordings;
807   Recordings.Load(); // probably have to do this
808
809   cRecording* recording = Recordings.GetByName((char*)fileName);
810
811   log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
812
813   if (recording)
814   {
815     cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
816     if (!rc)
817     {
818       log->log("RRProc", Log::DEBUG, "moving recording: %s", recording->Name());
819       log->log("RRProc", Log::DEBUG, "moving recording: %s", recording->FileName());
820       log->log("RRProc", Log::DEBUG, "to: %s", newPath);
821
822       const char* t = recording->FileName();
823
824       char* dateDirName = NULL;   int k;
825       char* titleDirName = NULL;  int j;
826
827       // Find the datedirname
828       for(k = strlen(t) - 1; k >= 0; k--)
829       {
830         if (t[k] == '/')
831         {
832           log->log("RRProc", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
833           dateDirName = new char[strlen(&t[k+1]) + 1];
834           strcpy(dateDirName, &t[k+1]);
835           break;
836         }
837       }
838
839       // Find the titledirname
840
841       for(j = k-1; j >= 0; j--)
842       {
843         if (t[j] == '/')
844         {
845           log->log("RRProc", Log::DEBUG, "l2: %i", (k - j - 1) + 1);
846           titleDirName = new char[(k - j - 1) + 1];
847           memcpy(titleDirName, &t[j+1], k - j - 1);
848           titleDirName[k - j - 1] = '\0';
849           break;
850         }
851       }
852
853       log->log("RRProc", Log::DEBUG, "datedirname: %s", dateDirName);
854       log->log("RRProc", Log::DEBUG, "titledirname: %s", titleDirName);
855 #if APIVERSNUM > 20101
856       log->log("RRProc", Log::DEBUG, "viddir: %s", cVideoDirectory::Name());
857 #else
858       log->log("RRProc", Log::DEBUG, "viddir: %s", VideoDirectory);
859 #endif
860
861       char* newPathConv = new char[strlen(newPath)+1];
862       strcpy(newPathConv, newPath);
863       ExchangeChars(newPathConv, true);
864       log->log("RRProc", Log::DEBUG, "EC: %s", newPathConv);
865
866 #if APIVERSNUM > 20101
867       char* newContainer = new char[strlen(cVideoDirectory::Name()) + strlen(newPathConv) + strlen(titleDirName) + 1];
868       log->log("RRProc", Log::DEBUG, "l10: %i", strlen(cVideoDirectory::Name()) + strlen(newPathConv) + strlen(titleDirName) + 1);
869       sprintf(newContainer, "%s%s%s", cVideoDirectory::Name(), newPathConv, titleDirName);
870 #else
871       char* newContainer = new char[strlen(VideoDirectory) + strlen(newPathConv) + strlen(titleDirName) + 1];
872       log->log("RRProc", Log::DEBUG, "l10: %i", strlen(VideoDirectory) + strlen(newPathConv) + strlen(titleDirName) + 1);
873       sprintf(newContainer, "%s%s%s", VideoDirectory, newPathConv, titleDirName);
874 #endif
875       delete[] newPathConv;
876
877       log->log("RRProc", Log::DEBUG, "%s", newContainer);
878
879       struct stat dstat;
880       int statret = stat(newContainer, &dstat);
881       if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
882       {
883         log->log("RRProc", Log::DEBUG, "new dir does not exist");
884         int mkdirret = mkdir(newContainer, 0755);
885         if (mkdirret != 0)
886         {
887           delete[] dateDirName;
888           delete[] titleDirName;
889           delete[] newContainer;
890
891           resp->addULONG(5);          
892           resp->finalise();
893           x.tcp.sendPacket(resp->getPtr(), resp->getLen());
894           return 1;
895         }
896       }
897       else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR))) // Something exists but it's not a dir
898       {
899         delete[] dateDirName;
900         delete[] titleDirName;
901         delete[] newContainer;
902
903         resp->addULONG(5);          
904         resp->finalise();
905         x.tcp.sendPacket(resp->getPtr(), resp->getLen());
906         return 1;
907       }
908
909       // Ok, the directory container has been made, or it pre-existed.
910
911       char* newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
912       sprintf(newDir, "%s/%s", newContainer, dateDirName);
913
914       log->log("RRProc", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
915       int renameret = rename(t, newDir);
916       if (renameret == 0)
917       {
918         // Success. Test for remove old dir containter
919         char* oldTitleDir = new char[k+1];
920         memcpy(oldTitleDir, t, k);
921         oldTitleDir[k] = '\0';
922         log->log("RRProc", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(oldTitleDir), oldTitleDir);
923         rmdir(oldTitleDir); // can't do anything about a fail result at this point.
924         delete[] oldTitleDir;
925       }
926
927       if (renameret == 0)
928       {
929 #if VDRVERSNUM > 10311
930         // Tell VDR
931         ::Recordings.Update();
932 #endif
933         // Success. Send a different packet from just a ulong
934         resp->addULONG(1); // success
935         resp->addString(newDir); //system depent do not convert
936       }
937       else
938       {
939         resp->addULONG(5);          
940       }
941
942       resp->finalise();
943       x.tcp.sendPacket(resp->getPtr(), resp->getLen());
944
945       delete[] dateDirName;
946       delete[] titleDirName;
947       delete[] newContainer;
948       delete[] newDir;
949     }
950     else
951     {
952       resp->addULONG(3);          
953       resp->finalise();
954       x.tcp.sendPacket(resp->getPtr(), resp->getLen());
955     }
956   }
957   else
958   {
959     resp->addULONG(4);          
960     resp->finalise();
961     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
962   }
963
964   return 1;
965 }
966
967 int VompClientRRProc::processGetChannelsList()
968 {
969   ULONG type;
970
971   char* chanConfig = x.config.getValueString("General", "Channels");
972   int allChans = 1;
973   if (chanConfig) allChans = strcasecmp(chanConfig, "FTA only");
974
975   for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
976   {
977 #if VDRVERSNUM < 10300
978     if (!channel->GroupSep() && (!channel->Ca() || allChans))
979 #else
980     if (!channel->GroupSep() && (!channel->Ca(0) || allChans))
981 #endif
982     {
983       log->log("RRProc", Log::DEBUG, "name: '%s'", channel->Name());
984
985       if (channel->Vpid()) type = 1;
986 #if VDRVERSNUM < 10300
987       else type = 2;
988 #else
989       else if (channel->Apid(0)) type = 2;
990       else continue;
991 #endif
992
993       resp->addULONG(channel->Number());
994       resp->addULONG(type);      
995       resp->addString(x.charconvsys->Convert(channel->Name()));
996 #if VDRVERSNUM < 10703
997       resp->addULONG(2);
998 #else
999       resp->addULONG(channel->Vtype());
1000 #endif      
1001     }
1002   }
1003
1004   resp->finalise();
1005   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1006
1007   log->log("RRProc", Log::DEBUG, "Written channels list");
1008
1009   return 1;
1010 }
1011
1012 int VompClientRRProc::processGetChannelPids()
1013 {
1014   ULONG channelNumber = ntohl(*(ULONG*)req->data);
1015
1016   cChannel* channel = x.channelFromNumber(channelNumber);
1017   if (!channel)
1018   {
1019     resp->addULONG(0);
1020     resp->finalise();
1021     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1022     return 1;
1023   }
1024
1025   ULONG numApids = 0;
1026   ULONG numDpids = 0;
1027   ULONG numSpids = 0;
1028
1029
1030 #if VDRVERSNUM < 10300
1031
1032   log->log("RRProc", Log::DEBUG, "Apid1: %i", channel->Apid1());
1033   log->log("RRProc", Log::DEBUG, "Apid2: %i", channel->Apid2());
1034
1035   if (channel->Apid2())
1036     numApids = 2;
1037   else if (channel->Apid1())
1038     numApids = 1;
1039   else
1040     numApids = 0;
1041
1042 #else
1043
1044   for (const int *Apid = channel->Apids(); *Apid; Apid++)
1045   {
1046     numApids++;
1047   }
1048   for (const int *Dpid = channel->Dpids(); *Dpid; Dpid++)
1049   {
1050     numDpids++;
1051   }
1052   for (const int *Spid = channel->Spids(); *Spid; Spid++)
1053   {
1054     numSpids++;
1055   }
1056 #endif
1057
1058
1059   // Format of response
1060   // vpid
1061   // number of apids
1062   // {
1063   //    apid
1064   //    lang string
1065   // }
1066   // number of dpids
1067   // {
1068   //    dpid
1069   //    lang string
1070   // }
1071   // number of spids
1072   // {
1073   //    spid
1074   //    lang string
1075   // }
1076   // tpid
1077
1078   resp->addULONG(channel->Vpid());
1079 #if VDRVERSNUM < 10703
1080   resp->addULONG(2);
1081 #else
1082   resp->addULONG(channel->Vtype());
1083 #endif
1084   resp->addULONG(numApids);
1085
1086 #if VDRVERSNUM < 10300
1087   if (numApids >= 1)
1088   {
1089     resp->addULONG(channel->Apid1());
1090     resp->addString("");
1091   }
1092   if (numApids == 2)
1093   {
1094     resp->addULONG(channel->Apid2());
1095     resp->addString("");
1096   }
1097   resp->addULONG(0);
1098   resp->addULONG(0); 
1099 #else
1100   for (ULONG i = 0; i < numApids; i++)
1101   {
1102     resp->addULONG(channel->Apid(i));
1103     resp->addString(x.charconvsys->Convert(channel->Alang(i)));
1104   }
1105   resp->addULONG(numDpids);
1106   for (ULONG i = 0; i < numDpids; i++)
1107   {
1108     resp->addULONG(channel->Dpid(i));
1109     resp->addString(x.charconvsys->Convert(channel->Dlang(i)));
1110   }
1111   resp->addULONG(numSpids);
1112   for (ULONG i = 0; i < numSpids; i++)
1113   {
1114     resp->addULONG(channel->Spid(i));
1115     resp->addString(x.charconvsys->Convert(channel->Slang(i)));
1116   }
1117 #endif
1118   resp->addULONG(channel->Tpid());
1119   // Format of extended response, for compatibility with older client at the end
1120   // {
1121   //    atypes
1122   // }
1123   // {
1124   //    dtypes
1125   // }
1126   // {
1127   //    stypes
1128   //    comppageid
1129   //    ancpageids
1130   // }
1131 #if VDRVERSNUM < 10300
1132   if (numApids >= 1)
1133   {
1134     resp->addULONG(4);
1135   }
1136   if (numApids == 2)
1137   {
1138     resp->addULONG(4);
1139   }
1140 #else
1141   for (ULONG i = 0; i < numApids; i++)
1142   {
1143 #if VDRVERSNUM < 10715
1144     resp->addULONG(4);
1145 #else
1146     resp->addULONG(channel->Atype(i));
1147 #endif
1148   }
1149   for (ULONG i = 0; i < numDpids; i++)
1150   {
1151 #if VDRVERSNUM < 10715
1152     resp->addULONG(0x6A /*AC3*/);
1153 #else
1154     resp->addULONG(channel->Dtype(i));
1155 #endif
1156   }
1157   for (ULONG i = 0; i < numSpids; i++)
1158   {
1159 #if VDRVERSNUM < 10715
1160     resp->addULONG(0);
1161     resp->addULONG(0);
1162     resp->addULONG(0);
1163 #else
1164     resp->addULONG(channel->SubtitlingType(i));
1165     resp->addULONG(channel->CompositionPageId(i));
1166     resp->addULONG(channel->AncillaryPageId(i));
1167 #endif
1168   }
1169 #endif
1170
1171
1172   resp->finalise();
1173   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1174   
1175   log->log("RRProc", Log::DEBUG, "Written channels pids");
1176
1177   return 1;
1178 }
1179
1180 int VompClientRRProc::processStartStreamingChannel()
1181 {
1182   if (x.lp)
1183   {
1184     log->log("RRProc", Log::ERR, "Client called start streaming twice");
1185     return 0;
1186   }
1187   
1188   log->log("RRProc", Log::DEBUG, "req->dataLength = %i", req->dataLength);
1189   ULONG channelNumber = ntohl(*(ULONG*)req->data);
1190
1191   cChannel* channel = x.channelFromNumber(channelNumber);
1192   if (!channel)
1193   {
1194     resp->addULONG(0);
1195     resp->finalise();
1196     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1197     return 1;
1198   }
1199
1200   // get the priority we should use
1201   int fail = 1;
1202   int priority = x.config.getValueLong("General", "Live priority", &fail);
1203   if (!fail)
1204   {
1205     log->log("RRProc", Log::DEBUG, "Config: Live TV priority: %i", priority);
1206   }
1207   else
1208   {
1209     log->log("RRProc", Log::DEBUG, "Config: Live TV priority config fail");
1210     priority = 0;
1211   }
1212
1213   // a bit of sanity..
1214 #if VDRVERSNUM < 10725
1215   if (priority < 0) priority = 0;
1216 #else 
1217   if (priority < -99) priority = -99;
1218 #endif
1219   if (priority > 99) priority = 99;
1220
1221   log->log("RRProc", Log::DEBUG, "Using live TV priority %i", priority);
1222   x.lp = MVPReceiver::create(channel, priority);
1223
1224   if (!x.lp)
1225   {
1226     resp->addULONG(0);
1227     resp->finalise();
1228     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1229     return 1;
1230   }
1231
1232   if (!x.lp->init(&x.tcp, req->requestID))
1233   {
1234     delete x.lp;
1235     x.lp = NULL;
1236     resp->addULONG(0);
1237     resp->finalise();
1238     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1239     return 1;
1240   }
1241
1242   resp->addULONG(1);
1243   resp->finalise();
1244   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1245   return 1;
1246 }
1247
1248 int VompClientRRProc::processStopStreaming()
1249 {
1250   log->log("RRProc", Log::DEBUG, "STOP STREAMING RECEIVED");
1251   if (x.lp)
1252   {
1253     x.lp->detachMVPReceiver();
1254     delete x.lp;
1255     x.lp = NULL;
1256   }
1257   else if (x.recplayer)
1258   {
1259     x.writeResumeData();
1260
1261     delete x.recplayer;
1262     delete x.recordingManager;
1263     x.recplayer = NULL;
1264     x.recordingManager = NULL;
1265   }
1266
1267   resp->addULONG(1);
1268   resp->finalise();
1269   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1270   return 1;
1271 }
1272
1273 int VompClientRRProc::processGetBlock()
1274 {
1275   if (x.lp)
1276   {
1277     log->log("RRProc", Log::ERR, "Get block called during live streaming");
1278     return 0;
1279   }
1280
1281   if (!x.recplayer)
1282   {
1283     log->log("RRProc", Log::ERR, "Get block called when no recording open");
1284     return 0;
1285   }
1286
1287   UCHAR* data = req->data;
1288
1289   ULLONG position = x.ntohll(*(ULLONG*)data);
1290   data += sizeof(ULLONG);
1291   ULONG amount = ntohl(*(ULONG*)data);
1292
1293   log->log("RRProc", Log::DEBUG, "getblock pos = %llu length = %lu", position, amount);
1294
1295   UCHAR sendBuffer[amount];
1296   ULONG amountReceived = x.recplayer->getBlock(&sendBuffer[0], position, amount);
1297
1298   if (!amountReceived)
1299   {
1300     resp->addULONG(0);
1301     log->log("RRProc", Log::DEBUG, "written 4(0) as getblock got 0");
1302   }
1303   else
1304   {
1305     resp->copyin(sendBuffer, amountReceived);
1306     log->log("RRProc", Log::DEBUG, "written %lu", amountReceived);
1307   }
1308
1309   resp->finalise();
1310   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1311   log->log("RRProc", Log::DEBUG, "Finished getblock, have sent %lu", resp->getLen());
1312   return 1;
1313 }
1314
1315 int VompClientRRProc::processStartStreamingRecording()
1316 {
1317   // data is a pointer to the fileName string
1318
1319   x.recordingManager = new cRecordings;
1320   x.recordingManager->Load();
1321
1322   cRecording* recording = x.recordingManager->GetByName((char*)req->data);
1323
1324   log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
1325
1326   if (recording)
1327   {
1328     x.recplayer = new RecPlayer(recording);
1329
1330     resp->addULLONG(x.recplayer->getLengthBytes());
1331     resp->addULONG(x.recplayer->getLengthFrames());
1332     
1333 #if VDRVERSNUM < 10703
1334     resp->addUCHAR(true);//added for TS    
1335 #else
1336     resp->addUCHAR(recording->IsPesRecording());//added for TS
1337 #endif
1338
1339     resp->finalise();
1340     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1341     
1342     log->log("RRProc", Log::DEBUG, "written totalLength");
1343   }
1344   else
1345   {
1346     delete x.recordingManager;
1347     x.recordingManager = NULL;
1348   }
1349   return 1;
1350 }
1351
1352 int VompClientRRProc::processPositionFromFrameNumber()
1353 {
1354   ULLONG retval = 0;
1355
1356   ULONG frameNumber = ntohl(*(ULONG*)req->data);
1357
1358   if (!x.recplayer)
1359   {
1360     log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1361   }
1362   else
1363   {
1364     retval = x.recplayer->positionFromFrameNumber(frameNumber);
1365   }
1366
1367   resp->addULLONG(retval);
1368   resp->finalise();
1369   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1370
1371   log->log("RRProc", Log::DEBUG, "Wrote posFromFrameNum reply to client");
1372   return 1;
1373 }
1374
1375 int VompClientRRProc::processFrameNumberFromPosition()
1376 {
1377   ULONG retval = 0;
1378
1379   ULLONG position = x.ntohll(*(ULLONG*)req->data);
1380
1381   if (!x.recplayer)
1382   {
1383     log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1384   }
1385   else
1386   {
1387     retval = x.recplayer->frameNumberFromPosition(position);
1388   }
1389
1390   resp->addULONG(retval);
1391   resp->finalise();
1392   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1393
1394   log->log("RRProc", Log::DEBUG, "Wrote frameNumFromPos reply to client");
1395   return 1;
1396 }
1397
1398 int VompClientRRProc::processGetIFrame()
1399 {
1400   bool success = false;
1401
1402   ULONG* data = (ULONG*)req->data;
1403
1404   ULONG frameNumber = ntohl(*data);
1405   data++;
1406   ULONG direction = ntohl(*data);
1407
1408   ULLONG rfilePosition = 0;
1409   ULONG rframeNumber = 0;
1410   ULONG rframeLength = 0;
1411
1412   if (!x.recplayer)
1413   {
1414     log->log("RRProc", Log::DEBUG, "GetIFrame recording called when no recording being played!");
1415   }
1416   else
1417   {
1418     success = x.recplayer->getNextIFrame(frameNumber, direction, &rfilePosition, &rframeNumber, &rframeLength);
1419   }
1420
1421   // returns file position, frame number, length
1422
1423   if (success)
1424   {
1425     resp->addULLONG(rfilePosition);
1426     resp->addULONG(rframeNumber);
1427     resp->addULONG(rframeLength);
1428   }
1429   else
1430   {
1431     resp->addULONG(0);
1432   }
1433
1434   resp->finalise();
1435   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1436   
1437   log->log("RRProc", Log::DEBUG, "Wrote GNIF reply to client %llu %lu %lu", rfilePosition, rframeNumber, rframeLength);
1438   return 1;
1439 }
1440
1441 int VompClientRRProc::processGetChannelSchedule()
1442 {
1443   ULONG* data = (ULONG*)req->data;
1444
1445   ULONG channelNumber = ntohl(*data);
1446   data++;
1447   ULONG startTime = ntohl(*data);
1448   data++;
1449   ULONG duration = ntohl(*data);
1450
1451   log->log("RRProc", Log::DEBUG, "get schedule called for channel %lu", channelNumber);
1452
1453   cChannel* channel = x.channelFromNumber(channelNumber);
1454   if (!channel)
1455   {
1456     resp->addULONG(0);
1457     resp->finalise();
1458     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1459   
1460     log->log("RRProc", Log::DEBUG, "written 0 because channel = NULL");
1461     return 1;
1462   }
1463
1464   log->log("RRProc", Log::DEBUG, "Got channel");
1465
1466 #if VDRVERSNUM < 10300
1467   cMutexLock MutexLock;
1468   const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1469 #else
1470   cSchedulesLock MutexLock;
1471   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
1472 #endif
1473   if (!Schedules)
1474   {
1475     resp->addULONG(0);
1476     resp->finalise();
1477     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1478     
1479     log->log("RRProc", Log::DEBUG, "written 0 because Schedule!s! = NULL");
1480     return 1;
1481   }
1482
1483   log->log("RRProc", Log::DEBUG, "Got schedule!s! object");
1484
1485   const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
1486   if (!Schedule)
1487   {
1488     resp->addULONG(0);
1489     resp->finalise();
1490     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1491     
1492     log->log("RRProc", Log::DEBUG, "written 0 because Schedule = NULL");
1493     return 1;
1494   }
1495
1496   log->log("RRProc", Log::DEBUG, "Got schedule object");
1497
1498   const char* empty = "";
1499   bool atLeastOneEvent = false;
1500
1501   ULONG thisEventID;
1502   ULONG thisEventTime;
1503   ULONG thisEventDuration;
1504   const char* thisEventTitle;
1505   const char* thisEventSubTitle;
1506   const char* thisEventDescription;
1507
1508 #if VDRVERSNUM < 10300
1509
1510   const cEventInfo *event;
1511   for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1512   {
1513     event = Schedule->GetEventNumber(eventNumber);
1514
1515     thisEventID = event->GetEventID();
1516     thisEventTime = event->GetTime();
1517     thisEventDuration = event->GetDuration();
1518     thisEventTitle = event->GetTitle();
1519     thisEventSubTitle = event->GetSubtitle();
1520     thisEventDescription = event->GetExtendedDescription();
1521
1522 #else
1523
1524   for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
1525   {
1526     thisEventID = event->EventID();
1527     thisEventTime = event->StartTime();
1528     thisEventDuration = event->Duration();
1529     thisEventTitle = event->Title();
1530     thisEventSubTitle = NULL;
1531     thisEventDescription = event->Description();
1532
1533 #endif
1534
1535     //in the past filter
1536     if ((thisEventTime + thisEventDuration) < (ULONG)time(NULL)) continue;
1537
1538     //start time filter
1539     if ((thisEventTime + thisEventDuration) <= startTime) continue;
1540
1541     //duration filter
1542     if (thisEventTime >= (startTime + duration)) continue;
1543
1544     if (!thisEventTitle) thisEventTitle = empty;
1545     if (!thisEventSubTitle) thisEventSubTitle = empty;
1546     if (!thisEventDescription) thisEventDescription = empty;
1547
1548     resp->addULONG(thisEventID);
1549     resp->addULONG(thisEventTime);
1550     resp->addULONG(thisEventDuration);
1551
1552     resp->addString(x.charconvsys->Convert(thisEventTitle));
1553     resp->addString(x.charconvsys->Convert(thisEventSubTitle));
1554     resp->addString(x.charconvsys->Convert(thisEventDescription));
1555
1556     atLeastOneEvent = true;
1557   }
1558
1559   log->log("RRProc", Log::DEBUG, "Got all event data");
1560
1561   if (!atLeastOneEvent)
1562   {
1563     resp->addULONG(0);
1564     log->log("RRProc", Log::DEBUG, "Written 0 because no data");
1565   }
1566   
1567   resp->finalise();
1568   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1569     
1570   log->log("RRProc", Log::DEBUG, "written schedules packet");
1571
1572   return 1;
1573 }
1574
1575 int VompClientRRProc::processGetTimers()
1576 {
1577   cTimer *timer;
1578   int numTimers = Timers.Count();
1579
1580   resp->addULONG(numTimers);
1581
1582   for (int i = 0; i < numTimers; i++)
1583   {
1584     timer = Timers.Get(i);
1585
1586 #if VDRVERSNUM < 10300
1587     resp->addULONG(timer->Active());
1588 #else
1589     resp->addULONG(timer->HasFlags(tfActive));
1590 #endif
1591     resp->addULONG(timer->Recording());
1592     resp->addULONG(timer->Pending());
1593     resp->addULONG(timer->Priority());
1594     resp->addULONG(timer->Lifetime());
1595     resp->addULONG(timer->Channel()->Number());
1596     resp->addULONG(timer->StartTime());
1597     resp->addULONG(timer->StopTime());
1598     resp->addULONG(timer->Day());
1599     resp->addULONG(timer->WeekDays());
1600     resp->addString(timer->File()); //Filename is system specific and not visible by user
1601   }
1602
1603   resp->finalise();
1604   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1605   
1606   log->log("RRProc", Log::DEBUG, "Written timers list");
1607
1608   return 1;
1609 }
1610
1611 int VompClientRRProc::processSetTimer()
1612 {
1613   char* timerString = new char[strlen((char*)req->data) + 1];
1614   strcpy(timerString, (char*)req->data);
1615
1616 #if VDRVERSNUM < 10300
1617
1618   // If this is VDR 1.2 the date part of the timer string must be reduced
1619   // to just DD rather than YYYY-MM-DD
1620
1621   int s = 0; // source
1622   int d = 0; // destination
1623   int c = 0; // count
1624   while(c != 2) // copy up to date section, including the second ':'
1625   {
1626     timerString[d] = req->data[s];
1627     if (req->data[s] == ':') c++;
1628     ++s;
1629     ++d;
1630   }
1631   // now it has copied up to the date section
1632   c = 0;
1633   while(c != 2) // waste YYYY-MM-
1634   {
1635     if (req->data[s] == '-') c++;
1636     ++s;
1637   }
1638   // now source is at the DD
1639   memcpy(&timerString[d], &req->data[s], req->dataLength - s);
1640   d += req->dataLength - s;
1641   timerString[d] = '\0';
1642
1643   log->log("RRProc", Log::DEBUG, "Timer string after 1.2 conversion:");
1644
1645 #endif
1646   log->log("RRProc", Log::DEBUG, "%s", timerString);
1647
1648   cTimer *timer = new cTimer;
1649   if (timer->Parse((char*)timerString))
1650   {
1651     cTimer *t = Timers.GetTimer(timer);
1652     if (!t)
1653     {
1654       Timers.Add(timer);
1655 #if VDRVERSNUM < 10300
1656       Timers.Save();
1657 #else
1658       Timers.SetModified();
1659 #endif
1660       resp->addULONG(0);
1661       resp->finalise();
1662       x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1663       return 1; // FIXME - cTimer* timer is leaked here!
1664     }
1665     else
1666     {
1667       resp->addULONG(1);
1668       resp->finalise();
1669       x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1670     }
1671   }
1672   else
1673   {
1674     resp->addULONG(2);
1675     resp->finalise();
1676     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1677   }
1678   delete timer;
1679   return 1;
1680 }
1681
1682 int VompClientRRProc::processDeleteTimer()
1683 {
1684   log->log("RRProc", Log::DEBUG, "Delete timer called");
1685   // get timer
1686   
1687   int position = 0;
1688   
1689   INT delChannel = ntohl(*(ULONG*)&req->data[position]); position += 4;
1690   INT delWeekdays = ntohl(*(ULONG*)&req->data[position]); position += 4;
1691   INT delDay = ntohl(*(ULONG*)&req->data[position]); position += 4;  
1692   INT delStart = ntohl(*(ULONG*)&req->data[position]); position += 4;  
1693   INT delStop = ntohl(*(ULONG*)&req->data[position]); position += 4;
1694     
1695   cTimer* ti = NULL;
1696   for (ti = Timers.First(); ti; ti = Timers.Next(ti))
1697   {
1698     if  ( (ti->Channel()->Number() == delChannel)
1699      &&   ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
1700      &&   (ti->StartTime() == delStart)
1701      &&   (ti->StopTime() == delStop) )
1702        break;
1703   }
1704   
1705   if (!ti)
1706   {
1707     resp->addULONG(4);
1708     resp->finalise();
1709     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1710     return 1;
1711   }
1712           
1713   if (!Timers.BeingEdited())
1714   {
1715     if (!ti->Recording())
1716     {
1717       Timers.Del(ti);
1718       Timers.SetModified();
1719       resp->addULONG(10);
1720       resp->finalise();
1721       x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1722       return 1;
1723     }
1724     else
1725     {
1726       log->log("RRProc", Log::ERR, "Unable to delete timer - timer is running");
1727       resp->addULONG(3);
1728       resp->finalise();
1729       x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1730       return 1;
1731     }  
1732   }
1733   else
1734   {
1735     log->log("RRProc", Log::ERR, "Unable to delete timer - timers being edited at VDR");
1736     resp->addULONG(1);
1737     resp->finalise();
1738     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1739     return 1;
1740   }  
1741 }
1742
1743 int VompClientRRProc::processGetRecInfo()
1744 {
1745   // data is a pointer to the fileName string
1746   
1747   cRecordings Recordings;
1748   Recordings.Load(); // probably have to do this
1749
1750   cRecording *recording = Recordings.GetByName((char*)req->data);
1751
1752   time_t timerStart = 0;
1753   time_t timerStop = 0;
1754   char* summary = NULL;
1755   char* shorttext = NULL;
1756   char* description = NULL;
1757   char* title = NULL;
1758   bool newsummary=false;
1759   ULONG resumePoint = 0;
1760
1761   if (!recording)
1762   {
1763     log->log("RRProc", Log::ERR, "GetRecInfo found no recording");
1764     resp->addULONG(0);
1765     resp->finalise();
1766     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1767     return 1;
1768   }
1769
1770   /* Return packet:
1771   4 bytes: start time for timer
1772   4 bytes: end time for timer
1773   4 bytes: resume point
1774   string: summary
1775   4 bytes: num components
1776   {
1777     1 byte: stream
1778     1 byte: type
1779     string: language
1780     string: description
1781   }
1782   8 bytes: frames per second
1783   */
1784
1785   // Get current timer
1786
1787   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
1788   if (rc)
1789   {
1790     timerStart = rc->Timer()->StartTime();
1791     timerStop = rc->Timer()->StopTime();
1792     log->log("RRProc", Log::DEBUG, "GRI: RC: %lu %lu", timerStart, timerStop);
1793   }
1794
1795   resp->addULONG(timerStart);
1796   resp->addULONG(timerStop);
1797
1798   // Get resume point
1799
1800 /*  char* value = x.config.getValueString("ResumeData", (char*)req->data);
1801   if (value)
1802   {
1803     resumePoint = strtoul(value, NULL, 10);
1804     delete[] value;
1805   }*/
1806
1807   char* ResumeIdC = x.config.getValueString("General", "ResumeId");
1808   int ResumeId;
1809   if (ResumeIdC) {
1810     ResumeId = atoi(ResumeIdC);
1811     delete[] ResumeIdC;
1812   }
1813   else
1814     ResumeId = 0;  //default if not defined in vomp-MAC.conf
1815
1816   while (ResumeIDLock)
1817     cCondWait::SleepMs(100);
1818   ResumeIDLock = true;
1819   int OldSetupResumeID = Setup.ResumeID;
1820   Setup.ResumeID = ResumeId;                            //UGLY: quickly change resumeid
1821 #if VDRVERSNUM < 10703
1822   cResumeFile ResumeFile(recording->FileName());        //get corresponding resume file
1823 #else
1824   cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording()); //get corresponding resume file
1825 #endif
1826   Setup.ResumeID = OldSetupResumeID;                    //and restore it back
1827   ResumeIDLock = false;
1828
1829   int resume = ResumeFile.Read();
1830   //isyslog("VOMPDEBUG: resumePoint = %i, resume = %i, ResumeId = %i",resumePoint, resume, ResumeId);
1831   if (resume >= 0) 
1832     resumePoint = ResumeFile.Read();
1833
1834   log->log("RRProc", Log::DEBUG, "GRI: RP: %lu", resumePoint);
1835
1836   resp->addULONG(resumePoint);
1837
1838   // Get summary
1839
1840 #if VDRVERSNUM < 10300
1841   summary = (char*)recording->Summary();
1842 #else
1843   const cRecordingInfo *Info = recording->Info();
1844   shorttext = (char*)Info->ShortText();
1845   description = (char*) (char*)Info->Description();
1846   if (isempty(shorttext)) summary=description;
1847   else if (isempty(description)) summary=shorttext;
1848   else {
1849      int length=strlen(description)+strlen(shorttext)+4;
1850      summary=new char[length];
1851      snprintf(summary,length,"%s\n\n%s",shorttext,description);
1852      newsummary=true;
1853   }
1854   
1855   if (isempty(summary)) summary = (char*)Info->Description();
1856 #endif
1857   log->log("RRProc", Log::DEBUG, "GRI: S: %s", summary);
1858   if (summary)
1859   {
1860     resp->addString(x.charconvsys->Convert(summary));
1861     if (newsummary) delete [] summary;
1862   }
1863   else
1864   {
1865     resp->addString("");
1866   }
1867
1868   // Get channels
1869
1870 #if VDRVERSNUM < 10300
1871
1872   // Send 0 for numchannels - this signals the client this info is not available
1873   resp->addULONG(0);
1874
1875 #else
1876   const cComponents* components = Info->Components();
1877
1878   log->log("RRProc", Log::DEBUG, "GRI: D1: %p", components);
1879
1880   if (!components)
1881   {
1882     resp->addULONG(0);
1883   }
1884   else
1885   {
1886     resp->addULONG(components->NumComponents());
1887   
1888     tComponent* component;
1889     for (int i = 0; i < components->NumComponents(); i++)
1890     {
1891       component = components->Component(i);
1892
1893       log->log("RRProc", Log::DEBUG, "GRI: C: %i %u %u %s %s", i, component->stream, component->type, component->language, component->description);
1894       
1895       resp->addUCHAR(component->stream);
1896       resp->addUCHAR(component->type);
1897
1898       if (component->language)
1899       {
1900         resp->addString(x.charconvsys->Convert(component->language));
1901       }
1902       else
1903       {
1904         resp->addString("");
1905       }
1906       if (component->description)
1907       {
1908         resp->addString(x.charconvsys->Convert(component->description));
1909       }
1910       else
1911       {
1912         resp->addString("");
1913       }
1914     }
1915   }
1916
1917 #endif
1918   double framespersec;
1919 #if VDRVERSNUM < 10703
1920   framespersec = FRAMESPERSEC;
1921 #else
1922   framespersec = Info->FramesPerSecond();
1923 #endif
1924   resp->adddouble(framespersec);
1925   title = (char*)Info->Title();
1926   if (title) 
1927   {
1928     resp->addString(x.charconvsys->Convert(title));
1929   }
1930   else
1931   {
1932       resp->addString(x.charconvsys->Convert(recording->Name()));
1933   }
1934   
1935   // Done. send it
1936
1937   resp->finalise();
1938   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1939
1940   log->log("RRProc", Log::DEBUG, "Written getrecinfo");
1941
1942   return 1;
1943 }
1944
1945
1946
1947
1948 // FIXME obselete
1949
1950 int VompClientRRProc::processReScanRecording()
1951 {
1952   if (!x.recplayer)
1953   {
1954     log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1955     return 0;
1956   }
1957
1958   x.recplayer->scan();
1959
1960   resp->addULLONG(x.recplayer->getLengthBytes());
1961   resp->addULONG(x.recplayer->getLengthFrames());
1962   resp->finalise();
1963   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1964   log->log("RRProc", Log::DEBUG, "Rescan recording, wrote new length to client");
1965   return 1;
1966 }
1967
1968 // FIXME without client calling rescan, getblock wont work even tho more data is avail
1969
1970 int VompClientRRProc::processGetMarks()
1971 {
1972   // data is a pointer to the fileName string
1973
1974   cMarks Marks;
1975   cRecordings Recordings;
1976   Recordings.Load(); // probably have to do this
1977
1978   cRecording *recording = Recordings.GetByName((char*)req->data);
1979
1980   log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
1981
1982   if (recording)
1983   {
1984 #if VDRVERSNUM < 10703
1985     Marks.Load(recording->FileName());
1986 #else
1987     Marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording());
1988 #endif
1989     if (Marks.Count())
1990     {
1991       for (const cMark *m = Marks.First(); m; m = Marks.Next(m))
1992       {
1993 #if VDRVERSNUM < 10721
1994         ULLONG mposition = m->position;
1995 #else
1996         ULLONG mposition = m->Position();
1997 #endif
1998         log->log("RRProc", Log::DEBUG, "found Mark %i", mposition);
1999
2000         resp->addULONG(mposition);
2001       }
2002     }
2003     else
2004     {
2005       log->log("RRProc", Log::DEBUG, "no marks found, sending 0-mark");
2006       resp->addULONG(0);
2007     }
2008   }
2009
2010   resp->finalise();
2011   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2012   
2013   log->log("RRProc", Log::DEBUG, "Written Marks list");
2014
2015   return 1;
2016 }
2017
2018 int VompClientRRProc::processVDRShutdown()
2019 {
2020   log->log("RRProc", Log::DEBUG, "Trying to shutdown VDR");
2021   VompClient::decClients(); // Temporarily make this client disappear
2022   cRemote::Put(kPower);
2023   VompClient::incClients();
2024   resp->finalise();
2025   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2026   return 1;
2027 }
2028
2029 int VompClientRRProc::processGetRecScraperEventType()
2030 {
2031   Recordings.Load(); // probably have to do this
2032
2033   cRecording *recording = Recordings.GetByName((char*)req->data);
2034   ScraperGetEventType call;
2035   call.type = tNone;
2036
2037   if (recording && x.scrapQuery()) 
2038   {
2039      call.recording = recording;
2040      x.scraper->Service("GetEventType",&call);
2041   }
2042   resp->addUCHAR(call.type);
2043   if (call.type == tMovie)
2044   {
2045      resp->addLONG(call.movieId);
2046   } else if (call.type == tSeries){
2047      resp->addLONG(call.seriesId);
2048      resp->addLONG(call.episodeId);
2049   }
2050   resp->finalise();
2051   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2052
2053   return 1;
2054 }
2055
2056 int VompClientRRProc::processGetEventScraperEventType()
2057 {
2058   ScraperGetEventType call;
2059   call.type = tNone;
2060   ULONG channelid = ntohl(*(ULONG*)req->data);
2061   ULONG eventid = ntohl(*(ULONG*)(req->data+4));
2062   const cEvent *event = NULL; 
2063   
2064   cChannel* channel = x.channelFromNumber(channelid);
2065
2066 #if VDRVERSNUM < 10300
2067   cMutexLock MutexLock;
2068   const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
2069 #else
2070   cSchedulesLock MutexLock;
2071   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
2072 #endif
2073   const cSchedule * Schedule;
2074   if (Schedules && channel)
2075   {
2076      const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
2077      if (Schedule) {
2078         event = Schedule->GetEvent(eventid);
2079     }
2080   }
2081     
2082   if (event && x.scrapQuery()) 
2083   {
2084      call.event = event;
2085      x.scraper->Service("GetEventType",&call);
2086   }
2087   resp->addUCHAR(call.type);
2088   if (call.type == tMovie)
2089   {
2090      resp->addLONG(call.movieId);
2091   } else if (call.type == tSeries){
2092      resp->addLONG(call.seriesId);
2093      resp->addLONG(call.episodeId);
2094   }
2095   if (x.pict->epgImageExists(eventid)) {
2096      resp->addLONG(1);
2097   } else {
2098      resp->addLONG(0);
2099   }
2100     
2101   resp->finalise();
2102   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2103
2104   return 1;
2105 }
2106
2107 #define ADDSTRING_TO_PAKET(y) if ((y)!=0)  resp->addString(x.charconvutf8->Convert(y)); else resp->addString(""); 
2108
2109 int VompClientRRProc::processGetScraperMovieInfo()
2110 {
2111    
2112    cMovie movie;
2113    movie.movieId = ntohl(*(ULONG*)req->data);
2114    if (!x.scrapQuery()) {
2115       log->log("RRProc", Log::DEBUG, "No Scraper, get SeriesInfo");
2116       return 0; //stupid, I have no scraper why are you still asking
2117    }
2118    x.scraper->Service("GetMovie",&movie);
2119    
2120
2121    ADDSTRING_TO_PAKET(movie.title.c_str());
2122    ADDSTRING_TO_PAKET(movie.originalTitle.c_str());
2123    ADDSTRING_TO_PAKET(movie.tagline.c_str());
2124    ADDSTRING_TO_PAKET(movie.overview.c_str());
2125    resp->addUCHAR(movie.adult);
2126    ADDSTRING_TO_PAKET(movie.collectionName.c_str());
2127
2128    resp->addLONG(movie.budget);
2129    resp->addLONG(movie.revenue);
2130    ADDSTRING_TO_PAKET(movie.genres.c_str());
2131    ADDSTRING_TO_PAKET(movie.homepage.c_str());
2132    ADDSTRING_TO_PAKET(movie.releaseDate.c_str());
2133    resp->addLONG(movie.runtime);
2134    resp->adddouble(movie.popularity);
2135    resp->adddouble(movie.voteAverage);
2136    resp->addULONG(movie.poster.width);
2137    resp->addULONG(movie.poster.height);
2138    resp->addULONG(movie.fanart.width);
2139    resp->addULONG(movie.fanart.height);
2140    resp->addULONG(movie.collectionPoster.width);
2141    resp->addULONG(movie.collectionPoster.height);
2142    resp->addULONG(movie.collectionFanart.width);
2143    resp->addULONG(movie.collectionFanart.height);
2144    resp->addULONG(movie.actors.size());
2145    for (ULONG acty=0; acty < movie.actors.size(); acty++) {
2146        ADDSTRING_TO_PAKET(movie.actors[acty].name.c_str());
2147        ADDSTRING_TO_PAKET(movie.actors[acty].role.c_str());
2148        resp->addULONG(movie.actors[acty].actorThumb.width);
2149        resp->addULONG(movie.actors[acty].actorThumb.height);
2150    }
2151   resp->finalise();
2152   
2153   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2154
2155   
2156   return 1;
2157
2158 }
2159
2160 int VompClientRRProc::processGetScraperSeriesInfo()
2161 {
2162    cSeries series;
2163    series.seriesId = ntohl(*(ULONG*)req->data);
2164    series.episodeId = ntohl(*(ULONG*)(req->data+4));
2165    if (!x.scrapQuery()) {
2166       log->log("RRProc", Log::DEBUG, "No Scraper, get SeriesInfo");
2167       return 0; //stupid, I have no scraper why are you still asking
2168    }
2169    x.scraper->Service("GetSeries",&series);
2170    
2171    ADDSTRING_TO_PAKET(series.name.c_str());
2172    ADDSTRING_TO_PAKET(series.overview.c_str());
2173    ADDSTRING_TO_PAKET(series.firstAired.c_str());
2174    ADDSTRING_TO_PAKET(series.network.c_str());
2175    ADDSTRING_TO_PAKET(series.genre.c_str());
2176    resp->adddouble(series.rating);
2177    ADDSTRING_TO_PAKET(series.status.c_str());
2178    
2179    resp->addLONG(series.episode.number);
2180    resp->addLONG(series.episode.season);
2181    ADDSTRING_TO_PAKET(series.episode.name.c_str());
2182    ADDSTRING_TO_PAKET(series.episode.firstAired.c_str());
2183    ADDSTRING_TO_PAKET(series.episode.guestStars.c_str());
2184    ADDSTRING_TO_PAKET(series.episode.overview.c_str());
2185    resp->adddouble(series.episode.rating);
2186    resp->addULONG(series.episode.episodeImage.width);
2187    resp->addULONG(series.episode.episodeImage.height);
2188    
2189    ULONG num_actors = series.actors.size();
2190    resp->addULONG(num_actors);
2191    for (ULONG acty=0; acty < num_actors; acty++) {
2192        ADDSTRING_TO_PAKET(series.actors[acty].name.c_str());
2193        ADDSTRING_TO_PAKET(series.actors[acty].role.c_str());
2194        resp->addULONG(series.actors[acty].actorThumb.width);
2195        resp->addULONG(series.actors[acty].actorThumb.height);
2196    }
2197    ULONG num_posters = series.posters.size();
2198    resp->addULONG(num_posters);
2199    for (ULONG medias = 0; medias < num_posters; medias++ ) {
2200        cTvMedia media=series.posters[medias];
2201        resp->addULONG(media.width);
2202        resp->addULONG(media.height);
2203    }
2204
2205    ULONG num_banners = series.banners.size();
2206    resp->addULONG(num_banners);
2207    for (ULONG medias = 0; medias < num_banners; medias++ ) {
2208        cTvMedia media=series.banners[medias];
2209        resp->addULONG(media.width);
2210        resp->addULONG(media.height);
2211    }
2212    ULONG num_fanarts = series.fanarts.size();
2213    resp->addULONG(num_fanarts);
2214    for (ULONG medias = 0; medias < num_fanarts; medias++ ) {
2215        cTvMedia media=series.fanarts[medias];
2216        resp->addULONG(media.width);
2217        resp->addULONG(media.height);
2218    }
2219    resp->addULONG(series.seasonPoster.width);
2220    resp->addULONG(series.seasonPoster.height);
2221    
2222    resp->finalise();
2223
2224    x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2225    
2226    return 1;
2227 }
2228
2229 int VompClientRRProc::processLoadTvMedia()
2230 {
2231    TVMediaRequest tvreq;
2232    tvreq.streamID = req->requestID;
2233    tvreq.type = ntohl(*(ULONG*)req->data);
2234    tvreq.primary_id = ntohl(*(ULONG*)(req->data+4));
2235    tvreq.secondary_id = ntohl(*(ULONG*)(req->data+8));
2236    tvreq.type_pict = ntohl(*(ULONG*)(req->data+12));
2237    tvreq.container = ntohl(*(ULONG*)(req->data+16));
2238    tvreq.container_member = ntohl(*(ULONG*)(req->data+20));
2239    log->log("RRProc", Log::DEBUG, "TVMedia request %d",req->requestID);
2240    x.pict->addTVMediaRequest(tvreq);
2241
2242    
2243    resp->finalise();
2244
2245    x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2246    
2247    return 1;
2248 }
2249
2250 int VompClientRRProc::processLoadTvMediaRecThumb()
2251 {
2252    TVMediaRequest tvreq;
2253    tvreq.streamID = req->requestID;
2254    tvreq.type = 3; // unknown but primary_name is set
2255    tvreq.primary_id = 0;
2256    tvreq.primary_name = std::string((const char*) req->data);
2257    tvreq.secondary_id = 0;
2258    tvreq.type_pict = 1;
2259    tvreq.container = 0;
2260    tvreq.container_member = 0;
2261    log->log("RRProc", Log::DEBUG, "TVMedia request %d %s",req->requestID,req->data);
2262    x.pict->addTVMediaRequest(tvreq);
2263
2264    
2265    resp->finalise();
2266
2267    x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2268    
2269    return 1;
2270 }
2271
2272 int VompClientRRProc::processLoadTvMediaEventThumb()
2273 {
2274    TVMediaRequest tvreq;
2275    tvreq.streamID = req->requestID;
2276    tvreq.type = 4; // unknown but primary_id is set
2277    UINT channelid = ntohl(*(ULONG*)req->data);
2278    tvreq.primary_id = ntohl(*(ULONG*)(req->data+4));
2279    tvreq.secondary_id = 0;
2280    cChannel* channel = x.channelFromNumber(channelid);
2281
2282    if (channel) tvreq.primary_name = std::string((const char*)channel->GetChannelID().ToString());
2283    tvreq.type_pict = 1;
2284    tvreq.container = 0;
2285    tvreq.container_member = 0;
2286    log->log("RRProc", Log::DEBUG, "TVMedia request %d %s",req->requestID,req->data);
2287    x.pict->addTVMediaRequest(tvreq);
2288
2289    
2290    resp->finalise();
2291
2292    x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2293    
2294    return 1;
2295 }
2296
2297 int VompClientRRProc::processLoadChannelLogo()
2298 {
2299    TVMediaRequest tvreq;
2300    tvreq.streamID = req->requestID;
2301    tvreq.type = 5; // channel logo
2302    UINT channelid = ntohl(*(ULONG*)req->data);
2303    tvreq.primary_id = channelid;
2304    tvreq.secondary_id = 0;
2305    cChannel* channel = x.channelFromNumber(channelid);
2306
2307    if (channel) tvreq.primary_name = std::string((const char*)channel->Name());
2308    tvreq.type_pict = 1;
2309    tvreq.container = 0;
2310    tvreq.container_member = 0;
2311    log->log("RRProc", Log::DEBUG, "TVMedia request %d %d %s",req->requestID,channelid, channel->Name());
2312    x.pict->addTVMediaRequest(tvreq);
2313
2314    
2315    resp->finalise();
2316
2317    x.tcp.sendPacket(resp->getPtr(), resp->getLen());
2318    
2319    return 1;
2320 }
2321
2322  
2323
2324
2325   
2326 #endif // !VOMPSTANDALONE
2327