From 022b716508ba0a2aac14e071b983a3f09139ff9c Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Wed, 21 Nov 2007 23:51:48 +0000 Subject: [PATCH 01/16] New protocol --- Makefile | 2 +- responsepacket.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++ responsepacket.h | 58 ++++++++++++++++++ 3 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 responsepacket.c create mode 100644 responsepacket.h diff --git a/Makefile b/Makefile index 9aa3d51..659d4e9 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,7 @@ DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' OBJS = $(PLUGIN).o dsock.o mvpserver.o udpreplier.o bootpd.o tftpd.o mvpclient.o tcp.o \ ringbuffer.o mvprelay.o \ recplayer.o config.o log.o thread.o mvpreceiver.o tftpclient.o \ - media.o + media.o responsepacket.o ### Implicit rules: diff --git a/responsepacket.c b/responsepacket.c new file mode 100644 index 0000000..0130235 --- /dev/null +++ b/responsepacket.c @@ -0,0 +1,149 @@ +/* + Copyright 2007 Chris Tallon + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include + +#include "responsepacket.h" +#include "log.h" + +/* Packet format for an RR channel response: + +4 bytes = channel ID = 1 (request/response channel) +4 bytes = request ID (from serialNumber) +4 bytes = length of the rest of the packet +? bytes = rest of packet. depends on packet +*/ + +ResponsePacket::ResponsePacket() +{ + buffer = NULL; + bufSize = 0; + bufUsed = 0; +} + +ResponsePacket::~ResponsePacket() +{ + if (buffer) free(buffer); +} + +bool ResponsePacket::init(ULONG requestID) +{ + if (buffer) return false; + + bufSize = 512; + buffer = (UCHAR*)malloc(bufSize); + if (!buffer) return false; + + *(ULONG*)&buffer[0] = htonl(1); // RR channel + *(ULONG*)&buffer[4] = htonl(requestID); + *(ULONG*)&buffer[userDataLenPos] = 0; + bufUsed = headerLength; + + return true; +} + +void ResponsePacket::finalise() +{ + *(ULONG*)&buffer[userDataLenPos] = htonl(bufUsed - headerLength); + Log::getInstance()->log("Client", Log::DEBUG, "RP finalise %lu", bufUsed - headerLength); +} + +bool ResponsePacket::copyin(const UCHAR* src, ULONG len) +{ + if (!checkExtend(len)) return false; + memcpy(buffer + bufUsed, src, len); + bufUsed += len; + return true; +} + +bool ResponsePacket::addString(const char* string) +{ + ULONG len = strlen(string) + 1; + if (!checkExtend(len)) return false; + memcpy(buffer + bufUsed, string, len); + bufUsed += len; + return true; +} + +bool ResponsePacket::addULONG(ULONG ul) +{ + if (!checkExtend(sizeof(ULONG))) return false; + *(ULONG*)&buffer[bufUsed] = htonl(ul); + bufUsed += sizeof(ULONG); + return true; +} + +bool ResponsePacket::addUCHAR(UCHAR c) +{ + if (!checkExtend(sizeof(UCHAR))) return false; + buffer[bufUsed] = c; + bufUsed += sizeof(UCHAR); + return true; +} + +bool ResponsePacket::addLONG(LONG l) +{ + if (!checkExtend(sizeof(LONG))) return false; + *(LONG*)&buffer[bufUsed] = htonl(l); + bufUsed += sizeof(LONG); + return true; +} + +bool ResponsePacket::addULLONG(ULLONG ull) +{ + if (!checkExtend(sizeof(ULLONG))) return false; + *(ULLONG*)&buffer[bufUsed] = htonll(ull); + bufUsed += sizeof(ULLONG); + return true; +} + +bool ResponsePacket::checkExtend(ULONG by) +{ + if ((bufUsed + by) < bufSize) return true; + if (512 > by) by = 512; + UCHAR* newBuf = (UCHAR*)realloc(buffer, bufSize + by); + if (!newBuf) return false; + buffer = newBuf; + bufSize += by; + return true; +} + +ULLONG ResponsePacket::htonll(ULLONG a) +{ + #if BYTE_ORDER == BIG_ENDIAN + return a; + #else + ULLONG b = 0; + + b = ((a << 56) & 0xFF00000000000000ULL) + | ((a << 40) & 0x00FF000000000000ULL) + | ((a << 24) & 0x0000FF0000000000ULL) + | ((a << 8) & 0x000000FF00000000ULL) + | ((a >> 8) & 0x00000000FF000000ULL) + | ((a >> 24) & 0x0000000000FF0000ULL) + | ((a >> 40) & 0x000000000000FF00ULL) + | ((a >> 56) & 0x00000000000000FFULL) ; + + return b; + #endif +} + diff --git a/responsepacket.h b/responsepacket.h new file mode 100644 index 0000000..e091701 --- /dev/null +++ b/responsepacket.h @@ -0,0 +1,58 @@ +/* + Copyright 2007 Chris Tallon + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef RESPONSEPACKET_H +#define RESPONSEPACKET_H + +#include "defines.h" + +class ResponsePacket +{ + public: + ResponsePacket(); + ~ResponsePacket(); + + bool init(ULONG requestID); + void finalise(); + bool copyin(const UCHAR* src, ULONG len); + bool addString(const char* string); + bool addULONG(ULONG ul); + bool addLONG(LONG l); + bool addUCHAR(UCHAR c); + bool addULLONG(ULLONG ull); + + UCHAR* getPtr() { return buffer; } + ULONG getLen() { return bufUsed; } + + private: + + UCHAR* buffer; + ULONG bufSize; + ULONG bufUsed; + + bool checkExtend(ULONG by); + ULLONG htonll(ULLONG a); + + const static ULONG headerLength = 12; + const static ULONG userDataLenPos = 8; +}; + +#endif + -- 2.39.2 From b4cd364d6794f3251ba0b6f140fa49d3a7fadf1e Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Thu, 22 Nov 2007 00:15:49 +0000 Subject: [PATCH 02/16] Protocol changes --- mvpclient.c | 2035 ++++++++++++++++++++++++--------------------------- 1 file changed, 955 insertions(+), 1080 deletions(-) diff --git a/mvpclient.c b/mvpclient.c index 01ead43..04f9745 100644 --- a/mvpclient.c +++ b/mvpclient.c @@ -20,6 +20,8 @@ #include "mvpclient.h" +#include "responsepacket.h" + // This is here else it causes compile errors with something in libdvbmpeg //#include @@ -32,7 +34,7 @@ MVPClient::MVPClient(Config* cfgBase, char* tconfigDirExtra, int tsocket) { #ifndef VOMPSTANDALONE lp = NULL; - rp = NULL; + recplayer = NULL; recordingManager = NULL; #endif imageFile = 0; @@ -46,19 +48,19 @@ MVPClient::MVPClient(Config* cfgBase, char* tconfigDirExtra, int tsocket) MVPClient::~MVPClient() { log->log("Client", Log::DEBUG, "MVP client destructor"); -#ifndef VOMPSTANDALONE +#ifndef VOMPSTANDALONE if (lp) { delete lp; lp = NULL; } - else if (rp) + else if (recplayer) { writeResumeData(); - delete rp; + delete recplayer; delete recordingManager; - rp = NULL; + recplayer = NULL; recordingManager = NULL; } #endif @@ -66,6 +68,29 @@ MVPClient::~MVPClient() decClients(); } +void MVPClient::incClients() +{ + pthread_mutex_lock(&threadClientMutex); + MVPClient::nr_clients++; + pthread_mutex_unlock(&threadClientMutex); +} + +void MVPClient::decClients() +{ + pthread_mutex_lock(&threadClientMutex); + MVPClient::nr_clients--; + pthread_mutex_unlock(&threadClientMutex); +} + +int MVPClient::getNrClients() +{ + int nrClients; + pthread_mutex_lock(&threadClientMutex); + nrClients = MVPClient::nr_clients; + pthread_mutex_unlock(&threadClientMutex); + return nrClients; +} + ULLONG MVPClient::ntohll(ULLONG a) { return htonll(a); @@ -127,19 +152,45 @@ cChannel* MVPClient::channelFromNumber(ULONG channelNumber) void MVPClient::writeResumeData() { config.setValueLong("ResumeData", - (char*)rp->getCurrentRecording()->FileName(), - rp->frameNumberFromPosition(rp->getLastPosition()) ); + (char*)recplayer->getCurrentRecording()->FileName(), + recplayer->frameNumberFromPosition(recplayer->getLastPosition()) ); } #endif -void MVPClient::sendULONG(ULONG ul) +void MVPClient::cleanConfig() { - UCHAR sendBuffer[8]; - *(ULONG*)&sendBuffer[0] = htonl(4); - *(ULONG*)&sendBuffer[4] = htonl(ul); + log->log("Client", Log::DEBUG, "Clean config"); + +#ifndef VOMPSTANDALONE + + cRecordings Recordings; + Recordings.Load(); + + int numReturns; + int length; + char* resumes = config.getSectionKeyNames("ResumeData", numReturns, length); + char* position = resumes; + for(int k = 0; k < numReturns; k++) + { + log->log("Client", Log::DEBUG, "EXAMINING: %i %i %p %s", k, numReturns, position, position); + + cRecording* recording = Recordings.GetByName(position); + if (!recording) + { + // doesn't exist anymore + log->log("Client", Log::DEBUG, "Found a recording that doesn't exist anymore"); + config.deleteValue("ResumeData", position); + } + else + { + log->log("Client", Log::DEBUG, "This recording still exists"); + } + + position += strlen(position) + 1; + } - tcp.sendPacket(sendBuffer, 8); - log->log("Client", Log::DEBUG, "written ULONG %lu", ul); + delete[] resumes; +#endif } void MVPClientStartThread(void* arg) @@ -173,7 +224,7 @@ void MVPClient::run2() tcp.setNonBlocking(); ULONG channelID; - ULONG serialNumber; + ULONG requestID; ULONG opcode; ULONG extraDataLength; UCHAR* data; @@ -194,8 +245,8 @@ void MVPClient::run2() log->log("Client", Log::DEBUG, "Got chan"); - if (!tcp.readData((UCHAR*)&serialNumber, sizeof(ULONG))) break; - serialNumber = ntohl(serialNumber); + if (!tcp.readData((UCHAR*)&requestID, sizeof(ULONG))) break; + requestID = ntohl(requestID); log->log("Client", Log::DEBUG, "Got ser"); @@ -235,7 +286,7 @@ void MVPClient::run2() data = NULL; } - log->log("Client", Log::DEBUG, "Received chan=%lu, ser=%lu, op=%lu, edl=%lu", channelID, serialNumber, opcode, extraDataLength); + log->log("Client", Log::DEBUG, "Received chan=%lu, ser=%lu, op=%lu, edl=%lu", channelID, requestID, opcode, extraDataLength); if (!loggedIn && (opcode != 1)) { @@ -244,86 +295,93 @@ void MVPClient::run2() break; } + ResponsePacket* rp = new ResponsePacket(); + if (!rp->init(requestID)) + { + log->log("Client", Log::ERR, "response packet init fail"); + break; + } + switch(opcode) { case 1: - result = processLogin(data, extraDataLength); + result = processLogin(data, extraDataLength, rp); break; -#ifndef VOMPSTANDALONE +#ifndef VOMPSTANDALONE case 2: - result = processGetRecordingsList(data, extraDataLength); + result = processGetRecordingsList(data, extraDataLength, rp); break; case 3: - result = processDeleteRecording(data, extraDataLength); + result = processDeleteRecording(data, extraDataLength, rp); break; case 5: - result = processGetChannelsList(data, extraDataLength); + result = processGetChannelsList(data, extraDataLength, rp); break; case 6: - result = processStartStreamingChannel(data, extraDataLength); + result = processStartStreamingChannel(data, extraDataLength, requestID, rp); break; case 7: - result = processGetBlock(data, extraDataLength); + result = processGetBlock(data, extraDataLength, rp); break; case 8: - result = processStopStreaming(data, extraDataLength); + result = processStopStreaming(data, extraDataLength, rp); break; case 9: - result = processStartStreamingRecording(data, extraDataLength); + result = processStartStreamingRecording(data, extraDataLength, rp); break; +#endif case 10: - result = processGetChannelSchedule(data, extraDataLength); + result = processGetChannelSchedule(data, extraDataLength, rp); break; -#endif case 11: - result = processConfigSave(data, extraDataLength); + result = processConfigSave(data, extraDataLength, rp); break; case 12: - result = processConfigLoad(data, extraDataLength); + result = processConfigLoad(data, extraDataLength, rp); break; -#ifndef VOMPSTANDALONE +#ifndef VOMPSTANDALONE case 13: - result = processReScanRecording(data, extraDataLength); // FIXME obselete + result = processReScanRecording(data, extraDataLength, rp); // FIXME obselete break; case 14: - result = processGetTimers(data, extraDataLength); + result = processGetTimers(data, extraDataLength, rp); break; case 15: - result = processSetTimer(data, extraDataLength); + result = processSetTimer(data, extraDataLength, rp); break; case 16: - result = processPositionFromFrameNumber(data, extraDataLength); + result = processPositionFromFrameNumber(data, extraDataLength, rp); break; case 17: - result = processFrameNumberFromPosition(data, extraDataLength); + result = processFrameNumberFromPosition(data, extraDataLength, rp); break; case 18: - result = processMoveRecording(data, extraDataLength); + result = processMoveRecording(data, extraDataLength, rp); break; case 19: - result = processGetIFrame(data, extraDataLength); + result = processGetIFrame(data, extraDataLength, rp); break; case 20: - result = processGetRecInfo(data, extraDataLength); + result = processGetRecInfo(data, extraDataLength, rp); break; case 21: - result = processGetMarks(data, extraDataLength); + result = processGetMarks(data, extraDataLength, rp); break; case 22: - result = processGetChannelPids(data, extraDataLength); + result = processGetChannelPids(data, extraDataLength, rp); break; case 23: - result = processDeleteTimer(data, extraDataLength); + result = processDeleteTimer(data, extraDataLength, rp); break; -#endif +#endif case 30: - result = processGetMediaList(data, extraDataLength); + result = processGetMediaList(data, extraDataLength, rp); break; case 31: - result = processGetPicture(data, extraDataLength); + result = processGetPicture(data, extraDataLength, rp); break; case 32: - result = processGetImageBlock(data, extraDataLength); + result = processGetImageBlock(data, extraDataLength, rp); break; } @@ -332,7 +390,7 @@ void MVPClient::run2() } } -int MVPClient::processLogin(UCHAR* buffer, int length) +int MVPClient::processLogin(UCHAR* buffer, int length, ResponsePacket* rp) { if (length != 6) return 0; @@ -359,68 +417,48 @@ int MVPClient::processLogin(UCHAR* buffer, int length) struct tm* timeStruct = localtime(&timeNow); int timeOffset = timeStruct->tm_gmtoff; - UCHAR sendBuffer[12]; - *(ULONG*)&sendBuffer[0] = htonl(8); - *(ULONG*)&sendBuffer[4] = htonl(timeNow); - *(signed int*)&sendBuffer[8] = htonl(timeOffset); - - tcp.sendPacket(sendBuffer, 12); - log->log("Client", Log::DEBUG, "written login reply"); - + rp->addULONG(timeNow); + rp->addLONG(timeOffset); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + log->log("Client", Log::DEBUG, "written login reply len %lu", rp->getLen()); + delete rp; + loggedIn = true; return 1; } #ifndef VOMPSTANDALONE -int MVPClient::processGetRecordingsList(UCHAR* data, int length) +int MVPClient::processGetRecordingsList(UCHAR* data, int length, ResponsePacket* rp) { - UCHAR* sendBuffer = new UCHAR[50000]; // hope this is enough - int count = 4; // leave space for the packet length - char* point; - - int FreeMB; int Percent = VideoDiskSpace(&FreeMB); int Total = (FreeMB / (100 - Percent)) * 100; - - *(ULONG*)&sendBuffer[count] = htonl(Total); - count += sizeof(ULONG); - *(ULONG*)&sendBuffer[count] = htonl(FreeMB); - count += sizeof(ULONG); - *(ULONG*)&sendBuffer[count] = htonl(Percent); - count += sizeof(ULONG); - + + rp->addULONG(Total); + rp->addULONG(FreeMB); + rp->addULONG(Percent); cRecordings Recordings; Recordings.Load(); for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) { - if (count > 49000) break; // just how big is that hard disk?! - *(ULONG*)&sendBuffer[count] = htonl(recording->start);// + timeOffset); - count += 4; - - point = (char*)recording->Name(); - strcpy((char*)&sendBuffer[count], point); - count += strlen(point) + 1; - - point = (char*)recording->FileName(); - strcpy((char*)&sendBuffer[count], point); - count += strlen(point) + 1; + rp->addULONG(recording->start); + rp->addString(recording->Name()); + rp->addString(recording->FileName()); } - *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field - - log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0])); - - tcp.sendPacket(sendBuffer, count); - delete[] sendBuffer; - log->log("Client", Log::DEBUG, "Written list"); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + + log->log("Client", Log::DEBUG, "Written recordings list"); return 1; } -int MVPClient::processDeleteRecording(UCHAR* data, int length) +int MVPClient::processDeleteRecording(UCHAR* data, int length, ResponsePacket* rp) { // data is a pointer to the fileName string @@ -444,27 +482,31 @@ int MVPClient::processDeleteRecording(UCHAR* data, int length) #if VDRVERSNUM > 10300 ::Recordings.DelByName(recording->FileName()); #endif - sendULONG(1); + rp->addULONG(1); } else { - sendULONG(2); + rp->addULONG(2); } } else { - sendULONG(3); + rp->addULONG(3); } } else { - sendULONG(4); + rp->addULONG(4); } + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + return 1; } -int MVPClient::processMoveRecording(UCHAR* data, int length) +int MVPClient::processMoveRecording(UCHAR* data, int length, ResponsePacket* rp) { log->log("Client", Log::DEBUG, "Process move recording"); char* fileName = (char*)data; @@ -552,7 +594,11 @@ int MVPClient::processMoveRecording(UCHAR* data, int length) delete[] dateDirName; delete[] titleDirName; delete[] newContainer; - sendULONG(5); + + rp->addULONG(5); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; return 1; } } @@ -561,7 +607,11 @@ int MVPClient::processMoveRecording(UCHAR* data, int length) delete[] dateDirName; delete[] titleDirName; delete[] newContainer; - sendULONG(5); + + rp->addULONG(5); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; return 1; } @@ -590,19 +640,18 @@ int MVPClient::processMoveRecording(UCHAR* data, int length) ::Recordings.Update(); #endif // Success. Send a different packet from just a ulong - int totalLength = 4 + 4 + strlen(newDir) + 1; - UCHAR* sendBuffer = new UCHAR[totalLength]; - *(ULONG*)&sendBuffer[0] = htonl(totalLength - 4); - *(ULONG*)&sendBuffer[4] = htonl(1); // success - strcpy((char*)&sendBuffer[8], newDir); - tcp.sendPacket(sendBuffer, totalLength); - delete[] sendBuffer; + rp->addULONG(1); // success + rp->addString(newDir); } else { - sendULONG(5); + rp->addULONG(5); } + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + delete[] dateDirName; delete[] titleDirName; delete[] newContainer; @@ -610,22 +659,25 @@ int MVPClient::processMoveRecording(UCHAR* data, int length) } else { - sendULONG(3); + rp->addULONG(3); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; } } else { - sendULONG(4); + rp->addULONG(4); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; } return 1; } -int MVPClient::processGetChannelsList(UCHAR* data, int length) +int MVPClient::processGetChannelsList(UCHAR* data, int length, ResponsePacket* rp) { - UCHAR* sendBuffer = new UCHAR[50000]; // FIXME hope this is enough - int count = 4; // leave space for the packet length - char* point; ULONG type; char* chanConfig = config.getValueString("General", "Channels"); @@ -650,44 +702,36 @@ int MVPClient::processGetChannelsList(UCHAR* data, int length) else continue; #endif - if (count > 49000) break; - *(ULONG*)&sendBuffer[count] = htonl(channel->Number()); - count += 4; - - *(ULONG*)&sendBuffer[count] = htonl(type); - count += 4; - - point = (char*)channel->Name(); - strcpy((char*)&sendBuffer[count], point); - count += strlen(point) + 1; + rp->addULONG(channel->Number()); + rp->addULONG(type); + rp->addString(channel->Name()); } } - *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; - log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0])); - - tcp.sendPacket(sendBuffer, count); - delete[] sendBuffer; log->log("Client", Log::DEBUG, "Written channels list"); return 1; } -int MVPClient::processGetChannelPids(UCHAR* data, int length) +int MVPClient::processGetChannelPids(UCHAR* data, int length, ResponsePacket* rp) { ULONG channelNumber = ntohl(*(ULONG*)data); cChannel* channel = channelFromNumber(channelNumber); if (!channel) { - sendULONG(0); + rp->addULONG(0); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; return 1; } ULONG numApids = 0; - ULONG spaceRequired = 12; // 4 for length field, 4 for vpid, 4 for number of apids - // Work out space required and number of Apids #if VDRVERSNUM < 10300 @@ -695,25 +739,16 @@ int MVPClient::processGetChannelPids(UCHAR* data, int length) log->log("Client", Log::DEBUG, "Apid2: %i", channel->Apid2()); if (channel->Apid2()) - { numApids = 2; - spaceRequired += 10; // 8 + 2 nulls - } else if (channel->Apid1()) - { numApids = 1; - spaceRequired += 5; // 4 + 1 null - } else - { numApids = 0; - } #else for (const int *Apid = channel->Apids(); *Apid; Apid++) { - spaceRequired += 4 + strlen(channel->Alang(numApids)) + 1; // 4 for pid, length of string + \0 numApids++; } #endif @@ -727,42 +762,38 @@ int MVPClient::processGetChannelPids(UCHAR* data, int length) // lang string // } - UCHAR* sendBuffer = new UCHAR[spaceRequired]; - ULONG point = 0; - *(ULONG*)&sendBuffer[point] = htonl(spaceRequired - 4); point += 4; // take off first 4 bytes - *(ULONG*)&sendBuffer[point] = htonl(channel->Vpid()); point += 4; - *(ULONG*)&sendBuffer[point] = htonl(numApids); point += 4; + rp->addULONG(channel->Vpid()); + rp->addULONG(numApids); #if VDRVERSNUM < 10300 if (numApids >= 1) { - *(ULONG*)&sendBuffer[point] = htonl(channel->Apid1()); point += 4; - sendBuffer[point] = '\0'; point += 1; + rp->addULONG(channel->Apid1()); + rp->addString(""); } if (numApids == 2) { - *(ULONG*)&sendBuffer[point] = htonl(channel->Apid2()); point += 4; - sendBuffer[point] = '\0'; point += 1; + rp->addULONG(channel->Apid2()); + rp->addString(""); } #else for (ULONG i = 0; i < numApids; i++) { - *(ULONG*)&sendBuffer[point] = htonl(channel->Apid(i)); point += 4; - strcpy((char*)&sendBuffer[point], channel->Alang(i)); point += strlen(channel->Alang(i)) + 1; + rp->addULONG(channel->Apid(i)); + rp->addString(channel->Alang(i)); } #endif -// printf("About to send getchannelpids response. length = %u\n", spaceRequired); - //tcp.dump(sendBuffer, spaceRequired); - - tcp.sendPacket(sendBuffer, spaceRequired); - delete[] sendBuffer; + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + log->log("Client", Log::DEBUG, "Written channels pids"); return 1; } -int MVPClient::processStartStreamingChannel(UCHAR* data, int length) +int MVPClient::processStartStreamingChannel(UCHAR* data, int length, ULONG streamID, ResponsePacket* rp) { log->log("Client", Log::DEBUG, "length = %i", length); ULONG channelNumber = ntohl(*(ULONG*)data); @@ -770,7 +801,10 @@ int MVPClient::processStartStreamingChannel(UCHAR* data, int length) cChannel* channel = channelFromNumber(channelNumber); if (!channel) { - sendULONG(0); + rp->addULONG(0); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; return 1; } @@ -796,23 +830,32 @@ int MVPClient::processStartStreamingChannel(UCHAR* data, int length) if (!lp) { - sendULONG(0); + rp->addULONG(0); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; return 1; } - if (!lp->init()) + if (!lp->init(&tcp, streamID)) { delete lp; lp = NULL; - sendULONG(0); + rp->addULONG(0); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; return 1; } - sendULONG(1); + rp->addULONG(1); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; return 1; } -int MVPClient::processStopStreaming(UCHAR* data, int length) +int MVPClient::processStopStreaming(UCHAR* data, int length, ResponsePacket* rp) { log->log("Client", Log::DEBUG, "STOP STREAMING RECEIVED"); if (lp) @@ -820,23 +863,26 @@ int MVPClient::processStopStreaming(UCHAR* data, int length) delete lp; lp = NULL; } - else if (rp) + else if (recplayer) { writeResumeData(); - delete rp; + delete recplayer; delete recordingManager; - rp = NULL; + recplayer = NULL; recordingManager = NULL; } - sendULONG(1); + rp->addULONG(1); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; return 1; } -int MVPClient::processGetBlock(UCHAR* data, int length) +int MVPClient::processGetBlock(UCHAR* data, int length, ResponsePacket* rp) { - if (!lp && !rp) + if (!lp && !recplayer) { log->log("Client", Log::DEBUG, "Get block called when no streaming happening!"); return 0; @@ -848,12 +894,12 @@ int MVPClient::processGetBlock(UCHAR* data, int length) log->log("Client", Log::DEBUG, "getblock pos = %llu length = %lu", position, amount); - UCHAR sendBuffer[amount + 4]; + UCHAR sendBuffer[amount]; ULONG amountReceived = 0; // compiler moan. if (lp) { log->log("Client", Log::DEBUG, "getting from live"); - amountReceived = lp->getBlock(&sendBuffer[4], amount); + amountReceived = lp->getBlock(&sendBuffer[0], amount); if (!amountReceived) { @@ -863,28 +909,31 @@ int MVPClient::processGetBlock(UCHAR* data, int length) lp = NULL; } } - else if (rp) + else if (recplayer) { log->log("Client", Log::DEBUG, "getting from recording"); - amountReceived = rp->getBlock(&sendBuffer[4], position, amount); + amountReceived = recplayer->getBlock(&sendBuffer[0], position, amount); } if (!amountReceived) { - sendULONG(0); + rp->addULONG(0); log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0"); } else { - *(ULONG*)&sendBuffer[0] = htonl(amountReceived); - tcp.sendPacket(sendBuffer, amountReceived + 4); - log->log("Client", Log::DEBUG, "written ok %lu", amountReceived); + rp->copyin(sendBuffer, amountReceived); + log->log("Client", Log::DEBUG, "written %lu", amountReceived); } + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + log->log("Client", Log::DEBUG, "Finished getblock, have sent %lu", rp->getLen()); + delete rp; return 1; } -int MVPClient::processStartStreamingRecording(UCHAR* data, int length) +int MVPClient::processStartStreamingRecording(UCHAR* data, int length, ResponsePacket* rp) { // data is a pointer to the fileName string @@ -897,14 +946,14 @@ int MVPClient::processStartStreamingRecording(UCHAR* data, int length) if (recording) { - rp = new RecPlayer(recording); + recplayer = new RecPlayer(recording); - UCHAR sendBuffer[16]; - *(ULONG*)&sendBuffer[0] = htonl(12); - *(ULLONG*)&sendBuffer[4] = htonll(rp->getLengthBytes()); - *(ULONG*)&sendBuffer[12] = htonl(rp->getLengthFrames()); - - tcp.sendPacket(sendBuffer, 16); + rp->addULONG(recplayer->getLengthBytes()); + rp->addULONG(recplayer->getLengthFrames()); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + log->log("Client", Log::DEBUG, "written totalLength"); } else @@ -915,57 +964,57 @@ int MVPClient::processStartStreamingRecording(UCHAR* data, int length) return 1; } -int MVPClient::processPositionFromFrameNumber(UCHAR* data, int length) +int MVPClient::processPositionFromFrameNumber(UCHAR* data, int length, ResponsePacket* rp) { ULLONG retval = 0; ULONG frameNumber = ntohl(*(ULONG*)data); data += 4; - if (!rp) + if (!recplayer) { log->log("Client", Log::DEBUG, "Rescan recording called when no recording being played!"); } else { - retval = rp->positionFromFrameNumber(frameNumber); + retval = recplayer->positionFromFrameNumber(frameNumber); } - UCHAR sendBuffer[12]; - *(ULONG*)&sendBuffer[0] = htonl(8); - *(ULLONG*)&sendBuffer[4] = htonll(retval); + rp->addULONG(retval); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; - tcp.sendPacket(sendBuffer, 12); log->log("Client", Log::DEBUG, "Wrote posFromFrameNum reply to client"); return 1; } -int MVPClient::processFrameNumberFromPosition(UCHAR* data, int length) +int MVPClient::processFrameNumberFromPosition(UCHAR* data, int length, ResponsePacket* rp) { ULONG retval = 0; ULLONG position = ntohll(*(ULLONG*)data); data += 8; - if (!rp) + if (!recplayer) { log->log("Client", Log::DEBUG, "Rescan recording called when no recording being played!"); } else { - retval = rp->frameNumberFromPosition(position); + retval = recplayer->frameNumberFromPosition(position); } - UCHAR sendBuffer[8]; - *(ULONG*)&sendBuffer[0] = htonl(4); - *(ULONG*)&sendBuffer[4] = htonl(retval); + rp->addULONG(retval); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; - tcp.sendPacket(sendBuffer, 8); log->log("Client", Log::DEBUG, "Wrote frameNumFromPos reply to client"); return 1; } -int MVPClient::processGetIFrame(UCHAR* data, int length) +int MVPClient::processGetIFrame(UCHAR* data, int length, ResponsePacket* rp) { bool success = false; @@ -978,43 +1027,37 @@ int MVPClient::processGetIFrame(UCHAR* data, int length) ULONG rframeNumber = 0; ULONG rframeLength = 0; - if (!rp) + if (!recplayer) { log->log("Client", Log::DEBUG, "GetIFrame recording called when no recording being played!"); } else { - success = rp->getNextIFrame(frameNumber, direction, &rfilePosition, &rframeNumber, &rframeLength); + success = recplayer->getNextIFrame(frameNumber, direction, &rfilePosition, &rframeNumber, &rframeLength); } // returns file position, frame number, length - UCHAR sendBuffer[20]; - int packetLength; - if (success) { - packetLength = 20; - *(ULONG*)&sendBuffer[0] = htonl(16); - *(ULLONG*)&sendBuffer[4] = htonll(rfilePosition); - *(ULONG*)&sendBuffer[12] = htonl(rframeNumber); - *(ULONG*)&sendBuffer[16] = htonl(rframeLength); + rp->addULLONG(rfilePosition); + rp->addULONG(rframeNumber); + rp->addULONG(rframeLength); } else { - packetLength = 8; - *(ULONG*)&sendBuffer[0] = htonl(4); - *(ULONG*)&sendBuffer[4] = 0; + rp->addULONG(0); } - log->log("Client", Log::DEBUG, "%llu %lu %lu", rfilePosition, rframeNumber, rframeLength); - - tcp.sendPacket(sendBuffer, packetLength); - log->log("Client", Log::DEBUG, "Wrote GNIF reply to client"); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + + log->log("Client", Log::DEBUG, "Wrote GNIF reply to client %llu %lu %lu", rfilePosition, rframeNumber, rframeLength); return 1; } -int MVPClient::processGetChannelSchedule(UCHAR* data, int length) +int MVPClient::processGetChannelSchedule(UCHAR* data, int length, ResponsePacket* rp) { ULONG channelNumber = ntohl(*(ULONG*)data); data += 4; @@ -1027,7 +1070,11 @@ int MVPClient::processGetChannelSchedule(UCHAR* data, int length) cChannel* channel = channelFromNumber(channelNumber); if (!channel) { - sendULONG(0); + rp->addULONG(0); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + log->log("Client", Log::DEBUG, "written 0 because channel = NULL"); return 1; } @@ -1043,7 +1090,11 @@ int MVPClient::processGetChannelSchedule(UCHAR* data, int length) #endif if (!Schedules) { - sendULONG(0); + rp->addULONG(0); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + log->log("Client", Log::DEBUG, "written 0 because Schedule!s! = NULL"); return 1; } @@ -1053,20 +1104,20 @@ int MVPClient::processGetChannelSchedule(UCHAR* data, int length) const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID()); if (!Schedule) { - sendULONG(0); + rp->addULONG(0); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + log->log("Client", Log::DEBUG, "written 0 because Schedule = NULL"); return 1; } log->log("Client", Log::DEBUG, "Got schedule object"); - UCHAR* sendBuffer = (UCHAR*)malloc(100000); - ULONG sendBufferLength = 100000; - ULONG sendBufferUsed = sizeof(ULONG); // leave a hole for the entire packet length - const char* empty = ""; + bool atLeastOneEvent = false; - // assign all the event info to temp vars then we know exactly what size they are ULONG thisEventID; ULONG thisEventTime; ULONG thisEventDuration; @@ -1074,9 +1125,6 @@ int MVPClient::processGetChannelSchedule(UCHAR* data, int length) const char* thisEventSubTitle; const char* thisEventDescription; - ULONG constEventLength = sizeof(thisEventID) + sizeof(thisEventTime) + sizeof(thisEventDuration); - ULONG thisEventLength; - #if VDRVERSNUM < 10300 const cEventInfo *event; @@ -1119,66 +1167,38 @@ int MVPClient::processGetChannelSchedule(UCHAR* data, int length) if (!thisEventSubTitle) thisEventSubTitle = empty; if (!thisEventDescription) thisEventDescription = empty; - thisEventLength = constEventLength + strlen(thisEventTitle) + 1 + strlen(thisEventSubTitle) + 1 + strlen(thisEventDescription) + 1; - - log->log("Client", Log::DEBUG, "Done s1"); - - // now extend the buffer if necessary - if ((sendBufferUsed + thisEventLength) > sendBufferLength) - { - log->log("Client", Log::DEBUG, "Extending buffer"); - sendBufferLength += 100000; - UCHAR* temp = (UCHAR*)realloc(sendBuffer, sendBufferLength); - if (temp == NULL) - { - free(sendBuffer); - UCHAR sendBuffer2[8]; - *(ULONG*)&sendBuffer2[0] = htonl(4); - *(ULONG*)&sendBuffer2[4] = htonl(0); - tcp.sendPacket(sendBuffer2, 8); - log->log("Client", Log::DEBUG, "written 0 because failed to realloc packet"); - return 1; - } - sendBuffer = temp; - } - - log->log("Client", Log::DEBUG, "Done s2"); + rp->addULONG(thisEventID); + rp->addULONG(thisEventTime); + rp->addULONG(thisEventDuration); - *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventID); sendBufferUsed += sizeof(ULONG); - *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventTime); sendBufferUsed += sizeof(ULONG); - *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventDuration); sendBufferUsed += sizeof(ULONG); + rp->addString(thisEventTitle); + rp->addString(thisEventSubTitle); + rp->addString(thisEventDescription); - strcpy((char*)&sendBuffer[sendBufferUsed], thisEventTitle); sendBufferUsed += strlen(thisEventTitle) + 1; - strcpy((char*)&sendBuffer[sendBufferUsed], thisEventSubTitle); sendBufferUsed += strlen(thisEventSubTitle) + 1; - strcpy((char*)&sendBuffer[sendBufferUsed], thisEventDescription); sendBufferUsed += strlen(thisEventDescription) + 1; - - log->log("Client", Log::DEBUG, "Done s3 %lu", sendBufferUsed); + atLeastOneEvent = true; + log->log("Client", Log::DEBUG, "Done s3"); } log->log("Client", Log::DEBUG, "Got all event data"); - if (sendBufferUsed == sizeof(ULONG)) + if (!atLeastOneEvent) { - // No data - sendULONG(0); + rp->addULONG(0); log->log("Client", Log::DEBUG, "Written 0 because no data"); } - else - { - // Write the length into the first 4 bytes. It's sendBufferUsed - 4 because of the hole! - *(ULONG*)&sendBuffer[0] = htonl(sendBufferUsed - sizeof(ULONG)); - tcp.sendPacket(sendBuffer, sendBufferUsed); - log->log("Client", Log::DEBUG, "written %lu schedules packet", sendBufferUsed); - } - - free(sendBuffer); + + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + + log->log("Client", Log::DEBUG, "written schedules packet"); return 1; } #endif //VOMPSTANDALONE -int MVPClient::processConfigSave(UCHAR* buffer, int length) +int MVPClient::processConfigSave(UCHAR* buffer, int length, ResponsePacket* rp) { char* section = (char*)buffer; char* key = NULL; @@ -1206,17 +1226,21 @@ int MVPClient::processConfigSave(UCHAR* buffer, int length) log->log("Client", Log::DEBUG, "Config save: %s %s %s", section, key, value); if (config.setValueString(section, key, value)) { - sendULONG(1); + rp->addULONG(1); } else { - sendULONG(0); + rp->addULONG(0); } + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + return 1; } -int MVPClient::processConfigLoad(UCHAR* buffer, int length) +int MVPClient::processConfigLoad(UCHAR* buffer, int length, ResponsePacket* rp) { char* section = (char*)buffer; char* key = NULL; @@ -1234,1025 +1258,876 @@ int MVPClient::processConfigLoad(UCHAR* buffer, int length) if (value) { - UCHAR sendBuffer[4 + strlen(value) + 1]; - *(ULONG*)&sendBuffer[0] = htonl(strlen(value) + 1); - strcpy((char*)&sendBuffer[4], value); - tcp.sendPacket(sendBuffer, 4 + strlen(value) + 1); - + rp->addString(value); log->log("Client", Log::DEBUG, "Written config load packet"); delete[] value; } else { - UCHAR sendBuffer[8]; - *(ULONG*)&sendBuffer[0] = htonl(4); - *(ULONG*)&sendBuffer[4] = htonl(0); - tcp.sendPacket(sendBuffer, 8); - + rp->addULONG(0); log->log("Client", Log::DEBUG, "Written config load failed packet"); } + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + return 1; } -void MVPClient::cleanConfig() -{ - log->log("Client", Log::DEBUG, "Clean config"); - #ifndef VOMPSTANDALONE - cRecordings Recordings; - Recordings.Load(); - int numReturns; - int length; - char* resumes = config.getSectionKeyNames("ResumeData", numReturns, length); - char* position = resumes; - for(int k = 0; k < numReturns; k++) - { - log->log("Client", Log::DEBUG, "EXAMINING: %i %i %p %s", k, numReturns, position, position); +int MVPClient::processGetTimers(UCHAR* buffer, int length, ResponsePacket* rp) +{ + cTimer *timer; + int numTimers = Timers.Count(); - cRecording* recording = Recordings.GetByName(position); - if (!recording) - { - // doesn't exist anymore - log->log("Client", Log::DEBUG, "Found a recording that doesn't exist anymore"); - config.deleteValue("ResumeData", position); - } - else - { - log->log("Client", Log::DEBUG, "This recording still exists"); - } + rp->addULONG(numTimers); - position += strlen(position) + 1; - } + for (int i = 0; i < numTimers; i++) + { + timer = Timers.Get(i); - delete[] resumes; +#if VDRVERSNUM < 10300 + rp->addULONG(timer->Active()); +#else + rp->addULONG(timer->HasFlags(tfActive)); #endif -} - - - - - - -/* - event = Schedule->GetPresentEvent(); - - fprintf(f, "\n\nCurrent event\n\n"); - - fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", 0, event->GetEventID(), event->GetTime(), event->GetDuration()); - fprintf(f, "Event %i title = %s subtitle = %s\n", 0, event->GetTitle(), event->GetSubtitle()); - fprintf(f, "Event %i extendeddescription = %s\n", 0, event->GetExtendedDescription()); - fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", 0, event->IsFollowing(), event->IsPresent()); - - event = Schedule->GetFollowingEvent(); - - fprintf(f, "\n\nFollowing event\n\n"); - - fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", 0, event->GetEventID(), event->GetTime(), event->GetDuration()); - fprintf(f, "Event %i title = %s subtitle = %s\n", 0, event->GetTitle(), event->GetSubtitle()); - fprintf(f, "Event %i extendeddescription = %s\n", 0, event->GetExtendedDescription()); - fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", 0, event->IsFollowing(), event->IsPresent()); - - fprintf(f, "\n\n"); -*/ - -/* - fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", eventNumber, event->GetEventID(), event->GetTime(), event->GetDuration()); - fprintf(f, "Event %i title = %s subtitle = %s\n", eventNumber, event->GetTitle(), event->GetSubtitle()); - fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription()); - fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", eventNumber, event->IsFollowing(), event->IsPresent()); - - fprintf(f, "\n\n"); -*/ - -/* + rp->addULONG(timer->Recording()); + rp->addULONG(timer->Pending()); + rp->addULONG(timer->Priority()); + rp->addULONG(timer->Lifetime()); + rp->addULONG(timer->Channel()->Number()); + rp->addULONG(timer->StartTime()); + rp->addULONG(timer->StopTime()); + rp->addULONG(timer->Day()); + rp->addULONG(timer->WeekDays()); + rp->addString(timer->File()); + } + + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + + log->log("Client", Log::DEBUG, "Written timers list"); + return 1; +} -void MVPClient::test2() +int MVPClient::processSetTimer(UCHAR* buffer, int length, ResponsePacket* rp) { - FILE* f = fopen("/tmp/s.txt", "w"); + char* timerString = new char[strlen((char*)buffer) + 1]; + strcpy(timerString, (char*)buffer); #if VDRVERSNUM < 10300 - cMutexLock MutexLock; - const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock); -#else - cSchedulesLock MutexLock; - const cSchedules *Schedules = cSchedules::Schedules(MutexLock); -#endif - if (!Schedules) + // If this is VDR 1.2 the date part of the timer string must be reduced + // to just DD rather than YYYY-MM-DD + + int s = 0; // source + int d = 0; // destination + int c = 0; // count + while(c != 2) // copy up to date section, including the second ':' { - fprintf(f, "Schedules = NULL\n"); - fclose(f); - return; + timerString[d] = buffer[s]; + if (buffer[s] == ':') c++; + ++s; + ++d; } + // now it has copied up to the date section + c = 0; + while(c != 2) // waste YYYY-MM- + { + if (buffer[s] == '-') c++; + ++s; + } + // now source is at the DD + memcpy(&timerString[d], &buffer[s], length - s); + d += length - s; + timerString[d] = '\0'; - fprintf(f, "Schedules dump:\n"); - Schedules->Dump(f); - + log->log("Client", Log::DEBUG, "Timer string after 1.2 conversion:"); + log->log("Client", Log::DEBUG, "%s", timerString); - const cSchedule *Schedule; - int scheduleNumber = 0; +#endif - tChannelID tchid; - cChannel *thisChannel; - -#if VDRVERSNUM < 10300 - const cEventInfo *event; - int eventNumber = 0; -#else - const cEvent *event; -#endif - -// Schedule = Schedules->GetSchedule(channel->GetChannelID()); -// Schedule = Schedules->GetSchedule(); - Schedule = Schedules->First(); - if (!Schedule) - { - fprintf(f, "First Schedule = NULL\n"); - fclose(f); - return; - } - - while (Schedule) + cTimer *timer = new cTimer; + if (timer->Parse((char*)timerString)) { - fprintf(f, "Schedule #%i\n", scheduleNumber); - fprintf(f, "-------------\n\n"); - -#if VDRVERSNUM < 10300 - tchid = Schedule->GetChannelID(); -#else - tchid = Schedule->ChannelID(); -#endif - + cTimer *t = Timers.GetTimer(timer); + if (!t) + { + Timers.Add(timer); #if VDRVERSNUM < 10300 - fprintf(f, "ChannelID.ToString() = %s\n", tchid.ToString()); - fprintf(f, "NumEvents() = %i\n", Schedule->NumEvents()); + Timers.Save(); #else -// put the count at the end. + Timers.SetModified(); #endif - - thisChannel = Channels.GetByChannelID(tchid, true); - if (thisChannel) - { - fprintf(f, "Channel Number: %p %i\n", thisChannel, thisChannel->Number()); + rp->addULONG(0); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + return 1; } else { - fprintf(f, "thisChannel = NULL for tchid\n"); + rp->addULONG(1); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; } + } + else + { + rp->addULONG(2); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + } + delete timer; + return 1; +} -#if VDRVERSNUM < 10300 - for (eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++) +int MVPClient::processDeleteTimer(UCHAR* buffer, int length, ResponsePacket* rp) +{ + log->log("Client", Log::DEBUG, "Delete timer called"); + // get timer + + int position = 0; + + INT delChannel = ntohl(*(ULONG*)&buffer[position]); position += 4; + INT delWeekdays = ntohl(*(ULONG*)&buffer[position]); position += 4; + INT delDay = ntohl(*(ULONG*)&buffer[position]); position += 4; + INT delStart = ntohl(*(ULONG*)&buffer[position]); position += 4; + INT delStop = ntohl(*(ULONG*)&buffer[position]); position += 4; + + cTimer* ti = NULL; + for (ti = Timers.First(); ti; ti = Timers.Next(ti)) + { + if ( (ti->Channel()->Number() == delChannel) + && ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay))) + && (ti->StartTime() == delStart) + && (ti->StopTime() == delStop) ) + break; + } + + if (!ti) + { + rp->addULONG(4); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + return 1; + } + + if (!Timers.BeingEdited()) + { + if (!ti->Recording()) { - event = Schedule->GetEventNumber(eventNumber); - fprintf(f, "Event %i tableid = %i timestring = %s endtimestring = %s\n", eventNumber, event->GetTableID(), event->GetTimeString(), event->GetEndTimeString()); - fprintf(f, "Event %i date = %s isfollowing = %i ispresent = %i\n", eventNumber, event->GetDate(), event->IsFollowing(), event->IsPresent()); - fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription()); - fprintf(f, "Event %i subtitle = %s title = %s\n", eventNumber, event->GetSubtitle(), event->GetTitle()); - fprintf(f, "Event %i eventid = %u duration = %li time = %lu channelnumber = %i\n", eventNumber, event->GetEventID(), event->GetDuration(), event->GetTime(), event->GetChannelNumber()); - fprintf(f, "Event %u dump:\n", eventNumber); - event->Dump(f); - fprintf(f, "\n\n"); - } -#else -// This whole section needs rewriting to walk the list. - event = Schedule->Events()->First(); - while (event) { - event = Schedule->Events()->Next(event); + Timers.Del(ti); + Timers.SetModified(); + rp->addULONG(10); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + return 1; } -#endif - - - fprintf(f, "\nDump from object:\n"); - Schedule->Dump(f); - fprintf(f, "\nEND\n"); - - - - - - - - - - fprintf(f, "End of current Schedule\n\n\n"); - - Schedule = (const cSchedule *)Schedules->Next(Schedule); - scheduleNumber++; + else + { + log->log("Client", Log::ERR, "Unable to delete timer - timer is running"); + rp->addULONG(3); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + return 1; + } } - - fclose(f); + else + { + log->log("Client", Log::ERR, "Unable to delete timer - timers being edited at VDR"); + rp->addULONG(1); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + return 1; + } } +int MVPClient::processGetRecInfo(UCHAR* data, int length, ResponsePacket* rp) +{ + // data is a pointer to the fileName string + cRecordings Recordings; + Recordings.Load(); // probably have to do this -*/ - + cRecording *recording = Recordings.GetByName((char*)data); + time_t timerStart = 0; + time_t timerStop = 0; + char* summary = NULL; + ULONG resumePoint = 0; -/* - const cEventInfo *GetPresentEvent(void) const; - const cEventInfo *GetFollowingEvent(void) const; - const cEventInfo *GetEvent(unsigned short uEventID, time_t tTime = 0) const; - const cEventInfo *GetEventAround(time_t tTime) const; - const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); } + if (!recording) + { + log->log("Client", Log::ERR, "GetRecInfo found no recording"); + rp->addULONG(0); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + return 1; + } + /* Return packet: + 4 bytes: start time for timer + 4 bytes: end time for timer + 4 bytes: resume point + string: summary + 4 bytes: num components + { + 1 byte: stream + 1 byte: type + string: language + string: description + } - const unsigned char GetTableID(void) const; - const char *GetTimeString(void) const; - const char *GetEndTimeString(void) const; - const char *GetDate(void) const; - bool IsFollowing(void) const; - bool IsPresent(void) const; - const char *GetExtendedDescription(void) const; - const char *GetSubtitle(void) const; - const char *GetTitle(void) const; - unsigned short GetEventID(void) const; - long GetDuration(void) const; - time_t GetTime(void) const; - tChannelID GetChannelID(void) const; - int GetChannelNumber(void) const { return nChannelNumber; } - void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const' - void Dump(FILE *f, const char *Prefix = "") const; + */ -*/ + // Get current timer + cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName()); + if (rc) + { + timerStart = rc->Timer()->StartTime(); + timerStop = rc->Timer()->StopTime(); + log->log("Client", Log::DEBUG, "GRI: RC: %lu %lu", timerStart, timerStop); + } -/* -void MVPClient::test(int channelNumber) -{ - FILE* f = fopen("/tmp/test.txt", "w"); + rp->addULONG(timerStart); + rp->addULONG(timerStop); - cMutexLock MutexLock; - const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock); + // Get resume point - if (!Schedules) + char* value = config.getValueString("ResumeData", (char*)data); + if (value) { - fprintf(f, "Schedules = NULL\n"); - fclose(f); - return; + resumePoint = strtoul(value, NULL, 10); + delete[] value; } + log->log("Client", Log::DEBUG, "GRI: RP: %lu", resumePoint); - fprintf(f, "Schedules dump:\n"); -// Schedules->Dump(f); + rp->addULONG(resumePoint); - const cSchedule *Schedule; - cChannel *thisChannel; - const cEventInfo *event; - thisChannel = channelFromNumber(channelNumber); - if (!thisChannel) + // Get summary + +#if VDRVERSNUM < 10300 + summary = (char*)recording->Summary(); +#else + const cRecordingInfo *Info = recording->Info(); + summary = (char*)Info->ShortText(); + if (isempty(summary)) summary = (char*)Info->Description(); +#endif + log->log("Client", Log::DEBUG, "GRI: S: %s", summary); + if (summary) { - fprintf(f, "thisChannel = NULL\n"); - fclose(f); - return; + rp->addString(summary); } - - Schedule = Schedules->GetSchedule(thisChannel->GetChannelID()); -// Schedule = Schedules->GetSchedule(); -// Schedule = Schedules->First(); - if (!Schedule) + else { - fprintf(f, "First Schedule = NULL\n"); - fclose(f); - return; + rp->addString(""); } - fprintf(f, "NumEvents() = %i\n\n", Schedule->NumEvents()); + // Get channels - // For some channels VDR seems to pick a random point in time to - // start dishing out events, but they are in order - // at some point in the list the time snaps to the current event +#if VDRVERSNUM < 10300 + // Send 0 for numchannels - this signals the client this info is not available + rp->addULONG(0); +#else + const cComponents* components = Info->Components(); + log->log("Client", Log::DEBUG, "GRI: D1: %p", components); - for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++) + if (!components) { - event = Schedule->GetEventNumber(eventNumber); - fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", eventNumber, event->GetEventID(), event->GetTime(), event->GetDuration()); - fprintf(f, "Event %i title = %s subtitle = %s\n", eventNumber, event->GetTitle(), event->GetSubtitle()); - fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription()); - fprintf(f, "\n\n"); + rp->addULONG(0); } + else + { + rp->addULONG(components->NumComponents()); + + tComponent* component; + for (int i = 0; i < components->NumComponents(); i++) + { + component = components->Component(i); - fprintf(f, "\nEND\n"); + log->log("Client", Log::DEBUG, "GRI: C: %i %u %u %s %s", i, component->stream, component->type, component->language, component->description); + + rp->addUCHAR(component->stream); + rp->addUCHAR(component->type); - fclose(f); -} + if (component->language) + { + rp->addString(component->language); + } + else + { + rp->addString(""); + } + if (component->description) + { + rp->addString(component->description); + } + else + { + rp->addString(""); + } + } + } -*/ +#endif + // Done. send it + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; -/* + log->log("Client", Log::DEBUG, "Written getrecinfo"); + return 1; +} -Right, so -Schedules = the collection of all the Schedule objects -Schedule = One schedule, contants all the events for a channel -Event = One programme -Want: +// FIXME obselete -Event ID -Time -Duration -Title -Subtitle (used for "Programmes resume at ...") -Description +int MVPClient::processReScanRecording(UCHAR* data, int length, ResponsePacket* rp) +{ + if (!recplayer) + { + log->log("Client", Log::DEBUG, "Rescan recording called when no recording being played!"); + return 0; + } -IsPresent ? easy to work out tho. Oh it doesn't always work + recplayer->scan(); -*/ + rp->addULLONG(recplayer->getLengthBytes()); + rp->addULONG(recplayer->getLengthFrames()); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + log->log("Client", Log::DEBUG, "Rescan recording, wrote new length to client"); + return 1; +} -/* -void MVPClient::test2() +// FIXME without client calling rescan, getblock wont work even tho more data is avail + + +int MVPClient::processGetMarks(UCHAR* data, int length, ResponsePacket* rp) { - log->log("-", Log::DEBUG, "Timers List"); + // data is a pointer to the fileName string - for (int i = 0; i < Timers.Count(); i++) + cMarks Marks; + cRecordings Recordings; + Recordings.Load(); // probably have to do this + + cRecording *recording = Recordings.GetByName((char*)data); + + log->log("Client", Log::DEBUG, "recording pointer %p", recording); + + if (recording) { - cTimer *timer = Timers.Get(i); - //Reply(i < Timers.Count() - 1 ? -250 : 250, "%d %s", timer->Index() + 1, timer->ToText()); - log->log("-", Log::DEBUG, "i=%i count=%i index=%d", i, Timers.Count(), timer->Index() + 1); -#if VDRVERSNUM < 10300 - 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()); -#else - 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()); -#endif - log->log("-", Log::DEBUG, "channel=%i file=%s summary=%s", timer->Channel()->Number(), timer->File(), timer->Summary()); - log->log("-", Log::DEBUG, ""); + Marks.Load(recording->FileName()); + if (Marks.Count()) + { + for (const cMark *m = Marks.First(); m; m = Marks.Next(m)) + { + log->log("Client", Log::DEBUG, "found Mark %i", m->position); + + rp->addULONG(m->position); + } + } + else + { + log->log("Client", Log::DEBUG, "no marks found, sending 0-mark"); + rp->addULONG(0); + } } - // asprintf(&buffer, "%d:%s:%s :%04d:%04d:%d:%d:%s:%s\n", -// active, (UseChannelID ? Channel()->GetChannelID().ToString() : itoa(Channel()->Number())), -// PrintDay(day, firstday), start, stop, priority, lifetime, file, summary ? summary : ""); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + + log->log("Client", Log::DEBUG, "Written Marks list"); + + return 1; } -*/ -/* -Active seems to be a bool - whether the timer should be done or not. If set to inactive it stays around after its time -recording is a bool, 0 for not currently recording, 1 for currently recording -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 -*/ +#endif //VOMPSTANDALONE -#ifndef VOMPSTANDALONE +/** + * media List Request: + * 4 length + * 4 VDR_GETMEDIALIST + * 4 flags (currently unused) + * n dirname + * n+1 0 + * Media List response: + * 4 length + * 4 VDR_ + * 4 numentries + * per entry: + * 4 media type + * 4 time stamp + * 4 flags + * 4 strlen (incl. 0 Byte) + * string + * 0 +*/ -int MVPClient::processGetTimers(UCHAR* buffer, int length) +int MVPClient::processGetMediaList(UCHAR* data, int length, ResponsePacket* rp) { - UCHAR* sendBuffer = new UCHAR[50000]; // FIXME hope this is enough - int count = 4; // leave space for the packet length + if (length < 4) { + log->log("Client", Log::ERR, "getMediaList packet too short %d", length); + return 0; + } + char * dirname=NULL; + if (length > 4) { + //we have a dirname provided + dirname=(char *)&data[4]; + log->log("Client", Log::DEBUG, "getMediaList for %s", dirname); + } - const char* fileName; - cTimer *timer; - int numTimers = Timers.Count(); + MediaList * ml=MediaList::readList(baseConfig,dirname); + if (ml == NULL) { + log->log("Client", Log::ERR, "getMediaList returned NULL"); + return 0; + } - *(ULONG*)&sendBuffer[count] = htonl(numTimers); count += 4; + //response code (not yet set) + rp->addULONG(0); - for (int i = 0; i < numTimers; i++) - { - if (count > 49000) break; + //numentries + rp->addULONG(ml->size()); + + for (MediaList::iterator nm=ml->begin(); nmend(); nm++) + { + Media *m=*nm; + log->log("Client", Log::DEBUG, "found media entry %s, type=%d",m->getFilename(),m->getType()); + rp->addULONG(m->getType()); + //time stamp + rp->addULONG(m->getTime()); + //flags + rp->addULONG(0); + int len=strlen(m->getFilename()); + //strlen + rp->addULONG(len+1); + rp->addString(m->getFilename()); + } + delete ml; - timer = Timers.Get(i); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + + log->log("Client", Log::DEBUG, "Written Media list"); + return 1; +} -#if VDRVERSNUM < 10300 - *(ULONG*)&sendBuffer[count] = htonl(timer->Active()); count += 4; -#else - *(ULONG*)&sendBuffer[count] = htonl(timer->HasFlags(tfActive)); count += 4; -#endif - *(ULONG*)&sendBuffer[count] = htonl(timer->Recording()); count += 4; - *(ULONG*)&sendBuffer[count] = htonl(timer->Pending()); count += 4; - *(ULONG*)&sendBuffer[count] = htonl(timer->Priority()); count += 4; - *(ULONG*)&sendBuffer[count] = htonl(timer->Lifetime()); count += 4; - *(ULONG*)&sendBuffer[count] = htonl(timer->Channel()->Number()); count += 4; - *(ULONG*)&sendBuffer[count] = htonl(timer->StartTime()); count += 4; - *(ULONG*)&sendBuffer[count] = htonl(timer->StopTime()); count += 4; - *(ULONG*)&sendBuffer[count] = htonl(timer->Day()); count += 4; - *(ULONG*)&sendBuffer[count] = htonl(timer->WeekDays()); count += 4; +/** + * get image Request: + * 4 flags (currently unused) + * 4 x size + * 4 y size + * n filename + * n+1 0 + * get image response: + * 4 length + * 4 VDR_GETIMAGE + * 4 len of image +*/ - fileName = timer->File(); - strcpy((char*)&sendBuffer[count], fileName); - count += strlen(fileName) + 1; +int MVPClient::processGetPicture(UCHAR* data, int length, ResponsePacket* rp) +{ + if (length < 12) { + log->log("Client", Log::ERR, "getPicture packet too short %d", length); + return 0; } + if (imageFile) { + fclose(imageFile); + imageFile=NULL; + } + char * filename=NULL; + if (length > 12) { + //we have a dirname provided + filename=(char *)&data[12]; + log->log("Client", Log::DEBUG, "getPicture %s", filename); + } + else { + log->log("Client", Log::ERR, "getPicture empty filename"); + } + if (filename) { + imageFile=fopen(filename,"r"); + if (!imageFile) log->log("Client", Log::ERR, "getPicture unable to open %s",filename); + } + int size=0; + if (imageFile) { + struct stat st; + if ( fstat(fileno(imageFile),&st) == 0) size=st.st_size; + } + //response code (not yet set) + rp->addULONG(31); + //size + rp->addULONG(size); - *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field - - log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0])); + log->log("Client", Log::DEBUG, "getPicture size %u", size); -//tcp.dump(sendBuffer, count); + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; - tcp.sendPacket(sendBuffer, count); - delete[] sendBuffer; - log->log("Client", Log::DEBUG, "Written timers list"); + log->log("Client", Log::DEBUG, "Written getPicture"); return 1; } -int MVPClient::processSetTimer(UCHAR* buffer, int length) + +int MVPClient::processGetImageBlock(UCHAR* data, int length, ResponsePacket* rp) { - char* timerString = new char[strlen((char*)buffer) + 1]; - strcpy(timerString, (char*)buffer); + if (!imageFile) + { + log->log("Client", Log::DEBUG, "Get image block called when no image active"); + return 0; + } -#if VDRVERSNUM < 10300 + ULLONG position = ntohll(*(ULLONG*)data); + data += sizeof(ULLONG); + ULONG amount = ntohl(*(ULONG*)data); - // If this is VDR 1.2 the date part of the timer string must be reduced - // to just DD rather than YYYY-MM-DD + log->log("Client", Log::DEBUG, "getImageblock pos = %llu length = %lu", position, amount); - int s = 0; // source - int d = 0; // destination - int c = 0; // count - while(c != 2) // copy up to date section, including the second ':' + UCHAR sendBuffer[amount]; + ULONG amountReceived = 0; // compiler moan. + ULLONG cpos=ftell(imageFile); + if (position != cpos) { + fseek(imageFile,position-cpos,SEEK_CUR); + } + if (position != (ULLONG)ftell(imageFile)) { + log->log("Client", Log::DEBUG, "getImageblock pos = %llu not available", position); + } + else { + amountReceived=fread(&sendBuffer[0],1,amount,imageFile); + } + + if (!amountReceived) { - timerString[d] = buffer[s]; - if (buffer[s] == ':') c++; - ++s; - ++d; + rp->addULONG(0); + log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0"); } - // now it has copied up to the date section - c = 0; - while(c != 2) // waste YYYY-MM- + else { - if (buffer[s] == '-') c++; - ++s; + rp->copyin(sendBuffer, amount); + log->log("Client", Log::DEBUG, "written %lu", amountReceived); } - // now source is at the DD - memcpy(&timerString[d], &buffer[s], length - s); - d += length - s; - timerString[d] = '\0'; + + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; - log->log("Client", Log::DEBUG, "Timer string after 1.2 conversion:"); - log->log("Client", Log::DEBUG, "%s", timerString); - -#endif - - cTimer *timer = new cTimer; - if (timer->Parse((char*)timerString)) - { - cTimer *t = Timers.GetTimer(timer); - if (!t) - { - Timers.Add(timer); -#if VDRVERSNUM < 10300 - Timers.Save(); -#else - Timers.SetModified(); -#endif - sendULONG(0); - return 1; - } - else - { - sendULONG(1); - } - } - else - { - sendULONG(2); - } - delete timer; return 1; } -#endif //VOMPSTANDALONE -void MVPClient::incClients() -{ - pthread_mutex_lock(&threadClientMutex); - MVPClient::nr_clients++; - pthread_mutex_unlock(&threadClientMutex); -} -void MVPClient::decClients() -{ - pthread_mutex_lock(&threadClientMutex); - MVPClient::nr_clients--; - pthread_mutex_unlock(&threadClientMutex); -} -int MVPClient::getNrClients() -{ - int nrClients; - pthread_mutex_lock(&threadClientMutex); - nrClients = MVPClient::nr_clients; - pthread_mutex_unlock(&threadClientMutex); - return nrClients; -} -#ifndef VOMPSTANDALONE -int MVPClient::processGetRecInfo(UCHAR* data, int length) -{ - // data is a pointer to the fileName string - cRecordings Recordings; - Recordings.Load(); // probably have to do this - cRecording *recording = Recordings.GetByName((char*)data); - time_t timerStart = 0; - time_t timerStop = 0; - char* summary = NULL; - ULONG resumePoint = 0; - if (!recording) - { - log->log("Client", Log::ERR, "GetRecInfo found no recording"); - sendULONG(0); - return 1; - } - ULONG sendBufferSize = 10000; - UCHAR* sendBuffer = (UCHAR*)malloc(sendBufferSize); - ULONG pos = 4; // leave first 4 bytes for size field +/* + event = Schedule->GetPresentEvent(); + fprintf(f, "\n\nCurrent event\n\n"); - /* Return packet: - 4 bytes: start time for timer - 4 bytes: end time for timer - 4 bytes: resume point - string: summary - 4 bytes: num components - { - 1 byte: stream - 1 byte: type - string: language - string: description - } + fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", 0, event->GetEventID(), event->GetTime(), event->GetDuration()); + fprintf(f, "Event %i title = %s subtitle = %s\n", 0, event->GetTitle(), event->GetSubtitle()); + fprintf(f, "Event %i extendeddescription = %s\n", 0, event->GetExtendedDescription()); + fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", 0, event->IsFollowing(), event->IsPresent()); - */ + event = Schedule->GetFollowingEvent(); - // Get current timer + fprintf(f, "\n\nFollowing event\n\n"); - cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName()); - if (rc) - { - timerStart = rc->Timer()->StartTime(); - timerStop = rc->Timer()->StopTime(); - log->log("Client", Log::DEBUG, "GRI: RC: %lu %lu", timerStart, timerStop); - } + fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", 0, event->GetEventID(), event->GetTime(), event->GetDuration()); + fprintf(f, "Event %i title = %s subtitle = %s\n", 0, event->GetTitle(), event->GetSubtitle()); + fprintf(f, "Event %i extendeddescription = %s\n", 0, event->GetExtendedDescription()); + fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", 0, event->IsFollowing(), event->IsPresent()); - *(time_t*)&sendBuffer[pos] = htonl(timerStart); pos += 4; - *(time_t*)&sendBuffer[pos] = htonl(timerStop); pos += 4; + fprintf(f, "\n\n"); - // Get resume point + fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", eventNumber, event->GetEventID(), event->GetTime(), event->GetDuration()); + fprintf(f, "Event %i title = %s subtitle = %s\n", eventNumber, event->GetTitle(), event->GetSubtitle()); + fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription()); + fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", eventNumber, event->IsFollowing(), event->IsPresent()); - char* value = config.getValueString("ResumeData", (char*)data); - if (value) - { - resumePoint = strtoul(value, NULL, 10); - delete[] value; - } - log->log("Client", Log::DEBUG, "GRI: RP: %lu", resumePoint); + fprintf(f, "\n\n"); - *(ULONG*)&sendBuffer[pos] = htonl(resumePoint); pos += 4; - // Get summary +void MVPClient::test2() +{ + FILE* f = fopen("/tmp/s.txt", "w"); #if VDRVERSNUM < 10300 - summary = (char*)recording->Summary(); + cMutexLock MutexLock; + const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock); #else - const cRecordingInfo *Info = recording->Info(); - summary = (char*)Info->ShortText(); - if (isempty(summary)) summary = (char*)Info->Description(); + cSchedulesLock MutexLock; + const cSchedules *Schedules = cSchedules::Schedules(MutexLock); #endif - log->log("Client", Log::DEBUG, "GRI: S: %s", summary); - if (summary) - { - // memory insanity... - if ((sendBufferSize - pos) < (strlen(summary) + 500)) // random - { - UCHAR* newBuffer = (UCHAR*)realloc(sendBuffer, sendBufferSize + strlen(summary) + 10000); - if (newBuffer) - { - sendBuffer = newBuffer; - sendBufferSize += strlen(summary) + 10000; - } - else - { - free(sendBuffer); - sendULONG(0); - return 1; - } - } - strcpy((char*)&sendBuffer[pos], summary); - pos += strlen(summary) + 1; - } - else + if (!Schedules) { - strcpy((char*)&sendBuffer[pos], ""); - pos += 1; + fprintf(f, "Schedules = NULL\n"); + fclose(f); + return; } + fprintf(f, "Schedules dump:\n"); + Schedules->Dump(f); - // Get channels -#if VDRVERSNUM < 10300 + const cSchedule *Schedule; + int scheduleNumber = 0; - // Send 0 for numchannels - this signals the client this info is not available - *(ULONG*)&sendBuffer[pos] = 0; pos += 4; + tChannelID tchid; + cChannel *thisChannel; +#if VDRVERSNUM < 10300 + const cEventInfo *event; + int eventNumber = 0; #else - const cComponents* components = Info->Components(); - - log->log("Client", Log::DEBUG, "GRI: D1: %p", components); + const cEvent *event; +#endif - if (!components) +// Schedule = Schedules->GetSchedule(channel->GetChannelID()); +// Schedule = Schedules->GetSchedule(); + Schedule = Schedules->First(); + if (!Schedule) { - *(ULONG*)&sendBuffer[pos] = htonl(0); pos += 4; + fprintf(f, "First Schedule = NULL\n"); + fclose(f); + return; } - else - { - *(ULONG*)&sendBuffer[pos] = htonl(components->NumComponents()); pos += 4; - - tComponent* component; - for (int i = 0; i < components->NumComponents(); i++) - { - component = components->Component(i); - // memory insanity... - ULONG extraNeeded = 2 + (component->language ? strlen(component->language) : 0) - + (component->description ? strlen(component->description) : 0) + 2; + while (Schedule) + { + fprintf(f, "Schedule #%i\n", scheduleNumber); + fprintf(f, "-------------\n\n"); - if ((sendBufferSize - pos) < extraNeeded) - { - UCHAR* newBuffer = (UCHAR*)realloc(sendBuffer, sendBufferSize + extraNeeded + 10000); - if (newBuffer) - { - sendBuffer = newBuffer; - sendBufferSize += extraNeeded + 10000; - } - else - { - free(sendBuffer); - sendULONG(0); - return 1; - } - } +#if VDRVERSNUM < 10300 + tchid = Schedule->GetChannelID(); +#else + tchid = Schedule->ChannelID(); +#endif - log->log("Client", Log::DEBUG, "GRI: C: %i %u %u %s %s", i, component->stream, component->type, component->language, component->description); - sendBuffer[pos] = component->stream; pos += 1; - sendBuffer[pos] = component->type; pos += 1; - if (component->language) - { - strcpy((char*)&sendBuffer[pos], component->language); - pos += strlen(component->language) + 1; - } - else - { - strcpy((char*)&sendBuffer[pos], ""); - pos += 1; - } - if (component->description) - { - strcpy((char*)&sendBuffer[pos], component->description); - pos += strlen(component->description) + 1; - } - else - { - strcpy((char*)&sendBuffer[pos], ""); - pos += 1; - } +#if VDRVERSNUM < 10300 + fprintf(f, "ChannelID.ToString() = %s\n", tchid.ToString()); + fprintf(f, "NumEvents() = %i\n", Schedule->NumEvents()); +#else +// put the count at the end. +#endif + thisChannel = Channels.GetByChannelID(tchid, true); + if (thisChannel) + { + fprintf(f, "Channel Number: %p %i\n", thisChannel, thisChannel->Number()); + } + else + { + fprintf(f, "thisChannel = NULL for tchid\n"); } - } +#if VDRVERSNUM < 10300 + for (eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++) + { + event = Schedule->GetEventNumber(eventNumber); + fprintf(f, "Event %i tableid = %i timestring = %s endtimestring = %s\n", eventNumber, event->GetTableID(), event->GetTimeString(), event->GetEndTimeString()); + fprintf(f, "Event %i date = %s isfollowing = %i ispresent = %i\n", eventNumber, event->GetDate(), event->IsFollowing(), event->IsPresent()); + fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription()); + fprintf(f, "Event %i subtitle = %s title = %s\n", eventNumber, event->GetSubtitle(), event->GetTitle()); + fprintf(f, "Event %i eventid = %u duration = %li time = %lu channelnumber = %i\n", eventNumber, event->GetEventID(), event->GetDuration(), event->GetTime(), event->GetChannelNumber()); + fprintf(f, "Event %u dump:\n", eventNumber); + event->Dump(f); + fprintf(f, "\n\n"); + } +#else +// This whole section needs rewriting to walk the list. + event = Schedule->Events()->First(); + while (event) { + event = Schedule->Events()->Next(event); + } #endif - // Done. send it - - *(ULONG*)&sendBuffer[0] = htonl(pos - 4); // -4 : take off the size field - - log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0])); - - tcp.sendPacket(sendBuffer, pos); - delete[] sendBuffer; - log->log("Client", Log::DEBUG, "Written getrecinfo"); - return 1; -} + fprintf(f, "\nDump from object:\n"); + Schedule->Dump(f); + fprintf(f, "\nEND\n"); -// FIXME obselete + fprintf(f, "End of current Schedule\n\n\n"); -int MVPClient::processReScanRecording(UCHAR* data, int length) -{ - if (!rp) - { - log->log("Client", Log::DEBUG, "Rescan recording called when no recording being played!"); - return 0; + Schedule = (const cSchedule *)Schedules->Next(Schedule); + scheduleNumber++; } - rp->scan(); + fclose(f); +} - UCHAR sendBuffer[16]; - *(ULONG*)&sendBuffer[0] = htonl(12); - *(ULLONG*)&sendBuffer[4] = htonll(rp->getLengthBytes()); - *(ULONG*)&sendBuffer[12] = htonl(rp->getLengthFrames()); - tcp.sendPacket(sendBuffer, 16); - log->log("Client", Log::DEBUG, "Rescan recording, wrote new length to client"); - return 1; -} - -// FIXME without client calling rescan, getblock wont work even tho more data is avail + const cEventInfo *GetPresentEvent(void) const; + const cEventInfo *GetFollowingEvent(void) const; + const cEventInfo *GetEvent(unsigned short uEventID, time_t tTime = 0) const; + const cEventInfo *GetEventAround(time_t tTime) const; + const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); } -int MVPClient::processGetMarks(UCHAR* data, int length) -{ - // data is a pointer to the fileName string - - UCHAR* sendBuffer = new UCHAR[50000]; // FIXME hope this is enough - int count = 4; // leave space for the packet length + const unsigned char GetTableID(void) const; + const char *GetTimeString(void) const; + const char *GetEndTimeString(void) const; + const char *GetDate(void) const; + bool IsFollowing(void) const; + bool IsPresent(void) const; + const char *GetExtendedDescription(void) const; + const char *GetSubtitle(void) const; + const char *GetTitle(void) const; + unsigned short GetEventID(void) const; + long GetDuration(void) const; + time_t GetTime(void) const; + tChannelID GetChannelID(void) const; + int GetChannelNumber(void) const { return nChannelNumber; } + void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const' + void Dump(FILE *f, const char *Prefix = "") const; - cMarks Marks; - cRecordings Recordings; - Recordings.Load(); // probably have to do this - cRecording *recording = Recordings.GetByName((char*)data); +void MVPClient::test(int channelNumber) +{ + FILE* f = fopen("/tmp/test.txt", "w"); - log->log("Client", Log::DEBUG, "recording pointer %p", recording); + cMutexLock MutexLock; + const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock); - if (recording) + if (!Schedules) { - Marks.Load(recording->FileName()); - if (Marks.Count()) - { - for (const cMark *m = Marks.First(); m; m = Marks.Next(m)) - { - log->log("Client", Log::DEBUG, "found Mark %i", m->position); - - if (count > 49000) break; - *(ULONG*)&sendBuffer[count] = htonl(m->position); - count += 4; - } - } - else - { - log->log("Client", Log::DEBUG, "no marks found, sending 0-mark"); - *(ULONG*)&sendBuffer[count] = htonl(0); - count += 4; - } + fprintf(f, "Schedules = NULL\n"); + fclose(f); + return; } - *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field + fprintf(f, "Schedules dump:\n"); +// Schedules->Dump(f); - log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0])); + const cSchedule *Schedule; + cChannel *thisChannel; + const cEventInfo *event; - tcp.sendPacket(sendBuffer, count); - delete[] sendBuffer; - log->log("Client", Log::DEBUG, "Written Marks list"); + thisChannel = channelFromNumber(channelNumber); + if (!thisChannel) + { + fprintf(f, "thisChannel = NULL\n"); + fclose(f); + return; + } - return 1; -} + Schedule = Schedules->GetSchedule(thisChannel->GetChannelID()); +// Schedule = Schedules->GetSchedule(); +// Schedule = Schedules->First(); + if (!Schedule) + { + fprintf(f, "First Schedule = NULL\n"); + fclose(f); + return; + } -#endif //VOMPSTANDALONE + fprintf(f, "NumEvents() = %i\n\n", Schedule->NumEvents()); + // For some channels VDR seems to pick a random point in time to + // start dishing out events, but they are in order + // at some point in the list the time snaps to the current event -/** - * media List Request: - * 4 length - * 4 VDR_GETMEDIALIST - * 4 flags (currently unused) - * n dirname - * n+1 0 - * Media List response: - * 4 length - * 4 VDR_ - * 4 numentries - * per entry: - * 4 media type - * 4 time stamp - * 4 flags - * 4 strlen (incl. 0 Byte) - * string - * 0 -*/ -#define MLISTBUF 500000 -int MVPClient::processGetMediaList(UCHAR* data, int length) -{ - if (length < 4) { - log->log("Client", Log::ERR, "getMediaList packet too short %d", length); - return 0; - } - char * dirname=NULL; - if (length > 4) { - //we have a dirname provided - dirname=(char *)&data[4]; - log->log("Client", Log::DEBUG, "getMediaList for %s", dirname); - } - UCHAR* sendBuffer = new UCHAR[MLISTBUF]; // FIXME hope this is enough - int count = 4; // leave space for the header - MediaList * ml=MediaList::readList(baseConfig,dirname); - if (ml == NULL) { - log->log("Client", Log::ERR, "getMediaList returned NULL"); - return 0; - } - //response code (not yet set) - *(ULONG*)&sendBuffer[count] = htonl(0); - count += 4; - //numentries - *(ULONG*)&sendBuffer[count] = htonl(ml->size()); - count += 4; - for (MediaList::iterator nm=ml->begin();nmend() && count < (MLISTBUF-1000);nm++) { - Media *m=*nm; - log->log("Client", Log::DEBUG, "found media entry %s, type=%d",m->getFilename(),m->getType()); - *(ULONG*)&sendBuffer[count] = htonl(m->getType()); - count += 4; - //time stamp - *(ULONG*)&sendBuffer[count] = htonl(m->getTime()); - count += 4; - //flags - *(ULONG*)&sendBuffer[count] = htonl(0); - count += 4; - int len=strlen(m->getFilename()); - //strlen - *(ULONG*)&sendBuffer[count] = htonl(len+1); - count += 4; - //should have a check for strlen > 1000... - strcpy((char *)&sendBuffer[count],m->getFilename()); - count+=len+1; + for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++) + { + event = Schedule->GetEventNumber(eventNumber); + fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", eventNumber, event->GetEventID(), event->GetTime(), event->GetDuration()); + fprintf(f, "Event %i title = %s subtitle = %s\n", eventNumber, event->GetTitle(), event->GetSubtitle()); + fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription()); + fprintf(f, "\n\n"); } - delete ml; - *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field + fprintf(f, "\nEND\n"); - log->log("Client", Log::DEBUG, "getMediaList size %u", ntohl(*(ULONG*)&sendBuffer[0])); + fclose(f); +} - tcp.sendPacket(sendBuffer, count); - delete[] sendBuffer; - log->log("Client", Log::DEBUG, "Written Media list"); - return 1; -} -/** - * get image Request: - * 4 flags (currently unused) - * 4 x size - * 4 y size - * n filename - * n+1 0 - * get image response: - * 4 length - * 4 VDR_GETIMAGE - * 4 len of image -*/ -#define MLISTBUF 500000 -int MVPClient::processGetPicture(UCHAR* data, int length) -{ - if (length < 12) { - log->log("Client", Log::ERR, "getPicture packet too short %d", length); - return 0; - } - if (imageFile) { - fclose(imageFile); - imageFile=NULL; - } - char * filename=NULL; - if (length > 12) { - //we have a dirname provided - filename=(char *)&data[12]; - log->log("Client", Log::DEBUG, "getPicture %s", filename); - } - else { - log->log("Client", Log::ERR, "getPicture empty filename"); - } - if (filename) { - imageFile=fopen(filename,"r"); - if (!imageFile) log->log("Client", Log::ERR, "getPicture unable to open %s",filename); - } - int size=0; - if (imageFile) { - struct stat st; - if ( fstat(fileno(imageFile),&st) == 0) size=st.st_size; - } - UCHAR* sendBuffer = new UCHAR[12]; - int count = 4; // leave space for the header - //response code (not yet set) - *(ULONG*)&sendBuffer[count] = htonl(31); - count += 4; - //size - *(ULONG*)&sendBuffer[count] = htonl(size); - count += 4; - *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field - log->log("Client", Log::DEBUG, "getPicture size %u", size); +Right, so - tcp.sendPacket(sendBuffer, count); - delete[] sendBuffer; - log->log("Client", Log::DEBUG, "Written Media list"); +Schedules = the collection of all the Schedule objects +Schedule = One schedule, contants all the events for a channel +Event = One programme - return 1; -} +Want: -int MVPClient::processGetImageBlock(UCHAR* data, int length) -{ - if (!imageFile) - { - log->log("Client", Log::DEBUG, "Get image block called when no image active"); - return 0; - } +Event ID +Time +Duration +Title +Subtitle (used for "Programmes resume at ...") +Description - ULLONG position = ntohll(*(ULLONG*)data); - data += sizeof(ULLONG); - ULONG amount = ntohl(*(ULONG*)data); +IsPresent ? easy to work out tho. Oh it doesn't always work - log->log("Client", Log::DEBUG, "getImageblock pos = %llu length = %lu", position, amount); - UCHAR sendBuffer[amount + 4]; - ULONG amountReceived = 0; // compiler moan. - ULLONG cpos=ftell(imageFile); - if (position != cpos) { - fseek(imageFile,position-cpos,SEEK_CUR); - } - if (position != (ULLONG)ftell(imageFile)) { - log->log("Client", Log::DEBUG, "getImageblock pos = %llu not available", position); - } - else { - amountReceived=fread(&sendBuffer[4],1,amount,imageFile); - } +void MVPClient::test2() +{ + log->log("-", Log::DEBUG, "Timers List"); - if (!amountReceived) - { - sendULONG(0); - log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0"); - } - else + for (int i = 0; i < Timers.Count(); i++) { - *(ULONG*)&sendBuffer[0] = htonl(amountReceived); - tcp.sendPacket(sendBuffer, amountReceived + 4); - log->log("Client", Log::DEBUG, "written ok %lu", amountReceived); + cTimer *timer = Timers.Get(i); + //Reply(i < Timers.Count() - 1 ? -250 : 250, "%d %s", timer->Index() + 1, timer->ToText()); + log->log("-", Log::DEBUG, "i=%i count=%i index=%d", i, Timers.Count(), timer->Index() + 1); +#if VDRVERSNUM < 10300 + 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()); +#else + 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()); +#endif + log->log("-", Log::DEBUG, "channel=%i file=%s summary=%s", timer->Channel()->Number(), timer->File(), timer->Summary()); + log->log("-", Log::DEBUG, ""); } - return 1; + // asprintf(&buffer, "%d:%s:%s :%04d:%04d:%d:%d:%s:%s\n", +// active, (UseChannelID ? Channel()->GetChannelID().ToString() : itoa(Channel()->Number())), +// PrintDay(day, firstday), start, stop, priority, lifetime, file, summary ? summary : ""); } -#ifndef VOMPSTANDALONE -int MVPClient::processDeleteTimer(UCHAR* buffer, int length) -{ - log->log("Client", Log::DEBUG, "Delete timer called"); - // get timer - - int position = 0; - - INT delChannel = ntohl(*(ULONG*)&buffer[position]); position += 4; - INT delWeekdays = ntohl(*(ULONG*)&buffer[position]); position += 4; - INT delDay = ntohl(*(ULONG*)&buffer[position]); position += 4; - INT delStart = ntohl(*(ULONG*)&buffer[position]); position += 4; - INT delStop = ntohl(*(ULONG*)&buffer[position]); position += 4; - - cTimer* ti = NULL; - for (ti = Timers.First(); ti; ti = Timers.Next(ti)) - { - if ( (ti->Channel()->Number() == delChannel) - && ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay))) - && (ti->StartTime() == delStart) - && (ti->StopTime() == delStop) ) - break; - } - - if (!ti) - { - sendULONG(4); - return 1; - } - - if (!Timers.BeingEdited()) - { - if (!ti->Recording()) - { - Timers.Del(ti); - Timers.SetModified(); - sendULONG(10); - return 1; - } - else - { - log->log("Client", Log::ERR, "Unable to delete timer - timer is running"); - sendULONG(3); - return 1; - } - } - else - { - log->log("Client", Log::ERR, "Unable to delete timer - timers being edited at VDR"); - sendULONG(1); - return 1; - } -} +Active seems to be a bool - whether the timer should be done or not. If set to inactive it stays around after its time +recording is a bool, 0 for not currently recording, 1 for currently recording +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 +*/ -#endif -- 2.39.2 From b336eb690c811e5e91acbd79ab01d280a26a18af Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Thu, 22 Nov 2007 23:45:23 +0000 Subject: [PATCH 03/16] Bug fixes to new protocol --- mvpclient.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mvpclient.c b/mvpclient.c index 04f9745..c2c23b5 100644 --- a/mvpclient.c +++ b/mvpclient.c @@ -948,7 +948,7 @@ int MVPClient::processStartStreamingRecording(UCHAR* data, int length, ResponseP { recplayer = new RecPlayer(recording); - rp->addULONG(recplayer->getLengthBytes()); + rp->addULLONG(recplayer->getLengthBytes()); rp->addULONG(recplayer->getLengthFrames()); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); @@ -980,7 +980,7 @@ int MVPClient::processPositionFromFrameNumber(UCHAR* data, int length, ResponseP retval = recplayer->positionFromFrameNumber(frameNumber); } - rp->addULONG(retval); + rp->addULLONG(retval); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); delete rp; -- 2.39.2 From a6764b2a4382a1f658413d5a43784f006b883c6a Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sun, 25 Nov 2007 13:25:36 +0000 Subject: [PATCH 04/16] Bug fix for new stream protocol --- mvpreceiver.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/mvpreceiver.c b/mvpreceiver.c index fcc9caf..ae8c01b 100755 --- a/mvpreceiver.c +++ b/mvpreceiver.c @@ -102,14 +102,17 @@ void MVPReceiver::threadMethod() threadWaitForSignal(); threadCheckExit(); - pthread_mutex_lock(&processedRingLock); - amountReceived = processed.get(buffer+12, streamChunkSize); - pthread_mutex_unlock(&processedRingLock); + do + { + pthread_mutex_lock(&processedRingLock); + amountReceived = processed.get(buffer+12, streamChunkSize); + pthread_mutex_unlock(&processedRingLock); - *(ULONG*)&buffer[0] = htonl(2); // stream channel - *(ULONG*)&buffer[4] = htonl(streamID); - *(ULONG*)&buffer[8] = htonl(amountReceived); - tcp->sendPacket(buffer, amountReceived + 12); + *(ULONG*)&buffer[0] = htonl(2); // stream channel + *(ULONG*)&buffer[4] = htonl(streamID); + *(ULONG*)&buffer[8] = htonl(amountReceived); + tcp->sendPacket(buffer, amountReceived + 12); + } while(processed.getContent()); } } -- 2.39.2 From 0483fd287e8ea0f0488cfe981da098d8161858e2 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sun, 25 Nov 2007 13:43:25 +0000 Subject: [PATCH 05/16] Streaming update --- mvpreceiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mvpreceiver.c b/mvpreceiver.c index ae8c01b..3f68ec5 100755 --- a/mvpreceiver.c +++ b/mvpreceiver.c @@ -112,7 +112,7 @@ void MVPReceiver::threadMethod() *(ULONG*)&buffer[4] = htonl(streamID); *(ULONG*)&buffer[8] = htonl(amountReceived); tcp->sendPacket(buffer, amountReceived + 12); - } while(processed.getContent()); + } while(processed.getContent() >= streamChunkSize); } } -- 2.39.2 From e0173289856d2fa047bfa31a2b5174d382f5189e Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sun, 25 Nov 2007 14:47:54 +0000 Subject: [PATCH 06/16] Live TV update --- mvpclient.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mvpclient.c b/mvpclient.c index c2c23b5..21674e9 100644 --- a/mvpclient.c +++ b/mvpclient.c @@ -795,6 +795,12 @@ int MVPClient::processGetChannelPids(UCHAR* data, int length, ResponsePacket* rp int MVPClient::processStartStreamingChannel(UCHAR* data, int length, ULONG streamID, ResponsePacket* rp) { + if (lp) + { + log->log("Client", Log::ERR, "Client called start streaming twice"); + return 0; + } + log->log("Client", Log::DEBUG, "length = %i", length); ULONG channelNumber = ntohl(*(ULONG*)data); -- 2.39.2 From 9e24808fed16d954217543169e643aa2b7ff0b9a Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Mon, 26 Nov 2007 18:49:07 +0000 Subject: [PATCH 07/16] Fix config dir thread safety --- mvpclient.c | 15 ++------------- mvpclient.h | 4 ++-- mvpserver.c | 32 +++++++++++--------------------- mvpserver.h | 2 +- vompserver.c | 24 +++++++++++++++++++++++- 5 files changed, 39 insertions(+), 38 deletions(-) diff --git a/mvpclient.c b/mvpclient.c index 21674e9..d366e51 100644 --- a/mvpclient.c +++ b/mvpclient.c @@ -29,7 +29,7 @@ pthread_mutex_t threadClientMutex; int MVPClient::nr_clients = 0; -MVPClient::MVPClient(Config* cfgBase, char* tconfigDirExtra, int tsocket) +MVPClient::MVPClient(Config* cfgBase, char* tconfigDir, int tsocket) : tcp(tsocket) { #ifndef VOMPSTANDALONE @@ -40,7 +40,7 @@ MVPClient::MVPClient(Config* cfgBase, char* tconfigDirExtra, int tsocket) imageFile = 0; log = Log::getInstance(); loggedIn = false; - configDirExtra = tconfigDirExtra; + configDir = tconfigDir; baseConfig = cfgBase; incClients(); } @@ -396,17 +396,6 @@ int MVPClient::processLogin(UCHAR* buffer, int length, ResponsePacket* rp) // Open the config -#ifndef VOMPSTANDALONE - const char* configDir = cPlugin::ConfigDirectory(configDirExtra); -#else - const char* configDir = "."; -#endif - if (!configDir) - { - log->log("Client", Log::DEBUG, "No config dir!"); - return 0; - } - char configFileName[PATH_MAX]; 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]); config.init(configFileName); diff --git a/mvpclient.h b/mvpclient.h index dfa767a..8afdf4f 100644 --- a/mvpclient.h +++ b/mvpclient.h @@ -49,7 +49,7 @@ class ResponsePacket; class MVPClient { public: - MVPClient(Config* baseConfig, char* configDirExtra, int tsocket); + MVPClient(Config* baseConfig, char* configDir, int tsocket); ~MVPClient(); int run(); @@ -66,7 +66,7 @@ class MVPClient Config config; Config* baseConfig; bool loggedIn; - char* configDirExtra; + char* configDir; FILE* imageFile; #ifndef VOMPSTANDALONE diff --git a/mvpserver.c b/mvpserver.c index 85bc8da..211150c 100644 --- a/mvpserver.c +++ b/mvpserver.c @@ -54,36 +54,27 @@ int MVPServer::stop() return 1; } -int MVPServer::run(char* tconfigDirExtra) +int MVPServer::run(char* tconfigDir) { if (threadIsActive()) return 1; - configDirExtra = tconfigDirExtra; + configDir = tconfigDir; // Start config -#ifndef VOMPSTANDALONE - const char* configDir = cPlugin::ConfigDirectory(configDirExtra); -#else - const char* configDir = "."; +#ifdef VOMPSTANDALONE #define dsyslog(x) std::cout << x << std::endl; #endif - if (!configDir) + + char configFileName[PATH_MAX]; + snprintf(configFileName, PATH_MAX, "%s/vomp.conf", configDir); + + if (config.init(configFileName)) { - dsyslog("VOMP: Could not get config dir from VDR"); + dsyslog("VOMP: Config file found"); } else { - char configFileName[PATH_MAX]; - snprintf(configFileName, PATH_MAX, "%s/vomp.conf", configDir); - - if (config.init(configFileName)) - { - dsyslog("VOMP: Config file found"); - } - else - { - dsyslog("VOMP: Config file not found"); - } + dsyslog("VOMP: Config file not found"); } // Start logging @@ -158,7 +149,6 @@ int MVPServer::run(char* tconfigDirExtra) if (tftpEnabled) { char tftpPath[PATH_MAX]; -// snprintf(configFileName, PATH_MAX, "%s/vomp.conf", configDir); configString = config.getValueString("General", "TFTP directory"); if (configString) @@ -258,7 +248,7 @@ void MVPServer::threadMethod() while(1) { clientSocket = accept(listeningSocket,(struct sockaddr *)&address, &length); - MVPClient* m = new MVPClient(&config, configDirExtra, clientSocket); + MVPClient* m = new MVPClient(&config, configDir, clientSocket); m->run(); } } diff --git a/mvpserver.h b/mvpserver.h index 5236f35..78523a6 100644 --- a/mvpserver.h +++ b/mvpserver.h @@ -53,7 +53,7 @@ class MVPServer : public Thread Tftpd tftpd; MVPRelay mvprelay; int listeningSocket; - char* configDirExtra; + char* configDir; }; #endif diff --git a/vompserver.c b/vompserver.c index 624f279..c1179e1 100644 --- a/vompserver.c +++ b/vompserver.c @@ -65,6 +65,19 @@ cPluginVompserver::cPluginVompserver(void) bool cPluginVompserver::Start(void) { // Start any background activities the plugin shall perform. + + if (!configDir) + { + const char* vdrret = cPlugin::ConfigDirectory("vompserver"); + if (!vdrret) + { + dsyslog("VOMP: Could not get config dir from VDR"); + return false; + } + configDir = new char[strlen(vdrret)+1]; + strcpy(configDir, vdrret); + } + int success = mvpserver.run(configDir); if (success) return true; else return false; @@ -74,6 +87,7 @@ cPluginVompserver::~cPluginVompserver() { // Clean up after yourself! mvpserver.stop(); + if (configDir) delete[] configDir; } const char *cPluginVompserver::CommandLineHelp(void) @@ -92,7 +106,15 @@ bool cPluginVompserver::ProcessArgs(int argc, char *argv[]) { if (c == 'c') { - configDir = optarg; + const char* vdrret = cPlugin::ConfigDirectory(optarg); + if (!vdrret) + { + dsyslog("VOMP: Could not get config dir from VDR"); + return false; + } + + configDir = new char[strlen(vdrret)+1]; + strcpy(configDir, vdrret); } else { -- 2.39.2 From fcf1581cf1474793631123b82a818f5dd5d386a3 Mon Sep 17 00:00:00 2001 From: Mark Calderbank Date: Thu, 6 Dec 2007 13:58:34 +0000 Subject: [PATCH 08/16] New I18n system: server code --- Makefile | 2 +- i18n.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++ i18n.h | 49 +++++++++++++++++++ mvpclient.c | 49 ++++++++++++++++++- mvpclient.h | 4 ++ 5 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 i18n.c create mode 100644 i18n.h diff --git a/Makefile b/Makefile index 659d4e9..fda7d9e 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' ### The object files (add further files here): -OBJS = $(PLUGIN).o dsock.o mvpserver.o udpreplier.o bootpd.o tftpd.o mvpclient.o tcp.o \ +OBJS = $(PLUGIN).o dsock.o mvpserver.o udpreplier.o bootpd.o tftpd.o i18n.o mvpclient.o tcp.o \ ringbuffer.o mvprelay.o \ recplayer.o config.o log.o thread.o mvpreceiver.o tftpclient.o \ media.o responsepacket.o diff --git a/i18n.c b/i18n.c new file mode 100644 index 0000000..7621b40 --- /dev/null +++ b/i18n.c @@ -0,0 +1,134 @@ +/* + Copyright 2007 Mark Calderbank + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "i18n.h" + +#include +#include +#include + +using namespace std; + +I18n::I18n(char* tconfigDir) +{ + configDir = tconfigDir; +} + +void I18n::findLanguages(void) +{ + glob_t globbuf; + char line[1000]; + + CodeList.clear(); + FileList.clear(); + + string l10nGlob = configDir; + l10nGlob += "/l10n/*"; + glob(l10nGlob.c_str(), 0, NULL, &globbuf); + for (unsigned int i=0; i < globbuf.gl_pathc; i++) + { + FILE *f = fopen(globbuf.gl_pathv[i], "r"); + if (f) + { + while (fgets(line, 1000, f) && strncmp(line, "l10n-vomp:", 10) == 0) + { + string langline = line; + string code, name; + + string::size_type pos_start, pos_end; + pos_start = langline.find_first_not_of(" \t\r\n", 10); + if (pos_start == string::npos) break; + pos_end = langline.find_first_of(" \t", pos_start); + if (pos_end == string::npos) break; + code = langline.substr(pos_start, pos_end - pos_start); + pos_start = langline.find_first_not_of(" \t\r\n", pos_end); + if (pos_start == string::npos) break; + pos_end = langline.find_last_not_of(" \t\r\n"); + name = langline.substr(pos_start, pos_end + 1 - pos_start); + CodeList[code] = name; + FileList.insert(lang_file(code, globbuf.gl_pathv[i])); + } + fclose(f); + } + } + globfree(&globbuf); +} + +I18n::trans_table I18n::getLanguageContent(const string code) +{ + trans_table Translations; + if (CodeList.count(code) == 0) return Translations; + LanguageCode = code; + + pair range; + range = FileList.equal_range(code); + lang_file_list::const_iterator iter; + for (iter = range.first; iter != range.second; ++iter) + { + FILE *f; + char line[1000]; + string key; + f = fopen((*iter).second.c_str(), "r"); + if (f) + { + while (fgets(line, 1000, f)) + { + int linetype = 0; + string::size_type offset = 0; + string fileline = line; + if (fileline.compare(0, 2, "x:") == 0) + { // New key to be translated + linetype = 1; offset = 2; + } + if (fileline.compare(0, code.size() + 1, code + ":") == 0) + { // Translation for previous key + if (key.empty()) continue; // Translation without preceding key + linetype = 2; offset = code.size() + 1; + } + if (linetype != 0) + { + string::size_type start, end; + start = fileline.find_first_not_of(" \t\r\n",offset); + if (start == string::npos) + { + if (linetype == 2) Translations[key].clear(); + continue; + } + end = fileline.find_last_not_of(" \t\r\n"); + string text = fileline.substr(start, end + 1 - start); + if (text.length() > 1) // Strip quotes if at both ends + { + if (text[0] == '"' && text[text.length()-1] == '"') + text = text.substr(1, text.length()-2); + } + if (linetype == 1) key = text; + if (linetype == 2) Translations[key] = text; + } + } + fclose(f); + } + } + return Translations; +} + +const I18n::lang_code_list& I18n::getLanguageList(void) +{ + return CodeList; +} diff --git a/i18n.h b/i18n.h new file mode 100644 index 0000000..109c336 --- /dev/null +++ b/i18n.h @@ -0,0 +1,49 @@ +/* + Copyright 2007 Mark Calderbank + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef I18N_H +#define I18N_H + +#include +#include + +class I18n +{ + public: + I18n(char* tconfigDir); + typedef std::map lang_code_list; + typedef std::pair lang_code; + typedef std::map trans_table; + typedef std::pair trans_entry; + + void findLanguages(void); + trans_table getLanguageContent(const std::string code); + const lang_code_list& getLanguageList(void); + + private: + char* configDir; + std::string LanguageCode; + lang_code_list CodeList; + + typedef std::multimap lang_file_list; + typedef std::pair lang_file; + lang_file_list FileList; +}; +#endif diff --git a/mvpclient.c b/mvpclient.c index d366e51..17fced9 100644 --- a/mvpclient.c +++ b/mvpclient.c @@ -30,7 +30,7 @@ int MVPClient::nr_clients = 0; MVPClient::MVPClient(Config* cfgBase, char* tconfigDir, int tsocket) - : tcp(tsocket) + : tcp(tsocket), i18n(tconfigDir) { #ifndef VOMPSTANDALONE lp = NULL; @@ -41,6 +41,7 @@ MVPClient::MVPClient(Config* cfgBase, char* tconfigDir, int tsocket) log = Log::getInstance(); loggedIn = false; configDir = tconfigDir; + log->log("Client", Log::DEBUG, "Config dir: %s", configDir); baseConfig = cfgBase; incClients(); } @@ -383,6 +384,12 @@ void MVPClient::run2() case 32: result = processGetImageBlock(data, extraDataLength, rp); break; + case 33: + result = processGetLanguageList(data, extraDataLength, rp); + break; + case 34: + result = processGetLanguageContent(data, extraDataLength, rp); + break; } if (data) free(data); @@ -1836,6 +1843,46 @@ int MVPClient::processGetImageBlock(UCHAR* data, int length, ResponsePacket* rp) } +int MVPClient::processGetLanguageList(UCHAR* data, int length, ResponsePacket* rp) +{ + i18n.findLanguages(); + const I18n::lang_code_list& languages = i18n.getLanguageList(); + std::string result; + I18n::lang_code_list::const_iterator iter; + for (iter = languages.begin(); iter != languages.end(); ++iter) + { + rp->addString(iter->first.c_str()); + rp->addString(iter->second.c_str()); + } + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + return 1; +} + +int MVPClient::processGetLanguageContent(UCHAR* data, int length, ResponsePacket* rp) +{ + if (length <= 0) return 0; + std::string code, result; + code.assign((char*)data, length - 1); + i18n.findLanguages(); + I18n::trans_table texts = i18n.getLanguageContent(code); + I18n::trans_table::const_iterator iter; + for (iter = texts.begin(); iter != texts.end(); ++iter) + { + rp->addString(iter->first.c_str()); + rp->addString(iter->second.c_str()); + } + rp->finalise(); + tcp.sendPacket(rp->getPtr(), rp->getLen()); + delete rp; + return 1; +} + + + + + diff --git a/mvpclient.h b/mvpclient.h index 8afdf4f..9ef5c84 100644 --- a/mvpclient.h +++ b/mvpclient.h @@ -43,6 +43,7 @@ #include "tcp.h" #include "config.h" #include "media.h" +#include "i18n.h" class ResponsePacket; @@ -65,6 +66,7 @@ class MVPClient TCP tcp; Config config; Config* baseConfig; + I18n i18n; bool loggedIn; char* configDir; FILE* imageFile; @@ -103,6 +105,8 @@ class MVPClient int processGetMediaList(UCHAR* data, int length, ResponsePacket* rp); int processGetPicture(UCHAR* data, int length, ResponsePacket* rp); int processGetImageBlock(UCHAR* data, int length, ResponsePacket* rp); + int processGetLanguageList(UCHAR* data, int length, ResponsePacket* rp); + int processGetLanguageContent(UCHAR* data, int length, ResponsePacket* rp); void incClients(); void decClients(); -- 2.39.2 From a767177744881cf441616d300eede1c2f2623850 Mon Sep 17 00:00:00 2001 From: Mark Calderbank Date: Mon, 10 Dec 2007 15:07:11 +0000 Subject: [PATCH 09/16] tabs -> spaces in source --- i18n.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/i18n.c b/i18n.c index 7621b40..2382f35 100644 --- a/i18n.c +++ b/i18n.c @@ -91,7 +91,7 @@ I18n::trans_table I18n::getLanguageContent(const string code) while (fgets(line, 1000, f)) { int linetype = 0; - string::size_type offset = 0; + string::size_type offset = 0; string fileline = line; if (fileline.compare(0, 2, "x:") == 0) { // New key to be translated @@ -105,19 +105,19 @@ I18n::trans_table I18n::getLanguageContent(const string code) if (linetype != 0) { string::size_type start, end; - start = fileline.find_first_not_of(" \t\r\n",offset); + start = fileline.find_first_not_of(" \t\r\n",offset); if (start == string::npos) - { - if (linetype == 2) Translations[key].clear(); - continue; - } + { + if (linetype == 2) Translations[key].clear(); + continue; + } end = fileline.find_last_not_of(" \t\r\n"); string text = fileline.substr(start, end + 1 - start); - if (text.length() > 1) // Strip quotes if at both ends - { - if (text[0] == '"' && text[text.length()-1] == '"') - text = text.substr(1, text.length()-2); - } + if (text.length() > 1) // Strip quotes if at both ends + { + if (text[0] == '"' && text[text.length()-1] == '"') + text = text.substr(1, text.length()-2); + } if (linetype == 1) key = text; if (linetype == 2) Translations[key] = text; } -- 2.39.2 From e8d774abacd3cfd9b3dbb480a919632069eea1c8 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sat, 12 Jan 2008 16:56:23 +0000 Subject: [PATCH 10/16] *** empty log message *** --- mvpclient.c | 54 ++++++----------------------------------------------- 1 file changed, 6 insertions(+), 48 deletions(-) diff --git a/mvpclient.c b/mvpclient.c index 17fced9..49fc7ea 100644 --- a/mvpclient.c +++ b/mvpclient.c @@ -229,12 +229,12 @@ void MVPClient::run2() ULONG opcode; ULONG extraDataLength; UCHAR* data; - - int result = 0; + int result; while(1) { log->log("Client", Log::DEBUG, "Waiting"); + result = 0; if (!tcp.readData((UCHAR*)&channelID, sizeof(ULONG))) break; channelID = ntohl(channelID); @@ -299,7 +299,8 @@ void MVPClient::run2() ResponsePacket* rp = new ResponsePacket(); if (!rp->init(requestID)) { - log->log("Client", Log::ERR, "response packet init fail"); + log->log("Client", Log::ERR, "response packet init fail"); + delete rp; break; } @@ -392,6 +393,7 @@ void MVPClient::run2() break; } + delete rp; if (data) free(data); if (!result) break; } @@ -418,8 +420,7 @@ int MVPClient::processLogin(UCHAR* buffer, int length, ResponsePacket* rp) rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); log->log("Client", Log::DEBUG, "written login reply len %lu", rp->getLen()); - delete rp; - + loggedIn = true; return 1; } @@ -447,7 +448,6 @@ int MVPClient::processGetRecordingsList(UCHAR* data, int length, ResponsePacket* rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "Written recordings list"); @@ -497,7 +497,6 @@ int MVPClient::processDeleteRecording(UCHAR* data, int length, ResponsePacket* r rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } @@ -594,7 +593,6 @@ int MVPClient::processMoveRecording(UCHAR* data, int length, ResponsePacket* rp) rp->addULONG(5); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } } @@ -607,7 +605,6 @@ int MVPClient::processMoveRecording(UCHAR* data, int length, ResponsePacket* rp) rp->addULONG(5); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } @@ -646,7 +643,6 @@ int MVPClient::processMoveRecording(UCHAR* data, int length, ResponsePacket* rp) rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; delete[] dateDirName; delete[] titleDirName; @@ -658,7 +654,6 @@ int MVPClient::processMoveRecording(UCHAR* data, int length, ResponsePacket* rp) rp->addULONG(3); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; } } else @@ -666,7 +661,6 @@ int MVPClient::processMoveRecording(UCHAR* data, int length, ResponsePacket* rp) rp->addULONG(4); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; } return 1; @@ -706,7 +700,6 @@ int MVPClient::processGetChannelsList(UCHAR* data, int length, ResponsePacket* r rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "Written channels list"); @@ -723,7 +716,6 @@ int MVPClient::processGetChannelPids(UCHAR* data, int length, ResponsePacket* rp rp->addULONG(0); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } @@ -782,7 +774,6 @@ int MVPClient::processGetChannelPids(UCHAR* data, int length, ResponsePacket* rp rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "Written channels pids"); @@ -806,7 +797,6 @@ int MVPClient::processStartStreamingChannel(UCHAR* data, int length, ULONG strea rp->addULONG(0); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } @@ -835,7 +825,6 @@ int MVPClient::processStartStreamingChannel(UCHAR* data, int length, ULONG strea rp->addULONG(0); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } @@ -846,14 +835,12 @@ int MVPClient::processStartStreamingChannel(UCHAR* data, int length, ULONG strea rp->addULONG(0); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } rp->addULONG(1); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } @@ -878,7 +865,6 @@ int MVPClient::processStopStreaming(UCHAR* data, int length, ResponsePacket* rp) rp->addULONG(1); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } @@ -931,7 +917,6 @@ int MVPClient::processGetBlock(UCHAR* data, int length, ResponsePacket* rp) rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); log->log("Client", Log::DEBUG, "Finished getblock, have sent %lu", rp->getLen()); - delete rp; return 1; } @@ -954,7 +939,6 @@ int MVPClient::processStartStreamingRecording(UCHAR* data, int length, ResponseP rp->addULONG(recplayer->getLengthFrames()); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "written totalLength"); } @@ -985,7 +969,6 @@ int MVPClient::processPositionFromFrameNumber(UCHAR* data, int length, ResponseP rp->addULLONG(retval); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "Wrote posFromFrameNum reply to client"); return 1; @@ -1010,7 +993,6 @@ int MVPClient::processFrameNumberFromPosition(UCHAR* data, int length, ResponseP rp->addULONG(retval); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "Wrote frameNumFromPos reply to client"); return 1; @@ -1053,7 +1035,6 @@ int MVPClient::processGetIFrame(UCHAR* data, int length, ResponsePacket* rp) rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "Wrote GNIF reply to client %llu %lu %lu", rfilePosition, rframeNumber, rframeLength); return 1; @@ -1075,7 +1056,6 @@ int MVPClient::processGetChannelSchedule(UCHAR* data, int length, ResponsePacket rp->addULONG(0); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "written 0 because channel = NULL"); return 1; @@ -1095,7 +1075,6 @@ int MVPClient::processGetChannelSchedule(UCHAR* data, int length, ResponsePacket rp->addULONG(0); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "written 0 because Schedule!s! = NULL"); return 1; @@ -1109,7 +1088,6 @@ int MVPClient::processGetChannelSchedule(UCHAR* data, int length, ResponsePacket rp->addULONG(0); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "written 0 because Schedule = NULL"); return 1; @@ -1191,7 +1169,6 @@ int MVPClient::processGetChannelSchedule(UCHAR* data, int length, ResponsePacket rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "written schedules packet"); @@ -1237,7 +1214,6 @@ int MVPClient::processConfigSave(UCHAR* buffer, int length, ResponsePacket* rp) rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } @@ -1272,7 +1248,6 @@ int MVPClient::processConfigLoad(UCHAR* buffer, int length, ResponsePacket* rp) rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } @@ -1309,7 +1284,6 @@ int MVPClient::processGetTimers(UCHAR* buffer, int length, ResponsePacket* rp) rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "Written timers list"); @@ -1368,7 +1342,6 @@ int MVPClient::processSetTimer(UCHAR* buffer, int length, ResponsePacket* rp) rp->addULONG(0); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } else @@ -1376,7 +1349,6 @@ int MVPClient::processSetTimer(UCHAR* buffer, int length, ResponsePacket* rp) rp->addULONG(1); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; } } else @@ -1384,7 +1356,6 @@ int MVPClient::processSetTimer(UCHAR* buffer, int length, ResponsePacket* rp) rp->addULONG(2); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; } delete timer; return 1; @@ -1418,7 +1389,6 @@ int MVPClient::processDeleteTimer(UCHAR* buffer, int length, ResponsePacket* rp) rp->addULONG(4); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } @@ -1431,7 +1401,6 @@ int MVPClient::processDeleteTimer(UCHAR* buffer, int length, ResponsePacket* rp) rp->addULONG(10); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } else @@ -1440,7 +1409,6 @@ int MVPClient::processDeleteTimer(UCHAR* buffer, int length, ResponsePacket* rp) rp->addULONG(3); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } } @@ -1450,7 +1418,6 @@ int MVPClient::processDeleteTimer(UCHAR* buffer, int length, ResponsePacket* rp) rp->addULONG(1); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } } @@ -1475,7 +1442,6 @@ int MVPClient::processGetRecInfo(UCHAR* data, int length, ResponsePacket* rp) rp->addULONG(0); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } @@ -1594,7 +1560,6 @@ int MVPClient::processGetRecInfo(UCHAR* data, int length, ResponsePacket* rp) rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "Written getrecinfo"); @@ -1620,7 +1585,6 @@ int MVPClient::processReScanRecording(UCHAR* data, int length, ResponsePacket* r rp->addULONG(recplayer->getLengthFrames()); rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "Rescan recording, wrote new length to client"); return 1; } @@ -1661,7 +1625,6 @@ int MVPClient::processGetMarks(UCHAR* data, int length, ResponsePacket* rp) rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "Written Marks list"); @@ -1733,7 +1696,6 @@ int MVPClient::processGetMediaList(UCHAR* data, int length, ResponsePacket* rp) rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "Written Media list"); return 1; @@ -1789,7 +1751,6 @@ int MVPClient::processGetPicture(UCHAR* data, int length, ResponsePacket* rp) rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; log->log("Client", Log::DEBUG, "Written getPicture"); @@ -1837,7 +1798,6 @@ int MVPClient::processGetImageBlock(UCHAR* data, int length, ResponsePacket* rp) rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } @@ -1856,7 +1816,6 @@ int MVPClient::processGetLanguageList(UCHAR* data, int length, ResponsePacket* r } rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } @@ -1875,7 +1834,6 @@ int MVPClient::processGetLanguageContent(UCHAR* data, int length, ResponsePacket } rp->finalise(); tcp.sendPacket(rp->getPtr(), rp->getLen()); - delete rp; return 1; } -- 2.39.2 From ddda0dc539979f3c4ddfdbae48042d840bdf05e0 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Tue, 25 Mar 2008 20:08:40 +0000 Subject: [PATCH 11/16] Update to advise Linux about FS caching --- recplayer.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/recplayer.c b/recplayer.c index 6647589..3c550ef 100644 --- a/recplayer.c +++ b/recplayer.c @@ -20,6 +20,9 @@ #include "recplayer.h" +#define _XOPEN_SOURCE 600 +#include + RecPlayer::RecPlayer(cRecording* rec) { log = Log::getInstance(); @@ -163,7 +166,10 @@ unsigned long RecPlayer::getBlock(unsigned char* buffer, ULLONG position, unsign filePosition = currentPosition - segments[segmentNumber]->start; fseek(file, filePosition, SEEK_SET); if (fread(&buffer[got], getFromThisSegment, 1, file) != 1) return 0; // umm, big problem. - + + // Tell linux not to bother keeping the data in the FS cache + posix_fadvise(file->_fileno, filePosition, getFromThisSegment, POSIX_FADV_DONTNEED); + got += getFromThisSegment; currentPosition += getFromThisSegment; yetToGet -= getFromThisSegment; -- 2.39.2 From a57dcbcead897941e7c2a7079bf077199aa0ddb9 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Tue, 25 Mar 2008 20:24:36 +0000 Subject: [PATCH 12/16] Patch from davep for VDR 1.5 / 1.6 --- mvpreceiver.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mvpreceiver.c b/mvpreceiver.c index 3f68ec5..292cc17 100755 --- a/mvpreceiver.c +++ b/mvpreceiver.c @@ -2,8 +2,12 @@ MVPReceiver* MVPReceiver::create(cChannel* channel, int priority) { - bool NeedsDetachReceivers; - cDevice* device = cDevice::GetDevice(channel, priority, &NeedsDetachReceivers); +#if VDRVERSNUM < 10500 + bool NeedsDetachReceivers; + cDevice* device = cDevice::GetDevice(channel, priority, &NeedsDetachReceivers); +#else + cDevice* device = cDevice::GetDevice(channel, priority, true); // last param is live-view +#endif if (!device) { @@ -11,12 +15,14 @@ MVPReceiver* MVPReceiver::create(cChannel* channel, int priority) return NULL; } +#if VDRVERSNUM < 10500 if (NeedsDetachReceivers) { Log::getInstance()->log("MVPReceiver", Log::DEBUG, "Needs detach receivers"); // Need to detach other receivers or VDR will shut down?? } +#endif MVPReceiver* m = new MVPReceiver(channel, device); return m; -- 2.39.2 From 3950b99bbf790bc71bc79bd5599fd1a1ef716c7b Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Wed, 26 Mar 2008 14:55:38 +0000 Subject: [PATCH 13/16] *** empty log message *** --- COPYING | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/COPYING b/COPYING index 5b6e7c6..d511905 100644 --- a/COPYING +++ b/COPYING @@ -1,8 +1,8 @@ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to +the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not @@ -55,7 +55,7 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION @@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions: License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -225,7 +225,7 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -278,7 +278,7 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS - + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest @@ -303,10 +303,9 @@ the "copyright" line and a pointer to where the full notice is found. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. @@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names: This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General +library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. -- 2.39.2 From b2c53ddf810b6ad81e282895918c8e9c7dac9e0b Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Wed, 26 Mar 2008 14:59:48 +0000 Subject: [PATCH 14/16] FSF address change --- bootpd.c | 2 +- bootpd.h | 2 +- config.c | 2 +- config.h | 2 +- defines.h | 2 +- dsock.c | 2 +- dsock.h | 2 +- i18n.c | 2 +- i18n.h | 2 +- log.c | 2 +- log.h | 2 +- media.c | 2 +- media.h | 2 +- mvpclient.c | 2 +- mvpclient.h | 2 +- mvpreceiver.h | 2 +- mvprelay.c | 2 +- mvprelay.h | 2 +- mvpserver.c | 2 +- mvpserver.h | 2 +- recplayer.c | 2 +- recplayer.h | 2 +- responsepacket.c | 2 +- responsepacket.h | 2 +- ringbuffer.c | 2 +- ringbuffer.h | 2 +- tcp.c | 2 +- tcp.h | 2 +- tftpclient.c | 2 +- tftpclient.h | 2 +- tftpd.c | 2 +- tftpd.h | 2 +- thread.c | 2 +- thread.h | 2 +- udpreplier.c | 2 +- udpreplier.h | 2 +- vompserver.c | 2 +- 37 files changed, 37 insertions(+), 37 deletions(-) diff --git a/bootpd.c b/bootpd.c index 704b439..a586132 100644 --- a/bootpd.c +++ b/bootpd.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "bootpd.h" diff --git a/bootpd.h b/bootpd.h index 2cad4a6..156d633 100644 --- a/bootpd.h +++ b/bootpd.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef BOOTPD_H diff --git a/config.c b/config.c index d4772e1..5ab6f4b 100644 --- a/config.c +++ b/config.c @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" diff --git a/config.h b/config.h index e93c221..2e4a2dd 100644 --- a/config.h +++ b/config.h @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef CONFIG_H diff --git a/defines.h b/defines.h index 0d13ce7..1ee1473 100644 --- a/defines.h +++ b/defines.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef DEFINES_H diff --git a/dsock.c b/dsock.c index cd8c880..8082d63 100644 --- a/dsock.c +++ b/dsock.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "dsock.h" diff --git a/dsock.h b/dsock.h index ba67360..078b3be 100644 --- a/dsock.h +++ b/dsock.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef DSOCK_H diff --git a/i18n.c b/i18n.c index 2382f35..5681980 100644 --- a/i18n.c +++ b/i18n.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "i18n.h" diff --git a/i18n.h b/i18n.h index 109c336..3358bc9 100644 --- a/i18n.h +++ b/i18n.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef I18N_H diff --git a/log.c b/log.c index 335d27d..c1f7445 100755 --- a/log.c +++ b/log.c @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "log.h" diff --git a/log.h b/log.h index 6946ade..ba70807 100755 --- a/log.h +++ b/log.h @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef LOG_H diff --git a/media.c b/media.c index 996413d..3b30baa 100644 --- a/media.c +++ b/media.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "media.h" diff --git a/media.h b/media.h index d9409e6..e058d66 100644 --- a/media.h +++ b/media.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef MEDIA_H diff --git a/mvpclient.c b/mvpclient.c index 49fc7ea..40449f4 100644 --- a/mvpclient.c +++ b/mvpclient.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "mvpclient.h" diff --git a/mvpclient.h b/mvpclient.h index 9ef5c84..2551b22 100644 --- a/mvpclient.h +++ b/mvpclient.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef MVPCLIENT_H diff --git a/mvpreceiver.h b/mvpreceiver.h index 523ba9a..648789c 100755 --- a/mvpreceiver.h +++ b/mvpreceiver.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef MVPRECEIVER_H diff --git a/mvprelay.c b/mvprelay.c index 0e49f28..d266674 100755 --- a/mvprelay.c +++ b/mvprelay.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "mvprelay.h" diff --git a/mvprelay.h b/mvprelay.h index fd51bfc..591b6a3 100755 --- a/mvprelay.h +++ b/mvprelay.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef MVPRELAY_H diff --git a/mvpserver.c b/mvpserver.c index 211150c..a1aea2c 100644 --- a/mvpserver.c +++ b/mvpserver.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "mvpserver.h" diff --git a/mvpserver.h b/mvpserver.h index 78523a6..9bf2549 100644 --- a/mvpserver.h +++ b/mvpserver.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef MVPSERVER_H diff --git a/recplayer.c b/recplayer.c index 3c550ef..1504b6e 100644 --- a/recplayer.c +++ b/recplayer.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "recplayer.h" diff --git a/recplayer.h b/recplayer.h index c3b1795..95f310a 100644 --- a/recplayer.h +++ b/recplayer.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef RECPLAYER_H diff --git a/responsepacket.c b/responsepacket.c index 0130235..d190f86 100644 --- a/responsepacket.c +++ b/responsepacket.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include diff --git a/responsepacket.h b/responsepacket.h index e091701..7b8f25d 100644 --- a/responsepacket.h +++ b/responsepacket.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef RESPONSEPACKET_H diff --git a/ringbuffer.c b/ringbuffer.c index 410d1af..20db41c 100644 --- a/ringbuffer.c +++ b/ringbuffer.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ringbuffer.h" diff --git a/ringbuffer.h b/ringbuffer.h index 568a286..c5a6e14 100644 --- a/ringbuffer.h +++ b/ringbuffer.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef RINGBUFFER_H diff --git a/tcp.c b/tcp.c index 7053be5..cc605c0 100644 --- a/tcp.c +++ b/tcp.c @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "tcp.h" diff --git a/tcp.h b/tcp.h index 7f0c092..4364798 100644 --- a/tcp.h +++ b/tcp.h @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef TCP_H diff --git a/tftpclient.c b/tftpclient.c index 9a6cb52..8dec41a 100644 --- a/tftpclient.c +++ b/tftpclient.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "tftpclient.h" diff --git a/tftpclient.h b/tftpclient.h index b4eea8b..7455066 100644 --- a/tftpclient.h +++ b/tftpclient.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef TFTPCLIENT_H diff --git a/tftpd.c b/tftpd.c index 38415e0..d1ed8e3 100644 --- a/tftpd.c +++ b/tftpd.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "tftpd.h" diff --git a/tftpd.h b/tftpd.h index 45da7ca..6886afc 100644 --- a/tftpd.h +++ b/tftpd.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef TFTPD_H diff --git a/thread.c b/thread.c index 851c024..97a41c1 100755 --- a/thread.c +++ b/thread.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "thread.h" diff --git a/thread.h b/thread.h index c48ea97..5943677 100755 --- a/thread.h +++ b/thread.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef THREAD_H diff --git a/udpreplier.c b/udpreplier.c index 79ff4b3..0b43e17 100644 --- a/udpreplier.c +++ b/udpreplier.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "udpreplier.h" diff --git a/udpreplier.h b/udpreplier.h index a16af54..a287189 100644 --- a/udpreplier.h +++ b/udpreplier.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef UDPREPLIER_H diff --git a/vompserver.c b/vompserver.c index c1179e1..236f568 100644 --- a/vompserver.c +++ b/vompserver.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef VOMPSTANDALONE -- 2.39.2 From 5feb7be74bb8b2f7002c3edd290884a55fa7f61c Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Wed, 26 Mar 2008 15:13:49 +0000 Subject: [PATCH 15/16] *** empty log message *** --- HISTORY | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 HISTORY diff --git a/HISTORY b/HISTORY deleted file mode 100644 index d7cdb3e..0000000 --- a/HISTORY +++ /dev/null @@ -1,7 +0,0 @@ -VDR Plugin 'vompserver' Revision History ----------------------------------------- - -2005-06-28: Version 0.0.0 - -- Upload to SF CVS. Not a release yet! - -- 2.39.2 From 675aa39eb63f09ba53f83c412d01bf44515632b8 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Wed, 26 Mar 2008 15:24:02 +0000 Subject: [PATCH 16/16] docs update --- mvpreceiver.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/mvpreceiver.h b/mvpreceiver.h index 648789c..cee6611 100755 --- a/mvpreceiver.h +++ b/mvpreceiver.h @@ -87,10 +87,28 @@ class MVPReceiver : public cReceiver, public Thread cDevice docs +(VDR 1.4) static cDevice *GetDevice(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL); ///< Returns a device that is able to receive the given Channel at the ///< given Priority. ///< See ProvidesChannel() for more information on how ///< priorities are handled, and the meaning of NeedsDetachReceivers. +(VDR >1.5) + static cDevice *GetDevice(const cChannel *Channel, int Priority, bool LiveView); + ///< Returns a device that is able to receive the given Channel at the + ///< given Priority, with the least impact on active recordings and + ///< live viewing. The LiveView parameter tells whether the device will + ///< be used for live viewing or a recording. + ///< If the Channel is encrypted, a CAM slot that claims to be able to + ///< decrypt the channel is automatically selected and assigned to the + ///< returned device. Whether or not this combination of device and CAM + ///< slot is actually able to decrypt the channel can only be determined + ///< by checking the "scrambling control" bits of the received TS packets. + ///< The Action() function automatically does this and takes care that + ///< after detaching any receivers because the channel can't be decrypted, + ///< this device/CAM combination will be skipped in the next call to + ///< GetDevice(). + ///< See also ProvidesChannel(). + */ -- 2.39.2