From b4cd364d6794f3251ba0b6f140fa49d3a7fadf1e Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Thu, 22 Nov 2007 00:15:49 +0000 Subject: [PATCH] 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