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 tcp->setReceiveWindow(size);
160 ///////////////////////////////////////////////////////
164 packet = (UCHAR*)tcp->receivePacket();
165 if (!packet) return 0;
166 packetLength = tcp->getDataLength();
170 void VDR::freePacket()
172 // Must be called if getPacket return 1, except in getBlock
179 int VDR::serverError()
181 if ((packetPos == 0) && (packetLength == 4) && !ntohl(*(ULONG*)packet)) return 1;
185 char* VDR::extractString()
187 if (serverError()) return NULL;
189 int length = strlen((char*)&packet[packetPos]);
190 if ((packetPos + length) > packetLength) return NULL;
191 char* str = new char[length + 1];
192 strcpy(str, (char*)&packet[packetPos]);
193 packetPos += length + 1;
197 ULONG VDR::extractULONG()
199 if ((packetPos + sizeof(ULONG)) > packetLength) return 0;
200 ULONG ul = ntohl(*(ULONG*)&packet[packetPos]);
201 packetPos += sizeof(ULONG);
205 ULLONG VDR::extractULLONG()
207 if ((packetPos + sizeof(ULLONG)) > packetLength) return 0;
208 ULLONG ull = ntohll(*(ULLONG*)&packet[packetPos]);
209 packetPos += sizeof(ULLONG);
213 long VDR::extractLONG()
215 if ((packetPos + sizeof(long)) > packetLength) return 0;
216 long l = ntohl(*(long*)&packet[packetPos]);
217 packetPos += sizeof(long);
221 /////////////////////////////////////////////////////////////////////////////
225 if (!connected) return 0;
229 *(unsigned long*)&buffer[0] = htonl(10);
230 *(unsigned long*)&buffer[4] = htonl(VDR_LOGIN);
232 tcp->getMAC((char*)&buffer[8]);
235 pthread_mutex_lock(&mutex);
236 int a = tcp->sendPacket(buffer, 14);
239 pthread_mutex_unlock(&mutex);
247 pthread_mutex_unlock(&mutex);
251 ULONG vdrTime = extractULONG();
252 logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
253 long vdrTimeOffset = extractLONG();
254 logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
257 pthread_mutex_unlock(&mutex);
260 struct timespec currentTime;
261 currentTime.tv_sec = vdrTime;
262 currentTime.tv_nsec = 0;
263 int b = clock_settime(CLOCK_REALTIME, ¤tTime);
265 logger->log("VDR", Log::DEBUG, "set clock = %u", b);
267 // now make a TZ variable and set it
271 if (vdrTimeOffset > 0) sign = '-';
274 vdrTimeOffset = abs(vdrTimeOffset);
276 hours = (int)vdrTimeOffset / 3600;
277 minutes = vdrTimeOffset % 3600;
279 logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
281 minutes = (int)minutes / 60;
283 logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
286 sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
287 setenv("TZ", newTZ, 1);
289 logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
294 Directory* VDR::getRecordingsList()
296 if (!connected) return 0;
300 *(unsigned long*)&buffer[0] = htonl(4);
301 *(unsigned long*)&buffer[4] = htonl(VDR_GETRECORDINGLIST);
303 pthread_mutex_lock(&mutex);
304 int a = tcp->sendPacket(buffer, 8);
307 pthread_mutex_unlock(&mutex);
315 pthread_mutex_unlock(&mutex);
319 Directory* recDir = new Directory();
320 recDir->setName("/");
323 Directory::totalSpace = extractULONG();
324 Directory::freeSpace = extractULONG();
325 Directory::usedPercent = extractULONG();
329 while (packetPos < packetLength)
331 Recording* rec = new Recording();
333 rec->start = extractULONG();
335 string = extractString();
336 rec->setName(string);
339 rec->fileName = extractString();
343 char* dirName = rec->getDirName();
345 Directory* d = recDir->getDirByName(dirName);
350 Log::getInstance()->log("VDR", Log::DEBUG, "Added a new directory = %s", d->name);
351 recDir->dirList.push_back(d);
354 d->recList.push_back(rec);
358 recDir->recList.push_back(rec);
361 Log::getInstance()->log("VDR", Log::DEBUG, "%s", rec->fileName);
365 pthread_mutex_unlock(&mutex);
367 // Sort the directory order
368 sort(recDir->dirList.begin(), recDir->dirList.end(), DirectorySorter());
370 // Sort all the sub lists
373 DirectoryList::iterator i;
374 for (i = recDir->dirList.begin(); i != recDir->dirList.end(); i++)
377 sort(sortDir->recList.begin(), sortDir->recList.end(), RecordingSorter());
380 // Sort the root level list
381 sort(recDir->recList.begin(), recDir->recList.end(), RecordingSorter());
386 int VDR::deleteRecording(char* fileName)
388 if (!connected) return 0;
390 unsigned long totalLength = 8 + strlen(fileName) + 1;
391 UCHAR buffer[totalLength];
393 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
394 *(unsigned long*)&buffer[4] = htonl(VDR_DELETERECORDING);
395 strcpy((char*)&buffer[8], fileName);
397 pthread_mutex_lock(&mutex);
398 unsigned int a = tcp->sendPacket(buffer, totalLength);
399 if (a != totalLength)
401 pthread_mutex_unlock(&mutex);
407 pthread_mutex_unlock(&mutex);
411 int toReturn = (int)extractULONG();
413 pthread_mutex_unlock(&mutex);
418 char* VDR::getRecordingSummary(char* fileName)
420 if (!connected) return 0;
422 unsigned long totalLength = 8 + strlen(fileName) + 1;
423 UCHAR buffer[totalLength];
425 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
426 *(unsigned long*)&buffer[4] = htonl(VDR_GETSUMMARY);
427 strcpy((char*)&buffer[8], fileName);
429 pthread_mutex_lock(&mutex);
430 unsigned int a = tcp->sendPacket(buffer, totalLength);
431 if (a != totalLength)
433 pthread_mutex_unlock(&mutex);
439 pthread_mutex_unlock(&mutex);
442 char* toReturn = extractString();
444 pthread_mutex_unlock(&mutex);
449 ChannelList* VDR::getChannelsList(ULONG type)
451 if (!connected) return 0;
455 *(unsigned long*)&buffer[0] = htonl(4);
456 *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELLIST);
458 pthread_mutex_lock(&mutex);
459 int a = tcp->sendPacket(buffer, 8);
462 pthread_mutex_unlock(&mutex);
470 pthread_mutex_unlock(&mutex);
474 ChannelList* chanList = new ChannelList();
476 while (packetPos < packetLength)
478 Channel* chan = new Channel();
479 chan->number = extractULONG();
480 chan->type = extractULONG();
481 chan->name = extractString();
483 if (chan->type == type)
485 chanList->push_back(chan);
486 Log::getInstance()->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
495 pthread_mutex_unlock(&mutex);
500 int VDR::streamChannel(ULONG number)
502 if (!connected) return 0;
506 *(unsigned long*)&buffer[0] = htonl(8);
507 *(unsigned long*)&buffer[4] = htonl(VDR_STREAMCHANNEL);
508 *(unsigned long*)&buffer[8] = htonl(number);
510 pthread_mutex_lock(&mutex);
511 int a = tcp->sendPacket(buffer, 12);
515 pthread_mutex_unlock(&mutex);
521 pthread_mutex_unlock(&mutex);
525 int toReturn = (int)extractULONG();
527 pthread_mutex_unlock(&mutex);
532 int VDR::stopStreaming()
534 if (!connected) return 0;
538 *(unsigned long*)&buffer[0] = htonl(4);
539 *(unsigned long*)&buffer[4] = htonl(VDR_STOPSTREAMING);
541 pthread_mutex_lock(&mutex);
542 int a = tcp->sendPacket(buffer, 8);
546 pthread_mutex_unlock(&mutex);
550 printf("sent request\n");
554 pthread_mutex_unlock(&mutex);
557 printf("got reply\n");
560 int toReturn = (int)extractULONG();
562 pthread_mutex_unlock(&mutex);
567 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
569 if (!connected) return 0;
573 *(unsigned long*)&buffer[0] = htonl(16);
574 *(unsigned long*)&buffer[4] = htonl(VDR_GETBLOCK);
575 *(ULLONG*)&buffer[8] = htonll(position);
576 *(unsigned long*)&buffer[16] = htonl(maxAmount);
578 pthread_mutex_lock(&mutex);
579 int a = tcp->sendPacket(buffer, 20);
582 pthread_mutex_unlock(&mutex);
588 pthread_mutex_unlock(&mutex);
592 UCHAR* toReturn = packet;
593 *amountReceived = packetLength;
594 // Manually clean up instead of running freePacket to keep the block
598 pthread_mutex_unlock(&mutex);
603 ULLONG VDR::streamRecording(Recording* rec)
605 if (!connected) return 0;
607 unsigned long totalLength = 8 + strlen(rec->fileName) + 1;
608 UCHAR buffer[totalLength];
610 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
611 *(unsigned long*)&buffer[4] = htonl(VDR_STREAMRECORDING);
612 strcpy((char*)&buffer[8], rec->fileName);
614 pthread_mutex_lock(&mutex);
615 unsigned int a = tcp->sendPacket(buffer, totalLength);
616 if (a != totalLength)
618 pthread_mutex_unlock(&mutex);
624 pthread_mutex_unlock(&mutex);
628 ULLONG recordingLength = extractULLONG();
630 pthread_mutex_unlock(&mutex);
632 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
634 return recordingLength;
637 ULLONG VDR::rescanRecording()
639 if (!connected) return 0;
641 unsigned long totalLength = 8;
642 UCHAR buffer[totalLength];
644 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
645 *(unsigned long*)&buffer[4] = htonl(VDR_RESCANRECORDING);
647 pthread_mutex_lock(&mutex);
648 unsigned int a = tcp->sendPacket(buffer, totalLength);
649 if (a != totalLength)
651 pthread_mutex_unlock(&mutex);
657 pthread_mutex_unlock(&mutex);
661 ULLONG recordingLength = extractULLONG();
663 pthread_mutex_unlock(&mutex);
665 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
667 return recordingLength;
670 EventList* VDR::getChannelSchedule(ULONG number)
674 return getChannelSchedule(number, now, 24 * 60 * 60);
677 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
679 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
680 if (!connected) return 0;
684 *(unsigned long*)&buffer[0] = htonl(16);
685 *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE);
686 *(unsigned long*)&buffer[8] = htonl(number);
687 *(unsigned long*)&buffer[12] = htonl(start);
688 *(unsigned long*)&buffer[16] = htonl(duration);
690 pthread_mutex_lock(&mutex);
691 int a = tcp->sendPacket(buffer, 20);
695 pthread_mutex_unlock(&mutex);
701 pthread_mutex_unlock(&mutex);
708 pthread_mutex_unlock(&mutex);
713 EventList* eventList = new EventList();
715 while (packetPos < packetLength)
717 Event* event = new Event();
718 event->id = extractULONG();
719 event->time = extractULONG();
720 event->duration = extractULONG();
721 event->title = extractString();
722 event->subtitle = extractString();
723 event->description = extractString();
724 eventList->push_back(event);
725 // eventList->next();
729 pthread_mutex_unlock(&mutex);
731 Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
736 Log* l = Log::getInstance();
739 l->log("VDR", Log::DEBUG, "datalength = %i count = %i", dataLength, count);
742 for(eventList->reset(); !eventList->eol(); eventList->next())
744 currentEvent = (Event*)eventList->getCurrent();
745 l->log("VDR", Log::DEBUG, "%lu %lu %lu %s %s %s", currentEvent->id, currentEvent->time, currentEvent->duration, currentEvent->title, currentEvent->subtitle, currentEvent->description);
752 ULLONG VDR::getResumePoint(char* fileName)
754 if (!connected) return 0;
756 char* resumeString = configLoad("ResumeData", fileName);
757 if (!resumeString) return 0;
759 ULLONG toReturn = strtoull(resumeString, NULL, 10);
760 delete[] resumeString;
764 int VDR::configSave(char* section, char* key, const char* value)
766 if (!connected) return 0;
768 ULONG totalLength = 8 + strlen(section) + strlen(key) + strlen(value) + 3; // 8 for headers, 3 for nulls
769 UCHAR buffer[totalLength];
771 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
772 *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGSAVE);
775 strcpy((char*)&buffer[position], section);
776 position += strlen(section) + 1;
777 strcpy((char*)&buffer[position], key);
778 position += strlen(key) + 1;
779 strcpy((char*)&buffer[position], value);
781 pthread_mutex_lock(&mutex);
782 unsigned int a = tcp->sendPacket(buffer, totalLength);
783 if (a != totalLength)
785 pthread_mutex_unlock(&mutex);
791 pthread_mutex_unlock(&mutex);
795 int toReturn = (int)extractULONG();
797 pthread_mutex_unlock(&mutex);
802 char* VDR::configLoad(char* section, char* key)
804 if (!connected) return 0;
806 ULONG totalLength = 8 + strlen(section) + strlen(key) + 2; // 8 for headers, 2 for nulls
807 UCHAR buffer[totalLength];
809 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
810 *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGLOAD);
813 strcpy((char*)&buffer[position], section);
814 position += strlen(section) + 1;
815 strcpy((char*)&buffer[position], key);
817 pthread_mutex_lock(&mutex);
818 unsigned int a = tcp->sendPacket(buffer, totalLength);
819 if (a != totalLength)
821 pthread_mutex_unlock(&mutex);
827 pthread_mutex_unlock(&mutex);
830 char* toReturn = extractString();
832 pthread_mutex_unlock(&mutex);
837 RecTimerList* VDR::getRecTimersList()
839 if (!connected) return NULL;
843 *(unsigned long*)&buffer[0] = htonl(4);
844 *(unsigned long*)&buffer[4] = htonl(VDR_GETTIMERS);
846 pthread_mutex_lock(&mutex);
847 int a = tcp->sendPacket(buffer, 8);
850 pthread_mutex_unlock(&mutex);
858 pthread_mutex_unlock(&mutex);
862 RecTimerList* recTimerList = new RecTimerList();
864 ULONG numTimers = extractULONG();
867 RecTimer* newRecTimer;
870 while (packetPos < packetLength)
872 newRecTimer = new RecTimer();
873 newRecTimer->active = extractULONG();
874 newRecTimer->recording = extractULONG();
875 newRecTimer->pending = extractULONG();
876 newRecTimer->priority = extractULONG();
877 newRecTimer->lifeTime = extractULONG();
878 newRecTimer->channelNumber = extractULONG();
879 newRecTimer->startTime = extractULONG();
880 newRecTimer->stopTime = extractULONG();
882 tempString = extractString();
883 newRecTimer->setFile(tempString);
886 newRecTimer->summary = extractString();
888 recTimerList->push_back(newRecTimer);
889 Log::getInstance()->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
890 newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
891 newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
896 pthread_mutex_unlock(&mutex);
900 sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
905 ULONG VDR::setEventTimer(char* timerString)
907 if (!connected) return false;
909 unsigned long totalLength = 8 + strlen(timerString) + 1;
910 UCHAR buffer[totalLength];
912 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
913 *(unsigned long*)&buffer[4] = htonl(VDR_SETTIMER);
914 strcpy((char*)&buffer[8], timerString);
916 pthread_mutex_lock(&mutex);
917 unsigned int a = tcp->sendPacket(buffer, totalLength);
918 if (a != totalLength)
920 pthread_mutex_unlock(&mutex);
926 pthread_mutex_unlock(&mutex);
930 ULONG toReturn = extractULONG();
932 pthread_mutex_unlock(&mutex);