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