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);
66 MVPClient::~MVPClient()
68 log->log("Client", Log::DEBUG, "MVP client destructor");
79 delete recordingManager;
81 recordingManager = NULL;
84 if (loggedIn) cleanConfig();
87 cChannel* MVPClient::channelFromNumber(ULONG channelNumber)
89 cChannel* channel = NULL;
91 for (channel = Channels.First(); channel; channel = Channels.Next(channel))
93 if (!channel->GroupSep())
95 log->log("Client", Log::DEBUG, "Looking for channel %lu::: number: %i name: '%s'", channelNumber, channel->Number(), channel->Name());
97 if (channel->Number() == (int)channelNumber)
99 int vpid = channel->Vpid();
100 #if VDRVERSNUM < 10300
101 int apid1 = channel->Apid1();
103 int apid1 = channel->Apid(0);
105 log->log("Client", Log::DEBUG, "Found channel number %lu, vpid = %i, apid1 = %i", channelNumber, vpid, apid1);
113 log->log("Client", Log::DEBUG, "Channel not found");
120 void MVPClient::writeResumeData()
122 config.setValueLongLong("ResumeData", (char*)rp->getCurrentRecording()->FileName(), rp->getLastPosition());
125 void MVPClient::sendULONG(ULONG ul)
128 *(ULONG*)&sendBuffer[0] = htonl(4);
129 *(ULONG*)&sendBuffer[4] = htonl(ul);
131 tcp.sendPacket(sendBuffer, 8);
132 log->log("Client", Log::DEBUG, "written ULONG %lu", ul);
135 void MVPClientStartThread(void* arg)
137 MVPClient* m = (MVPClient*)arg;
139 // Nothing external to this class has a reference to it
140 // This is the end of the thread.. so delete m
147 if (pthread_create(&runThread, NULL, (void*(*)(void*))MVPClientStartThread, (void *)this) == -1) return 0;
148 log->log("Client", Log::DEBUG, "MVPClient run success");
152 void MVPClient::run2()
157 pthread_sigmask(SIG_BLOCK, &sigset, NULL);
158 pthread_detach(runThread); // Detach
160 tcp.disableReadTimeout();
162 tcp.setSoKeepTime(3);
163 tcp.setNonBlocking();
173 log->log("Client", Log::DEBUG, "Waiting");
174 buffer = (UCHAR*)tcp.receivePacket();
175 log->log("Client", Log::DEBUG, "Received packet, length = %u", tcp.getDataLength());
178 log->log("Client", Log::DEBUG, "Detected connection closed");
182 packetLength = tcp.getDataLength() - 4;
183 opcode = ntohl(*(ULONG*)buffer);
186 if (!loggedIn && (opcode != 1))
195 result = processLogin(data, packetLength);
198 result = processGetRecordingsList(data, packetLength);
201 result = processDeleteRecording(data, packetLength);
204 result = processGetSummary(data, packetLength);
207 result = processGetChannelsList(data, packetLength);
210 result = processStartStreamingChannel(data, packetLength);
213 result = processGetBlock(data, packetLength);
216 result = processStopStreaming(data, packetLength);
219 result = processStartStreamingRecording(data, packetLength);
222 result = processGetChannelSchedule(data, packetLength);
225 result = processConfigSave(data, packetLength);
228 result = processConfigLoad(data, packetLength);
231 result = processReScanRecording(data, packetLength);
240 int MVPClient::processLogin(UCHAR* buffer, int length)
242 if (length != 6) return 0;
246 const char* configDir = cPlugin::ConfigDirectory();
249 log->log("Client", Log::DEBUG, "No config dir!");
253 char configFileName[PATH_MAX];
254 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]);
255 config.init(configFileName);
257 // Send the login reply
259 time_t timeNow = time(NULL);
260 struct tm* timeStruct = localtime(&timeNow);
261 int timeOffset = timeStruct->tm_gmtoff;
263 UCHAR sendBuffer[12];
264 *(ULONG*)&sendBuffer[0] = htonl(8);
265 *(ULONG*)&sendBuffer[4] = htonl(timeNow);
266 *(signed int*)&sendBuffer[8] = htonl(timeOffset);
268 tcp.sendPacket(sendBuffer, 12);
269 log->log("Client", Log::DEBUG, "written login reply");
275 int MVPClient::processGetRecordingsList(UCHAR* data, int length)
277 UCHAR* sendBuffer = new UCHAR[50000]; // hope this is enough
278 int count = 4; // leave space for the packet length
283 int Percent = VideoDiskSpace(&FreeMB);
284 int Total = (FreeMB / (100 - Percent)) * 100;
286 *(ULONG*)&sendBuffer[count] = htonl(Total);
287 count += sizeof(ULONG);
288 *(ULONG*)&sendBuffer[count] = htonl(FreeMB);
289 count += sizeof(ULONG);
290 *(ULONG*)&sendBuffer[count] = htonl(Percent);
291 count += sizeof(ULONG);
294 cRecordings Recordings;
297 for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
299 if (count > 49000) break; // just how big is that hard disk?!
300 *(ULONG*)&sendBuffer[count] = htonl(recording->start);// + timeOffset);
303 point = (char*)recording->Name();
304 strcpy((char*)&sendBuffer[count], point);
305 count += strlen(point) + 1;
307 point = (char*)recording->FileName();
308 strcpy((char*)&sendBuffer[count], point);
309 count += strlen(point) + 1;
312 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
314 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
316 tcp.sendPacket(sendBuffer, count);
318 log->log("Client", Log::DEBUG, "Written list");
323 int MVPClient::processDeleteRecording(UCHAR* data, int length)
325 // data is a pointer to the fileName string
327 cRecordings Recordings;
328 Recordings.Load(); // probably have to do this
330 cRecording* recording = Recordings.GetByName((char*)data);
332 log->log("Client", Log::DEBUG, "recording pointer %p", recording);
336 log->log("Client", Log::DEBUG, "deleting recording: %s", recording->Name());
348 int MVPClient::processGetSummary(UCHAR* data, int length)
350 // data is a pointer to the fileName string
352 cRecordings Recordings;
353 Recordings.Load(); // probably have to do this
355 cRecording *recording = Recordings.GetByName((char*)data);
357 log->log("Client", Log::DEBUG, "recording pointer %p", recording);
361 UCHAR* sendBuffer = new UCHAR[50000]; // hope this is enough
362 int count = 4; // leave space for the packet length
365 #if VDRVERSNUM < 10300
366 point = (char*)recording->Summary();
368 const cRecordingInfo *Info = recording->Info();
369 point = (char*)Info->ShortText();
370 log->log("Client", Log::DEBUG, "info pointer %p summary pointer %p", Info, point);
373 point = (char*)Info->Description();
374 log->log("Client", Log::DEBUG, "description pointer %p", point);
377 strcpy((char*)&sendBuffer[count], point);
378 count += strlen(point) + 1;
379 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
381 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
383 tcp.sendPacket(sendBuffer, count);
385 log->log("Client", Log::DEBUG, "Written summary");
397 int MVPClient::processGetChannelsList(UCHAR* data, int length)
399 UCHAR* sendBuffer = new UCHAR[50000]; // FIXME hope this is enough
400 int count = 4; // leave space for the packet length
404 char* chanConfig = config.getValueString("General", "Channels");
406 if (chanConfig) allChans = strcasecmp(chanConfig, "FTA only");
408 for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
410 #if VDRVERSNUM < 10300
411 if (!channel->GroupSep() && (!channel->Ca() || allChans))
413 if (!channel->GroupSep() && (!channel->Ca(0) || allChans))
416 log->log("Client", Log::DEBUG, "name: '%s'", channel->Name());
418 if (channel->Vpid()) type = 1;
419 #if VDRVERSNUM < 10300
422 else if (channel->Apid(0)) type = 2;
426 if (count > 49000) break;
427 *(ULONG*)&sendBuffer[count] = htonl(channel->Number());
430 *(ULONG*)&sendBuffer[count] = htonl(type);
433 point = (char*)channel->Name();
434 strcpy((char*)&sendBuffer[count], point);
435 count += strlen(point) + 1;
439 *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field
441 log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(ULONG*)&sendBuffer[0]));
443 tcp.sendPacket(sendBuffer, count);
445 log->log("Client", Log::DEBUG, "Written channels list");
450 int MVPClient::processStartStreamingChannel(UCHAR* data, int length)
452 log->log("Client", Log::DEBUG, "length = %i", length);
453 ULONG channelNumber = ntohl(*(ULONG*)data);
455 cChannel* channel = channelFromNumber(channelNumber);
462 // get the priority we should use
464 int priority = config.getValueLong("General", "Live priority", &fail);
467 log->log("Client", Log::DEBUG, "Config: Live TV priority: %i", priority);
471 log->log("Client", Log::DEBUG, "Config: Live TV priority config fail");
476 if (priority < 0) priority = 0;
477 if (priority > 99) priority = 99;
479 log->log("Client", Log::DEBUG, "Using live TV priority %i", priority);
480 lp = MVPReceiver::create(channel, priority);
500 int MVPClient::processStopStreaming(UCHAR* data, int length)
502 log->log("Client", Log::DEBUG, "STOP STREAMING RECEIVED");
513 delete recordingManager;
515 recordingManager = NULL;
522 int MVPClient::processGetBlock(UCHAR* data, int length)
526 log->log("Client", Log::DEBUG, "Get block called when no streaming happening!");
530 ULLONG position = ntohll(*(ULLONG*)data);
531 data += sizeof(ULLONG);
532 ULONG amount = ntohl(*(ULONG*)data);
534 log->log("Client", Log::DEBUG, "getblock pos = %llu length = %lu", position, amount);
536 UCHAR sendBuffer[amount + 4];
537 ULONG amountReceived = 0; // compiler moan.
540 log->log("Client", Log::DEBUG, "getting from live");
541 amountReceived = lp->getBlock(&sendBuffer[4], amount);
545 // vdr has possibly disconnected the receiver
546 log->log("Client", Log::DEBUG, "VDR has disconnected the live receiver");
553 log->log("Client", Log::DEBUG, "getting from recording");
554 amountReceived = rp->getBlock(&sendBuffer[4], position, amount);
557 *(ULONG*)&sendBuffer[0] = htonl(amountReceived);
558 tcp.sendPacket(sendBuffer, amountReceived + 4);
559 log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
564 int MVPClient::processStartStreamingRecording(UCHAR* data, int length)
566 // data is a pointer to the fileName string
568 recordingManager = new cRecordings;
569 recordingManager->Load();
571 cRecording* recording = recordingManager->GetByName((char*)data);
573 log->log("Client", Log::DEBUG, "recording pointer %p", recording);
577 rp = new RecPlayer(recording);
579 UCHAR sendBuffer[12];
580 *(ULONG*)&sendBuffer[0] = htonl(8);
581 *(ULLONG*)&sendBuffer[4] = htonll(rp->getTotalLength());
583 tcp.sendPacket(sendBuffer, 12);
584 log->log("Client", Log::DEBUG, "written totalLength");
588 delete recordingManager;
589 recordingManager = NULL;
594 int MVPClient::processReScanRecording(UCHAR* data, int length)
600 log->log("Client", Log::DEBUG, "Rescan recording called when no recording being played!");
605 retval = rp->getTotalLength();
608 UCHAR sendBuffer[12];
609 *(ULONG*)&sendBuffer[0] = htonl(8);
610 *(ULLONG*)&sendBuffer[4] = htonll(retval);
612 tcp.sendPacket(sendBuffer, 12);
613 log->log("Client", Log::DEBUG, "Rescan recording, wrote new length to client");
617 int MVPClient::processGetChannelSchedule(UCHAR* data, int length)
619 ULONG channelNumber = ntohl(*(ULLONG*)data);
621 ULONG startTime = ntohl(*(ULLONG*)data);
623 ULONG duration = ntohl(*(ULLONG*)data);
625 log->log("Client", Log::DEBUG, "get schedule called for channel %lu", channelNumber);
627 cChannel* channel = channelFromNumber(channelNumber);
631 *(ULONG*)&sendBuffer[0] = htonl(4);
632 *(ULONG*)&sendBuffer[4] = htonl(0);
633 tcp.sendPacket(sendBuffer, 8);
634 log->log("Client", Log::DEBUG, "written 0 because channel = NULL");
638 log->log("Client", Log::DEBUG, "Got channel");
640 #if VDRVERSNUM < 10300
641 cMutexLock MutexLock;
642 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
644 cSchedulesLock MutexLock;
645 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
650 *(ULONG*)&sendBuffer[0] = htonl(4);
651 *(ULONG*)&sendBuffer[4] = htonl(0);
652 tcp.sendPacket(sendBuffer, 8);
653 log->log("Client", Log::DEBUG, "written 0 because Schedule!s! = NULL");
657 log->log("Client", Log::DEBUG, "Got schedule!s! object");
659 const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
663 *(ULONG*)&sendBuffer[0] = htonl(4);
664 *(ULONG*)&sendBuffer[4] = htonl(0);
665 tcp.sendPacket(sendBuffer, 8);
666 log->log("Client", Log::DEBUG, "written 0 because Schedule = NULL");
670 log->log("Client", Log::DEBUG, "Got schedule object");
672 UCHAR* sendBuffer = (UCHAR*)malloc(100000);
673 ULONG sendBufferLength = 100000;
674 ULONG sendBufferUsed = sizeof(ULONG); // leave a hole for the entire packet length
678 // assign all the event info to temp vars then we know exactly what size they are
681 ULONG thisEventDuration;
682 const char* thisEventTitle;
683 const char* thisEventSubTitle;
684 const char* thisEventDescription;
686 ULONG constEventLength = sizeof(thisEventID) + sizeof(thisEventTime) + sizeof(thisEventDuration);
687 ULONG thisEventLength;
689 #if VDRVERSNUM < 10300
691 const cEventInfo *event;
692 for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
694 event = Schedule->GetEventNumber(eventNumber);
696 thisEventID = event->GetEventID();
697 thisEventTime = event->GetTime();
698 thisEventDuration = event->GetDuration();
699 thisEventTitle = event->GetTitle();
700 thisEventSubTitle = event->GetSubtitle();
701 thisEventDescription = event->GetExtendedDescription();
705 for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
707 thisEventID = event->EventID();
708 thisEventTime = event->StartTime();
709 thisEventDuration = event->Duration();
710 thisEventTitle = event->Title();
711 thisEventSubTitle = NULL;
712 thisEventDescription = event->Description();
716 log->log("Client", Log::DEBUG, "Got an event object %p", event);
719 if ((thisEventTime + thisEventDuration) < (ULONG)time(NULL)) continue;
722 if ((thisEventTime + thisEventDuration) <= startTime) continue;
725 if (thisEventTime >= (startTime + duration)) continue;
727 if (!thisEventTitle) thisEventTitle = empty;
728 if (!thisEventSubTitle) thisEventSubTitle = empty;
729 if (!thisEventDescription) thisEventDescription = empty;
731 thisEventLength = constEventLength + strlen(thisEventTitle) + 1 + strlen(thisEventSubTitle) + 1 + strlen(thisEventDescription) + 1;
733 log->log("Client", Log::DEBUG, "Done s1");
735 // now extend the buffer if necessary
736 if ((sendBufferUsed + thisEventLength) > sendBufferLength)
738 log->log("Client", Log::DEBUG, "Extending buffer");
739 sendBufferLength += 100000;
740 UCHAR* temp = (UCHAR*)realloc(sendBuffer, sendBufferLength);
744 UCHAR sendBuffer2[8];
745 *(ULONG*)&sendBuffer2[0] = htonl(4);
746 *(ULONG*)&sendBuffer2[4] = htonl(0);
747 tcp.sendPacket(sendBuffer2, 8);
748 log->log("Client", Log::DEBUG, "written 0 because failed to realloc packet");
754 log->log("Client", Log::DEBUG, "Done s2");
756 *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventID); sendBufferUsed += sizeof(ULONG);
757 *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventTime); sendBufferUsed += sizeof(ULONG);
758 *(ULONG*)&sendBuffer[sendBufferUsed] = htonl(thisEventDuration); sendBufferUsed += sizeof(ULONG);
760 strcpy((char*)&sendBuffer[sendBufferUsed], thisEventTitle); sendBufferUsed += strlen(thisEventTitle) + 1;
761 strcpy((char*)&sendBuffer[sendBufferUsed], thisEventSubTitle); sendBufferUsed += strlen(thisEventSubTitle) + 1;
762 strcpy((char*)&sendBuffer[sendBufferUsed], thisEventDescription); sendBufferUsed += strlen(thisEventDescription) + 1;
764 log->log("Client", Log::DEBUG, "Done s3 %lu", sendBufferUsed);
767 log->log("Client", Log::DEBUG, "Got all event data");
769 // Write the length into the first 4 bytes. It's sendBufferUsed - 4 because of the hole!
770 *(ULONG*)&sendBuffer[0] = htonl(sendBufferUsed - sizeof(ULONG));
772 tcp.sendPacket(sendBuffer, sendBufferUsed);
773 log->log("Client", Log::DEBUG, "written %lu schedules packet", sendBufferUsed);
780 int MVPClient::processConfigSave(UCHAR* buffer, int length)
782 char* section = (char*)buffer;
786 for (int k = 0; k < length; k++)
788 if (buffer[k] == '\0')
792 key = (char*)&buffer[k+1];
796 value = (char*)&buffer[k+1];
802 // if the last string (value) doesnt have null terminator, give up
803 if (buffer[length - 1] != '\0') return 0;
805 log->log("Client", Log::DEBUG, "Config save: %s %s %s", section, key, value);
806 if (config.setValueString(section, key, value))
818 int MVPClient::processConfigLoad(UCHAR* buffer, int length)
820 char* section = (char*)buffer;
823 for (int k = 0; k < length; k++)
825 if (buffer[k] == '\0')
827 key = (char*)&buffer[k+1];
832 char* value = config.getValueString(section, key);
836 UCHAR sendBuffer[4 + strlen(value) + 1];
837 *(ULONG*)&sendBuffer[0] = htonl(strlen(value) + 1);
838 strcpy((char*)&sendBuffer[4], value);
839 tcp.sendPacket(sendBuffer, 4 + strlen(value) + 1);
841 log->log("Client", Log::DEBUG, "Written config load packet");
847 *(ULONG*)&sendBuffer[0] = htonl(4);
848 *(ULONG*)&sendBuffer[4] = htonl(0);
849 tcp.sendPacket(sendBuffer, 8);
851 log->log("Client", Log::DEBUG, "Written config load failed packet");
857 void MVPClient::cleanConfig()
859 log->log("Client", Log::DEBUG, "Clean config");
861 cRecordings Recordings;
866 char* resumes = config.getSectionKeyNames("ResumeData", numReturns, length);
867 char* position = resumes;
868 for(int k = 0; k < numReturns; k++)
870 log->log("Client", Log::DEBUG, "EXAMINING: %i %i %p %s", k, numReturns, position, position);
872 cRecording* recording = Recordings.GetByName(position);
875 // doesn't exist anymore
876 log->log("Client", Log::DEBUG, "Found a recording that doesn't exist anymore");
877 config.deleteValue("ResumeData", position);
881 log->log("Client", Log::DEBUG, "This recording still exists");
884 position += strlen(position) + 1;
896 event = Schedule->GetPresentEvent();
898 fprintf(f, "\n\nCurrent event\n\n");
900 fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", 0, event->GetEventID(), event->GetTime(), event->GetDuration());
901 fprintf(f, "Event %i title = %s subtitle = %s\n", 0, event->GetTitle(), event->GetSubtitle());
902 fprintf(f, "Event %i extendeddescription = %s\n", 0, event->GetExtendedDescription());
903 fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", 0, event->IsFollowing(), event->IsPresent());
905 event = Schedule->GetFollowingEvent();
907 fprintf(f, "\n\nFollowing event\n\n");
909 fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", 0, event->GetEventID(), event->GetTime(), event->GetDuration());
910 fprintf(f, "Event %i title = %s subtitle = %s\n", 0, event->GetTitle(), event->GetSubtitle());
911 fprintf(f, "Event %i extendeddescription = %s\n", 0, event->GetExtendedDescription());
912 fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", 0, event->IsFollowing(), event->IsPresent());
918 fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", eventNumber, event->GetEventID(), event->GetTime(), event->GetDuration());
919 fprintf(f, "Event %i title = %s subtitle = %s\n", eventNumber, event->GetTitle(), event->GetSubtitle());
920 fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
921 fprintf(f, "Event %i isFollowing = %i, isPresent = %i\n", eventNumber, event->IsFollowing(), event->IsPresent());
929 void MVPClient::test2()
931 FILE* f = fopen("/tmp/s.txt", "w");
933 #if VDRVERSNUM < 10300
934 cMutexLock MutexLock;
935 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
937 cSchedulesLock MutexLock;
938 const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
943 fprintf(f, "Schedules = NULL\n");
948 fprintf(f, "Schedules dump:\n");
952 const cSchedule *Schedule;
953 int scheduleNumber = 0;
956 cChannel *thisChannel;
958 #if VDRVERSNUM < 10300
959 const cEventInfo *event;
965 // Schedule = Schedules->GetSchedule(channel->GetChannelID());
966 // Schedule = Schedules->GetSchedule();
967 Schedule = Schedules->First();
970 fprintf(f, "First Schedule = NULL\n");
977 fprintf(f, "Schedule #%i\n", scheduleNumber);
978 fprintf(f, "-------------\n\n");
980 #if VDRVERSNUM < 10300
981 tchid = Schedule->GetChannelID();
983 tchid = Schedule->ChannelID();
986 #if VDRVERSNUM < 10300
987 fprintf(f, "ChannelID.ToString() = %s\n", tchid.ToString());
988 fprintf(f, "NumEvents() = %i\n", Schedule->NumEvents());
990 // put the count at the end.
993 thisChannel = Channels.GetByChannelID(tchid, true);
996 fprintf(f, "Channel Number: %p %i\n", thisChannel, thisChannel->Number());
1000 fprintf(f, "thisChannel = NULL for tchid\n");
1003 #if VDRVERSNUM < 10300
1004 for (eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1006 event = Schedule->GetEventNumber(eventNumber);
1007 fprintf(f, "Event %i tableid = %i timestring = %s endtimestring = %s\n", eventNumber, event->GetTableID(), event->GetTimeString(), event->GetEndTimeString());
1008 fprintf(f, "Event %i date = %s isfollowing = %i ispresent = %i\n", eventNumber, event->GetDate(), event->IsFollowing(), event->IsPresent());
1009 fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
1010 fprintf(f, "Event %i subtitle = %s title = %s\n", eventNumber, event->GetSubtitle(), event->GetTitle());
1011 fprintf(f, "Event %i eventid = %u duration = %li time = %lu channelnumber = %i\n", eventNumber, event->GetEventID(), event->GetDuration(), event->GetTime(), event->GetChannelNumber());
1012 fprintf(f, "Event %u dump:\n", eventNumber);
1017 // This whole section needs rewriting to walk the list.
1018 event = Schedule->Events()->First();
1020 event = Schedule->Events()->Next(event);
1025 fprintf(f, "\nDump from object:\n");
1027 fprintf(f, "\nEND\n");
1037 fprintf(f, "End of current Schedule\n\n\n");
1039 Schedule = (const cSchedule *)Schedules->Next(Schedule);
1053 const cEventInfo *GetPresentEvent(void) const;
1054 const cEventInfo *GetFollowingEvent(void) const;
1055 const cEventInfo *GetEvent(unsigned short uEventID, time_t tTime = 0) const;
1056 const cEventInfo *GetEventAround(time_t tTime) const;
1057 const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); }
1060 const unsigned char GetTableID(void) const;
1061 const char *GetTimeString(void) const;
1062 const char *GetEndTimeString(void) const;
1063 const char *GetDate(void) const;
1064 bool IsFollowing(void) const;
1065 bool IsPresent(void) const;
1066 const char *GetExtendedDescription(void) const;
1067 const char *GetSubtitle(void) const;
1068 const char *GetTitle(void) const;
1069 unsigned short GetEventID(void) const;
1070 long GetDuration(void) const;
1071 time_t GetTime(void) const;
1072 tChannelID GetChannelID(void) const;
1073 int GetChannelNumber(void) const { return nChannelNumber; }
1074 void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const'
1075 void Dump(FILE *f, const char *Prefix = "") const;
1081 void MVPClient::test(int channelNumber)
1083 FILE* f = fopen("/tmp/test.txt", "w");
1085 cMutexLock MutexLock;
1086 const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
1090 fprintf(f, "Schedules = NULL\n");
1095 fprintf(f, "Schedules dump:\n");
1096 // Schedules->Dump(f);
1098 const cSchedule *Schedule;
1099 cChannel *thisChannel;
1100 const cEventInfo *event;
1102 thisChannel = channelFromNumber(channelNumber);
1105 fprintf(f, "thisChannel = NULL\n");
1110 Schedule = Schedules->GetSchedule(thisChannel->GetChannelID());
1111 // Schedule = Schedules->GetSchedule();
1112 // Schedule = Schedules->First();
1115 fprintf(f, "First Schedule = NULL\n");
1120 fprintf(f, "NumEvents() = %i\n\n", Schedule->NumEvents());
1122 // For some channels VDR seems to pick a random point in time to
1123 // start dishing out events, but they are in order
1124 // at some point in the list the time snaps to the current event
1129 for (int eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
1131 event = Schedule->GetEventNumber(eventNumber);
1132 fprintf(f, "Event %i eventid = %u time = %lu duration = %li\n", eventNumber, event->GetEventID(), event->GetTime(), event->GetDuration());
1133 fprintf(f, "Event %i title = %s subtitle = %s\n", eventNumber, event->GetTitle(), event->GetSubtitle());
1134 fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
1138 fprintf(f, "\nEND\n");
1152 Schedules = the collection of all the Schedule objects
1153 Schedule = One schedule, contants all the events for a channel
1154 Event = One programme
1163 Subtitle (used for "Programmes resume at ...")
1166 IsPresent ? easy to work out tho. Oh it doesn't always work