]> git.vomp.tv Git - vompclient.git/blob - command.cc
Fix text corruption in channel number display on live tv
[vompclient.git] / command.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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #ifndef WIN32
22 #include <errno.h>
23 #endif
24
25 #include "command.h"
26
27 #ifdef WIN32
28 #include "remotewin.h"
29 #endif
30
31 #ifdef __ANDROID__
32 #include "remoteandroid.h"
33 #endif
34
35 #include "led.h"
36 #include "video.h"
37 #include "audio.h"
38 #include "mtd.h"
39 #include "vdr.h"
40 #include "vvolume.h"
41 #include "vserverselect.h"
42 #include "vwelcome.h"
43 #include "vmute.h"
44 #include "colour.h"
45 #include "osd.h"
46 #include "i18n.h"
47 #include "timerreceiver.h"
48 #include "timers.h"
49 #include "wol.h"
50 #include "vconnect.h"
51 #include "message.h"
52 #include "remote.h"
53 #include "vinfo.h"
54 #include "boxx.h"
55 #include "boxstack.h"
56 #include "log.h"
57 #include "vsleeptimer.h"
58 #include "wjpeg.h"
59 #include "osdvector.h"
60
61
62 Command* Command::instance = NULL;
63
64 Command::Command()
65 {
66   if (instance) return;
67   instance = this;
68   initted = 0;
69   isStandby = 0;
70   firstBoot = 1;
71   signals = 0;
72   connLost = NULL;
73   crashed = false;
74   server = NULL;
75   wallpaper = wallpaper_pict = NULL;
76 }
77
78 Command::~Command()
79 {
80   instance = NULL;
81 }
82
83 Command* Command::getInstance()
84 {
85   return instance;
86 }
87
88 int Command::init(bool tcrashed, char* tServer)
89 {
90   if (initted) return 0;
91   initted = 1;
92   crashed = tcrashed;
93   server = tServer;
94
95   logger = Log::getInstance();
96   boxstack = BoxStack::getInstance();
97   remote = Remote::getInstance();
98   
99   remote->InitHWCListwithDefaults();
100   
101   if (!logger || !boxstack || !remote)
102   {
103     initted = 0;
104     return 0;
105   }
106
107   SkinFactory::InitSkin(0);
108
109 #ifndef WIN32
110   pthread_mutex_init(&masterLock, NULL);
111 #else
112   masterLock=CreateMutex(NULL,FALSE,NULL);
113 #endif
114
115   return 1;
116 }
117
118 int Command::shutdown()
119 {
120   if (!initted) return 0;
121   initted = 0;
122   return 1;
123 }
124
125 void Command::stop()
126 {
127 //  VDR::getInstance()->cancelFindingServer();
128         logger->log("Command", Log::NOTICE, "Command stop1...");
129         
130   udp.shutdown();
131   logger->log("Command", Log::NOTICE,  "Command stop2...");
132   irun = 0;
133 }
134
135 void Command::doWallpaper()
136 {
137         Video* video = Video::getInstance();
138
139         // Blue background
140         Boxx* bbg = new Boxx();
141         bbg->setSize(video->getScreenWidth(), video->getScreenHeight());
142         bbg->createBuffer();
143         bbg->fillColour(DrawStyle::WALLPAPER);
144         boxstack->add(bbg);
145         boxstack->update(bbg);
146         boxstack->remove(bbg);
147
148         // Wallpaper
149         wallpaper = new Boxx();
150         wallpaper->setSize(video->getScreenWidth(), video->getScreenHeight());
151         wallpaper->createBuffer();
152         wallpaper ->setBackgroundColour(DrawStyle::WALLPAPER);
153
154
155
156
157         wallpaper_pict = new WJpegTYPE();
158         wallpaper_pict->setSize(video->getScreenWidth(), video->getScreenHeight());
159
160
161         if (video->getFormat() == Video::PAL)
162         {
163                 logger->log("Command", Log::DEBUG, "PAL wallpaper selected");
164 #ifndef _MIPS_ARCH    
165                 wallpaper_pict->init("/wallpaperPAL.jpg");
166 #else
167                 wallpaper_pict->init("wallpaperPAL.jpg");
168 #endif
169         }
170         else
171         {
172                 logger->log("Command", Log::DEBUG, "NTSC wallpaper selected");
173                 wallpaper_pict->init("/wallpaperNTSC.jpg");
174         }
175         if (DrawStyle::WALLPAPER.alpha) {
176                 wallpaper_pict->setVisible(true);
177         } else {
178                 wallpaper_pict->setVisible(false);
179         }
180         wallpaper->add(wallpaper_pict);
181         wallpaper->draw();
182
183         boxstack->add(wallpaper);
184         boxstack->update(wallpaper);
185
186     OsdVector* osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
187     if (osdv)
188     {
189           osdv->updateBackgroundColor(DrawStyle::WALLPAPER);
190     }
191
192
193
194 }
195
196 void Command::run()
197 {
198   if (!initted) return;
199   irun = 1;
200 #ifndef WIN32
201   mainPid = getpid();
202 #endif
203
204   // just in case
205   Video::getInstance()->signalOn();
206   Led::getInstance()->on();
207
208   doWallpaper();
209
210   // End of startup. Lock the mutex and put the first view up
211 //  logger->log("Command", Log::DEBUG, "WANT LOCK");
212 #ifndef WIN32
213   pthread_mutex_lock(&masterLock);
214 #else
215   WaitForSingleObject(masterLock, INFINITE );
216 #endif
217   //logger->log("Command", Log::DEBUG, "LOCKED");
218
219   if (crashed)
220   {
221     buildCrashedBox();
222   }
223   else
224   {
225     VConnect* vconnect = new VConnect(server);
226     boxstack->add(vconnect);
227     vconnect->run();
228   }
229
230   // Start method 2 of getting commands in...
231   udp.run(this);
232
233   UCHAR button = 0;
234   while(irun)
235   {
236     // unlock and wait
237     //logger->log("Command", Log::DEBUG, "UNLOCK");
238 #ifndef WIN32
239     pthread_mutex_unlock(&masterLock);
240 #else
241     ReleaseMutex(masterLock);
242 #endif
243     button = remote->getButtonPress(2);  // Don't block (0) in case a signal arrives after checking signals but before this line
244     // something happened, lock and process
245     if (signals) processSignals(); // If a signal arrived process now.
246
247     //  logger->log("Command", Log::DEBUG, "WANT LOCK");
248 #ifndef WIN32
249     pthread_mutex_lock(&masterLock);
250 #else
251     WaitForSingleObject(masterLock, INFINITE );
252 #endif
253     // logger->log("Command", Log::DEBUG, "LOCK");
254
255     if ((button == Remote::NA_NONE) /*|| (button == Remote::NA_UNKNOWN)*/) continue;
256
257     if (button != Remote::NA_SIGNAL) handleCommand(button);
258     processMessageQueue();
259
260   }
261
262   //logger->log("Command", Log::DEBUG, "UNLOCK");
263 #ifndef WIN32
264   pthread_mutex_unlock(&masterLock);
265 #else
266   ReleaseMutex(masterLock);
267 #endif
268
269
270
271   boxstack->removeAllExceptWallpaper();
272   boxstack->remove(wallpaper);
273   delete wallpaper_pict; wallpaper_pict = NULL; wallpaper = NULL;
274
275 }
276
277 void Command::setSignal(int signalReceived)
278 {
279 #ifndef WIN32
280   if (signalReceived == SIGINT)
281     signals |= SIG_INT;
282   else if (signalReceived == SIGTERM)
283     signals |= SIG_TERM;
284   else if (signalReceived == SIGUSR1)
285     signals |= SIG_USR1;
286   else if (signalReceived == SIGUSR2)
287     signals |= SIG_USR2;
288   else if (signalReceived == SIGURG)
289     signals |= SIG_URG;
290 #endif
291 }
292
293 void Command::processSignals()
294 {
295 #ifndef WIN32
296   if (signals & SIG_INT)
297   {
298     signals = signals & ~SIG_INT;
299     logger->log("Command", Log::NOTICE, "INT signal, shutting down...");
300     stop();
301   }
302
303   if (signals & SIG_TERM)
304   {
305     signals = signals & ~SIG_TERM;
306     logger->log("Command", Log::NOTICE, "TERM signal, shutting down...");
307     stop();
308   }
309
310   if (signals & SIG_USR1)
311   {
312     logger->log("Command", Log::NOTICE, "USR1 signal");
313     signals = signals & ~SIG_USR1;
314   }
315
316   if (signals & SIG_USR2)
317   {
318     logger->log("Command", Log::NOTICE, "USR2 signal");
319     signals = signals & ~SIG_USR2;
320   }
321
322   if (signals & SIG_URG)
323   {
324     logger->log("Command", Log::NOTICE, "URG signal"); // This is used to break from getButtonPress to process the message queue
325     signals = signals & ~SIG_URG;
326   }
327 #endif
328 }
329
330 void Command::postMessage(Message* m)
331 {
332   // This is locked here in case the main loop is not waiting for an event, but is processing one
333   // it could be killed but then not react to it because the signal wouldn't cause
334   // remote->getButtonPress to break
335   // locking the mutex ensures that the master thread is waiting on getButtonPress
336
337
338   //logger->log("Command", Log::DEBUG, "WANT LOCK");
339 #ifndef WIN32
340   pthread_mutex_lock(&masterLock);
341 #else
342   WaitForSingleObject(masterLock, INFINITE );
343 #endif
344   //logger->log("Command", Log::DEBUG, "LOCK");
345   MessageQueue::postMessage(m);
346
347 #ifndef WIN32
348 #ifndef __ANDROID__
349   kill(mainPid, SIGURG);
350 #else
351   ((RemoteAndroid*)Remote::getInstance())->Signal();
352 #endif
353   pthread_mutex_unlock(&masterLock);
354 #else
355   ((RemoteWin*)Remote::getInstance())->Signal();
356   ReleaseMutex(masterLock);
357 #endif
358   //logger->log("Command", Log::DEBUG, "UNLOCK");
359 }
360
361 void Command::postMessageNoLock(Message* m)
362 {
363   // As above but use this one if this message is being posted because of a button press
364   // the mutex is already locked, locking around postMessage is not needed as the
365   // queue is guaranteed to be run when the button has been processed
366   MessageQueue::postMessage(m);
367 }
368
369 bool Command::postMessageIfNotBusy(Message* m)
370 {
371   // Used for Windows mouse events
372
373   //logger->log("Command", Log::DEBUG, "TRY LOCK");
374 #ifndef WIN32
375   if (pthread_mutex_trylock(&masterLock) != EBUSY)
376   {
377     //logger->log("Command", Log::DEBUG, "LOCK");
378     MessageQueue::postMessage(m);
379 #ifndef __ANDROID__
380     kill(mainPid, SIGURG);
381 #else
382     ((RemoteAndroid*)Remote::getInstance())->Signal();
383 #endif
384     pthread_mutex_unlock(&masterLock);
385     //logger->log("Command", Log::DEBUG, "UNLOCK");
386     return true;
387   }
388   else
389   {
390     return false;
391   }
392 #else
393   switch (WaitForSingleObject(masterLock, 0 ))
394   { //FIXME this is not "if not busy" check
395     case WAIT_OBJECT_0: //but with proper argument 0 this did not work
396     // case WAIT_ABANDONED:
397     MessageQueue::postMessage(m);
398     ((RemoteWin*)Remote::getInstance())->Signal();
399     ReleaseMutex(masterLock);
400     return true;
401
402     case WAIT_ABANDONED: return false;
403     case WAIT_TIMEOUT: return false;
404   }
405     return false;
406 #endif
407 }
408
409 void Command::postMessageFromOuterSpace(Message* m)
410 {
411   /*
412   Yet another way of getting messages into Command. This one is for events that
413   are not standard button presses (or UDP generated buttons). It is also not for
414   events that are generated as a result of other events (events that can safely
415   call postMessageNoLock and be guaranteed that the message will be processed
416   because it is known that the queue is currently being processed).
417   This is for events that come from outer space and can occur when the master
418   mutex is locked or not, they need to be queued and executed but it doesn't
419   matter when.
420   Actually so far it is for events caused by the video stream - aspect ratio
421   changes. These can occur when the master mutex is locked and so postMessage
422   doesn't work. postMessageNoLock doesn't work because if the mutex *isn't*
423   locked at the time then the message could be sat around a while before
424   being noticed.
425   The whole message system was at first supposed to prevent the problem of
426   calling a function on an object that had just been deleted, by ordering
427   messages such that all calls are done before object deletion. However,
428   because of the new centralised messaging system and the fact that BoxStack
429   locates the destination object before calling it, the messaging system now
430   allows the kind of sloppy calls it was supposed to stop. Weird huh. This
431   is mentioned here because the video stream might generate an event just as
432   the user hits stop. The mutex is locked, and by the time the message
433   is examined the vvideorec/live has been deleted. This doesn't matter because
434   boxstack will drop the message if it can't find the matching object to
435   deliver it to.
436   Finally, all this is fine and dandy, except that I'm not 100% sure that
437   this sloppy postMessage and hope a queued signal will force it to be processed
438   thingy will actually work. Hmmm.
439   Lastly <g>, I will consider making the naming system a little more sane
440   if this works.
441   */
442
443   logger->log("Command", Log::DEBUG, "PMFOS called");
444   MessageQueue::postMessage(m);
445
446 #ifndef WIN32
447 #ifndef __ANDROID__
448   kill(mainPid, SIGURG);
449 #else
450   ((RemoteAndroid*)Remote::getInstance())->Signal();
451 #endif
452 #else
453   ((RemoteWin*)Remote::getInstance())->Signal();
454 #endif
455 }
456
457 void Command::processMessage(Message* m)
458 {
459     // FIXME - a slight modification - how if messagereceivers were to register
460     // themselves as receivers to avoid the calling-a-deleted-object problem
461     // then only deliver/register/unregister would have to be protected
462
463   logger->log("Command", Log::DEBUG, "processing message %i", m->message);
464
465
466   if (m->to == this)
467   {
468     switch(m->message)
469     {
470       // << FIXME OBSELETE
471       case Message::STOP_PLAYBACK:
472       {
473         handleCommand(Remote::STOP); // an odd way of doing it, but so simple
474         break;
475       }
476       // Also connection_lost comes from player - anywhere else?
477       // FIXME OBSELETE >>
478
479
480       case Message::VDR_CONNECTED:
481       {
482         doJustConnected((VConnect*)m->from);
483         break;
484       }
485       case Message::SCREENSHOT:
486       {
487 #ifdef VOMP_PLATTFORM_MVP
488         Osd::getInstance()->screenShot("/out.jpg");
489 #else
490         logger->log("Osd", Log::NOTICE, "Screenshot Message arrived");
491         Osd::getInstance()->screenShot("out.jpg");
492 #endif
493         break;
494       }
495       case Message::CONNECTION_LOST:
496       {
497         doFromTheTop(true);
498         break;
499       }
500       case Message::UDP_BUTTON:
501       {
502         handleCommand(m->parameter.num);
503         break;
504       }
505       case Message::CHANGE_LANGUAGE:
506       {
507         boxstack->removeAllExceptWallpaper();
508         boxstack->update(wallpaper);
509         I18n::initialize();
510         if (!VDR::getInstance()->isConnected()) { connectionLost(); break; }
511         VWelcome* vw = new VWelcome();
512         vw->draw();
513         boxstack->add(vw);
514         boxstack->update(vw);
515         break;
516       }
517       case Message::LAST_VIEW_CLOSE:
518       {
519         // Shouldn't be done like this. Some generic message pass back from vinfo perhaps
520         if (crashed)
521         {
522           crashed = false;
523           doFromTheTop(false);        
524         }
525       
526 //        VWelcome* vw = new VWelcome();
527 //        vw->draw();
528 //        boxstack->add(vw);
529 //        boxstack->update(vw);
530
531         break;
532       }
533       case Message::NEW_PICTURE:
534       {
535           //Log::getInstance()->log("Command", Log::DEBUG, "TVMedia NEW_PICTURE");
536           OsdVector *osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
537           if (osdv) {
538                   osdv->informPicture(m->tag,m->parameter.handle);
539           }
540
541       } break;
542       case Message::NEW_PICTURE_STATIC:
543       {
544           //Log::getInstance()->log("Command", Log::DEBUG, "TVMedia NEW_PICTURE %x %x",m->tag,m->parameter.num);
545           OsdVector *osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
546           if (osdv) {
547                   osdv->informPicture(((unsigned long long)m->tag)<<32LL,m->parameter.handle);
548           }
549
550       } break;
551     }
552   }
553   else
554   {
555     /* FIXME
556     
557     Instead of sending through the boxstack, implement a more generic MessageReceiver interface
558     and have potential receivers register with something
559     When a message needs to be delivered, check if the receiver is still registered, if so, deliver the message
560     This could all be done using the existing big command mutex to keep it simple
561     */
562   
563     logger->log("Command", Log::DEBUG, "Sending message to boxstack");
564     boxstack->processMessage(m);
565   }
566 }
567
568 void Command::handleCommand(int button)
569 {
570   if (isStandby && (button != Remote::POWER) 
571       && (button != Remote::POWERON) && (button != Remote::POWEROFF))  return;
572   if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost
573
574   // command was not handled
575
576   switch(button)
577   {
578     case Remote::DF_LEFT:
579     case Remote::DF_RIGHT:
580     case Remote::VOLUMEUP:
581     case Remote::VOLUMEDOWN:
582     {
583         if (remote->handlesVolume()) {
584                 if (button==Remote::DF_LEFT || button==Remote::VOLUMEDOWN)
585                         remote->volumeDown();
586                 else remote->volumeUp();
587         } else {
588                 VVolume* v = new VVolume();
589                 boxstack->add(v);
590                 v->handleCommand(button); // this will draw+show
591         }
592       return;
593     }
594     case Remote::MUTE:
595     {
596         if (remote->handlesVolume()) {
597                 remote->volumeMute();
598         } else {
599                 VMute* v = new VMute();
600                 v->draw();
601                 boxstack->add(v);
602                 boxstack->update(v);
603         }
604       return;
605     }
606     case Remote::POWER:
607     {
608       doStandby();
609       return;
610     }
611     case Remote::POWERON:
612     {
613       doPowerOn();
614       return;
615     }
616     case Remote::POWEROFF:
617     {
618       doPowerOff();
619       return;
620     }
621     case Remote::OK:
622     {
623       // FIXME
624       if (!connLost) return; // if connLost, handle Remote::OK
625       doFromTheTop(false);
626       return;
627     }
628     case Remote::GO:
629     {
630       VSleeptimer* sleep = new VSleeptimer();
631       boxstack->add(sleep);
632       sleep->handleCommand(button); // this will draw+show
633       return;
634     }
635   }
636 }
637
638 void Command::sig1()
639 {
640 #ifdef DEV
641   Message* m = new Message(); // break into master mutex
642   m->message = Message::SCREENSHOT;
643   m->to = this;
644   postMessage(m);
645 #endif
646 }
647
648 void Command::doStandby()
649 {
650   if (isStandby)
651   {
652     doPowerOn();
653   }
654   else
655   {
656    doPowerOff();
657   }
658 }
659
660
661 void Command::doPowerOn()
662 {
663   if (isStandby)
664   {
665     Video::getInstance()->signalOn();
666     Led::getInstance()->on();
667     Remote::getInstance()->changePowerState(true);
668     isStandby = 0;
669
670
671     VConnect* vconnect = new VConnect(server);
672     boxstack->add(vconnect);
673     vconnect->run();
674   }
675 }
676
677 void Command::doPowerOff()
678 {
679   if (!isStandby)
680   {
681     VDR::getInstance()->shutdownVDR();
682     boxstack->removeAllExceptWallpaper();
683     Video::getInstance()->signalOff();
684     boxstack->update(wallpaper);
685
686     VDR::getInstance()->configSave("General", "Last Power State", "Off");
687     logger->unsetExternLogger();
688     VDR::getInstance()->disconnect();
689     Led::getInstance()->off();
690     Remote::getInstance()->changePowerState(false);
691     isStandby = 1;
692     Sleeptimer::getInstance()->shutdown();
693 #ifdef WIN32
694     stop(); //different behavoiur on windows, we exit
695 #endif
696   }
697 }
698
699 void Command::doFromTheTop(bool which)
700 {
701   if (isStandby) return;
702   if (which)
703   {
704     if (connLost)
705     {
706       logger->log("Command", Log::NOTICE, "Connection lost dialog already present");
707       return;
708     }
709   
710     logger->log("Command", Log::NOTICE, "Doing connection lost dialog");
711     connLost = new VInfo();
712     connLost->setSize(360, 200);
713     connLost->createBuffer();
714     if (Video::getInstance()->getFormat() == Video::PAL)
715       connLost->setPosition(190, 170);
716     else
717       connLost->setPosition(180, 120);
718     connLost->setOneLiner(tr("Connection lost"));
719     connLost->setDropThrough();
720     connLost->setBorderOn(1);
721     connLost->setTitleBarColour(DrawStyle::DANGER);
722     connLost->okButton();
723     connLost->draw();
724     boxstack->add(connLost);
725     boxstack->update(connLost);
726     remote->clearBuffer();
727   }
728   else
729   {
730     logger->unsetExternLogger();
731     VDR::getInstance()->disconnect();
732     boxstack->removeAllExceptWallpaper();
733     boxstack->update(wallpaper);
734     connLost = NULL;
735     
736     flushMessageQueue();
737     remote->clearBuffer();
738     
739     // at this point, everything should be reset to first-go
740     
741     VConnect* vconnect = new VConnect(server);
742     boxstack->add(vconnect);
743     vconnect->run();
744   }
745 }
746
747 void Command::doReboot()
748 {
749
750   logger->unsetExternLogger();
751   VDR::getInstance()->disconnect();
752   // just kill it...
753   logger->log("Command", Log::NOTICE, "Reboot");
754 #ifndef WIN32
755 #ifndef VOMP_HAS_EXIT
756   // some plattforms, want a proper deinitialisation of their hardware before reboot
757   Osd::getInstance()->shutdown();
758   Audio::getInstance()->shutdown();
759   Video::getInstance()->shutdown();
760   Remote::getInstance()->shutdown();
761
762   reboot(LINUX_REBOOT_CMD_RESTART);
763   // if  reboot is not allowed -> stop
764   stop();
765
766
767 #else
768   stop();
769
770 #ifdef __ANDROID__
771   exit(0);
772 #endif
773
774 #endif
775 #endif //Would we support this on windows?
776 }
777
778 void Command::connectionLost()
779 {
780   logger->unsetExternLogger();
781   Message* m = new Message(); // break into master mutex
782   m->message = Message::CONNECTION_LOST;
783   m->to = this;
784   postMessageFromOuterSpace(m);
785 }
786
787 void Command::buildCrashedBox()
788 {
789   VInfo* crash = new VInfo();
790   crash->setSize(360, 250);
791   crash->createBuffer();
792   if (Video::getInstance()->getFormat() == Video::PAL)
793     crash->setPosition(190, 146);
794   else
795     crash->setPosition(180, 96);
796   crash->setMainText("Oops, vomp crashed.. :(\nPlease report this crash to the author, with as much detail as possible about what you were doing at the time that might have caused the crash.");
797   crash->setBorderOn(1);
798   crash->setTitleBarColour(DrawStyle::DANGER);
799   crash->okButton();
800   crash->setExitable();
801   crash->draw();
802   boxstack->add(crash);
803   boxstack->update(crash);
804 }
805
806 int Command::getLangPref(bool subtitle,const char* langcode)
807 {
808         vector<struct ASLPref>::iterator itty=langcodes.begin();
809         char templangcode[4];
810         templangcode[0]=langcode[0];
811         templangcode[1]=langcode[1];
812         templangcode[2]=langcode[2];
813         templangcode[3]='\0';
814         int langpos =0;
815         while (itty != langcodes.end()) {
816                 size_t pos=(*itty).langcode.find(templangcode);
817                 if (pos != string::npos) {
818                         //vector<struct ASLPref>::iterator itty2=langcodes.begin();
819                         for (unsigned int i=0; i<langcodes.size();i++) {
820                                 int pref=0;
821                                 if (subtitle) {
822                                         pref=langcodes[i].subtitlepref;
823                                 } else {
824                                         pref=langcodes[i].audiopref;
825                                 }
826                                 if (pref < 0) break;
827
828                                 if (subtitle) {
829                                         if (langcodes[i].subtitlepref==langpos) {
830                                                 return i;
831                                         }
832                                 } else {
833                                         if (langcodes[i].audiopref==langpos) {
834                                                 return i;
835                                         }
836                                 }
837                         }
838                         break;
839                 }
840                 itty++;
841                 langpos++;
842         }
843         return langcodes.size(); //neutral
844 }
845
846 void Command::doJustConnected(VConnect* vconnect)
847 {
848   I18n::initialize();
849   if (!VDR::getInstance()->isConnected()) { connectionLost(); return; }
850   logger->log("Command", Log::INFO, "Entering doJustConnected");
851   
852   Video* video = Video::getInstance();
853   Audio* audio = Audio::getInstance();  
854   boxstack->remove(vconnect);
855
856   VInfo* vi = new VInfo();
857   vi->setSize(400, 200);
858   vi->createBuffer();
859   if (video->getFormat() == Video::PAL)
860     vi->setPosition(170, 200);
861   else
862     vi->setPosition(160, 150);
863   vi->setOneLiner(tr("Connected, loading config"));
864   vi->draw();
865   boxstack->add(vi);
866   boxstack->update(vi);
867
868   VDR* vdr = VDR::getInstance();
869   char* config;
870
871   // See if we're supposed to do network logging
872   config = vdr->configLoad("Advanced", "Network logging");
873   if (config && !STRCASECMP(config, "On"))
874   {
875     logger->log("Command", Log::INFO, "Turning on network logging");
876     logger->setExternLogger(vdr);
877   }  
878   else
879   {
880           logger->unsetExternLogger();
881     logger->log("Command", Log::INFO, "Turned off network logging");
882   }
883   if (config) delete[] config;
884
885   config = vdr->configLoad("Advanced", "Skin Name");
886   if (config) {
887           const char **skinnames=SkinFactory::getSkinNames();
888           for (int i=0;i<SkinFactory::getNumberofSkins();i++) {
889                   if (!STRCASECMP(config, skinnames[i])) {
890                           SkinFactory::InitSkin(i);
891                           break;
892                   }
893           }
894           delete[] config;
895           if (wallpaper && wallpaper_pict) {
896                   if (DrawStyle::WALLPAPER.alpha) {
897                           wallpaper_pict->setVisible(true);
898                   } else {
899                           wallpaper_pict->setVisible(false);
900                   }
901                   wallpaper->draw();
902                   boxstack->update(wallpaper);
903           }
904
905   } else {
906           SkinFactory::InitSkin(0);
907   }
908
909   // See if config says to override video format (PAL/NTSC)
910   config = vdr->configLoad("General", "Override Video Format");
911   if (config)
912   {
913     logger->log("Command", Log::DEBUG, "Override Video Format is present");
914
915     if (   (!strcmp(config, "PAL") && (video->getFormat() != Video::PAL))
916         || (!strcmp(config, "NTSC") && (video->getFormat() != Video::NTSC))
917         || (!strcmp(config, "PAL_M") && (video->getFormat() != Video::PAL_M))
918         || (!strcmp(config, "NTSC_J") && (video->getFormat() != Video::NTSC_J))
919         )
920     {
921       // Oh sheesh, need to switch format. Bye bye TV...
922
923       // Take everything down
924       boxstack->removeAllExceptWallpaper();
925       boxstack->remove(wallpaper);
926       delete wallpaper_pict; wallpaper_pict = NULL; wallpaper = NULL;
927
928       Osd* osd = Osd::getInstance();
929 #ifndef __ANDROID__
930       osd->shutdown();
931 #endif
932       video->shutdown();
933
934       remote->shutdown(); // need on raspberry shut not do any harm, hopefully
935       remote->init(RemoteStartDev);
936
937       // Get video and osd back up with the new mode
938       if (!strcmp(config, "PAL"))
939       {
940         logger->log("Command", Log::DEBUG, "Switching to PAL");
941         video->init(Video::PAL);
942       }
943       else if (!strcmp(config, "NTSC"))
944       {
945         logger->log("Command", Log::DEBUG, "Switching to NTSC");
946         video->init(Video::NTSC);
947       } else if (!strcmp(config, "PAL_M"))
948       {
949         logger->log("Command", Log::DEBUG, "Switching to PAL_M");
950         video->init(Video::PAL_M);
951       } else if (!strcmp(config, "NTSC_J"))
952       {
953         logger->log("Command", Log::DEBUG, "Switching to NTSC_J");
954         video->init(Video::NTSC_J);
955       }
956       delete[] config;
957
958 #ifndef __ANDROID__
959       //we do not init twice
960       osd->init((char*)("/dev/stbgfx"));
961 #endif
962
963       // Put the wallpaper back
964       doWallpaper();
965
966       // Re add the vinfo
967       vi = new VInfo();
968       vi->setSize(400, 200);
969       vi->createBuffer();
970       if (video->getFormat() == Video::PAL)
971         vi->setPosition(170, 200);
972       else
973         vi->setPosition(160, 150);
974
975       vi->setOneLiner(tr("Connected, loading config"));
976       vi->draw();
977       boxstack->add(vi);
978       boxstack->update(vi);
979     }
980     else
981     {
982       logger->log("Command", Log::DEBUG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
983     }
984   }
985   else
986   {
987     logger->log("Command", Log::DEBUG, "Phew, no dangerous on-the-fly mode switching to do!");
988   }
989
990   // Power off if first boot and config says so
991   if (firstBoot)
992   {
993     firstBoot = 0;
994
995     logger->log("Command", Log::DEBUG, "Load power after boot");
996
997     config = vdr->configLoad("General", "Power After Boot");
998
999     if (config)
1000     {
1001       if (!STRCASECMP(config, "On"))
1002       {
1003         logger->log("Command", Log::INFO, "Config says Power After Boot = On");
1004       }
1005       else if (!STRCASECMP(config, "Off"))
1006       {
1007         logger->log("Command", Log::INFO, "Config says Power After Boot = Off");
1008         doStandby();
1009         delete[] config;
1010         return; // quit here
1011       }
1012       else if (!STRCASECMP(config, "Last state"))
1013       {
1014         char* lastPowerState = vdr->configLoad("General", "Last Power State");
1015         if (lastPowerState)
1016         {
1017           if (!STRCASECMP(lastPowerState, "On"))
1018           {
1019             logger->log("Command", Log::INFO, "Config says Last Power State = On");
1020           }
1021           else if (!STRCASECMP(lastPowerState, "Off"))
1022           {
1023             logger->log("Command", Log::INFO, "Config says Last Power State = Off");
1024             doStandby();
1025             delete[] config;
1026             return; // quit here
1027           }
1028           else
1029           {
1030             logger->log("Command", Log::INFO, "Config General/Last Power State not understood");
1031           }
1032         }
1033         else
1034         {
1035           logger->log("Command", Log::INFO, "Config General/Last Power State not found");
1036         }
1037       }
1038       else
1039       {
1040         logger->log("Command", Log::INFO, "Config/Power After Boot not understood");
1041       }
1042       delete[] config;
1043     }
1044     else
1045     {
1046       logger->log("Command", Log::INFO, "Config General/Power After Boot not found");
1047     }
1048   }
1049
1050
1051   // Go S-Video if config says so
1052
1053   config = vdr->configLoad("TV", "Connection");
1054
1055   if (config)
1056   {
1057     if (!STRCASECMP(config, "S-Video"))
1058     {
1059       logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);
1060       video->setConnection(Video::SVIDEO);
1061     } else  if (!STRCASECMP(config, "HDMI"))
1062     {
1063       logger->log("Command", Log::INFO, "Switching to HDMI as Connection=%s", config);
1064       video->setConnection(Video::HDMI);
1065     } else  if (!STRCASECMP(config, "HDMI3D"))
1066     {
1067       logger->log("Command", Log::INFO, "Switching to HDMI3D as Connection=%s", config);
1068       video->setConnection(Video::HDMI3D);
1069     }
1070     else
1071     {
1072       logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);
1073       video->setConnection(Video::COMPOSITERGB);
1074     }
1075     delete[] config;
1076   }
1077   else
1078   {
1079     logger->log("Command", Log::INFO, "Config TV/S-Video not found");
1080   }
1081
1082   // Set to shutdown VDR if config says
1083   
1084   config = vdr->configLoad("General", "VDR shutdown");
1085   if (config)
1086   {
1087     if (!STRCASECMP(config, "On"))
1088     {
1089       logger->log("Command", Log::INFO, "Shutdown VDR when  shutting down vomp");
1090       vdr->setVDRShutdown(true);
1091     }
1092     else if (!STRCASECMP(config, "Off"))
1093     {
1094       logger->log("Command", Log::INFO, "Shutdown only vomp");
1095       vdr->setVDRShutdown(false);
1096     }
1097   }
1098   else
1099   {
1100     logger->log("Command", Log::INFO, "Default shutdown only vomp");
1101     vdr->setVDRShutdown(false); // Default
1102   }
1103           
1104   // Set remote type
1105
1106   config = vdr->configLoad("General", "Remote type");
1107
1108   if (config)
1109   {
1110     if (!STRCASECMP(config, "New"))
1111     {
1112       logger->log("Command", Log::INFO, "Switching to New remote type");
1113       remote->setRemoteType(Remote::NEWREMOTE);
1114     }
1115     else
1116     {
1117       logger->log("Command", Log::INFO, "Switching to Old remote type");
1118       remote->setRemoteType(Remote::OLDREMOTE);
1119     }
1120     delete[] config;
1121   }
1122   else
1123   {
1124     logger->log("Command", Log::INFO, "Config General/Remote type not found");
1125     remote->setRemoteType(Remote::OLDREMOTE);
1126   }
1127
1128
1129
1130   // Get TV aspect ratio
1131
1132   config = vdr->configLoad("TV", "Aspect");
1133   if (config)
1134   {
1135     if (!STRCASECMP(config, "16:9"))
1136     {
1137       logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");
1138       video->setTVsize(Video::ASPECT16X9);
1139     }
1140     else
1141     {
1142       logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");
1143       video->setTVsize(Video::ASPECT4X3);
1144     }
1145     delete[] config;
1146   }
1147   else
1148   {
1149     logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");
1150     video->setTVsize(Video::ASPECT4X3);
1151   }
1152
1153   config = vdr->configLoad("TV", "Widemode");
1154   if (config)
1155   {
1156     if (!STRCASECMP(config, "Letterbox"))
1157     {
1158       logger->log("Command", Log::INFO, "Setting letterbox mode");
1159       video->setMode(Video::LETTERBOX);
1160     }
1161     else
1162     {
1163       logger->log("Command", Log::INFO, "Setting chop-sides mode");
1164       video->setMode(Video::NORMAL);
1165     }
1166     delete[] config;
1167   }
1168   else
1169   {
1170 #ifdef __ANDROID__
1171          logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting letterbox mode");
1172          video->setMode(Video::LETTERBOX);
1173 #else
1174     logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");
1175     video->setMode(Video::NORMAL);
1176 #endif
1177   }
1178
1179   config = vdr->configLoad("Advanced", "TCP receive window");
1180   if (config)
1181   {
1182     size_t newTCPsize = atoi(config);
1183     delete[] config;
1184
1185     logger->log("Command", Log::INFO, "Setting TCP window size %i", newTCPsize);
1186     vdr->setReceiveWindow(newTCPsize);
1187   }
1188   else
1189   {
1190     logger->log("Command", Log::INFO, "TCP window size not found, setting 2048");
1191     if (DEFAULT_TCP_WINDOWSIZE) vdr->setReceiveWindow(2048); // Default
1192   }
1193
1194   config = vdr->configLoad("Advanced", "Font Name");
1195   if (config)
1196   {
1197         Osd::getInstance()->setFont(config);
1198     logger->log("Command", Log::INFO, "Setting Font to %s", config);
1199     delete[] config;
1200
1201   }
1202
1203
1204   // Set recording list type
1205
1206   advmenues=false;
1207 #ifdef    ADVANCED_MENUES
1208   config = vdr->configLoad("Advanced", "Menu type");
1209
1210   if (config)
1211   {
1212           if (!STRCASECMP(config, "Advanced"))
1213           {
1214                   logger->log("Command", Log::INFO, "Switching to Advanced menu");
1215                   advmenues=true;
1216
1217           }
1218           else
1219           {
1220                   logger->log("Command", Log::INFO, "Switching to Classic menu");
1221                   advmenues=false;
1222           }
1223           delete[] config;
1224   }
1225   else
1226   {
1227           logger->log("Command", Log::INFO, "Config General/menu type not found");
1228           advmenues=true;
1229   }
1230 #endif
1231
1232   config = vdr->configLoad("Advanced", "Disable WOL");
1233   if (config)
1234   {
1235     if (!STRCASECMP(config, "Yes"))
1236     {
1237       logger->log("Command", Log::INFO, "Config says disable WOL");
1238       Wol::getInstance()->setEnabled(false);
1239     }
1240     else
1241     {
1242       logger->log("Command", Log::INFO, "Config says enable WOL");
1243       Wol::getInstance()->setEnabled(true);
1244     }
1245
1246     delete[] config;
1247   }
1248   else
1249   {
1250     logger->log("Command", Log::INFO, "By default, enable WOL");
1251     Wol::getInstance()->setEnabled(true);
1252   }
1253   /* device dependend config */
1254   audio->loadOptionsfromServer(vdr);
1255   video->loadOptionsfromServer(vdr);
1256   remote->loadOptionsfromServer(vdr);
1257
1258   video->executePendingModeChanges();
1259   // config done
1260
1261   // Save power state = on
1262
1263   vdr->configSave("General", "Last Power State", "On");
1264
1265   // Make sure connection didn't die
1266   if (!vdr->isConnected())
1267   {
1268     Command::getInstance()->connectionLost();
1269   }
1270   else
1271   {
1272     boxstack->remove(vi);
1273
1274     VWelcome* vw = new VWelcome();
1275     vw->draw();
1276     boxstack->add(vw);
1277     boxstack->update(vw);
1278
1279     // Enter pre-keys here
1280 //    handleCommand(Remote::OK);
1281 //    handleCommand(Remote::THREE);
1282 //    handleCommand(Remote::SIX);
1283 //    handleCommand(Remote::OK);
1284 //    handleCommand(Remote::UP);
1285 //    handleCommand(Remote::PLAY);
1286 //    handleCommand(Remote::DOWN);
1287 //    handleCommand(Remote::DOWN);
1288 //    handleCommand(Remote::DOWN);
1289  //   handleCommand(Remote::OK);
1290 //    handleCommand(Remote::RED);
1291   }
1292 }