]> git.vomp.tv Git - vompclient-marten.git/blob - vdr.cc
Demuxer changes/fixes/improvements
[vompclient-marten.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 #include "recman.h"
24 #include "tcp.h"
25 #include "log.h"
26 #include "recinfo.h"
27 #include "dsock.h"
28 #include "channel.h"
29 #include "event.h"
30 #include "wol.h"
31
32 VDR* VDR::instance = NULL;
33
34 #ifndef WIN32
35 #define MUTEX_LOCK(mutex) pthread_mutex_lock(mutex)
36 #define MUTEX_UNLOCK(mutex) pthread_mutex_unlock(mutex)
37 #else
38 #define MUTEX_LOCK(mutex) WaitForSingleObject(*(mutex), INFINITE )
39 #define MUTEX_UNLOCK(mutex) ReleaseMutex(*(mutex))
40 #endif
41
42
43 VDR::VDR()
44 {
45   if (instance) return;
46   instance = this;
47   initted = 0;
48   findingServer = 0;
49   tcp = NULL;
50 #ifndef WIN32
51   pthread_mutex_init(&mutex, NULL);
52 #else
53   mutex=CreateMutex(NULL,FALSE,NULL);
54 #endif
55   packetLength = 0;
56   packetPos = 0;
57   packet = NULL;
58   connected = false;
59   maxChannelNumber = 0;
60   channelNumberWidth = 1;
61 }
62
63 VDR::~VDR()
64 {
65 #ifdef WIN32
66   CloseHandle(mutex);
67 #endif
68   instance = NULL;
69   if (initted) shutdown();
70 }
71
72 VDR* VDR::getInstance()
73 {
74   return instance;
75 }
76
77 int VDR::init(int tport)
78 {
79   if (initted) return 0;
80   initted = 1;
81   port = tport;
82   logger = Log::getInstance();
83   return 1;
84 }
85
86 int VDR::shutdown()
87 {
88   if (!initted) return 0;
89   initted = 0;
90   disconnect();
91   return 1;
92 }
93
94 void VDR::findServers(vector<VDRServer>& servers)
95 {
96   Wol* wol = Wol::getInstance();
97   findingServer = 1;
98   char* message = "VOMP";
99
100   DatagramSocket ds(port);
101   int haveAtLeastOne = 0;
102   int retval;
103   int waitType = 1;
104   bool firstloop = true;
105   while(findingServer)
106   {
107     if (waitType == 1)
108     {
109       ds.shutdown();
110       ds.init();
111       logger->log("VDR", Log::NOTICE, "Broadcasting for server");
112       ds.send("255.255.255.255", 3024, message, strlen(message));
113       if(!firstloop) wol->doWakeUp();
114     }
115     retval = ds.waitforMessage(waitType);
116
117     if (retval == 2) // we got a reply
118     {
119       if (!strcmp(ds.getData(), "VOMP")) // echo.....
120       {
121         waitType = 2;
122       }
123       else
124       {
125         VDRServer newServer;
126         newServer.ip = new char[16];
127         strcpy(newServer.ip, ds.getFromIPA());
128
129         if (ds.getDataLength() == 0)
130         {
131           newServer.name = new char[1];
132           newServer.name[0] = '\0';
133         }
134         else
135         {
136           newServer.name = new char[strlen(ds.getData())+1];
137           strcpy(newServer.name, ds.getData());
138         }
139
140         servers.push_back(newServer);
141         waitType = 2;
142         haveAtLeastOne = 1;
143       }
144     }
145     else
146     {
147       if (haveAtLeastOne) break;
148       waitType = 1;
149       firstloop = false;
150     }
151   }
152   sort(servers.begin(), servers.end(), ServerSorter());
153 }
154
155 void VDR::cancelFindingServer()
156 {
157   findingServer = 0;
158 }
159
160 void VDR::setServerIP(char* newIP)
161 {
162   strcpy(serverIP, newIP);
163 }
164
165 int VDR::connect()
166 {
167   maxChannelNumber = 0;
168   channelNumberWidth = 1;
169
170   if (tcp) delete tcp;
171   tcp = new TCP();
172   if (tcp->connectTo(serverIP, 3024))
173   {
174     connected = true;
175     return 1;
176   }
177   else
178   {
179     return 0;
180   }
181 }
182
183 void VDR::disconnect()
184 {
185   if (tcp) delete tcp;
186   tcp = NULL;
187   connected = false;
188   Log::getInstance()->log("VDR", Log::DEBUG, "Disconnect");
189 }
190
191 void VDR::setReceiveWindow(size_t size)
192 {
193   if (connected) tcp->setReceiveWindow(size);
194 }
195
196 ///////////////////////////////////////////////////////
197
198 int VDR::getPacket()
199 {
200   packet = (UCHAR*)tcp->receivePacket();
201   if (!packet)
202   {
203     disconnect();
204     return 0;
205   }
206   packetLength = tcp->getDataLength();
207   return 1;
208 }
209
210 void VDR::freePacket()
211 {
212   // Must be called if getPacket return 1, except in getBlock
213   packetLength = 0;
214   packetPos = 0;
215   free(packet);
216   packet = NULL;
217 }
218
219 int VDR::serverError()
220 {
221   if ((packetPos == 0) && (packetLength == 4) && !ntohl(*(ULONG*)packet)) return 1;
222   else return 0;
223 }
224
225 char* VDR::extractString()
226 {
227   if (serverError()) return NULL;
228
229   int length = strlen((char*)&packet[packetPos]);
230   if ((packetPos + length) > packetLength) return NULL;
231   char* str = new char[length + 1];
232   strcpy(str, (char*)&packet[packetPos]);
233   packetPos += length + 1;
234   return str;
235 }
236
237 UCHAR VDR::extractUCHAR()
238 {
239   if ((packetPos + sizeof(UCHAR)) > packetLength) return 0;
240   UCHAR uc = packet[packetPos];
241   packetPos += sizeof(UCHAR);
242   return uc;
243 }
244
245 ULONG VDR::extractULONG()
246 {
247   if ((packetPos + sizeof(ULONG)) > packetLength) return 0;
248   ULONG ul = ntohl(*(ULONG*)&packet[packetPos]);
249   packetPos += sizeof(ULONG);
250   return ul;
251 }
252
253 ULLONG VDR::extractULLONG()
254 {
255   if ((packetPos + sizeof(ULLONG)) > packetLength) return 0;
256   ULLONG ull = ntohll(*(ULLONG*)&packet[packetPos]);
257   packetPos += sizeof(ULLONG);
258   return ull;
259 }
260
261 long VDR::extractLONG()
262 {
263   if ((packetPos + sizeof(long)) > packetLength) return 0;
264   long l = ntohl(*(long*)&packet[packetPos]);
265   packetPos += sizeof(long);
266   return l;
267 }
268
269 /////////////////////////////////////////////////////////////////////////////
270
271 int VDR::doLogin()
272 {
273   UCHAR buffer[14];
274
275   *(unsigned long*)&buffer[0] = htonl(10);
276   *(unsigned long*)&buffer[4] = htonl(VDR_LOGIN);
277
278   tcp->getMAC((char*)&buffer[8]);
279
280
281   MUTEX_LOCK(&mutex);
282   if (!connected)
283   {
284     MUTEX_UNLOCK(&mutex);
285     return 0;
286   }
287
288   int a = tcp->sendPacket(buffer, 14);
289   if (a != 14)
290   {
291     disconnect();
292     MUTEX_UNLOCK(&mutex);
293     return 0;
294   }
295
296   // reply
297
298   if (!getPacket())
299   {
300     MUTEX_UNLOCK(&mutex);
301     return 0;
302   }
303
304   ULONG vdrTime = extractULONG();
305   logger->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime);
306   long vdrTimeOffset = extractLONG();
307   logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset);
308
309   freePacket();
310   MUTEX_UNLOCK(&mutex);
311
312   // Set the time and zone on the MVP
313
314 #ifndef WIN32
315   struct timespec currentTime;
316   currentTime.tv_sec = vdrTime;
317   currentTime.tv_nsec = 0;
318   int b = clock_settime(CLOCK_REALTIME, &currentTime);
319
320   logger->log("VDR", Log::DEBUG, "set clock = %u", b);
321
322   // now make a TZ variable and set it
323   char sign;
324   int hours;
325   int minutes;
326   if (vdrTimeOffset > 0) sign = '-';
327   else sign = '+';
328
329   vdrTimeOffset = abs(vdrTimeOffset);
330
331   hours = (int)vdrTimeOffset / 3600;
332   minutes = vdrTimeOffset % 3600;
333
334   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
335
336   minutes = (int)minutes / 60;
337
338   logger->log("VDR", Log::DEBUG, "%c %i %i", sign, hours, minutes);
339
340   char newTZ[30];
341   sprintf(newTZ, "MVP%c%i:%i", sign, hours, minutes);
342   setenv("TZ", newTZ, 1);
343
344   logger->log("VDR", Log::DEBUG, "Timezone data: %s", newTZ);
345 #endif
346
347   return 1;
348 }
349
350 bool VDR::getRecordingsList(RecMan* recman)
351 {
352   UCHAR buffer[8];
353
354   *(unsigned long*)&buffer[0] = htonl(4);
355   *(unsigned long*)&buffer[4] = htonl(VDR_GETRECORDINGLIST);
356
357   MUTEX_LOCK(&mutex);
358   if (!connected)
359   {
360     MUTEX_UNLOCK(&mutex);
361     return 0;
362   }
363
364   int a = tcp->sendPacket(buffer, 8);
365   if (a != 8)
366   {
367     disconnect();
368     MUTEX_UNLOCK(&mutex);
369     return false;
370   }
371
372   // reply
373
374   if (!getPacket())
375   {
376     MUTEX_UNLOCK(&mutex);
377     return false;
378   }
379
380   ULONG totalSpace = extractULONG();
381   ULONG freeSpace = extractULONG();
382   ULONG percent = extractULONG();
383   recman->setStats(totalSpace, freeSpace, percent);
384
385   ULONG start;
386   char* name;
387   char* fileName;
388
389   while (packetPos < packetLength)
390   {
391     start = extractULONG();
392     name = extractString();
393     fileName = extractString();
394
395     recman->addEntry(start, name, fileName);
396
397     delete[] name;
398     delete[] fileName;
399   }
400
401   freePacket();
402   MUTEX_UNLOCK(&mutex);
403
404   return true;
405 }
406
407 int VDR::deleteRecording(char* fileName)
408 {
409   unsigned long totalLength = 8 + strlen(fileName) + 1;
410   UCHAR* buffer = new UCHAR[totalLength];
411
412   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
413   *(unsigned long*)&buffer[4] = htonl(VDR_DELETERECORDING);
414   strcpy((char*)&buffer[8], fileName);
415
416   MUTEX_LOCK(&mutex);
417   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
418
419   unsigned int a = tcp->sendPacket(buffer, totalLength);
420   delete []buffer;
421
422   if (a != totalLength)
423   {
424     disconnect();
425     MUTEX_UNLOCK(&mutex);
426     return 0;
427   }
428
429   if (!getPacket())
430   {
431     MUTEX_UNLOCK(&mutex);
432     return 0;
433   }
434
435   int toReturn = (int)extractULONG();
436   freePacket();
437   MUTEX_UNLOCK(&mutex);
438
439   return toReturn;
440 }
441
442 char* VDR::moveRecording(char* fileName, char* newPath)
443 {
444   unsigned long totalLength = 8 + strlen(fileName) + 1 + strlen(newPath) + 1;
445   UCHAR* buffer = new UCHAR[totalLength];
446
447   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
448   *(unsigned long*)&buffer[4] = htonl(VDR_MOVERECORDING);
449   strcpy((char*)&buffer[8], fileName);
450   strcpy((char*)&buffer[8 + strlen(fileName) + 1], newPath);
451
452   MUTEX_LOCK(&mutex);
453   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
454
455   unsigned int a = tcp->sendPacket(buffer, totalLength);
456   delete []buffer;
457
458   if (a != totalLength)
459   {
460     disconnect();
461     MUTEX_UNLOCK(&mutex);
462     return 0;
463   }
464
465   if (!getPacket())
466   {
467     MUTEX_UNLOCK(&mutex);
468     return 0;
469   }
470
471   char* toReturn = NULL;
472   int success = (int)extractULONG();
473   if (success == 1)
474   {
475     toReturn = extractString();
476   }
477
478   freePacket();
479   MUTEX_UNLOCK(&mutex);
480
481   return toReturn;
482 }
483
484 ChannelList* VDR::getChannelsList(ULONG type)
485 {
486   UCHAR buffer[8];
487
488   *(unsigned long*)&buffer[0] = htonl(4);
489   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELLIST);
490
491   MUTEX_LOCK(&mutex);
492   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
493
494   int a = tcp->sendPacket(buffer, 8);
495   if (a != 8)
496   {
497     disconnect();
498     MUTEX_UNLOCK(&mutex);
499     return NULL;
500   }
501
502   // reply
503
504   if (!getPacket())
505   {
506     MUTEX_UNLOCK(&mutex);
507     return NULL;
508   }
509
510   ChannelList* chanList = new ChannelList();
511
512   while (packetPos < packetLength)
513   {
514     Channel* chan = new Channel();
515     chan->number = extractULONG();
516     chan->type = extractULONG();
517     chan->name = extractString();
518
519     if (chan->type == type)
520     {
521       chanList->push_back(chan);
522       Log::getInstance()->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name);
523       if (chan->number > maxChannelNumber) maxChannelNumber = chan->number;
524     }
525     else
526     {
527       delete chan;
528     }
529   }
530
531   freePacket();
532   MUTEX_UNLOCK(&mutex);
533
534   if (maxChannelNumber > 99999)
535     channelNumberWidth = 6;
536   else if (maxChannelNumber > 9999)
537     channelNumberWidth = 5;
538   else if (maxChannelNumber > 999)
539     channelNumberWidth = 4;
540   else if (maxChannelNumber > 99)
541     channelNumberWidth = 3;
542   else if (maxChannelNumber > 9)
543     channelNumberWidth = 2;
544   else
545     channelNumberWidth = 1;
546
547   return chanList;
548 }
549
550 int VDR::streamChannel(ULONG number)
551 {
552   UCHAR buffer[12];
553
554   *(unsigned long*)&buffer[0] = htonl(8);
555   *(unsigned long*)&buffer[4] = htonl(VDR_STREAMCHANNEL);
556   *(unsigned long*)&buffer[8] = htonl(number);
557
558   MUTEX_LOCK(&mutex);
559   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
560
561   int a = tcp->sendPacket(buffer, 12);
562
563   if (a != 12)
564   {
565     disconnect();
566     MUTEX_UNLOCK(&mutex);
567     return 0;
568   }
569
570   if (!getPacket())
571   {
572     MUTEX_UNLOCK(&mutex);
573     return 0;
574   }
575
576   int toReturn = (int)extractULONG();
577   freePacket();
578   MUTEX_UNLOCK(&mutex);
579
580   return toReturn;
581 }
582
583 int VDR::stopStreaming()
584 {
585   UCHAR buffer[8];
586
587   *(unsigned long*)&buffer[0] = htonl(4);
588   *(unsigned long*)&buffer[4] = htonl(VDR_STOPSTREAMING);
589
590   MUTEX_LOCK(&mutex);
591   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
592
593   int a = tcp->sendPacket(buffer, 8);
594
595   if (a != 8)
596   {
597     disconnect();
598     MUTEX_UNLOCK(&mutex);
599     return 0;
600   }
601
602   if (!getPacket())
603   {
604     MUTEX_UNLOCK(&mutex);
605     return 0;
606   }
607
608   int toReturn = (int)extractULONG();
609   freePacket();
610   MUTEX_UNLOCK(&mutex);
611
612   return toReturn;
613 }
614
615 UCHAR* VDR::getImageBlock(ULONG position, UINT maxAmount, UINT* amountReceived)
616 {
617   return getBlock(position, maxAmount, amountReceived, VDR_GETIMAGEBLOCK);
618 }
619
620 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived)
621 {
622   return getBlock(position, maxAmount, amountReceived, VDR_GETBLOCK);
623 }
624
625 UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived, ULONG cmd)
626 {
627   UCHAR buffer[20];
628
629   *(unsigned long*)&buffer[0] = htonl(16);
630   *(unsigned long*)&buffer[4] = htonl(cmd);
631   *(ULLONG*)&buffer[8]        = htonll(position);
632   *(unsigned long*)&buffer[16] = htonl(maxAmount);
633
634   MUTEX_LOCK(&mutex);
635   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
636
637   int a = tcp->sendPacket(buffer, 20);
638   if (a != 20)
639   {
640     disconnect();
641     MUTEX_UNLOCK(&mutex);
642     return NULL;
643   }
644
645   if (!getPacket())
646   {
647     MUTEX_UNLOCK(&mutex);
648     return NULL;
649   }
650
651   if (serverError())
652   {
653     Log::getInstance()->log("VDR", Log::DEBUG, "Detected getblock 0");
654     freePacket();
655     MUTEX_UNLOCK(&mutex);
656     return NULL;
657   }
658
659   UCHAR* toReturn = packet;
660   *amountReceived = packetLength;
661   // Manually clean up instead of running freePacket to keep the block
662   packet = NULL;
663   packetLength = 0;
664   packetPos = 0;
665   MUTEX_UNLOCK(&mutex);
666
667
668   return toReturn;
669 }
670
671 ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames)
672 {
673   unsigned long totalLength = 8 + strlen(fileName) + 1;
674   UCHAR* buffer = new UCHAR[totalLength];
675
676   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
677   *(unsigned long*)&buffer[4] = htonl(VDR_STREAMRECORDING);
678   strcpy((char*)&buffer[8], fileName);
679
680   MUTEX_LOCK(&mutex);
681   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
682
683   unsigned int a = tcp->sendPacket(buffer, totalLength);
684   delete []buffer;
685
686   if (a != totalLength)
687   {
688     disconnect();
689     MUTEX_UNLOCK(&mutex);
690     return 0;
691   }
692
693   if (!getPacket())
694   {
695     MUTEX_UNLOCK(&mutex);
696     return 0;
697   }
698
699   ULLONG lengthBytes = extractULLONG();
700   ULONG lengthFrames = extractULONG();
701   freePacket();
702   MUTEX_UNLOCK(&mutex);
703
704   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
705
706   *totalFrames = lengthFrames;
707   return lengthBytes;
708 }
709
710 ULLONG VDR::positionFromFrameNumber(ULONG frameNumber)
711 {
712   unsigned long totalLength = 12;
713   UCHAR* buffer = new UCHAR[totalLength];
714
715   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
716   *(unsigned long*)&buffer[4] = htonl(VDR_POSFROMFRAME);
717   *(unsigned long*)&buffer[8] = htonl(frameNumber);
718
719   MUTEX_LOCK(&mutex);
720   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
721
722   unsigned int a = tcp->sendPacket(buffer, totalLength);
723   delete []buffer;
724
725   if (a != totalLength)
726   {
727     disconnect();
728     MUTEX_UNLOCK(&mutex);
729     return 0;
730   }
731
732   if (!getPacket())
733   {
734     MUTEX_UNLOCK(&mutex);
735     return 0;
736   }
737
738   ULLONG position = extractULLONG();
739   freePacket();
740   MUTEX_UNLOCK(&mutex);
741
742   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new position is: %llu", position);
743
744   return position;
745 }
746
747 ULONG VDR::frameNumberFromPosition(ULLONG position)
748 {
749   unsigned long totalLength = 16;
750   UCHAR* buffer = new UCHAR[totalLength];
751
752   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
753   *(unsigned long*)&buffer[4] = htonl(VDR_FRAMEFROMPOS);
754   *(ULLONG*)&buffer[8] = htonll(position);
755
756   MUTEX_LOCK(&mutex);
757   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
758
759   unsigned int a = tcp->sendPacket(buffer, totalLength);
760   delete []buffer;
761
762   if (a != totalLength)
763   {
764     disconnect();
765     MUTEX_UNLOCK(&mutex);
766     return 0;
767   }
768
769   if (!getPacket())
770   {
771     MUTEX_UNLOCK(&mutex);
772     return 0;
773   }
774
775   ULONG framenumber = extractULONG();
776   freePacket();
777   MUTEX_UNLOCK(&mutex);
778
779   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said new framenumber is: %u", framenumber);
780
781   return framenumber;
782 }
783
784 bool VDR::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)
785 {
786   unsigned long totalLength = 16;
787   UCHAR* buffer = new UCHAR[totalLength];
788
789   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
790   *(unsigned long*)&buffer[4] = htonl(VDR_GETNEXTIFRAME);
791   *(unsigned long*)&buffer[8] = htonl(frameNumber);
792   *(unsigned long*)&buffer[12] = htonl(direction);
793
794   MUTEX_LOCK(&mutex);
795   if (!connected) { MUTEX_UNLOCK(&mutex); return false; }
796
797   unsigned int a = tcp->sendPacket(buffer, totalLength);
798   delete []buffer;
799
800   if (a != totalLength)
801   {
802     disconnect();
803     MUTEX_UNLOCK(&mutex);
804     return false;
805   }
806
807   if (!getPacket())
808   {
809     MUTEX_UNLOCK(&mutex);
810     return false;
811   }
812
813   if (serverError())
814   {
815     Log::getInstance()->log("VDR", Log::DEBUG, "Detected getNextIFrame error");
816     freePacket();
817     MUTEX_UNLOCK(&mutex);
818     return false;
819   }
820
821   *rfilePosition = extractULLONG();
822   *rframeNumber = extractULONG();
823   *rframeLength = extractULONG();
824
825   freePacket();
826   MUTEX_UNLOCK(&mutex);
827
828 //  Log::getInstance()->log("VDR", Log::DEBUG, "VDR GNIF said %llu %lu %lu", *rfilePosition, *rframeNumber, *rframeLength);
829
830   return true;
831 }
832
833 EventList* VDR::getChannelSchedule(ULONG number)
834 {
835   time_t now;
836   time(&now);
837   return getChannelSchedule(number, now, 24 * 60 * 60);
838 }
839
840 EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
841 {
842 // retrieve event list (vector of events) from vdr within filter window. duration is in seconds
843   UCHAR buffer[20];
844
845   *(unsigned long*)&buffer[0] = htonl(16);
846   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE);
847   *(unsigned long*)&buffer[8] = htonl(number);
848   *(unsigned long*)&buffer[12] = htonl(start);
849   *(unsigned long*)&buffer[16] = htonl(duration);
850
851   MUTEX_LOCK(&mutex);
852   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
853
854   int a = tcp->sendPacket(buffer, 20);
855
856   if (a != 20)
857   {
858     disconnect();
859     MUTEX_UNLOCK(&mutex);
860     return NULL;
861   }
862
863   if (!getPacket())
864   {
865     MUTEX_UNLOCK(&mutex);
866     return NULL;
867   }
868
869   // received a ulong(0) - schedules error in the plugin
870   if (serverError())
871   {
872     freePacket();
873     MUTEX_UNLOCK(&mutex);
874     return NULL;
875   }
876
877   EventList* eventList = new EventList();
878
879   while (packetPos < packetLength)
880   {
881     Event* event = new Event();
882     event->id = extractULONG();
883     event->time = extractULONG();
884     event->duration = extractULONG();
885     event->title = extractString();
886     event->subtitle = extractString();
887     event->description = extractString();
888     eventList->push_back(event);
889   }
890
891   freePacket();
892   MUTEX_UNLOCK(&mutex);
893
894   Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule");
895   return eventList;
896 }
897
898 int VDR::configSave(const char* section, const char* key, const char* value)
899 {
900   ULONG totalLength = 8 + strlen(section) + strlen(key) + strlen(value) + 3; // 8 for headers, 3 for nulls
901   UCHAR* buffer = new UCHAR[totalLength];
902
903   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
904   *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGSAVE);
905
906   int position = 8;
907   strcpy((char*)&buffer[position], section);
908   position += strlen(section) + 1;
909   strcpy((char*)&buffer[position], key);
910   position += strlen(key) + 1;
911   strcpy((char*)&buffer[position], value);
912
913   MUTEX_LOCK(&mutex);
914   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
915
916   unsigned int a = tcp->sendPacket(buffer, totalLength);
917   delete[] buffer;
918
919   if (a != totalLength)
920   {
921     disconnect();
922     MUTEX_UNLOCK(&mutex);
923     return 0;
924   }
925
926   if (!getPacket())
927   {
928     MUTEX_UNLOCK(&mutex);
929     return 0;
930   }
931
932   int toReturn = (int)extractULONG();
933   freePacket();
934   MUTEX_UNLOCK(&mutex);
935
936   return toReturn;
937 }
938
939 char* VDR::configLoad(const char* section, const char* key)
940 {
941   ULONG totalLength = 8 + strlen(section) + strlen(key) + 2; // 8 for headers, 2 for nulls
942   UCHAR* buffer = new UCHAR[totalLength];
943
944   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
945   *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGLOAD);
946
947   int position = 8;
948   strcpy((char*)&buffer[position], section);
949   position += strlen(section) + 1;
950   strcpy((char*)&buffer[position], key);
951
952   MUTEX_LOCK(&mutex);
953   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
954
955   unsigned int a = tcp->sendPacket(buffer, totalLength);
956   delete[] buffer;
957
958   if (a != totalLength)
959   {
960     disconnect();
961     MUTEX_UNLOCK(&mutex);
962     return NULL;
963   }
964
965   if (!getPacket())
966   {
967     MUTEX_UNLOCK(&mutex);
968     return NULL;
969   }
970   char* toReturn = extractString();
971   freePacket();
972   MUTEX_UNLOCK(&mutex);
973
974   return toReturn;
975 }
976
977 RecTimerList* VDR::getRecTimersList()
978 {
979   UCHAR buffer[8];
980
981   *(unsigned long*)&buffer[0] = htonl(4);
982   *(unsigned long*)&buffer[4] = htonl(VDR_GETTIMERS);
983
984   MUTEX_LOCK(&mutex);
985   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
986
987   int a = tcp->sendPacket(buffer, 8);
988   if (a != 8)
989   {
990     disconnect();
991     MUTEX_UNLOCK(&mutex);
992     return NULL;
993   }
994
995   // reply
996
997   if (!getPacket())
998   {
999     MUTEX_UNLOCK(&mutex);
1000     return NULL;
1001   }
1002
1003   RecTimerList* recTimerList = new RecTimerList();
1004
1005   ULONG numTimers = extractULONG();
1006   if (numTimers > 0)
1007   {
1008     RecTimer* newRecTimer;
1009     char* tempString;
1010
1011     while (packetPos < packetLength)
1012     {
1013       newRecTimer = new RecTimer();
1014       newRecTimer->active = extractULONG();
1015       newRecTimer->recording = extractULONG();
1016       newRecTimer->pending = extractULONG();
1017       newRecTimer->priority = extractULONG();
1018       newRecTimer->lifeTime = extractULONG();
1019       newRecTimer->channelNumber = extractULONG();
1020       newRecTimer->startTime = extractULONG();
1021       newRecTimer->stopTime = extractULONG();
1022       newRecTimer->day = extractULONG();
1023       newRecTimer->weekDays = extractULONG();
1024
1025       tempString = extractString();
1026       newRecTimer->setFile(tempString);
1027       delete[] tempString;
1028
1029       recTimerList->push_back(newRecTimer);
1030       Log::getInstance()->log("VDR", Log::DEBUG, "TL: %lu %lu %lu %lu %lu %lu %lu %lu %s",
1031         newRecTimer->active, newRecTimer->recording, newRecTimer->pending, newRecTimer->priority, newRecTimer->lifeTime,
1032         newRecTimer->channelNumber, newRecTimer->startTime, newRecTimer->stopTime, newRecTimer->getFile());
1033     }
1034   }
1035
1036   freePacket();
1037   MUTEX_UNLOCK(&mutex);
1038
1039   sort(recTimerList->begin(), recTimerList->end(), RecTimerSorter());
1040
1041   return recTimerList;
1042 }
1043
1044 ULONG VDR::setEventTimer(char* timerString)
1045 {
1046   unsigned long totalLength = 8 + strlen(timerString) + 1;
1047   UCHAR* buffer = new UCHAR[totalLength];
1048
1049   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1050   *(unsigned long*)&buffer[4] = htonl(VDR_SETTIMER);
1051   strcpy((char*)&buffer[8], timerString);
1052
1053   MUTEX_LOCK(&mutex);
1054   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1055
1056   unsigned int a = tcp->sendPacket(buffer, totalLength);
1057   delete []buffer;
1058
1059   if (a != totalLength)
1060   {
1061     disconnect();
1062     MUTEX_UNLOCK(&mutex);
1063     return 0;
1064   }
1065
1066   if (!getPacket())
1067   {
1068     MUTEX_UNLOCK(&mutex);
1069     return 0;
1070   }
1071
1072   ULONG toReturn = extractULONG();
1073   freePacket();
1074   MUTEX_UNLOCK(&mutex);
1075
1076   return toReturn;
1077 }
1078
1079 RecInfo* VDR::getRecInfo(char* fileName)
1080 {
1081   unsigned long totalLength = 8 + strlen(fileName) + 1;
1082   UCHAR* buffer = new UCHAR[totalLength];
1083
1084   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1085   *(unsigned long*)&buffer[4] = htonl(VDR_GETRECINFO);
1086   strcpy((char*)&buffer[8], fileName);
1087
1088   MUTEX_LOCK(&mutex);
1089   if (!connected) { MUTEX_UNLOCK(&mutex); return NULL; }
1090
1091   unsigned int a = tcp->sendPacket(buffer, totalLength);
1092   delete []buffer;
1093
1094   if (a != totalLength)
1095   {
1096     disconnect();
1097     MUTEX_UNLOCK(&mutex);
1098     return NULL;
1099   }
1100
1101   if (!getPacket())
1102   {
1103     MUTEX_UNLOCK(&mutex);
1104     return NULL;
1105   }
1106
1107   if (serverError())
1108   {
1109     Log::getInstance()->log("VDR", Log::DEBUG, "Could not get rec info");
1110     freePacket();
1111     MUTEX_UNLOCK(&mutex);
1112     return NULL;
1113   }
1114
1115   TCP::dump(packet, packetLength);
1116
1117   RecInfo* recInfo = new RecInfo();
1118
1119   recInfo->timerStart = extractULONG();
1120   recInfo->timerEnd = extractULONG();
1121   recInfo->resumePoint = extractULONG();
1122   recInfo->summary = extractString();
1123
1124   ULONG numComponents = extractULONG();
1125   if (numComponents)
1126   {
1127     recInfo->setNumComponents(numComponents);
1128     for (ULONG i = 0; i < numComponents; i++)
1129     {
1130       recInfo->streams[i] = extractUCHAR();
1131       recInfo->types[i] = extractUCHAR();
1132       recInfo->languages[i] = extractString();
1133       recInfo->descriptions[i] = extractString();
1134     }
1135   }
1136
1137   recInfo->print();
1138
1139   freePacket();
1140   MUTEX_UNLOCK(&mutex);
1141   return recInfo;
1142 }
1143
1144 // FIXME obselete
1145 ULLONG VDR::rescanRecording(ULONG* totalFrames)
1146 {
1147   unsigned long totalLength = 8;
1148   UCHAR* buffer = new UCHAR[totalLength];
1149
1150   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1151   *(unsigned long*)&buffer[4] = htonl(VDR_RESCANRECORDING);
1152
1153   MUTEX_LOCK(&mutex);
1154   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1155
1156   unsigned int a = tcp->sendPacket(buffer, totalLength);
1157   delete []buffer;
1158
1159   if (a != totalLength)
1160   {
1161     disconnect();
1162     MUTEX_UNLOCK(&mutex);
1163     return 0;
1164   }
1165
1166   if (!getPacket())
1167   {
1168     MUTEX_UNLOCK(&mutex);
1169     return 0;
1170   }
1171
1172   ULLONG lengthBytes = extractULLONG();
1173   ULONG lengthFrames = extractULONG();
1174   freePacket();
1175   MUTEX_UNLOCK(&mutex);
1176
1177   Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames);
1178
1179   *totalFrames = lengthFrames;
1180   return lengthBytes;
1181 }
1182
1183 MarkList* VDR::getMarks(char* fileName)
1184 {
1185   unsigned long totalLength = 8 + strlen(fileName) + 1;
1186   UCHAR* buffer = new UCHAR[totalLength];
1187
1188   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1189   *(unsigned long*)&buffer[4] = htonl(VDR_GETMARKS);
1190   strcpy((char*)&buffer[8], fileName);
1191
1192   MUTEX_LOCK(&mutex);
1193   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1194
1195   unsigned int a = tcp->sendPacket(buffer, totalLength);
1196   delete []buffer;
1197
1198   if (a != totalLength)
1199   {
1200     disconnect();
1201     MUTEX_UNLOCK(&mutex);
1202     return NULL;
1203   }
1204
1205   if (!getPacket())
1206   {
1207     MUTEX_UNLOCK(&mutex);
1208     return NULL;
1209   }
1210
1211   if (serverError())
1212   {
1213     MUTEX_UNLOCK(&mutex);
1214     return NULL;
1215   }
1216
1217   MarkList* markList = new MarkList();
1218
1219   while (packetPos < packetLength)
1220   {
1221     Mark* mark = new Mark();
1222     mark->pos = extractULONG();
1223
1224     markList->push_back(mark);
1225     Log::getInstance()->log("VDR", Log::DEBUG, "Have added a mark to list. %lu", mark->pos);
1226   }
1227
1228   freePacket();
1229   MUTEX_UNLOCK(&mutex);
1230
1231   return markList;
1232 }
1233
1234 void VDR::getChannelPids(Channel* channel)
1235 {
1236   UCHAR buffer[12];
1237
1238   *(unsigned long*)&buffer[0] = htonl(8);
1239   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELPIDS);
1240   *(unsigned long*)&buffer[8] = htonl(channel->number);
1241
1242   MUTEX_LOCK(&mutex);
1243   if (!connected) { MUTEX_UNLOCK(&mutex); return ; }
1244
1245   int a = tcp->sendPacket(buffer, 12);
1246
1247   if (a != 12)
1248   {
1249     disconnect();
1250     MUTEX_UNLOCK(&mutex);
1251     return ;
1252   }
1253
1254   if (!getPacket())
1255   {
1256     MUTEX_UNLOCK(&mutex);
1257     return ;
1258   }
1259
1260   // Format of response
1261   // vpid
1262   // number of apids
1263   // {
1264   //    apid
1265   //    lang string
1266   // }
1267
1268   channel->vpid = extractULONG();
1269   channel->numAPids = extractULONG();
1270
1271   for (ULONG i = 0; i < channel->numAPids; i++)
1272   {
1273     apid newapid;
1274     newapid.pid = extractULONG();
1275     newapid.name = extractString();
1276     channel->apids.push_back(newapid);
1277   }
1278
1279   freePacket();
1280   MUTEX_UNLOCK(&mutex);
1281
1282   return ;
1283 }
1284
1285 /**
1286   * media List Request:
1287   * 4 length
1288   * 4 VDR_GETMEDIALIST
1289   * 4 flags (currently unused)
1290   * n dirname
1291   * n+1 0
1292   * Media List response:
1293   * 4 length
1294   * 4 VDR_
1295   * 4 numentries
1296   * per entry:
1297   * 4 media type
1298   * 4 time stamp
1299   * 4 flags
1300   * 4 strlen (incl. 0 Byte)
1301   * string
1302   * 0
1303 */
1304 MediaList* VDR::getMediaList(const char* parent,int mediaType)
1305 {
1306   Log::getInstance()->log("VDR", Log::DEBUG, "getMediaList %s,type=%d",
1307       (parent?parent:"NULL"), mediaType);
1308   unsigned long totalLength = 12;
1309   if (parent) totalLength+=strlen(parent) + 1;
1310   UCHAR* buffer = new UCHAR[totalLength];
1311
1312   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1313   *(unsigned long*)&buffer[4] = htonl(VDR_GETMEDIALIST);
1314   //unused flags
1315   for (int i=8;i<12;i++) buffer[i]=0;
1316   //name
1317   if (parent) {
1318     strcpy((char*)&buffer[12], parent);
1319     buffer[totalLength-1]=0;
1320     }
1321   MUTEX_LOCK(&mutex);
1322   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1323
1324   unsigned int a = tcp->sendPacket(buffer, totalLength);
1325   delete []buffer;
1326
1327   if (a != totalLength)
1328   {
1329     disconnect();
1330     MUTEX_UNLOCK(&mutex);
1331     return NULL;
1332   }
1333
1334   if (!getPacket())
1335   {
1336     MUTEX_UNLOCK(&mutex);
1337     return NULL;
1338   }
1339
1340   if (serverError())
1341   {
1342     MUTEX_UNLOCK(&mutex);
1343     return NULL;
1344   }
1345   if (packetLength < 12) {
1346     Log::getInstance()->log("VDR", Log::ERR, "receiveMediaList packet too short, expected 12, got %d", packetLength);
1347     freePacket();
1348     MUTEX_UNLOCK(&mutex);
1349     return NULL;
1350     }
1351   MediaList* mediaList = new MediaList();
1352   ULONG code=0;
1353   code=extractULONG();
1354   ULONG numEntries=extractULONG();
1355   Log::getInstance()->log("VDR", Log::DEBUG, "receiveMediaList with %d entries",numEntries);
1356   while (packetPos < packetLength && numEntries >0)
1357   {
1358     Media* m = new Media();
1359     ULONG mtype = extractULONG();
1360     ULONG mtime=extractULONG();
1361     ULONG flags=0;
1362     flags=extractULONG();
1363     ULONG stsize=extractULONG();
1364     char * name=extractString();
1365     if (! name || stsize != (strlen(name)+1)) {
1366       Log::getInstance()->log("VDR", Log::ERR, "receiveMediaList invalid packet entry, read size %d, strlen %d", stsize, strlen(name)+1);
1367       delete m;
1368       delete mediaList;
1369       freePacket();
1370       MUTEX_UNLOCK(&mutex);
1371       return NULL;
1372       }
1373     //ignore . and .. entries
1374     if (strcmp(name,".") == 0 || strcmp(name,"..")==0) {
1375   delete m;
1376   continue;
1377     }
1378     m->setFileName(name);
1379     m->setTime(mtime);
1380     m->setMediaType(mtype);
1381     mediaList->push_back(m);
1382     Log::getInstance()->log("VDR", Log::DEBUG, "Have added a media to list. %s, type=%d, time=%d", name,mtype,mtime);
1383     numEntries--;
1384   }
1385
1386   freePacket();
1387   MUTEX_UNLOCK(&mutex);
1388
1389   return mediaList;
1390 }
1391 /**
1392   * get image Request:
1393   * 4 length
1394   * 4 VDR_GETIMAGE
1395   * 4 flags (currently unused)
1396   * 4 x size
1397   * 4 y size
1398   * n filename
1399   * n+1 0
1400   * get image response:
1401   * 4 length
1402   * 4 VDR_GETIMAGE
1403   * 4 len of image
1404 */
1405 ULONG VDR::loadImage(const char* fileName, ULONG x, ULONG y)
1406 {
1407   unsigned long totalLength = 20 + strlen(fileName) + 1;
1408   UCHAR* buffer = new UCHAR[totalLength];
1409
1410   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1411   *(unsigned long*)&buffer[4] = htonl(VDR_GETIMAGE);
1412   *(unsigned long*)&buffer[8] = htonl(0);
1413   *(unsigned long*)&buffer[8] = htonl(x);
1414   *(unsigned long*)&buffer[8] = htonl(y);
1415   strcpy((char*)&buffer[12], fileName);
1416
1417   MUTEX_LOCK(&mutex);
1418   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1419
1420   unsigned int a = tcp->sendPacket(buffer, totalLength);
1421   delete []buffer;
1422
1423   if (a != totalLength)
1424   {
1425     disconnect();
1426     MUTEX_UNLOCK(&mutex);
1427     return 0;
1428   }
1429
1430   if (!getPacket())
1431   {
1432     MUTEX_UNLOCK(&mutex);
1433     return 0;
1434   }
1435   ULONG cmd=0;
1436   cmd=extractULONG();
1437   ULONG lengthBytes = extractULONG();
1438   freePacket();
1439   MUTEX_UNLOCK(&mutex);
1440
1441   Log::getInstance()->log("VDR", Log::DEBUG, "getImage %s: %lu", fileName,lengthBytes);
1442
1443   return lengthBytes;
1444 }
1445
1446 int VDR::deleteTimer(RecTimer* delTimer)
1447 {
1448   Log::getInstance()->log("VDR", Log::DEBUG, "Delete timer called");
1449   
1450   unsigned long totalLength = 28;
1451   UCHAR* buffer = new UCHAR[totalLength];
1452
1453   *(unsigned long*)&buffer[0] = htonl(totalLength - 4);
1454   *(unsigned long*)&buffer[4] = htonl(VDR_DELETETIMER);
1455   *(unsigned long*)&buffer[8] = htonl(delTimer->channelNumber);
1456   *(unsigned long*)&buffer[12] = htonl(delTimer->weekDays);
1457   *(unsigned long*)&buffer[16] = htonl(delTimer->day);
1458   *(unsigned long*)&buffer[20] = htonl(delTimer->startTime);
1459   *(unsigned long*)&buffer[24] = htonl(delTimer->stopTime);
1460    
1461
1462   MUTEX_LOCK(&mutex);
1463   if (!connected) { MUTEX_UNLOCK(&mutex); return 0; }
1464
1465   unsigned int a = tcp->sendPacket(buffer, totalLength);
1466   delete []buffer;
1467
1468   if (a != totalLength)
1469   {
1470     disconnect();
1471     MUTEX_UNLOCK(&mutex);
1472     return 0;
1473   }
1474
1475   if (!getPacket())
1476   {
1477     MUTEX_UNLOCK(&mutex);
1478     return 0;
1479   }
1480
1481   int toReturn = (int)extractULONG();
1482   freePacket();
1483   MUTEX_UNLOCK(&mutex);
1484
1485   return toReturn;
1486 }
1487