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