]> git.vomp.tv Git - vompserver.git/blob - mvpclient.c
Replacement transceiver and use of new thread class (from client!)
[vompserver.git] / mvpclient.c
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 "mvpclient.h"
22
23 MVPClient::MVPClient(int tsocket)
24  : tcp(tsocket)
25 {
26   lp = NULL;
27   rp = NULL;
28   recordingManager = NULL;
29   log = Log::getInstance();
30
31   // Get IP address of client for config module
32
33   char ipa[20];
34   struct sockaddr_in peer;
35   socklen_t salen = sizeof(struct sockaddr);
36   if(getpeername(tsocket, (struct sockaddr*)&peer, &salen) == 0)
37   {
38     strcpy(ipa, inet_ntoa(peer.sin_addr));
39   }
40   else
41   {
42     ipa[0] = '\0';
43     log->log("Client", Log::DEBUG, "Cannot get peer name!");
44   }
45
46   const char* configDir = cPlugin::ConfigDirectory();
47   if (!configDir)
48   {
49     log->log("Client", Log::DEBUG, "No config dir!");
50     return;
51   }
52
53   char configFileName[PATH_MAX];
54   snprintf(configFileName, PATH_MAX - strlen(configDir) - strlen(ipa) - 20, "%s/vomp-%s.conf", configDir, ipa);
55   config.init(configFileName);
56
57   log->log("Client", Log::DEBUG, "Config file name: %s", configFileName);
58
59 //  processGetChannelSchedule(NULL, 0);
60
61 //test();
62
63 }
64
65 MVPClient::~MVPClient()
66 {
67   log->log("Client", Log::DEBUG, "MVP client destructor");
68   if (lp)
69   {
70     delete lp;
71     lp = NULL;
72   }
73   else if (rp)
74   {
75     writeResumeData();
76
77     delete rp;
78     delete recordingManager;
79     rp = NULL;
80     recordingManager = NULL;
81   }
82
83   cleanConfig();
84 }
85
86 cChannel* MVPClient::channelFromNumber(unsigned long channelNumber)
87 {
88   cChannel* channel = NULL;
89
90   for (channel = Channels.First(); channel; channel = Channels.Next(channel))
91   {
92     if (!channel->GroupSep())
93     {
94       log->log("Client", Log::DEBUG, "Looking for channel %lu::: number: %i name: '%s'", channelNumber, channel->Number(), channel->Name());
95
96       if (channel->Number() == (int)channelNumber)
97       {
98         int vpid = channel->Vpid();
99 #if VDRVERSNUM < 10300
100         int apid1 = channel->Apid1();
101 #else
102         int apid1 = channel->Apid(0);
103 #endif
104         log->log("Client", Log::DEBUG, "Found channel number %lu, vpid = %i, apid1 = %i", channelNumber, vpid, apid1);
105         return channel;
106       }
107     }
108   }
109
110   if (!channel)
111   {
112     log->log("Client", Log::DEBUG, "Channel not found");
113   }
114
115   return channel;
116 }
117
118
119 void MVPClient::writeResumeData()
120 {
121   config.setValueLongLong("ResumeData", (char*)rp->getCurrentRecording()->FileName(), rp->getLastPosition());
122 }
123
124 void MVPClient::sendULONG(ULONG ul)
125 {
126   unsigned char sendBuffer[8];
127   *(unsigned long*)&sendBuffer[0] = htonl(4);
128   *(unsigned long*)&sendBuffer[4] = htonl(ul);
129
130   tcp.sendPacket(sendBuffer, 8);
131   log->log("Client", Log::DEBUG, "written ULONG %lu", ul);
132 }
133
134 void MVPClientStartThread(void* arg)
135 {
136   MVPClient* m = (MVPClient*)arg;
137   m->run2();
138   // Nothing external to this class has a reference to it
139   // This is the end of the thread.. so delete m
140   delete m;
141   pthread_exit(NULL);
142 }
143
144 int MVPClient::run()
145 {
146   if (pthread_create(&runThread, NULL, (void*(*)(void*))MVPClientStartThread, (void *)this) == -1) return 0;
147   log->log("Client", Log::DEBUG, "MVPClient run success");
148   return 1;
149 }
150
151 void MVPClient::run2()
152 {
153   // Thread stuff
154   sigset_t sigset;
155   sigfillset(&sigset);
156   pthread_sigmask(SIG_BLOCK, &sigset, NULL);
157   pthread_detach(runThread);  // Detach
158
159   tcp.disableReadTimeout();
160
161   tcp.setSoKeepTime(3);
162   tcp.setNonBlocking();
163
164   unsigned char* buffer;
165   unsigned char* data;
166   int packetLength;
167   unsigned long opcode;
168
169   while(1)
170   {
171     log->log("Client", Log::DEBUG, "Waiting");
172     buffer = (unsigned char*)tcp.receivePacket();
173     log->log("Client", Log::DEBUG, "Received packet, length = %u", tcp.getDataLength());
174     if (buffer == NULL)
175     {
176       log->log("Client", Log::DEBUG, "Detected connection closed");
177       break;
178     }
179
180     packetLength = tcp.getDataLength() - 4;
181     opcode = ntohl(*(unsigned long*)buffer);
182     data = buffer + 4;
183
184
185     switch(opcode)
186     {
187       case 1:
188         processLogin(data, packetLength);
189         break;
190       case 2:
191         processGetRecordingsList(data, packetLength);
192         break;
193       case 3:
194         processDeleteRecording(data, packetLength);
195         break;
196       case 4:
197         processGetSummary(data, packetLength);
198         break;
199       case 5:
200         processGetChannelsList(data, packetLength);
201         break;
202       case 6:
203         processStartStreamingChannel(data, packetLength);
204         break;
205       case 7:
206         processGetBlock(data, packetLength);
207         break;
208       case 8:
209         processStopStreaming(data, packetLength);
210         break;
211       case 9:
212         processStartStreamingRecording(data, packetLength);
213         break;
214       case 10:
215         processGetChannelSchedule(data, packetLength);
216         break;
217       case 11:
218         processConfigSave(data, packetLength);
219         break;
220       case 12:
221         processConfigLoad(data, packetLength);
222         break;
223     }
224
225     free(buffer);
226   }
227 }
228
229 void MVPClient::processLogin(unsigned char* buffer, int length)
230 {
231   time_t timeNow = time(NULL);
232   struct tm* timeStruct = localtime(&timeNow);
233   int timeOffset = timeStruct->tm_gmtoff;
234
235   unsigned char sendBuffer[12];
236   *(unsigned long*)&sendBuffer[0] = htonl(8);
237   *(unsigned long*)&sendBuffer[4] = htonl(timeNow);
238   *(signed int*)&sendBuffer[8] = htonl(timeOffset);
239
240   tcp.sendPacket(sendBuffer, 12);
241   log->log("Client", Log::DEBUG, "written login reply");
242 }
243
244 void MVPClient::processGetRecordingsList(unsigned char* data, int length)
245 {
246   unsigned char* sendBuffer = new unsigned char[50000]; // hope this is enough
247   int count = 4; // leave space for the packet length
248   char* point;
249
250
251   int FreeMB;
252   int Percent = VideoDiskSpace(&FreeMB);
253   int Total = (FreeMB / (100 - Percent)) * 100;
254
255   *(unsigned long*)&sendBuffer[count] = htonl(Total);
256   count += sizeof(unsigned long);
257   *(unsigned long*)&sendBuffer[count] = htonl(FreeMB);
258   count += sizeof(unsigned long);
259   *(unsigned long*)&sendBuffer[count] = htonl(Percent);
260   count += sizeof(unsigned long);
261
262
263   cRecordings Recordings;
264   Recordings.Load();
265
266   for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
267   {
268     if (count > 49000) break; // just how big is that hard disk?!
269     *(unsigned long*)&sendBuffer[count] = htonl(recording->start);// + timeOffset);
270     count += 4;
271
272     point = (char*)recording->Name();
273     strcpy((char*)&sendBuffer[count], point);
274     count += strlen(point) + 1;
275
276     point = (char*)recording->FileName();
277     strcpy((char*)&sendBuffer[count], point);
278     count += strlen(point) + 1;
279   }
280
281   *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
282
283   log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(unsigned long*)&sendBuffer[0]));
284
285   tcp.sendPacket(sendBuffer, count);
286   delete[] sendBuffer;
287   log->log("Client", Log::DEBUG, "Written list");
288 }
289
290 void MVPClient::processDeleteRecording(unsigned char* data, int length)
291 {
292   // data is a pointer to the fileName string
293
294   cRecordings Recordings;
295   Recordings.Load(); // probably have to do this
296
297   cRecording* recording = Recordings.GetByName((char*)data);
298
299   log->log("Client", Log::DEBUG, "recording pointer %p", recording);
300
301   if (recording)
302   {
303     log->log("Client", Log::DEBUG, "deleting recording: %s", recording->Name());
304     recording->Delete();
305     sendULONG(1);
306   }
307   else
308   {
309     sendULONG(0);
310   }
311 }
312
313 void MVPClient::processGetSummary(unsigned char* data, int length)
314 {
315   // data is a pointer to the fileName string
316
317   cRecordings Recordings;
318   Recordings.Load(); // probably have to do this
319
320   cRecording *recording = Recordings.GetByName((char*)data);
321
322   log->log("Client", Log::DEBUG, "recording pointer %p", recording);
323
324   if (recording)
325   {
326     unsigned char* sendBuffer = new unsigned char[50000]; // hope this is enough
327     int count = 4; // leave space for the packet length
328
329     char* point;
330 #if VDRVERSNUM < 10300
331     point = (char*)recording->Summary();
332 #else
333     const cRecordingInfo *Info = recording->Info();
334     point = (char*)Info->ShortText();
335     log->log("Client", Log::DEBUG, "info pointer %p summary pointer %p", Info, point);
336     if (isempty(point))
337     {
338       point = (char*)Info->Description();
339       log->log("Client", Log::DEBUG, "description pointer %p", point);
340     }
341 #endif
342     strcpy((char*)&sendBuffer[count], point);
343     count += strlen(point) + 1;
344     *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
345
346     log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(unsigned long*)&sendBuffer[0]));
347
348     tcp.sendPacket(sendBuffer, count);
349     delete[] sendBuffer;
350     log->log("Client", Log::DEBUG, "Written summary");
351
352
353   }
354   else
355   {
356     sendULONG(0);
357   }
358 }
359
360 void MVPClient::processGetChannelsList(unsigned char* data, int length)
361 {
362   unsigned char* sendBuffer = new unsigned char[50000]; // FIXME hope this is enough
363   int count = 4; // leave space for the packet length
364   char* point;
365   unsigned long type;
366
367   for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
368   {
369 #if VDRVERSNUM < 10300
370     if (!channel->GroupSep() && !channel->Ca())
371 #else
372     if (!channel->GroupSep() && !channel->Ca(0))
373 #endif
374     {
375       log->log("Client", Log::DEBUG, "name: '%s'", channel->Name());
376
377       if (channel->Vpid()) type = 1;
378 #if VDRVERSNUM < 10300
379       else type = 2;
380 #else
381       else if (channel->Apid(0)) type = 2;
382       else continue;
383 #endif
384
385       if (count > 49000) break;
386       *(unsigned long*)&sendBuffer[count] = htonl(channel->Number());
387       count += 4;
388
389       *(unsigned long*)&sendBuffer[count] = htonl(type);
390       count += 4;
391
392       point = (char*)channel->Name();
393       strcpy((char*)&sendBuffer[count], point);
394       count += strlen(point) + 1;
395     }
396   }
397
398   *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
399
400   log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(unsigned long*)&sendBuffer[0]));
401
402   tcp.sendPacket(sendBuffer, count);
403   delete[] sendBuffer;
404   log->log("Client", Log::DEBUG, "Written channels list");
405 }
406
407 void MVPClient::processStartStreamingChannel(unsigned char* data, int length)
408 {
409   log->log("Client", Log::DEBUG, "length = %i", length);
410   unsigned long channelNumber = ntohl(*(unsigned long*)data);
411
412   cChannel* channel = channelFromNumber(channelNumber);
413   if (!channel)
414   {
415     sendULONG(0);
416     return;
417   }
418
419   lp = MVPReceiver::create(channel);
420
421   if (!lp)
422   {
423     sendULONG(0);
424     return;
425   }
426
427   if (!lp->init())
428   {
429     delete lp;
430     lp = NULL;
431     sendULONG(0);
432     return;
433   }
434
435   sendULONG(1);
436 }
437
438 void MVPClient::processStopStreaming(unsigned char* data, int length)
439 {
440   log->log("Client", Log::DEBUG, "STOP STREAMING RECEIVED");
441   if (lp)
442   {
443     delete lp;
444     lp = NULL;
445   }
446   else if (rp)
447   {
448     writeResumeData();
449
450     delete rp;
451     delete recordingManager;
452     rp = NULL;
453     recordingManager = NULL;
454   }
455
456   sendULONG(1);
457 }
458
459 void MVPClient::processGetBlock(unsigned char* data, int length)
460 {
461   if (!lp && !rp)
462   {
463     log->log("Client", Log::DEBUG, "Get block called when no streaming happening!");
464     return;
465   }
466
467   ULLONG position = ntohll(*(ULLONG*)data);
468   data += sizeof(ULLONG);
469   unsigned long amount = ntohl(*(unsigned long*)data);
470
471   log->log("Client", Log::DEBUG, "getblock pos = %llu length = %lu", position, amount);
472
473   unsigned char sendBuffer[amount + 4];
474   unsigned long amountReceived = 0; // compiler moan.
475   if (lp)
476   {
477     log->log("Client", Log::DEBUG, "getting from live");
478     amountReceived = lp->getBlock(&sendBuffer[4], amount);
479
480     if (!amountReceived)
481     {
482       // vdr has possibly disconnected the receiver
483       log->log("Client", Log::DEBUG, "VDR has disconnected the live receiver");
484       delete lp;
485       lp = NULL;
486     }
487   }
488   else if (rp)
489   {
490     log->log("Client", Log::DEBUG, "getting from recording");
491     amountReceived = rp->getBlock(&sendBuffer[4], position, amount);
492   }
493
494   *(unsigned long*)&sendBuffer[0] = htonl(amountReceived);
495   tcp.sendPacket(sendBuffer, amountReceived + 4);
496   log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
497 }
498
499 void MVPClient::processStartStreamingRecording(unsigned char* data, int length)
500 {
501   // data is a pointer to the fileName string
502
503   recordingManager = new cRecordings;
504   recordingManager->Load();
505
506   cRecording* recording = recordingManager->GetByName((char*)data);
507
508   log->log("Client", Log::DEBUG, "recording pointer %p", recording);
509
510   if (recording)
511   {
512     rp = new RecPlayer(recording);
513
514     unsigned char sendBuffer[12];
515     *(unsigned long*)&sendBuffer[0] = htonl(8);
516     *(ULLONG*)&sendBuffer[4] = htonll(rp->getTotalLength());
517
518     tcp.sendPacket(sendBuffer, 12);
519     log->log("Client", Log::DEBUG, "written totalLength");
520   }
521   else
522   {
523     delete recordingManager;
524     recordingManager = NULL;
525   }
526 }
527
528 void MVPClient::processGetChannelSchedule(unsigned char* data, int length)
529 {
530   ULONG channelNumber = ntohl(*(ULLONG*)data);
531   log->log("Client", Log::DEBUG, "get schedule called for channel %lu", channelNumber);
532
533   cChannel* channel = channelFromNumber(channelNumber);
534   if (!channel)
535   {
536     unsigned char sendBuffer[4];
537     *(unsigned long*)&sendBuffer[0] = htonl(0);
538     tcp.sendPacket(sendBuffer, 4);
539     log->log("Client", Log::DEBUG, "written null");
540     return;
541   }
542
543 #if VDRVERSNUM < 10300
544   cMutexLock MutexLock;
545   const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
546 #else
547   cSchedulesLock MutexLock;
548   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
549 #endif
550   if (!Schedules)
551   {
552     unsigned char sendBuffer[8];
553     *(unsigned long*)&sendBuffer[0] = htonl(4);
554     *(unsigned long*)&sendBuffer[4] = htonl(0);
555     tcp.sendPacket(sendBuffer, 8);
556     log->log("Client", Log::DEBUG, "written 0");
557     return;
558   }
559
560   unsigned char sendBuffer[8];
561   *(unsigned long*)&sendBuffer[0] = htonl(4);
562   *(unsigned long*)&sendBuffer[4] = htonl(1);
563   tcp.sendPacket(sendBuffer, 8);
564   log->log("Client", Log::DEBUG, "written 1");
565
566
567 }
568
569 void MVPClient::testChannelSchedule(unsigned char* data, int length)
570 {
571   FILE* f = fopen("/tmp/s.txt", "w");
572
573 #if VDRVERSNUM < 10300
574   cMutexLock MutexLock;
575   const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
576 #else
577   cSchedulesLock MutexLock;
578   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
579 #endif
580   if (!Schedules)
581   {
582     fprintf(f, "Schedules = NULL\n");
583     fclose(f);
584     return;
585   }
586
587   fprintf(f, "Schedules dump:\n");
588   Schedules->Dump(f);
589
590
591   const cSchedule *Schedule;
592   int scheduleNumber = 0;
593
594   tChannelID tchid;
595   cChannel *thisChannel;
596
597 #if VDRVERSNUM < 10300
598   const cEventInfo *event;
599   int eventNumber = 0;
600 #else
601   const cEvent *event;
602 #endif
603
604 //    Schedule = Schedules->GetSchedule(channel->GetChannelID());
605 //    Schedule = Schedules->GetSchedule();
606   Schedule = Schedules->First();
607   if (!Schedule)
608   {
609     fprintf(f, "First Schedule = NULL\n");
610     fclose(f);
611     return;
612   }
613
614   while (Schedule)
615   {
616     fprintf(f, "Schedule #%i\n", scheduleNumber);
617     fprintf(f, "-------------\n\n");
618
619 #if VDRVERSNUM < 10300
620     tchid = Schedule->GetChannelID();
621 #else
622     tchid = Schedule->ChannelID();
623 #endif
624 #if VDRVERSNUM < 10300
625     fprintf(f, "ChannelID.ToString() = %s\n", tchid.ToString());
626     fprintf(f, "NumEvents() = %i\n", Schedule->NumEvents());
627 #else
628 //  put the count at the end.
629 #endif
630     thisChannel = Channels.GetByChannelID(tchid, true);
631     if (thisChannel)
632     {
633       fprintf(f, "Channel Number: %p %i\n", thisChannel, thisChannel->Number());
634     }
635     else
636     {
637       fprintf(f, "thisChannel = NULL for tchid\n");
638     }
639
640 #if VDRVERSNUM < 10300
641     for (eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
642     {
643       event = Schedule->GetEventNumber(eventNumber);
644       fprintf(f, "Event %i tableid = %i timestring = %s endtimestring = %s\n", eventNumber, event->GetTableID(), event->GetTimeString(), event->GetEndTimeString());
645       fprintf(f, "Event %i date = %s isfollowing = %i ispresent = %i\n", eventNumber, event->GetDate(), event->IsFollowing(), event->IsPresent());
646       fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
647       fprintf(f, "Event %i subtitle = %s title = %s\n", eventNumber, event->GetSubtitle(), event->GetTitle());
648       fprintf(f, "Event %i eventid = %u duration = %li time = %lu channelnumber = %i\n", eventNumber, event->GetEventID(), event->GetDuration(), event->GetTime(), event->GetChannelNumber());
649       fprintf(f, "Event %u dump:\n", eventNumber);
650       event->Dump(f);
651       fprintf(f, "\n\n");
652     }
653 #else
654 //  This whole section needs rewriting to walk the list.
655     event = Schedule->Events()->First();
656     while (event) {
657       event = Schedule->Events()->Next(event);
658     }
659 #endif
660
661
662     fprintf(f, "\nDump from object:\n");
663     Schedule->Dump(f);
664     fprintf(f, "\nEND\n");
665
666
667
668
669 /*
670   const cEventInfo *GetPresentEvent(void) const;
671   const cEventInfo *GetFollowingEvent(void) const;
672   const cEventInfo *GetEvent(unsigned short uEventID, time_t tTime = 0) const;
673   const cEventInfo *GetEventAround(time_t tTime) const;
674   const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); }
675
676
677   const unsigned char GetTableID(void) const;
678   const char *GetTimeString(void) const;
679   const char *GetEndTimeString(void) const;
680   const char *GetDate(void) const;
681   bool IsFollowing(void) const;
682   bool IsPresent(void) const;
683   const char *GetExtendedDescription(void) const;
684   const char *GetSubtitle(void) const;
685   const char *GetTitle(void) const;
686   unsigned short GetEventID(void) const;
687   long GetDuration(void) const;
688   time_t GetTime(void) const;
689   tChannelID GetChannelID(void) const;
690   int GetChannelNumber(void) const { return nChannelNumber; }
691   void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const'
692   void Dump(FILE *f, const char *Prefix = "") const;
693
694 */
695
696
697
698
699
700     fprintf(f, "End of current Schedule\n\n\n");
701
702     Schedule = (const cSchedule *)Schedules->Next(Schedule);
703     scheduleNumber++;
704   }
705
706   fclose(f);
707 }
708
709 void MVPClient::processConfigSave(unsigned char* buffer, int length)
710 {
711   char* section = (char*)buffer;
712   char* key = NULL;
713   char* value = NULL;
714
715   for (int k = 0; k < length; k++)
716   {
717     if (buffer[k] == '\0')
718     {
719       if (!key)
720       {
721         key = (char*)&buffer[k+1];
722       }
723       else
724       {
725         value = (char*)&buffer[k+1];
726         break;
727       }
728     }
729   }
730
731   // if the last string (value) doesnt have null terminator, give up
732   if (buffer[length - 1] != '\0') return;
733
734   log->log("Client", Log::DEBUG, "Config save: %s %s %s", section, key, value);
735   if (config.setValueString(section, key, value))
736   {
737     sendULONG(1);
738   }
739   else
740   {
741     sendULONG(0);
742   }
743 }
744
745 void MVPClient::processConfigLoad(unsigned char* buffer, int length)
746 {
747   char* section = (char*)buffer;
748   char* key = NULL;
749
750   for (int k = 0; k < length; k++)
751   {
752     if (buffer[k] == '\0')
753     {
754       key = (char*)&buffer[k+1];
755       break;
756     }
757   }
758
759   char* value = config.getValueString(section, key);
760
761   if (value)
762   {
763     unsigned char sendBuffer[4 + strlen(value) + 1];
764     *(unsigned long*)&sendBuffer[0] = htonl(strlen(value) + 1);
765     strcpy((char*)&sendBuffer[4], value);
766     tcp.sendPacket(sendBuffer, 4 + strlen(value) + 1);
767
768     log->log("Client", Log::DEBUG, "Written config load packet");
769     delete[] value;
770   }
771   else
772   {
773     unsigned char sendBuffer[8];
774     *(unsigned long*)&sendBuffer[0] = htonl(4);
775     *(unsigned long*)&sendBuffer[4] = htonl(0);
776     tcp.sendPacket(sendBuffer, 8);
777
778     log->log("Client", Log::DEBUG, "Written config load failed packet");
779   }
780 }
781
782 void MVPClient::cleanConfig()
783 {
784   log->log("Client", Log::DEBUG, "Clean config");
785
786   cRecordings Recordings;
787   Recordings.Load();
788
789   int numReturns;
790   int length;
791   char* resumes = config.getSectionKeyNames("ResumeData", numReturns, length);
792   char* position = resumes;
793   for(int k = 0; k < numReturns; k++)
794   {
795     log->log("Client", Log::DEBUG, "EXAMINING: %i %i %p %s", k, numReturns, position, position);
796
797     cRecording* recording = Recordings.GetByName(position);
798     if (!recording)
799     {
800       // doesn't exist anymore
801       log->log("Client", Log::DEBUG, "Found a recording that doesn't exist anymore");
802       config.deleteValue("ResumeData", position);
803     }
804     else
805     {
806       log->log("Client", Log::DEBUG, "This recording still exists");
807     }
808
809     position += strlen(position) + 1;
810   }
811
812   delete[] resumes;
813 }
814
815