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 ///////////////////////////////////////////////////////
159 packet = (UCHAR*)tcp->receivePacket();
160 if (!packet) return 0;
161 packetLength = tcp->getDataLength();
165 void VDR::freePacket()
167 // Must be called if getPacket return 1, except in getBlock
174 int VDR::serverError()
176 if ((packetPos == 0) && (packetLength == 4) && !ntohl(*(ULONG*)packet)) return 1;
180 char* VDR::extractString()
182 if (serverError()) return NULL;
184 int length = strlen((char*)&packet[packetPos]);
185 if ((packetPos + length) > packetLength) return NULL;
186 char* str = new char[length + 1];
187 strcpy(str, (char*)&packet[packetPos]);
188 packetPos += length + 1;
192 ULONG VDR::extractULONG()
194 if ((packetPos + sizeof(ULONG)) > packetLength) return 0;
195 ULONG ul = ntohl(*(ULONG*)&packet[packetPos]);
196 packetPos += sizeof(ULONG);
200 ULLONG VDR::extractULLONG()
202 if ((packetPos + sizeof(ULLONG)) > packetLength) return 0;
203 ULLONG ull = ntohll(*(ULLONG*)&packet[packetPos]);
204 packetPos += sizeof(ULLONG);
208 long VDR::extractLONG()
210 if ((packetPos + sizeof(long)) > packetLength) return 0;
211 long l = ntohl(*(long*)&packet[packetPos]);
212 packetPos += sizeof(long);
216 /////////////////////////////////////////////////////////////////////////////
220 if (!connected) return 0;
224 *(unsigned long*)&buffer[0] = htonl(10);
225 *(unsigned long*)&buffer[4] = htonl(VDR_LOGIN);
227 tcp->getMAC((char*)&buffer[8]);
230 pthread_mutex_lock(&mutex);
231 int a = tcp->sendPacket(buffer, 14);
234 pthread_mutex_unlock(&mutex);
242 pthread_mutex_unlock(&mutex);
246 ULONG vdrTime = extractULONG();
247 logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
248 long vdrTimeOffset = extractLONG();
249 logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
252 pthread_mutex_unlock(&mutex);
255 struct timespec currentTime;
256 currentTime.tv_sec = vdrTime;
257 currentTime.tv_nsec = 0;
258 int b = clock_settime(CLOCK_REALTIME, ¤tTime);
260 logger->log("VDR", Log::DEBUG, "set clock = %u", b);
262 // now make a TZ variable and set it
266 if (vdrTimeOffset > 0) sign = '-';
269 vdrTimeOffset = abs(vdrTimeOffset);
271 hours = (int)vdrTimeOffset / 3600;
272 minutes = vdrTimeOffset % 3600;
274 logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
276 minutes = (int)minutes / 60;
278 logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
281 sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
282 setenv("TZ", newTZ, 1);
284 logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
289 Directory* VDR::getRecordingsList()
291 if (!connected) return 0;
295 *(unsigned long*)&buffer[0] = htonl(4);
296 *(unsigned long*)&buffer[4] = htonl(VDR_GETRECORDINGLIST);
298 pthread_mutex_lock(&mutex);
299 int a = tcp->sendPacket(buffer, 8);
302 pthread_mutex_unlock(&mutex);
310 pthread_mutex_unlock(&mutex);
314 Directory* recDir = new Directory();
315 recDir->setName("/");
318 Directory::totalSpace = extractULONG();
319 Directory::freeSpace = extractULONG();
320 Directory::usedPercent = extractULONG();
324 while (packetPos < packetLength)
326 Recording* rec = new Recording();
328 rec->start = extractULONG();
330 string = extractString();
331 rec->setName(string);
334 rec->fileName = extractString();
338 char* dirName = rec->getDirName();
340 Directory* d = recDir->getDirByName(dirName);
345 Log::getInstance()->log("VDR", Log::DEBUG, "Added a new directory = %s", d->name);
346 recDir->dirList.push_back(d);
349 d->recList.push_back(rec);
353 recDir->recList.push_back(rec);
356 Log::getInstance()->log("VDR", Log::DEBUG, "%s", rec->fileName);
360 pthread_mutex_unlock(&mutex);
362 // Sort the directory order
363 sort(recDir->dirList.begin(), recDir->dirList.end(), DirectorySorter());
365 // Sort all the sub lists
368 DirectoryList::iterator i;
369 for (i = recDir->dirList.begin(); i != recDir->dirList.end(); i++)
372 sort(sortDir->recList.begin(), sortDir->recList.end(), RecordingSorter());
375 // Sort the root level list
376 sort(recDir->recList.begin(), recDir->recList.end(), RecordingSorter());
381 int VDR::deleteRecording(char* fileName)
383 if (!connected) return 0;
385 unsigned long totalLength = 8 + strlen(fileName) + 1;
386 UCHAR buffer[totalLength];
388 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
389 *(unsigned long*)&buffer[4] = htonl(VDR_DELETERECORDING);
390 strcpy((char*)&buffer[8], fileName);
392 pthread_mutex_lock(&mutex);
393 unsigned int a = tcp->sendPacket(buffer, totalLength);
394 if (a != totalLength)
396 pthread_mutex_unlock(&mutex);
402 pthread_mutex_unlock(&mutex);
406 int toReturn = (int)extractULONG();
408 pthread_mutex_unlock(&mutex);
413 char* VDR::getRecordingSummary(char* fileName)
415 if (!connected) return 0;
417 unsigned long totalLength = 8 + strlen(fileName) + 1;
418 UCHAR buffer[totalLength];
420 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
421 *(unsigned long*)&buffer[4] = htonl(VDR_GETSUMMARY);
422 strcpy((char*)&buffer[8], fileName);
424 pthread_mutex_lock(&mutex);
425 unsigned int a = tcp->sendPacket(buffer, totalLength);
426 if (a != totalLength)
428 pthread_mutex_unlock(&mutex);
434 pthread_mutex_unlock(&mutex);
437 char* toReturn = extractString();
439 pthread_mutex_unlock(&mutex);
444 ChannelList* VDR::getChannelsList(ULONG type)
446 if (!connected) return 0;
450 *(unsigned long*)&buffer[0] = htonl(4);
451 *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELLIST);
453 pthread_mutex_lock(&mutex);
454 int a = tcp->sendPacket(buffer, 8);
457 pthread_mutex_unlock(&mutex);
465 pthread_mutex_unlock(&mutex);
469 ChannelList* chanList = new ChannelList();
471 while (packetPos < packetLength)
473 Channel* chan = new Channel();
474 chan->number = extractULONG();
475 chan->type = extractULONG();
476 chan->name = extractString();
478 if (chan->type == type)
480 chanList->push_back(chan);
481 Log::getInstance()->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
490 pthread_mutex_unlock(&mutex);
495 int VDR::streamChannel(ULONG number)
497 if (!connected) return 0;
501 *(unsigned long*)&buffer[0] = htonl(8);
502 *(unsigned long*)&buffer[4] = htonl(VDR_STREAMCHANNEL);
503 *(unsigned long*)&buffer[8] = htonl(number);
505 pthread_mutex_lock(&mutex);
506 int a = tcp->sendPacket(buffer, 12);
510 pthread_mutex_unlock(&mutex);
516 pthread_mutex_unlock(&mutex);
520 int toReturn = (int)extractULONG();
522 pthread_mutex_unlock(&mutex);
527 int VDR::stopStreaming()
529 if (!connected) return 0;
533 *(unsigned long*)&buffer[0] = htonl(4);
534 *(unsigned long*)&buffer[4] = htonl(VDR_STOPSTREAMING);
536 pthread_mutex_lock(&mutex);
537 int a = tcp->sendPacket(buffer, 8);
541 pthread_mutex_unlock(&mutex);
545 printf("sent request\n");
549 pthread_mutex_unlock(&mutex);
552 printf("got reply\n");
555 int toReturn = (int)extractULONG();
557 pthread_mutex_unlock(&mutex);
562 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
564 if (!connected) return 0;
568 *(unsigned long*)&buffer[0] = htonl(16);
569 *(unsigned long*)&buffer[4] = htonl(VDR_GETBLOCK);
570 *(ULLONG*)&buffer[8] = htonll(position);
571 *(unsigned long*)&buffer[16] = htonl(maxAmount);
573 pthread_mutex_lock(&mutex);
574 int a = tcp->sendPacket(buffer, 20);
577 pthread_mutex_unlock(&mutex);
583 pthread_mutex_unlock(&mutex);
587 UCHAR* toReturn = packet;
588 *amountReceived = packetLength;
589 // Manually clean up instead of running freePacket to keep the block
593 pthread_mutex_unlock(&mutex);
598 ULLONG VDR::streamRecording(Recording* rec)
600 if (!connected) return 0;
602 unsigned long totalLength = 8 + strlen(rec->fileName) + 1;
603 UCHAR buffer[totalLength];
605 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
606 *(unsigned long*)&buffer[4] = htonl(VDR_STREAMRECORDING);
607 strcpy((char*)&buffer[8], rec->fileName);
609 pthread_mutex_lock(&mutex);
610 unsigned int a = tcp->sendPacket(buffer, totalLength);
611 if (a != totalLength)
613 pthread_mutex_unlock(&mutex);
619 pthread_mutex_unlock(&mutex);
623 ULLONG recordingLength = extractULLONG();
625 pthread_mutex_unlock(&mutex);
627 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
629 return recordingLength;
632 ULLONG VDR::rescanRecording()
634 if (!connected) return 0;
636 unsigned long totalLength = 8;
637 UCHAR buffer[totalLength];
639 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
640 *(unsigned long*)&buffer[4] = htonl(VDR_RESCANRECORDING);
642 pthread_mutex_lock(&mutex);
643 unsigned int a = tcp->sendPacket(buffer, totalLength);
644 if (a != totalLength)
646 pthread_mutex_unlock(&mutex);
652 pthread_mutex_unlock(&mutex);
656 ULLONG recordingLength = extractULLONG();
658 pthread_mutex_unlock(&mutex);
660 Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
662 return recordingLength;
665 EventList* VDR::getChannelSchedule(ULONG number)
669 return getChannelSchedule(number, now, 24 * 60 * 60);
672 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
674 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
675 if (!connected) return 0;
679 *(unsigned long*)&buffer[0] = htonl(16);
680 *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE);
681 *(unsigned long*)&buffer[8] = htonl(number);
682 *(unsigned long*)&buffer[12] = htonl(start);
683 *(unsigned long*)&buffer[16] = htonl(duration);
685 pthread_mutex_lock(&mutex);
686 int a = tcp->sendPacket(buffer, 20);
690 pthread_mutex_unlock(&mutex);
696 pthread_mutex_unlock(&mutex);
703 pthread_mutex_unlock(&mutex);
708 EventList* eventList = new EventList();
710 while (packetPos < packetLength)
712 Event* event = new Event();
713 event->id = extractULONG();
714 event->time = extractULONG();
715 event->duration = extractULONG();
716 event->title = extractString();
717 event->subtitle = extractString();
718 event->description = extractString();
719 eventList->push_back(event);
720 // eventList->next();
724 pthread_mutex_unlock(&mutex);
726 Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
731 Log* l = Log::getInstance();
734 l->log("VDR", Log::DEBUG, "datalength = %i count = %i", dataLength, count);
737 for(eventList->reset(); !eventList->eol(); eventList->next())
739 currentEvent = (Event*)eventList->getCurrent();
740 l->log("VDR", Log::DEBUG, "%lu %lu %lu %s %s %s", currentEvent->id, currentEvent->time, currentEvent->duration, currentEvent->title, currentEvent->subtitle, currentEvent->description);
747 ULLONG VDR::getResumePoint(char* fileName)
749 if (!connected) return 0;
751 char* resumeString = configLoad("ResumeData", fileName);
752 if (!resumeString) return 0;
754 ULLONG toReturn = strtoull(resumeString, NULL, 10);
755 delete[] resumeString;
759 int VDR::configSave(char* section, char* key, const char* value)
761 if (!connected) return 0;
763 ULONG totalLength = 8 + strlen(section) + strlen(key) + strlen(value) + 3; // 8 for headers, 3 for nulls
764 UCHAR buffer[totalLength];
766 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
767 *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGSAVE);
770 strcpy((char*)&buffer[position], section);
771 position += strlen(section) + 1;
772 strcpy((char*)&buffer[position], key);
773 position += strlen(key) + 1;
774 strcpy((char*)&buffer[position], value);
776 pthread_mutex_lock(&mutex);
777 unsigned int a = tcp->sendPacket(buffer, totalLength);
778 if (a != totalLength)
780 pthread_mutex_unlock(&mutex);
786 pthread_mutex_unlock(&mutex);
790 int toReturn = (int)extractULONG();
792 pthread_mutex_unlock(&mutex);
797 char* VDR::configLoad(char* section, char* key)
799 if (!connected) return 0;
801 ULONG totalLength = 8 + strlen(section) + strlen(key) + 2; // 8 for headers, 2 for nulls
802 UCHAR buffer[totalLength];
804 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
805 *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGLOAD);
808 strcpy((char*)&buffer[position], section);
809 position += strlen(section) + 1;
810 strcpy((char*)&buffer[position], key);
812 pthread_mutex_lock(&mutex);
813 unsigned int a = tcp->sendPacket(buffer, totalLength);
814 if (a != totalLength)
816 pthread_mutex_unlock(&mutex);
822 pthread_mutex_unlock(&mutex);
825 char* toReturn = extractString();
827 pthread_mutex_unlock(&mutex);
832 RecTimerList* VDR::getRecTimersList()
834 if (!connected) return NULL;
838 *(unsigned long*)&buffer[0] = htonl(4);
839 *(unsigned long*)&buffer[4] = htonl(VDR_GETTIMERS);
841 pthread_mutex_lock(&mutex);
842 int a = tcp->sendPacket(buffer, 8);
845 pthread_mutex_unlock(&mutex);
853 pthread_mutex_unlock(&mutex);
857 RecTimerList* recTimerList = new RecTimerList();
859 RecTimer* newRecTimer;
862 while (packetPos < packetLength)
864 newRecTimer = new RecTimer();
865 newRecTimer->active = extractULONG();
866 newRecTimer->recording = extractULONG();
867 newRecTimer->pending = extractULONG();
868 newRecTimer->priority = extractULONG();
869 newRecTimer->lifeTime = extractULONG();
870 newRecTimer->channelNumber = extractULONG();
871 newRecTimer->startTime = extractULONG();
872 newRecTimer->stopTime = extractULONG();
874 tempString = extractString();
875 newRecTimer->setFile(tempString);
878 newRecTimer->summary = extractString();
880 recTimerList->push_back(newRecTimer);
881 Log::getInstance()->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
882 newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
883 newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
887 pthread_mutex_unlock(&mutex);
891 sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
896 ULONG VDR::setEventTimer(char* timerString)
898 if (!connected) return false;
900 unsigned long totalLength = 8 + strlen(timerString) + 1;
901 UCHAR buffer[totalLength];
903 *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
904 *(unsigned long*)&buffer[4] = htonl(VDR_SETTIMER);
905 strcpy((char*)&buffer[8], timerString);
907 pthread_mutex_lock(&mutex);
908 unsigned int a = tcp->sendPacket(buffer, totalLength);
909 if (a != totalLength)
911 pthread_mutex_unlock(&mutex);
917 pthread_mutex_unlock(&mutex);
921 ULONG toReturn = extractULONG();
923 pthread_mutex_unlock(&mutex);