2 Copyright 2004-2005 Chris Tallon
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "mvpclient.h"
23 MVPClient::MVPClient(int tsocket)
28 recordingManager = NULL;
29 log = Log::getInstance();
33 // Get IP address of client for config module
36 struct sockaddr_in peer;
37 socklen_t salen = sizeof(struct sockaddr);
38 if(getpeername(tsocket, (struct sockaddr*)&peer, &salen) == 0)
40 strcpy(ipa, inet_ntoa(peer.sin_addr));
45 log->log("Client", Log::DEBUG, "Cannot get peer name!");
48 const char* configDir = cPlugin::ConfigDirectory();
51 log->log("Client", Log::DEBUG, "No config dir!");
55 char configFileName[PATH_MAX];
56 snprintf(configFileName, PATH_MAX - strlen(configDir) - strlen(ipa) - 20, "%s/vomp-%s.conf", configDir, ipa);
57 config.init(configFileName);
59 log->log("Client", Log::DEBUG, "Config file name: %s", configFileName);
68 MVPClient::~MVPClient()
70 log->log("Client", Log::DEBUG, "MVP client destructor");
81 delete recordingManager;
83 recordingManager = NULL;
86 if (loggedIn) cleanConfig();
89 cChannel* MVPClient::channelFromNumber(ULONG channelNumber)
91 cChannel* channel = NULL;
93 for (channel = Channels.First(); channel; channel = Channels.Next(channel))
95 if (!channel->GroupSep())
97 log->log("Client", Log::DEBUG, "Looking for channel %lu::: number: %i name: '%s'", channelNumber, channel->Number(), channel->Name());
99 if (channel->Number() == (int)channelNumber)
101 int vpid = channel->Vpid();
102 #if VDRVERSNUM < 10300
103 int apid1 = channel->Apid1();
105 int apid1 = channel->Apid(0);
107 log->log("Client", Log::DEBUG, "Found channel number %lu, vpid = %i, apid1 = %i", channelNumber, vpid, apid1);
115 log->log("Client", Log::DEBUG, "Channel not found");
122 void MVPClient::writeResumeData()
124 config.setValueLongLong("ResumeData", (char*)rp->getCurrentRecording()->FileName(), rp->getLastPosition());
127 void MVPClient::sendULONG(ULONG ul)
130 *(ULONG*)&sendBuffer[0] = htonl(4);
131 *(ULONG*)&sendBuffer[4] = htonl(ul);
133 tcp.sendPacket(sendBuffer, 8);
134 log->log("Client", Log::DEBUG, "written ULONG %lu", ul);
137 void MVPClientStartThread(void* arg)
139 MVPClient* m = (MVPClient*)arg;
141 // Nothing external to this class has a reference to it
142 // This is the end of the thread.. so delete m
149 if (pthread_create(&runThread, NULL, (void*(*)(void*))MVPClientStartThread, (void *)this) == -1) return 0;
150 log->log("Client", Log::DEBUG, "MVPClient run success");
154 void MVPClient::run2()
159 pthread_sigmask(SIG_BLOCK, &sigset, NULL);
160 pthread_detach(runThread); // Detach
162 tcp.disableReadTimeout();
164 tcp.setSoKeepTime(3);
165 tcp.setNonBlocking();
175 log->log("Client", Log::DEBUG, "Waiting");
176 buffer = (UCHAR*)tcp.receivePacket();
177 log->log("Client", Log::DEBUG, "Received packet, length = %u", tcp.getDataLength());
180 log->log("Client", Log::DEBUG, "Detected connection closed");
184 packetLength = tcp.getDataLength() - 4;
185 opcode = ntohl(*(ULONG*)buffer);
188 if (!loggedIn && (opcode != 1))
197 result = processLogin(data, packetLength);
200 result = processGetRecordingsList(data, packetLength);
203 result = processDeleteRecording(data, packetLength);
206 result = processGetSummary(data, packetLength);
209 result = processGetChannelsList(data, packetLength);
212 result = processStartStreamingChannel(data, packetLength);
215 result = processGetBlock(data, packetLength);
218 result = processStopStreaming(data, packetLength);
221 result = processStartStreamingRecording(data, packetLength);
224 result = processGetChannelSchedule(data, packetLength);
227 result = processConfigSave(data, packetLength);
230 result = processConfigLoad(data, packetLength);
233 result = processReScanRecording(data, packetLength);
236 result = processGetTimers(data, packetLength);
245 int MVPClient::processLogin(UCHAR* buffer, int length)
247 if (length != 6) return 0;
251 const char* configDir = cPlugin::ConfigDirectory();
254 log->log("Client", Log::DEBUG, "No config dir!");
258 char configFileName[PATH_MAX];
259 snprintf(configFileName, PATH_MAX - strlen(configDir) - 17 - 20, "%s/vomp-%02X-%02X-%02X-%02X-%02X-%02X.conf", configDir, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
260 config.init(configFileName);
262 // Send the login reply
264 time_t timeNow = time(NULL);
265 struct tm* timeStruct = localtime(&timeNow);
266 int timeOffset = timeStruct->tm_gmtoff;
268 UCHAR sendBuffer[12];
269 *(ULONG*)&sendBuffer[0] = htonl(8);
270 *(ULONG*)&sendBuffer[4] = htonl(timeNow);
271 *(signed int*)&sendBuffer[8] = htonl(timeOffset);
273 tcp.sendPacket(sendBuffer, 12);
274 log->log("Client", Log::DEBUG, "written login reply");
280 int MVPClient::processGetRecordingsList(UCHAR* data, int length)
282 UCHAR* sendBuffer = new UCHAR[50000]; // hope this is enough
283 int count = 4; // leave space for the packet length
288 int Percent = VideoDiskSpace(&FreeMB);
289 int Total = (FreeMB / (100 - Percent)) * 100;
291 *(ULONG*)&sendBuffer[count] = htonl(Total);
292 count += sizeof(ULONG);
293 *(ULONG*)&sendBuffer[count] = htonl(FreeMB);
294 count += sizeof(ULONG);
295 *(ULONG*)&sendBuffer[count] = htonl(Percent);
296 count += sizeof(ULONG);
299 cRecordings Recordings;
302 for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
304 if (count > 49000) break; // just how big is that hard disk?!
305 *(ULONG*)&sendBuffer[count] = htonl(recording->start);// + timeOffset);
308 point = (char*)recording->Name();
309 strcpy((char*)&sendBuffer[count], point);
310 count += strlen(point) + 1;
312 point = (char*)recording->FileName();
313 strcpy((char*)&sendBuffer[count], point);
314 count += strlen(point) + 1;
317 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
319 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
321 tcp.sendPacket(sendBuffer, count);
323 log->log("Client", Log::DEBUG, "Written list");
328 int MVPClient::processDeleteRecording(UCHAR* data, int length)
330 // data is a pointer to the fileName string
332 cRecordings Recordings;
333 Recordings.Load(); // probably have to do this
335 cRecording* recording = Recordings.GetByName((char*)data);
337 log->log("Client", Log::DEBUG, "recording pointer %p", recording);
341 log->log("Client", Log::DEBUG, "deleting recording: %s", recording->Name());
353 int MVPClient::processGetSummary(UCHAR* data, int length)
355 // data is a pointer to the fileName string
357 cRecordings Recordings;
358 Recordings.Load(); // probably have to do this
360 cRecording *recording = Recordings.GetByName((char*)data);
362 log->log("Client", Log::DEBUG, "recording pointer %p", recording);
366 UCHAR* sendBuffer = new UCHAR[50000]; // hope this is enough
367 int count = 4; // leave space for the packet length
370 #if VDRVERSNUM < 10300
371 point = (char*)recording->Summary();
373 const cRecordingInfo *Info = recording->Info();
374 point = (char*)Info->ShortText();
375 log->log("Client", Log::DEBUG, "info pointer %p summary pointer %p", Info, point);
378 point = (char*)Info->Description();
379 log->log("Client", Log::DEBUG, "description pointer %p", point);
382 strcpy((char*)&sendBuffer[count], point);
383 count += strlen(point) + 1;
384 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
386 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
388 tcp.sendPacket(sendBuffer, count);
390 log->log("Client", Log::DEBUG, "Written summary");
402 int MVPClient::processGetChannelsList(UCHAR* data, int length)
404 UCHAR* sendBuffer = new UCHAR[50000]; // FIXME hope this is enough
405 int count = 4; // leave space for the packet length
409 char* chanConfig = config.getValueString("General", "Channels");
411 if (chanConfig) allChans = strcasecmp(chanConfig, "FTA only");
413 for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
415 #if VDRVERSNUM < 10300
416 if (!channel->GroupSep() && (!channel->Ca() || allChans))
418 if (!channel->GroupSep() && (!channel->Ca(0) || allChans))
421 log->log("Client", Log::DEBUG, "name: '%s'", channel->Name());
423 if (channel->Vpid()) type = 1;
424 #if VDRVERSNUM < 10300
427 else if (channel->Apid(0)) type = 2;
431 if (count > 49000) break;
432 *(ULONG*)&sendBuffer[count] = htonl(channel->Number());
435 *(ULONG*)&sendBuffer[count] = htonl(type);
438 point = (char*)channel->Name();
439 strcpy((char*)&sendBuffer[count], point);
440 count += strlen(point) + 1;
444 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
446 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
448 tcp.sendPacket(sendBuffer, count);
450 log->log("Client", Log::DEBUG, "Written channels list");
455 int MVPClient::processStartStreamingChannel(UCHAR* data, int length)
457 log->log("Client", Log::DEBUG, "length = %i", length);
458 ULONG channelNumber = ntohl(*(ULONG*)data);
460 cChannel* channel = channelFromNumber(channelNumber);
467 // get the priority we should use
469 int priority = config.getValueLong("General", "Live priority", &fail);
472 log->log("Client", Log::DEBUG, "Config: Live TV priority: %i", priority);
476 log->log("Client", Log::DEBUG, "Config: Live TV priority config fail");
481 if (priority < 0) priority = 0;
482 if (priority > 99) priority = 99;
484 log->log("Client", Log::DEBUG, "Using live TV priority %i", priority);
485 lp = MVPReceiver::create(channel, priority);
505 int MVPClient::processStopStreaming(UCHAR* data, int length)
507 log->log("Client", Log::DEBUG, "STOP STREAMING RECEIVED");
518 delete recordingManager;
520 recordingManager = NULL;
527 int MVPClient::processGetBlock(UCHAR* data, int length)
531 log->log("Client", Log::DEBUG, "Get block called when no streaming happening!");
535 ULLONG position = ntohll(*(ULLONG*)data);
536 data += sizeof(ULLONG);
537 ULONG amount = ntohl(*(ULONG*)data);
539 log->log("Client", Log::DEBUG, "getblock pos = %llu length = %lu", position, amount);
541 UCHAR sendBuffer[amount + 4];
542 ULONG amountReceived = 0; // compiler moan.
545 log->log("Client", Log::DEBUG, "getting from live");
546 amountReceived = lp->getBlock(&sendBuffer[4], amount);
550 // vdr has possibly disconnected the receiver
551 log->log("Client", Log::DEBUG, "VDR has disconnected the live receiver");
558 log->log("Client", Log::DEBUG, "getting from recording");
559 amountReceived = rp->getBlock(&sendBuffer[4], position, amount);
562 *(ULONG*)&sendBuffer[0] = htonl(amountReceived);
563 tcp.sendPacket(sendBuffer, amountReceived + 4);
564 log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
569 int MVPClient::processStartStreamingRecording(UCHAR* data, int length)
571 // data is a pointer to the fileName string
573 recordingManager = new cRecordings;
574 recordingManager->Load();
576 cRecording* recording = recordingManager->GetByName((char*)data);
578 log->log("Client", Log::DEBUG, "recording pointer %p", recording);
582 rp = new RecPlayer(recording);
584 UCHAR sendBuffer[12];
585 *(ULONG*)&sendBuffer[0] = htonl(8);
586 *(ULLONG*)&sendBuffer[4] = htonll(rp->getTotalLength());
588 tcp.sendPacket(sendBuffer, 12);
589 log->log("Client", Log::DEBUG, "written totalLength");
593 delete recordingManager;
594 recordingManager = NULL;
599 int MVPClient::processReScanRecording(UCHAR* data, int length)
605 log->log("Client", Log::DEBUG, "Rescan recording called when no recording being played!");
610 retval = rp->getTotalLength();
613 UCHAR sendBuffer[12];
614 *(ULONG*)&sendBuffer[0] = htonl(8);
615 *(ULLONG*)&sendBuffer[4] = htonll(retval);
617 tcp.sendPacket(sendBuffer, 12);
618 log->log("Client", Log::DEBUG, "Rescan recording, wrote new length to client");
622 int MVPClient::processGetChannelSchedule(UCHAR* data, int length)
624 ULONG channelNumber = ntohl(*(ULLONG*)data);
626 ULONG startTime = ntohl(*(ULLONG*)data);
628 ULONG duration = ntohl(*(ULLONG*)data);
630 log->log("Client", Log::DEBUG, "get schedule called for channel %lu", channelNumber);
632 cChannel* channel = channelFromNumber(channelNumber);
636 *(ULONG*)&sendBuffer[0] = htonl(4);
637 *(ULONG*)&sendBuffer[4] = htonl(0);
638 tcp.sendPacket(sendBuffer, 8);
639 log->log("Client", Log::DEBUG, "written 0 because channel = NULL");
643 log->log("Client", Log::DEBUG, "Got channel");
645 #if VDRVERSNUM < 10300
646 cMutexLock MutexLock;
647 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
649 cSchedulesLock MutexLock;
650 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
655 *(ULONG*)&sendBuffer[0] = htonl(4);
656 *(ULONG*)&sendBuffer[4] = htonl(0);
657 tcp.sendPacket(sendBuffer, 8);
658 log->log("Client", Log::DEBUG, "written 0 because Schedule!s! = NULL");
662 log->log("Client", Log::DEBUG, "Got schedule!s! object");
664 const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
668 *(ULONG*)&sendBuffer[0] = htonl(4);
669 *(ULONG*)&sendBuffer[4] = htonl(0);
670 tcp.sendPacket(sendBuffer, 8);
671 log->log("Client", Log::DEBUG, "written 0 because Schedule = NULL");
675 log->log("Client", Log::DEBUG, "Got schedule object");
677 UCHAR* sendBuffer = (UCHAR*)malloc(100000);
678 ULONG sendBufferLength = 100000;
679 ULONG sendBufferUsed = sizeof(ULONG); // leave a hole for the entire packet length
683 // assign all the event info to temp vars then we know exactly what size they are
686 ULONG thisEventDuration;
687 const char* thisEventTitle;
688 const char* thisEventSubTitle;
689 const char* thisEventDescription;
691 ULONG constEventLength = sizeof(thisEventID) + sizeof(thisEventTime) + sizeof(thisEventDuration);
692 ULONG thisEventLength;
694 #if VDRVERSNUM < 10300
696 const cEventInfo *event;
697 for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
699 event = Schedule->GetEventNumber(eventNumber);
701 thisEventID = event->GetEventID();
702 thisEventTime = event->GetTime();
703 thisEventDuration = event->GetDuration();
704 thisEventTitle = event->GetTitle();
705 thisEventSubTitle = event->GetSubtitle();
706 thisEventDescription = event->GetExtendedDescription();
710 for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
712 thisEventID = event->EventID();
713 thisEventTime = event->StartTime();
714 thisEventDuration = event->Duration();
715 thisEventTitle = event->Title();
716 thisEventSubTitle = NULL;
717 thisEventDescription = event->Description();
721 log->log("Client", Log::DEBUG, "Got an event object %p", event);
724 if ((thisEventTime + thisEventDuration) < (ULONG)time(NULL)) continue;
727 if ((thisEventTime + thisEventDuration) <= startTime) continue;
730 if (thisEventTime >= (startTime + duration)) continue;
732 if (!thisEventTitle) thisEventTitle = empty;
733 if (!thisEventSubTitle) thisEventSubTitle = empty;
734 if (!thisEventDescription) thisEventDescription = empty;
736 thisEventLength = constEventLength + strlen(thisEventTitle) + 1 + strlen(thisEventSubTitle) + 1 + strlen(thisEventDescription) + 1;
738 log->log("Client", Log::DEBUG, "Done s1");
740 // now extend the buffer if necessary
741 if ((sendBufferUsed + thisEventLength) > sendBufferLength)
743 log->log("Client", Log::DEBUG, "Extending buffer");
744 sendBufferLength += 100000;
745 UCHAR* temp = (UCHAR*)realloc(sendBuffer, sendBufferLength);
749 UCHAR sendBuffer2[8];
750 *(ULONG*)&sendBuffer2[0] = htonl(4);
751 *(ULONG*)&sendBuffer2[4] = htonl(0);
752 tcp.sendPacket(sendBuffer2, 8);
753 log->log("Client", Log::DEBUG, "written 0 because failed to realloc packet");
759 log->log("Client", Log::DEBUG, "Done s2");
761 *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventID); sendBufferUsed += sizeof(ULONG);
762 *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventTime); sendBufferUsed += sizeof(ULONG);
763 *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventDuration); sendBufferUsed += sizeof(ULONG);
765 strcpy((char*)&sendBuffer[sendBufferUsed], thisEventTitle); sendBufferUsed += strlen(thisEventTitle) + 1;
766 strcpy((char*)&sendBuffer[sendBufferUsed], thisEventSubTitle); sendBufferUsed += strlen(thisEventSubTitle) + 1;
767 strcpy((char*)&sendBuffer[sendBufferUsed], thisEventDescription); sendBufferUsed += strlen(thisEventDescription) + 1;
769 log->log("Client", Log::DEBUG, "Done s3 %lu", sendBufferUsed);
772 log->log("Client", Log::DEBUG, "Got all event data");
774 // Write the length into the first 4 bytes. It's sendBufferUsed - 4 because of the hole!
775 *(ULONG*)&sendBuffer[0] = htonl(sendBufferUsed - sizeof(ULONG));
777 tcp.sendPacket(sendBuffer, sendBufferUsed);
778 log->log("Client", Log::DEBUG, "written %lu schedules packet", sendBufferUsed);
785 int MVPClient::processConfigSave(UCHAR* buffer, int length)
787 char* section = (char*)buffer;
791 for (int k = 0; k < length; k++)
793 if (buffer[k] == '\0')
797 key = (char*)&buffer[k+1];
801 value = (char*)&buffer[k+1];
807 // if the last string (value) doesnt have null terminator, give up
808 if (buffer[length - 1] != '\0') return 0;
810 log->log("Client", Log::DEBUG, "Config save: %s %s %s", section, key, value);
811 if (config.setValueString(section, key, value))
823 int MVPClient::processConfigLoad(UCHAR* buffer, int length)
825 char* section = (char*)buffer;
828 for (int k = 0; k < length; k++)
830 if (buffer[k] == '\0')
832 key = (char*)&buffer[k+1];
837 char* value = config.getValueString(section, key);
841 UCHAR sendBuffer[4 + strlen(value) + 1];
842 *(ULONG*)&sendBuffer[0] = htonl(strlen(value) + 1);
843 strcpy((char*)&sendBuffer[4], value);
844 tcp.sendPacket(sendBuffer, 4 + strlen(value) + 1);
846 log->log("Client", Log::DEBUG, "Written config load packet");
852 *(ULONG*)&sendBuffer[0] = htonl(4);
853 *(ULONG*)&sendBuffer[4] = htonl(0);
854 tcp.sendPacket(sendBuffer, 8);
856 log->log("Client", Log::DEBUG, "Written config load failed packet");
862 void MVPClient::cleanConfig()
864 log->log("Client", Log::DEBUG, "Clean config");
866 cRecordings Recordings;
871 char* resumes = config.getSectionKeyNames("ResumeData", numReturns, length);
872 char* position = resumes;
873 for(int k = 0; k < numReturns; k++)
875 log->log("Client", Log::DEBUG, "EXAMINING: %i %i %p %s", k, numReturns, position, position);
877 cRecording* recording = Recordings.GetByName(position);
880 // doesn't exist anymore
881 log->log("Client", Log::DEBUG, "Found a recording that doesn't exist anymore");
882 config.deleteValue("ResumeData", position);
886 log->log("Client", Log::DEBUG, "This recording still exists");
889 position += strlen(position) + 1;
901 event = Schedule->GetPresentEvent();
903 fprintf(f, "\n\nCurrent event\n\n");
905 fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", 0, event->GetEventID(), event->GetTime(), event->GetDuration());
906 fprintf(f, "Event %i title = %s subtitle = %s\n", 0, event->GetTitle(), event->GetSubtitle());
907 fprintf(f, "Event %i extendeddescription = %s\n", 0, event->GetExtendedDescription());
908 fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", 0, event->IsFollowing(), event->IsPresent());
910 event = Schedule->GetFollowingEvent();
912 fprintf(f, "\n\nFollowing event\n\n");
914 fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", 0, event->GetEventID(), event->GetTime(), event->GetDuration());
915 fprintf(f, "Event %i title = %s subtitle = %s\n", 0, event->GetTitle(), event->GetSubtitle());
916 fprintf(f, "Event %i extendeddescription = %s\n", 0, event->GetExtendedDescription());
917 fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", 0, event->IsFollowing(), event->IsPresent());
923 fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", eventNumber, event->GetEventID(), event->GetTime(), event->GetDuration());
924 fprintf(f, "Event %i title = %s subtitle = %s\n", eventNumber, event->GetTitle(), event->GetSubtitle());
925 fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
926 fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", eventNumber, event->IsFollowing(), event->IsPresent());
934 void MVPClient::test2()
936 FILE* f = fopen("/tmp/s.txt", "w");
938 #if VDRVERSNUM < 10300
939 cMutexLock MutexLock;
940 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
942 cSchedulesLock MutexLock;
943 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
948 fprintf(f, "Schedules = NULL\n");
953 fprintf(f, "Schedules dump:\n");
957 const cSchedule *Schedule;
958 int scheduleNumber = 0;
961 cChannel *thisChannel;
963 #if VDRVERSNUM < 10300
964 const cEventInfo *event;
970 // Schedule = Schedules->GetSchedule(channel->GetChannelID());
971 // Schedule = Schedules->GetSchedule();
972 Schedule = Schedules->First();
975 fprintf(f, "First Schedule = NULL\n");
982 fprintf(f, "Schedule #%i\n", scheduleNumber);
983 fprintf(f, "-------------\n\n");
985 #if VDRVERSNUM < 10300
986 tchid = Schedule->GetChannelID();
988 tchid = Schedule->ChannelID();
991 #if VDRVERSNUM < 10300
992 fprintf(f, "ChannelID.ToString() = %s\n", tchid.ToString());
993 fprintf(f, "NumEvents() = %i\n", Schedule->NumEvents());
995 // put the count at the end.
998 thisChannel = Channels.GetByChannelID(tchid, true);
1001 fprintf(f, "Channel Number: %p %i\n", thisChannel, thisChannel->Number());
1005 fprintf(f, "thisChannel = NULL for tchid\n");
1008 #if VDRVERSNUM < 10300
1009 for (eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1011 event = Schedule->GetEventNumber(eventNumber);
1012 fprintf(f, "Event %i tableid = %i timestring = %s endtimestring = %s\n", eventNumber, event->GetTableID(), event->GetTimeString(), event->GetEndTimeString());
1013 fprintf(f, "Event %i date = %s isfollowing = %i ispresent = %i\n", eventNumber, event->GetDate(), event->IsFollowing(), event->IsPresent());
1014 fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
1015 fprintf(f, "Event %i subtitle = %s title = %s\n", eventNumber, event->GetSubtitle(), event->GetTitle());
1016 fprintf(f, "Event %i eventid = %u duration = %li time = %lu channelnumber = %i\n", eventNumber, event->GetEventID(), event->GetDuration(), event->GetTime(), event->GetChannelNumber());
1017 fprintf(f, "Event %u dump:\n", eventNumber);
1022 // This whole section needs rewriting to walk the list.
1023 event = Schedule->Events()->First();
1025 event = Schedule->Events()->Next(event);
1030 fprintf(f, "\nDump from object:\n");
1032 fprintf(f, "\nEND\n");
1042 fprintf(f, "End of current Schedule\n\n\n");
1044 Schedule = (const cSchedule *)Schedules->Next(Schedule);
1058 const cEventInfo *GetPresentEvent(void) const;
1059 const cEventInfo *GetFollowingEvent(void) const;
1060 const cEventInfo *GetEvent(unsigned short uEventID, time_t tTime = 0) const;
1061 const cEventInfo *GetEventAround(time_t tTime) const;
1062 const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); }
1065 const unsigned char GetTableID(void) const;
1066 const char *GetTimeString(void) const;
1067 const char *GetEndTimeString(void) const;
1068 const char *GetDate(void) const;
1069 bool IsFollowing(void) const;
1070 bool IsPresent(void) const;
1071 const char *GetExtendedDescription(void) const;
1072 const char *GetSubtitle(void) const;
1073 const char *GetTitle(void) const;
1074 unsigned short GetEventID(void) const;
1075 long GetDuration(void) const;
1076 time_t GetTime(void) const;
1077 tChannelID GetChannelID(void) const;
1078 int GetChannelNumber(void) const { return nChannelNumber; }
1079 void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const'
1080 void Dump(FILE *f, const char *Prefix = "") const;
1086 void MVPClient::test(int channelNumber)
1088 FILE* f = fopen("/tmp/test.txt", "w");
1090 cMutexLock MutexLock;
1091 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1095 fprintf(f, "Schedules = NULL\n");
1100 fprintf(f, "Schedules dump:\n");
1101 // Schedules->Dump(f);
1103 const cSchedule *Schedule;
1104 cChannel *thisChannel;
1105 const cEventInfo *event;
1107 thisChannel = channelFromNumber(channelNumber);
1110 fprintf(f, "thisChannel = NULL\n");
1115 Schedule = Schedules->GetSchedule(thisChannel->GetChannelID());
1116 // Schedule = Schedules->GetSchedule();
1117 // Schedule = Schedules->First();
1120 fprintf(f, "First Schedule = NULL\n");
1125 fprintf(f, "NumEvents() = %i\n\n", Schedule->NumEvents());
1127 // For some channels VDR seems to pick a random point in time to
1128 // start dishing out events, but they are in order
1129 // at some point in the list the time snaps to the current event
1134 for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1136 event = Schedule->GetEventNumber(eventNumber);
1137 fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", eventNumber, event->GetEventID(), event->GetTime(), event->GetDuration());
1138 fprintf(f, "Event %i title = %s subtitle = %s\n", eventNumber, event->GetTitle(), event->GetSubtitle());
1139 fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
1143 fprintf(f, "\nEND\n");
1157 Schedules = the collection of all the Schedule objects
1158 Schedule = One schedule, contants all the events for a channel
1159 Event = One programme
1168 Subtitle (used for "Programmes resume at ...")
1171 IsPresent ? easy to work out tho. Oh it doesn't always work
1176 void MVPClient::test2()
1178 log->log("-", Log::DEBUG, "Timers List");
1180 for (int i = 0; i < Timers.Count(); i++)
1182 cTimer *timer = Timers.Get(i);
1183 //Reply(i < Timers.Count() - 1 ? -250 : 250, "%d %s", timer->Index() + 1, timer->ToText());
1184 log->log("-", Log::DEBUG, "i=%i count=%i index=%d", i, Timers.Count(), timer->Index() + 1);
1185 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());
1186 log->log("-", Log::DEBUG, "channel=%i file=%s summary=%s", timer->Channel()->Number(), timer->File(), timer->Summary());
1187 log->log("-", Log::DEBUG, "");
1190 // asprintf(&buffer, "%d:%s:%s :%04d:%04d:%d:%d:%s:%s\n",
1191 // active, (UseChannelID ? Channel()->GetChannelID().ToString() : itoa(Channel()->Number())),
1192 // PrintDay(day, firstday), start, stop, priority, lifetime, file, summary ? summary : "");
1197 Active seems to be a bool - whether the timer should be done or not. If set to inactive it stays around after its time
1198 recording is a bool, 0 for not currently recording, 1 for currently recording
1199 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
1203 int MVPClient::processGetTimers(UCHAR* buffer, int length)
1205 UCHAR* sendBuffer = new UCHAR[50000]; // FIXME hope this is enough
1206 int count = 4; // leave space for the packet length
1210 int numTimers = Timers.Count();
1212 // *(ULONG*)&sendBuffer[count] = htonl(numTimers); count += 4;
1214 for (int i = 0; i < numTimers; i++)
1216 if (count > 49000) break;
1218 timer = Timers.Get(i);
1220 *(ULONG*)&sendBuffer[count] = htonl(timer->Active()); count += 4;
1221 *(ULONG*)&sendBuffer[count] = htonl(timer->Recording()); count += 4;
1222 *(ULONG*)&sendBuffer[count] = htonl(timer->Pending()); count += 4;
1223 *(ULONG*)&sendBuffer[count] = htonl(timer->Priority()); count += 4;
1224 *(ULONG*)&sendBuffer[count] = htonl(timer->Lifetime()); count += 4;
1225 *(ULONG*)&sendBuffer[count] = htonl(timer->Channel()->Number()); count += 4;
1226 *(ULONG*)&sendBuffer[count] = htonl(timer->StartTime()); count += 4;
1227 *(ULONG*)&sendBuffer[count] = htonl(timer->StopTime()); count += 4;
1229 string = timer->File();
1230 strcpy((char*)&sendBuffer[count], string);
1231 count += strlen(string) + 1;
1233 string = timer->Summary();
1234 strcpy((char*)&sendBuffer[count], string);
1235 count += strlen(string) + 1;
1238 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
1240 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
1242 tcp.sendPacket(sendBuffer, count);
1243 delete[] sendBuffer;
1244 log->log("Client", Log::DEBUG, "Written timers list");