]> git.vomp.tv Git - vompclient.git/blob - vdr.cc
Channel schedules in live banner
[vompclient.git] / vdr.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
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.
10
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.
15
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
19 */
20
21 #include "vdr.h"
22
23 VDR* VDR::instance = NULL;
24
25 VDR::VDR()
26 {
27   if (instance) return;
28   instance = this;
29   initted = 0;
30   findingServer = 0;
31   tcp = NULL;
32   pthread_mutex_init(&mutex, NULL);
33   packetLength = 0;
34   packetPos = 0;
35   packet = NULL;
36 }
37
38 VDR::~VDR()
39 {
40   instance = NULL;
41   if (initted) shutdown();
42 }
43
44 VDR* VDR::getInstance()
45 {
46   return instance;
47 }
48
49 int VDR::init(int tport)
50 {
51   if (initted) return 0;
52   initted = 1;
53   port = tport;
54   logger = Log::getInstance();
55   return 1;
56 }
57
58 int VDR::shutdown()
59 {
60   if (!initted) return 0;
61   initted = 0;
62   disconnect();
63   return 1;
64 }
65
66 void VDR::findServers(vector<char*>& serverIPs)
67 {
68   findingServer = 1;
69   char* message = "VOMP CLIENT";
70   DatagramSocket ds(port);
71
72   int haveAtLeastOne = 0;
73   char* newIP;
74   int retval;
75   int waitType = 1;
76   while(findingServer)
77   {
78     if (waitType == 1)
79     {
80       logger->log("VDR", Log::NOTICE, "Broadcasting for server");
81       ds.send("255.255.255.255", 3024, message, strlen(message));
82     }
83     retval = ds.waitforMessage(waitType);
84
85     if (retval == 2) // we got a reply
86     {
87       if (strcmp(ds.getData(), "VOMP SERVER")) // echo.....
88       {
89         waitType = 2;
90       }
91       else
92       {
93         newIP = new char[16];
94         strcpy(newIP, ds.getFromIPA());
95         serverIPs.push_back(newIP);
96         waitType = 2;
97         haveAtLeastOne = 1;
98       }
99     }
100     else
101     {
102       if (haveAtLeastOne) break;
103       waitType = 1;
104     }
105   }
106 }
107
108 void VDR::cancelFindingServer()
109 {
110   findingServer = 0;
111 }
112
113 void VDR::setServerIP(char* newIP)
114 {
115   strcpy(serverIP, newIP);
116 }
117
118 int VDR::connect()
119 {
120   if (tcp) delete tcp;
121   tcp = new TCP();
122   return tcp->connectTo(serverIP, 3024);
123 }
124
125 void VDR::disconnect()
126 {
127   if (tcp) delete tcp;
128   tcp = NULL;
129   Log::getInstance()->log("VDR", Log::DEBUG, "Disconnect");
130 }
131
132 ///////////////////////////////////////////////////////
133
134 int VDR::getPacket()
135 {
136   packet = (UCHAR*)tcp->receivePacket();
137   if (!packet) return 0;
138   packetLength = tcp->getDataLength();
139   return 1;
140 }
141
142 void VDR::freePacket()
143 {
144   // Must be called if getPacket return 1, except in getBlock
145   packetLength = 0;
146   packetPos = 0;
147   free(packet);
148   packet = NULL;
149 }
150
151 int VDR::serverError()
152 {
153   if ((packetPos == 0) && (packetLength == 4) && !ntohl(*(ULONG*)packet)) return 1;
154   else return 0;
155 }
156
157 char* VDR::extractString()
158 {
159   if (serverError()) return NULL;
160
161   int length = strlen((char*)&packet[packetPos]);
162   if ((packetPos + length) > packetLength) return NULL;
163   char* str = new char[length + 1];
164   strcpy(str, (char*)&packet[packetPos]);
165   packetPos += length + 1;
166   return str;
167 }
168
169 ULONG VDR::extractULONG()
170 {
171   if ((packetPos + sizeof(ULONG)) > packetLength) return 0;
172   ULONG ul = ntohl(*(ULONG*)&packet[packetPos]);
173   packetPos += sizeof(ULONG);
174   return ul;
175 }
176
177 ULLONG VDR::extractULLONG()
178 {
179   if ((packetPos + sizeof(ULLONG)) > packetLength) return 0;
180   ULLONG ull = ntohll(*(ULLONG*)&packet[packetPos]);
181   packetPos += sizeof(ULLONG);
182   return ull;
183 }
184
185 long VDR::extractLONG()
186 {
187   if ((packetPos + sizeof(long)) > packetLength) return 0;
188   long l = ntohl(*(long*)&packet[packetPos]);
189   packetPos += sizeof(long);
190   return l;
191 }
192
193 /////////////////////////////////////////////////////////////////////////////
194
195 int VDR::doLogin()
196 {
197   UCHAR buffer[8];
198
199   *(unsigned long*)&buffer[0] = htonl(4);
200   *(unsigned long*)&buffer[4] = htonl(VDR_LOGIN);
201
202   pthread_mutex_lock(&mutex);
203   int a = tcp->sendPacket(buffer, 8);
204   if (a != 8)
205   {
206     pthread_mutex_unlock(&mutex);
207     return 0;
208   }
209
210   // reply
211
212   if (!getPacket())
213   {
214     pthread_mutex_unlock(&mutex);
215     return 0;
216   }
217
218   ULONG vdrTime = extractULONG();
219   logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
220   long vdrTimeOffset = extractLONG();
221   logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
222
223   freePacket();
224   pthread_mutex_unlock(&mutex);
225
226
227   struct timespec currentTime;
228   currentTime.tv_sec = vdrTime;
229   currentTime.tv_nsec = 0;
230   int b = clock_settime(CLOCK_REALTIME, &currentTime);
231
232   logger->log("VDR", Log::DEBUG, "set clock = %u", b);
233
234   // now make a TZ variable and set it
235   char sign;
236   int hours;
237   int minutes;
238   if (vdrTimeOffset > 0) sign = '-';
239   else sign = '+';
240
241   vdrTimeOffset = abs(vdrTimeOffset);
242
243   hours = (int)vdrTimeOffset / 3600;
244   minutes = vdrTimeOffset % 3600;
245
246   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
247
248   minutes = (int)minutes / 60;
249
250   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
251
252   char newTZ[30];
253   sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
254   setenv("TZ", newTZ, 1);
255
256   logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
257
258   return 1;
259 }
260
261 Directory* VDR::getRecordingsList()
262 {
263   UCHAR buffer[8];
264
265   *(unsigned long*)&buffer[0] = htonl(4);
266   *(unsigned long*)&buffer[4] = htonl(VDR_GETRECORDINGLIST);
267
268   pthread_mutex_lock(&mutex);
269   int a = tcp->sendPacket(buffer, 8);
270   if (a != 8)
271   {
272     pthread_mutex_unlock(&mutex);
273     return NULL;
274   }
275
276   // reply
277
278   if (!getPacket())
279   {
280     pthread_mutex_unlock(&mutex);
281     return NULL;
282   }
283
284   Directory* recDir = new Directory();
285   recDir->setName("/");
286   recDir->isRoot = 1;
287
288   Directory::totalSpace = extractULONG();
289   Directory::freeSpace = extractULONG();
290   Directory::usedPercent = extractULONG();
291
292   char* string;
293
294   while (packetPos < packetLength)
295   {
296     Recording* rec = new Recording();
297
298     rec->start = extractULONG();
299
300     string = extractString();
301     rec->setName(string);
302     delete[] string;
303
304     rec->fileName = extractString();
305
306     if(rec->isInDir())
307     {
308       char* dirName = rec->getDirName();
309
310       Directory* d = recDir->getDirByName(dirName);
311       if (!d)
312       {
313         d = new Directory();
314         d->setName(dirName);
315         Log::getInstance()->log("VDR", Log::DEBUG, "Added a new directory = %s", d->name);
316         recDir->dirList.push_back(d);
317       }
318
319       d->recList.push_back(rec);
320     }
321     else
322     {
323       recDir->recList.push_back(rec);
324     }
325
326     Log::getInstance()->log("VDR", Log::DEBUG, "Have added a recording to list. %lu %s", rec->start, rec->getProgName());
327   }
328
329   freePacket();
330   pthread_mutex_unlock(&mutex);
331
332   return recDir;
333 }
334
335 int VDR::deleteRecording(char* fileName)
336 {
337   unsigned long totalLength = 8 + strlen(fileName) + 1;
338   UCHAR buffer[totalLength];
339
340   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
341   *(unsigned long*)&buffer[4] = htonl(VDR_DELETERECORDING);
342   strcpy((char*)&buffer[8], fileName);
343
344   pthread_mutex_lock(&mutex);
345   unsigned int a = tcp->sendPacket(buffer, totalLength);
346   if (a != totalLength)
347   {
348     pthread_mutex_unlock(&mutex);
349     return 0;
350   }
351
352   if (!getPacket())
353   {
354     pthread_mutex_unlock(&mutex);
355     return 0;
356   }
357
358   int toReturn = (int)extractULONG();
359   freePacket();
360   pthread_mutex_unlock(&mutex);
361
362   return toReturn;
363 }
364
365 char* VDR::getRecordingSummary(char* fileName)
366 {
367   unsigned long totalLength = 8 + strlen(fileName) + 1;
368   UCHAR buffer[totalLength];
369
370   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
371   *(unsigned long*)&buffer[4] = htonl(VDR_GETSUMMARY);
372   strcpy((char*)&buffer[8], fileName);
373
374   pthread_mutex_lock(&mutex);
375   unsigned int a = tcp->sendPacket(buffer, totalLength);
376   if (a != totalLength)
377   {
378     pthread_mutex_unlock(&mutex);
379     return NULL;
380   }
381
382   if (!getPacket())
383   {
384     pthread_mutex_unlock(&mutex);
385     return NULL;
386   }
387   char* toReturn = extractString();
388   freePacket();
389   pthread_mutex_unlock(&mutex);
390
391   return toReturn;
392 }
393
394 ChannelList* VDR::getChannelsList(ULONG type)
395 {
396   UCHAR buffer[8];
397
398   *(unsigned long*)&buffer[0] = htonl(4);
399   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELLIST);
400
401   pthread_mutex_lock(&mutex);
402   int a = tcp->sendPacket(buffer, 8);
403   if (a != 8)
404   {
405     pthread_mutex_unlock(&mutex);
406     return NULL;
407   }
408
409   // reply
410
411   if (!getPacket())
412   {
413     pthread_mutex_unlock(&mutex);
414     return NULL;
415   }
416
417   ChannelList* chanList = new ChannelList();
418
419   while (packetPos < packetLength)
420   {
421     Channel* chan = new Channel();
422     chan->number = extractULONG();
423     chan->type = extractULONG();
424     chan->name = extractString();
425
426     if (chan->type == type)
427     {
428       chanList->push_back(chan);
429       Log::getInstance()->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
430     }
431     else
432     {
433       delete chan;
434     }
435   }
436
437   freePacket();
438   pthread_mutex_unlock(&mutex);
439
440   return chanList;
441 }
442
443 int VDR::streamChannel(ULONG number)
444 {
445   UCHAR buffer[12];
446
447   *(unsigned long*)&buffer[0] = htonl(8);
448   *(unsigned long*)&buffer[4] = htonl(VDR_STREAMCHANNEL);
449   *(unsigned long*)&buffer[8] = htonl(number);
450
451   pthread_mutex_lock(&mutex);
452   int a = tcp->sendPacket(buffer, 12);
453
454   if (a != 12)
455   {
456     pthread_mutex_unlock(&mutex);
457     return 0;
458   }
459
460   if (!getPacket())
461   {
462     pthread_mutex_unlock(&mutex);
463     return 0;
464   }
465
466   int toReturn = (int)extractULONG();
467   freePacket();
468   pthread_mutex_unlock(&mutex);
469
470   return toReturn;
471 }
472
473 int VDR::stopStreaming()
474 {
475   UCHAR buffer[8];
476
477   *(unsigned long*)&buffer[0] = htonl(4);
478   *(unsigned long*)&buffer[4] = htonl(VDR_STOPSTREAMING);
479
480   pthread_mutex_lock(&mutex);
481   int a = tcp->sendPacket(buffer, 8);
482
483   if (a != 8)
484   {
485     pthread_mutex_unlock(&mutex);
486     return 0;
487   }
488
489   if (!getPacket())
490   {
491     pthread_mutex_unlock(&mutex);
492     return 0;
493   }
494
495   int toReturn = (int)extractULONG();
496   freePacket();
497   pthread_mutex_unlock(&mutex);
498
499   return toReturn;
500 }
501
502 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
503 {
504   UCHAR buffer[20];
505
506   *(unsigned long*)&buffer[0] = htonl(16);
507   *(unsigned long*)&buffer[4] = htonl(VDR_GETBLOCK);
508   *(ULLONG*)&buffer[8]        = htonll(position);
509   *(unsigned long*)&buffer[16] = htonl(maxAmount);
510
511   pthread_mutex_lock(&mutex);
512   int a = tcp->sendPacket(buffer, 20);
513   if (a != 20)
514   {
515     pthread_mutex_unlock(&mutex);
516     return NULL;
517   }
518
519   if (!getPacket())
520   {
521     pthread_mutex_unlock(&mutex);
522     return NULL;
523   }
524
525   UCHAR* toReturn = packet;
526   *amountReceived = packetLength;
527   // Manually clean up instead of running freePacket to keep the block
528   packet = NULL;
529   packetLength = 0;
530   packetPos = 0;
531   pthread_mutex_unlock(&mutex);
532
533   return toReturn;
534 }
535
536 ULLONG VDR::streamRecording(Recording* rec)
537 {
538   unsigned long totalLength = 8 + strlen(rec->fileName) + 1;
539   UCHAR buffer[totalLength];
540
541   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
542   *(unsigned long*)&buffer[4] = htonl(VDR_STREAMRECORDING);
543   strcpy((char*)&buffer[8], rec->fileName);
544
545   pthread_mutex_lock(&mutex);
546   unsigned int a = tcp->sendPacket(buffer, totalLength);
547   if (a != totalLength)
548   {
549     pthread_mutex_unlock(&mutex);
550     return 0;
551   }
552
553   if (!getPacket())
554   {
555     pthread_mutex_unlock(&mutex);
556     return 0;
557   }
558
559   ULLONG recordingLength = extractULLONG();
560   freePacket();
561   pthread_mutex_unlock(&mutex);
562
563   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
564
565   return recordingLength;
566 }
567
568 ULLONG VDR::rescanRecording()
569 {
570   unsigned long totalLength = 8;
571   UCHAR buffer[totalLength];
572
573   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
574   *(unsigned long*)&buffer[4] = htonl(VDR_RESCANRECORDING);
575
576   pthread_mutex_lock(&mutex);
577   unsigned int a = tcp->sendPacket(buffer, totalLength);
578   if (a != totalLength)
579   {
580     pthread_mutex_unlock(&mutex);
581     return 0;
582   }
583
584   if (!getPacket())
585   {
586     pthread_mutex_unlock(&mutex);
587     return 0;
588   }
589
590   ULLONG recordingLength = extractULLONG();
591   freePacket();
592   pthread_mutex_unlock(&mutex);
593
594   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength);
595
596   return recordingLength;
597 }
598
599 EventList* VDR::getChannelSchedule(ULONG number)
600 {
601   UCHAR buffer[12];
602
603   *(unsigned long*)&buffer[0] = htonl(8);
604   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE);
605   *(unsigned long*)&buffer[8] = htonl(number);
606
607   pthread_mutex_lock(&mutex);
608   int a = tcp->sendPacket(buffer, 12);
609
610   if (a != 12)
611   {
612     pthread_mutex_unlock(&mutex);
613     return NULL;
614   }
615
616   if (!getPacket())
617   {
618     pthread_mutex_unlock(&mutex);
619     return NULL;
620   }
621
622   if (serverError())
623   {
624     freePacket();
625     pthread_mutex_unlock(&mutex);
626     return NULL;
627   }
628
629
630   EventList* eventList = new EventList();
631
632   while (packetPos < packetLength)
633   {
634     Event* event = new Event();
635     event->id = extractULONG();
636     event->time = extractULONG();
637     event->duration = extractULONG();
638     event->title = extractString();
639     event->subtitle = extractString();
640     event->description = extractString();
641     eventList->push_back(event);
642 //    eventList->next();
643   }
644
645   freePacket();
646   pthread_mutex_unlock(&mutex);
647
648   Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
649
650
651   // debug
652 /*
653   Log* l = Log::getInstance();
654
655
656   l->log("VDR", Log::DEBUG, "datalength = %i count = %i", dataLength, count);
657
658   Event* currentEvent;
659   for(eventList->reset(); !eventList->eol(); eventList->next())
660   {
661     currentEvent = (Event*)eventList->getCurrent();
662     l->log("VDR", Log::DEBUG, "%lu %lu %lu %s %s %s", currentEvent->id, currentEvent->time, currentEvent->duration, currentEvent->title, currentEvent->subtitle, currentEvent->description);
663   }
664 */
665
666   return eventList;
667 }
668
669 ULLONG VDR::getResumePoint(char* fileName)
670 {
671   char* resumeString = configLoad("ResumeData", fileName);
672   if (!resumeString) return 0;
673
674   ULLONG toReturn = strtoull(resumeString, NULL, 10);
675   delete[] resumeString;
676   return toReturn;
677 }
678
679 int VDR::configSave(char* section, char* key, char* value)
680 {
681   ULONG totalLength = 8 + strlen(section) + strlen(key) + strlen(value) + 3; // 8 for headers, 3 for nulls
682   UCHAR buffer[totalLength];
683
684   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
685   *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGSAVE);
686
687   int position = 8;
688   strcpy((char*)&buffer[position], section);
689   position += strlen(section) + 1;
690   strcpy((char*)&buffer[position], key);
691   position += strlen(key) + 1;
692   strcpy((char*)&buffer[position], value);
693
694   pthread_mutex_lock(&mutex);
695   unsigned int a = tcp->sendPacket(buffer, totalLength);
696   if (a != totalLength)
697   {
698     pthread_mutex_unlock(&mutex);
699     return 0;
700   }
701
702   if (!getPacket())
703   {
704     pthread_mutex_unlock(&mutex);
705     return 0;
706   }
707
708   int toReturn = (int)extractULONG();
709   freePacket();
710   pthread_mutex_unlock(&mutex);
711
712   return toReturn;
713 }
714
715 char* VDR::configLoad(char* section, char* key)
716 {
717   ULONG totalLength = 8 + strlen(section) + strlen(key) + 2; // 8 for headers, 2 for nulls
718   UCHAR buffer[totalLength];
719
720   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
721   *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGLOAD);
722
723   int position = 8;
724   strcpy((char*)&buffer[position], section);
725   position += strlen(section) + 1;
726   strcpy((char*)&buffer[position], key);
727
728   pthread_mutex_lock(&mutex);
729   unsigned int a = tcp->sendPacket(buffer, totalLength);
730   if (a != totalLength)
731   {
732     pthread_mutex_unlock(&mutex);
733     return NULL;
734   }
735
736   if (!getPacket())
737   {
738     pthread_mutex_unlock(&mutex);
739     return NULL;
740   }
741   char* toReturn = extractString();
742   freePacket();
743   pthread_mutex_unlock(&mutex);
744
745   return toReturn;
746 }