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