]> git.vomp.tv Git - vompserver.git/blob - vompclientrrproc.c
VDR 1.7.7 compatibility
[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 "recplayer.h"
31 #include "mvpreceiver.h"
32 #endif
33
34 #include "vompclientrrproc.h"
35 #include "vompclient.h"
36 #include "log.h"
37 #include "media.h"
38 #include "mediaplayer.h"
39 #include "servermediafile.h"
40 #include "i18n.h"
41 #include "vdrcommand.h"
42
43 bool ResumeIDLock;
44
45 VompClientRRProc::VompClientRRProc(VompClient& x)
46  : x(x)
47 {
48   log = Log::getInstance();
49   req = NULL;
50   resp = NULL;
51 }
52
53 VompClientRRProc::~VompClientRRProc()
54 {
55   threadStop();
56 }
57
58 bool VompClientRRProc::init()
59 {
60   return threadStart();
61 }
62
63 bool VompClientRRProc::recvRequest(RequestPacket* newRequest)
64 {
65   /*
66      Accept a new request
67      Now we have a queue system is used,
68      since on rare occasion the client fire two request at once
69      e.g. heavily channel switching 
70      then processing only a single request would cause a deadlock in the client
71      Marten
72   */
73
74   threadLock();
75   req_queue.push(newRequest);
76   threadSignalNoLock();
77   log->log("RRProc", Log::DEBUG, "recvReq set req and signalled");     
78   threadUnlock();
79
80   return true;
81 }
82
83 void VompClientRRProc::threadMethod()
84 {
85   threadLock();
86   log->log("RRProc", Log::DEBUG, "threadMethod startup");     
87
88   if (req_queue.size() != 0)
89   {
90     log->log("RRProc", Log::ERR, "threadMethod err 1");     
91     threadUnlock();
92     return;
93   }
94     
95   while(1)  
96   {
97     log->log("RRProc", Log::DEBUG, "threadMethod waiting");     
98     threadWaitForSignal();  // unlocks, waits, relocks
99     if (req_queue.size() == 0)
100     {
101       log->log("RRProc", Log::INFO, "threadMethod err 2 or quit");     
102       threadUnlock();
103       return;
104     }
105     
106     // signalled with something in queue
107     
108     log->log("RRProc", Log::DEBUG, "thread woken with req, queue size: %i", req_queue.size());
109
110     while (req_queue.size()) 
111     {
112       //log->log("RRProc", Log::DEBUG, "thread while");
113       req = req_queue.front();
114       req_queue.pop();
115       
116       threadUnlock(); // allow recvRequest to be queuing packets while we are working on this one
117       
118       if (!processPacket())
119       {
120         log->log("RRProc", Log::ERR, "processPacket exited with fail");     
121         return;
122       }
123       
124       threadLock();
125     } 
126     
127     // locked and run out of packets to process
128   }  
129 }
130
131 bool VompClientRRProc::processPacket()
132 {
133   resp = new ResponsePacket();
134   if (!resp->init(req->requestID))
135   {
136     log->log("RRProc", Log::ERR, "response packet init fail");     
137     delete resp; 
138     
139     if (req->data) free(req->data);
140     delete req;
141     req = NULL;
142
143     return false;
144   }
145     
146   int result = 0;
147
148   switch(req->opcode)
149   {
150     case 1:
151       result = processLogin();
152       break;
153 #ifndef VOMPSTANDALONE        
154     case 2:
155       result = processGetRecordingsList();
156       break;
157     case 3:
158       result = processDeleteRecording();
159       break;
160     case 5:
161       result = processGetChannelsList();
162       break;
163     case 6:
164       result = processStartStreamingChannel();
165       break;
166     case 7:
167       result = processGetBlock();
168       break;
169     case 8:
170       result = processStopStreaming();
171       break;
172     case 9:
173       result = processStartStreamingRecording();
174       break;
175     case 10:
176       result = processGetChannelSchedule();
177       break;
178 #endif     
179     case 11:
180       result = processConfigSave();
181       break;
182     case 12:
183       result = processConfigLoad();
184       break;
185 #ifndef VOMPSTANDALONE        
186     case 13:
187       result = processReScanRecording();         // FIXME obselete
188       break;
189     case 14:
190       result = processGetTimers();
191       break;
192     case 15:
193       result = processSetTimer();
194       break;
195     case 16:
196       result = processPositionFromFrameNumber();
197       break;
198     case 17:
199       result = processFrameNumberFromPosition();
200       break;
201     case 18:
202       result = processMoveRecording();
203       break;
204     case 19:
205       result = processGetIFrame();
206       break;
207     case 20:
208       result = processGetRecInfo();
209       break;
210     case 21:
211       result = processGetMarks();
212       break;
213     case 22:
214       result = processGetChannelPids();
215       break;
216     case 23:
217       result = processDeleteTimer();
218       break;
219 #endif        
220     case VDR_GETMEDIALIST:
221       result = processGetMediaList();
222       break;
223     case VDR_OPENMEDIA:
224       result = processOpenMedia();
225       break;
226     case VDR_GETMEDIABLOCK:
227       result = processGetMediaBlock();
228       break;
229     case 33:
230       result = processGetLanguageList();
231       break;
232     case 34:
233       result = processGetLanguageContent();
234       break;
235     case VDR_GETMEDIAINFO:
236              result= processGetMediaInfo();
237              break;
238     case VDR_CLOSECHANNEL:
239              result= processCloseMediaChannel();
240              break;
241
242   }
243
244   delete resp;
245   resp = NULL;
246   
247   if (req->data) free(req->data);
248   delete req;
249   req = NULL;
250   
251   if (result) return true;
252   return false;
253 }
254
255 int VompClientRRProc::processLogin()
256 {
257   if (req->dataLength != 6) return 0;
258
259   // Open the config
260
261   char configFileName[PATH_MAX];
262   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]);
263   x.config.init(configFileName);
264
265   // Send the login reply
266
267   time_t timeNow = time(NULL);
268   struct tm* timeStruct = localtime(&timeNow);
269   int timeOffset = timeStruct->tm_gmtoff;
270
271   resp->addULONG(timeNow);
272   resp->addLONG(timeOffset);
273   resp->finalise();
274   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
275   log->log("RRProc", Log::DEBUG, "written login reply len %lu", resp->getLen());
276     
277   x.loggedIn = true;
278   return 1;
279 }
280
281 int VompClientRRProc::processConfigSave()
282 {
283   char* section = (char*)req->data;
284   char* key = NULL;
285   char* value = NULL;
286
287   for (UINT k = 0; k < req->dataLength; k++)
288   {
289     if (req->data[k] == '\0')
290     {
291       if (!key)
292       {
293         key = (char*)&req->data[k+1];
294       }
295       else
296       {
297         value = (char*)&req->data[k+1];
298         break;
299       }
300     }
301   }
302
303   // if the last string (value) doesnt have null terminator, give up
304   if (req->data[req->dataLength - 1] != '\0') return 0;
305
306   log->log("RRProc", Log::DEBUG, "Config save: %s %s %s", section, key, value);
307   if (x.config.setValueString(section, key, value))
308   {
309     resp->addULONG(1);
310   }
311   else
312   {
313     resp->addULONG(0);
314   }
315
316   resp->finalise();
317   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
318   
319   return 1;
320 }
321
322 int VompClientRRProc::processConfigLoad()
323 {
324   char* section = (char*)req->data;
325   char* key = NULL;
326
327   for (UINT k = 0; k < req->dataLength; k++)
328   {
329     if (req->data[k] == '\0')
330     {
331       key = (char*)&req->data[k+1];
332       break;
333     }
334   }
335
336   char* value = x.config.getValueString(section, key);
337
338   if (value)
339   {
340     resp->addString(value);
341     log->log("RRProc", Log::DEBUG, "Written config load packet");
342     delete[] value;
343   }
344   else
345   {
346     resp->addULONG(0);
347     log->log("RRProc", Log::DEBUG, "Written config load failed packet");
348   }
349
350   resp->finalise();
351   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
352   
353   return 1;
354 }
355
356
357 //helper for sending from a serialize buffer
358 //insert the used len into the first 4 Bytes of the buffer
359 void VompClientRRProc::sendPacket(SerializeBuffer *b) {
360   resp->copyin(b->getStart(),b->getCurrent()-b->getStart());
361   resp->finalise();
362   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
363 }
364
365 /**
366   * media List Request:
367   * Media List response:
368   * flags, mediaList
369 */
370 #define MLISTBUF 500000
371 int VompClientRRProc::processGetMediaList()
372 {
373   SerializeBuffer buffer(req->data,req->dataLength);
374   MediaURI uri(0,NULL,NULL);
375   VDR_GetMediaListRequest request(&uri);
376   if (request.deserialize(&buffer) != 0) {
377     log->log("Client", Log::ERR, "getMediaList unable to deserialize");
378     return 0;
379   }
380   const char *dirname=uri.getName();
381   log->log("Client", Log::DEBUG, "getMediaList for %s", dirname);
382
383   MediaList * ml=NULL;
384   if (dirname == NULL) {
385     ml=x.media->getRootList();
386   } else {
387     ml=x.media->getMediaList(&uri);
388   }
389   if (ml == NULL) {
390      log->log("Client", Log::ERR, "getMediaList returned NULL");
391      return 0;
392   }
393   SerializeBuffer rbuf(MLISTBUF,false,true);
394   ULONG flags=0; //TODO: real error handling by setting flags
395   VDR_GetMediaListResponse response(&flags,ml);
396   if (response.serialize(&rbuf) != 0) {
397      log->log("Client", Log::ERR, "getMediaList returned NULL");
398      delete ml;
399      return 0;
400   }
401   log->log("Client", Log::DEBUG, "getMediaList size  %u", ml->size());
402   delete ml;
403   
404
405   sendPacket(&rbuf);
406   log->log("Client", Log::DEBUG, "Written Media list");
407   return 1;
408 }
409 /**
410   * openMedia Request:
411   * openMedia response:
412 */
413 int VompClientRRProc::processOpenMedia()
414 {
415   SerializeBuffer buffer(req->data,req->dataLength);
416   MediaURI uri(0,NULL,NULL);
417   ULONG channel=0;
418   ULONG xs=0;
419   ULONG ys=0;
420   VDR_OpenMediumRequest request(&channel,&uri,&xs,&ys);
421   if (request.deserialize(&buffer) != 0) {
422     log->log("Client", Log::ERR, "openMediaRequest unable to deserialize");
423     return 0;
424   }
425   const char *name=uri.getName();
426   log->log("Client", Log::DEBUG, "openMediaRequest for %s", name);
427   ULLONG size=0;
428   int rt=x.media->openMedium(channel,&uri,&size,xs,ys);
429   ULONG flags=0;
430   if (rt != 0) {
431     size=0;
432     flags=1;
433     log->log("Client", Log::ERR, "openMediaRequest unable to open");
434   }
435   VDR_OpenMediumResponse response(&flags,&size);
436   SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
437   if (response.serialize(&rbuf) != 0) {
438      log->log("Client", Log::ERR, "openMediaRequest cannot serialize");
439      return 0;
440   }
441   log->log("Client", Log::DEBUG, "openMediaRequest size  %llu", size);
442   sendPacket(&rbuf);
443   return 1;
444 }
445 /**
446   * VDR_GETMEDIABLOCK
447   * resp
448   * packet - no serialized response!
449   */
450 int VompClientRRProc::processGetMediaBlock()
451 {
452   SerializeBuffer buffer(req->data,req->dataLength);
453   ULLONG position = 0;
454   ULONG amount = 0;
455   ULONG channel = 0;
456   VDR_GetMediaBlockRequest request(&channel,&position,&amount);
457   if (request.deserialize(&buffer) != 0) {
458     log->log("Client", Log::ERR, "getMediaBlock unable to deserialize");
459     return 0;
460   }
461   log->log("Client", Log::DEBUG, "getMediaBlock pos = %llu length = %lu,chan=%lu", position, amount,channel);
462
463   UCHAR sendBuffer[amount ];
464   ULONG amountReceived = 0; 
465   UCHAR *rbuf=sendBuffer;
466   int rt=x.media->getMediaBlock(channel,position,amount,&amountReceived,&rbuf);
467   if (!amountReceived || rt != 0)
468   {
469     log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0");
470   }
471   else
472   {
473     if (rbuf != sendBuffer) {
474       //the provider did not use the optimized handling with using my buffer
475       resp->copyin(rbuf,amountReceived);
476       free(rbuf);
477     } else {
478       // the provider did not allocate a new buffer
479       resp->copyin(sendBuffer,amountReceived);
480     }
481   }
482   resp->finalise();
483   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
484   log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
485   return 1;
486 }
487 /**
488   * VDR_GETMEDIAINFO
489   */
490
491 int VompClientRRProc::processGetMediaInfo()
492 {
493   SerializeBuffer buffer(req->data,req->dataLength);
494   ULONG channel=0;
495   VDR_GetMediaInfoRequest request(&channel);
496   if (request.deserialize(&buffer) != 0) {
497     log->log("Client", Log::ERR, "getMediaInfo unable to deserialize");
498     return 0;
499   }
500   log->log("Client", Log::DEBUG, "getMediaInfo chan=%lu", channel);
501   ULONG flags=0;
502   MediaInfo mi;
503   int rt=x.media->getMediaInfo(channel,&mi);
504   if (rt != 0) {
505     flags=1;
506     log->log("Client", Log::ERR, "getMediaInfo unable to get");
507   }
508   VDR_GetMediaInfoResponse response(&flags,&mi);
509   SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
510   if (response.serialize(&rbuf) != 0) {
511      log->log("Client", Log::ERR, "getMediaInfo cannot serialize");
512      return 0;
513   }
514   sendPacket(&rbuf);
515   return 1;
516 }
517
518 /**
519   * VDR_CLOSECHANNEL
520   */
521
522
523 int VompClientRRProc::processCloseMediaChannel()
524 {
525   SerializeBuffer buffer(req->data,req->dataLength);
526   ULONG channel=0;
527   VDR_CloseMediaChannelRequest request(&channel);
528   if (request.deserialize(&buffer) != 0) {
529     log->log("Client", Log::ERR, "closeMediaChannel unable to deserialize");
530     return 0;
531   }
532   ULONG flags=0;
533   log->log("Client", Log::DEBUG, "closeMediaChannel chan=%lu", channel);
534   int rt=x.media->closeMediaChannel(channel);
535   if (rt != 0) {
536     flags=1;
537     log->log("Client", Log::ERR, "closeMediaChannel unable to get");
538   }
539   VDR_CloseMediaChannelResponse response(&flags);
540   SerializeBuffer rbuf(response.getSerializedLen()+4,false,true);
541   if (response.serialize(&rbuf) != 0) {
542      log->log("Client", Log::ERR, "closeMediaChannel cannot serialize");
543      return 0;
544   }
545   sendPacket(&rbuf);
546   return 1;
547 }
548
549
550
551 int VompClientRRProc::processGetLanguageList()
552 {
553   x.i18n.findLanguages();
554   const I18n::lang_code_list& languages = x.i18n.getLanguageList();
555   std::string result;
556   I18n::lang_code_list::const_iterator iter;
557   for (iter = languages.begin(); iter != languages.end(); ++iter)
558   {
559     resp->addString(iter->first.c_str());
560     resp->addString(iter->second.c_str());
561   }
562   resp->finalise();
563   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
564   return 1;
565 }
566
567 int VompClientRRProc::processGetLanguageContent()
568 {
569   if (req->dataLength <= 0) return 0;
570   std::string code, result;
571   code.assign((char*)req->data, req->dataLength - 1);
572   x.i18n.findLanguages();
573   I18n::trans_table texts = x.i18n.getLanguageContent(code);
574   I18n::trans_table::const_iterator iter;
575   for (iter = texts.begin(); iter != texts.end(); ++iter)
576   {
577     resp->addString(iter->first.c_str());
578     resp->addString(iter->second.c_str());
579   }
580   resp->finalise();
581   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
582   return 1;
583 }
584
585 #ifndef VOMPSTANDALONE
586
587 int VompClientRRProc::processGetRecordingsList()
588 {
589   int FreeMB;
590   int Percent = VideoDiskSpace(&FreeMB);
591   int Total = (FreeMB / (100 - Percent)) * 100;
592   
593   resp->addULONG(Total);
594   resp->addULONG(FreeMB);
595   resp->addULONG(Percent);
596
597   cRecordings Recordings;
598   Recordings.Load();
599
600   for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
601   {
602     resp->addULONG(recording->start);
603     resp->addString(recording->Name());
604     resp->addString(recording->FileName());
605   }
606
607   resp->finalise();
608   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
609   
610   log->log("RRProc", Log::DEBUG, "Written recordings list");
611
612   return 1;
613 }
614
615 int VompClientRRProc::processDeleteRecording()
616 {
617   // data is a pointer to the fileName string
618
619   cRecordings Recordings;
620   Recordings.Load(); // probably have to do this
621
622   cRecording* recording = Recordings.GetByName((char*)req->data);
623
624   log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
625
626   if (recording)
627   {
628     log->log("RRProc", Log::DEBUG, "deleting recording: %s", recording->Name());
629
630     cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
631     if (!rc)
632     {
633       if (recording->Delete())
634       {
635         // Copy svdrp's way of doing this, see if it works
636 #if VDRVERSNUM > 10300
637         ::Recordings.DelByName(recording->FileName());
638 #endif
639         resp->addULONG(1);
640       }
641       else
642       {
643         resp->addULONG(2);
644       }
645     }
646     else
647     {
648       resp->addULONG(3);
649     }
650   }
651   else
652   {
653     resp->addULONG(4);
654   }
655
656   resp->finalise();
657   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
658   
659   return 1;
660 }
661
662 int VompClientRRProc::processMoveRecording()
663 {
664   log->log("RRProc", Log::DEBUG, "Process move recording");
665   char* fileName = (char*)req->data;
666   char* newPath = NULL;
667
668   for (UINT k = 0; k < req->dataLength; k++)
669   {
670     if (req->data[k] == '\0')
671     {
672       newPath = (char*)&req->data[k+1];
673       break;
674     }
675   }
676   if (!newPath) return 0;
677
678   cRecordings Recordings;
679   Recordings.Load(); // probably have to do this
680
681   cRecording* recording = Recordings.GetByName((char*)fileName);
682
683   log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
684
685   if (recording)
686   {
687     cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
688     if (!rc)
689     {
690       log->log("RRProc", Log::DEBUG, "moving recording: %s", recording->Name());
691       log->log("RRProc", Log::DEBUG, "moving recording: %s", recording->FileName());
692       log->log("RRProc", Log::DEBUG, "to: %s", newPath);
693
694       const char* t = recording->FileName();
695
696       char* dateDirName = NULL;   int k;
697       char* titleDirName = NULL;  int j;
698
699       // Find the datedirname
700       for(k = strlen(t) - 1; k >= 0; k--)
701       {
702         if (t[k] == '/')
703         {
704           log->log("RRProc", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
705           dateDirName = new char[strlen(&t[k+1]) + 1];
706           strcpy(dateDirName, &t[k+1]);
707           break;
708         }
709       }
710
711       // Find the titledirname
712
713       for(j = k-1; j >= 0; j--)
714       {
715         if (t[j] == '/')
716         {
717           log->log("RRProc", Log::DEBUG, "l2: %i", (k - j - 1) + 1);
718           titleDirName = new char[(k - j - 1) + 1];
719           memcpy(titleDirName, &t[j+1], k - j - 1);
720           titleDirName[k - j - 1] = '\0';
721           break;
722         }
723       }
724
725       log->log("RRProc", Log::DEBUG, "datedirname: %s", dateDirName);
726       log->log("RRProc", Log::DEBUG, "titledirname: %s", titleDirName);
727       log->log("RRProc", Log::DEBUG, "viddir: %s", VideoDirectory);
728
729       char* newPathConv = new char[strlen(newPath)+1];
730       strcpy(newPathConv, newPath);
731       ExchangeChars(newPathConv, true);
732       log->log("RRProc", Log::DEBUG, "EC: %s", newPathConv);
733
734       char* newContainer = new char[strlen(VideoDirectory) + strlen(newPathConv) + strlen(titleDirName) + 1];
735       log->log("RRProc", Log::DEBUG, "l10: %i", strlen(VideoDirectory) + strlen(newPathConv) + strlen(titleDirName) + 1);
736       sprintf(newContainer, "%s%s%s", VideoDirectory, newPathConv, titleDirName);
737       delete[] newPathConv;
738
739       log->log("RRProc", Log::DEBUG, "%s", newContainer);
740
741       struct stat dstat;
742       int statret = stat(newContainer, &dstat);
743       if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
744       {
745         log->log("RRProc", Log::DEBUG, "new dir does not exist");
746         int mkdirret = mkdir(newContainer, 0755);
747         if (mkdirret != 0)
748         {
749           delete[] dateDirName;
750           delete[] titleDirName;
751           delete[] newContainer;
752
753           resp->addULONG(5);          
754           resp->finalise();
755           x.tcp.sendPacket(resp->getPtr(), resp->getLen());
756           return 1;
757         }
758       }
759       else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR))) // Something exists but it's not a dir
760       {
761         delete[] dateDirName;
762         delete[] titleDirName;
763         delete[] newContainer;
764
765         resp->addULONG(5);          
766         resp->finalise();
767         x.tcp.sendPacket(resp->getPtr(), resp->getLen());
768         return 1;
769       }
770
771       // Ok, the directory container has been made, or it pre-existed.
772
773       char* newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
774       sprintf(newDir, "%s/%s", newContainer, dateDirName);
775
776       log->log("RRProc", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
777       int renameret = rename(t, newDir);
778       if (renameret == 0)
779       {
780         // Success. Test for remove old dir containter
781         char* oldTitleDir = new char[k+1];
782         memcpy(oldTitleDir, t, k);
783         oldTitleDir[k] = '\0';
784         log->log("RRProc", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(oldTitleDir), oldTitleDir);
785         rmdir(oldTitleDir); // can't do anything about a fail result at this point.
786         delete[] oldTitleDir;
787       }
788
789       if (renameret == 0)
790       {
791 #if VDRVERSNUM > 10311
792         // Tell VDR
793         ::Recordings.Update();
794 #endif
795         // Success. Send a different packet from just a ulong
796         resp->addULONG(1); // success
797         resp->addString(newDir);
798       }
799       else
800       {
801         resp->addULONG(5);          
802       }
803
804       resp->finalise();
805       x.tcp.sendPacket(resp->getPtr(), resp->getLen());
806
807       delete[] dateDirName;
808       delete[] titleDirName;
809       delete[] newContainer;
810       delete[] newDir;
811     }
812     else
813     {
814       resp->addULONG(3);          
815       resp->finalise();
816       x.tcp.sendPacket(resp->getPtr(), resp->getLen());
817     }
818   }
819   else
820   {
821     resp->addULONG(4);          
822     resp->finalise();
823     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
824   }
825
826   return 1;
827 }
828
829 int VompClientRRProc::processGetChannelsList()
830 {
831   ULONG type;
832
833   char* chanConfig = x.config.getValueString("General", "Channels");
834   int allChans = 1;
835   if (chanConfig) allChans = strcasecmp(chanConfig, "FTA only");
836
837   for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
838   {
839 #if VDRVERSNUM < 10300
840     if (!channel->GroupSep() && (!channel->Ca() || allChans))
841 #else
842     if (!channel->GroupSep() && (!channel->Ca(0) || allChans))
843 #endif
844     {
845       log->log("RRProc", Log::DEBUG, "name: '%s'", channel->Name());
846
847       if (channel->Vpid()) type = 1;
848 #if VDRVERSNUM < 10300
849       else type = 2;
850 #else
851       else if (channel->Apid(0)) type = 2;
852       else continue;
853 #endif
854
855       resp->addULONG(channel->Number());
856       resp->addULONG(type);      
857       resp->addString(channel->Name());
858     }
859   }
860
861   resp->finalise();
862   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
863
864   log->log("RRProc", Log::DEBUG, "Written channels list");
865
866   return 1;
867 }
868
869 int VompClientRRProc::processGetChannelPids()
870 {
871   ULONG channelNumber = ntohl(*(ULONG*)req->data);
872
873   cChannel* channel = x.channelFromNumber(channelNumber);
874   if (!channel)
875   {
876     resp->addULONG(0);
877     resp->finalise();
878     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
879     return 1;
880   }
881
882   ULONG numApids = 0;
883   ULONG numDpids = 0;
884   ULONG numSpids = 0;
885
886
887 #if VDRVERSNUM < 10300
888
889   log->log("RRProc", Log::DEBUG, "Apid1: %i", channel->Apid1());
890   log->log("RRProc", Log::DEBUG, "Apid2: %i", channel->Apid2());
891
892   if (channel->Apid2())
893     numApids = 2;
894   else if (channel->Apid1())
895     numApids = 1;
896   else
897     numApids = 0;
898
899 #else
900
901   for (const int *Apid = channel->Apids(); *Apid; Apid++)
902   {
903     numApids++;
904   }
905   for (const int *Dpid = channel->Dpids(); *Dpid; Dpid++)
906   {
907     numDpids++;
908   }
909   for (const int *Spid = channel->Spids(); *Spid; Spid++)
910   {
911     numSpids++;
912   }
913 #endif
914
915
916   // Format of response
917   // vpid
918   // number of apids
919   // {
920   //    apid
921   //    lang string
922   // }
923   // number of dpids
924   // {
925   //    dpid
926   //    lang string
927   // }
928   // number of spids
929   // {
930   //    spid
931   //    lang string
932   // }
933   // tpid
934
935   resp->addULONG(channel->Vpid());
936   resp->addULONG(numApids);
937
938 #if VDRVERSNUM < 10300
939   if (numApids >= 1)
940   {
941     resp->addULONG(channel->Apid1());
942     resp->addString("");
943   }
944   if (numApids == 2)
945   {
946     resp->addULONG(channel->Apid2());
947     resp->addString("");
948   }
949   resp->addULONG(0);
950   resp->addULONG(0); 
951 #else
952   for (ULONG i = 0; i < numApids; i++)
953   {
954     resp->addULONG(channel->Apid(i));
955     resp->addString(channel->Alang(i));
956   }
957   resp->addULONG(numDpids);
958   for (ULONG i = 0; i < numDpids; i++)
959   {
960     resp->addULONG(channel->Dpid(i));
961     resp->addString(channel->Dlang(i));
962   }
963   resp->addULONG(numSpids);
964   for (ULONG i = 0; i < numSpids; i++)
965   {
966     resp->addULONG(channel->Spid(i));
967     resp->addString(channel->Slang(i));
968   }
969 #endif
970   resp->addULONG(channel->Tpid());
971
972
973   resp->finalise();
974   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
975   
976   log->log("RRProc", Log::DEBUG, "Written channels pids");
977
978   return 1;
979 }
980
981 int VompClientRRProc::processStartStreamingChannel()
982 {
983   if (x.lp)
984   {
985     log->log("RRProc", Log::ERR, "Client called start streaming twice");
986     return 0;
987   }
988   
989   log->log("RRProc", Log::DEBUG, "req->dataLength = %i", req->dataLength);
990   ULONG channelNumber = ntohl(*(ULONG*)req->data);
991
992   cChannel* channel = x.channelFromNumber(channelNumber);
993   if (!channel)
994   {
995     resp->addULONG(0);
996     resp->finalise();
997     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
998     return 1;
999   }
1000
1001   // get the priority we should use
1002   int fail = 1;
1003   int priority = x.config.getValueLong("General", "Live priority", &fail);
1004   if (!fail)
1005   {
1006     log->log("RRProc", Log::DEBUG, "Config: Live TV priority: %i", priority);
1007   }
1008   else
1009   {
1010     log->log("RRProc", Log::DEBUG, "Config: Live TV priority config fail");
1011     priority = 0;
1012   }
1013
1014   // a bit of sanity..
1015   if (priority < 0) priority = 0;
1016   if (priority > 99) priority = 99;
1017
1018   log->log("RRProc", Log::DEBUG, "Using live TV priority %i", priority);
1019   x.lp = MVPReceiver::create(channel, priority);
1020
1021   if (!x.lp)
1022   {
1023     resp->addULONG(0);
1024     resp->finalise();
1025     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1026     return 1;
1027   }
1028
1029   if (!x.lp->init(&x.tcp, req->requestID))
1030   {
1031     delete x.lp;
1032     x.lp = NULL;
1033     resp->addULONG(0);
1034     resp->finalise();
1035     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1036     return 1;
1037   }
1038
1039   resp->addULONG(1);
1040   resp->finalise();
1041   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1042   return 1;
1043 }
1044
1045 int VompClientRRProc::processStopStreaming()
1046 {
1047   log->log("RRProc", Log::DEBUG, "STOP STREAMING RECEIVED");
1048   if (x.lp)
1049   {
1050     delete x.lp;
1051     x.lp = NULL;
1052   }
1053   else if (x.recplayer)
1054   {
1055     x.writeResumeData();
1056
1057     delete x.recplayer;
1058     delete x.recordingManager;
1059     x.recplayer = NULL;
1060     x.recordingManager = NULL;
1061   }
1062
1063   resp->addULONG(1);
1064   resp->finalise();
1065   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1066   return 1;
1067 }
1068
1069 int VompClientRRProc::processGetBlock()
1070 {
1071   if (x.lp)
1072   {
1073     log->log("RRProc", Log::ERR, "Get block called during live streaming");
1074     return 0;
1075   }
1076
1077   if (!x.recplayer)
1078   {
1079     log->log("RRProc", Log::ERR, "Get block called when no recording open");
1080     return 0;
1081   }
1082
1083   UCHAR* data = req->data;
1084
1085   ULLONG position = x.ntohll(*(ULLONG*)data);
1086   data += sizeof(ULLONG);
1087   ULONG amount = ntohl(*(ULONG*)data);
1088
1089   log->log("RRProc", Log::DEBUG, "getblock pos = %llu length = %lu", position, amount);
1090
1091   UCHAR sendBuffer[amount];
1092   ULONG amountReceived = x.recplayer->getBlock(&sendBuffer[0], position, amount);
1093
1094   if (!amountReceived)
1095   {
1096     resp->addULONG(0);
1097     log->log("RRProc", Log::DEBUG, "written 4(0) as getblock got 0");
1098   }
1099   else
1100   {
1101     resp->copyin(sendBuffer, amountReceived);
1102     log->log("RRProc", Log::DEBUG, "written %lu", amountReceived);
1103   }
1104
1105   resp->finalise();
1106   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1107   log->log("RRProc", Log::DEBUG, "Finished getblock, have sent %lu", resp->getLen());
1108   return 1;
1109 }
1110
1111 int VompClientRRProc::processStartStreamingRecording()
1112 {
1113   // data is a pointer to the fileName string
1114
1115   x.recordingManager = new cRecordings;
1116   x.recordingManager->Load();
1117
1118   cRecording* recording = x.recordingManager->GetByName((char*)req->data);
1119
1120   log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
1121
1122   if (recording)
1123   {
1124     x.recplayer = new RecPlayer(recording);
1125
1126     resp->addULLONG(x.recplayer->getLengthBytes());
1127     resp->addULONG(x.recplayer->getLengthFrames());
1128 #if VDRVERSNUM < 10703
1129     resp->addUCHAR(true);//added for TS
1130 #else
1131     resp->addUCHAR(recording->IsPesRecording());//added for TS
1132 #endif
1133
1134     resp->finalise();
1135     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1136     
1137     log->log("RRProc", Log::DEBUG, "written totalLength");
1138   }
1139   else
1140   {
1141     delete x.recordingManager;
1142     x.recordingManager = NULL;
1143   }
1144   return 1;
1145 }
1146
1147 int VompClientRRProc::processPositionFromFrameNumber()
1148 {
1149   ULLONG retval = 0;
1150
1151   ULONG frameNumber = ntohl(*(ULONG*)req->data);
1152
1153   if (!x.recplayer)
1154   {
1155     log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1156   }
1157   else
1158   {
1159     retval = x.recplayer->positionFromFrameNumber(frameNumber);
1160   }
1161
1162   resp->addULLONG(retval);
1163   resp->finalise();
1164   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1165
1166   log->log("RRProc", Log::DEBUG, "Wrote posFromFrameNum reply to client");
1167   return 1;
1168 }
1169
1170 int VompClientRRProc::processFrameNumberFromPosition()
1171 {
1172   ULONG retval = 0;
1173
1174   ULLONG position = x.ntohll(*(ULLONG*)req->data);
1175
1176   if (!x.recplayer)
1177   {
1178     log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1179   }
1180   else
1181   {
1182     retval = x.recplayer->frameNumberFromPosition(position);
1183   }
1184
1185   resp->addULONG(retval);
1186   resp->finalise();
1187   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1188
1189   log->log("RRProc", Log::DEBUG, "Wrote frameNumFromPos reply to client");
1190   return 1;
1191 }
1192
1193 int VompClientRRProc::processGetIFrame()
1194 {
1195   bool success = false;
1196
1197   ULONG* data = (ULONG*)req->data;
1198
1199   ULONG frameNumber = ntohl(*data);
1200   data++;
1201   ULONG direction = ntohl(*data);
1202
1203   ULLONG rfilePosition = 0;
1204   ULONG rframeNumber = 0;
1205   ULONG rframeLength = 0;
1206
1207   if (!x.recplayer)
1208   {
1209     log->log("RRProc", Log::DEBUG, "GetIFrame recording called when no recording being played!");
1210   }
1211   else
1212   {
1213     success = x.recplayer->getNextIFrame(frameNumber, direction, &rfilePosition, &rframeNumber, &rframeLength);
1214   }
1215
1216   // returns file position, frame number, length
1217
1218   if (success)
1219   {
1220     resp->addULLONG(rfilePosition);
1221     resp->addULONG(rframeNumber);
1222     resp->addULONG(rframeLength);
1223   }
1224   else
1225   {
1226     resp->addULONG(0);
1227   }
1228
1229   resp->finalise();
1230   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1231   
1232   log->log("RRProc", Log::DEBUG, "Wrote GNIF reply to client %llu %lu %lu", rfilePosition, rframeNumber, rframeLength);
1233   return 1;
1234 }
1235
1236 int VompClientRRProc::processGetChannelSchedule()
1237 {
1238   ULONG* data = (ULONG*)req->data;
1239
1240   ULONG channelNumber = ntohl(*data);
1241   data++;
1242   ULONG startTime = ntohl(*data);
1243   data++;
1244   ULONG duration = ntohl(*data);
1245
1246   log->log("RRProc", Log::DEBUG, "get schedule called for channel %lu", channelNumber);
1247
1248   cChannel* channel = x.channelFromNumber(channelNumber);
1249   if (!channel)
1250   {
1251     resp->addULONG(0);
1252     resp->finalise();
1253     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1254   
1255     log->log("RRProc", Log::DEBUG, "written 0 because channel = NULL");
1256     return 1;
1257   }
1258
1259   log->log("RRProc", Log::DEBUG, "Got channel");
1260
1261 #if VDRVERSNUM < 10300
1262   cMutexLock MutexLock;
1263   const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1264 #else
1265   cSchedulesLock MutexLock;
1266   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
1267 #endif
1268   if (!Schedules)
1269   {
1270     resp->addULONG(0);
1271     resp->finalise();
1272     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1273     
1274     log->log("RRProc", Log::DEBUG, "written 0 because Schedule!s! = NULL");
1275     return 1;
1276   }
1277
1278   log->log("RRProc", Log::DEBUG, "Got schedule!s! object");
1279
1280   const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
1281   if (!Schedule)
1282   {
1283     resp->addULONG(0);
1284     resp->finalise();
1285     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1286     
1287     log->log("RRProc", Log::DEBUG, "written 0 because Schedule = NULL");
1288     return 1;
1289   }
1290
1291   log->log("RRProc", Log::DEBUG, "Got schedule object");
1292
1293   const char* empty = "";
1294   bool atLeastOneEvent = false;
1295
1296   ULONG thisEventID;
1297   ULONG thisEventTime;
1298   ULONG thisEventDuration;
1299   const char* thisEventTitle;
1300   const char* thisEventSubTitle;
1301   const char* thisEventDescription;
1302
1303 #if VDRVERSNUM < 10300
1304
1305   const cEventInfo *event;
1306   for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1307   {
1308     event = Schedule->GetEventNumber(eventNumber);
1309
1310     thisEventID = event->GetEventID();
1311     thisEventTime = event->GetTime();
1312     thisEventDuration = event->GetDuration();
1313     thisEventTitle = event->GetTitle();
1314     thisEventSubTitle = event->GetSubtitle();
1315     thisEventDescription = event->GetExtendedDescription();
1316
1317 #else
1318
1319   for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
1320   {
1321     thisEventID = event->EventID();
1322     thisEventTime = event->StartTime();
1323     thisEventDuration = event->Duration();
1324     thisEventTitle = event->Title();
1325     thisEventSubTitle = NULL;
1326     thisEventDescription = event->Description();
1327
1328 #endif
1329
1330     //in the past filter
1331     if ((thisEventTime + thisEventDuration) < (ULONG)time(NULL)) continue;
1332
1333     //start time filter
1334     if ((thisEventTime + thisEventDuration) <= startTime) continue;
1335
1336     //duration filter
1337     if (thisEventTime >= (startTime + duration)) continue;
1338
1339     if (!thisEventTitle) thisEventTitle = empty;
1340     if (!thisEventSubTitle) thisEventSubTitle = empty;
1341     if (!thisEventDescription) thisEventDescription = empty;
1342
1343     resp->addULONG(thisEventID);
1344     resp->addULONG(thisEventTime);
1345     resp->addULONG(thisEventDuration);
1346
1347     resp->addString(thisEventTitle);
1348     resp->addString(thisEventSubTitle);
1349     resp->addString(thisEventDescription);
1350
1351     atLeastOneEvent = true;
1352   }
1353
1354   log->log("RRProc", Log::DEBUG, "Got all event data");
1355
1356   if (!atLeastOneEvent)
1357   {
1358     resp->addULONG(0);
1359     log->log("RRProc", Log::DEBUG, "Written 0 because no data");
1360   }
1361   
1362   resp->finalise();
1363   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1364     
1365   log->log("RRProc", Log::DEBUG, "written schedules packet");
1366
1367   return 1;
1368 }
1369
1370 int VompClientRRProc::processGetTimers()
1371 {
1372   cTimer *timer;
1373   int numTimers = Timers.Count();
1374
1375   resp->addULONG(numTimers);
1376
1377   for (int i = 0; i < numTimers; i++)
1378   {
1379     timer = Timers.Get(i);
1380
1381 #if VDRVERSNUM < 10300
1382     resp->addULONG(timer->Active());
1383 #else
1384     resp->addULONG(timer->HasFlags(tfActive));
1385 #endif
1386     resp->addULONG(timer->Recording());
1387     resp->addULONG(timer->Pending());
1388     resp->addULONG(timer->Priority());
1389     resp->addULONG(timer->Lifetime());
1390     resp->addULONG(timer->Channel()->Number());
1391     resp->addULONG(timer->StartTime());
1392     resp->addULONG(timer->StopTime());
1393     resp->addULONG(timer->Day());
1394     resp->addULONG(timer->WeekDays());
1395     resp->addString(timer->File());
1396   }
1397
1398   resp->finalise();
1399   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1400   
1401   log->log("RRProc", Log::DEBUG, "Written timers list");
1402
1403   return 1;
1404 }
1405
1406 int VompClientRRProc::processSetTimer()
1407 {
1408   char* timerString = new char[strlen((char*)req->data) + 1];
1409   strcpy(timerString, (char*)req->data);
1410
1411 #if VDRVERSNUM < 10300
1412
1413   // If this is VDR 1.2 the date part of the timer string must be reduced
1414   // to just DD rather than YYYY-MM-DD
1415
1416   int s = 0; // source
1417   int d = 0; // destination
1418   int c = 0; // count
1419   while(c != 2) // copy up to date section, including the second ':'
1420   {
1421     timerString[d] = req->data[s];
1422     if (req->data[s] == ':') c++;
1423     ++s;
1424     ++d;
1425   }
1426   // now it has copied up to the date section
1427   c = 0;
1428   while(c != 2) // waste YYYY-MM-
1429   {
1430     if (req->data[s] == '-') c++;
1431     ++s;
1432   }
1433   // now source is at the DD
1434   memcpy(&timerString[d], &req->data[s], req->dataLength - s);
1435   d += req->dataLength - s;
1436   timerString[d] = '\0';
1437
1438   log->log("RRProc", Log::DEBUG, "Timer string after 1.2 conversion:");
1439   log->log("RRProc", Log::DEBUG, "%s", timerString);
1440
1441 #endif
1442
1443   cTimer *timer = new cTimer;
1444   if (timer->Parse((char*)timerString))
1445   {
1446     cTimer *t = Timers.GetTimer(timer);
1447     if (!t)
1448     {
1449       Timers.Add(timer);
1450 #if VDRVERSNUM < 10300
1451       Timers.Save();
1452 #else
1453       Timers.SetModified();
1454 #endif
1455       resp->addULONG(0);
1456       resp->finalise();
1457       x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1458       return 1;
1459     }
1460     else
1461     {
1462       resp->addULONG(1);
1463       resp->finalise();
1464       x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1465     }
1466   }
1467   else
1468   {
1469     resp->addULONG(2);
1470     resp->finalise();
1471     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1472   }
1473   delete timer;
1474   return 1;
1475 }
1476
1477 int VompClientRRProc::processDeleteTimer()
1478 {
1479   log->log("RRProc", Log::DEBUG, "Delete timer called");
1480   // get timer
1481   
1482   int position = 0;
1483   
1484   INT delChannel = ntohl(*(ULONG*)&req->data[position]); position += 4;
1485   INT delWeekdays = ntohl(*(ULONG*)&req->data[position]); position += 4;
1486   INT delDay = ntohl(*(ULONG*)&req->data[position]); position += 4;  
1487   INT delStart = ntohl(*(ULONG*)&req->data[position]); position += 4;  
1488   INT delStop = ntohl(*(ULONG*)&req->data[position]); position += 4;
1489     
1490   cTimer* ti = NULL;
1491   for (ti = Timers.First(); ti; ti = Timers.Next(ti))
1492   {
1493     if  ( (ti->Channel()->Number() == delChannel)
1494      &&   ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
1495      &&   (ti->StartTime() == delStart)
1496      &&   (ti->StopTime() == delStop) )
1497        break;
1498   }
1499   
1500   if (!ti)
1501   {
1502     resp->addULONG(4);
1503     resp->finalise();
1504     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1505     return 1;
1506   }
1507           
1508   if (!Timers.BeingEdited())
1509   {
1510     if (!ti->Recording())
1511     {
1512       Timers.Del(ti);
1513       Timers.SetModified();
1514       resp->addULONG(10);
1515       resp->finalise();
1516       x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1517       return 1;
1518     }
1519     else
1520     {
1521       log->log("RRProc", Log::ERR, "Unable to delete timer - timer is running");
1522       resp->addULONG(3);
1523       resp->finalise();
1524       x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1525       return 1;
1526     }  
1527   }
1528   else
1529   {
1530     log->log("RRProc", Log::ERR, "Unable to delete timer - timers being edited at VDR");
1531     resp->addULONG(1);
1532     resp->finalise();
1533     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1534     return 1;
1535   }  
1536 }
1537
1538 int VompClientRRProc::processGetRecInfo()
1539 {
1540   // data is a pointer to the fileName string
1541
1542   cRecordings Recordings;
1543   Recordings.Load(); // probably have to do this
1544
1545   cRecording *recording = Recordings.GetByName((char*)req->data);
1546
1547   time_t timerStart = 0;
1548   time_t timerStop = 0;
1549   char* summary = NULL;
1550   ULONG resumePoint = 0;
1551
1552   if (!recording)
1553   {
1554     log->log("RRProc", Log::ERR, "GetRecInfo found no recording");
1555     resp->addULONG(0);
1556     resp->finalise();
1557     x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1558     return 1;
1559   }
1560
1561   /* Return packet:
1562   4 bytes: start time for timer
1563   4 bytes: end time for timer
1564   4 bytes: resume point
1565   string: summary
1566   4 bytes: num components
1567   {
1568     1 byte: stream
1569     1 byte: type
1570     string: language
1571     string: description
1572   }
1573
1574   */
1575
1576   // Get current timer
1577
1578   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
1579   if (rc)
1580   {
1581     timerStart = rc->Timer()->StartTime();
1582     timerStop = rc->Timer()->StopTime();
1583     log->log("RRProc", Log::DEBUG, "GRI: RC: %lu %lu", timerStart, timerStop);
1584   }
1585
1586   resp->addULONG(timerStart);
1587   resp->addULONG(timerStop);
1588
1589   // Get resume point
1590
1591 /*  char* value = x.config.getValueString("ResumeData", (char*)req->data);
1592   if (value)
1593   {
1594     resumePoint = strtoul(value, NULL, 10);
1595     delete[] value;
1596   }*/
1597
1598   char* ResumeIdC = x.config.getValueString("General", "ResumeId");
1599   int ResumeId;
1600   if (ResumeIdC) {
1601     ResumeId = atoi(ResumeIdC);
1602     delete[] ResumeIdC;
1603   }
1604   else
1605     ResumeId = 0;  //default if not defined in vomp-MAC.conf
1606
1607   while (ResumeIDLock)
1608     cCondWait::SleepMs(100);
1609   ResumeIDLock = true;
1610   int OldSetupResumeID = Setup.ResumeID;
1611   Setup.ResumeID = ResumeId;                            //UGLY: quickly change resumeid
1612 #if VDRVERSNUM < 10703
1613   cResumeFile ResumeFile(recording->FileName());        //get corresponding resume file
1614 #else
1615   cResumeFile ResumeFile(recording->FileName(), recording->IsPesRecording()); //get corresponding resume file
1616 #endif
1617   Setup.ResumeID = OldSetupResumeID;                    //and restore it back
1618   ResumeIDLock = false;
1619
1620   int resume = ResumeFile.Read();
1621   //isyslog("VOMPDEBUG: resumePoint = %i, resume = %i, ResumeId = %i",resumePoint, resume, ResumeId);
1622   if (resume >= 0) 
1623     resumePoint = ResumeFile.Read();
1624
1625   log->log("RRProc", Log::DEBUG, "GRI: RP: %lu", resumePoint);
1626
1627   resp->addULONG(resumePoint);
1628
1629   // Get summary
1630
1631 #if VDRVERSNUM < 10300
1632   summary = (char*)recording->Summary();
1633 #else
1634   const cRecordingInfo *Info = recording->Info();
1635   summary = (char*)Info->ShortText();
1636   if (isempty(summary)) summary = (char*)Info->Description();
1637 #endif
1638   log->log("RRProc", Log::DEBUG, "GRI: S: %s", summary);
1639   if (summary)
1640   {
1641     resp->addString(summary);
1642   }
1643   else
1644   {
1645     resp->addString("");
1646   }
1647
1648   // Get channels
1649
1650 #if VDRVERSNUM < 10300
1651
1652   // Send 0 for numchannels - this signals the client this info is not available
1653   resp->addULONG(0);
1654
1655 #else
1656   const cComponents* components = Info->Components();
1657
1658   log->log("RRProc", Log::DEBUG, "GRI: D1: %p", components);
1659
1660   if (!components)
1661   {
1662     resp->addULONG(0);
1663   }
1664   else
1665   {
1666     resp->addULONG(components->NumComponents());
1667   
1668     tComponent* component;
1669     for (int i = 0; i < components->NumComponents(); i++)
1670     {
1671       component = components->Component(i);
1672
1673       log->log("RRProc", Log::DEBUG, "GRI: C: %i %u %u %s %s", i, component->stream, component->type, component->language, component->description);
1674       
1675       resp->addUCHAR(component->stream);
1676       resp->addUCHAR(component->type);
1677
1678       if (component->language)
1679       {
1680         resp->addString(component->language);
1681       }
1682       else
1683       {
1684         resp->addString("");
1685       }
1686       if (component->description)
1687       {
1688         resp->addString(component->description);
1689       }
1690       else
1691       {
1692         resp->addString("");
1693       }
1694     }
1695   }
1696
1697 #endif
1698
1699   // Done. send it
1700
1701   resp->finalise();
1702   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1703
1704   log->log("RRProc", Log::DEBUG, "Written getrecinfo");
1705
1706   return 1;
1707 }
1708
1709
1710
1711
1712 // FIXME obselete
1713
1714 int VompClientRRProc::processReScanRecording()
1715 {
1716   if (!x.recplayer)
1717   {
1718     log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1719     return 0;
1720   }
1721
1722   x.recplayer->scan();
1723
1724   resp->addULLONG(x.recplayer->getLengthBytes());
1725   resp->addULONG(x.recplayer->getLengthFrames());
1726   resp->finalise();
1727   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1728   log->log("RRProc", Log::DEBUG, "Rescan recording, wrote new length to client");
1729   return 1;
1730 }
1731
1732 // FIXME without client calling rescan, getblock wont work even tho more data is avail
1733
1734 int VompClientRRProc::processGetMarks()
1735 {
1736   // data is a pointer to the fileName string
1737
1738   cMarks Marks;
1739   cRecordings Recordings;
1740   Recordings.Load(); // probably have to do this
1741
1742   cRecording *recording = Recordings.GetByName((char*)req->data);
1743
1744   log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
1745
1746   if (recording)
1747   {
1748 #if VDRVERSNUM < 10703
1749     Marks.Load(recording->FileName());
1750 #else
1751     Marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording());
1752 #endif
1753     if (Marks.Count())
1754     {
1755       for (const cMark *m = Marks.First(); m; m = Marks.Next(m))
1756       {
1757         log->log("RRProc", Log::DEBUG, "found Mark %i", m->position);
1758
1759         resp->addULONG(m->position);
1760       }
1761     }
1762     else
1763     {
1764       log->log("RRProc", Log::DEBUG, "no marks found, sending 0-mark");
1765       resp->addULONG(0);
1766     }
1767   }
1768
1769   resp->finalise();
1770   x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1771   
1772   log->log("RRProc", Log::DEBUG, "Written Marks list");
1773
1774   return 1;
1775 }
1776
1777 #endif // !VOMPSTANDALONE
1778
1779