2 Copyright 2008 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #ifndef VOMPSTANDALONE
24 #include <vdr/recording.h>
25 #include <vdr/channels.h>
26 #include <vdr/videodir.h>
27 #include <vdr/plugin.h>
28 #include <vdr/timers.h>
30 #include "recplayer.h"
31 #include "mvpreceiver.h"
34 #include "vompclientrrproc.h"
35 #include "vompclient.h"
40 VompClientRRProc::VompClientRRProc(VompClient& x)
43 log = Log::getInstance();
48 bool VompClientRRProc::init()
53 bool VompClientRRProc::recvRequest(RequestPacket* newRequest)
57 Currently only one at once is supported but this
58 could be upgraded to a queueing system
65 log->log("RRProc", Log::ERR, "recvReq err 1");
73 log->log("RRProc", Log::DEBUG, "recvReq set req and signalled");
79 void VompClientRRProc::threadMethod()
82 log->log("RRProc", Log::DEBUG, "threadMethod startup");
88 log->log("RRProc", Log::ERR, "threadMethod err 1");
93 log->log("RRProc", Log::DEBUG, "threadMethod waiting");
94 threadWaitForSignal();
97 log->log("RRProc", Log::ERR, "threadMethod err 2");
102 log->log("RRProc", Log::DEBUG, "thread woken with req");
108 bool VompClientRRProc::processPacket()
110 resp = new ResponsePacket();
111 if (!resp->init(req->requestID))
113 log->log("RRProc", Log::ERR, "response packet init fail");
123 result = processLogin();
125 #ifndef VOMPSTANDALONE
127 result = processGetRecordingsList();
130 result = processDeleteRecording();
133 result = processGetChannelsList();
136 result = processStartStreamingChannel();
139 result = processGetBlock();
142 result = processStopStreaming();
145 result = processStartStreamingRecording();
149 result = processGetChannelSchedule();
152 result = processConfigSave();
155 result = processConfigLoad();
157 #ifndef VOMPSTANDALONE
159 result = processReScanRecording(); // FIXME obselete
162 result = processGetTimers();
165 result = processSetTimer();
168 result = processPositionFromFrameNumber();
171 result = processFrameNumberFromPosition();
174 result = processMoveRecording();
177 result = processGetIFrame();
180 result = processGetRecInfo();
183 result = processGetMarks();
186 result = processGetChannelPids();
189 result = processDeleteTimer();
193 result = processGetMediaList();
196 result = processGetPicture();
199 result = processGetImageBlock();
202 result = processGetLanguageList();
205 result = processGetLanguageContent();
212 if (req->data) free(req->data);
216 if (result) return true;
220 int VompClientRRProc::processLogin()
222 if (req->dataLength != 6) return 0;
226 char configFileName[PATH_MAX];
227 snprintf(configFileName, PATH_MAX, "%s/vomp-%02X-%02X-%02X-%02X-%02X-%02X.conf", x.configDir, req->data[0], req->data[1], req->data[2], req->data[3], req->data[4], req->data[5]);
228 x.config.init(configFileName);
230 // Send the login reply
232 time_t timeNow = time(NULL);
233 struct tm* timeStruct = localtime(&timeNow);
234 int timeOffset = timeStruct->tm_gmtoff;
236 resp->addULONG(timeNow);
237 resp->addLONG(timeOffset);
239 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
240 log->log("RRProc", Log::DEBUG, "written login reply len %lu", resp->getLen());
246 int VompClientRRProc::processConfigSave()
248 char* section = (char*)req->data;
252 for (UINT k = 0; k < req->dataLength; k++)
254 if (req->data[k] == '\0')
258 key = (char*)&req->data[k+1];
262 value = (char*)&req->data[k+1];
268 // if the last string (value) doesnt have null terminator, give up
269 if (req->data[req->dataLength - 1] != '\0') return 0;
271 log->log("RRProc", Log::DEBUG, "Config save: %s %s %s", section, key, value);
272 if (x.config.setValueString(section, key, value))
282 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
287 int VompClientRRProc::processConfigLoad()
289 char* section = (char*)req->data;
292 for (UINT k = 0; k < req->dataLength; k++)
294 if (req->data[k] == '\0')
296 key = (char*)&req->data[k+1];
301 char* value = x.config.getValueString(section, key);
305 resp->addString(value);
306 log->log("RRProc", Log::DEBUG, "Written config load packet");
312 log->log("RRProc", Log::DEBUG, "Written config load failed packet");
316 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
322 * media List Request:
325 * 4 flags (currently unused)
328 * Media List response:
336 * 4 strlen (incl. 0 Byte)
341 int VompClientRRProc::processGetMediaList()
343 if (req->dataLength < 4) {
344 log->log("RRProc", Log::ERR, "getMediaList packet too short %d", req->dataLength);
348 if (req->dataLength > 4) {
349 //we have a dirname provided
350 dirname=(char *)&req->data[4];
351 log->log("RRProc", Log::DEBUG, "getMediaList for %s", dirname);
354 MediaList * ml=MediaList::readList(x.baseConfig, dirname);
356 log->log("RRProc", Log::ERR, "getMediaList returned NULL");
360 //response code (not yet set)
364 resp->addULONG(ml->size());
366 for (MediaList::iterator nm=ml->begin(); nm<ml->end(); nm++)
369 log->log("RRProc", Log::DEBUG, "found media entry %s, type=%d",m->getFilename(),m->getType());
370 resp->addULONG(m->getType());
372 resp->addULONG(m->getTime());
375 int len=strlen(m->getFilename());
377 resp->addULONG(len+1);
378 resp->addString(m->getFilename());
383 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
385 log->log("RRProc", Log::DEBUG, "Written Media list");
391 * 4 flags (currently unused)
396 * get image response:
402 int VompClientRRProc::processGetPicture()
404 if (req->dataLength < 12) {
405 log->log("RRProc", Log::ERR, "getPicture packet too short %d", req->dataLength);
412 char * filename=NULL;
413 if (req->dataLength > 12) {
414 //we have a dirname provided
415 filename=(char *)&req->data[12];
416 log->log("RRProc", Log::DEBUG, "getPicture %s", filename);
419 log->log("RRProc", Log::ERR, "getPicture empty filename");
422 x.imageFile=fopen(filename,"r");
423 if (!x.imageFile) log->log("RRProc", Log::ERR, "getPicture unable to open %s",filename);
428 if ( fstat(fileno(x.imageFile),&st) == 0) size=st.st_size;
430 //response code (not yet set)
433 resp->addULONG(size);
435 log->log("RRProc", Log::DEBUG, "getPicture size %u", size);
438 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
440 log->log("RRProc", Log::DEBUG, "Written getPicture");
446 int VompClientRRProc::processGetImageBlock()
450 log->log("RRProc", Log::DEBUG, "Get image block called when no image active");
454 UCHAR* data = req->data;
456 ULLONG position = x.ntohll(*(ULLONG*)data);
457 data += sizeof(ULLONG);
458 ULONG amount = ntohl(*(ULONG*)data);
460 log->log("RRProc", Log::DEBUG, "getImageblock pos = %llu length = %lu", position, amount);
462 UCHAR sendBuffer[amount];
463 ULONG amountReceived = 0; // compiler moan.
464 ULLONG cpos=ftell(x.imageFile);
465 if (position != cpos) {
466 fseek(x.imageFile,position-cpos,SEEK_CUR);
468 if (position != (ULLONG)ftell(x.imageFile)) {
469 log->log("RRProc", Log::DEBUG, "getImageblock pos = %llu not available", position);
472 amountReceived=fread(&sendBuffer[0],1,amount,x.imageFile);
478 log->log("RRProc", Log::DEBUG, "written 4(0) as getblock got 0");
482 resp->copyin(sendBuffer, amount);
483 log->log("RRProc", Log::DEBUG, "written %lu", amountReceived);
487 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
493 int VompClientRRProc::processGetLanguageList()
495 x.i18n.findLanguages();
496 const I18n::lang_code_list& languages = x.i18n.getLanguageList();
498 I18n::lang_code_list::const_iterator iter;
499 for (iter = languages.begin(); iter != languages.end(); ++iter)
501 resp->addString(iter->first.c_str());
502 resp->addString(iter->second.c_str());
505 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
509 int VompClientRRProc::processGetLanguageContent()
511 if (req->dataLength <= 0) return 0;
512 std::string code, result;
513 code.assign((char*)req->data, req->dataLength - 1);
514 x.i18n.findLanguages();
515 I18n::trans_table texts = x.i18n.getLanguageContent(code);
516 I18n::trans_table::const_iterator iter;
517 for (iter = texts.begin(); iter != texts.end(); ++iter)
519 resp->addString(iter->first.c_str());
520 resp->addString(iter->second.c_str());
523 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
527 #ifndef VOMPSTANDALONE
529 int VompClientRRProc::processGetRecordingsList()
531 log->log("RRProc", Log::DEBUG, "Test sleep start");
533 log->log("RRProc", Log::DEBUG, "Test sleep end");
536 int Percent = VideoDiskSpace(&FreeMB);
537 int Total = (FreeMB / (100 - Percent)) * 100;
539 resp->addULONG(Total);
540 resp->addULONG(FreeMB);
541 resp->addULONG(Percent);
543 cRecordings Recordings;
546 for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
548 resp->addULONG(recording->start);
549 resp->addString(recording->Name());
550 resp->addString(recording->FileName());
554 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
556 log->log("RRProc", Log::DEBUG, "Written recordings list");
561 int VompClientRRProc::processDeleteRecording()
563 // data is a pointer to the fileName string
565 cRecordings Recordings;
566 Recordings.Load(); // probably have to do this
568 cRecording* recording = Recordings.GetByName((char*)req->data);
570 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
574 log->log("RRProc", Log::DEBUG, "deleting recording: %s", recording->Name());
576 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
579 if (recording->Delete())
581 // Copy svdrp's way of doing this, see if it works
582 #if VDRVERSNUM > 10300
583 ::Recordings.DelByName(recording->FileName());
603 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
608 int VompClientRRProc::processMoveRecording()
610 log->log("RRProc", Log::DEBUG, "Process move recording");
611 char* fileName = (char*)req->data;
612 char* newPath = NULL;
614 for (UINT k = 0; k < req->dataLength; k++)
616 if (req->data[k] == '\0')
618 newPath = (char*)&req->data[k+1];
622 if (!newPath) return 0;
624 cRecordings Recordings;
625 Recordings.Load(); // probably have to do this
627 cRecording* recording = Recordings.GetByName((char*)fileName);
629 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
633 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
636 log->log("RRProc", Log::DEBUG, "moving recording: %s", recording->Name());
637 log->log("RRProc", Log::DEBUG, "moving recording: %s", recording->FileName());
638 log->log("RRProc", Log::DEBUG, "to: %s", newPath);
640 const char* t = recording->FileName();
642 char* dateDirName = NULL; int k;
643 char* titleDirName = NULL; int j;
645 // Find the datedirname
646 for(k = strlen(t) - 1; k >= 0; k--)
650 log->log("RRProc", Log::DEBUG, "l1: %i", strlen(&t[k+1]) + 1);
651 dateDirName = new char[strlen(&t[k+1]) + 1];
652 strcpy(dateDirName, &t[k+1]);
657 // Find the titledirname
659 for(j = k-1; j >= 0; j--)
663 log->log("RRProc", Log::DEBUG, "l2: %i", (k - j - 1) + 1);
664 titleDirName = new char[(k - j - 1) + 1];
665 memcpy(titleDirName, &t[j+1], k - j - 1);
666 titleDirName[k - j - 1] = '\0';
671 log->log("RRProc", Log::DEBUG, "datedirname: %s", dateDirName);
672 log->log("RRProc", Log::DEBUG, "titledirname: %s", titleDirName);
673 log->log("RRProc", Log::DEBUG, "viddir: %s", VideoDirectory);
675 char* newPathConv = new char[strlen(newPath)+1];
676 strcpy(newPathConv, newPath);
677 ExchangeChars(newPathConv, true);
678 log->log("RRProc", Log::DEBUG, "EC: %s", newPathConv);
680 char* newContainer = new char[strlen(VideoDirectory) + strlen(newPathConv) + strlen(titleDirName) + 1];
681 log->log("RRProc", Log::DEBUG, "l10: %i", strlen(VideoDirectory) + strlen(newPathConv) + strlen(titleDirName) + 1);
682 sprintf(newContainer, "%s%s%s", VideoDirectory, newPathConv, titleDirName);
683 delete[] newPathConv;
685 log->log("RRProc", Log::DEBUG, "%s", newContainer);
688 int statret = stat(newContainer, &dstat);
689 if ((statret == -1) && (errno == ENOENT)) // Dir does not exist
691 log->log("RRProc", Log::DEBUG, "new dir does not exist");
692 int mkdirret = mkdir(newContainer, 0755);
695 delete[] dateDirName;
696 delete[] titleDirName;
697 delete[] newContainer;
701 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
705 else if ((statret == 0) && (! (dstat.st_mode && S_IFDIR))) // Something exists but it's not a dir
707 delete[] dateDirName;
708 delete[] titleDirName;
709 delete[] newContainer;
713 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
717 // Ok, the directory container has been made, or it pre-existed.
719 char* newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1];
720 sprintf(newDir, "%s/%s", newContainer, dateDirName);
722 log->log("RRProc", Log::DEBUG, "doing rename '%s' '%s'", t, newDir);
723 int renameret = rename(t, newDir);
726 // Success. Test for remove old dir containter
727 char* oldTitleDir = new char[k+1];
728 memcpy(oldTitleDir, t, k);
729 oldTitleDir[k] = '\0';
730 log->log("RRProc", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(oldTitleDir), oldTitleDir);
731 rmdir(oldTitleDir); // can't do anything about a fail result at this point.
732 delete[] oldTitleDir;
737 #if VDRVERSNUM > 10311
739 ::Recordings.Update();
741 // Success. Send a different packet from just a ulong
742 resp->addULONG(1); // success
743 resp->addString(newDir);
751 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
753 delete[] dateDirName;
754 delete[] titleDirName;
755 delete[] newContainer;
762 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
769 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
775 int VompClientRRProc::processGetChannelsList()
779 char* chanConfig = x.config.getValueString("General", "Channels");
781 if (chanConfig) allChans = strcasecmp(chanConfig, "FTA only");
783 for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
785 #if VDRVERSNUM < 10300
786 if (!channel->GroupSep() && (!channel->Ca() || allChans))
788 if (!channel->GroupSep() && (!channel->Ca(0) || allChans))
791 log->log("RRProc", Log::DEBUG, "name: '%s'", channel->Name());
793 if (channel->Vpid()) type = 1;
794 #if VDRVERSNUM < 10300
797 else if (channel->Apid(0)) type = 2;
801 resp->addULONG(channel->Number());
802 resp->addULONG(type);
803 resp->addString(channel->Name());
808 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
810 log->log("RRProc", Log::DEBUG, "Written channels list");
815 int VompClientRRProc::processGetChannelPids()
817 ULONG channelNumber = ntohl(*(ULONG*)req->data);
819 cChannel* channel = x.channelFromNumber(channelNumber);
824 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
833 #if VDRVERSNUM < 10300
835 log->log("RRProc", Log::DEBUG, "Apid1: %i", channel->Apid1());
836 log->log("RRProc", Log::DEBUG, "Apid2: %i", channel->Apid2());
838 if (channel->Apid2())
840 else if (channel->Apid1())
847 for (const int *Apid = channel->Apids(); *Apid; Apid++)
851 for (const int *Dpid = channel->Dpids(); *Dpid; Dpid++)
855 for (const int *Spid = channel->Spids(); *Spid; Spid++)
862 // Format of response
881 resp->addULONG(channel->Vpid());
882 resp->addULONG(numApids);
884 #if VDRVERSNUM < 10300
887 resp->addULONG(channel->Apid1());
892 resp->addULONG(channel->Apid2());
898 for (ULONG i = 0; i < numApids; i++)
900 resp->addULONG(channel->Apid(i));
901 resp->addString(channel->Alang(i));
903 resp->addULONG(numDpids);
904 for (ULONG i = 0; i < numDpids; i++)
906 resp->addULONG(channel->Dpid(i));
907 resp->addString(channel->Dlang(i));
909 resp->addULONG(numSpids);
910 for (ULONG i = 0; i < numSpids; i++)
912 resp->addULONG(channel->Spid(i));
913 resp->addString(channel->Slang(i));
916 resp->addULONG(channel->Tpid());
920 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
922 log->log("RRProc", Log::DEBUG, "Written channels pids");
927 int VompClientRRProc::processStartStreamingChannel()
931 log->log("RRProc", Log::ERR, "Client called start streaming twice");
935 log->log("RRProc", Log::DEBUG, "req->dataLength = %i", req->dataLength);
936 ULONG channelNumber = ntohl(*(ULONG*)req->data);
938 cChannel* channel = x.channelFromNumber(channelNumber);
943 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
947 // get the priority we should use
949 int priority = x.config.getValueLong("General", "Live priority", &fail);
952 log->log("RRProc", Log::DEBUG, "Config: Live TV priority: %i", priority);
956 log->log("RRProc", Log::DEBUG, "Config: Live TV priority config fail");
961 if (priority < 0) priority = 0;
962 if (priority > 99) priority = 99;
964 log->log("RRProc", Log::DEBUG, "Using live TV priority %i", priority);
965 x.lp = MVPReceiver::create(channel, priority);
971 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
975 if (!x.lp->init(&x.tcp, req->requestID))
981 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
987 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
991 int VompClientRRProc::processStopStreaming()
993 log->log("RRProc", Log::DEBUG, "STOP STREAMING RECEIVED");
999 else if (x.recplayer)
1001 x.writeResumeData();
1004 delete x.recordingManager;
1006 x.recordingManager = NULL;
1011 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1015 int VompClientRRProc::processGetBlock()
1017 if (!x.lp && !x.recplayer)
1019 log->log("RRProc", Log::DEBUG, "Get block called when no streaming happening!");
1023 UCHAR* data = req->data;
1025 ULLONG position = x.ntohll(*(ULLONG*)data);
1026 data += sizeof(ULLONG);
1027 ULONG amount = ntohl(*(ULONG*)data);
1029 log->log("RRProc", Log::DEBUG, "getblock pos = %llu length = %lu", position, amount);
1031 UCHAR sendBuffer[amount];
1032 ULONG amountReceived = 0; // compiler moan.
1035 log->log("RRProc", Log::DEBUG, "getting from live");
1036 amountReceived = x.lp->getBlock(&sendBuffer[0], amount);
1038 if (!amountReceived)
1040 // vdr has possibly disconnected the receiver
1041 log->log("RRProc", Log::DEBUG, "VDR has disconnected the live receiver");
1046 else if (x.recplayer)
1048 log->log("RRProc", Log::DEBUG, "getting from recording");
1049 amountReceived = x.recplayer->getBlock(&sendBuffer[0], position, amount);
1052 if (!amountReceived)
1055 log->log("RRProc", Log::DEBUG, "written 4(0) as getblock got 0");
1059 resp->copyin(sendBuffer, amountReceived);
1060 log->log("RRProc", Log::DEBUG, "written %lu", amountReceived);
1064 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1065 log->log("RRProc", Log::DEBUG, "Finished getblock, have sent %lu", resp->getLen());
1069 int VompClientRRProc::processStartStreamingRecording()
1071 // data is a pointer to the fileName string
1073 x.recordingManager = new cRecordings;
1074 x.recordingManager->Load();
1076 cRecording* recording = x.recordingManager->GetByName((char*)req->data);
1078 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
1082 x.recplayer = new RecPlayer(recording);
1084 resp->addULLONG(x.recplayer->getLengthBytes());
1085 resp->addULONG(x.recplayer->getLengthFrames());
1087 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1089 log->log("RRProc", Log::DEBUG, "written totalLength");
1093 delete x.recordingManager;
1094 x.recordingManager = NULL;
1099 int VompClientRRProc::processPositionFromFrameNumber()
1103 ULONG frameNumber = ntohl(*(ULONG*)req->data);
1107 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1111 retval = x.recplayer->positionFromFrameNumber(frameNumber);
1114 resp->addULLONG(retval);
1116 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1118 log->log("RRProc", Log::DEBUG, "Wrote posFromFrameNum reply to client");
1122 int VompClientRRProc::processFrameNumberFromPosition()
1126 ULLONG position = x.ntohll(*(ULLONG*)req->data);
1130 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1134 retval = x.recplayer->frameNumberFromPosition(position);
1137 resp->addULONG(retval);
1139 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1141 log->log("RRProc", Log::DEBUG, "Wrote frameNumFromPos reply to client");
1145 int VompClientRRProc::processGetIFrame()
1147 bool success = false;
1149 ULONG* data = (ULONG*)req->data;
1151 ULONG frameNumber = ntohl(*data);
1153 ULONG direction = ntohl(*data);
1155 ULLONG rfilePosition = 0;
1156 ULONG rframeNumber = 0;
1157 ULONG rframeLength = 0;
1161 log->log("RRProc", Log::DEBUG, "GetIFrame recording called when no recording being played!");
1165 success = x.recplayer->getNextIFrame(frameNumber, direction, &rfilePosition, &rframeNumber, &rframeLength);
1168 // returns file position, frame number, length
1172 resp->addULLONG(rfilePosition);
1173 resp->addULONG(rframeNumber);
1174 resp->addULONG(rframeLength);
1182 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1184 log->log("RRProc", Log::DEBUG, "Wrote GNIF reply to client %llu %lu %lu", rfilePosition, rframeNumber, rframeLength);
1188 int VompClientRRProc::processGetChannelSchedule()
1190 ULONG* data = (ULONG*)req->data;
1192 ULONG channelNumber = ntohl(*data);
1194 ULONG startTime = ntohl(*data);
1196 ULONG duration = ntohl(*data);
1198 log->log("RRProc", Log::DEBUG, "get schedule called for channel %lu", channelNumber);
1200 cChannel* channel = x.channelFromNumber(channelNumber);
1205 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1207 log->log("RRProc", Log::DEBUG, "written 0 because channel = NULL");
1211 log->log("RRProc", Log::DEBUG, "Got channel");
1213 #if VDRVERSNUM < 10300
1214 cMutexLock MutexLock;
1215 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1217 cSchedulesLock MutexLock;
1218 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
1224 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1226 log->log("RRProc", Log::DEBUG, "written 0 because Schedule!s! = NULL");
1230 log->log("RRProc", Log::DEBUG, "Got schedule!s! object");
1232 const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
1237 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1239 log->log("RRProc", Log::DEBUG, "written 0 because Schedule = NULL");
1243 log->log("RRProc", Log::DEBUG, "Got schedule object");
1245 const char* empty = "";
1246 bool atLeastOneEvent = false;
1249 ULONG thisEventTime;
1250 ULONG thisEventDuration;
1251 const char* thisEventTitle;
1252 const char* thisEventSubTitle;
1253 const char* thisEventDescription;
1255 #if VDRVERSNUM < 10300
1257 const cEventInfo *event;
1258 for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1260 event = Schedule->GetEventNumber(eventNumber);
1262 thisEventID = event->GetEventID();
1263 thisEventTime = event->GetTime();
1264 thisEventDuration = event->GetDuration();
1265 thisEventTitle = event->GetTitle();
1266 thisEventSubTitle = event->GetSubtitle();
1267 thisEventDescription = event->GetExtendedDescription();
1271 for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
1273 thisEventID = event->EventID();
1274 thisEventTime = event->StartTime();
1275 thisEventDuration = event->Duration();
1276 thisEventTitle = event->Title();
1277 thisEventSubTitle = NULL;
1278 thisEventDescription = event->Description();
1282 //in the past filter
1283 if ((thisEventTime + thisEventDuration) < (ULONG)time(NULL)) continue;
1286 if ((thisEventTime + thisEventDuration) <= startTime) continue;
1289 if (thisEventTime >= (startTime + duration)) continue;
1291 if (!thisEventTitle) thisEventTitle = empty;
1292 if (!thisEventSubTitle) thisEventSubTitle = empty;
1293 if (!thisEventDescription) thisEventDescription = empty;
1295 resp->addULONG(thisEventID);
1296 resp->addULONG(thisEventTime);
1297 resp->addULONG(thisEventDuration);
1299 resp->addString(thisEventTitle);
1300 resp->addString(thisEventSubTitle);
1301 resp->addString(thisEventDescription);
1303 atLeastOneEvent = true;
1306 log->log("RRProc", Log::DEBUG, "Got all event data");
1308 if (!atLeastOneEvent)
1311 log->log("RRProc", Log::DEBUG, "Written 0 because no data");
1315 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1317 log->log("RRProc", Log::DEBUG, "written schedules packet");
1322 int VompClientRRProc::processGetTimers()
1325 int numTimers = Timers.Count();
1327 resp->addULONG(numTimers);
1329 for (int i = 0; i < numTimers; i++)
1331 timer = Timers.Get(i);
1333 #if VDRVERSNUM < 10300
1334 resp->addULONG(timer->Active());
1336 resp->addULONG(timer->HasFlags(tfActive));
1338 resp->addULONG(timer->Recording());
1339 resp->addULONG(timer->Pending());
1340 resp->addULONG(timer->Priority());
1341 resp->addULONG(timer->Lifetime());
1342 resp->addULONG(timer->Channel()->Number());
1343 resp->addULONG(timer->StartTime());
1344 resp->addULONG(timer->StopTime());
1345 resp->addULONG(timer->Day());
1346 resp->addULONG(timer->WeekDays());
1347 resp->addString(timer->File());
1351 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1353 log->log("RRProc", Log::DEBUG, "Written timers list");
1358 int VompClientRRProc::processSetTimer()
1360 char* timerString = new char[strlen((char*)req->data) + 1];
1361 strcpy(timerString, (char*)req->data);
1363 #if VDRVERSNUM < 10300
1365 // If this is VDR 1.2 the date part of the timer string must be reduced
1366 // to just DD rather than YYYY-MM-DD
1368 int s = 0; // source
1369 int d = 0; // destination
1371 while(c != 2) // copy up to date section, including the second ':'
1373 timerString[d] = req->data[s];
1374 if (req->data[s] == ':') c++;
1378 // now it has copied up to the date section
1380 while(c != 2) // waste YYYY-MM-
1382 if (req->data[s] == '-') c++;
1385 // now source is at the DD
1386 memcpy(&timerString[d], &req->data[s], req->dataLength - s);
1387 d += req->dataLength - s;
1388 timerString[d] = '\0';
1390 log->log("RRProc", Log::DEBUG, "Timer string after 1.2 conversion:");
1391 log->log("RRProc", Log::DEBUG, "%s", timerString);
1395 cTimer *timer = new cTimer;
1396 if (timer->Parse((char*)timerString))
1398 cTimer *t = Timers.GetTimer(timer);
1402 #if VDRVERSNUM < 10300
1405 Timers.SetModified();
1409 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1416 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1423 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1429 int VompClientRRProc::processDeleteTimer()
1431 log->log("RRProc", Log::DEBUG, "Delete timer called");
1436 INT delChannel = ntohl(*(ULONG*)&req->data[position]); position += 4;
1437 INT delWeekdays = ntohl(*(ULONG*)&req->data[position]); position += 4;
1438 INT delDay = ntohl(*(ULONG*)&req->data[position]); position += 4;
1439 INT delStart = ntohl(*(ULONG*)&req->data[position]); position += 4;
1440 INT delStop = ntohl(*(ULONG*)&req->data[position]); position += 4;
1443 for (ti = Timers.First(); ti; ti = Timers.Next(ti))
1445 if ( (ti->Channel()->Number() == delChannel)
1446 && ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay)))
1447 && (ti->StartTime() == delStart)
1448 && (ti->StopTime() == delStop) )
1456 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1460 if (!Timers.BeingEdited())
1462 if (!ti->Recording())
1465 Timers.SetModified();
1468 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1473 log->log("RRProc", Log::ERR, "Unable to delete timer - timer is running");
1476 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1482 log->log("RRProc", Log::ERR, "Unable to delete timer - timers being edited at VDR");
1485 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1490 int VompClientRRProc::processGetRecInfo()
1492 // data is a pointer to the fileName string
1494 cRecordings Recordings;
1495 Recordings.Load(); // probably have to do this
1497 cRecording *recording = Recordings.GetByName((char*)req->data);
1499 time_t timerStart = 0;
1500 time_t timerStop = 0;
1501 char* summary = NULL;
1502 ULONG resumePoint = 0;
1506 log->log("RRProc", Log::ERR, "GetRecInfo found no recording");
1509 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1514 4 bytes: start time for timer
1515 4 bytes: end time for timer
1516 4 bytes: resume point
1518 4 bytes: num components
1528 // Get current timer
1530 cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
1533 timerStart = rc->Timer()->StartTime();
1534 timerStop = rc->Timer()->StopTime();
1535 log->log("RRProc", Log::DEBUG, "GRI: RC: %lu %lu", timerStart, timerStop);
1538 resp->addULONG(timerStart);
1539 resp->addULONG(timerStop);
1543 char* value = x.config.getValueString("ResumeData", (char*)req->data);
1546 resumePoint = strtoul(value, NULL, 10);
1549 log->log("RRProc", Log::DEBUG, "GRI: RP: %lu", resumePoint);
1551 resp->addULONG(resumePoint);
1556 #if VDRVERSNUM < 10300
1557 summary = (char*)recording->Summary();
1559 const cRecordingInfo *Info = recording->Info();
1560 summary = (char*)Info->ShortText();
1561 if (isempty(summary)) summary = (char*)Info->Description();
1563 log->log("RRProc", Log::DEBUG, "GRI: S: %s", summary);
1566 resp->addString(summary);
1570 resp->addString("");
1575 #if VDRVERSNUM < 10300
1577 // Send 0 for numchannels - this signals the client this info is not available
1581 const cComponents* components = Info->Components();
1583 log->log("RRProc", Log::DEBUG, "GRI: D1: %p", components);
1591 resp->addULONG(components->NumComponents());
1593 tComponent* component;
1594 for (int i = 0; i < components->NumComponents(); i++)
1596 component = components->Component(i);
1598 log->log("RRProc", Log::DEBUG, "GRI: C: %i %u %u %s %s", i, component->stream, component->type, component->language, component->description);
1600 resp->addUCHAR(component->stream);
1601 resp->addUCHAR(component->type);
1603 if (component->language)
1605 resp->addString(component->language);
1609 resp->addString("");
1611 if (component->description)
1613 resp->addString(component->description);
1617 resp->addString("");
1627 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1629 log->log("RRProc", Log::DEBUG, "Written getrecinfo");
1639 int VompClientRRProc::processReScanRecording()
1643 log->log("RRProc", Log::DEBUG, "Rescan recording called when no recording being played!");
1647 x.recplayer->scan();
1649 resp->addULLONG(x.recplayer->getLengthBytes());
1650 resp->addULONG(x.recplayer->getLengthFrames());
1652 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1653 log->log("RRProc", Log::DEBUG, "Rescan recording, wrote new length to client");
1657 // FIXME without client calling rescan, getblock wont work even tho more data is avail
1659 int VompClientRRProc::processGetMarks()
1661 // data is a pointer to the fileName string
1664 cRecordings Recordings;
1665 Recordings.Load(); // probably have to do this
1667 cRecording *recording = Recordings.GetByName((char*)req->data);
1669 log->log("RRProc", Log::DEBUG, "recording pointer %p", recording);
1673 Marks.Load(recording->FileName());
1676 for (const cMark *m = Marks.First(); m; m = Marks.Next(m))
1678 log->log("RRProc", Log::DEBUG, "found Mark %i", m->position);
1680 resp->addULONG(m->position);
1685 log->log("RRProc", Log::DEBUG, "no marks found, sending 0-mark");
1691 x.tcp.sendPacket(resp->getPtr(), resp->getLen());
1693 log->log("RRProc", Log::DEBUG, "Written Marks list");
1698 #endif // !VOMPSTANDALONE