2 Copyright 2004-2005 Chris Tallon
4 This file is part of VOMP.
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.
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.
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
21 #include "mvpclient.h"
23 // This is here else it causes compile errors with something in libdvbmpeg
24 //#include <vdr/menu.h>
26 pthread_mutex_t threadClientMutex;
27 int MVPClient::nr_clients = 0;
30 MVPClient::MVPClient(Config* cfgBase, char* tconfigDirExtra, int tsocket)
36 recordingManager = NULL;
37 log = Log::getInstance();
39 configDirExtra = tconfigDirExtra;
44 MVPClient::~MVPClient()
46 log->log("Client", Log::DEBUG, "MVP client destructor");
57 delete recordingManager;
59 recordingManager = NULL;
62 if (loggedIn) cleanConfig();
66 ULLONG MVPClient::ntohll(ULLONG a)
71 ULLONG MVPClient::htonll(ULLONG a)
73 #if BYTE_ORDER == BIG_ENDIAN
78 b = ((a << 56) & 0xFF00000000000000ULL)
79 | ((a << 40) & 0x00FF000000000000ULL)
80 | ((a << 24) & 0x0000FF0000000000ULL)
81 | ((a << 8) & 0x000000FF00000000ULL)
82 | ((a >> 8) & 0x00000000FF000000ULL)
83 | ((a >> 24) & 0x0000000000FF0000ULL)
84 | ((a >> 40) & 0x000000000000FF00ULL)
85 | ((a >> 56) & 0x00000000000000FFULL) ;
91 cChannel* MVPClient::channelFromNumber(ULONG channelNumber)
93 cChannel* channel = NULL;
95 for (channel = Channels.First(); channel; channel = Channels.Next(channel))
97 if (!channel->GroupSep())
99 log->log("Client", Log::DEBUG, "Looking for channel %lu::: number: %i name: '%s'", channelNumber, channel->Number(), channel->Name());
101 if (channel->Number() == (int)channelNumber)
103 int vpid = channel->Vpid();
104 #if VDRVERSNUM < 10300
105 int apid1 = channel->Apid1();
107 int apid1 = channel->Apid(0);
109 log->log("Client", Log::DEBUG, "Found channel number %lu, vpid = %i, apid1 = %i", channelNumber, vpid, apid1);
117 log->log("Client", Log::DEBUG, "Channel not found");
123 void MVPClient::writeResumeData()
125 config.setValueLong("ResumeData",
126 (char*)rp->getCurrentRecording()->FileName(),
127 rp->frameNumberFromPosition(rp->getLastPosition()) );
130 void MVPClient::sendULONG(ULONG ul)
133 *(ULONG*)&sendBuffer[0] = htonl(4);
134 *(ULONG*)&sendBuffer[4] = htonl(ul);
136 tcp.sendPacket(sendBuffer, 8);
137 log->log("Client", Log::DEBUG, "written ULONG %lu", ul);
140 void MVPClientStartThread(void* arg)
142 MVPClient* m = (MVPClient*)arg;
144 // Nothing external to this class has a reference to it
145 // This is the end of the thread.. so delete m
152 if (pthread_create(&runThread, NULL, (void*(*)(void*))MVPClientStartThread, (void *)this) == -1) return 0;
153 log->log("Client", Log::DEBUG, "MVPClient run success");
157 void MVPClient::run2()
162 pthread_sigmask(SIG_BLOCK, &sigset, NULL);
163 pthread_detach(runThread); // Detach
165 tcp.disableReadTimeout();
167 tcp.setSoKeepTime(3);
168 tcp.setNonBlocking();
173 ULONG extraDataLength;
180 log->log("Client", Log::DEBUG, "Waiting");
182 if (!tcp.readData((UCHAR*)&channelID, sizeof(ULONG))) break;
183 channelID = ntohl(channelID);
186 log->log("Client", Log::ERR, "Incoming channel number not 1!");
190 log->log("Client", Log::DEBUG, "Got chan");
192 if (!tcp.readData((UCHAR*)&serialNumber, sizeof(ULONG))) break;
193 serialNumber = ntohl(serialNumber);
195 log->log("Client", Log::DEBUG, "Got ser");
197 if (!tcp.readData((UCHAR*)&opcode, sizeof(ULONG))) break;
198 opcode = ntohl(opcode);
200 log->log("Client", Log::DEBUG, "Got op %lu", opcode);
202 if (!tcp.readData((UCHAR*)&extraDataLength, sizeof(ULONG))) break;
203 extraDataLength = ntohl(extraDataLength);
204 if (extraDataLength > 200000)
206 log->log("Client", Log::ERR, "ExtraDataLength > 200000!");
210 log->log("Client", Log::DEBUG, "Got edl %lu", extraDataLength);
214 data = (UCHAR*)malloc(extraDataLength);
217 log->log("Client", Log::ERR, "Extra data buffer malloc error");
221 if (!tcp.readData(data, extraDataLength))
223 log->log("Client", Log::ERR, "Could not read extradata");
233 log->log("Client", Log::DEBUG, "Received chan=%lu, ser=%lu, op=%lu, edl=%lu", channelID, serialNumber, opcode, extraDataLength);
235 if (!loggedIn && (opcode != 1))
237 log->log("Client", Log::ERR, "Not logged in and opcode != 1");
238 if (data) free(data);
245 result = processLogin(data, extraDataLength);
248 result = processGetRecordingsList(data, extraDataLength);
251 result = processDeleteRecording(data, extraDataLength);
254 result = processGetChannelsList(data, extraDataLength);
257 result = processStartStreamingChannel(data, extraDataLength);
260 result = processGetBlock(data, extraDataLength);
263 result = processStopStreaming(data, extraDataLength);
266 result = processStartStreamingRecording(data, extraDataLength);
269 result = processGetChannelSchedule(data, extraDataLength);
272 result = processConfigSave(data, extraDataLength);
275 result = processConfigLoad(data, extraDataLength);
278 result = processReScanRecording(data, extraDataLength); // FIXME obselete
281 result = processGetTimers(data, extraDataLength);
284 result = processSetTimer(data, extraDataLength);
287 result = processPositionFromFrameNumber(data, extraDataLength);
290 result = processFrameNumberFromPosition(data, extraDataLength);
293 result = processMoveRecording(data, extraDataLength);
296 result = processGetIFrame(data, extraDataLength);
299 result = processGetRecInfo(data, extraDataLength);
302 result = processGetMarks(data, extraDataLength);
305 result = processGetChannelPids(data, extraDataLength);
308 result = processDeleteTimer(data, extraDataLength);
311 result = processGetMediaList(data, extraDataLength);
314 result = processGetPicture(data, extraDataLength);
317 result = processGetImageBlock(data, extraDataLength);
321 if (data) free(data);
326 int MVPClient::processLogin(UCHAR* buffer, int length)
328 if (length != 6) return 0;
332 const char* configDir = cPlugin::ConfigDirectory(configDirExtra);
335 log->log("Client", Log::DEBUG, "No config dir!");
339 char configFileName[PATH_MAX];
340 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]);
341 config.init(configFileName);
343 // Send the login reply
345 time_t timeNow = time(NULL);
346 struct tm* timeStruct = localtime(&timeNow);
347 int timeOffset = timeStruct->tm_gmtoff;
349 UCHAR sendBuffer[12];
350 *(ULONG*)&sendBuffer[0] = htonl(8);
351 *(ULONG*)&sendBuffer[4] = htonl(timeNow);
352 *(signed int*)&sendBuffer[8] = htonl(timeOffset);
354 tcp.sendPacket(sendBuffer, 12);
355 log->log("Client", Log::DEBUG, "written login reply");
361 int MVPClient::processGetRecordingsList(UCHAR* data, int length)
363 UCHAR* sendBuffer = new UCHAR[50000]; // hope this is enough
364 int count = 4; // leave space for the packet length
369 int Percent = VideoDiskSpace(&FreeMB);
370 int Total = (FreeMB / (100 - Percent)) * 100;
372 *(ULONG*)&sendBuffer[count] = htonl(Total);
373 count += sizeof(ULONG);
374 *(ULONG*)&sendBuffer[count] = htonl(FreeMB);
375 count += sizeof(ULONG);
376 *(ULONG*)&sendBuffer[count] = htonl(Percent);
377 count += sizeof(ULONG);
380 cRecordings Recordings;
383 for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
385 if (count > 49000) break; // just how big is that hard disk?!
386 *(ULONG*)&sendBuffer[count] = htonl(recording->start);// + timeOffset);
389 point = (char*)recording->Name();
390 strcpy((char*)&sendBuffer[count], point);
391 count += strlen(point) + 1;
393 point = (char*)recording->FileName();
394 strcpy((char*)&sendBuffer[count], point);
395 count += strlen(point) + 1;
398 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
400 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
402 tcp.sendPacket(sendBuffer, count);
404 log->log("Client", Log::DEBUG, "Written list");
409 int MVPClient::processDeleteRecording(UCHAR* data, int length)
411 // data is a pointer to the fileName string
413 cRecordings Recordings;
414 Recordings.Load(); // probably have to do this
416 cRecording* recording = Recordings.GetByName((char*)data);
418 log->log("Client", Log::DEBUG, "recording pointer %p", recording);
422 log->log("Client", Log::DEBUG, "deleting recording: %s", recording->Name());
424 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
427 if (recording->Delete())
429 // Copy svdrp's way of doing this, see if it works
430 #if VDRVERSNUM > 10300
431 ::Recordings.DelByName(recording->FileName());
453 int MVPClient::processMoveRecording(UCHAR* data, int length)
455 log->log("Client", Log::DEBUG, "Process move recording");
456 char* fileName = (char*)data;
457 char* newPath = NULL;
459 for (int k = 0; k < length; k++)
463 newPath = (char*)&data[k+1];
467 if (!newPath) return 0;
469 cRecordings Recordings;
470 Recordings.Load(); // probably have to do this
472 cRecording* recording = Recordings.GetByName((char*)fileName);
474 log->log("Client", Log::DEBUG, "recording pointer %p", recording);
478 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
481 log->log("Client", Log::DEBUG, "moving recording: %s", recording->Name());
482 log->log("Client", Log::DEBUG, "moving recording: %s", recording->FileName());
483 log->log("Client", Log::DEBUG, "to: %s", newPath);
485 const char* t = recording->FileName();
487 char* dateDirName = NULL; int k;
488 char* titleDirName = NULL; int j;
490 // Find the datedirname
491 for(k = strlen(t) - 1; k >= 0; k--)
495 log->log("Client", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
496 dateDirName = new char[strlen(&t[k+1]) + 1];
497 strcpy(dateDirName, &t[k+1]);
502 // Find the titledirname
504 for(j = k-1; j >= 0; j--)
508 log->log("Client", Log::DEBUG, "l2: %i", (k - j - 1) + 1);
509 titleDirName = new char[(k - j - 1) + 1];
510 memcpy(titleDirName, &t[j+1], k - j - 1);
511 titleDirName[k - j - 1] = '\0';
516 log->log("Client", Log::DEBUG, "datedirname: %s", dateDirName);
517 log->log("Client", Log::DEBUG, "titledirname: %s", titleDirName);
519 log->log("Client", Log::DEBUG, "viddir: %s", VideoDirectory);
521 char* newContainer = new char[strlen(VideoDirectory) + strlen(newPath) + strlen(titleDirName) + 1];
522 log->log("Client", Log::DEBUG, "l10: %i", strlen(VideoDirectory) + strlen(newPath) + strlen(titleDirName) + 1);
523 sprintf(newContainer, "%s%s%s", VideoDirectory, newPath, titleDirName);
525 // FIXME Check whether this already exists before mkdiring it
527 log->log("Client", Log::DEBUG, "%s", newContainer);
531 int statret = stat(newContainer, &dstat);
532 if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
534 log->log("Client", Log::DEBUG, "new dir does not exist");
535 int mkdirret = mkdir(newContainer, 0755);
538 delete[] dateDirName;
539 delete[] titleDirName;
540 delete[] newContainer;
545 else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR))) // Something exists but it's not a dir
547 delete[] dateDirName;
548 delete[] titleDirName;
549 delete[] newContainer;
554 // Ok, the directory container has been made, or it pre-existed.
556 char* newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
557 sprintf(newDir, "%s/%s", newContainer, dateDirName);
559 log->log("Client", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
560 int renameret = rename(t, newDir);
563 // Success. Test for remove old dir containter
564 char* oldTitleDir = new char[k+1];
565 memcpy(oldTitleDir, t, k);
566 oldTitleDir[k] = '\0';
567 log->log("Client", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(oldTitleDir), oldTitleDir);
568 rmdir(oldTitleDir); // can't do anything about a fail result at this point.
569 delete[] oldTitleDir;
574 #if VDRVERSNUM > 10311
576 ::Recordings.Update();
578 // Success. Send a different packet from just a ulong
579 int totalLength = 4 + 4 + strlen(newDir) + 1;
580 UCHAR* sendBuffer = new UCHAR[totalLength];
581 *(ULONG*)&sendBuffer[0] = htonl(totalLength - 4);
582 *(ULONG*)&sendBuffer[4] = htonl(1); // success
583 strcpy((char*)&sendBuffer[8], newDir);
584 tcp.sendPacket(sendBuffer, totalLength);
592 delete[] dateDirName;
593 delete[] titleDirName;
594 delete[] newContainer;
610 int MVPClient::processGetChannelsList(UCHAR* data, int length)
612 UCHAR* sendBuffer = new UCHAR[50000]; // FIXME hope this is enough
613 int count = 4; // leave space for the packet length
617 char* chanConfig = config.getValueString("General", "Channels");
619 if (chanConfig) allChans = strcasecmp(chanConfig, "FTA only");
621 for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
623 #if VDRVERSNUM < 10300
624 if (!channel->GroupSep() && (!channel->Ca() || allChans))
626 if (!channel->GroupSep() && (!channel->Ca(0) || allChans))
629 log->log("Client", Log::DEBUG, "name: '%s'", channel->Name());
631 if (channel->Vpid()) type = 1;
632 #if VDRVERSNUM < 10300
635 else if (channel->Apid(0)) type = 2;
639 if (count > 49000) break;
640 *(ULONG*)&sendBuffer[count] = htonl(channel->Number());
643 *(ULONG*)&sendBuffer[count] = htonl(type);
646 point = (char*)channel->Name();
647 strcpy((char*)&sendBuffer[count], point);
648 count += strlen(point) + 1;
652 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
654 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
656 tcp.sendPacket(sendBuffer, count);
658 log->log("Client", Log::DEBUG, "Written channels list");
663 int MVPClient::processGetChannelPids(UCHAR* data, int length)
665 ULONG channelNumber = ntohl(*(ULONG*)data);
667 cChannel* channel = channelFromNumber(channelNumber);
675 ULONG spaceRequired = 12; // 4 for length field, 4 for vpid, 4 for number of apids
676 // Work out space required and number of Apids
678 #if VDRVERSNUM < 10300
680 log->log("Client", Log::DEBUG, "Apid1: %i", channel->Apid1());
681 log->log("Client", Log::DEBUG, "Apid2: %i", channel->Apid2());
683 if (channel->Apid2())
686 spaceRequired += 10; // 8 + 2 nulls
688 else if (channel->Apid1())
691 spaceRequired += 5; // 4 + 1 null
700 for (const int *Apid = channel->Apids(); *Apid; Apid++)
702 spaceRequired += 4 + strlen(channel->Alang(numApids)) + 1; // 4 for pid, length of string + \0
708 // Format of response
716 UCHAR* sendBuffer = new UCHAR[spaceRequired];
718 *(ULONG*)&sendBuffer[point] = htonl(spaceRequired - 4); point += 4; // take off first 4 bytes
719 *(ULONG*)&sendBuffer[point] = htonl(channel->Vpid()); point += 4;
720 *(ULONG*)&sendBuffer[point] = htonl(numApids); point += 4;
722 #if VDRVERSNUM < 10300
725 *(ULONG*)&sendBuffer[point] = htonl(channel->Apid1()); point += 4;
726 sendBuffer[point] = '\0'; point += 1;
730 *(ULONG*)&sendBuffer[point] = htonl(channel->Apid2()); point += 4;
731 sendBuffer[point] = '\0'; point += 1;
734 for (ULONG i = 0; i < numApids; i++)
736 *(ULONG*)&sendBuffer[point] = htonl(channel->Apid(i)); point += 4;
737 strcpy((char*)&sendBuffer[point], channel->Alang(i)); point += strlen(channel->Alang(i)) + 1;
741 // printf("About to send getchannelpids response. length = %u\n", spaceRequired);
742 //tcp.dump(sendBuffer, spaceRequired);
744 tcp.sendPacket(sendBuffer, spaceRequired);
746 log->log("Client", Log::DEBUG, "Written channels pids");
751 int MVPClient::processStartStreamingChannel(UCHAR* data, int length)
753 log->log("Client", Log::DEBUG, "length = %i", length);
754 ULONG channelNumber = ntohl(*(ULONG*)data);
756 cChannel* channel = channelFromNumber(channelNumber);
763 // get the priority we should use
765 int priority = config.getValueLong("General", "Live priority", &fail);
768 log->log("Client", Log::DEBUG, "Config: Live TV priority: %i", priority);
772 log->log("Client", Log::DEBUG, "Config: Live TV priority config fail");
777 if (priority < 0) priority = 0;
778 if (priority > 99) priority = 99;
780 log->log("Client", Log::DEBUG, "Using live TV priority %i", priority);
781 lp = MVPReceiver::create(channel, priority);
801 int MVPClient::processStopStreaming(UCHAR* data, int length)
803 log->log("Client", Log::DEBUG, "STOP STREAMING RECEIVED");
814 delete recordingManager;
816 recordingManager = NULL;
823 int MVPClient::processGetBlock(UCHAR* data, int length)
827 log->log("Client", Log::DEBUG, "Get block called when no streaming happening!");
831 ULLONG position = ntohll(*(ULLONG*)data);
832 data += sizeof(ULLONG);
833 ULONG amount = ntohl(*(ULONG*)data);
835 log->log("Client", Log::DEBUG, "getblock pos = %llu length = %lu", position, amount);
837 UCHAR sendBuffer[amount + 4];
838 ULONG amountReceived = 0; // compiler moan.
841 log->log("Client", Log::DEBUG, "getting from live");
842 amountReceived = lp->getBlock(&sendBuffer[4], amount);
846 // vdr has possibly disconnected the receiver
847 log->log("Client", Log::DEBUG, "VDR has disconnected the live receiver");
854 log->log("Client", Log::DEBUG, "getting from recording");
855 amountReceived = rp->getBlock(&sendBuffer[4], position, amount);
861 log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0");
865 *(ULONG*)&sendBuffer[0] = htonl(amountReceived);
866 tcp.sendPacket(sendBuffer, amountReceived + 4);
867 log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
873 int MVPClient::processStartStreamingRecording(UCHAR* data, int length)
875 // data is a pointer to the fileName string
877 recordingManager = new cRecordings;
878 recordingManager->Load();
880 cRecording* recording = recordingManager->GetByName((char*)data);
882 log->log("Client", Log::DEBUG, "recording pointer %p", recording);
886 rp = new RecPlayer(recording);
888 UCHAR sendBuffer[16];
889 *(ULONG*)&sendBuffer[0] = htonl(12);
890 *(ULLONG*)&sendBuffer[4] = htonll(rp->getLengthBytes());
891 *(ULONG*)&sendBuffer[12] = htonl(rp->getLengthFrames());
893 tcp.sendPacket(sendBuffer, 16);
894 log->log("Client", Log::DEBUG, "written totalLength");
898 delete recordingManager;
899 recordingManager = NULL;
904 int MVPClient::processPositionFromFrameNumber(UCHAR* data, int length)
908 ULONG frameNumber = ntohl(*(ULONG*)data);
913 log->log("Client", Log::DEBUG, "Rescan recording called when no recording being played!");
917 retval = rp->positionFromFrameNumber(frameNumber);
920 UCHAR sendBuffer[12];
921 *(ULONG*)&sendBuffer[0] = htonl(8);
922 *(ULLONG*)&sendBuffer[4] = htonll(retval);
924 tcp.sendPacket(sendBuffer, 12);
925 log->log("Client", Log::DEBUG, "Wrote posFromFrameNum reply to client");
929 int MVPClient::processFrameNumberFromPosition(UCHAR* data, int length)
933 ULLONG position = ntohll(*(ULLONG*)data);
938 log->log("Client", Log::DEBUG, "Rescan recording called when no recording being played!");
942 retval = rp->frameNumberFromPosition(position);
946 *(ULONG*)&sendBuffer[0] = htonl(4);
947 *(ULONG*)&sendBuffer[4] = htonl(retval);
949 tcp.sendPacket(sendBuffer, 8);
950 log->log("Client", Log::DEBUG, "Wrote frameNumFromPos reply to client");
954 int MVPClient::processGetIFrame(UCHAR* data, int length)
956 bool success = false;
958 ULONG frameNumber = ntohl(*(ULONG*)data);
960 ULONG direction = ntohl(*(ULONG*)data);
963 ULLONG rfilePosition = 0;
964 ULONG rframeNumber = 0;
965 ULONG rframeLength = 0;
969 log->log("Client", Log::DEBUG, "GetIFrame recording called when no recording being played!");
973 success = rp->getNextIFrame(frameNumber, direction, &rfilePosition, &rframeNumber, &rframeLength);
976 // returns file position, frame number, length
978 UCHAR sendBuffer[20];
984 *(ULONG*)&sendBuffer[0] = htonl(16);
985 *(ULLONG*)&sendBuffer[4] = htonll(rfilePosition);
986 *(ULONG*)&sendBuffer[12] = htonl(rframeNumber);
987 *(ULONG*)&sendBuffer[16] = htonl(rframeLength);
992 *(ULONG*)&sendBuffer[0] = htonl(4);
993 *(ULONG*)&sendBuffer[4] = 0;
996 log->log("Client", Log::DEBUG, "%llu %lu %lu", rfilePosition, rframeNumber, rframeLength);
998 tcp.sendPacket(sendBuffer, packetLength);
999 log->log("Client", Log::DEBUG, "Wrote GNIF reply to client");
1003 int MVPClient::processGetChannelSchedule(UCHAR* data, int length)
1005 ULONG channelNumber = ntohl(*(ULONG*)data);
1007 ULONG startTime = ntohl(*(ULONG*)data);
1009 ULONG duration = ntohl(*(ULONG*)data);
1011 log->log("Client", Log::DEBUG, "get schedule called for channel %lu", channelNumber);
1013 cChannel* channel = channelFromNumber(channelNumber);
1017 log->log("Client", Log::DEBUG, "written 0 because channel = NULL");
1021 log->log("Client", Log::DEBUG, "Got channel");
1023 #if VDRVERSNUM < 10300
1024 cMutexLock MutexLock;
1025 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1027 cSchedulesLock MutexLock;
1028 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
1033 log->log("Client", Log::DEBUG, "written 0 because Schedule!s! = NULL");
1037 log->log("Client", Log::DEBUG, "Got schedule!s! object");
1039 const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
1043 log->log("Client", Log::DEBUG, "written 0 because Schedule = NULL");
1047 log->log("Client", Log::DEBUG, "Got schedule object");
1049 UCHAR* sendBuffer = (UCHAR*)malloc(100000);
1050 ULONG sendBufferLength = 100000;
1051 ULONG sendBufferUsed = sizeof(ULONG); // leave a hole for the entire packet length
1053 const char* empty = "";
1055 // assign all the event info to temp vars then we know exactly what size they are
1057 ULONG thisEventTime;
1058 ULONG thisEventDuration;
1059 const char* thisEventTitle;
1060 const char* thisEventSubTitle;
1061 const char* thisEventDescription;
1063 ULONG constEventLength = sizeof(thisEventID) + sizeof(thisEventTime) + sizeof(thisEventDuration);
1064 ULONG thisEventLength;
1066 #if VDRVERSNUM < 10300
1068 const cEventInfo *event;
1069 for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1071 event = Schedule->GetEventNumber(eventNumber);
1073 thisEventID = event->GetEventID();
1074 thisEventTime = event->GetTime();
1075 thisEventDuration = event->GetDuration();
1076 thisEventTitle = event->GetTitle();
1077 thisEventSubTitle = event->GetSubtitle();
1078 thisEventDescription = event->GetExtendedDescription();
1082 for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
1084 thisEventID = event->EventID();
1085 thisEventTime = event->StartTime();
1086 thisEventDuration = event->Duration();
1087 thisEventTitle = event->Title();
1088 thisEventSubTitle = NULL;
1089 thisEventDescription = event->Description();
1093 log->log("Client", Log::DEBUG, "Got an event object %p", event);
1095 //in the past filter
1096 if ((thisEventTime + thisEventDuration) < (ULONG)time(NULL)) continue;
1099 if ((thisEventTime + thisEventDuration) <= startTime) continue;
1102 if (thisEventTime >= (startTime + duration)) continue;
1104 if (!thisEventTitle) thisEventTitle = empty;
1105 if (!thisEventSubTitle) thisEventSubTitle = empty;
1106 if (!thisEventDescription) thisEventDescription = empty;
1108 thisEventLength = constEventLength + strlen(thisEventTitle) + 1 + strlen(thisEventSubTitle) + 1 + strlen(thisEventDescription) + 1;
1110 log->log("Client", Log::DEBUG, "Done s1");
1112 // now extend the buffer if necessary
1113 if ((sendBufferUsed + thisEventLength) > sendBufferLength)
1115 log->log("Client", Log::DEBUG, "Extending buffer");
1116 sendBufferLength += 100000;
1117 UCHAR* temp = (UCHAR*)realloc(sendBuffer, sendBufferLength);
1121 UCHAR sendBuffer2[8];
1122 *(ULONG*)&sendBuffer2[0] = htonl(4);
1123 *(ULONG*)&sendBuffer2[4] = htonl(0);
1124 tcp.sendPacket(sendBuffer2, 8);
1125 log->log("Client", Log::DEBUG, "written 0 because failed to realloc packet");
1131 log->log("Client", Log::DEBUG, "Done s2");
1133 *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventID); sendBufferUsed += sizeof(ULONG);
1134 *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventTime); sendBufferUsed += sizeof(ULONG);
1135 *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventDuration); sendBufferUsed += sizeof(ULONG);
1137 strcpy((char*)&sendBuffer[sendBufferUsed], thisEventTitle); sendBufferUsed += strlen(thisEventTitle) + 1;
1138 strcpy((char*)&sendBuffer[sendBufferUsed], thisEventSubTitle); sendBufferUsed += strlen(thisEventSubTitle) + 1;
1139 strcpy((char*)&sendBuffer[sendBufferUsed], thisEventDescription); sendBufferUsed += strlen(thisEventDescription) + 1;
1141 log->log("Client", Log::DEBUG, "Done s3 %lu", sendBufferUsed);
1144 log->log("Client", Log::DEBUG, "Got all event data");
1146 if (sendBufferUsed == sizeof(ULONG))
1150 log->log("Client", Log::DEBUG, "Written 0 because no data");
1154 // Write the length into the first 4 bytes. It's sendBufferUsed - 4 because of the hole!
1155 *(ULONG*)&sendBuffer[0] = htonl(sendBufferUsed - sizeof(ULONG));
1156 tcp.sendPacket(sendBuffer, sendBufferUsed);
1157 log->log("Client", Log::DEBUG, "written %lu schedules packet", sendBufferUsed);
1165 int MVPClient::processConfigSave(UCHAR* buffer, int length)
1167 char* section = (char*)buffer;
1171 for (int k = 0; k < length; k++)
1173 if (buffer[k] == '\0')
1177 key = (char*)&buffer[k+1];
1181 value = (char*)&buffer[k+1];
1187 // if the last string (value) doesnt have null terminator, give up
1188 if (buffer[length - 1] != '\0') return 0;
1190 log->log("Client", Log::DEBUG, "Config save: %s %s %s", section, key, value);
1191 if (config.setValueString(section, key, value))
1203 int MVPClient::processConfigLoad(UCHAR* buffer, int length)
1205 char* section = (char*)buffer;
1208 for (int k = 0; k < length; k++)
1210 if (buffer[k] == '\0')
1212 key = (char*)&buffer[k+1];
1217 char* value = config.getValueString(section, key);
1221 UCHAR sendBuffer[4 + strlen(value) + 1];
1222 *(ULONG*)&sendBuffer[0] = htonl(strlen(value) + 1);
1223 strcpy((char*)&sendBuffer[4], value);
1224 tcp.sendPacket(sendBuffer, 4 + strlen(value) + 1);
1226 log->log("Client", Log::DEBUG, "Written config load packet");
1231 UCHAR sendBuffer[8];
1232 *(ULONG*)&sendBuffer[0] = htonl(4);
1233 *(ULONG*)&sendBuffer[4] = htonl(0);
1234 tcp.sendPacket(sendBuffer, 8);
1236 log->log("Client", Log::DEBUG, "Written config load failed packet");
1242 void MVPClient::cleanConfig()
1244 log->log("Client", Log::DEBUG, "Clean config");
1246 cRecordings Recordings;
1251 char* resumes = config.getSectionKeyNames("ResumeData", numReturns, length);
1252 char* position = resumes;
1253 for(int k = 0; k < numReturns; k++)
1255 log->log("Client", Log::DEBUG, "EXAMINING: %i %i %p %s", k, numReturns, position, position);
1257 cRecording* recording = Recordings.GetByName(position);
1260 // doesn't exist anymore
1261 log->log("Client", Log::DEBUG, "Found a recording that doesn't exist anymore");
1262 config.deleteValue("ResumeData", position);
1266 log->log("Client", Log::DEBUG, "This recording still exists");
1269 position += strlen(position) + 1;
1281 event = Schedule->GetPresentEvent();
1283 fprintf(f, "\n\nCurrent event\n\n");
1285 fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", 0, event->GetEventID(), event->GetTime(), event->GetDuration());
1286 fprintf(f, "Event %i title = %s subtitle = %s\n", 0, event->GetTitle(), event->GetSubtitle());
1287 fprintf(f, "Event %i extendeddescription = %s\n", 0, event->GetExtendedDescription());
1288 fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", 0, event->IsFollowing(), event->IsPresent());
1290 event = Schedule->GetFollowingEvent();
1292 fprintf(f, "\n\nFollowing event\n\n");
1294 fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", 0, event->GetEventID(), event->GetTime(), event->GetDuration());
1295 fprintf(f, "Event %i title = %s subtitle = %s\n", 0, event->GetTitle(), event->GetSubtitle());
1296 fprintf(f, "Event %i extendeddescription = %s\n", 0, event->GetExtendedDescription());
1297 fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", 0, event->IsFollowing(), event->IsPresent());
1303 fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", eventNumber, event->GetEventID(), event->GetTime(), event->GetDuration());
1304 fprintf(f, "Event %i title = %s subtitle = %s\n", eventNumber, event->GetTitle(), event->GetSubtitle());
1305 fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
1306 fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", eventNumber, event->IsFollowing(), event->IsPresent());
1314 void MVPClient::test2()
1316 FILE* f = fopen("/tmp/s.txt", "w");
1318 #if VDRVERSNUM < 10300
1319 cMutexLock MutexLock;
1320 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1322 cSchedulesLock MutexLock;
1323 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
1328 fprintf(f, "Schedules = NULL\n");
1333 fprintf(f, "Schedules dump:\n");
1337 const cSchedule *Schedule;
1338 int scheduleNumber = 0;
1341 cChannel *thisChannel;
1343 #if VDRVERSNUM < 10300
1344 const cEventInfo *event;
1345 int eventNumber = 0;
1347 const cEvent *event;
1350 // Schedule = Schedules->GetSchedule(channel->GetChannelID());
1351 // Schedule = Schedules->GetSchedule();
1352 Schedule = Schedules->First();
1355 fprintf(f, "First Schedule = NULL\n");
1362 fprintf(f, "Schedule #%i\n", scheduleNumber);
1363 fprintf(f, "-------------\n\n");
1365 #if VDRVERSNUM < 10300
1366 tchid = Schedule->GetChannelID();
1368 tchid = Schedule->ChannelID();
1371 #if VDRVERSNUM < 10300
1372 fprintf(f, "ChannelID.ToString() = %s\n", tchid.ToString());
1373 fprintf(f, "NumEvents() = %i\n", Schedule->NumEvents());
1375 // put the count at the end.
1378 thisChannel = Channels.GetByChannelID(tchid, true);
1381 fprintf(f, "Channel Number: %p %i\n", thisChannel, thisChannel->Number());
1385 fprintf(f, "thisChannel = NULL for tchid\n");
1388 #if VDRVERSNUM < 10300
1389 for (eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1391 event = Schedule->GetEventNumber(eventNumber);
1392 fprintf(f, "Event %i tableid = %i timestring = %s endtimestring = %s\n", eventNumber, event->GetTableID(), event->GetTimeString(), event->GetEndTimeString());
1393 fprintf(f, "Event %i date = %s isfollowing = %i ispresent = %i\n", eventNumber, event->GetDate(), event->IsFollowing(), event->IsPresent());
1394 fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
1395 fprintf(f, "Event %i subtitle = %s title = %s\n", eventNumber, event->GetSubtitle(), event->GetTitle());
1396 fprintf(f, "Event %i eventid = %u duration = %li time = %lu channelnumber = %i\n", eventNumber, event->GetEventID(), event->GetDuration(), event->GetTime(), event->GetChannelNumber());
1397 fprintf(f, "Event %u dump:\n", eventNumber);
1402 // This whole section needs rewriting to walk the list.
1403 event = Schedule->Events()->First();
1405 event = Schedule->Events()->Next(event);
1410 fprintf(f, "\nDump from object:\n");
1412 fprintf(f, "\nEND\n");
1422 fprintf(f, "End of current Schedule\n\n\n");
1424 Schedule = (const cSchedule *)Schedules->Next(Schedule);
1438 const cEventInfo *GetPresentEvent(void) const;
1439 const cEventInfo *GetFollowingEvent(void) const;
1440 const cEventInfo *GetEvent(unsigned short uEventID, time_t tTime = 0) const;
1441 const cEventInfo *GetEventAround(time_t tTime) const;
1442 const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); }
1445 const unsigned char GetTableID(void) const;
1446 const char *GetTimeString(void) const;
1447 const char *GetEndTimeString(void) const;
1448 const char *GetDate(void) const;
1449 bool IsFollowing(void) const;
1450 bool IsPresent(void) const;
1451 const char *GetExtendedDescription(void) const;
1452 const char *GetSubtitle(void) const;
1453 const char *GetTitle(void) const;
1454 unsigned short GetEventID(void) const;
1455 long GetDuration(void) const;
1456 time_t GetTime(void) const;
1457 tChannelID GetChannelID(void) const;
1458 int GetChannelNumber(void) const { return nChannelNumber; }
1459 void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const'
1460 void Dump(FILE *f, const char *Prefix = "") const;
1466 void MVPClient::test(int channelNumber)
1468 FILE* f = fopen("/tmp/test.txt", "w");
1470 cMutexLock MutexLock;
1471 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1475 fprintf(f, "Schedules = NULL\n");
1480 fprintf(f, "Schedules dump:\n");
1481 // Schedules->Dump(f);
1483 const cSchedule *Schedule;
1484 cChannel *thisChannel;
1485 const cEventInfo *event;
1487 thisChannel = channelFromNumber(channelNumber);
1490 fprintf(f, "thisChannel = NULL\n");
1495 Schedule = Schedules->GetSchedule(thisChannel->GetChannelID());
1496 // Schedule = Schedules->GetSchedule();
1497 // Schedule = Schedules->First();
1500 fprintf(f, "First Schedule = NULL\n");
1505 fprintf(f, "NumEvents() = %i\n\n", Schedule->NumEvents());
1507 // For some channels VDR seems to pick a random point in time to
1508 // start dishing out events, but they are in order
1509 // at some point in the list the time snaps to the current event
1514 for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1516 event = Schedule->GetEventNumber(eventNumber);
1517 fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", eventNumber, event->GetEventID(), event->GetTime(), event->GetDuration());
1518 fprintf(f, "Event %i title = %s subtitle = %s\n", eventNumber, event->GetTitle(), event->GetSubtitle());
1519 fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
1523 fprintf(f, "\nEND\n");
1537 Schedules = the collection of all the Schedule objects
1538 Schedule = One schedule, contants all the events for a channel
1539 Event = One programme
1548 Subtitle (used for "Programmes resume at ...")
1551 IsPresent ? easy to work out tho. Oh it doesn't always work
1556 void MVPClient::test2()
1558 log->log("-", Log::DEBUG, "Timers List");
1560 for (int i = 0; i < Timers.Count(); i++)
1562 cTimer *timer = Timers.Get(i);
1563 //Reply(i < Timers.Count() - 1 ? -250 : 250, "%d %s", timer->Index() + 1, timer->ToText());
1564 log->log("-", Log::DEBUG, "i=%i count=%i index=%d", i, Timers.Count(), timer->Index() + 1);
1565 #if VDRVERSNUM < 10300
1566 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());
1568 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());
1570 log->log("-", Log::DEBUG, "channel=%i file=%s summary=%s", timer->Channel()->Number(), timer->File(), timer->Summary());
1571 log->log("-", Log::DEBUG, "");
1574 // asprintf(&buffer, "%d:%s:%s :%04d:%04d:%d:%d:%s:%s\n",
1575 // active, (UseChannelID ? Channel()->GetChannelID().ToString() : itoa(Channel()->Number())),
1576 // PrintDay(day, firstday), start, stop, priority, lifetime, file, summary ? summary : "");
1581 Active seems to be a bool - whether the timer should be done or not. If set to inactive it stays around after its time
1582 recording is a bool, 0 for not currently recording, 1 for currently recording
1583 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
1587 int MVPClient::processGetTimers(UCHAR* buffer, int length)
1589 UCHAR* sendBuffer = new UCHAR[50000]; // FIXME hope this is enough
1590 int count = 4; // leave space for the packet length
1592 const char* fileName;
1594 int numTimers = Timers.Count();
1596 *(ULONG*)&sendBuffer[count] = htonl(numTimers); count += 4;
1598 for (int i = 0; i < numTimers; i++)
1600 if (count > 49000) break;
1602 timer = Timers.Get(i);
1604 #if VDRVERSNUM < 10300
1605 *(ULONG*)&sendBuffer[count] = htonl(timer->Active()); count += 4;
1607 *(ULONG*)&sendBuffer[count] = htonl(timer->HasFlags(tfActive)); count += 4;
1609 *(ULONG*)&sendBuffer[count] = htonl(timer->Recording()); count += 4;
1610 *(ULONG*)&sendBuffer[count] = htonl(timer->Pending()); count += 4;
1611 *(ULONG*)&sendBuffer[count] = htonl(timer->Priority()); count += 4;
1612 *(ULONG*)&sendBuffer[count] = htonl(timer->Lifetime()); count += 4;
1613 *(ULONG*)&sendBuffer[count] = htonl(timer->Channel()->Number()); count += 4;
1614 *(ULONG*)&sendBuffer[count] = htonl(timer->StartTime()); count += 4;
1615 *(ULONG*)&sendBuffer[count] = htonl(timer->StopTime()); count += 4;
1616 *(ULONG*)&sendBuffer[count] = htonl(timer->Day()); count += 4;
1617 *(ULONG*)&sendBuffer[count] = htonl(timer->WeekDays()); count += 4;
1619 fileName = timer->File();
1620 strcpy((char*)&sendBuffer[count], fileName);
1621 count += strlen(fileName) + 1;
1624 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
1626 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
1628 //tcp.dump(sendBuffer, count);
1630 tcp.sendPacket(sendBuffer, count);
1631 delete[] sendBuffer;
1632 log->log("Client", Log::DEBUG, "Written timers list");
1637 int MVPClient::processSetTimer(UCHAR* buffer, int length)
1639 char* timerString = new char[strlen((char*)buffer) + 1];
1640 strcpy(timerString, (char*)buffer);
1642 #if VDRVERSNUM < 10300
1644 // If this is VDR 1.2 the date part of the timer string must be reduced
1645 // to just DD rather than YYYY-MM-DD
1647 int s = 0; // source
1648 int d = 0; // destination
1650 while(c != 2) // copy up to date section, including the second ':'
1652 timerString[d] = buffer[s];
1653 if (buffer[s] == ':') c++;
1657 // now it has copied up to the date section
1659 while(c != 2) // waste YYYY-MM-
1661 if (buffer[s] == '-') c++;
1664 // now source is at the DD
1665 memcpy(&timerString[d], &buffer[s], length - s);
1667 timerString[d] = '\0';
1669 log->log("Client", Log::DEBUG, "Timer string after 1.2 conversion:");
1670 log->log("Client", Log::DEBUG, "%s", timerString);
1674 cTimer *timer = new cTimer;
1675 if (timer->Parse((char*)timerString))
1677 cTimer *t = Timers.GetTimer(timer);
1681 #if VDRVERSNUM < 10300
1684 Timers.SetModified();
1702 void MVPClient::incClients()
1704 pthread_mutex_lock(&threadClientMutex);
1705 MVPClient::nr_clients++;
1706 pthread_mutex_unlock(&threadClientMutex);
1709 void MVPClient::decClients()
1711 pthread_mutex_lock(&threadClientMutex);
1712 MVPClient::nr_clients--;
1713 pthread_mutex_unlock(&threadClientMutex);
1716 int MVPClient::getNrClients()
1719 pthread_mutex_lock(&threadClientMutex);
1720 nrClients = MVPClient::nr_clients;
1721 pthread_mutex_unlock(&threadClientMutex);
1725 int MVPClient::processGetRecInfo(UCHAR* data, int length)
1727 // data is a pointer to the fileName string
1729 cRecordings Recordings;
1730 Recordings.Load(); // probably have to do this
1732 cRecording *recording = Recordings.GetByName((char*)data);
1734 time_t timerStart = 0;
1735 time_t timerStop = 0;
1736 char* summary = NULL;
1737 ULONG resumePoint = 0;
1741 log->log("Client", Log::ERR, "GetRecInfo found no recording");
1746 ULONG sendBufferSize = 10000;
1747 UCHAR* sendBuffer = (UCHAR*)malloc(sendBufferSize);
1748 ULONG pos = 4; // leave first 4 bytes for size field
1752 4 bytes: start time for timer
1753 4 bytes: end time for timer
1754 4 bytes: resume point
1756 4 bytes: num components
1766 // Get current timer
1768 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
1771 timerStart = rc->Timer()->StartTime();
1772 timerStop = rc->Timer()->StopTime();
1773 log->log("Client", Log::DEBUG, "GRI: RC: %lu %lu", timerStart, timerStop);
1776 *(time_t*)&sendBuffer[pos] = htonl(timerStart); pos += 4;
1777 *(time_t*)&sendBuffer[pos] = htonl(timerStop); pos += 4;
1781 char* value = config.getValueString("ResumeData", (char*)data);
1784 resumePoint = strtoul(value, NULL, 10);
1787 log->log("Client", Log::DEBUG, "GRI: RP: %lu", resumePoint);
1789 *(ULONG*)&sendBuffer[pos] = htonl(resumePoint); pos += 4;
1794 #if VDRVERSNUM < 10300
1795 summary = (char*)recording->Summary();
1797 const cRecordingInfo *Info = recording->Info();
1798 summary = (char*)Info->ShortText();
1799 if (isempty(summary)) summary = (char*)Info->Description();
1801 log->log("Client", Log::DEBUG, "GRI: S: %s", summary);
1804 // memory insanity...
1805 if ((sendBufferSize - pos) < (strlen(summary) + 500)) // random
1807 UCHAR* newBuffer = (UCHAR*)realloc(sendBuffer, sendBufferSize + strlen(summary) + 10000);
1810 sendBuffer = newBuffer;
1811 sendBufferSize += strlen(summary) + 10000;
1821 strcpy((char*)&sendBuffer[pos], summary);
1822 pos += strlen(summary) + 1;
1826 strcpy((char*)&sendBuffer[pos], "");
1833 #if VDRVERSNUM < 10300
1835 // Send 0 for numchannels - this signals the client this info is not available
1836 *(ULONG*)&sendBuffer[pos] = 0; pos += 4;
1839 const cComponents* components = Info->Components();
1841 log->log("Client", Log::DEBUG, "GRI: D1: %p", components);
1845 *(ULONG*)&sendBuffer[pos] = htonl(0); pos += 4;
1849 *(ULONG*)&sendBuffer[pos] = htonl(components->NumComponents()); pos += 4;
1851 tComponent* component;
1852 for (int i = 0; i < components->NumComponents(); i++)
1854 component = components->Component(i);
1856 // memory insanity...
1857 ULONG extraNeeded = 2 + (component->language ? strlen(component->language) : 0)
1858 + (component->description ? strlen(component->description) : 0) + 2;
1860 if ((sendBufferSize - pos) < extraNeeded)
1862 UCHAR* newBuffer = (UCHAR*)realloc(sendBuffer, sendBufferSize + extraNeeded + 10000);
1865 sendBuffer = newBuffer;
1866 sendBufferSize += extraNeeded + 10000;
1876 log->log("Client", Log::DEBUG, "GRI: C: %i %u %u %s %s", i, component->stream, component->type, component->language, component->description);
1877 sendBuffer[pos] = component->stream; pos += 1;
1878 sendBuffer[pos] = component->type; pos += 1;
1879 if (component->language)
1881 strcpy((char*)&sendBuffer[pos], component->language);
1882 pos += strlen(component->language) + 1;
1886 strcpy((char*)&sendBuffer[pos], "");
1889 if (component->description)
1891 strcpy((char*)&sendBuffer[pos], component->description);
1892 pos += strlen(component->description) + 1;
1896 strcpy((char*)&sendBuffer[pos], "");
1907 *(ULONG*)&sendBuffer[0] = htonl(pos - 4); // -4 : take off the size field
1909 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
1911 tcp.sendPacket(sendBuffer, pos);
1912 delete[] sendBuffer;
1913 log->log("Client", Log::DEBUG, "Written getrecinfo");
1923 int MVPClient::processReScanRecording(UCHAR* data, int length)
1927 log->log("Client", Log::DEBUG, "Rescan recording called when no recording being played!");
1933 UCHAR sendBuffer[16];
1934 *(ULONG*)&sendBuffer[0] = htonl(12);
1935 *(ULLONG*)&sendBuffer[4] = htonll(rp->getLengthBytes());
1936 *(ULONG*)&sendBuffer[12] = htonl(rp->getLengthFrames());
1938 tcp.sendPacket(sendBuffer, 16);
1939 log->log("Client", Log::DEBUG, "Rescan recording, wrote new length to client");
1943 // FIXME without client calling rescan, getblock wont work even tho more data is avail
1946 int MVPClient::processGetMarks(UCHAR* data, int length)
1948 // data is a pointer to the fileName string
1950 UCHAR* sendBuffer = new UCHAR[50000]; // FIXME hope this is enough
1951 int count = 4; // leave space for the packet length
1955 cRecordings Recordings;
1956 Recordings.Load(); // probably have to do this
1958 cRecording *recording = Recordings.GetByName((char*)data);
1960 log->log("Client", Log::DEBUG, "recording pointer %p", recording);
1964 Marks.Load(recording->FileName());
1967 for (const cMark *m = Marks.First(); m; m = Marks.Next(m))
1969 log->log("Client", Log::DEBUG, "found Mark %i", m->position);
1971 if (count > 49000) break;
1972 *(ULONG*)&sendBuffer[count] = htonl(m->position);
1978 log->log("Client", Log::DEBUG, "no marks found, sending 0-mark");
1979 *(ULONG*)&sendBuffer[count] = htonl(0);
1984 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
1986 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
1988 tcp.sendPacket(sendBuffer, count);
1989 delete[] sendBuffer;
1990 log->log("Client", Log::DEBUG, "Written Marks list");
1997 * media List Request:
1999 * 4 VDR_GETMEDIALIST
2000 * 4 flags (currently unused)
2003 * Media List response:
2011 * 4 strlen (incl. 0 Byte)
2015 #define MLISTBUF 500000
2016 int MVPClient::processGetMediaList(UCHAR* data, int length)
2019 log->log("Client", Log::ERR, "getMediaList packet too short %d", length);
2022 char * dirname=NULL;
2024 //we have a dirname provided
2025 dirname=(char *)&data[4];
2026 log->log("Client", Log::DEBUG, "getMediaList for %s", dirname);
2030 UCHAR* sendBuffer = new UCHAR[MLISTBUF]; // FIXME hope this is enough
2031 int count = 4; // leave space for the header
2033 MediaList * ml=MediaList::readList(baseConfig,dirname);
2035 log->log("Client", Log::ERR, "getMediaList returned NULL");
2038 //response code (not yet set)
2039 *(ULONG*)&sendBuffer[count] = htonl(0);
2042 *(ULONG*)&sendBuffer[count] = htonl(ml->Count());
2044 for (int nm=0;nm<ml->Count() && count < (MLISTBUF-1000);nm++) {
2045 Media *m=ml->Get(nm);
2046 log->log("Client", Log::DEBUG, "found media entry %s, type=%d",m->getFilename(),m->getType());
2047 *(ULONG*)&sendBuffer[count] = htonl(m->getType());
2050 *(ULONG*)&sendBuffer[count] = htonl(m->getTime());
2053 *(ULONG*)&sendBuffer[count] = htonl(0);
2055 int len=strlen(m->getFilename());
2057 *(ULONG*)&sendBuffer[count] = htonl(len+1);
2059 //should have a check for strlen > 1000...
2060 strcpy((char *)&sendBuffer[count],m->getFilename());
2065 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
2067 log->log("Client", Log::DEBUG, "getMediaList size %u", ntohl(*(ULONG*)&sendBuffer[0]));
2069 tcp.sendPacket(sendBuffer, count);
2070 delete[] sendBuffer;
2071 log->log("Client", Log::DEBUG, "Written Media list");
2077 * get image Request:
2080 * 4 flags (currently unused)
2085 * get image response:
2090 #define MLISTBUF 500000
2091 int MVPClient::processGetPicture(UCHAR* data, int length)
2094 log->log("Client", Log::ERR, "getPicture packet too short %d", length);
2101 char * filename=NULL;
2103 //we have a dirname provided
2104 filename=(char *)&data[4];
2105 log->log("Client", Log::DEBUG, "getPicture %s", filename);
2108 log->log("Client", Log::ERR, "getPicture empty filename");
2111 imageFile=fopen(filename,"r");
2112 if (!imageFile) log->log("Client", Log::ERR, "getPicture unable to open %s",filename);
2117 if ( fstat(fileno(imageFile),&st) == 0) size=st.st_size;
2119 UCHAR* sendBuffer = new UCHAR[12];
2120 int count = 4; // leave space for the header
2121 //response code (not yet set)
2122 *(ULONG*)&sendBuffer[count] = htonl(31);
2125 *(ULONG*)&sendBuffer[count] = htonl(size);
2127 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
2128 log->log("Client", Log::DEBUG, "getPicture size %u", size);
2130 tcp.sendPacket(sendBuffer, count);
2131 delete[] sendBuffer;
2132 log->log("Client", Log::DEBUG, "Written Media list");
2138 int MVPClient::processGetImageBlock(UCHAR* data, int length)
2142 log->log("Client", Log::DEBUG, "Get image block called when no image active");
2146 ULLONG position = ntohll(*(ULLONG*)data);
2147 data += sizeof(ULLONG);
2148 ULONG amount = ntohl(*(ULONG*)data);
2150 log->log("Client", Log::DEBUG, "getImageblock pos = %llu length = %lu", position, amount);
2152 UCHAR sendBuffer[amount + 4];
2153 ULONG amountReceived = 0; // compiler moan.
2154 ULLONG cpos=ftell(imageFile);
2155 if (position != cpos) {
2156 fseek(imageFile,position-cpos,SEEK_CUR);
2158 if (position != (ULLONG)ftell(imageFile)) {
2159 log->log("Client", Log::DEBUG, "getImageblock pos = %llu not available", position);
2162 amountReceived=fread(&sendBuffer[4],1,amount,imageFile);
2165 if (!amountReceived)
2168 log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0");
2172 *(ULONG*)&sendBuffer[0] = htonl(amountReceived);
2173 tcp.sendPacket(sendBuffer, amountReceived + 4);
2174 log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
2180 int MVPClient::processDeleteTimer(UCHAR* buffer, int length)
2182 log->log("Client", Log::DEBUG, "Delete timer called");
2187 INT delChannel = ntohl(*(ULONG*)&buffer[position]); position += 4;
2188 INT delWeekdays = ntohl(*(ULONG*)&buffer[position]); position += 4;
2189 INT delDay = ntohl(*(ULONG*)&buffer[position]); position += 4;
2190 INT delStart = ntohl(*(ULONG*)&buffer[position]); position += 4;
2191 INT delStop = ntohl(*(ULONG*)&buffer[position]); position += 4;
2194 for (ti = Timers.First(); ti; ti = Timers.Next(ti))
2196 if ( (ti->Channel()->Number() == delChannel)
2197 && ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
2198 && (ti->StartTime() == delStart)
2199 && (ti->StopTime() == delStop) )
2209 if (!Timers.BeingEdited())
2211 if (!ti->Recording())
2214 Timers.SetModified();
2220 log->log("Client", Log::ERR, "Unable to delete timer - timer is running");
2227 log->log("Client", Log::ERR, "Unable to delete timer - timers being edited at VDR");