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