]> git.vomp.tv Git - vompserver.git/blob - mvpclient.c
Turn logging off again.
[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       case 13:
224         processReScanRecording(data, packetLength);
225         break;
226     }
227
228     free(buffer);
229   }
230 }
231
232 void MVPClient::processLogin(unsigned char* buffer, int length)
233 {
234   time_t timeNow = time(NULL);
235   struct tm* timeStruct = localtime(&timeNow);
236   int timeOffset = timeStruct->tm_gmtoff;
237
238   unsigned char sendBuffer[12];
239   *(unsigned long*)&sendBuffer[0] = htonl(8);
240   *(unsigned long*)&sendBuffer[4] = htonl(timeNow);
241   *(signed int*)&sendBuffer[8] = htonl(timeOffset);
242
243   tcp.sendPacket(sendBuffer, 12);
244   log->log("Client", Log::DEBUG, "written login reply");
245 }
246
247 void MVPClient::processGetRecordingsList(unsigned char* data, int length)
248 {
249   unsigned char* sendBuffer = new unsigned char[50000]; // hope this is enough
250   int count = 4; // leave space for the packet length
251   char* point;
252
253
254   int FreeMB;
255   int Percent = VideoDiskSpace(&FreeMB);
256   int Total = (FreeMB / (100 - Percent)) * 100;
257
258   *(unsigned long*)&sendBuffer[count] = htonl(Total);
259   count += sizeof(unsigned long);
260   *(unsigned long*)&sendBuffer[count] = htonl(FreeMB);
261   count += sizeof(unsigned long);
262   *(unsigned long*)&sendBuffer[count] = htonl(Percent);
263   count += sizeof(unsigned long);
264
265
266   cRecordings Recordings;
267   Recordings.Load();
268
269   for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
270   {
271     if (count > 49000) break; // just how big is that hard disk?!
272     *(unsigned long*)&sendBuffer[count] = htonl(recording->start);// + timeOffset);
273     count += 4;
274
275     point = (char*)recording->Name();
276     strcpy((char*)&sendBuffer[count], point);
277     count += strlen(point) + 1;
278
279     point = (char*)recording->FileName();
280     strcpy((char*)&sendBuffer[count], point);
281     count += strlen(point) + 1;
282   }
283
284   *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
285
286   log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(unsigned long*)&sendBuffer[0]));
287
288   tcp.sendPacket(sendBuffer, count);
289   delete[] sendBuffer;
290   log->log("Client", Log::DEBUG, "Written list");
291 }
292
293 void MVPClient::processDeleteRecording(unsigned char* data, int length)
294 {
295   // data is a pointer to the fileName string
296
297   cRecordings Recordings;
298   Recordings.Load(); // probably have to do this
299
300   cRecording* recording = Recordings.GetByName((char*)data);
301
302   log->log("Client", Log::DEBUG, "recording pointer %p", recording);
303
304   if (recording)
305   {
306     log->log("Client", Log::DEBUG, "deleting recording: %s", recording->Name());
307     recording->Delete();
308     sendULONG(1);
309   }
310   else
311   {
312     sendULONG(0);
313   }
314 }
315
316 void MVPClient::processGetSummary(unsigned char* data, int length)
317 {
318   // data is a pointer to the fileName string
319
320   cRecordings Recordings;
321   Recordings.Load(); // probably have to do this
322
323   cRecording *recording = Recordings.GetByName((char*)data);
324
325   log->log("Client", Log::DEBUG, "recording pointer %p", recording);
326
327   if (recording)
328   {
329     unsigned char* sendBuffer = new unsigned char[50000]; // hope this is enough
330     int count = 4; // leave space for the packet length
331
332     char* point;
333 #if VDRVERSNUM < 10300
334     point = (char*)recording->Summary();
335 #else
336     const cRecordingInfo *Info = recording->Info();
337     point = (char*)Info->ShortText();
338     log->log("Client", Log::DEBUG, "info pointer %p summary pointer %p", Info, point);
339     if (isempty(point))
340     {
341       point = (char*)Info->Description();
342       log->log("Client", Log::DEBUG, "description pointer %p", point);
343     }
344 #endif
345     strcpy((char*)&sendBuffer[count], point);
346     count += strlen(point) + 1;
347     *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
348
349     log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(unsigned long*)&sendBuffer[0]));
350
351     tcp.sendPacket(sendBuffer, count);
352     delete[] sendBuffer;
353     log->log("Client", Log::DEBUG, "Written summary");
354
355
356   }
357   else
358   {
359     sendULONG(0);
360   }
361 }
362
363 void MVPClient::processGetChannelsList(unsigned char* data, int length)
364 {
365   unsigned char* sendBuffer = new unsigned char[50000]; // FIXME hope this is enough
366   int count = 4; // leave space for the packet length
367   char* point;
368   unsigned long type;
369
370   for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
371   {
372
373 // Re-enable later with some client side option
374 //#if VDRVERSNUM < 10300
375 //    if (!channel->GroupSep() && !channel->Ca())
376 //#else
377 //    if (!channel->GroupSep() && !channel->Ca(0))
378 //#endif
379 //    {
380
381     if (!channel->GroupSep())
382     {
383       log->log("Client", Log::DEBUG, "name: '%s'", channel->Name());
384
385       if (channel->Vpid()) type = 1;
386 #if VDRVERSNUM < 10300
387       else type = 2;
388 #else
389       else if (channel->Apid(0)) type = 2;
390       else continue;
391 #endif
392
393       if (count > 49000) break;
394       *(unsigned long*)&sendBuffer[count] = htonl(channel->Number());
395       count += 4;
396
397       *(unsigned long*)&sendBuffer[count] = htonl(type);
398       count += 4;
399
400       point = (char*)channel->Name();
401       strcpy((char*)&sendBuffer[count], point);
402       count += strlen(point) + 1;
403     }
404   }
405
406   *(unsigned long*)&sendBuffer[0] = htonl(count - 4); // -4 :  take off the size field
407
408   log->log("Client", Log::DEBUG, "recorded size as %u", ntohl(*(unsigned long*)&sendBuffer[0]));
409
410   tcp.sendPacket(sendBuffer, count);
411   delete[] sendBuffer;
412   log->log("Client", Log::DEBUG, "Written channels list");
413 }
414
415 void MVPClient::processStartStreamingChannel(unsigned char* data, int length)
416 {
417   log->log("Client", Log::DEBUG, "length = %i", length);
418   unsigned long channelNumber = ntohl(*(unsigned long*)data);
419
420   cChannel* channel = channelFromNumber(channelNumber);
421   if (!channel)
422   {
423     sendULONG(0);
424     return;
425   }
426
427   lp = MVPReceiver::create(channel);
428
429   if (!lp)
430   {
431     sendULONG(0);
432     return;
433   }
434
435   if (!lp->init())
436   {
437     delete lp;
438     lp = NULL;
439     sendULONG(0);
440     return;
441   }
442
443   sendULONG(1);
444 }
445
446 void MVPClient::processStopStreaming(unsigned char* data, int length)
447 {
448   log->log("Client", Log::DEBUG, "STOP STREAMING RECEIVED");
449   if (lp)
450   {
451     delete lp;
452     lp = NULL;
453   }
454   else if (rp)
455   {
456     writeResumeData();
457
458     delete rp;
459     delete recordingManager;
460     rp = NULL;
461     recordingManager = NULL;
462   }
463
464   sendULONG(1);
465 }
466
467 void MVPClient::processGetBlock(unsigned char* data, int length)
468 {
469   if (!lp && !rp)
470   {
471     log->log("Client", Log::DEBUG, "Get block called when no streaming happening!");
472     return;
473   }
474
475   ULLONG position = ntohll(*(ULLONG*)data);
476   data += sizeof(ULLONG);
477   unsigned long amount = ntohl(*(unsigned long*)data);
478
479   log->log("Client", Log::DEBUG, "getblock pos = %llu length = %lu", position, amount);
480
481   unsigned char sendBuffer[amount + 4];
482   unsigned long amountReceived = 0; // compiler moan.
483   if (lp)
484   {
485     log->log("Client", Log::DEBUG, "getting from live");
486     amountReceived = lp->getBlock(&sendBuffer[4], amount);
487
488     if (!amountReceived)
489     {
490       // vdr has possibly disconnected the receiver
491       log->log("Client", Log::DEBUG, "VDR has disconnected the live receiver");
492       delete lp;
493       lp = NULL;
494     }
495   }
496   else if (rp)
497   {
498     log->log("Client", Log::DEBUG, "getting from recording");
499     amountReceived = rp->getBlock(&sendBuffer[4], position, amount);
500   }
501
502   *(unsigned long*)&sendBuffer[0] = htonl(amountReceived);
503   tcp.sendPacket(sendBuffer, amountReceived + 4);
504   log->log("Client", Log::DEBUG, "written ok %lu", amountReceived);
505 }
506
507 void MVPClient::processStartStreamingRecording(unsigned char* data, int length)
508 {
509   // data is a pointer to the fileName string
510
511   recordingManager = new cRecordings;
512   recordingManager->Load();
513
514   cRecording* recording = recordingManager->GetByName((char*)data);
515
516   log->log("Client", Log::DEBUG, "recording pointer %p", recording);
517
518   if (recording)
519   {
520     rp = new RecPlayer(recording);
521
522     unsigned char sendBuffer[12];
523     *(unsigned long*)&sendBuffer[0] = htonl(8);
524     *(ULLONG*)&sendBuffer[4] = htonll(rp->getTotalLength());
525
526     tcp.sendPacket(sendBuffer, 12);
527     log->log("Client", Log::DEBUG, "written totalLength");
528   }
529   else
530   {
531     delete recordingManager;
532     recordingManager = NULL;
533   }
534 }
535
536 void MVPClient::processReScanRecording(unsigned char* data, int length)
537 {
538   ULLONG retval = 0;
539
540   if (!rp)
541   {
542     log->log("Client", Log::DEBUG, "Rescan recording called when no recording being played!");
543   }
544   else
545   {
546     rp->scan();
547     retval = rp->getTotalLength();
548   }
549
550   unsigned char sendBuffer[12];
551   *(unsigned long*)&sendBuffer[0] = htonl(8);
552   *(ULLONG*)&sendBuffer[4] = htonll(retval);
553
554   tcp.sendPacket(sendBuffer, 12);
555   log->log("Client", Log::DEBUG, "Rescan recording, wrote new length to client");
556 }
557
558 void MVPClient::processGetChannelSchedule(unsigned char* data, int length)
559 {
560   ULONG channelNumber = ntohl(*(ULLONG*)data);
561   log->log("Client", Log::DEBUG, "get schedule called for channel %lu", channelNumber);
562
563   cChannel* channel = channelFromNumber(channelNumber);
564   if (!channel)
565   {
566     unsigned char sendBuffer[4];
567     *(unsigned long*)&sendBuffer[0] = htonl(0);
568     tcp.sendPacket(sendBuffer, 4);
569     log->log("Client", Log::DEBUG, "written null");
570     return;
571   }
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     unsigned char sendBuffer[8];
583     *(unsigned long*)&sendBuffer[0] = htonl(4);
584     *(unsigned long*)&sendBuffer[4] = htonl(0);
585     tcp.sendPacket(sendBuffer, 8);
586     log->log("Client", Log::DEBUG, "written 0");
587     return;
588   }
589
590   unsigned char sendBuffer[8];
591   *(unsigned long*)&sendBuffer[0] = htonl(4);
592   *(unsigned long*)&sendBuffer[4] = htonl(1);
593   tcp.sendPacket(sendBuffer, 8);
594   log->log("Client", Log::DEBUG, "written 1");
595
596
597 }
598
599 void MVPClient::testChannelSchedule(unsigned char* data, int length)
600 {
601   FILE* f = fopen("/tmp/s.txt", "w");
602
603 #if VDRVERSNUM < 10300
604   cMutexLock MutexLock;
605   const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
606 #else
607   cSchedulesLock MutexLock;
608   const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
609 #endif
610   if (!Schedules)
611   {
612     fprintf(f, "Schedules = NULL\n");
613     fclose(f);
614     return;
615   }
616
617   fprintf(f, "Schedules dump:\n");
618   Schedules->Dump(f);
619
620
621   const cSchedule *Schedule;
622   int scheduleNumber = 0;
623
624   tChannelID tchid;
625   cChannel *thisChannel;
626
627 #if VDRVERSNUM < 10300
628   const cEventInfo *event;
629   int eventNumber = 0;
630 #else
631   const cEvent *event;
632 #endif
633
634 //    Schedule = Schedules->GetSchedule(channel->GetChannelID());
635 //    Schedule = Schedules->GetSchedule();
636   Schedule = Schedules->First();
637   if (!Schedule)
638   {
639     fprintf(f, "First Schedule = NULL\n");
640     fclose(f);
641     return;
642   }
643
644   while (Schedule)
645   {
646     fprintf(f, "Schedule #%i\n", scheduleNumber);
647     fprintf(f, "-------------\n\n");
648
649 #if VDRVERSNUM < 10300
650     tchid = Schedule->GetChannelID();
651 #else
652     tchid = Schedule->ChannelID();
653 #endif
654 #if VDRVERSNUM < 10300
655     fprintf(f, "ChannelID.ToString() = %s\n", tchid.ToString());
656     fprintf(f, "NumEvents() = %i\n", Schedule->NumEvents());
657 #else
658 //  put the count at the end.
659 #endif
660     thisChannel = Channels.GetByChannelID(tchid, true);
661     if (thisChannel)
662     {
663       fprintf(f, "Channel Number: %p %i\n", thisChannel, thisChannel->Number());
664     }
665     else
666     {
667       fprintf(f, "thisChannel = NULL for tchid\n");
668     }
669
670 #if VDRVERSNUM < 10300
671     for (eventNumber = 0; eventNumber < Schedule->NumEvents(); eventNumber++)
672     {
673       event = Schedule->GetEventNumber(eventNumber);
674       fprintf(f, "Event %i tableid = %i timestring = %s endtimestring = %s\n", eventNumber, event->GetTableID(), event->GetTimeString(), event->GetEndTimeString());
675       fprintf(f, "Event %i date = %s isfollowing = %i ispresent = %i\n", eventNumber, event->GetDate(), event->IsFollowing(), event->IsPresent());
676       fprintf(f, "Event %i extendeddescription = %s\n", eventNumber, event->GetExtendedDescription());
677       fprintf(f, "Event %i subtitle = %s title = %s\n", eventNumber, event->GetSubtitle(), event->GetTitle());
678       fprintf(f, "Event %i eventid = %u duration = %li time = %lu channelnumber = %i\n", eventNumber, event->GetEventID(), event->GetDuration(), event->GetTime(), event->GetChannelNumber());
679       fprintf(f, "Event %u dump:\n", eventNumber);
680       event->Dump(f);
681       fprintf(f, "\n\n");
682     }
683 #else
684 //  This whole section needs rewriting to walk the list.
685     event = Schedule->Events()->First();
686     while (event) {
687       event = Schedule->Events()->Next(event);
688     }
689 #endif
690
691
692     fprintf(f, "\nDump from object:\n");
693     Schedule->Dump(f);
694     fprintf(f, "\nEND\n");
695
696
697
698
699 /*
700   const cEventInfo *GetPresentEvent(void) const;
701   const cEventInfo *GetFollowingEvent(void) const;
702   const cEventInfo *GetEvent(unsigned short uEventID, time_t tTime = 0) const;
703   const cEventInfo *GetEventAround(time_t tTime) const;
704   const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); }
705
706
707   const unsigned char GetTableID(void) const;
708   const char *GetTimeString(void) const;
709   const char *GetEndTimeString(void) const;
710   const char *GetDate(void) const;
711   bool IsFollowing(void) const;
712   bool IsPresent(void) const;
713   const char *GetExtendedDescription(void) const;
714   const char *GetSubtitle(void) const;
715   const char *GetTitle(void) const;
716   unsigned short GetEventID(void) const;
717   long GetDuration(void) const;
718   time_t GetTime(void) const;
719   tChannelID GetChannelID(void) const;
720   int GetChannelNumber(void) const { return nChannelNumber; }
721   void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const'
722   void Dump(FILE *f, const char *Prefix = "") const;
723
724 */
725
726
727
728
729
730     fprintf(f, "End of current Schedule\n\n\n");
731
732     Schedule = (const cSchedule *)Schedules->Next(Schedule);
733     scheduleNumber++;
734   }
735
736   fclose(f);
737 }
738
739 void MVPClient::processConfigSave(unsigned char* buffer, int length)
740 {
741   char* section = (char*)buffer;
742   char* key = NULL;
743   char* value = NULL;
744
745   for (int k = 0; k < length; k++)
746   {
747     if (buffer[k] == '\0')
748     {
749       if (!key)
750       {
751         key = (char*)&buffer[k+1];
752       }
753       else
754       {
755         value = (char*)&buffer[k+1];
756         break;
757       }
758     }
759   }
760
761   // if the last string (value) doesnt have null terminator, give up
762   if (buffer[length - 1] != '\0') return;
763
764   log->log("Client", Log::DEBUG, "Config save: %s %s %s", section, key, value);
765   if (config.setValueString(section, key, value))
766   {
767     sendULONG(1);
768   }
769   else
770   {
771     sendULONG(0);
772   }
773 }
774
775 void MVPClient::processConfigLoad(unsigned char* buffer, int length)
776 {
777   char* section = (char*)buffer;
778   char* key = NULL;
779
780   for (int k = 0; k < length; k++)
781   {
782     if (buffer[k] == '\0')
783     {
784       key = (char*)&buffer[k+1];
785       break;
786     }
787   }
788
789   char* value = config.getValueString(section, key);
790
791   if (value)
792   {
793     unsigned char sendBuffer[4 + strlen(value) + 1];
794     *(unsigned long*)&sendBuffer[0] = htonl(strlen(value) + 1);
795     strcpy((char*)&sendBuffer[4], value);
796     tcp.sendPacket(sendBuffer, 4 + strlen(value) + 1);
797
798     log->log("Client", Log::DEBUG, "Written config load packet");
799     delete[] value;
800   }
801   else
802   {
803     unsigned char sendBuffer[8];
804     *(unsigned long*)&sendBuffer[0] = htonl(4);
805     *(unsigned long*)&sendBuffer[4] = htonl(0);
806     tcp.sendPacket(sendBuffer, 8);
807
808     log->log("Client", Log::DEBUG, "Written config load failed packet");
809   }
810 }
811
812 void MVPClient::cleanConfig()
813 {
814   log->log("Client", Log::DEBUG, "Clean config");
815
816   cRecordings Recordings;
817   Recordings.Load();
818
819   int numReturns;
820   int length;
821   char* resumes = config.getSectionKeyNames("ResumeData", numReturns, length);
822   char* position = resumes;
823   for(int k = 0; k < numReturns; k++)
824   {
825     log->log("Client", Log::DEBUG, "EXAMINING: %i %i %p %s", k, numReturns, position, position);
826
827     cRecording* recording = Recordings.GetByName(position);
828     if (!recording)
829     {
830       // doesn't exist anymore
831       log->log("Client", Log::DEBUG, "Found a recording that doesn't exist anymore");
832       config.deleteValue("ResumeData", position);
833     }
834     else
835     {
836       log->log("Client", Log::DEBUG, "This recording still exists");
837     }
838
839     position += strlen(position) + 1;
840   }
841
842   delete[] resumes;
843 }
844
845