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