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();
178 log->log("Client", Log::DEBUG, "Waiting");
179 buffer = (UCHAR*)tcp.receivePacket();
180 log->log("Client", Log::DEBUG, "Received packet, length = %u", tcp.getDataLength());
183 log->log("Client", Log::DEBUG, "Detected connection closed");
187 packetLength = tcp.getDataLength() - 4;
188 opcode = ntohl(*(ULONG*)buffer);
191 if (!loggedIn && (opcode != 1))
197 log->log("Client", Log::DEBUG, "SwitchOp");
201 result = processLogin(data, packetLength);
204 result = processGetRecordingsList(data, packetLength);
207 result = processDeleteRecording(data, packetLength);
210 result = processGetChannelsList(data, packetLength);
213 result = processStartStreamingChannel(data, packetLength);
216 result = processGetBlock(data, packetLength);
219 result = processStopStreaming(data, packetLength);
222 result = processStartStreamingRecording(data, packetLength);
225 result = processGetChannelSchedule(data, packetLength);
228 result = processConfigSave(data, packetLength);
231 result = processConfigLoad(data, packetLength);
234 result = processReScanRecording(data, packetLength); // FIXME obselete
237 result = processGetTimers(data, packetLength);
240 result = processSetTimer(data, packetLength);
243 result = processPositionFromFrameNumber(data, packetLength);
246 result = processFrameNumberFromPosition(data, packetLength);
249 result = processMoveRecording(data, packetLength);
252 result = processGetIFrame(data, packetLength);
255 result = processGetRecInfo(data, packetLength);
258 result = processGetMarks(data, packetLength);
261 result = processGetChannelPids(data, packetLength);
264 result = processDeleteTimer(data, packetLength);
267 result = processGetMediaList(data, packetLength);
270 result = processGetPicture(data, packetLength);
273 result = processGetImageBlock(data, packetLength);
282 int MVPClient::processLogin(UCHAR* buffer, int length)
284 if (length != 6) return 0;
288 const char* configDir = cPlugin::ConfigDirectory(configDirExtra);
291 log->log("Client", Log::DEBUG, "No config dir!");
295 char configFileName[PATH_MAX];
296 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]);
297 config.init(configFileName);
299 // Send the login reply
301 time_t timeNow = time(NULL);
302 struct tm* timeStruct = localtime(&timeNow);
303 int timeOffset = timeStruct->tm_gmtoff;
305 UCHAR sendBuffer[12];
306 *(ULONG*)&sendBuffer[0] = htonl(8);
307 *(ULONG*)&sendBuffer[4] = htonl(timeNow);
308 *(signed int*)&sendBuffer[8] = htonl(timeOffset);
310 tcp.sendPacket(sendBuffer, 12);
311 log->log("Client", Log::DEBUG, "written login reply");
317 int MVPClient::processGetRecordingsList(UCHAR* data, int length)
319 UCHAR* sendBuffer = new UCHAR[50000]; // hope this is enough
320 int count = 4; // leave space for the packet length
325 int Percent = VideoDiskSpace(&FreeMB);
326 int Total = (FreeMB / (100 - Percent)) * 100;
328 *(ULONG*)&sendBuffer[count] = htonl(Total);
329 count += sizeof(ULONG);
330 *(ULONG*)&sendBuffer[count] = htonl(FreeMB);
331 count += sizeof(ULONG);
332 *(ULONG*)&sendBuffer[count] = htonl(Percent);
333 count += sizeof(ULONG);
336 cRecordings Recordings;
339 for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
341 if (count > 49000) break; // just how big is that hard disk?!
342 *(ULONG*)&sendBuffer[count] = htonl(recording->start);// + timeOffset);
345 point = (char*)recording->Name();
346 strcpy((char*)&sendBuffer[count], point);
347 count += strlen(point) + 1;
349 point = (char*)recording->FileName();
350 strcpy((char*)&sendBuffer[count], point);
351 count += strlen(point) + 1;
354 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
356 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
358 tcp.sendPacket(sendBuffer, count);
360 log->log("Client", Log::DEBUG, "Written list");
365 int MVPClient::processDeleteRecording(UCHAR* data, int length)
367 // data is a pointer to the fileName string
369 cRecordings Recordings;
370 Recordings.Load(); // probably have to do this
372 cRecording* recording = Recordings.GetByName((char*)data);
374 log->log("Client", Log::DEBUG, "recording pointer %p", recording);
378 log->log("Client", Log::DEBUG, "deleting recording: %s", recording->Name());
380 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
383 if (recording->Delete())
385 // Copy svdrp's way of doing this, see if it works
386 #if VDRVERSNUM > 10300
387 ::Recordings.DelByName(recording->FileName());
409 int MVPClient::processMoveRecording(UCHAR* data, int length)
411 log->log("Client", Log::DEBUG, "Process move recording");
412 char* fileName = (char*)data;
413 char* newPath = NULL;
415 for (int k = 0; k < length; k++)
419 newPath = (char*)&data[k+1];
423 if (!newPath) return 0;
425 cRecordings Recordings;
426 Recordings.Load(); // probably have to do this
428 cRecording* recording = Recordings.GetByName((char*)fileName);
430 log->log("Client", Log::DEBUG, "recording pointer %p", recording);
434 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
437 log->log("Client", Log::DEBUG, "moving recording: %s", recording->Name());
438 log->log("Client", Log::DEBUG, "moving recording: %s", recording->FileName());
439 log->log("Client", Log::DEBUG, "to: %s", newPath);
441 const char* t = recording->FileName();
443 char* dateDirName = NULL; int k;
444 char* titleDirName = NULL; int j;
446 // Find the datedirname
447 for(k = strlen(t) - 1; k >= 0; k--)
451 log->log("Client", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
452 dateDirName = new char[strlen(&t[k+1]) + 1];
453 strcpy(dateDirName, &t[k+1]);
458 // Find the titledirname
460 for(j = k-1; j >= 0; j--)
464 log->log("Client", Log::DEBUG, "l2: %i", (k - j - 1) + 1);
465 titleDirName = new char[(k - j - 1) + 1];
466 memcpy(titleDirName, &t[j+1], k - j - 1);
467 titleDirName[k - j - 1] = '\0';
472 log->log("Client", Log::DEBUG, "datedirname: %s", dateDirName);
473 log->log("Client", Log::DEBUG, "titledirname: %s", titleDirName);
475 log->log("Client", Log::DEBUG, "viddir: %s", VideoDirectory);
477 char* newContainer = new char[strlen(VideoDirectory) + strlen(newPath) + strlen(titleDirName) + 1];
478 log->log("Client", Log::DEBUG, "l10: %i", strlen(VideoDirectory) + strlen(newPath) + strlen(titleDirName) + 1);
479 sprintf(newContainer, "%s%s%s", VideoDirectory, newPath, titleDirName);
481 // FIXME Check whether this already exists before mkdiring it
483 log->log("Client", Log::DEBUG, "%s", newContainer);
487 int statret = stat(newContainer, &dstat);
488 if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
490 log->log("Client", Log::DEBUG, "new dir does not exist");
491 int mkdirret = mkdir(newContainer, 0755);
494 delete[] dateDirName;
495 delete[] titleDirName;
496 delete[] newContainer;
501 else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR))) // Something exists but it's not a dir
503 delete[] dateDirName;
504 delete[] titleDirName;
505 delete[] newContainer;
510 // Ok, the directory container has been made, or it pre-existed.
512 char* newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
513 sprintf(newDir, "%s/%s", newContainer, dateDirName);
515 log->log("Client", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
516 int renameret = rename(t, newDir);
519 // Success. Test for remove old dir containter
520 char* oldTitleDir = new char[k+1];
521 memcpy(oldTitleDir, t, k);
522 oldTitleDir[k] = '\0';
523 log->log("Client", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(oldTitleDir), oldTitleDir);
524 rmdir(oldTitleDir); // can't do anything about a fail result at this point.
525 delete[] oldTitleDir;
530 #if VDRVERSNUM > 10311
532 ::Recordings.Update();
534 // Success. Send a different packet from just a ulong
535 int totalLength = 4 + 4 + strlen(newDir) + 1;
536 UCHAR* sendBuffer = new UCHAR[totalLength];
537 *(ULONG*)&sendBuffer[0] = htonl(totalLength - 4);
538 *(ULONG*)&sendBuffer[4] = htonl(1); // success
539 strcpy((char*)&sendBuffer[8], newDir);
540 tcp.sendPacket(sendBuffer, totalLength);
548 delete[] dateDirName;
549 delete[] titleDirName;
550 delete[] newContainer;
566 int MVPClient::processGetChannelsList(UCHAR* data, int length)
568 UCHAR* sendBuffer = new UCHAR[50000]; // FIXME hope this is enough
569 int count = 4; // leave space for the packet length
573 char* chanConfig = config.getValueString("General", "Channels");
575 if (chanConfig) allChans = strcasecmp(chanConfig, "FTA only");
577 for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
579 #if VDRVERSNUM < 10300
580 if (!channel->GroupSep() && (!channel->Ca() || allChans))
582 if (!channel->GroupSep() && (!channel->Ca(0) || allChans))
585 log->log("Client", Log::DEBUG, "name: '%s'", channel->Name());
587 if (channel->Vpid()) type = 1;
588 #if VDRVERSNUM < 10300
591 else if (channel->Apid(0)) type = 2;
595 if (count > 49000) break;
596 *(ULONG*)&sendBuffer[count] = htonl(channel->Number());
599 *(ULONG*)&sendBuffer[count] = htonl(type);
602 point = (char*)channel->Name();
603 strcpy((char*)&sendBuffer[count], point);
604 count += strlen(point) + 1;
608 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
610 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
612 tcp.sendPacket(sendBuffer, count);
614 log->log("Client", Log::DEBUG, "Written channels list");
619 int MVPClient::processGetChannelPids(UCHAR* data, int length)
621 ULONG channelNumber = ntohl(*(ULONG*)data);
623 cChannel* channel = channelFromNumber(channelNumber);
631 ULONG spaceRequired = 12; // 4 for length field, 4 for vpid, 4 for number of apids
632 // Work out space required and number of Apids
634 #if VDRVERSNUM < 10300
636 log->log("Client", Log::DEBUG, "Apid1: %i", channel->Apid1());
637 log->log("Client", Log::DEBUG, "Apid2: %i", channel->Apid2());
639 if (channel->Apid2())
642 spaceRequired += 10; // 8 + 2 nulls
644 else if (channel->Apid1())
647 spaceRequired += 5; // 4 + 1 null
656 for (const int *Apid = channel->Apids(); *Apid; Apid++)
658 spaceRequired += 4 + strlen(channel->Alang(numApids)) + 1; // 4 for pid, length of string + \0
664 // Format of response
672 UCHAR* sendBuffer = new UCHAR[spaceRequired];
674 *(ULONG*)&sendBuffer[point] = htonl(spaceRequired - 4); point += 4; // take off first 4 bytes
675 *(ULONG*)&sendBuffer[point] = htonl(channel->Vpid()); point += 4;
676 *(ULONG*)&sendBuffer[point] = htonl(numApids); point += 4;
678 #if VDRVERSNUM < 10300
681 *(ULONG*)&sendBuffer[point] = htonl(channel->Apid1()); point += 4;
682 sendBuffer[point] = '\0'; point += 1;
686 *(ULONG*)&sendBuffer[point] = htonl(channel->Apid2()); point += 4;
687 sendBuffer[point] = '\0'; point += 1;
690 for (ULONG i = 0; i < numApids; i++)
692 *(ULONG*)&sendBuffer[point] = htonl(channel->Apid(i)); point += 4;
693 strcpy((char*)&sendBuffer[point], channel->Alang(i)); point += strlen(channel->Alang(i)) + 1;
697 // printf("About to send getchannelpids response. length = %u\n", spaceRequired);
698 tcp.dump(sendBuffer, spaceRequired);
700 tcp.sendPacket(sendBuffer, spaceRequired);
702 log->log("Client", Log::DEBUG, "Written channels pids");
707 int MVPClient::processStartStreamingChannel(UCHAR* data, int length)
709 log->log("Client", Log::DEBUG, "length = %i", length);
710 ULONG channelNumber = ntohl(*(ULONG*)data);
712 cChannel* channel = channelFromNumber(channelNumber);
719 // get the priority we should use
721 int priority = config.getValueLong("General", "Live priority", &fail);
724 log->log("Client", Log::DEBUG, "Config: Live TV priority: %i", priority);
728 log->log("Client", Log::DEBUG, "Config: Live TV priority config fail");
733 if (priority < 0) priority = 0;
734 if (priority > 99) priority = 99;
736 log->log("Client", Log::DEBUG, "Using live TV priority %i", priority);
737 lp = MVPReceiver::create(channel, priority);
757 int MVPClient::processStopStreaming(UCHAR* data, int length)
759 log->log("Client", Log::DEBUG, "STOP STREAMING RECEIVED");
770 delete recordingManager;
772 recordingManager = NULL;
779 int MVPClient::processGetBlock(UCHAR* data, int length)
783 log->log("Client", Log::DEBUG, "Get block called when no streaming happening!");
787 ULLONG position = ntohll(*(ULLONG*)data);
788 data += sizeof(ULLONG);
789 ULONG amount = ntohl(*(ULONG*)data);
791 log->log("Client", Log::DEBUG, "getblock pos = %llu length = %lu", position, amount);
793 UCHAR sendBuffer[amount + 4];
794 ULONG amountReceived = 0; // compiler moan.
797 log->log("Client", Log::DEBUG, "getting from live");
798 amountReceived = lp->getBlock(&sendBuffer[4], amount);
802 // vdr has possibly disconnected the receiver
803 log->log("Client", Log::DEBUG, "VDR has disconnected the live receiver");
810 log->log("Client", Log::DEBUG, "getting from recording");
811 amountReceived = rp->getBlock(&sendBuffer[4], position, amount);
817 log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0");
821 *(ULONG*)&sendBuffer[0] = htonl(amountReceived);
822 tcp.sendPacket(sendBuffer, amountReceived + 4);
823 log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
829 int MVPClient::processStartStreamingRecording(UCHAR* data, int length)
831 // data is a pointer to the fileName string
833 recordingManager = new cRecordings;
834 recordingManager->Load();
836 cRecording* recording = recordingManager->GetByName((char*)data);
838 log->log("Client", Log::DEBUG, "recording pointer %p", recording);
842 rp = new RecPlayer(recording);
844 UCHAR sendBuffer[16];
845 *(ULONG*)&sendBuffer[0] = htonl(12);
846 *(ULLONG*)&sendBuffer[4] = htonll(rp->getLengthBytes());
847 *(ULONG*)&sendBuffer[12] = htonl(rp->getLengthFrames());
849 tcp.sendPacket(sendBuffer, 16);
850 log->log("Client", Log::DEBUG, "written totalLength");
854 delete recordingManager;
855 recordingManager = NULL;
860 int MVPClient::processPositionFromFrameNumber(UCHAR* data, int length)
864 ULONG frameNumber = ntohl(*(ULONG*)data);
869 log->log("Client", Log::DEBUG, "Rescan recording called when no recording being played!");
873 retval = rp->positionFromFrameNumber(frameNumber);
876 UCHAR sendBuffer[12];
877 *(ULONG*)&sendBuffer[0] = htonl(8);
878 *(ULLONG*)&sendBuffer[4] = htonll(retval);
880 tcp.sendPacket(sendBuffer, 12);
881 log->log("Client", Log::DEBUG, "Wrote posFromFrameNum reply to client");
885 int MVPClient::processFrameNumberFromPosition(UCHAR* data, int length)
889 ULLONG position = ntohll(*(ULLONG*)data);
894 log->log("Client", Log::DEBUG, "Rescan recording called when no recording being played!");
898 retval = rp->frameNumberFromPosition(position);
902 *(ULONG*)&sendBuffer[0] = htonl(4);
903 *(ULONG*)&sendBuffer[4] = htonl(retval);
905 tcp.sendPacket(sendBuffer, 8);
906 log->log("Client", Log::DEBUG, "Wrote frameNumFromPos reply to client");
910 int MVPClient::processGetIFrame(UCHAR* data, int length)
912 bool success = false;
914 ULONG frameNumber = ntohl(*(ULONG*)data);
916 ULONG direction = ntohl(*(ULONG*)data);
919 ULLONG rfilePosition = 0;
920 ULONG rframeNumber = 0;
921 ULONG rframeLength = 0;
925 log->log("Client", Log::DEBUG, "GetIFrame recording called when no recording being played!");
929 success = rp->getNextIFrame(frameNumber, direction, &rfilePosition, &rframeNumber, &rframeLength);
932 // returns file position, frame number, length
934 UCHAR sendBuffer[20];
940 *(ULONG*)&sendBuffer[0] = htonl(16);
941 *(ULLONG*)&sendBuffer[4] = htonll(rfilePosition);
942 *(ULONG*)&sendBuffer[12] = htonl(rframeNumber);
943 *(ULONG*)&sendBuffer[16] = htonl(rframeLength);
948 *(ULONG*)&sendBuffer[0] = htonl(4);
949 *(ULONG*)&sendBuffer[4] = 0;
952 log->log("Client", Log::DEBUG, "%llu %lu %lu", rfilePosition, rframeNumber, rframeLength);
954 tcp.sendPacket(sendBuffer, packetLength);
955 log->log("Client", Log::DEBUG, "Wrote GNIF reply to client");
959 int MVPClient::processGetChannelSchedule(UCHAR* data, int length)
961 ULONG channelNumber = ntohl(*(ULONG*)data);
963 ULONG startTime = ntohl(*(ULONG*)data);
965 ULONG duration = ntohl(*(ULONG*)data);
967 log->log("Client", Log::DEBUG, "get schedule called for channel %lu", channelNumber);
969 cChannel* channel = channelFromNumber(channelNumber);
973 log->log("Client", Log::DEBUG, "written 0 because channel = NULL");
977 log->log("Client", Log::DEBUG, "Got channel");
979 #if VDRVERSNUM < 10300
980 cMutexLock MutexLock;
981 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
983 cSchedulesLock MutexLock;
984 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
989 log->log("Client", Log::DEBUG, "written 0 because Schedule!s! = NULL");
993 log->log("Client", Log::DEBUG, "Got schedule!s! object");
995 const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
999 log->log("Client", Log::DEBUG, "written 0 because Schedule = NULL");
1003 log->log("Client", Log::DEBUG, "Got schedule object");
1005 UCHAR* sendBuffer = (UCHAR*)malloc(100000);
1006 ULONG sendBufferLength = 100000;
1007 ULONG sendBufferUsed = sizeof(ULONG); // leave a hole for the entire packet length
1011 // assign all the event info to temp vars then we know exactly what size they are
1013 ULONG thisEventTime;
1014 ULONG thisEventDuration;
1015 const char* thisEventTitle;
1016 const char* thisEventSubTitle;
1017 const char* thisEventDescription;
1019 ULONG constEventLength = sizeof(thisEventID) + sizeof(thisEventTime) + sizeof(thisEventDuration);
1020 ULONG thisEventLength;
1022 #if VDRVERSNUM < 10300
1024 const cEventInfo *event;
1025 for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1027 event = Schedule->GetEventNumber(eventNumber);
1029 thisEventID = event->GetEventID();
1030 thisEventTime = event->GetTime();
1031 thisEventDuration = event->GetDuration();
1032 thisEventTitle = event->GetTitle();
1033 thisEventSubTitle = event->GetSubtitle();
1034 thisEventDescription = event->GetExtendedDescription();
1038 for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
1040 thisEventID = event->EventID();
1041 thisEventTime = event->StartTime();
1042 thisEventDuration = event->Duration();
1043 thisEventTitle = event->Title();
1044 thisEventSubTitle = NULL;
1045 thisEventDescription = event->Description();
1049 log->log("Client", Log::DEBUG, "Got an event object %p", event);
1051 //in the past filter
1052 if ((thisEventTime + thisEventDuration) < (ULONG)time(NULL)) continue;
1055 if ((thisEventTime + thisEventDuration) <= startTime) continue;
1058 if (thisEventTime >= (startTime + duration)) continue;
1060 if (!thisEventTitle) thisEventTitle = empty;
1061 if (!thisEventSubTitle) thisEventSubTitle = empty;
1062 if (!thisEventDescription) thisEventDescription = empty;
1064 thisEventLength = constEventLength + strlen(thisEventTitle) + 1 + strlen(thisEventSubTitle) + 1 + strlen(thisEventDescription) + 1;
1066 log->log("Client", Log::DEBUG, "Done s1");
1068 // now extend the buffer if necessary
1069 if ((sendBufferUsed + thisEventLength) > sendBufferLength)
1071 log->log("Client", Log::DEBUG, "Extending buffer");
1072 sendBufferLength += 100000;
1073 UCHAR* temp = (UCHAR*)realloc(sendBuffer, sendBufferLength);
1077 UCHAR sendBuffer2[8];
1078 *(ULONG*)&sendBuffer2[0] = htonl(4);
1079 *(ULONG*)&sendBuffer2[4] = htonl(0);
1080 tcp.sendPacket(sendBuffer2, 8);
1081 log->log("Client", Log::DEBUG, "written 0 because failed to realloc packet");
1087 log->log("Client", Log::DEBUG, "Done s2");
1089 *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventID); sendBufferUsed += sizeof(ULONG);
1090 *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventTime); sendBufferUsed += sizeof(ULONG);
1091 *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventDuration); sendBufferUsed += sizeof(ULONG);
1093 strcpy((char*)&sendBuffer[sendBufferUsed], thisEventTitle); sendBufferUsed += strlen(thisEventTitle) + 1;
1094 strcpy((char*)&sendBuffer[sendBufferUsed], thisEventSubTitle); sendBufferUsed += strlen(thisEventSubTitle) + 1;
1095 strcpy((char*)&sendBuffer[sendBufferUsed], thisEventDescription); sendBufferUsed += strlen(thisEventDescription) + 1;
1097 log->log("Client", Log::DEBUG, "Done s3 %lu", sendBufferUsed);
1100 log->log("Client", Log::DEBUG, "Got all event data");
1102 if (sendBufferUsed == sizeof(ULONG))
1106 log->log("Client", Log::DEBUG, "Written 0 because no data");
1110 // Write the length into the first 4 bytes. It's sendBufferUsed - 4 because of the hole!
1111 *(ULONG*)&sendBuffer[0] = htonl(sendBufferUsed - sizeof(ULONG));
1112 tcp.sendPacket(sendBuffer, sendBufferUsed);
1113 log->log("Client", Log::DEBUG, "written %lu schedules packet", sendBufferUsed);
1121 int MVPClient::processConfigSave(UCHAR* buffer, int length)
1123 char* section = (char*)buffer;
1127 for (int k = 0; k < length; k++)
1129 if (buffer[k] == '\0')
1133 key = (char*)&buffer[k+1];
1137 value = (char*)&buffer[k+1];
1143 // if the last string (value) doesnt have null terminator, give up
1144 if (buffer[length - 1] != '\0') return 0;
1146 log->log("Client", Log::DEBUG, "Config save: %s %s %s", section, key, value);
1147 if (config.setValueString(section, key, value))
1159 int MVPClient::processConfigLoad(UCHAR* buffer, int length)
1161 char* section = (char*)buffer;
1164 for (int k = 0; k < length; k++)
1166 if (buffer[k] == '\0')
1168 key = (char*)&buffer[k+1];
1173 char* value = config.getValueString(section, key);
1177 UCHAR sendBuffer[4 + strlen(value) + 1];
1178 *(ULONG*)&sendBuffer[0] = htonl(strlen(value) + 1);
1179 strcpy((char*)&sendBuffer[4], value);
1180 tcp.sendPacket(sendBuffer, 4 + strlen(value) + 1);
1182 log->log("Client", Log::DEBUG, "Written config load packet");
1187 UCHAR sendBuffer[8];
1188 *(ULONG*)&sendBuffer[0] = htonl(4);
1189 *(ULONG*)&sendBuffer[4] = htonl(0);
1190 tcp.sendPacket(sendBuffer, 8);
1192 log->log("Client", Log::DEBUG, "Written config load failed packet");
1198 void MVPClient::cleanConfig()
1200 log->log("Client", Log::DEBUG, "Clean config");
1202 cRecordings Recordings;
1207 char* resumes = config.getSectionKeyNames("ResumeData", numReturns, length);
1208 char* position = resumes;
1209 for(int k = 0; k < numReturns; k++)
1211 log->log("Client", Log::DEBUG, "EXAMINING: %i %i %p %s", k, numReturns, position, position);
1213 cRecording* recording = Recordings.GetByName(position);
1216 // doesn't exist anymore
1217 log->log("Client", Log::DEBUG, "Found a recording that doesn't exist anymore");
1218 config.deleteValue("ResumeData", position);
1222 log->log("Client", Log::DEBUG, "This recording still exists");
1225 position += strlen(position) + 1;
1237 event = Schedule->GetPresentEvent();
1239 fprintf(f, "\n\nCurrent event\n\n");
1241 fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", 0, event->GetEventID(), event->GetTime(), event->GetDuration());
1242 fprintf(f, "Event %i title = %s subtitle = %s\n", 0, event->GetTitle(), event->GetSubtitle());
1243 fprintf(f, "Event %i extendeddescription = %s\n", 0, event->GetExtendedDescription());
1244 fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", 0, event->IsFollowing(), event->IsPresent());
1246 event = Schedule->GetFollowingEvent();
1248 fprintf(f, "\n\nFollowing event\n\n");
1250 fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", 0, event->GetEventID(), event->GetTime(), event->GetDuration());
1251 fprintf(f, "Event %i title = %s subtitle = %s\n", 0, event->GetTitle(), event->GetSubtitle());
1252 fprintf(f, "Event %i extendeddescription = %s\n", 0, event->GetExtendedDescription());
1253 fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", 0, event->IsFollowing(), event->IsPresent());
1259 fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", eventNumber, event->GetEventID(), event->GetTime(), event->GetDuration());
1260 fprintf(f, "Event %i title = %s subtitle = %s\n", eventNumber, event->GetTitle(), event->GetSubtitle());
1261 fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
1262 fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", eventNumber, event->IsFollowing(), event->IsPresent());
1270 void MVPClient::test2()
1272 FILE* f = fopen("/tmp/s.txt", "w");
1274 #if VDRVERSNUM < 10300
1275 cMutexLock MutexLock;
1276 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1278 cSchedulesLock MutexLock;
1279 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
1284 fprintf(f, "Schedules = NULL\n");
1289 fprintf(f, "Schedules dump:\n");
1293 const cSchedule *Schedule;
1294 int scheduleNumber = 0;
1297 cChannel *thisChannel;
1299 #if VDRVERSNUM < 10300
1300 const cEventInfo *event;
1301 int eventNumber = 0;
1303 const cEvent *event;
1306 // Schedule = Schedules->GetSchedule(channel->GetChannelID());
1307 // Schedule = Schedules->GetSchedule();
1308 Schedule = Schedules->First();
1311 fprintf(f, "First Schedule = NULL\n");
1318 fprintf(f, "Schedule #%i\n", scheduleNumber);
1319 fprintf(f, "-------------\n\n");
1321 #if VDRVERSNUM < 10300
1322 tchid = Schedule->GetChannelID();
1324 tchid = Schedule->ChannelID();
1327 #if VDRVERSNUM < 10300
1328 fprintf(f, "ChannelID.ToString() = %s\n", tchid.ToString());
1329 fprintf(f, "NumEvents() = %i\n", Schedule->NumEvents());
1331 // put the count at the end.
1334 thisChannel = Channels.GetByChannelID(tchid, true);
1337 fprintf(f, "Channel Number: %p %i\n", thisChannel, thisChannel->Number());
1341 fprintf(f, "thisChannel = NULL for tchid\n");
1344 #if VDRVERSNUM < 10300
1345 for (eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1347 event = Schedule->GetEventNumber(eventNumber);
1348 fprintf(f, "Event %i tableid = %i timestring = %s endtimestring = %s\n", eventNumber, event->GetTableID(), event->GetTimeString(), event->GetEndTimeString());
1349 fprintf(f, "Event %i date = %s isfollowing = %i ispresent = %i\n", eventNumber, event->GetDate(), event->IsFollowing(), event->IsPresent());
1350 fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
1351 fprintf(f, "Event %i subtitle = %s title = %s\n", eventNumber, event->GetSubtitle(), event->GetTitle());
1352 fprintf(f, "Event %i eventid = %u duration = %li time = %lu channelnumber = %i\n", eventNumber, event->GetEventID(), event->GetDuration(), event->GetTime(), event->GetChannelNumber());
1353 fprintf(f, "Event %u dump:\n", eventNumber);
1358 // This whole section needs rewriting to walk the list.
1359 event = Schedule->Events()->First();
1361 event = Schedule->Events()->Next(event);
1366 fprintf(f, "\nDump from object:\n");
1368 fprintf(f, "\nEND\n");
1378 fprintf(f, "End of current Schedule\n\n\n");
1380 Schedule = (const cSchedule *)Schedules->Next(Schedule);
1394 const cEventInfo *GetPresentEvent(void) const;
1395 const cEventInfo *GetFollowingEvent(void) const;
1396 const cEventInfo *GetEvent(unsigned short uEventID, time_t tTime = 0) const;
1397 const cEventInfo *GetEventAround(time_t tTime) const;
1398 const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); }
1401 const unsigned char GetTableID(void) const;
1402 const char *GetTimeString(void) const;
1403 const char *GetEndTimeString(void) const;
1404 const char *GetDate(void) const;
1405 bool IsFollowing(void) const;
1406 bool IsPresent(void) const;
1407 const char *GetExtendedDescription(void) const;
1408 const char *GetSubtitle(void) const;
1409 const char *GetTitle(void) const;
1410 unsigned short GetEventID(void) const;
1411 long GetDuration(void) const;
1412 time_t GetTime(void) const;
1413 tChannelID GetChannelID(void) const;
1414 int GetChannelNumber(void) const { return nChannelNumber; }
1415 void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const'
1416 void Dump(FILE *f, const char *Prefix = "") const;
1422 void MVPClient::test(int channelNumber)
1424 FILE* f = fopen("/tmp/test.txt", "w");
1426 cMutexLock MutexLock;
1427 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1431 fprintf(f, "Schedules = NULL\n");
1436 fprintf(f, "Schedules dump:\n");
1437 // Schedules->Dump(f);
1439 const cSchedule *Schedule;
1440 cChannel *thisChannel;
1441 const cEventInfo *event;
1443 thisChannel = channelFromNumber(channelNumber);
1446 fprintf(f, "thisChannel = NULL\n");
1451 Schedule = Schedules->GetSchedule(thisChannel->GetChannelID());
1452 // Schedule = Schedules->GetSchedule();
1453 // Schedule = Schedules->First();
1456 fprintf(f, "First Schedule = NULL\n");
1461 fprintf(f, "NumEvents() = %i\n\n", Schedule->NumEvents());
1463 // For some channels VDR seems to pick a random point in time to
1464 // start dishing out events, but they are in order
1465 // at some point in the list the time snaps to the current event
1470 for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1472 event = Schedule->GetEventNumber(eventNumber);
1473 fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", eventNumber, event->GetEventID(), event->GetTime(), event->GetDuration());
1474 fprintf(f, "Event %i title = %s subtitle = %s\n", eventNumber, event->GetTitle(), event->GetSubtitle());
1475 fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
1479 fprintf(f, "\nEND\n");
1493 Schedules = the collection of all the Schedule objects
1494 Schedule = One schedule, contants all the events for a channel
1495 Event = One programme
1504 Subtitle (used for "Programmes resume at ...")
1507 IsPresent ? easy to work out tho. Oh it doesn't always work
1512 void MVPClient::test2()
1514 log->log("-", Log::DEBUG, "Timers List");
1516 for (int i = 0; i < Timers.Count(); i++)
1518 cTimer *timer = Timers.Get(i);
1519 //Reply(i < Timers.Count() - 1 ? -250 : 250, "%d %s", timer->Index() + 1, timer->ToText());
1520 log->log("-", Log::DEBUG, "i=%i count=%i index=%d", i, Timers.Count(), timer->Index() + 1);
1521 #if VDRVERSNUM < 10300
1522 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());
1524 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());
1526 log->log("-", Log::DEBUG, "channel=%i file=%s summary=%s", timer->Channel()->Number(), timer->File(), timer->Summary());
1527 log->log("-", Log::DEBUG, "");
1530 // asprintf(&buffer, "%d:%s:%s :%04d:%04d:%d:%d:%s:%s\n",
1531 // active, (UseChannelID ? Channel()->GetChannelID().ToString() : itoa(Channel()->Number())),
1532 // PrintDay(day, firstday), start, stop, priority, lifetime, file, summary ? summary : "");
1537 Active seems to be a bool - whether the timer should be done or not. If set to inactive it stays around after its time
1538 recording is a bool, 0 for not currently recording, 1 for currently recording
1539 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
1543 int MVPClient::processGetTimers(UCHAR* buffer, int length)
1545 UCHAR* sendBuffer = new UCHAR[50000]; // FIXME hope this is enough
1546 int count = 4; // leave space for the packet length
1548 const char* fileName;
1550 int numTimers = Timers.Count();
1552 *(ULONG*)&sendBuffer[count] = htonl(numTimers); count += 4;
1554 for (int i = 0; i < numTimers; i++)
1556 if (count > 49000) break;
1558 timer = Timers.Get(i);
1560 #if VDRVERSNUM < 10300
1561 *(ULONG*)&sendBuffer[count] = htonl(timer->Active()); count += 4;
1563 *(ULONG*)&sendBuffer[count] = htonl(timer->HasFlags(tfActive)); count += 4;
1565 *(ULONG*)&sendBuffer[count] = htonl(timer->Recording()); count += 4;
1566 *(ULONG*)&sendBuffer[count] = htonl(timer->Pending()); count += 4;
1567 *(ULONG*)&sendBuffer[count] = htonl(timer->Priority()); count += 4;
1568 *(ULONG*)&sendBuffer[count] = htonl(timer->Lifetime()); count += 4;
1569 *(ULONG*)&sendBuffer[count] = htonl(timer->Channel()->Number()); count += 4;
1570 *(ULONG*)&sendBuffer[count] = htonl(timer->StartTime()); count += 4;
1571 *(ULONG*)&sendBuffer[count] = htonl(timer->StopTime()); count += 4;
1572 *(ULONG*)&sendBuffer[count] = htonl(timer->Day()); count += 4;
1573 *(ULONG*)&sendBuffer[count] = htonl(timer->WeekDays()); count += 4;
1575 fileName = timer->File();
1576 strcpy((char*)&sendBuffer[count], fileName);
1577 count += strlen(fileName) + 1;
1580 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
1582 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
1584 tcp.sendPacket(sendBuffer, count);
1585 delete[] sendBuffer;
1586 log->log("Client", Log::DEBUG, "Written timers list");
1591 int MVPClient::processSetTimer(UCHAR* buffer, int length)
1593 char* timerString = new char[strlen((char*)buffer) + 1];
1594 strcpy(timerString, (char*)buffer);
1596 #if VDRVERSNUM < 10300
1598 // If this is VDR 1.2 the date part of the timer string must be reduced
1599 // to just DD rather than YYYY-MM-DD
1601 int s = 0; // source
1602 int d = 0; // destination
1604 while(c != 2) // copy up to date section, including the second ':'
1606 timerString[d] = buffer[s];
1607 if (buffer[s] == ':') c++;
1611 // now it has copied up to the date section
1613 while(c != 2) // waste YYYY-MM-
1615 if (buffer[s] == '-') c++;
1618 // now source is at the DD
1619 memcpy(&timerString[d], &buffer[s], length - s);
1621 timerString[d] = '\0';
1623 log->log("Client", Log::DEBUG, "Timer string after 1.2 conversion:");
1624 log->log("Client", Log::DEBUG, "%s", timerString);
1628 cTimer *timer = new cTimer;
1629 if (timer->Parse((char*)timerString))
1631 cTimer *t = Timers.GetTimer(timer);
1635 #if VDRVERSNUM < 10300
1638 Timers.SetModified();
1656 void MVPClient::incClients()
1658 pthread_mutex_lock(&threadClientMutex);
1659 MVPClient::nr_clients++;
1660 pthread_mutex_unlock(&threadClientMutex);
1663 void MVPClient::decClients()
1665 pthread_mutex_lock(&threadClientMutex);
1666 MVPClient::nr_clients--;
1667 pthread_mutex_unlock(&threadClientMutex);
1670 int MVPClient::getNrClients()
1673 pthread_mutex_lock(&threadClientMutex);
1674 nrClients = MVPClient::nr_clients;
1675 pthread_mutex_unlock(&threadClientMutex);
1679 int MVPClient::processGetRecInfo(UCHAR* data, int length)
1681 // data is a pointer to the fileName string
1683 cRecordings Recordings;
1684 Recordings.Load(); // probably have to do this
1686 cRecording *recording = Recordings.GetByName((char*)data);
1688 time_t timerStart = 0;
1689 time_t timerStop = 0;
1690 char* summary = NULL;
1691 ULONG resumePoint = 0;
1695 log->log("Client", Log::ERR, "GetRecInfo found no recording");
1700 ULONG sendBufferSize = 10000;
1701 UCHAR* sendBuffer = (UCHAR*)malloc(sendBufferSize);
1702 ULONG pos = 4; // leave first 4 bytes for size field
1706 4 bytes: start time for timer
1707 4 bytes: end time for timer
1708 4 bytes: resume point
1710 4 bytes: num components
1720 // Get current timer
1722 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
1725 timerStart = rc->Timer()->StartTime();
1726 timerStop = rc->Timer()->StopTime();
1727 log->log("Client", Log::DEBUG, "GRI: RC: %lu %lu", timerStart, timerStop);
1730 *(time_t*)&sendBuffer[pos] = htonl(timerStart); pos += 4;
1731 *(time_t*)&sendBuffer[pos] = htonl(timerStop); pos += 4;
1735 char* value = config.getValueString("ResumeData", (char*)data);
1738 resumePoint = strtoul(value, NULL, 10);
1741 log->log("Client", Log::DEBUG, "GRI: RP: %lu", resumePoint);
1743 *(ULONG*)&sendBuffer[pos] = htonl(resumePoint); pos += 4;
1748 #if VDRVERSNUM < 10300
1749 summary = (char*)recording->Summary();
1751 const cRecordingInfo *Info = recording->Info();
1752 summary = (char*)Info->ShortText();
1753 if (isempty(summary)) summary = (char*)Info->Description();
1755 log->log("Client", Log::DEBUG, "GRI: S: %s", summary);
1758 // memory insanity...
1759 if ((sendBufferSize - pos) < (strlen(summary) + 500)) // random
1761 UCHAR* newBuffer = (UCHAR*)realloc(sendBuffer, sendBufferSize + strlen(summary) + 10000);
1764 sendBuffer = newBuffer;
1765 sendBufferSize += strlen(summary) + 10000;
1775 strcpy((char*)&sendBuffer[pos], summary);
1776 pos += strlen(summary) + 1;
1780 strcpy((char*)&sendBuffer[pos], "");
1787 #if VDRVERSNUM < 10300
1789 // Send 0 for numchannels - this signals the client this info is not available
1790 *(ULONG*)&sendBuffer[pos] = 0; pos += 4;
1793 const cComponents* components = Info->Components();
1795 log->log("Client", Log::DEBUG, "GRI: D1: %p", components);
1799 *(ULONG*)&sendBuffer[pos] = htonl(0); pos += 4;
1803 *(ULONG*)&sendBuffer[pos] = htonl(components->NumComponents()); pos += 4;
1805 tComponent* component;
1806 for (int i = 0; i < components->NumComponents(); i++)
1808 component = components->Component(i);
1810 // memory insanity...
1811 ULONG extraNeeded = 2 + (component->language ? strlen(component->language) : 0)
1812 + (component->description ? strlen(component->description) : 0) + 2;
1814 if ((sendBufferSize - pos) < extraNeeded)
1816 UCHAR* newBuffer = (UCHAR*)realloc(sendBuffer, sendBufferSize + extraNeeded + 10000);
1819 sendBuffer = newBuffer;
1820 sendBufferSize += extraNeeded + 10000;
1830 log->log("Client", Log::DEBUG, "GRI: C: %i %u %u %s %s", i, component->stream, component->type, component->language, component->description);
1831 sendBuffer[pos] = component->stream; pos += 1;
1832 sendBuffer[pos] = component->type; pos += 1;
1833 if (component->language)
1835 strcpy((char*)&sendBuffer[pos], component->language);
1836 pos += strlen(component->language) + 1;
1840 strcpy((char*)&sendBuffer[pos], "");
1843 if (component->description)
1845 strcpy((char*)&sendBuffer[pos], component->description);
1846 pos += strlen(component->description) + 1;
1850 strcpy((char*)&sendBuffer[pos], "");
1861 *(ULONG*)&sendBuffer[0] = htonl(pos - 4); // -4 : take off the size field
1863 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
1865 tcp.sendPacket(sendBuffer, pos);
1866 delete[] sendBuffer;
1867 log->log("Client", Log::DEBUG, "Written getrecinfo");
1877 int MVPClient::processReScanRecording(UCHAR* data, int length)
1881 log->log("Client", Log::DEBUG, "Rescan recording called when no recording being played!");
1887 UCHAR sendBuffer[16];
1888 *(ULONG*)&sendBuffer[0] = htonl(12);
1889 *(ULLONG*)&sendBuffer[4] = htonll(rp->getLengthBytes());
1890 *(ULONG*)&sendBuffer[12] = htonl(rp->getLengthFrames());
1892 tcp.sendPacket(sendBuffer, 16);
1893 log->log("Client", Log::DEBUG, "Rescan recording, wrote new length to client");
1897 // FIXME without client calling rescan, getblock wont work even tho more data is avail
1900 int MVPClient::processGetMarks(UCHAR* data, int length)
1902 // data is a pointer to the fileName string
1904 UCHAR* sendBuffer = new UCHAR[50000]; // FIXME hope this is enough
1905 int count = 4; // leave space for the packet length
1909 cRecordings Recordings;
1910 Recordings.Load(); // probably have to do this
1912 cRecording *recording = Recordings.GetByName((char*)data);
1914 log->log("Client", Log::DEBUG, "recording pointer %p", recording);
1918 Marks.Load(recording->FileName());
1921 for (const cMark *m = Marks.First(); m; m = Marks.Next(m))
1923 log->log("Client", Log::DEBUG, "found Mark %i", m->position);
1925 if (count > 49000) break;
1926 *(ULONG*)&sendBuffer[count] = htonl(m->position);
1932 log->log("Client", Log::DEBUG, "no marks found, sending 0-mark");
1933 *(ULONG*)&sendBuffer[count] = htonl(0);
1938 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
1940 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
1942 tcp.sendPacket(sendBuffer, count);
1943 delete[] sendBuffer;
1944 log->log("Client", Log::DEBUG, "Written Marks list");
1951 * media List Request:
1953 * 4 VDR_GETMEDIALIST
1954 * 4 flags (currently unused)
1957 * Media List response:
1965 * 4 strlen (incl. 0 Byte)
1969 #define MLISTBUF 500000
1970 int MVPClient::processGetMediaList(UCHAR* data, int length)
1973 log->log("Client", Log::ERR, "getMediaList packet too short %d", length);
1976 char * dirname=NULL;
1978 //we have a dirname provided
1979 dirname=(char *)&data[4];
1980 log->log("Client", Log::DEBUG, "getMediaList for %s", dirname);
1984 UCHAR* sendBuffer = new UCHAR[MLISTBUF]; // FIXME hope this is enough
1985 int count = 4; // leave space for the header
1987 MediaList * ml=MediaList::readList(baseConfig,dirname);
1989 log->log("Client", Log::ERR, "getMediaList returned NULL");
1992 //response code (not yet set)
1993 *(ULONG*)&sendBuffer[count] = htonl(0);
1996 *(ULONG*)&sendBuffer[count] = htonl(ml->Count());
1998 for (int nm=0;nm<ml->Count() && count < (MLISTBUF-1000);nm++) {
1999 Media *m=ml->Get(nm);
2000 log->log("Client", Log::DEBUG, "found media entry %s, type=%d",m->getFilename(),m->getType());
2001 *(ULONG*)&sendBuffer[count] = htonl(m->getType());
2004 *(ULONG*)&sendBuffer[count] = htonl(m->getTime());
2007 *(ULONG*)&sendBuffer[count] = htonl(0);
2009 int len=strlen(m->getFilename());
2011 *(ULONG*)&sendBuffer[count] = htonl(len+1);
2013 //should have a check for strlen > 1000...
2014 strcpy((char *)&sendBuffer[count],m->getFilename());
2019 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
2021 log->log("Client", Log::DEBUG, "getMediaList size %u", ntohl(*(ULONG*)&sendBuffer[0]));
2023 tcp.sendPacket(sendBuffer, count);
2024 delete[] sendBuffer;
2025 log->log("Client", Log::DEBUG, "Written Media list");
2031 * get image Request:
2034 * 4 flags (currently unused)
2039 * get image response:
2044 #define MLISTBUF 500000
2045 int MVPClient::processGetPicture(UCHAR* data, int length)
2048 log->log("Client", Log::ERR, "getPicture packet too short %d", length);
2055 char * filename=NULL;
2057 //we have a dirname provided
2058 filename=(char *)&data[4];
2059 log->log("Client", Log::DEBUG, "getPicture %s", filename);
2062 log->log("Client", Log::ERR, "getPicture empty filename");
2065 imageFile=fopen(filename,"r");
2066 if (!imageFile) log->log("Client", Log::ERR, "getPicture unable to open %s",filename);
2071 if ( fstat(fileno(imageFile),&st) == 0) size=st.st_size;
2073 UCHAR* sendBuffer = new UCHAR[12];
2074 int count = 4; // leave space for the header
2075 //response code (not yet set)
2076 *(ULONG*)&sendBuffer[count] = htonl(31);
2079 *(ULONG*)&sendBuffer[count] = htonl(size);
2081 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
2082 log->log("Client", Log::DEBUG, "getPicture size %u", size);
2084 tcp.sendPacket(sendBuffer, count);
2085 delete[] sendBuffer;
2086 log->log("Client", Log::DEBUG, "Written Media list");
2092 int MVPClient::processGetImageBlock(UCHAR* data, int length)
2096 log->log("Client", Log::DEBUG, "Get image block called when no image active");
2100 ULLONG position = ntohll(*(ULLONG*)data);
2101 data += sizeof(ULLONG);
2102 ULONG amount = ntohl(*(ULONG*)data);
2104 log->log("Client", Log::DEBUG, "getImageblock pos = %llu length = %lu", position, amount);
2106 UCHAR sendBuffer[amount + 4];
2107 ULONG amountReceived = 0; // compiler moan.
2108 ULLONG cpos=ftell(imageFile);
2109 if (position != cpos) {
2110 fseek(imageFile,position-cpos,SEEK_CUR);
2112 if (position != (ULLONG)ftell(imageFile)) {
2113 log->log("Client", Log::DEBUG, "getImageblock pos = %llu not available", position);
2116 amountReceived=fread(&sendBuffer[4],1,amount,imageFile);
2119 if (!amountReceived)
2122 log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0");
2126 *(ULONG*)&sendBuffer[0] = htonl(amountReceived);
2127 tcp.sendPacket(sendBuffer, amountReceived + 4);
2128 log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
2134 int MVPClient::processDeleteTimer(UCHAR* buffer, int length)
2136 log->log("Client", Log::DEBUG, "Delete timer called");
2141 INT delChannel = ntohl(*(ULONG*)&buffer[position]); position += 4;
2142 INT delWeekdays = ntohl(*(ULONG*)&buffer[position]); position += 4;
2143 INT delDay = ntohl(*(ULONG*)&buffer[position]); position += 4;
2144 ULONG delStart = ntohl(*(ULONG*)&buffer[position]); position += 4;
2145 ULONG delStop = ntohl(*(ULONG*)&buffer[position]); position += 4;
2148 for (ti = Timers.First(); ti; ti = Timers.Next(ti))
2150 if ( (ti->Channel()->Number() == delChannel)
2151 && ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
2152 && (ti->StartTime() == delStart)
2153 && (ti->StopTime() == delStop) )
2163 if (!Timers.BeingEdited())
2165 if (!ti->Recording())
2168 Timers.SetModified();
2174 log->log("Client", Log::ERR, "Unable to delete timer - timer is running");
2181 log->log("Client", Log::ERR, "Unable to delete timer - timers being edited at VDR");