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