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