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
23 VDR* VDR::instance = NULL;
32 pthread_mutex_init(&mutex, NULL);
42 if (initted) shutdown();
45 VDR* VDR::getInstance()
50 int VDR::init(int tport)
52 if (initted) return 0;
55 logger = Log::getInstance();
61 if (!initted) return 0;
67 void VDR::findServers(vector<VDRServer>& servers)
70 char* message = "VOMP";
71 DatagramSocket ds(port);
73 int haveAtLeastOne = 0;
80 logger->log("VDR", Log::NOTICE, "Broadcasting for server");
81 ds.send("255.255.255.255", 3024, message, strlen(message));
83 retval = ds.waitforMessage(waitType);
85 if (retval == 2) // we got a reply
87 if (!strcmp(ds.getData(), "VOMP")) // echo.....
94 newServer.ip = new char[16];
95 strcpy(newServer.ip, ds.getFromIPA());
97 if (ds.getDataLength() == 0)
99 newServer.name = new char[1];
100 newServer.name[0] = '\0';
104 newServer.name = new char[strlen(ds.getData())+1];
105 strcpy(newServer.name, ds.getData());
108 servers.push_back(newServer);
115 if (haveAtLeastOne) break;
119 sort(servers.begin(), servers.end(), ServerSorter());
122 void VDR::cancelFindingServer()
127 void VDR::setServerIP(char* newIP)
129 strcpy(serverIP, newIP);
136 if (tcp->connectTo(serverIP, 3024))
147 void VDR::disconnect()
152 Log::getInstance()->log("VDR", Log::DEBUG, "Disconnect");
155 void VDR::setReceiveWindow(size_t size)
157 if (connected) tcp->setReceiveWindow(size);
160 ///////////////////////////////////////////////////////
164 packet = (UCHAR*)tcp->receivePacket();
170 packetLength = tcp->getDataLength();
174 void VDR::freePacket()
176 // Must be called if getPacket return 1, except in getBlock
183 int VDR::serverError()
185 if ((packetPos == 0) && (packetLength == 4) && !ntohl(*(ULONG*)packet)) return 1;
189 char* VDR::extractString()
191 if (serverError()) return NULL;
193 int length = strlen((char*)&packet[packetPos]);
194 if ((packetPos + length) > packetLength) return NULL;
195 char* str = new char[length + 1];
196 strcpy(str, (char*)&packet[packetPos]);
197 packetPos += length + 1;
201 ULONG VDR::extractULONG()
203 if ((packetPos + sizeof(ULONG)) > packetLength) return 0;
204 ULONG ul = ntohl(*(ULONG*)&packet[packetPos]);
205 packetPos += sizeof(ULONG);
209 ULLONG VDR::extractULLONG()
211 if ((packetPos + sizeof(ULLONG)) > packetLength) return 0;
212 ULLONG ull = ntohll(*(ULLONG*)&packet[packetPos]);
213 packetPos += sizeof(ULLONG);
217 long VDR::extractLONG()
219 if ((packetPos + sizeof(long)) > packetLength) return 0;
220 long l = ntohl(*(long*)&packet[packetPos]);
221 packetPos += sizeof(long);
225 /////////////////////////////////////////////////////////////////////////////
231 *(unsigned long*)&buffer[0] = htonl(10);
232 *(unsigned long*)&buffer[4] = htonl(VDR_LOGIN);
234 tcp->getMAC((char*)&buffer[8]);
236 pthread_mutex_lock(&mutex);
237 if (!connected) { pthread_mutex_unlock(&mutex); return 0; }
239 int a = tcp->sendPacket(buffer, 14);
243 pthread_mutex_unlock(&mutex);
251 pthread_mutex_unlock(&mutex);
255 ULONG vdrTime = extractULONG();
256 logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
257 long vdrTimeOffset = extractLONG();
258 logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
261 pthread_mutex_unlock(&mutex);
264 struct timespec currentTime;
265 currentTime.tv_sec = vdrTime;
266 currentTime.tv_nsec = 0;
267 int b = clock_settime(CLOCK_REALTIME, ¤tTime);
269 logger->log("VDR", Log::DEBUG, "set clock = %u", b);
271 // now make a TZ variable and set it
275 if (vdrTimeOffset > 0) sign = '-';
278 vdrTimeOffset = abs(vdrTimeOffset);
280 hours = (int)vdrTimeOffset / 3600;
281 minutes = vdrTimeOffset % 3600;
283 logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
285 minutes = (int)minutes / 60;
287 logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
290 sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
291 setenv("TZ", newTZ, 1);
293 logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
298 Directory* VDR::getRecordingsList()
302 *(unsigned long*)&buffer[0] = htonl(4);
303 *(unsigned long*)&buffer[4] = htonl(VDR_GETRECORDINGLIST);
305 pthread_mutex_lock(&mutex);
306 if (!connected) { pthread_mutex_unlock(&mutex); return 0; }
308 int a = tcp->sendPacket(buffer, 8);
312 pthread_mutex_unlock(&mutex);
320 pthread_mutex_unlock(&mutex);
324 Directory* recDir = new Directory();
325 recDir->setName("/");
328 Directory::totalSpace = extractULONG();
329 Directory::freeSpace = extractULONG();
330 Directory::usedPercent = extractULONG();
334 while (packetPos < packetLength)
336 Recording* rec = new Recording();
338 rec->start = extractULONG();
340 string = extractString();
341 rec->setName(string);
344 rec->fileName = extractString();
348 char* dirName = rec->getDirName();
350 Directory* d = recDir->getDirByName(dirName);
355 // Log::getInstance()->log("VDR", Log::DEBUG, "Added a new directory = %s", d->name);
356 recDir->dirList.push_back(d);
359 d->recList.push_back(rec);
363 recDir->recList.push_back(rec);
366 // Log::getInstance()->log("VDR", Log::DEBUG, "%s", rec->fileName);
370 pthread_mutex_unlock(&mutex);
372 // Sort the directory order
373 sort(recDir->dirList.begin(), recDir->dirList.end(), DirectorySorter());
375 // Sort all the sub lists
378 DirectoryList::iterator i;
379 for (i = recDir->dirList.begin(); i != recDir->dirList.end(); i++)
382 sort(sortDir->recList.begin(), sortDir->recList.end(), RecordingSorter());
385 // Sort the root level list
386 sort(recDir->recList.begin(), recDir->recList.end(), RecordingSorter());
391 int VDR::deleteRecording(char* fileName)
393 unsigned long totalLength = 8 + strlen(fileName) + 1;
394 UCHAR buffer[totalLength];
396 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
397 *(unsigned long*)&buffer[4] = htonl(VDR_DELETERECORDING);
398 strcpy((char*)&buffer[8], fileName);
400 pthread_mutex_lock(&mutex);
401 if (!connected) { pthread_mutex_unlock(&mutex); return 0; }
403 unsigned int a = tcp->sendPacket(buffer, totalLength);
404 if (a != totalLength)
407 pthread_mutex_unlock(&mutex);
413 pthread_mutex_unlock(&mutex);
417 int toReturn = (int)extractULONG();
419 pthread_mutex_unlock(&mutex);
424 char* VDR::getRecordingSummary(char* fileName)
426 unsigned long totalLength = 8 + strlen(fileName) + 1;
427 UCHAR buffer[totalLength];
429 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
430 *(unsigned long*)&buffer[4] = htonl(VDR_GETSUMMARY);
431 strcpy((char*)&buffer[8], fileName);
433 pthread_mutex_lock(&mutex);
434 if (!connected) { pthread_mutex_unlock(&mutex); return 0; }
436 unsigned int a = tcp->sendPacket(buffer, totalLength);
437 if (a != totalLength)
440 pthread_mutex_unlock(&mutex);
446 pthread_mutex_unlock(&mutex);
449 char* toReturn = extractString();
451 pthread_mutex_unlock(&mutex);
456 ChannelList* VDR::getChannelsList(ULONG type)
460 *(unsigned long*)&buffer[0] = htonl(4);
461 *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELLIST);
463 pthread_mutex_lock(&mutex);
464 if (!connected) { pthread_mutex_unlock(&mutex); return 0; }
466 int a = tcp->sendPacket(buffer, 8);
470 pthread_mutex_unlock(&mutex);
478 pthread_mutex_unlock(&mutex);
482 ChannelList* chanList = new ChannelList();
484 while (packetPos < packetLength)
486 Channel* chan = new Channel();
487 chan->number = extractULONG();
488 chan->type = extractULONG();
489 chan->name = extractString();
491 if (chan->type == type)
493 chanList->push_back(chan);
494 Log::getInstance()->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
503 pthread_mutex_unlock(&mutex);
508 int VDR::streamChannel(ULONG number)
512 *(unsigned long*)&buffer[0] = htonl(8);
513 *(unsigned long*)&buffer[4] = htonl(VDR_STREAMCHANNEL);
514 *(unsigned long*)&buffer[8] = htonl(number);
516 pthread_mutex_lock(&mutex);
517 if (!connected) { pthread_mutex_unlock(&mutex); return 0; }
519 int a = tcp->sendPacket(buffer, 12);
524 pthread_mutex_unlock(&mutex);
530 pthread_mutex_unlock(&mutex);
534 int toReturn = (int)extractULONG();
536 pthread_mutex_unlock(&mutex);
541 int VDR::stopStreaming()
545 *(unsigned long*)&buffer[0] = htonl(4);
546 *(unsigned long*)&buffer[4] = htonl(VDR_STOPSTREAMING);
548 pthread_mutex_lock(&mutex);
549 if (!connected) { pthread_mutex_unlock(&mutex); return 0; }
551 int a = tcp->sendPacket(buffer, 8);
556 pthread_mutex_unlock(&mutex);
562 pthread_mutex_unlock(&mutex);
566 int toReturn = (int)extractULONG();
568 pthread_mutex_unlock(&mutex);
573 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
577 *(unsigned long*)&buffer[0] = htonl(16);
578 *(unsigned long*)&buffer[4] = htonl(VDR_GETBLOCK);
579 *(ULLONG*)&buffer[8] = htonll(position);
580 *(unsigned long*)&buffer[16] = htonl(maxAmount);
582 pthread_mutex_lock(&mutex);
583 if (!connected) { pthread_mutex_unlock(&mutex); return 0; }
585 int a = tcp->sendPacket(buffer, 20);
589 pthread_mutex_unlock(&mutex);
595 pthread_mutex_unlock(&mutex);
601 Log::getInstance()->log("VDR", Log::DEBUG, "Detected getblock 0");
603 pthread_mutex_unlock(&mutex);
607 UCHAR* toReturn = packet;
608 *amountReceived = packetLength;
609 // Manually clean up instead of running freePacket to keep the block
613 pthread_mutex_unlock(&mutex);
618 ULLONG VDR::streamRecording(Recording* rec)
620 unsigned long totalLength = 8 + strlen(rec->fileName) + 1;
621 UCHAR buffer[totalLength];
623 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
624 *(unsigned long*)&buffer[4] = htonl(VDR_STREAMRECORDING);
625 strcpy((char*)&buffer[8], rec->fileName);
627 pthread_mutex_lock(&mutex);
628 if (!connected) { pthread_mutex_unlock(&mutex); return 0; }
630 unsigned int a = tcp->sendPacket(buffer, totalLength);
631 if (a != totalLength)
634 pthread_mutex_unlock(&mutex);
640 pthread_mutex_unlock(&mutex);
644 ULLONG recordingLength = extractULLONG();
646 pthread_mutex_unlock(&mutex);
648 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
650 return recordingLength;
653 ULLONG VDR::rescanRecording()
655 unsigned long totalLength = 8;
656 UCHAR buffer[totalLength];
658 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
659 *(unsigned long*)&buffer[4] = htonl(VDR_RESCANRECORDING);
661 pthread_mutex_lock(&mutex);
662 if (!connected) { pthread_mutex_unlock(&mutex); return 0; }
664 unsigned int a = tcp->sendPacket(buffer, totalLength);
665 if (a != totalLength)
668 pthread_mutex_unlock(&mutex);
674 pthread_mutex_unlock(&mutex);
678 ULLONG recordingLength = extractULLONG();
680 pthread_mutex_unlock(&mutex);
682 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
684 return recordingLength;
687 ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)
689 unsigned long totalLength = 12;
690 UCHAR buffer[totalLength];
692 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
693 *(unsigned long*)&buffer[4] = htonl(VDR_POSFROMFRAME);
694 *(unsigned long*)&buffer[8] = htonl(frameNumber);
696 pthread_mutex_lock(&mutex);
697 if (!connected) { pthread_mutex_unlock(&mutex); return 0; }
699 unsigned int a = tcp->sendPacket(buffer, totalLength);
700 if (a != totalLength)
703 pthread_mutex_unlock(&mutex);
709 pthread_mutex_unlock(&mutex);
713 ULLONG position = extractULLONG();
715 pthread_mutex_unlock(&mutex);
717 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);
722 EventList* VDR::getChannelSchedule(ULONG number)
726 return getChannelSchedule(number, now, 24 * 60 * 60);
729 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
731 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
734 *(unsigned long*)&buffer[0] = htonl(16);
735 *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE);
736 *(unsigned long*)&buffer[8] = htonl(number);
737 *(unsigned long*)&buffer[12] = htonl(start);
738 *(unsigned long*)&buffer[16] = htonl(duration);
740 pthread_mutex_lock(&mutex);
741 if (!connected) { pthread_mutex_unlock(&mutex); return 0; }
743 int a = tcp->sendPacket(buffer, 20);
748 pthread_mutex_unlock(&mutex);
754 pthread_mutex_unlock(&mutex);
758 // received a ulong(0) - schedules error in the plugin
762 pthread_mutex_unlock(&mutex);
767 EventList* eventList = new EventList();
769 while (packetPos < packetLength)
771 Event* event = new Event();
772 event->id = extractULONG();
773 event->time = extractULONG();
774 event->duration = extractULONG();
775 event->title = extractString();
776 event->subtitle = extractString();
777 event->description = extractString();
778 eventList->push_back(event);
779 // eventList->next();
783 pthread_mutex_unlock(&mutex);
785 Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
790 Log* l = Log::getInstance();
793 l->log("VDR", Log::DEBUG, "datalength = %i count = %i", dataLength, count);
796 for(eventList->reset(); !eventList->eol(); eventList->next())
798 currentEvent = (Event*)eventList->getCurrent();
799 l->log("VDR", Log::DEBUG, "%lu %lu %lu %s %s %s", currentEvent->id, currentEvent->time, currentEvent->duration, currentEvent->title, currentEvent->subtitle, currentEvent->description);
806 ULLONG VDR::getResumePoint(char* fileName)
808 if (!connected) return 0;
810 char* resumeString = configLoad("ResumeData", fileName);
811 if (!resumeString) return 0;
813 ULLONG toReturn = STRTOULL(resumeString, NULL, 10);
814 delete[] resumeString;
818 int VDR::configSave(char* section, char* key, const char* value)
820 ULONG totalLength = 8 + strlen(section) + strlen(key) + strlen(value) + 3; // 8 for headers, 3 for nulls
821 UCHAR buffer[totalLength];
823 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
824 *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGSAVE);
827 strcpy((char*)&buffer[position], section);
828 position += strlen(section) + 1;
829 strcpy((char*)&buffer[position], key);
830 position += strlen(key) + 1;
831 strcpy((char*)&buffer[position], value);
833 pthread_mutex_lock(&mutex);
834 if (!connected) { pthread_mutex_unlock(&mutex); return 0; }
836 unsigned int a = tcp->sendPacket(buffer, totalLength);
837 if (a != totalLength)
840 pthread_mutex_unlock(&mutex);
846 pthread_mutex_unlock(&mutex);
850 int toReturn = (int)extractULONG();
852 pthread_mutex_unlock(&mutex);
857 char* VDR::configLoad(char* section, char* key)
859 ULONG totalLength = 8 + strlen(section) + strlen(key) + 2; // 8 for headers, 2 for nulls
860 UCHAR buffer[totalLength];
862 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
863 *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGLOAD);
866 strcpy((char*)&buffer[position], section);
867 position += strlen(section) + 1;
868 strcpy((char*)&buffer[position], key);
870 pthread_mutex_lock(&mutex);
871 if (!connected) { pthread_mutex_unlock(&mutex); return 0; }
873 unsigned int a = tcp->sendPacket(buffer, totalLength);
874 if (a != totalLength)
877 pthread_mutex_unlock(&mutex);
883 pthread_mutex_unlock(&mutex);
886 char* toReturn = extractString();
888 pthread_mutex_unlock(&mutex);
893 RecTimerList* VDR::getRecTimersList()
897 *(unsigned long*)&buffer[0] = htonl(4);
898 *(unsigned long*)&buffer[4] = htonl(VDR_GETTIMERS);
900 pthread_mutex_lock(&mutex);
901 if (!connected) { pthread_mutex_unlock(&mutex); return 0; }
903 int a = tcp->sendPacket(buffer, 8);
907 pthread_mutex_unlock(&mutex);
915 pthread_mutex_unlock(&mutex);
919 RecTimerList* recTimerList = new RecTimerList();
921 ULONG numTimers = extractULONG();
924 RecTimer* newRecTimer;
927 while (packetPos < packetLength)
929 newRecTimer = new RecTimer();
930 newRecTimer->active = extractULONG();
931 newRecTimer->recording = extractULONG();
932 newRecTimer->pending = extractULONG();
933 newRecTimer->priority = extractULONG();
934 newRecTimer->lifeTime = extractULONG();
935 newRecTimer->channelNumber = extractULONG();
936 newRecTimer->startTime = extractULONG();
937 newRecTimer->stopTime = extractULONG();
939 tempString = extractString();
940 newRecTimer->setFile(tempString);
943 recTimerList->push_back(newRecTimer);
944 Log::getInstance()->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
945 newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
946 newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
951 pthread_mutex_unlock(&mutex);
955 sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
960 ULONG VDR::setEventTimer(char* timerString)
962 unsigned long totalLength = 8 + strlen(timerString) + 1;
963 UCHAR buffer[totalLength];
965 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
966 *(unsigned long*)&buffer[4] = htonl(VDR_SETTIMER);
967 strcpy((char*)&buffer[8], timerString);
969 pthread_mutex_lock(&mutex);
970 if (!connected) { pthread_mutex_unlock(&mutex); return 0; }
972 unsigned int a = tcp->sendPacket(buffer, totalLength);
973 if (a != totalLength)
976 pthread_mutex_unlock(&mutex);
982 pthread_mutex_unlock(&mutex);
986 ULONG toReturn = extractULONG();
988 pthread_mutex_unlock(&mutex);