]> git.vomp.tv Git - vompserver.git/blob - mvpclient.c
Updates for media player after protocol change
[vompserver.git] / mvpclient.c
1 /*
2     Copyright 2004-2005 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "mvpclient.h"
22
23 // This is here else it causes compile errors with something in libdvbmpeg
24 //#include <vdr/menu.h>
25
26 pthread_mutex_t threadClientMutex;
27 int MVPClient::nr_clients = 0;
28
29
30 MVPClient::MVPClient(Config* cfgBase, char* tconfigDirExtra, int tsocket)
31  : tcp(tsocket)
32 {
33 #ifndef VOMPSTANDALONE
34   lp = NULL;
35   rp = NULL;
36   recordingManager = NULL;
37 #endif
38   imageFile = 0;
39   log = Log::getInstance();
40   loggedIn = false;
41   configDirExtra = tconfigDirExtra;
42   baseConfig = cfgBase;
43   incClients();
44 }
45
46 MVPClient::~MVPClient()
47 {
48   log->log("Client", Log::DEBUG, "MVP client destructor");
49 #ifndef VOMPSTANDALONE
50   if (lp)
51   {
52     delete lp;
53     lp = NULL;
54   }
55   else if (rp)
56   {
57     writeResumeData();
58
59     delete rp;
60     delete recordingManager;
61     rp = NULL;
62     recordingManager = NULL;
63   }
64 #endif
65   if (loggedIn) cleanConfig();
66   decClients();
67 }
68
69 ULLONG MVPClient::ntohll(ULLONG a)
70 {
71   return htonll(a);
72 }
73
74 ULLONG MVPClient::htonll(ULLONG a)
75 {
76   #if BYTE_ORDER == BIG_ENDIAN
77     return a;
78   #else
79     ULLONG b = 0;
80
81     b = ((a << 56) & 0xFF00000000000000ULL)
82       | ((a << 40) & 0x00FF000000000000ULL)
83       | ((a << 24) & 0x0000FF0000000000ULL)
84       | ((a <<  8) & 0x000000FF00000000ULL)
85       | ((a >>  8) & 0x00000000FF000000ULL)
86       | ((a >> 24) & 0x0000000000FF0000ULL)
87       | ((a >> 40) & 0x000000000000FF00ULL)
88       | ((a >> 56) & 0x00000000000000FFULL) ;
89
90     return b;
91   #endif
92 }
93
94 #ifndef VOMPSTANDALONE
95 cChannel* MVPClient::channelFromNumber(ULONG channelNumber)
96 {
97   cChannel* channel = NULL;
98
99   for (channel = Channels.First(); channel; channel = Channels.Next(channel))
100   {
101     if (!channel->GroupSep())
102     {
103       log->log("Client", Log::DEBUG, "Looking for channel %lu::: number: %i name: '%s'", channelNumber, channel->Number(), channel->Name());
104
105       if (channel->Number() == (int)channelNumber)
106       {
107         int vpid = channel->Vpid();
108 #if VDRVERSNUM < 10300
109         int apid1 = channel->Apid1();
110 #else
111         int apid1 = channel->Apid(0);
112 #endif
113         log->log("Client", Log::DEBUG, "Found channel number %lu, vpid = %i, apid1 = %i", channelNumber, vpid, apid1);
114         return channel;
115       }
116     }
117   }
118
119   if (!channel)
120   {
121     log->log("Client", Log::DEBUG, "Channel not found");
122   }
123
124   return channel;
125 }
126
127 void MVPClient::writeResumeData()
128 {
129   config.setValueLong("ResumeData",
130                           (char*)rp->getCurrentRecording()->FileName(),
131                           rp->frameNumberFromPosition(rp->getLastPosition()) );
132 }
133 #endif
134
135 void MVPClient::sendULONG(ULONG ul)
136 {
137   UCHAR sendBuffer[8];
138   *(ULONG*)&sendBuffer[0] = htonl(4);
139   *(ULONG*)&sendBuffer[4] = htonl(ul);
140
141   tcp.sendPacket(sendBuffer, 8);
142   log->log("Client", Log::DEBUG, "written ULONG %lu", ul);
143 }
144
145 void MVPClientStartThread(void* arg)
146 {
147   MVPClient* m = (MVPClient*)arg;
148   m->run2();
149   // Nothing external to this class has a reference to it
150   // This is the end of the thread.. so delete m
151   delete m;
152   pthread_exit(NULL);
153 }
154
155 int MVPClient::run()
156 {
157   if (pthread_create(&runThread, NULL, (void*(*)(void*))MVPClientStartThread, (void *)this) == -1) return 0;
158   log->log("Client", Log::DEBUG, "MVPClient run success");
159   return 1;
160 }
161
162 void MVPClient::run2()
163 {
164   // Thread stuff
165   sigset_t sigset;
166   sigfillset(&sigset);
167   pthread_sigmask(SIG_BLOCK, &sigset, NULL);
168   pthread_detach(runThread);  // Detach
169
170   tcp.disableReadTimeout();
171
172   tcp.setSoKeepTime(3);
173   tcp.setNonBlocking();
174
175   ULONG channelID;
176   ULONG serialNumber;
177   ULONG opcode;
178   ULONG extraDataLength;
179   UCHAR* data;
180     
181   int result = 0;
182
183   while(1)
184   {
185     log->log("Client", Log::DEBUG, "Waiting");
186     
187     if (!tcp.readData((UCHAR*)&channelID, sizeof(ULONG))) break;
188     channelID = ntohl(channelID);
189     if (channelID != 1)
190     {
191       log->log("Client", Log::ERR, "Incoming channel number not 1!");
192       break;
193     }
194
195     log->log("Client", Log::DEBUG, "Got chan");
196     
197     if (!tcp.readData((UCHAR*)&serialNumber, sizeof(ULONG))) break;
198     serialNumber = ntohl(serialNumber);
199
200     log->log("Client", Log::DEBUG, "Got ser");
201
202     if (!tcp.readData((UCHAR*)&opcode, sizeof(ULONG))) break;
203     opcode = ntohl(opcode);
204
205     log->log("Client", Log::DEBUG, "Got op %lu", opcode);
206
207     if (!tcp.readData((UCHAR*)&extraDataLength, sizeof(ULONG))) break;
208     extraDataLength = ntohl(extraDataLength);
209     if (extraDataLength > 200000)
210     {
211       log->log("Client", Log::ERR, "ExtraDataLength > 200000!");
212       break;
213     }
214
215     log->log("Client", Log::DEBUG, "Got edl %lu", extraDataLength);
216
217     if (extraDataLength)
218     {
219       data = (UCHAR*)malloc(extraDataLength);
220       if (!data)
221       {
222         log->log("Client", Log::ERR, "Extra data buffer malloc error");
223         break;
224       }
225       
226       if (!tcp.readData(data, extraDataLength))
227       {
228         log->log("Client", Log::ERR, "Could not read extradata");
229         free(data);
230         break;
231       }      
232     }
233     else
234     {
235       data = NULL;
236     }
237
238     log->log("Client", Log::DEBUG, "Received chan=%lu, ser=%lu, op=%lu, edl=%lu", channelID, serialNumber, opcode, extraDataLength);
239
240     if (!loggedIn && (opcode != 1))
241     {
242       log->log("Client", Log::ERR, "Not logged in and opcode != 1");
243       if (data) free(data);
244       break;
245     }
246
247     switch(opcode)
248     {
249       case 1:
250         result = processLogin(data, extraDataLength);
251         break;
252 #ifndef VOMPSTANDALONE
253       case 2:
254         result = processGetRecordingsList(data, extraDataLength);
255         break;
256       case 3:
257         result = processDeleteRecording(data, extraDataLength);
258         break;
259       case 5:
260         result = processGetChannelsList(data, extraDataLength);
261         break;
262       case 6:
263         result = processStartStreamingChannel(data, extraDataLength);
264         break;
265       case 7:
266         result = processGetBlock(data, extraDataLength);
267         break;
268       case 8:
269         result = processStopStreaming(data, extraDataLength);
270         break;
271       case 9:
272         result = processStartStreamingRecording(data, extraDataLength);
273         break;
274       case 10:
275         result = processGetChannelSchedule(data, extraDataLength);
276         break;
277 #endif
278       case 11:
279         result = processConfigSave(data, extraDataLength);
280         break;
281       case 12:
282         result = processConfigLoad(data, extraDataLength);
283         break;
284 #ifndef VOMPSTANDALONE
285       case 13:
286         result = processReScanRecording(data, extraDataLength);         // FIXME obselete
287         break;
288       case 14:
289         result = processGetTimers(data, extraDataLength);
290         break;
291       case 15:
292         result = processSetTimer(data, extraDataLength);
293         break;
294       case 16:
295         result = processPositionFromFrameNumber(data, extraDataLength);
296         break;
297       case 17:
298         result = processFrameNumberFromPosition(data, extraDataLength);
299         break;
300       case 18:
301         result = processMoveRecording(data, extraDataLength);
302         break;
303       case 19:
304         result = processGetIFrame(data, extraDataLength);
305         break;
306       case 20:
307         result = processGetRecInfo(data, extraDataLength);
308         break;
309       case 21:
310         result = processGetMarks(data, extraDataLength);
311         break;
312       case 22:
313         result = processGetChannelPids(data, extraDataLength);
314         break;
315       case 23:
316         result = processDeleteTimer(data, extraDataLength);
317         break;
318 #endif
319       case 30:
320         result = processGetMediaList(data, extraDataLength);
321         break;
322       case 31:
323         result = processGetPicture(data, extraDataLength);
324         break;
325       case 32:
326         result = processGetImageBlock(data, extraDataLength);
327         break;
328     }
329
330     if (data) free(data);
331     if (!result) break;
332   }
333 }
334
335 int MVPClient::processLogin(UCHAR* buffer, int length)
336 {
337   if (length != 6) return 0;
338
339   // Open the config
340
341 #ifndef VOMPSTANDALONE
342   const char* configDir = cPlugin::ConfigDirectory(configDirExtra);
343 #else
344   const char* configDir = ".";
345 #endif
346   if (!configDir)
347   {
348     log->log("Client", Log::DEBUG, "No config dir!");
349     return 0;
350   }
351
352   char configFileName[PATH_MAX];
353   snprintf(configFileName, PATH_MAX, "%s/vomp-%02X-%02X-%02X-%02X-%02X-%02X.conf", configDir, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
354   config.init(configFileName);
355
356   // Send the login reply
357
358   time_t timeNow = time(NULL);
359   struct tm* timeStruct = localtime(&timeNow);
360   int timeOffset = timeStruct->tm_gmtoff;
361
362   UCHAR sendBuffer[12];
363   *(ULONG*)&sendBuffer[0] = htonl(8);
364   *(ULONG*)&sendBuffer[4] = htonl(timeNow);
365   *(signed int*)&sendBuffer[8] = htonl(timeOffset);
366
367   tcp.sendPacket(sendBuffer, 12);
368   log->log("Client", Log::DEBUG, "written login reply");
369
370   loggedIn = true;
371   return 1;
372 }
373
374 #ifndef VOMPSTANDALONE
375 int MVPClient::processGetRecordingsList(UCHAR* data, int length)
376 {
377   UCHAR* sendBuffer = new UCHAR[50000]; // hope this is enough
378   int count = 4; // leave space for the packet length
379   char* point;
380
381
382   int FreeMB;
383   int Percent = VideoDiskSpace(&FreeMB);
384   int Total = (FreeMB / (100 - Percent)) * 100;
385
386   *(ULONG*)&sendBuffer[count] = htonl(Total);
387   count += sizeof(ULONG);
388   *(ULONG*)&sendBuffer[count] = htonl(FreeMB);
389   count += sizeof(ULONG);
390   *(ULONG*)&sendBuffer[count] = htonl(Percent);
391   count += sizeof(ULONG);
392
393
394   cRecordings Recordings;
395   Recordings.Load();
396
397   for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
398   {
399     if (count > 49000) break; // just how big is that hard disk?!
400     *(ULONG*)&sendBuffer[count] = htonl(recording->start);// + timeOffset);
401     count += 4;
402
403     point = (char*)recording->Name();
404     strcpy((char*)&sendBuffer[count], point);
405     count += strlen(point) + 1;
406
407     point = (char*)recording->FileName();
408     strcpy((char*)&sendBuffer[count], point);
409     count += strlen(point) + 1;
410   }
411
412   *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
413
414   log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
415
416   tcp.sendPacket(sendBuffer, count);
417   delete[] sendBuffer;
418   log->log("Client", Log::DEBUG, "Written list");
419
420   return 1;
421 }
422
423 int MVPClient::processDeleteRecording(UCHAR* data, int length)
424 {
425   // data is a pointer to the fileName string
426
427   cRecordings Recordings;
428   Recordings.Load(); // probably have to do this
429
430   cRecording* recording = Recordings.GetByName((char*)data);
431
432   log->log("Client", Log::DEBUG, "recording pointer %p", recording);
433
434   if (recording)
435   {
436     log->log("Client", Log::DEBUG, "deleting recording: %s", recording->Name());
437
438     cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
439     if (!rc)
440     {
441       if (recording->Delete())
442       {
443         // Copy svdrp's way of doing this, see if it works
444 #if VDRVERSNUM > 10300
445         ::Recordings.DelByName(recording->FileName());
446 #endif
447         sendULONG(1);
448       }
449       else
450       {
451         sendULONG(2);
452       }
453     }
454     else
455     {
456       sendULONG(3);
457     }
458   }
459   else
460   {
461     sendULONG(4);
462   }
463
464   return 1;
465 }
466
467 int MVPClient::processMoveRecording(UCHAR* data, int length)
468 {
469   log->log("Client", Log::DEBUG, "Process move recording");
470   char* fileName = (char*)data;
471   char* newPath = NULL;
472
473   for (int k = 0; k < length; k++)
474   {
475     if (data[k] == '\0')
476     {
477       newPath = (char*)&data[k+1];
478       break;
479     }
480   }
481   if (!newPath) return 0;
482
483   cRecordings Recordings;
484   Recordings.Load(); // probably have to do this
485
486   cRecording* recording = Recordings.GetByName((char*)fileName);
487
488   log->log("Client", Log::DEBUG, "recording pointer %p", recording);
489
490   if (recording)
491   {
492     cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
493     if (!rc)
494     {
495       log->log("Client", Log::DEBUG, "moving recording: %s", recording->Name());
496       log->log("Client", Log::DEBUG, "moving recording: %s", recording->FileName());
497       log->log("Client", Log::DEBUG, "to: %s", newPath);
498
499       const char* t = recording->FileName();
500
501       char* dateDirName = NULL;   int k;
502       char* titleDirName = NULL;  int j;
503
504       // Find the datedirname
505       for(k = strlen(t) - 1; k >= 0; k--)
506       {
507         if (t[k] == '/')
508         {
509           log->log("Client", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
510           dateDirName = new char[strlen(&t[k+1]) + 1];
511           strcpy(dateDirName, &t[k+1]);
512           break;
513         }
514       }
515
516       // Find the titledirname
517
518       for(j = k-1; j >= 0; j--)
519       {
520         if (t[j] == '/')
521         {
522           log->log("Client", Log::DEBUG, "l2: %i", (k - j - 1) + 1);
523           titleDirName = new char[(k - j - 1) + 1];
524           memcpy(titleDirName, &t[j+1], k - j - 1);
525           titleDirName[k - j - 1] = '\0';
526           break;
527         }
528       }
529
530       log->log("Client", Log::DEBUG, "datedirname: %s", dateDirName);
531       log->log("Client", Log::DEBUG, "titledirname: %s", titleDirName);
532
533       log->log("Client", Log::DEBUG, "viddir: %s", VideoDirectory);
534
535       char* newContainer = new char[strlen(VideoDirectory) + strlen(newPath) + strlen(titleDirName) + 1];
536       log->log("Client", Log::DEBUG, "l10: %i", strlen(VideoDirectory) + strlen(newPath) + strlen(titleDirName) + 1);
537       sprintf(newContainer, "%s%s%s", VideoDirectory, newPath, titleDirName);
538
539       // FIXME Check whether this already exists before mkdiring it
540
541       log->log("Client", Log::DEBUG, "%s", newContainer);
542
543
544       struct stat dstat;
545       int statret = stat(newContainer, &dstat);
546       if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
547       {
548         log->log("Client", Log::DEBUG, "new dir does not exist");
549         int mkdirret = mkdir(newContainer, 0755);
550         if (mkdirret != 0)
551         {
552           delete[] dateDirName;
553           delete[] titleDirName;
554           delete[] newContainer;
555           sendULONG(5);
556           return 1;
557         }
558       }
559       else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR))) // Something exists but it's not a dir
560       {
561         delete[] dateDirName;
562         delete[] titleDirName;
563         delete[] newContainer;
564         sendULONG(5);
565         return 1;
566       }
567
568       // Ok, the directory container has been made, or it pre-existed.
569
570       char* newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
571       sprintf(newDir, "%s/%s", newContainer, dateDirName);
572
573       log->log("Client", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
574       int renameret = rename(t, newDir);
575       if (renameret == 0)
576       {
577         // Success. Test for remove old dir containter
578         char* oldTitleDir = new char[k+1];
579         memcpy(oldTitleDir, t, k);
580         oldTitleDir[k] = '\0';
581         log->log("Client", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(oldTitleDir), oldTitleDir);
582         rmdir(oldTitleDir); // can't do anything about a fail result at this point.
583         delete[] oldTitleDir;
584       }
585
586       if (renameret == 0)
587       {
588 #if VDRVERSNUM > 10311
589         // Tell VDR
590         ::Recordings.Update();
591 #endif
592         // Success. Send a different packet from just a ulong
593         int totalLength = 4 + 4 + strlen(newDir) + 1;
594         UCHAR* sendBuffer = new UCHAR[totalLength];
595         *(ULONG*)&sendBuffer[0] = htonl(totalLength - 4);
596         *(ULONG*)&sendBuffer[4] = htonl(1); // success
597         strcpy((char*)&sendBuffer[8], newDir);
598         tcp.sendPacket(sendBuffer, totalLength);
599         delete[] sendBuffer;
600       }
601       else
602       {
603         sendULONG(5);
604       }
605
606       delete[] dateDirName;
607       delete[] titleDirName;
608       delete[] newContainer;
609       delete[] newDir;
610     }
611     else
612     {
613       sendULONG(3);
614     }
615   }
616   else
617   {
618     sendULONG(4);
619   }
620
621   return 1;
622 }
623
624 int MVPClient::processGetChannelsList(UCHAR* data, int length)
625 {
626   UCHAR* sendBuffer = new UCHAR[50000]; // FIXME hope this is enough
627   int count = 4; // leave space for the packet length
628   char* point;
629   ULONG type;
630
631   char* chanConfig = config.getValueString("General", "Channels");
632   int allChans = 1;
633   if (chanConfig) allChans = strcasecmp(chanConfig, "FTA only");
634
635   for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
636   {
637 #if VDRVERSNUM < 10300
638     if (!channel->GroupSep() && (!channel->Ca() || allChans))
639 #else
640     if (!channel->GroupSep() && (!channel->Ca(0) || allChans))
641 #endif
642     {
643       log->log("Client", Log::DEBUG, "name: '%s'", channel->Name());
644
645       if (channel->Vpid()) type = 1;
646 #if VDRVERSNUM < 10300
647       else type = 2;
648 #else
649       else if (channel->Apid(0)) type = 2;
650       else continue;
651 #endif
652
653       if (count > 49000) break;
654       *(ULONG*)&sendBuffer[count] = htonl(channel->Number());
655       count += 4;
656
657       *(ULONG*)&sendBuffer[count] = htonl(type);
658       count += 4;
659
660       point = (char*)channel->Name();
661       strcpy((char*)&sendBuffer[count], point);
662       count += strlen(point) + 1;
663     }
664   }
665
666   *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
667
668   log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
669
670   tcp.sendPacket(sendBuffer, count);
671   delete[] sendBuffer;
672   log->log("Client", Log::DEBUG, "Written channels list");
673
674   return 1;
675 }
676
677 int MVPClient::processGetChannelPids(UCHAR* data, int length)
678 {
679   ULONG channelNumber = ntohl(*(ULONG*)data);
680
681   cChannel* channel = channelFromNumber(channelNumber);
682   if (!channel)
683   {
684     sendULONG(0);
685     return 1;
686   }
687
688   ULONG numApids = 0;
689   ULONG spaceRequired = 12; // 4 for length field, 4 for vpid, 4 for number of apids
690   // Work out space required and number of Apids
691
692 #if VDRVERSNUM < 10300
693
694   log->log("Client", Log::DEBUG, "Apid1: %i", channel->Apid1());
695   log->log("Client", Log::DEBUG, "Apid2: %i", channel->Apid2());
696
697   if (channel->Apid2())
698   {
699     numApids = 2;
700     spaceRequired += 10; // 8 + 2 nulls
701   }
702   else if (channel->Apid1())
703   {
704     numApids = 1;
705     spaceRequired += 5; // 4 + 1 null
706   }
707   else
708   {
709     numApids = 0;
710   }
711
712 #else
713
714   for (const int *Apid = channel->Apids(); *Apid; Apid++)
715   {
716     spaceRequired += 4 + strlen(channel->Alang(numApids)) + 1; // 4 for pid, length of string + \0
717     numApids++;
718   }
719 #endif
720
721
722   // Format of response
723   // vpid
724   // number of apids
725   // {
726   //    apid
727   //    lang string
728   // }
729
730   UCHAR* sendBuffer = new UCHAR[spaceRequired];
731   ULONG point = 0;
732   *(ULONG*)&sendBuffer[point] = htonl(spaceRequired - 4);   point += 4;   // take off first 4 bytes
733   *(ULONG*)&sendBuffer[point] = htonl(channel->Vpid());     point += 4;
734   *(ULONG*)&sendBuffer[point] = htonl(numApids);            point += 4;
735
736 #if VDRVERSNUM < 10300
737   if (numApids >= 1)
738   {
739     *(ULONG*)&sendBuffer[point] = htonl(channel->Apid1());  point += 4;
740     sendBuffer[point] = '\0';                               point += 1;
741   }
742   if (numApids == 2)
743   {
744     *(ULONG*)&sendBuffer[point] = htonl(channel->Apid2());  point += 4;
745     sendBuffer[point] = '\0';                               point += 1;
746   }
747 #else
748   for (ULONG i = 0; i < numApids; i++)
749   {
750     *(ULONG*)&sendBuffer[point] = htonl(channel->Apid(i));  point += 4;
751     strcpy((char*)&sendBuffer[point], channel->Alang(i));   point += strlen(channel->Alang(i)) + 1;
752   }
753 #endif
754
755 //  printf("About to send getchannelpids response. length = %u\n", spaceRequired);
756   //tcp.dump(sendBuffer, spaceRequired);
757
758   tcp.sendPacket(sendBuffer, spaceRequired);
759   delete[] sendBuffer;
760   log->log("Client", Log::DEBUG, "Written channels pids");
761
762   return 1;
763 }
764
765 int MVPClient::processStartStreamingChannel(UCHAR* data, int length)
766 {
767   log->log("Client", Log::DEBUG, "length = %i", length);
768   ULONG channelNumber = ntohl(*(ULONG*)data);
769
770   cChannel* channel = channelFromNumber(channelNumber);
771   if (!channel)
772   {
773     sendULONG(0);
774     return 1;
775   }
776
777   // get the priority we should use
778   int fail = 1;
779   int priority = config.getValueLong("General", "Live priority", &fail);
780   if (!fail)
781   {
782     log->log("Client", Log::DEBUG, "Config: Live TV priority: %i", priority);
783   }
784   else
785   {
786     log->log("Client", Log::DEBUG, "Config: Live TV priority config fail");
787     priority = 0;
788   }
789
790   // a bit of sanity..
791   if (priority < 0) priority = 0;
792   if (priority > 99) priority = 99;
793
794   log->log("Client", Log::DEBUG, "Using live TV priority %i", priority);
795   lp = MVPReceiver::create(channel, priority);
796
797   if (!lp)
798   {
799     sendULONG(0);
800     return 1;
801   }
802
803   if (!lp->init())
804   {
805     delete lp;
806     lp = NULL;
807     sendULONG(0);
808     return 1;
809   }
810
811   sendULONG(1);
812   return 1;
813 }
814
815 int MVPClient::processStopStreaming(UCHAR* data, int length)
816 {
817   log->log("Client", Log::DEBUG, "STOP STREAMING RECEIVED");
818   if (lp)
819   {
820     delete lp;
821     lp = NULL;
822   }
823   else if (rp)
824   {
825     writeResumeData();
826
827     delete rp;
828     delete recordingManager;
829     rp = NULL;
830     recordingManager = NULL;
831   }
832
833   sendULONG(1);
834   return 1;
835 }
836
837 int MVPClient::processGetBlock(UCHAR* data, int length)
838 {
839   if (!lp && !rp)
840   {
841     log->log("Client", Log::DEBUG, "Get block called when no streaming happening!");
842     return 0;
843   }
844
845   ULLONG position = ntohll(*(ULLONG*)data);
846   data += sizeof(ULLONG);
847   ULONG amount = ntohl(*(ULONG*)data);
848
849   log->log("Client", Log::DEBUG, "getblock pos = %llu length = %lu", position, amount);
850
851   UCHAR sendBuffer[amount + 4];
852   ULONG amountReceived = 0; // compiler moan.
853   if (lp)
854   {
855     log->log("Client", Log::DEBUG, "getting from live");
856     amountReceived = lp->getBlock(&sendBuffer[4], amount);
857
858     if (!amountReceived)
859     {
860       // vdr has possibly disconnected the receiver
861       log->log("Client", Log::DEBUG, "VDR has disconnected the live receiver");
862       delete lp;
863       lp = NULL;
864     }
865   }
866   else if (rp)
867   {
868     log->log("Client", Log::DEBUG, "getting from recording");
869     amountReceived = rp->getBlock(&sendBuffer[4], position, amount);
870   }
871
872   if (!amountReceived)
873   {
874     sendULONG(0);
875     log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0");
876   }
877   else
878   {
879     *(ULONG*)&sendBuffer[0] = htonl(amountReceived);
880     tcp.sendPacket(sendBuffer, amountReceived + 4);
881     log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
882   }
883
884   return 1;
885 }
886
887 int MVPClient::processStartStreamingRecording(UCHAR* data, int length)
888 {
889   // data is a pointer to the fileName string
890
891   recordingManager = new cRecordings;
892   recordingManager->Load();
893
894   cRecording* recording = recordingManager->GetByName((char*)data);
895
896   log->log("Client", Log::DEBUG, "recording pointer %p", recording);
897
898   if (recording)
899   {
900     rp = new RecPlayer(recording);
901
902     UCHAR sendBuffer[16];
903     *(ULONG*)&sendBuffer[0] = htonl(12);
904     *(ULLONG*)&sendBuffer[4] = htonll(rp->getLengthBytes());
905     *(ULONG*)&sendBuffer[12] = htonl(rp->getLengthFrames());
906
907     tcp.sendPacket(sendBuffer, 16);
908     log->log("Client", Log::DEBUG, "written totalLength");
909   }
910   else
911   {
912     delete recordingManager;
913     recordingManager = NULL;
914   }
915   return 1;
916 }
917
918 int MVPClient::processPositionFromFrameNumber(UCHAR* data, int length)
919 {
920   ULLONG retval = 0;
921
922   ULONG frameNumber = ntohl(*(ULONG*)data);
923   data += 4;
924
925   if (!rp)
926   {
927     log->log("Client", Log::DEBUG, "Rescan recording called when no recording being played!");
928   }
929   else
930   {
931     retval = rp->positionFromFrameNumber(frameNumber);
932   }
933
934   UCHAR sendBuffer[12];
935   *(ULONG*)&sendBuffer[0] = htonl(8);
936   *(ULLONG*)&sendBuffer[4] = htonll(retval);
937
938   tcp.sendPacket(sendBuffer, 12);
939   log->log("Client", Log::DEBUG, "Wrote posFromFrameNum reply to client");
940   return 1;
941 }
942
943 int MVPClient::processFrameNumberFromPosition(UCHAR* data, int length)
944 {
945   ULONG retval = 0;
946
947   ULLONG position = ntohll(*(ULLONG*)data);
948   data += 8;
949
950   if (!rp)
951   {
952     log->log("Client", Log::DEBUG, "Rescan recording called when no recording being played!");
953   }
954   else
955   {
956     retval = rp->frameNumberFromPosition(position);
957   }
958
959   UCHAR sendBuffer[8];
960   *(ULONG*)&sendBuffer[0] = htonl(4);
961   *(ULONG*)&sendBuffer[4] = htonl(retval);
962
963   tcp.sendPacket(sendBuffer, 8);
964   log->log("Client", Log::DEBUG, "Wrote frameNumFromPos reply to client");
965   return 1;
966 }
967
968 int MVPClient::processGetIFrame(UCHAR* data, int length)
969 {
970   bool success = false;
971
972   ULONG frameNumber = ntohl(*(ULONG*)data);
973   data += 4;
974   ULONG direction = ntohl(*(ULONG*)data);
975   data += 4;
976
977   ULLONG rfilePosition = 0;
978   ULONG rframeNumber = 0;
979   ULONG rframeLength = 0;
980
981   if (!rp)
982   {
983     log->log("Client", Log::DEBUG, "GetIFrame recording called when no recording being played!");
984   }
985   else
986   {
987     success = rp->getNextIFrame(frameNumber, direction, &rfilePosition, &rframeNumber, &rframeLength);
988   }
989
990   // returns file position, frame number, length
991
992   UCHAR sendBuffer[20];
993   int packetLength;
994
995   if (success)
996   {
997     packetLength = 20;
998     *(ULONG*)&sendBuffer[0] = htonl(16);
999     *(ULLONG*)&sendBuffer[4] = htonll(rfilePosition);
1000     *(ULONG*)&sendBuffer[12] = htonl(rframeNumber);
1001     *(ULONG*)&sendBuffer[16] = htonl(rframeLength);
1002   }
1003   else
1004   {
1005     packetLength = 8;
1006     *(ULONG*)&sendBuffer[0] = htonl(4);
1007     *(ULONG*)&sendBuffer[4] = 0;
1008   }
1009
1010   log->log("Client", Log::DEBUG, "%llu %lu %lu", rfilePosition, rframeNumber, rframeLength);
1011
1012   tcp.sendPacket(sendBuffer, packetLength);
1013   log->log("Client", Log::DEBUG, "Wrote GNIF reply to client");
1014   return 1;
1015 }
1016
1017 int MVPClient::processGetChannelSchedule(UCHAR* data, int length)
1018 {
1019   ULONG channelNumber = ntohl(*(ULONG*)data);
1020   data += 4;
1021   ULONG startTime = ntohl(*(ULONG*)data);
1022   data += 4;
1023   ULONG duration = ntohl(*(ULONG*)data);
1024
1025   log->log("Client", Log::DEBUG, "get schedule called for channel %lu", channelNumber);
1026
1027   cChannel* channel = channelFromNumber(channelNumber);
1028   if (!channel)
1029   {
1030     sendULONG(0);
1031     log->log("Client", Log::DEBUG, "written 0 because channel = NULL");
1032     return 1;
1033   }
1034
1035   log->log("Client", Log::DEBUG, "Got channel");
1036
1037 #if VDRVERSNUM < 10300
1038   cMutexLock MutexLock;
1039   const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1040 #else
1041   cSchedulesLock MutexLock;
1042   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
1043 #endif
1044   if (!Schedules)
1045   {
1046     sendULONG(0);
1047     log->log("Client", Log::DEBUG, "written 0 because Schedule!s! = NULL");
1048     return 1;
1049   }
1050
1051   log->log("Client", Log::DEBUG, "Got schedule!s! object");
1052
1053   const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
1054   if (!Schedule)
1055   {
1056     sendULONG(0);
1057     log->log("Client", Log::DEBUG, "written 0 because Schedule = NULL");
1058     return 1;
1059   }
1060
1061   log->log("Client", Log::DEBUG, "Got schedule object");
1062
1063   UCHAR* sendBuffer = (UCHAR*)malloc(100000);
1064   ULONG sendBufferLength = 100000;
1065   ULONG sendBufferUsed = sizeof(ULONG); // leave a hole for the entire packet length
1066
1067   const char* empty = "";
1068
1069   // assign all the event info to temp vars then we know exactly what size they are
1070   ULONG thisEventID;
1071   ULONG thisEventTime;
1072   ULONG thisEventDuration;
1073   const char* thisEventTitle;
1074   const char* thisEventSubTitle;
1075   const char* thisEventDescription;
1076
1077   ULONG constEventLength = sizeof(thisEventID) + sizeof(thisEventTime) + sizeof(thisEventDuration);
1078   ULONG thisEventLength;
1079
1080 #if VDRVERSNUM < 10300
1081
1082   const cEventInfo *event;
1083   for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1084   {
1085     event = Schedule->GetEventNumber(eventNumber);
1086
1087     thisEventID = event->GetEventID();
1088     thisEventTime = event->GetTime();
1089     thisEventDuration = event->GetDuration();
1090     thisEventTitle = event->GetTitle();
1091     thisEventSubTitle = event->GetSubtitle();
1092     thisEventDescription = event->GetExtendedDescription();
1093
1094 #else
1095
1096   for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
1097   {
1098     thisEventID = event->EventID();
1099     thisEventTime = event->StartTime();
1100     thisEventDuration = event->Duration();
1101     thisEventTitle = event->Title();
1102     thisEventSubTitle = NULL;
1103     thisEventDescription = event->Description();
1104
1105 #endif
1106
1107     log->log("Client", Log::DEBUG, "Got an event object %p", event);
1108
1109     //in the past filter
1110     if ((thisEventTime + thisEventDuration) < (ULONG)time(NULL)) continue;
1111
1112     //start time filter
1113     if ((thisEventTime + thisEventDuration) <= startTime) continue;
1114
1115     //duration filter
1116     if (thisEventTime >= (startTime + duration)) continue;
1117
1118     if (!thisEventTitle) thisEventTitle = empty;
1119     if (!thisEventSubTitle) thisEventSubTitle = empty;
1120     if (!thisEventDescription) thisEventDescription = empty;
1121
1122     thisEventLength = constEventLength + strlen(thisEventTitle) + 1 + strlen(thisEventSubTitle) + 1 + strlen(thisEventDescription) + 1;
1123
1124     log->log("Client", Log::DEBUG, "Done s1");
1125
1126     // now extend the buffer if necessary
1127     if ((sendBufferUsed + thisEventLength) > sendBufferLength)
1128     {
1129       log->log("Client", Log::DEBUG, "Extending buffer");
1130       sendBufferLength += 100000;
1131       UCHAR* temp = (UCHAR*)realloc(sendBuffer, sendBufferLength);
1132       if (temp == NULL)
1133       {
1134         free(sendBuffer);
1135         UCHAR sendBuffer2[8];
1136         *(ULONG*)&sendBuffer2[0] = htonl(4);
1137         *(ULONG*)&sendBuffer2[4] = htonl(0);
1138         tcp.sendPacket(sendBuffer2, 8);
1139         log->log("Client", Log::DEBUG, "written 0 because failed to realloc packet");
1140         return 1;
1141       }
1142       sendBuffer = temp;
1143     }
1144
1145     log->log("Client", Log::DEBUG, "Done s2");
1146
1147     *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventID);       sendBufferUsed += sizeof(ULONG);
1148     *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventTime);     sendBufferUsed += sizeof(ULONG);
1149     *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventDuration); sendBufferUsed += sizeof(ULONG);
1150
1151     strcpy((char*)&sendBuffer[sendBufferUsed], thisEventTitle);       sendBufferUsed += strlen(thisEventTitle) + 1;
1152     strcpy((char*)&sendBuffer[sendBufferUsed], thisEventSubTitle);    sendBufferUsed += strlen(thisEventSubTitle) + 1;
1153     strcpy((char*)&sendBuffer[sendBufferUsed], thisEventDescription); sendBufferUsed += strlen(thisEventDescription) + 1;
1154
1155     log->log("Client", Log::DEBUG, "Done s3 %lu", sendBufferUsed);
1156   }
1157
1158   log->log("Client", Log::DEBUG, "Got all event data");
1159
1160   if (sendBufferUsed == sizeof(ULONG))
1161   {
1162     // No data
1163     sendULONG(0);
1164     log->log("Client", Log::DEBUG, "Written 0 because no data");
1165   }
1166   else
1167   {
1168     // Write the length into the first 4 bytes. It's sendBufferUsed - 4 because of the hole!
1169     *(ULONG*)&sendBuffer[0] = htonl(sendBufferUsed - sizeof(ULONG));
1170     tcp.sendPacket(sendBuffer, sendBufferUsed);
1171     log->log("Client", Log::DEBUG, "written %lu schedules packet", sendBufferUsed);
1172   }
1173
1174   free(sendBuffer);
1175
1176   return 1;
1177 }
1178
1179 #endif //VOMPSTANDALONE
1180
1181 int MVPClient::processConfigSave(UCHAR* buffer, int length)
1182 {
1183   char* section = (char*)buffer;
1184   char* key = NULL;
1185   char* value = NULL;
1186
1187   for (int k = 0; k < length; k++)
1188   {
1189     if (buffer[k] == '\0')
1190     {
1191       if (!key)
1192       {
1193         key = (char*)&buffer[k+1];
1194       }
1195       else
1196       {
1197         value = (char*)&buffer[k+1];
1198         break;
1199       }
1200     }
1201   }
1202
1203   // if the last string (value) doesnt have null terminator, give up
1204   if (buffer[length - 1] != '\0') return 0;
1205
1206   log->log("Client", Log::DEBUG, "Config save: %s %s %s", section, key, value);
1207   if (config.setValueString(section, key, value))
1208   {
1209     sendULONG(1);
1210   }
1211   else
1212   {
1213     sendULONG(0);
1214   }
1215
1216   return 1;
1217 }
1218
1219 int MVPClient::processConfigLoad(UCHAR* buffer, int length)
1220 {
1221   char* section = (char*)buffer;
1222   char* key = NULL;
1223
1224   for (int k = 0; k < length; k++)
1225   {
1226     if (buffer[k] == '\0')
1227     {
1228       key = (char*)&buffer[k+1];
1229       break;
1230     }
1231   }
1232
1233   char* value = config.getValueString(section, key);
1234
1235   if (value)
1236   {
1237     UCHAR sendBuffer[4 + strlen(value) + 1];
1238     *(ULONG*)&sendBuffer[0] = htonl(strlen(value) + 1);
1239     strcpy((char*)&sendBuffer[4], value);
1240     tcp.sendPacket(sendBuffer, 4 + strlen(value) + 1);
1241
1242     log->log("Client", Log::DEBUG, "Written config load packet");
1243     delete[] value;
1244   }
1245   else
1246   {
1247     UCHAR sendBuffer[8];
1248     *(ULONG*)&sendBuffer[0] = htonl(4);
1249     *(ULONG*)&sendBuffer[4] = htonl(0);
1250     tcp.sendPacket(sendBuffer, 8);
1251
1252     log->log("Client", Log::DEBUG, "Written config load failed packet");
1253   }
1254
1255   return 1;
1256 }
1257
1258 void MVPClient::cleanConfig()
1259 {
1260   log->log("Client", Log::DEBUG, "Clean config");
1261
1262 #ifndef VOMPSTANDALONE
1263   cRecordings Recordings;
1264   Recordings.Load();
1265
1266   int numReturns;
1267   int length;
1268   char* resumes = config.getSectionKeyNames("ResumeData", numReturns, length);
1269   char* position = resumes;
1270   for(int k = 0; k < numReturns; k++)
1271   {
1272     log->log("Client", Log::DEBUG, "EXAMINING: %i %i %p %s", k, numReturns, position, position);
1273
1274     cRecording* recording = Recordings.GetByName(position);
1275     if (!recording)
1276     {
1277       // doesn't exist anymore
1278       log->log("Client", Log::DEBUG, "Found a recording that doesn't exist anymore");
1279       config.deleteValue("ResumeData", position);
1280     }
1281     else
1282     {
1283       log->log("Client", Log::DEBUG, "This recording still exists");
1284     }
1285
1286     position += strlen(position) + 1;
1287   }
1288
1289   delete[] resumes;
1290 #endif
1291 }
1292
1293
1294
1295
1296
1297
1298 /*
1299     event = Schedule->GetPresentEvent();
1300
1301     fprintf(f, "\n\nCurrent event\n\n");
1302
1303     fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", 0, event->GetEventID(), event->GetTime(), event->GetDuration());
1304     fprintf(f, "Event %i title = %s subtitle = %s\n", 0, event->GetTitle(), event->GetSubtitle());
1305     fprintf(f, "Event %i extendeddescription = %s\n", 0, event->GetExtendedDescription());
1306     fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", 0, event->IsFollowing(), event->IsPresent());
1307
1308     event = Schedule->GetFollowingEvent();
1309
1310     fprintf(f, "\n\nFollowing event\n\n");
1311
1312     fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", 0, event->GetEventID(), event->GetTime(), event->GetDuration());
1313     fprintf(f, "Event %i title = %s subtitle = %s\n", 0, event->GetTitle(), event->GetSubtitle());
1314     fprintf(f, "Event %i extendeddescription = %s\n", 0, event->GetExtendedDescription());
1315     fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", 0, event->IsFollowing(), event->IsPresent());
1316
1317     fprintf(f, "\n\n");
1318 */
1319
1320 /*
1321     fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", eventNumber, event->GetEventID(), event->GetTime(), event->GetDuration());
1322     fprintf(f, "Event %i title = %s subtitle = %s\n", eventNumber, event->GetTitle(), event->GetSubtitle());
1323     fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
1324     fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", eventNumber, event->IsFollowing(), event->IsPresent());
1325
1326     fprintf(f, "\n\n");
1327 */
1328
1329 /*
1330
1331
1332 void MVPClient::test2()
1333 {
1334   FILE* f = fopen("/tmp/s.txt", "w");
1335
1336 #if VDRVERSNUM < 10300
1337   cMutexLock MutexLock;
1338   const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1339 #else
1340   cSchedulesLock MutexLock;
1341   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
1342 #endif
1343
1344   if (!Schedules)
1345   {
1346     fprintf(f, "Schedules = NULL\n");
1347     fclose(f);
1348     return;
1349   }
1350
1351   fprintf(f, "Schedules dump:\n");
1352   Schedules->Dump(f);
1353
1354
1355   const cSchedule *Schedule;
1356   int scheduleNumber = 0;
1357
1358   tChannelID tchid;
1359   cChannel *thisChannel;
1360
1361 #if VDRVERSNUM < 10300
1362   const cEventInfo *event;
1363   int eventNumber = 0;
1364 #else
1365   const cEvent *event;
1366 #endif
1367
1368 //    Schedule = Schedules->GetSchedule(channel->GetChannelID());
1369 //    Schedule = Schedules->GetSchedule();
1370   Schedule = Schedules->First();
1371   if (!Schedule)
1372   {
1373     fprintf(f, "First Schedule = NULL\n");
1374     fclose(f);
1375     return;
1376   }
1377
1378   while (Schedule)
1379   {
1380     fprintf(f, "Schedule #%i\n", scheduleNumber);
1381     fprintf(f, "-------------\n\n");
1382
1383 #if VDRVERSNUM < 10300
1384     tchid = Schedule->GetChannelID();
1385 #else
1386     tchid = Schedule->ChannelID();
1387 #endif
1388
1389 #if VDRVERSNUM < 10300
1390     fprintf(f, "ChannelID.ToString() = %s\n", tchid.ToString());
1391     fprintf(f, "NumEvents() = %i\n", Schedule->NumEvents());
1392 #else
1393 //  put the count at the end.
1394 #endif
1395
1396     thisChannel = Channels.GetByChannelID(tchid, true);
1397     if (thisChannel)
1398     {
1399       fprintf(f, "Channel Number: %p %i\n", thisChannel, thisChannel->Number());
1400     }
1401     else
1402     {
1403       fprintf(f, "thisChannel = NULL for tchid\n");
1404     }
1405
1406 #if VDRVERSNUM < 10300
1407     for (eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1408     {
1409       event = Schedule->GetEventNumber(eventNumber);
1410       fprintf(f, "Event %i tableid = %i timestring = %s endtimestring = %s\n", eventNumber, event->GetTableID(), event->GetTimeString(), event->GetEndTimeString());
1411       fprintf(f, "Event %i date = %s isfollowing = %i ispresent = %i\n", eventNumber, event->GetDate(), event->IsFollowing(), event->IsPresent());
1412       fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
1413       fprintf(f, "Event %i subtitle = %s title = %s\n", eventNumber, event->GetSubtitle(), event->GetTitle());
1414       fprintf(f, "Event %i eventid = %u duration = %li time = %lu channelnumber = %i\n", eventNumber, event->GetEventID(), event->GetDuration(), event->GetTime(), event->GetChannelNumber());
1415       fprintf(f, "Event %u dump:\n", eventNumber);
1416       event->Dump(f);
1417       fprintf(f, "\n\n");
1418     }
1419 #else
1420 //  This whole section needs rewriting to walk the list.
1421     event = Schedule->Events()->First();
1422     while (event) {
1423       event = Schedule->Events()->Next(event);
1424     }
1425 #endif
1426
1427
1428     fprintf(f, "\nDump from object:\n");
1429     Schedule->Dump(f);
1430     fprintf(f, "\nEND\n");
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440     fprintf(f, "End of current Schedule\n\n\n");
1441
1442     Schedule = (const cSchedule *)Schedules->Next(Schedule);
1443     scheduleNumber++;
1444   }
1445
1446   fclose(f);
1447 }
1448
1449
1450
1451 */
1452
1453
1454
1455 /*
1456   const cEventInfo *GetPresentEvent(void) const;
1457   const cEventInfo *GetFollowingEvent(void) const;
1458   const cEventInfo *GetEvent(unsigned short uEventID, time_t tTime = 0) const;
1459   const cEventInfo *GetEventAround(time_t tTime) const;
1460   const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); }
1461
1462
1463   const unsigned char GetTableID(void) const;
1464   const char *GetTimeString(void) const;
1465   const char *GetEndTimeString(void) const;
1466   const char *GetDate(void) const;
1467   bool IsFollowing(void) const;
1468   bool IsPresent(void) const;
1469   const char *GetExtendedDescription(void) const;
1470   const char *GetSubtitle(void) const;
1471   const char *GetTitle(void) const;
1472   unsigned short GetEventID(void) const;
1473   long GetDuration(void) const;
1474   time_t GetTime(void) const;
1475   tChannelID GetChannelID(void) const;
1476   int GetChannelNumber(void) const { return nChannelNumber; }
1477   void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const'
1478   void Dump(FILE *f, const char *Prefix = "") const;
1479
1480 */
1481
1482
1483 /*
1484 void MVPClient::test(int channelNumber)
1485 {
1486   FILE* f = fopen("/tmp/test.txt", "w");
1487
1488   cMutexLock MutexLock;
1489   const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1490
1491   if (!Schedules)
1492   {
1493     fprintf(f, "Schedules = NULL\n");
1494     fclose(f);
1495     return;
1496   }
1497
1498   fprintf(f, "Schedules dump:\n");
1499 //  Schedules->Dump(f);
1500
1501   const cSchedule *Schedule;
1502   cChannel *thisChannel;
1503   const cEventInfo *event;
1504
1505   thisChannel = channelFromNumber(channelNumber);
1506   if (!thisChannel)
1507   {
1508     fprintf(f, "thisChannel = NULL\n");
1509     fclose(f);
1510     return;
1511   }
1512
1513   Schedule = Schedules->GetSchedule(thisChannel->GetChannelID());
1514 //    Schedule = Schedules->GetSchedule();
1515 //  Schedule = Schedules->First();
1516   if (!Schedule)
1517   {
1518     fprintf(f, "First Schedule = NULL\n");
1519     fclose(f);
1520     return;
1521   }
1522
1523   fprintf(f, "NumEvents() = %i\n\n", Schedule->NumEvents());
1524
1525   // For some channels VDR seems to pick a random point in time to
1526   // start dishing out events, but they are in order
1527   // at some point in the list the time snaps to the current event
1528
1529
1530
1531
1532   for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1533   {
1534     event = Schedule->GetEventNumber(eventNumber);
1535     fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", eventNumber, event->GetEventID(), event->GetTime(), event->GetDuration());
1536     fprintf(f, "Event %i title = %s subtitle = %s\n", eventNumber, event->GetTitle(), event->GetSubtitle());
1537     fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
1538     fprintf(f, "\n\n");
1539   }
1540
1541   fprintf(f, "\nEND\n");
1542
1543   fclose(f);
1544 }
1545
1546 */
1547
1548
1549
1550 /*
1551
1552
1553 Right, so
1554
1555 Schedules = the collection of all the Schedule objects
1556 Schedule  = One schedule, contants all the events for a channel
1557 Event     = One programme
1558
1559
1560 Want:
1561
1562 Event ID
1563 Time
1564 Duration
1565 Title
1566 Subtitle (used for "Programmes resume at ...")
1567 Description
1568
1569 IsPresent ? easy to work out tho. Oh it doesn't always work
1570
1571 */
1572
1573 /*
1574 void MVPClient::test2()
1575 {
1576   log->log("-", Log::DEBUG, "Timers List");
1577
1578   for (int i = 0; i < Timers.Count(); i++)
1579   {
1580     cTimer *timer = Timers.Get(i);
1581     //Reply(i < Timers.Count() - 1 ? -250 : 250, "%d %s", timer->Index() + 1, timer->ToText());
1582     log->log("-", Log::DEBUG, "i=%i count=%i index=%d", i, Timers.Count(), timer->Index() + 1);
1583 #if VDRVERSNUM < 10300
1584     log->log("-", Log::DEBUG, "active=%i recording=%i pending=%i start=%li stop=%li priority=%i lifetime=%i", timer->Active(), timer->Recording(), timer->Pending(), timer->StartTime(), timer->StopTime(), timer->Priority(), timer->Lifetime());
1585 #else
1586     log->log("-", Log::DEBUG, "active=%i recording=%i pending=%i start=%li stop=%li priority=%i lifetime=%i", timer->HasFlags(tfActive), timer->Recording(), timer->Pending(), timer->StartTime(), timer->StopTime(), timer->Priority(), timer->Lifetime());
1587 #endif
1588     log->log("-", Log::DEBUG, "channel=%i file=%s summary=%s", timer->Channel()->Number(), timer->File(), timer->Summary());
1589     log->log("-", Log::DEBUG, "");
1590   }
1591
1592   // asprintf(&buffer, "%d:%s:%s  :%04d:%04d:%d:%d:%s:%s\n",
1593 //            active, (UseChannelID ? Channel()->GetChannelID().ToString() : itoa(Channel()->Number())),
1594 //            PrintDay(day, firstday), start, stop, priority, lifetime, file, summary ? summary : "");
1595 }
1596 */
1597
1598 /*
1599 Active seems to be a bool - whether the timer should be done or not. If set to inactive it stays around after its time
1600 recording is a bool, 0 for not currently recording, 1 for currently recording
1601 pending is a bool, 0 for would not be trying to record this right now, 1 for would/is trying to record this right now
1602 */
1603
1604 #ifndef VOMPSTANDALONE
1605
1606 int MVPClient::processGetTimers(UCHAR* buffer, int length)
1607 {
1608   UCHAR* sendBuffer = new UCHAR[50000]; // FIXME hope this is enough
1609   int count = 4; // leave space for the packet length
1610
1611   const char* fileName;
1612   cTimer *timer;
1613   int numTimers = Timers.Count();
1614
1615   *(ULONG*)&sendBuffer[count] = htonl(numTimers);    count += 4;
1616
1617   for (int i = 0; i < numTimers; i++)
1618   {
1619     if (count > 49000) break;
1620
1621     timer = Timers.Get(i);
1622
1623 #if VDRVERSNUM < 10300
1624     *(ULONG*)&sendBuffer[count] = htonl(timer->Active());                 count += 4;
1625 #else
1626     *(ULONG*)&sendBuffer[count] = htonl(timer->HasFlags(tfActive));       count += 4;
1627 #endif
1628     *(ULONG*)&sendBuffer[count] = htonl(timer->Recording());              count += 4;
1629     *(ULONG*)&sendBuffer[count] = htonl(timer->Pending());                count += 4;
1630     *(ULONG*)&sendBuffer[count] = htonl(timer->Priority());               count += 4;
1631     *(ULONG*)&sendBuffer[count] = htonl(timer->Lifetime());               count += 4;
1632     *(ULONG*)&sendBuffer[count] = htonl(timer->Channel()->Number());      count += 4;
1633     *(ULONG*)&sendBuffer[count] = htonl(timer->StartTime());              count += 4;
1634     *(ULONG*)&sendBuffer[count] = htonl(timer->StopTime());               count += 4;
1635     *(ULONG*)&sendBuffer[count] = htonl(timer->Day());                    count += 4;
1636     *(ULONG*)&sendBuffer[count] = htonl(timer->WeekDays());               count += 4;
1637
1638     fileName = timer->File();
1639     strcpy((char*)&sendBuffer[count], fileName);
1640     count += strlen(fileName) + 1;
1641   }
1642
1643   *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
1644
1645   log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
1646
1647 //tcp.dump(sendBuffer, count);
1648
1649   tcp.sendPacket(sendBuffer, count);
1650   delete[] sendBuffer;
1651   log->log("Client", Log::DEBUG, "Written timers list");
1652
1653   return 1;
1654 }
1655
1656 int MVPClient::processSetTimer(UCHAR* buffer, int length)
1657 {
1658   char* timerString = new char[strlen((char*)buffer) + 1];
1659   strcpy(timerString, (char*)buffer);
1660
1661 #if VDRVERSNUM < 10300
1662
1663   // If this is VDR 1.2 the date part of the timer string must be reduced
1664   // to just DD rather than YYYY-MM-DD
1665
1666   int s = 0; // source
1667   int d = 0; // destination
1668   int c = 0; // count
1669   while(c != 2) // copy up to date section, including the second ':'
1670   {
1671     timerString[d] = buffer[s];
1672     if (buffer[s] == ':') c++;
1673     ++s;
1674     ++d;
1675   }
1676   // now it has copied up to the date section
1677   c = 0;
1678   while(c != 2) // waste YYYY-MM-
1679   {
1680     if (buffer[s] == '-') c++;
1681     ++s;
1682   }
1683   // now source is at the DD
1684   memcpy(&timerString[d], &buffer[s], length - s);
1685   d += length - s;
1686   timerString[d] = '\0';
1687
1688   log->log("Client", Log::DEBUG, "Timer string after 1.2 conversion:");
1689   log->log("Client", Log::DEBUG, "%s", timerString);
1690
1691 #endif
1692
1693   cTimer *timer = new cTimer;
1694   if (timer->Parse((char*)timerString))
1695   {
1696     cTimer *t = Timers.GetTimer(timer);
1697     if (!t)
1698     {
1699       Timers.Add(timer);
1700 #if VDRVERSNUM < 10300
1701       Timers.Save();
1702 #else
1703       Timers.SetModified();
1704 #endif
1705       sendULONG(0);
1706       return 1;
1707     }
1708     else
1709     {
1710       sendULONG(1);
1711     }
1712   }
1713   else
1714   {
1715      sendULONG(2);
1716   }
1717   delete timer;
1718   return 1;
1719 }
1720
1721 #endif //VOMPSTANDALONE
1722
1723 void MVPClient::incClients()
1724 {
1725   pthread_mutex_lock(&threadClientMutex);
1726   MVPClient::nr_clients++;
1727   pthread_mutex_unlock(&threadClientMutex);
1728 }
1729
1730 void MVPClient::decClients()
1731 {
1732   pthread_mutex_lock(&threadClientMutex);
1733   MVPClient::nr_clients--;
1734   pthread_mutex_unlock(&threadClientMutex);
1735 }
1736
1737 int MVPClient::getNrClients()
1738 {
1739   int nrClients;
1740   pthread_mutex_lock(&threadClientMutex);
1741   nrClients = MVPClient::nr_clients;
1742   pthread_mutex_unlock(&threadClientMutex);
1743   return nrClients;
1744 }
1745
1746 #ifndef VOMPSTANDALONE
1747
1748 int MVPClient::processGetRecInfo(UCHAR* data, int length)
1749 {
1750   // data is a pointer to the fileName string
1751
1752   cRecordings Recordings;
1753   Recordings.Load(); // probably have to do this
1754
1755   cRecording *recording = Recordings.GetByName((char*)data);
1756
1757   time_t timerStart = 0;
1758   time_t timerStop = 0;
1759   char* summary = NULL;
1760   ULONG resumePoint = 0;
1761
1762   if (!recording)
1763   {
1764     log->log("Client", Log::ERR, "GetRecInfo found no recording");
1765     sendULONG(0);
1766     return 1;
1767   }
1768
1769   ULONG sendBufferSize = 10000;
1770   UCHAR* sendBuffer = (UCHAR*)malloc(sendBufferSize);
1771   ULONG pos = 4; // leave first 4 bytes for size field
1772
1773
1774   /* Return packet:
1775   4 bytes: start time for timer
1776   4 bytes: end time for timer
1777   4 bytes: resume point
1778   string: summary
1779   4 bytes: num components
1780   {
1781     1 byte: stream
1782     1 byte: type
1783     string: language
1784     string: description
1785   }
1786
1787   */
1788
1789   // Get current timer
1790
1791   cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
1792   if (rc)
1793   {
1794     timerStart = rc->Timer()->StartTime();
1795     timerStop = rc->Timer()->StopTime();
1796     log->log("Client", Log::DEBUG, "GRI: RC: %lu %lu", timerStart, timerStop);
1797   }
1798
1799   *(time_t*)&sendBuffer[pos] = htonl(timerStart);    pos += 4;
1800   *(time_t*)&sendBuffer[pos] = htonl(timerStop);     pos += 4;
1801
1802   // Get resume point
1803
1804   char* value = config.getValueString("ResumeData", (char*)data);
1805   if (value)
1806   {
1807     resumePoint = strtoul(value, NULL, 10);
1808     delete[] value;
1809   }
1810   log->log("Client", Log::DEBUG, "GRI: RP: %lu", resumePoint);
1811
1812   *(ULONG*)&sendBuffer[pos] = htonl(resumePoint);    pos += 4;
1813
1814
1815   // Get summary
1816
1817 #if VDRVERSNUM < 10300
1818   summary = (char*)recording->Summary();
1819 #else
1820   const cRecordingInfo *Info = recording->Info();
1821   summary = (char*)Info->ShortText();
1822   if (isempty(summary)) summary = (char*)Info->Description();
1823 #endif
1824   log->log("Client", Log::DEBUG, "GRI: S: %s", summary);
1825   if (summary)
1826   {
1827     // memory insanity...
1828     if ((sendBufferSize - pos) < (strlen(summary) + 500)) // random
1829     {
1830       UCHAR* newBuffer = (UCHAR*)realloc(sendBuffer, sendBufferSize + strlen(summary) + 10000);
1831       if (newBuffer)
1832       {
1833         sendBuffer = newBuffer;
1834         sendBufferSize += strlen(summary) + 10000;
1835       }
1836       else
1837       {
1838         free(sendBuffer);
1839         sendULONG(0);
1840         return 1;
1841       }
1842     }
1843
1844     strcpy((char*)&sendBuffer[pos], summary);
1845     pos += strlen(summary) + 1;
1846   }
1847   else
1848   {
1849     strcpy((char*)&sendBuffer[pos], "");
1850     pos += 1;
1851   }
1852
1853
1854   // Get channels
1855
1856 #if VDRVERSNUM < 10300
1857
1858   // Send 0 for numchannels - this signals the client this info is not available
1859   *(ULONG*)&sendBuffer[pos] = 0;    pos += 4;
1860
1861 #else
1862   const cComponents* components = Info->Components();
1863
1864   log->log("Client", Log::DEBUG, "GRI: D1: %p", components);
1865
1866   if (!components)
1867   {
1868     *(ULONG*)&sendBuffer[pos] = htonl(0);    pos += 4;
1869   }
1870   else
1871   {
1872     *(ULONG*)&sendBuffer[pos] = htonl(components->NumComponents());    pos += 4;
1873
1874     tComponent* component;
1875     for (int i = 0; i < components->NumComponents(); i++)
1876     {
1877       component = components->Component(i);
1878
1879       // memory insanity...
1880       ULONG extraNeeded = 2 + (component->language ? strlen(component->language) : 0)
1881                             + (component->description ? strlen(component->description) : 0) + 2;
1882
1883       if ((sendBufferSize - pos) < extraNeeded)
1884       {
1885         UCHAR* newBuffer = (UCHAR*)realloc(sendBuffer, sendBufferSize + extraNeeded + 10000);
1886         if (newBuffer)
1887         {
1888           sendBuffer = newBuffer;
1889           sendBufferSize += extraNeeded + 10000;
1890         }
1891         else
1892         {
1893           free(sendBuffer);
1894           sendULONG(0);
1895           return 1;
1896         }
1897       }
1898
1899       log->log("Client", Log::DEBUG, "GRI: C: %i %u %u %s %s", i, component->stream, component->type, component->language, component->description);
1900       sendBuffer[pos] = component->stream;  pos += 1;
1901       sendBuffer[pos] = component->type;    pos += 1;
1902       if (component->language)
1903       {
1904         strcpy((char*)&sendBuffer[pos], component->language);
1905         pos += strlen(component->language) + 1;
1906       }
1907       else
1908       {
1909         strcpy((char*)&sendBuffer[pos], "");
1910         pos += 1;
1911       }
1912       if (component->description)
1913       {
1914         strcpy((char*)&sendBuffer[pos], component->description);
1915         pos += strlen(component->description) + 1;
1916       }
1917       else
1918       {
1919         strcpy((char*)&sendBuffer[pos], "");
1920         pos += 1;
1921       }
1922
1923     }
1924   }
1925
1926 #endif
1927
1928   // Done. send it
1929
1930   *(ULONG*)&sendBuffer[0] = htonl(pos - 4); // -4 :  take off the size field
1931
1932   log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
1933
1934   tcp.sendPacket(sendBuffer, pos);
1935   delete[] sendBuffer;
1936   log->log("Client", Log::DEBUG, "Written getrecinfo");
1937
1938   return 1;
1939 }
1940
1941
1942
1943
1944 // FIXME obselete
1945
1946 int MVPClient::processReScanRecording(UCHAR* data, int length)
1947 {
1948   if (!rp)
1949   {
1950     log->log("Client", Log::DEBUG, "Rescan recording called when no recording being played!");
1951     return 0;
1952   }
1953
1954   rp->scan();
1955
1956   UCHAR sendBuffer[16];
1957   *(ULONG*)&sendBuffer[0] = htonl(12);
1958   *(ULLONG*)&sendBuffer[4] = htonll(rp->getLengthBytes());
1959   *(ULONG*)&sendBuffer[12] = htonl(rp->getLengthFrames());
1960
1961   tcp.sendPacket(sendBuffer, 16);
1962   log->log("Client", Log::DEBUG, "Rescan recording, wrote new length to client");
1963   return 1;
1964 }
1965
1966 // FIXME without client calling rescan, getblock wont work even tho more data is avail
1967
1968
1969 int MVPClient::processGetMarks(UCHAR* data, int length)
1970 {
1971   // data is a pointer to the fileName string
1972
1973   UCHAR* sendBuffer = new UCHAR[50000]; // FIXME hope this is enough
1974   int count = 4; // leave space for the packet length
1975
1976
1977   cMarks Marks;
1978   cRecordings Recordings;
1979   Recordings.Load(); // probably have to do this
1980
1981   cRecording *recording = Recordings.GetByName((char*)data);
1982
1983   log->log("Client", Log::DEBUG, "recording pointer %p", recording);
1984
1985   if (recording)
1986   {
1987     Marks.Load(recording->FileName());
1988     if (Marks.Count())
1989     {
1990       for (const cMark *m = Marks.First(); m; m = Marks.Next(m))
1991       {
1992         log->log("Client", Log::DEBUG, "found Mark %i", m->position);
1993
1994         if (count > 49000) break;
1995         *(ULONG*)&sendBuffer[count] = htonl(m->position);
1996         count += 4;
1997       }
1998     }
1999     else
2000     {
2001       log->log("Client", Log::DEBUG, "no marks found, sending 0-mark");
2002       *(ULONG*)&sendBuffer[count] = htonl(0);
2003       count += 4;
2004     }
2005   }
2006
2007   *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
2008
2009   log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
2010
2011   tcp.sendPacket(sendBuffer, count);
2012   delete[] sendBuffer;
2013   log->log("Client", Log::DEBUG, "Written Marks list");
2014
2015   return 1;
2016 }
2017
2018 #endif //VOMPSTANDALONE
2019
2020
2021 /**
2022   * media List Request:
2023   * 4 length
2024   * 4 VDR_GETMEDIALIST
2025   * 4 flags (currently unused)
2026   * n dirname
2027   * n+1 0
2028   * Media List response:
2029   * 4 length
2030   * 4 VDR_
2031   * 4 numentries
2032   * per entry:
2033   * 4 media type
2034   * 4 time stamp
2035   * 4 flags
2036   * 4 strlen (incl. 0 Byte)
2037   * string
2038   * 0
2039 */
2040 #define MLISTBUF 500000
2041 int MVPClient::processGetMediaList(UCHAR* data, int length)
2042 {
2043   if (length < 4) {
2044     log->log("Client", Log::ERR, "getMediaList packet too short %d", length);
2045     return 0;
2046   }
2047   char * dirname=NULL;
2048   if (length > 4) {
2049     //we have a dirname provided
2050     dirname=(char *)&data[4];
2051     log->log("Client", Log::DEBUG, "getMediaList for %s", dirname);
2052   }
2053
2054
2055   UCHAR* sendBuffer = new UCHAR[MLISTBUF]; // FIXME hope this is enough
2056   int count = 4; // leave space for the header
2057
2058   MediaList * ml=MediaList::readList(baseConfig,dirname);
2059   if (ml == NULL) {
2060      log->log("Client", Log::ERR, "getMediaList returned NULL");
2061      return 0;
2062   }
2063   //response code (not yet set)
2064   *(ULONG*)&sendBuffer[count] = htonl(0);
2065   count += 4;
2066   //numentries
2067   *(ULONG*)&sendBuffer[count] = htonl(ml->size());
2068   count += 4;
2069   for (MediaList::iterator nm=ml->begin();nm<ml->end() && count < (MLISTBUF-1000);nm++) {
2070       Media *m=*nm;
2071       log->log("Client", Log::DEBUG, "found media entry %s, type=%d",m->getFilename(),m->getType());
2072       *(ULONG*)&sendBuffer[count] = htonl(m->getType());
2073       count += 4;
2074       //time stamp
2075       *(ULONG*)&sendBuffer[count] = htonl(m->getTime());
2076       count += 4;
2077       //flags
2078       *(ULONG*)&sendBuffer[count] = htonl(0);
2079       count += 4;
2080       int len=strlen(m->getFilename());
2081       //strlen
2082       *(ULONG*)&sendBuffer[count] = htonl(len+1);
2083       count += 4;
2084       //should have a check for strlen > 1000...
2085       strcpy((char *)&sendBuffer[count],m->getFilename());
2086       count+=len+1;
2087   }
2088   delete ml;
2089
2090   *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
2091
2092   log->log("Client", Log::DEBUG, "getMediaList size  %u", ntohl(*(ULONG*)&sendBuffer[0]));
2093
2094   tcp.sendPacket(sendBuffer, count);
2095   delete[] sendBuffer;
2096   log->log("Client", Log::DEBUG, "Written Media list");
2097
2098   return 1;
2099 }
2100
2101 /**
2102   * get image Request:
2103   * 4 flags (currently unused)
2104   * 4 x size
2105   * 4 y size
2106   * n filename
2107   * n+1 0
2108   * get image response:
2109   * 4 length
2110   * 4 VDR_GETIMAGE
2111   * 4 len of image
2112 */
2113 #define MLISTBUF 500000
2114 int MVPClient::processGetPicture(UCHAR* data, int length)
2115 {
2116   if (length < 12) {
2117     log->log("Client", Log::ERR, "getPicture packet too short %d", length);
2118     return 0;
2119   }
2120   if (imageFile) {
2121     fclose(imageFile);
2122     imageFile=NULL;
2123   }
2124   char * filename=NULL;
2125   if (length > 12) {
2126     //we have a dirname provided
2127     filename=(char *)&data[12];
2128     log->log("Client", Log::DEBUG, "getPicture  %s", filename);
2129   }
2130   else {
2131     log->log("Client", Log::ERR, "getPicture  empty filename");
2132   }
2133   if (filename) {
2134     imageFile=fopen(filename,"r");
2135     if (!imageFile) log->log("Client", Log::ERR, "getPicture unable to open %s",filename);
2136   }
2137   int size=0;
2138   if (imageFile) {
2139     struct stat st;
2140     if ( fstat(fileno(imageFile),&st) == 0) size=st.st_size;
2141   }
2142   UCHAR* sendBuffer = new UCHAR[12];
2143   int count = 4; // leave space for the header
2144   //response code (not yet set)
2145   *(ULONG*)&sendBuffer[count] = htonl(31);
2146   count += 4;
2147   //size
2148   *(ULONG*)&sendBuffer[count] = htonl(size);
2149   count += 4;
2150   *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
2151   log->log("Client", Log::DEBUG, "getPicture size  %u", size);
2152
2153   tcp.sendPacket(sendBuffer, count);
2154   delete[] sendBuffer;
2155   log->log("Client", Log::DEBUG, "Written Media list");
2156
2157   return 1;
2158 }
2159
2160
2161 int MVPClient::processGetImageBlock(UCHAR* data, int length)
2162 {
2163   if (!imageFile)
2164   {
2165     log->log("Client", Log::DEBUG, "Get image block called when no image active");
2166     return 0;
2167   }
2168
2169   ULLONG position = ntohll(*(ULLONG*)data);
2170   data += sizeof(ULLONG);
2171   ULONG amount = ntohl(*(ULONG*)data);
2172
2173   log->log("Client", Log::DEBUG, "getImageblock pos = %llu length = %lu", position, amount);
2174
2175   UCHAR sendBuffer[amount + 4];
2176   ULONG amountReceived = 0; // compiler moan.
2177   ULLONG cpos=ftell(imageFile);
2178   if (position != cpos) {
2179     fseek(imageFile,position-cpos,SEEK_CUR);
2180   }
2181   if (position != (ULLONG)ftell(imageFile)) {
2182     log->log("Client", Log::DEBUG, "getImageblock pos = %llu not available", position);
2183   }
2184   else {
2185     amountReceived=fread(&sendBuffer[4],1,amount,imageFile);
2186   }
2187
2188   if (!amountReceived)
2189   {
2190     sendULONG(0);
2191     log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0");
2192   }
2193   else
2194   {
2195     *(ULONG*)&sendBuffer[0] = htonl(amountReceived);
2196     tcp.sendPacket(sendBuffer, amountReceived + 4);
2197     log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
2198   }
2199
2200   return 1;
2201 }
2202
2203 #ifndef VOMPSTANDALONE
2204
2205 int MVPClient::processDeleteTimer(UCHAR* buffer, int length)
2206 {
2207   log->log("Client", Log::DEBUG, "Delete timer called");
2208   // get timer
2209   
2210   int position = 0;
2211   
2212   INT delChannel = ntohl(*(ULONG*)&buffer[position]); position += 4;
2213   INT delWeekdays = ntohl(*(ULONG*)&buffer[position]); position += 4;
2214   INT delDay = ntohl(*(ULONG*)&buffer[position]); position += 4;  
2215   INT delStart = ntohl(*(ULONG*)&buffer[position]); position += 4;  
2216   INT delStop = ntohl(*(ULONG*)&buffer[position]); position += 4;
2217     
2218   cTimer* ti = NULL;
2219   for (ti = Timers.First(); ti; ti = Timers.Next(ti))
2220   {
2221     if  ( (ti->Channel()->Number() == delChannel)
2222      &&   ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
2223      &&   (ti->StartTime() == delStart)
2224      &&   (ti->StopTime() == delStop) )
2225        break;
2226   }
2227   
2228   if (!ti)
2229   {
2230     sendULONG(4);
2231     return 1;
2232   }
2233           
2234   if (!Timers.BeingEdited())
2235   {
2236     if (!ti->Recording())
2237     {
2238       Timers.Del(ti);
2239       Timers.SetModified();
2240       sendULONG(10);
2241       return 1;
2242     }
2243     else
2244     {
2245       log->log("Client", Log::ERR, "Unable to delete timer - timer is running");
2246       sendULONG(3);
2247       return 1;
2248     }  
2249   }
2250   else
2251   {
2252     log->log("Client", Log::ERR, "Unable to delete timer - timers being edited at VDR");
2253     sendULONG(1);
2254     return 1;
2255   }  
2256 }
2257
2258 #endif