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