MythTV  master
mythcontext.cpp
Go to the documentation of this file.
1 #include <QCoreApplication>
2 #include <QDir>
3 #include <QFileInfo>
4 #include <QDebug>
5 #include <QMutex>
6 #include <QDateTime>
7 #include <QTcpSocket>
8 #include <QEventLoop>
9 
10 #include <cmath>
11 #include <iostream>
12 
13 #include <queue>
14 #include <algorithm>
15 #include <thread>
16 
17 using namespace std;
18 
19 #include "config.h"
20 #include "mythcontext.h"
21 #include "exitcodes.h"
22 #include "mythdate.h"
23 #include "remotefile.h"
24 #include "backendselect.h"
25 #include "dbsettings.h"
26 #include "langsettings.h"
27 #include "mythtranslation.h"
28 #include "mythxdisplay.h"
29 #include "mythevent.h"
30 #include "dbutil.h"
31 #include "DisplayRes.h"
32 #include "mythmediamonitor.h"
33 
34 #include "mythdb.h"
35 #include "mythdirs.h"
36 #include "mythversion.h"
37 #include "mythdialogbox.h"
38 #include "mythmainwindow.h"
39 #include "mythuihelper.h"
40 #include "mythimage.h"
41 #include "mythxmlclient.h"
42 #include "upnp.h"
43 #include "mythlogging.h"
44 #include "mythsystemlegacy.h"
45 #include "mythmiscutil.h"
46 
47 #include "mythplugin.h"
48 #include "portchecker.h"
49 #include "guistartup.h"
50 
51 #include <unistd.h> // for usleep(), gethostname
52 
53 #ifdef _WIN32
54 #include "compat.h"
55 #endif
56 
57 #define LOC QString("MythContext: ")
58 
60 
61 static const QString _Location = "MythContext";
62 
63 class MythContextPrivate : public QObject
64 {
65  friend class MythContextSlotHandler;
66 
67  public:
70 
71  bool Init (const bool gui,
72  const bool prompt, const bool noPrompt,
73  const bool ignoreDB);
74  bool FindDatabase(const bool prompt, const bool noPrompt);
75 
76  void TempMainWindow(bool languagePrompt = true);
77  void EndTempWindow(void);
78 
79  bool LoadDatabaseSettings(void);
80  bool SaveDatabaseParams(const DatabaseParams &params, bool force);
81 
82  bool PromptForDatabaseParams(const QString &error);
83  QString TestDBconnection(bool prompt=true);
84  void SilenceDBerrors(void);
85  void EnableDBerrors(void);
86  void ResetDatabase(void);
87 
88  int ChooseBackend(const QString &error);
89  int UPnPautoconf(const int milliSeconds = 2000);
90  bool DefaultUPnP(QString &error);
91  bool UPnPconnect(const DeviceLocation *device, const QString &PIN);
92  void ShowGuiStartup(void);
93  bool checkPort(QString &host, int port, int wakeupTime);
94  void processEvents(void);
95  bool saveSettingsCache(void);
96  void loadSettingsCacheOverride(void);
97  void clearSettingsCacheOverride(void);
98 
99 
100  protected:
101  bool event(QEvent*);
102 
103  void ShowConnectionFailurePopup(bool persistent);
104  void HideConnectionFailurePopup(void);
105 
106  void ShowVersionMismatchPopup(uint remoteVersion);
107 
108  public slots:
109  void OnCloseDialog();
110 
111  public:
113 
114  bool m_gui;
115 
117 
119  QString m_DBhostCp;
120 
122 
124 
128  QEventLoop *m_loop;
130 
131  private:
134  QDateTime m_lastCheck;
135  QTcpSocket *m_socket;
136  static const QString settingsToSave[];
137 };
138 
139 static void exec_program_cb(const QString &cmd)
140 {
141  myth_system(cmd);
142 }
143 
144 static void exec_program_tv_cb(const QString &cmd)
145 {
146  QString s = cmd;
147  QStringList tokens = cmd.simplified().split(" ");
148  QStringList strlist;
149 
150  bool cardidok;
151  int wantcardid = tokens[0].toInt(&cardidok, 10);
152 
153  if (cardidok && wantcardid > 0)
154  {
155  strlist << QString("LOCK_TUNER %1").arg(wantcardid);
156  s = s.replace(0, tokens[0].length() + 1, "");
157  }
158  else
159  strlist << "LOCK_TUNER";
160 
162  int cardid = strlist[0].toInt();
163 
164  if (cardid >= 0)
165  {
166  s = s.sprintf(qPrintable(s),
167  qPrintable(strlist[1]),
168  qPrintable(strlist[2]),
169  qPrintable(strlist[3]));
170 
171  myth_system(s);
172 
173  strlist = QStringList(QString("FREE_TUNER %1").arg(cardid));
175  QString ret = strlist[0];
176  }
177  else
178  {
179  QString label;
180 
181  if (cardidok)
182  {
183  if (cardid == -1)
184  label = QObject::tr("Could not find specified tuner (%1).")
185  .arg(wantcardid);
186  else
187  label = QObject::tr("Specified tuner (%1) is already in use.")
188  .arg(wantcardid);
189  }
190  else
191  {
192  label = QObject::tr("All tuners are currently in use. If you want "
193  "to watch TV, you can cancel one of the "
194  "in-progress recordings from the delete menu");
195  }
196 
197  LOG(VB_GENERAL, LOG_ALERT, QString("exec_program_tv: ") + label);
198 
199  ShowOkPopup(label);
200  }
201 }
202 
203 static void configplugin_cb(const QString &cmd)
204 {
206  if (!pmanager)
207  return;
208 
209  if (GetNotificationCenter() && pmanager->config_plugin(cmd.trimmed()))
210  {
212  QObject::tr("Failed to configure plugin"));
213  }
214 }
215 
216 static void plugin_cb(const QString &cmd)
217 {
219  if (!pmanager)
220  return;
221 
222  if (GetNotificationCenter() && pmanager->run_plugin(cmd.trimmed()))
223  {
224  ShowNotificationError(QObject::tr("Plugin failure"),
225  _Location,
226  QObject::tr("%1 failed to run for some reason").arg(cmd));
227  }
228 }
229 
230 static void eject_cb(void)
231 {
233 }
234 
236  : parent(lparent),
237  m_gui(false),
238  m_pConfig(NULL),
239  disableeventpopup(false),
240  m_ui(NULL),
241  m_sh(new MythContextSlotHandler(this)),
242  m_guiStartup(0),
243  needsBackend(false),
244  MBEversionPopup(NULL),
245  m_registration(-1),
246  m_socket(0)
247 {
248  m_loop = new QEventLoop(this);
250 }
251 
253 {
254  if (m_pConfig)
255  delete m_pConfig;
257  {
259  }
260 
261  if (m_loop)
262  {
263  delete m_loop;
264  }
265 
266  if (m_ui)
267  DestroyMythUI();
268  if (m_sh)
269  m_sh->deleteLater();
270 }
271 
282 void MythContextPrivate::TempMainWindow(bool languagePrompt)
283 {
284  if (HasMythMainWindow())
285  return;
286 
287  SilenceDBerrors();
288 
291 
292 #ifdef Q_OS_MAC
293  // Qt 4.4 has window-focus problems
294  gCoreContext->OverrideSettingForSession("RunFrontendInWindow", "1");
295 #endif
296  GetMythUI()->Init();
297  GetMythUI()->LoadQtConfig();
298 
299  MythMainWindow *mainWindow = MythMainWindow::getMainWindow(false);
300  mainWindow->Init();
301 
302  if (languagePrompt)
303  {
304  // ask user for language settings
306  MythTranslation::load("mythfrontend");
307  }
308 }
309 
311 {
312  if (HasMythMainWindow())
313  {
315  {
317  if (mainStack) {
318  mainStack->PopScreen(m_guiStartup, false);
319  m_guiStartup = 0;
320  }
321  }
323  }
326  EnableDBerrors();
327 }
328 
336 bool MythContextPrivate::checkPort(QString &host, int port, int timeLimit)
337 {
338  PortChecker checker;
339  if (m_guiStartup)
340  QObject::connect(m_guiStartup,SIGNAL(cancelPortCheck()),&checker,SLOT(cancelPortCheck()));
341  return checker.checkPort(host, port, timeLimit*1000);
342 }
343 
344 
345 bool MythContextPrivate::Init(const bool gui,
346  const bool promptForBackend,
347  const bool noPrompt,
348  const bool ignoreDB)
349 {
350  gCoreContext->GetDB()->IgnoreDatabase(ignoreDB);
351  m_gui = gui;
352 
353  if (gCoreContext->IsFrontend())
354  needsBackend = true;
355 
356  // We don't have a database yet, so lets use the config.xml file.
357  m_pConfig = new XmlConfiguration("config.xml");
358 
359  // Creates screen saver control if we will have a GUI
360  if (gui)
361  m_ui = GetMythUI();
362 
363  // ---- database connection stuff ----
364 
365  if (!ignoreDB && !FindDatabase(promptForBackend, noPrompt))
366  {
367  EndTempWindow();
368  return false;
369  }
370 
371  // ---- keep all DB-using stuff below this line ----
372 
373  // Prompt for language if this is a first time install and
374  // we didn't already do so.
375  if (m_gui && !gCoreContext->GetDB()->HaveSchema())
376  {
377  TempMainWindow(false);
379  MythTranslation::load("mythfrontend");
380  }
383 
384  // Close GUI Startup Window.
385  if (m_guiStartup) {
387  if (mainStack)
388  mainStack->PopScreen(m_guiStartup, false);
389  m_guiStartup=0;
390  }
391  EndTempWindow();
392 
393  if (gui)
394  {
399  cbs.plugin = plugin_cb;
400  cbs.eject = eject_cb;
401 
402  m_ui->Init(cbs);
403  }
404 
405  return true;
406 }
407 
420 bool MythContextPrivate::FindDatabase(bool prompt, bool noAutodetect)
421 {
422  // We can only prompt if autodiscovery is enabled..
423  bool manualSelect = prompt && !noAutodetect;
424 
425  QString failure;
426 
427  // 1. Either load config.xml or use sensible "localhost" defaults:
428  bool loaded = LoadDatabaseSettings();
429  DatabaseParams dbParamsFromFile = m_DBparams;
430 
431  // In addition to the UI chooser, we can also try to autoSelect later,
432  // but only if we're not doing manualSelect and there was no
433  // valid config.xml
434  bool autoSelect = !manualSelect && !loaded && !noAutodetect;
435 
436  // 2. If the user isn't forcing up the chooser UI, look for a default
437  // backend in config.xml, then test DB settings we've got so far:
438  if (!manualSelect)
439  {
440  // config.xml may contain a backend host UUID and PIN.
441  // If so, try to AutoDiscover UPnP server, and use its DB settings:
442 
443  if (DefaultUPnP(failure)) // Probably a valid backend,
444  autoSelect = manualSelect = false; // so disable any further UPnP
445  else
446  if (failure.length())
447  LOG(VB_GENERAL, LOG_ALERT, failure);
448 
449  failure = TestDBconnection(loaded);
450  if (failure.isEmpty())
451  goto DBfound;
453  return false;
455  autoSelect=true;
456  }
457 
458  // 3. Try to automatically find the single backend:
459  if (autoSelect)
460  {
461  int count = UPnPautoconf();
462 
463  if (count == 0)
464  failure = QObject::tr("No UPnP backends found", "Backend Setup");
465 
466  if (count == 1)
467  {
468  failure = TestDBconnection();
469  if (failure.isEmpty())
470  goto DBfound;
472  return false;
473  }
474 
475  // Multiple BEs, or needs PIN.
476  manualSelect |= (count > 1 || count == -1);
477  // Search requested
479  manualSelect=true;
480  }
481 
482  manualSelect &= m_gui; // no interactive command-line chooser yet
483 
484  // Queries the user for the DB info
485  do
486  {
487  if (manualSelect)
488  {
489  // Get the user to select a backend from a possible list:
491  ChooseBackend(failure);
492  switch (d)
493  {
495  break;
497  manualSelect = false;
498  break;
500  goto NoDBfound;
501  }
502  }
503 
504  if (!manualSelect)
505  {
506  if (!PromptForDatabaseParams(failure))
507  goto NoDBfound;
508  }
509  failure = TestDBconnection();
510  if (!failure.isEmpty())
511  LOG(VB_GENERAL, LOG_ALERT, failure);
513  return false;
515  manualSelect=true;
517  manualSelect=false;
518  }
519  while (!failure.isEmpty());
520 
521 DBfound:
522  LOG(VB_GENERAL, LOG_DEBUG, "FindDatabase() - Success!");
523  // If we got the database from UPNP then the wakeup settings are lost.
524  // Restore them.
525  m_DBparams.wolEnabled = dbParamsFromFile.wolEnabled;
526  m_DBparams.wolReconnect = dbParamsFromFile.wolReconnect;
527  m_DBparams.wolRetry = dbParamsFromFile.wolRetry;
528  m_DBparams.wolCommand = dbParamsFromFile.wolCommand;
529 
531  !loaded || m_DBparams.forceSave ||
532  dbParamsFromFile != m_DBparams);
533  EnableDBerrors();
534  ResetDatabase();
535  return true;
536 
537 NoDBfound:
538  LOG(VB_GENERAL, LOG_DEBUG, "FindDatabase() - failed");
539  return false;
540 }
541 
546 {
547  // try new format first
549 
550  m_DBparams.localHostName = m_pConfig->GetValue("LocalHostName", "");
551  m_DBparams.dbHostPing = m_pConfig->GetValue(kDefaultDB + "PingHost", true);
553  m_DBparams.dbUserName = m_pConfig->GetValue(kDefaultDB + "UserName", "");
554  m_DBparams.dbPassword = m_pConfig->GetValue(kDefaultDB + "Password", "");
555  m_DBparams.dbName = m_pConfig->GetValue(kDefaultDB + "DatabaseName", "");
557 
559  m_pConfig->GetValue(kDefaultWOL + "Enabled", false);
561  m_pConfig->GetValue(kDefaultWOL + "SQLReconnectWaitTime", 0);
563  m_pConfig->GetValue(kDefaultWOL + "SQLConnectRetry", 5);
565  m_pConfig->GetValue(kDefaultWOL + "Command", "");
566 
567  bool ok = m_DBparams.IsValid("config.xml");
568  if (!ok) // if new format fails, try legacy format
569  {
572  kDefaultMFE + "DBHostName", "");
574  kDefaultMFE + "DBUserName", "");
576  kDefaultMFE + "DBPassword", "");
578  kDefaultMFE + "DBName", "");
580  kDefaultMFE + "DBPort", 0);
581  m_DBparams.forceSave = true;
582  ok = m_DBparams.IsValid("config.xml");
583  }
584  if (!ok)
586 
587  gCoreContext->GetDB()->SetDatabaseParams(m_DBparams);
588 
590  if (hostname.isEmpty() ||
591  hostname == "my-unique-identifier-goes-here")
592  {
593  char localhostname[1024];
594  if (gethostname(localhostname, 1024))
595  {
596  LOG(VB_GENERAL, LOG_ALERT,
597  "MCP: Error, could not determine host name." + ENO);
598  localhostname[0] = '\0';
599  }
600  hostname = localhostname;
601  LOG(VB_GENERAL, LOG_NOTICE, "Empty LocalHostName.");
602  }
603  else
604  {
605  m_DBparams.localEnabled = true;
606  }
607 
608  LOG(VB_GENERAL, LOG_INFO, QString("Using localhost value of %1")
609  .arg(hostname));
610  gCoreContext->SetLocalHostname(hostname);
611 
612  return ok;
613 }
614 
616  const DatabaseParams &params, bool force)
617 {
618  bool ret = true;
619 
620  // only rewrite file if it has changed
621  if (params != m_DBparams || force)
622  {
624  "LocalHostName", params.localHostName);
625 
627  kDefaultDB + "PingHost", params.dbHostPing);
628 
629  // If dbHostName is an IPV6 address with scope,
630  // remove the scope. Unescaped % signs are an
631  // xml violation
632  QString dbHostName(params.dbHostName);
633  QHostAddress addr;
634  if (addr.setAddress(dbHostName))
635  {
636  addr.setScopeId(QString());
637  dbHostName = addr.toString();
638  }
640  kDefaultDB + "Host", dbHostName);
642  kDefaultDB + "UserName", params.dbUserName);
644  kDefaultDB + "Password", params.dbPassword);
646  kDefaultDB + "DatabaseName", params.dbName);
648  kDefaultDB + "Port", params.dbPort);
649 
651  kDefaultWOL + "Enabled", params.wolEnabled);
653  kDefaultWOL + "SQLReconnectWaitTime", params.wolReconnect);
655  kDefaultWOL + "SQLConnectRetry", params.wolRetry);
657  kDefaultWOL + "Command", params.wolCommand);
658 
659  // clear out any legacy nodes..
660  m_pConfig->ClearValue(kDefaultMFE + "DBHostName");
661  m_pConfig->ClearValue(kDefaultMFE + "DBUserName");
662  m_pConfig->ClearValue(kDefaultMFE + "DBPassword");
663  m_pConfig->ClearValue(kDefaultMFE + "DBName");
664  m_pConfig->ClearValue(kDefaultMFE + "DBPort");
665  m_pConfig->ClearValue(kDefaultMFE + "DBHostPing");
666 
667  // actually save the file
668  m_pConfig->Save();
669 
670  // Save the new settings:
671  m_DBparams = params;
672  gCoreContext->GetDB()->SetDatabaseParams(m_DBparams);
673 
674  // If database has changed, force its use:
675  ResetDatabase();
676  }
677  return ret;
678 }
679 
681 {
682  if (d && d->m_loop
683  && d->m_loop->isRunning())
684  d->m_loop->exit();
685 }
686 
687 
689 {
690  bool accepted = false;
691  if (m_gui)
692  {
693  TempMainWindow();
694 
695  // Tell the user what went wrong:
696  if (error.length())
697  ShowOkPopup(error);
698 
699  // ask user for database parameters
700 
701  EnableDBerrors();
703  DatabaseSettings *dbsetting = new DatabaseSettings();
704  StandardSettingDialog *ssd =
705  new StandardSettingDialog(mainStack, "databasesettings",
706  dbsetting);
707  if (ssd->Create())
708  {
709  mainStack->AddScreen(ssd);
710  connect(dbsetting, &DatabaseSettings::isClosing,
712  if (!m_loop->isRunning())
713  m_loop->exec();
714  }
715  else
716  delete ssd;
717  SilenceDBerrors();
718  EndTempWindow();
719  accepted = true;
720  }
721  else
722  {
724  QString response;
725  std::this_thread::sleep_for(std::chrono::seconds(1));
726  // give user chance to skip config
727  cout << endl << error.toLocal8Bit().constData() << endl << endl;
728  response = getResponse("Would you like to configure the database "
729  "connection now?",
730  "no");
731  if (!response.startsWith('y', Qt::CaseInsensitive))
732  return false;
733 
734  params.dbHostName = getResponse("Database host name:",
735  params.dbHostName);
736  response = getResponse("Should I test connectivity to this host "
737  "using the ping command?", "yes");
738  params.dbHostPing = response.startsWith('y', Qt::CaseInsensitive);
739 
740  params.dbPort = intResponse("Database non-default port:",
741  params.dbPort);
742  params.dbName = getResponse("Database name:",
743  params.dbName);
744  params.dbUserName = getResponse("Database user name:",
745  params.dbUserName);
746  params.dbPassword = getResponse("Database password:",
747  params.dbPassword);
748 
749  params.localHostName = getResponse("Unique identifier for this machine "
750  "(if empty, the local host name "
751  "will be used):",
752  params.localHostName);
753  params.localEnabled = !params.localHostName.isEmpty();
754 
755  response = getResponse("Would you like to use Wake-On-LAN to retry "
756  "database connections?",
757  (params.wolEnabled ? "yes" : "no"));
758  params.wolEnabled = response.startsWith('y', Qt::CaseInsensitive);
759 
760  if (params.wolEnabled)
761  {
762  params.wolReconnect = intResponse("Seconds to wait for "
763  "reconnection:",
764  params.wolReconnect);
765  params.wolRetry = intResponse("Number of times to retry:",
766  params.wolRetry);
767  params.wolCommand = getResponse("Command to use to wake server:",
768  params.wolCommand);
769  }
770 
771  accepted = parent->SaveDatabaseParams(params);
772  }
773  return accepted;
774 }
775 
782 {
783  QString err = QString::null;
784  QString host;
785 
786  // Jan 20, 2017
787  // Changed to use port check instead of ping
788 
789  int port;
790 
791  // 1 = db awake, 2 = db listening, 3 = db connects,
792  // 4 = backend awake, 5 = backend listening
793  // 9 = all ok, 10 = quit
794 
795  enum startupStates {
796  st_start = 0,
797  st_dbAwake = 1,
798  st_dbStarted = 2,
799  st_dbConnects = 3,
800  st_beWOL = 4,
801  st_beAwake = 5,
802  st_success = 6
803  } startupState = st_start;
804 
805  static const QString guiStatuses[7] =
806  {"start","dbAwake","dbStarted","dbConnects","beWOL","beAwake",
807  "success" };
808 
809  do
810  {
811  host = m_DBparams.dbHostName;
812  port = m_DBparams.dbPort;
813  if (port == 0)
814  port = 3306;
815  int wakeupTime = 3;
816  int attempts = 11;
817  if (m_DBparams.wolEnabled) {
818  wakeupTime = m_DBparams.wolReconnect;
819  attempts = m_DBparams.wolRetry + 1;
820  startupState = st_start;
821  }
822  else
823  startupState = st_dbAwake;
824  if (attempts < 6)
825  attempts = 6;
826  if (!prompt)
827  attempts=1;
828  if (wakeupTime < 5)
829  wakeupTime = 5;
830 
831  int progressTotal = wakeupTime * attempts;
832 
834  m_guiStartup->setTotal(progressTotal);
835 
836  QString beWOLCmd = QString();
837  QString backendIP = QString();
838  int backendPort = 0;
839  QString masterserver;
840 
841  for (int attempt = 0;
842  attempt < attempts && startupState != st_success;
843  ++attempt)
844  {
845  // The first time do everything with minimum timeout and
846  // no GUI, for the normal case where all is OK
847  // After that show the GUI (if this is a GUI program)
848 
849  LOG(VB_GENERAL, LOG_INFO,
850  QString("Start up testing connections. DB %1, BE %2, attempt %3, status %4")
851  .arg(host).arg(backendIP).arg(attempt).arg(guiStatuses[startupState]));
852 
853  int useTimeout = wakeupTime;
854  if (attempt == 0)
855  useTimeout=1;
856 
857  if (m_gui && !m_guiStartup)
858  {
859  if (attempt > 0)
860  {
861  ShowGuiStartup();
862  if (m_guiStartup)
863  m_guiStartup->setTotal(progressTotal);
864  }
865  }
867  {
868  if (attempt > 0)
869  m_guiStartup->setStatusState(guiStatuses[startupState]);
870  m_guiStartup->setMessageState("empty");
871  processEvents();
872  }
873  switch (startupState) {
874  case st_start:
876  {
877  if (attempt > 0)
879  if (!checkPort(host, port, useTimeout))
880  break;
881  }
882  startupState = st_dbAwake;
883  // Fall through to next case
884  case st_dbAwake:
885  if (!checkPort(host, port, useTimeout))
886  break;
887  startupState = st_dbStarted;
888  // Fall through to next case
889  case st_dbStarted:
890  // If the database is connecting with link-local
891  // address, it may have changed
892  if (m_DBparams.dbHostName != host)
893  {
894  m_DBparams.dbHostName = host;
895  gCoreContext->GetDB()->SetDatabaseParams(m_DBparams);
896  }
897  EnableDBerrors();
898  ResetDatabase();
900  {
901  for (int temp = 0; temp < useTimeout * 2 ; temp++)
902  {
903  processEvents();
904  std::this_thread::sleep_for(std::chrono::milliseconds(500));
905  }
906  break;
907  }
908  startupState = st_dbConnects;
909  // Fall through to next case
910  case st_dbConnects:
911  if (needsBackend)
912  {
913  beWOLCmd = gCoreContext->GetSetting("WOLbackendCommand", "");
914  if (!beWOLCmd.isEmpty())
915  {
916  wakeupTime += gCoreContext->GetNumSetting
917  ("WOLbackendReconnectWaitTime", 0);
918  attempts += gCoreContext->GetNumSetting
919  ("WOLbackendConnectRetry", 0);
920  useTimeout = wakeupTime;
921  if (m_gui && !m_guiStartup && attempt == 0)
922  useTimeout=1;
923  progressTotal = wakeupTime * attempts;
925  m_guiStartup->setTotal(progressTotal);
926  startupState = st_beWOL;
927  }
928  }
929  else {
930  startupState = st_success;
931  break;
932  }
933  masterserver = gCoreContext->GetSetting
934  ("MasterServerName");
935  backendIP = gCoreContext->GetSettingOnHost
936  ("BackendServerAddr", masterserver);
937  backendPort = gCoreContext->GetMasterServerPort();
938  // Fall through to next case
939  case st_beWOL:
940  if (!beWOLCmd.isEmpty()) {
941  if (attempt > 0)
942  myth_system(beWOLCmd);
943  if (!checkPort(backendIP, backendPort, useTimeout))
944  break;
945  }
946  startupState = st_beAwake;
947  // Fall through to next case
948  case st_beAwake:
949  if (!checkPort(backendIP, backendPort, useTimeout))
950  break;
951  startupState = st_success;
952  }
953  if (m_guiStartup)
954  {
955  if (m_guiStartup->m_Exit
958  || m_guiStartup->m_Retry)
959  break;
960  }
961  processEvents();
962  }
963  if (startupState == st_success)
964  break;
965 
966  QString stateMsg = guiStatuses[startupState];
967  stateMsg.append("Fail");
968  LOG(VB_GENERAL, LOG_INFO,
969  QString("Start up failure. host %1, status %2")
970  .arg(host).arg(stateMsg));
971 
972  if (m_guiStartup
973  && !m_guiStartup->m_Exit
974  && !m_guiStartup->m_Setup
976  && !m_guiStartup->m_Retry)
977  {
979  m_guiStartup->setStatusState(stateMsg);
980  m_guiStartup->setMessageState("makeselection");
981  m_loop->exec();
982  }
983  }
984  while (m_guiStartup && m_guiStartup->m_Retry);
985 
986  if (startupState < st_dbAwake)
987  {
988  LOG(VB_GENERAL, LOG_WARNING, QString("Pinging to %1 failed, database will be unavailable").arg(host));
989  SilenceDBerrors();
990  err = QObject::tr(
991  "Cannot find (ping) database host %1 on the network",
992  "Backend Setup");
993  return err.arg(host);
994  }
995 
996  if (startupState < st_dbConnects)
997  {
998  SilenceDBerrors();
999  return QObject::tr("Cannot login to database", "Backend Setup");
1000  }
1001 
1002  if (startupState < st_success)
1003  {
1004  return QObject::tr("Cannot connect to backend", "Backend Setup");
1005  }
1006 
1007  // Current DB connection may have been silenced (invalid):
1008  EnableDBerrors();
1009  ResetDatabase();
1011 
1012  return QString::null;
1013 }
1014 
1015 // Show the Gui Startup window.
1016 // This is called if there is a delay in startup for any reason
1017 // such as the database being unavailable
1019 {
1020  if (!m_gui)
1021  return;
1022  TempMainWindow(false);
1023  MythMainWindow *mainWindow = GetMythMainWindow();
1024  MythScreenStack *mainStack = mainWindow->GetMainStack();
1025  if (mainStack) {
1026  if (!m_guiStartup) {
1027  m_guiStartup = new GUIStartup(mainStack,m_loop);
1028  if (!m_guiStartup->Create()) {
1029  delete m_guiStartup;
1030  m_guiStartup = 0;
1031  }
1032  if (m_guiStartup) {
1033  mainStack->AddScreen(m_guiStartup, false);
1034  processEvents();
1035  }
1036  }
1037  }
1038 }
1039 
1049 {
1050  // This silences any DB errors from Get*Setting(),
1051  // (which is the vast majority of them)
1052  gCoreContext->GetDB()->SetSuppressDBMessages(true);
1053 
1054  // Save the configured hostname, so that we can
1055  // still display it in the DatabaseSettings screens
1056  if (m_DBparams.dbHostName.length())
1058 
1059  m_DBparams.dbHostName.clear();
1060  gCoreContext->GetDB()->SetDatabaseParams(m_DBparams);
1061 }
1062 
1064 {
1065  // Restore (possibly) blanked hostname
1066  if (m_DBparams.dbHostName.isNull() && m_DBhostCp.length())
1067  {
1069  gCoreContext->GetDB()->SetDatabaseParams(m_DBparams);
1070  }
1071 
1072  gCoreContext->GetDB()->SetSuppressDBMessages(false);
1073 }
1074 
1075 
1088 {
1090  gCoreContext->GetDB()->SetDatabaseParams(m_DBparams);
1092 }
1093 
1098 {
1099  TempMainWindow();
1100 
1101  // Tell the user what went wrong:
1102  if (!error.isEmpty())
1103  {
1104  LOG(VB_GENERAL, LOG_ERR, QString("Error: %1").arg(error));
1105  ShowOkPopup(error);
1106  }
1107 
1108  LOG(VB_GENERAL, LOG_INFO, "Putting up the UPnP backend chooser");
1109 
1112 
1113  EndTempWindow();
1114 
1115  return (int)ret;
1116 }
1117 
1124 int MythContextPrivate::UPnPautoconf(const int milliSeconds)
1125 {
1126  LOG(VB_GENERAL, LOG_INFO, QString("UPNP Search %1 secs")
1127  .arg(milliSeconds / 1000));
1128 
1129  SSDP::Instance()->PerformSearch(gBackendURI, milliSeconds / 1000);
1130 
1131  // Search for a total of 'milliSeconds' ms, sending new search packet
1132  // about every 250 ms until less than one second remains.
1133  MythTimer totalTime; totalTime.start();
1134  MythTimer searchTime; searchTime.start();
1135  while (totalTime.elapsed() < milliSeconds)
1136  {
1137  usleep(25000);
1138  int ttl = milliSeconds - totalTime.elapsed();
1139  if ((searchTime.elapsed() > 249) && (ttl > 1000))
1140  {
1141  LOG(VB_GENERAL, LOG_INFO, QString("UPNP Search %1 secs")
1142  .arg(ttl / 1000));
1143  SSDP::Instance()->PerformSearch(gBackendURI, ttl / 1000);
1144  searchTime.start();
1145  }
1146  }
1147 
1149 
1150  if (!backends)
1151  {
1152  LOG(VB_GENERAL, LOG_INFO, "No UPnP backends found");
1153  return 0;
1154  }
1155 
1156  int count = backends->Count();
1157  if (count)
1158  {
1159  LOG(VB_GENERAL, LOG_INFO,
1160  QString("Found %1 UPnP backends").arg(count));
1161  }
1162  else
1163  {
1164  LOG(VB_GENERAL, LOG_ERR,
1165  "No UPnP backends found, but SSDP::Find() not NULL");
1166  }
1167 
1168  if (count != 1)
1169  {
1170  backends->DecrRef();
1171  return count;
1172  }
1173 
1174  // Get this backend's location:
1175  DeviceLocation *BE = backends->GetFirst();
1176  backends->DecrRef();
1177  backends = NULL;
1178 
1179  // We don't actually know the backend's access PIN, so this will
1180  // only work for ones that have PIN access disabled (i.e. 0000)
1181  int ret = (UPnPconnect(BE, QString::null)) ? 1 : -1;
1182 
1183  BE->DecrRef();
1184 
1185  return ret;
1186 }
1187 
1194 {
1195  QString loc = "DefaultUPnP() - ";
1196  QString PIN = m_pConfig->GetValue(kDefaultPIN, "");
1197  QString USN = m_pConfig->GetValue(kDefaultUSN, "");
1198 
1199  if (USN.isEmpty())
1200  {
1201  LOG(VB_UPNP, LOG_INFO, loc + "No default UPnP backend");
1202  return false;
1203  }
1204 
1205  LOG(VB_UPNP, LOG_INFO, loc + "config.xml has default " +
1206  QString("PIN '%1' and host USN: %2") .arg(PIN).arg(USN));
1207 
1208  // ----------------------------------------------------------------------
1209 
1210  int timeout_ms = 2000;
1211  LOG(VB_GENERAL, LOG_INFO, QString("UPNP Search up to %1 secs")
1212  .arg(timeout_ms / 1000));
1213  SSDP::Instance()->PerformSearch(gBackendURI, timeout_ms / 1000);
1214 
1215  // ----------------------------------------------------------------------
1216  // We need to give the server time to respond...
1217  // ----------------------------------------------------------------------
1218 
1219  DeviceLocation *pDevLoc = NULL;
1220  MythTimer totalTime; totalTime.start();
1221  MythTimer searchTime; searchTime.start();
1222  while (totalTime.elapsed() < timeout_ms)
1223  {
1224  pDevLoc = SSDP::Instance()->Find( gBackendURI, USN );
1225 
1226  if (pDevLoc)
1227  break;
1228 
1229  usleep(25000);
1230 
1231  int ttl = timeout_ms - totalTime.elapsed();
1232  if ((searchTime.elapsed() > 249) && (ttl > 1000))
1233  {
1234  LOG(VB_GENERAL, LOG_INFO, QString("UPNP Search up to %1 secs")
1235  .arg(ttl / 1000));
1236  SSDP::Instance()->PerformSearch(gBackendURI, ttl / 1000);
1237  searchTime.start();
1238  }
1239  }
1240 
1241  // ----------------------------------------------------------------------
1242 
1243  if (!pDevLoc)
1244  {
1245  error = "Cannot find default UPnP backend";
1246  return false;
1247  }
1248 
1249  if (UPnPconnect(pDevLoc, PIN))
1250  {
1251  pDevLoc->DecrRef();
1252  return true;
1253  }
1254 
1255  pDevLoc->DecrRef();
1256 
1257  error = "Cannot connect to default backend via UPnP. Wrong saved PIN?";
1258  return false;
1259 }
1260 
1265  const QString &PIN)
1266 {
1267  QString error;
1268  QString loc = "UPnPconnect() - ";
1269  QString URL = backend->m_sLocation;
1270  MythXMLClient client(URL);
1271 
1272  LOG(VB_UPNP, LOG_INFO, loc + QString("Trying host at %1").arg(URL));
1273  switch (client.GetConnectionInfo(PIN, &m_DBparams, error))
1274  {
1275  case UPnPResult_Success:
1276  gCoreContext->GetDB()->SetDatabaseParams(m_DBparams);
1277  LOG(VB_UPNP, LOG_INFO, loc +
1278  "Got database hostname: " + m_DBparams.dbHostName);
1279  return true;
1280 
1282  // The stored PIN is probably not correct.
1283  // We could prompt for the PIN and try again, but that needs a UI.
1284  // Easier to fail for now, and put up the full UI selector later
1285  LOG(VB_UPNP, LOG_ERR, loc + "Wrong PIN?");
1286  return false;
1287 
1288  default:
1289  LOG(VB_UPNP, LOG_ERR, loc + error);
1290  break;
1291  }
1292 
1293  // This backend may have a local DB with the default user/pass/DBname.
1294  // For whatever reason, we have failed to get anything back via UPnP,
1295  // so we might as well try the database directly as a last resort.
1296  QUrl theURL(URL);
1297  URL = theURL.host();
1298  if (URL.isEmpty())
1299  return false;
1300 
1301  LOG(VB_UPNP, LOG_INFO, "Trying default DB credentials at " + URL);
1303 
1304  return true;
1305 }
1306 
1308 {
1309  if (e->type() == (QEvent::Type) MythEvent::MythEventMessage)
1310  {
1311  if (disableeventpopup)
1312  return true;
1313 
1315  {
1317  }
1318 
1319  MythEvent *me = (MythEvent*)e;
1320  if (me->Message() == "VERSION_MISMATCH" && (1 == me->ExtraDataCount()))
1321  ShowVersionMismatchPopup(me->ExtraData(0).toUInt());
1322  else if (me->Message() == "CONNECTION_FAILURE")
1324  else if (me->Message() == "PERSISTENT_CONNECTION_FAILURE")
1326  else if (me->Message() == "CONNECTION_RESTABLISHED")
1328  return true;
1329  }
1330 
1331  return QObject::event(e);
1332 }
1333 
1335 {
1336  QDateTime now = MythDate::current();
1337 
1338  if (!GetNotificationCenter() || !m_ui || !m_ui->IsScreenSetup())
1339  return;
1340 
1341  if (m_lastCheck.isValid() && now < m_lastCheck)
1342  return;
1343 
1344  // When WOL is disallowed, standy mode,
1345  // we should not show connection failures.
1346  if (!gCoreContext->IsWOLAllowed())
1347  return;
1348 
1349  m_lastCheck = now.addMSecs(5000); // don't refresh notification more than every 5s
1350 
1351  QString description = (persistent) ?
1352  QObject::tr(
1353  "The connection to the master backend "
1354  "server has gone away for some reason. "
1355  "Is it running?") :
1356  QObject::tr(
1357  "Could not connect to the master backend server. Is "
1358  "it running? Is the IP address set for it in "
1359  "mythtv-setup correct?");
1360 
1361  QString message = QObject::tr("Could not connect to master backend");
1362  MythErrorNotification n(message, _Location, description);
1363  n.SetId(m_registration);
1364  n.SetParent(this);
1366 }
1367 
1369 {
1370  if (!GetNotificationCenter())
1371  return;
1372 
1373  if (!m_lastCheck.isValid())
1374  return;
1375 
1376  MythCheckNotification n(QObject::tr("Backend is online"), _Location);
1377  n.SetId(m_registration);
1378  n.SetParent(this);
1379  n.SetDuration(5);
1381  m_lastCheck = QDateTime();
1382 }
1383 
1385 {
1386  if (MBEversionPopup)
1387  return;
1388 
1389  QString message =
1390  QObject::tr(
1391  "The server uses network protocol version %1, "
1392  "but this client only understands version %2. "
1393  "Make sure you are running compatible versions of "
1394  "the backend and frontend.")
1395  .arg(remote_version).arg(MYTH_PROTO_VERSION);
1396 
1397  if (HasMythMainWindow() && m_ui && m_ui->IsScreenSetup())
1398  {
1400  message, m_sh, SLOT(VersionMismatchPopupClosed()));
1401  }
1402  else
1403  {
1404  LOG(VB_GENERAL, LOG_ERR, LOC + message);
1405  qApp->exit(GENERIC_EXIT_SOCKET_ERROR);
1406  }
1407 }
1408 
1409 // Process Events while waiting for connection
1410 // return true if progress is 100%
1412 {
1413 // bool ret = false;
1414 // if (m_guiStartup)
1415 // ret = m_guiStartup->updateProgress();
1416  qApp->processEvents(QEventLoop::AllEvents, 250);
1417  qApp->processEvents(QEventLoop::AllEvents, 250);
1418 // return ret;
1419 }
1420 
1421 // cache some settings in cache/contextcache.xml
1422 // only call this if the database is available.
1423 
1424 const QString MythContextPrivate::settingsToSave[] =
1425 { "Theme", "Language", "Country", "GuiHeight",
1426  "GuiOffsetX", "GuiOffsetY", "GuiWidth", "RunFrontendInWindow" };
1427 
1428 
1430 {
1431  QString cacheDirName = GetConfDir() + "/cache/";
1432  QDir dir(cacheDirName);
1433  dir.mkpath(cacheDirName);
1434  // remove prior cache in case it was corrupt
1435  QFile::remove(cacheDirName+"contextcache.xml");
1436  XmlConfiguration config = XmlConfiguration("cache/contextcache.xml");
1437 
1439 
1440  static const int arraySize = sizeof(settingsToSave)/sizeof(settingsToSave[0]);
1441  for (int ix = 0; ix < arraySize; ix++)
1442  {
1443  QString value = gCoreContext->GetSetting(settingsToSave[ix],QString());
1444  if (!value.isEmpty())
1445  config.SetValue("Settings/"+settingsToSave[ix],value);
1446  }
1447  return config.Save();
1448 }
1449 
1451 {
1452  XmlConfiguration config = XmlConfiguration("cache/contextcache.xml");
1453  static const int arraySize = sizeof(settingsToSave)/sizeof(settingsToSave[0]);
1454  for (int ix = 0; ix < arraySize; ix++)
1455  {
1456  QString value = config.GetValue("Settings/"+settingsToSave[ix],QString());
1457  if (!value.isEmpty())
1459  }
1460  // Prevent power off TV after temporary window
1461  gCoreContext->OverrideSettingForSession("PowerOffTVAllowed", 0);
1462 
1463  QString language = gCoreContext->GetSetting("Language",QString());
1464  MythTranslation::load("mythfrontend");
1465 }
1466 
1468 {
1469  QString language = gCoreContext->GetSetting("Language",QString());
1470  static const int arraySize = sizeof(settingsToSave)/sizeof(settingsToSave[0]);
1471  for (int ix = 0; ix < arraySize; ix++)
1472  {
1474  }
1475  // Restore power off TV setting
1476  gCoreContext->ClearOverrideSettingForSession("PowerOffTVAllowed");
1477 
1478  if (language != gCoreContext->GetSetting("Language",QString()))
1479  MythTranslation::load("mythfrontend");
1480 }
1481 
1482 
1484 {
1485  d->MBEversionPopup = NULL;
1486  qApp->exit(GENERIC_EXIT_SOCKET_ERROR);
1487 }
1488 
1489 MythContext::MythContext(const QString &binversion, bool needsBackend)
1490  : d(NULL), app_binary_version(binversion)
1491 {
1492 #ifdef _WIN32
1493  static bool WSAStarted = false;
1494  if (!WSAStarted) {
1495  WSADATA wsadata;
1496  int res = WSAStartup(MAKEWORD(2, 0), &wsadata);
1497  LOG(VB_SOCKET, LOG_INFO,
1498  QString("WSAStartup returned %1").arg(res));
1499  }
1500 #endif
1501 
1502  d = new MythContextPrivate(this);
1503  d->needsBackend = needsBackend;
1504 
1506 
1507  if (!gCoreContext || !gCoreContext->Init())
1508  {
1509  LOG(VB_GENERAL, LOG_EMERG, LOC + "Unable to allocate MythCoreContext");
1510  qApp->exit(GENERIC_EXIT_NO_MYTHCONTEXT);
1511  }
1512 }
1513 
1514 bool MythContext::Init(const bool gui,
1515  const bool promptForBackend,
1516  const bool disableAutoDiscovery,
1517  const bool ignoreDB)
1518 {
1519  if (!d)
1520  {
1521  LOG(VB_GENERAL, LOG_EMERG, LOC + "Init() Out-of-memory");
1522  return false;
1523  }
1524 
1525  if (app_binary_version != MYTH_BINARY_VERSION)
1526  {
1527  LOG(VB_GENERAL, LOG_EMERG,
1528  QString("Application binary version (%1) does not "
1529  "match libraries (%2)")
1530  .arg(app_binary_version) .arg(MYTH_BINARY_VERSION));
1531 
1532  QString warning = QObject::tr(
1533  "This application is not compatible "
1534  "with the installed MythTV libraries.");
1535  if (gui)
1536  {
1537  d->TempMainWindow(false);
1538  ShowOkPopup(warning);
1539  }
1540  LOG(VB_GENERAL, LOG_WARNING, warning);
1541 
1542  return false;
1543  }
1544 
1545 #ifdef _WIN32
1546  // HOME environment variable might not be defined
1547  // some libraries will fail without it
1548  QString home = getenv("HOME");
1549  if (home.isEmpty())
1550  {
1551  home = getenv("LOCALAPPDATA"); // Vista
1552  if (home.isEmpty())
1553  home = getenv("APPDATA"); // XP
1554  if (home.isEmpty())
1555  home = QString("."); // getenv("TEMP")?
1556 
1557  _putenv(QString("HOME=%1").arg(home).toLocal8Bit().constData());
1558  }
1559 #endif
1560 
1561  // If HOME isn't defined, we won't be able to use default confdir of
1562  // $HOME/.mythtv nor can we rely on a MYTHCONFDIR that references $HOME
1563  QString homedir = QDir::homePath();
1564  QString confdir = getenv("MYTHCONFDIR");
1565  if ((homedir.isEmpty() || homedir == "/") &&
1566  (confdir.isEmpty() || confdir.contains("$HOME")))
1567  {
1568  QString warning = "Cannot locate your home directory."
1569  " Please set the environment variable HOME";
1570  if (gui)
1571  {
1572  d->TempMainWindow(false);
1573  ShowOkPopup(warning);
1574  }
1575  LOG(VB_GENERAL, LOG_WARNING, warning);
1576 
1577  return false;
1578  }
1579 
1580  if (!d->Init(gui, promptForBackend, disableAutoDiscovery, ignoreDB))
1581  {
1582  return false;
1583  }
1584 
1586 
1587  return true;
1588 }
1589 
1591 {
1592  if (MThreadPool::globalInstance()->activeThreadCount())
1593  LOG(VB_GENERAL, LOG_INFO, "Waiting for threads to exit.");
1594 
1596  logStop();
1597 
1598  SSDP::Shutdown();
1600 
1601  delete gCoreContext;
1602  gCoreContext = NULL;
1603 
1604  delete d;
1605 }
1606 
1608 {
1609  d->disableeventpopup = check;
1610 }
1611 
1613 {
1614  return d->m_DBparams;
1615 }
1616 
1618 {
1619  return d->SaveDatabaseParams(params, false);
1620 }
1621 
1623 {
1624  return d->saveSettingsCache();
1625 }
1626 
1627 /* vim: set expandtab tabstop=4 shiftwidth=4: */
void SaveLocaleDefaults(void)
void ShowGuiStartup(void)
virtual bool Save(void)
Startup context for MythTV.
Definition: mythcontext.h:42
void SetParent(void *parent)
contains the parent address.
bool wolEnabled
true if wake-on-lan params are used
Definition: mythdbparams.h:32
virtual int GetValue(const QString &sSetting, int Default)=0
bool setStatusState(const QString &name)
Definition: guistartup.cpp:122
int intResponse(const QString &query, int def)
In an interactive shell, prompt the user to input a number.
virtual int GetValue(const QString &sSetting, int Default)
unsigned int slots[4]
Definition: element.c:38
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:13
QString wolCommand
command to use for wake-on-lan
Definition: mythdbparams.h:35
static void configplugin_cb(const QString &cmd)
QString dbName
database name
Definition: mythdbparams.h:26
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:83
QString app_binary_version
Definition: mythcontext.h:61
void LoadQtConfig(void)
Dialog asking for user confirmation.
int UPnPautoconf(const int milliSeconds=2000)
If there is only a single UPnP backend, use it.
void EndTempWindow(void)
MythConfirmationDialog * ShowOkPopup(const QString &message, QObject *parent, const char *slot, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
virtual void ClearValue(const QString &sSetting)=0
void SetId(int id)
Optional MythNotification elements.
bool setMessageState(const QString &name)
Definition: guistartup.cpp:132
static void exec_program_tv_cb(const QString &cmd)
const QString kDefaultWOL
Definition: backendselect.h:23
static Type MythEventMessage
Definition: mythevent.h:65
static void error(const char *str,...)
Definition: vbi.c:41
virtual void SetValue(const QString &sSetting, int value)
int GetMasterServerPort(void)
static void ejectOpticalDisc(void)
Eject a disk, unmount a drive, open a tray.
bool Create(void)
Definition: guistartup.cpp:82
static MythMainWindow * getMainWindow(const bool useDB=true)
Return the existing main window, or create one.
const QString gBackendURI
Service type for the backend&#39;s UPnP server.
Definition: backendselect.h:21
void isClosing(void)
static const char URL[]
Definition: cddb.cpp:29
bool m_Retry
Definition: guistartup.h:56
void UnRegister(void *from, int id, bool closeimemdiately=false)
Unregister the client.
bool IsFrontend(void) const
is this process a frontend process
QString GetSettingOnHost(const QString &key, const QString &host, const QString &defaultval="")
bool SaveDatabaseParams(const DatabaseParams &params, bool force)
void DestroyMythMainWindow(void)
void SetDisableEventPopup(bool check)
bool IsScreenSetup(void)
unsigned int uint
Definition: compat.h:136
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static Decision Prompt(DatabaseParams *dbParams, Configuration *pConfig)
MythScreenStack * GetMainStack()
DatabaseParams GetDatabaseParams(void)
bool saveSettingsCache(void)
void waitForDone(void)
bool localEnabled
true if localHostName is not default
Definition: mythdbparams.h:29
MythContext * gContext
This global variable contains the MythContext instance for the application.
Definition: mythcontext.cpp:59
bool Init(const bool gui, const bool prompt, const bool noPrompt, const bool ignoreDB)
void DestroyMythUI()
void SetLocalHostname(const QString &hostname)
const QString kDefaultDB
Definition: backendselect.h:22
void(* exec_program)(const QString &cmd)
Definition: mythuihelper.h:35
bool checkPort(QString &host, int port, int wakeupTime)
Check if a port is open and sort out the link-local scope.
QString dbPassword
DB password.
Definition: mythdbparams.h:25
bool checkPort(QString &host, int port, int timeLimit=30000, bool linkLocalOnly=false)
Check if a port is open and sort out the link-local scope.
Definition: portchecker.cpp:81
QString GetConfDir(void)
Definition: mythdirs.cpp:212
static void Shutdown()
Definition: taskqueue.cpp:76
void Init(MythUIMenuCallbacks &cbs)
MythContextPrivate(MythContext *lparent)
static void eject_cb(void)
bool FindDatabase(const bool prompt, const bool noPrompt)
Get database connection settings and test connectivity.
bool config_plugin(const QString &plugname)
Definition: mythplugin.cpp:202
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
MythContext * parent
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
MythContextSlotHandler * m_sh
QString dbUserName
DB user name.
Definition: mythdbparams.h:24
__u32 addr
Definition: videodev2.h:1040
DeviceLocation * GetFirst(void)
Returns random entry in cache, returns NULL when list is empty.
Definition: ssdpcache.cpp:72
bool Init(const bool gui=true, const bool promptForBackend=false, const bool bypassAutoDiscovery=false, const bool ignoreDB=false)
static void plugin_cb(const QString &cmd)
void PerformSearch(const QString &sST, uint timeout_secs=2)
Definition: ssdp.cpp:214
MythPluginManager * GetPluginManager(void)
This class is used as a container for messages.
Definition: mythevent.h:15
void ClearOverrideSettingForSession(const QString &key)
void EnableDBerrors(void)
void VersionMismatchPopupClosed(void)
int ChooseBackend(const QString &error)
Search for backends via UPnP, put up a UI for the user to choose one.
QString TestDBconnection(bool prompt=true)
Some quick sanity checks before opening a database connection.
uint Count(void) const
Definition: ssdpcache.h:44
void setTotal(int total)
Definition: guistartup.cpp:143
bool PromptForDatabaseParams(const QString &error)
static const uint16_t * d
void OverrideSettingForSession(const QString &key, const QString &value)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
QString GetSetting(const QString &key, const QString &defaultval="")
DatabaseParams m_DBparams
Current database host & WOL details.
MythContext(const QString &binversion, bool needsBackend=false)
void SetDuration(int duration)
contains a duration during which the notification will be displayed for.
bool m_Setup
Definition: guistartup.h:55
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
virtual bool Save(void)=0
bool updateProgress(bool finished=false)
Definition: guistartup.cpp:160
QEventLoop * m_loop
MythContextPrivate * d
Definition: mythcontext.h:60
static void load(const QString &module_name)
Load a QTranslator for the user&#39;s preferred language.
MythConfirmationDialog * MBEversionPopup
void ShowNotificationError(const QString &msg, const QString &from, const QString &detail, const VNMask visibility, const MythNotification::Priority priority)
convenience utility to display error message as notification
Small class to handle TCP port checking and finding link-local context.
Definition: portchecker.h:43
static bool testDBConnection()
Checks DB connection + login (login info via Mythcontext)
Definition: mythdbcon.cpp:885
void(* configplugin)(const QString &cmd)
Definition: mythuihelper.h:37
bool Queue(const MythNotification &notification)
Queue a notification Queue() is thread-safe and can be called from anywhere.
bool dbHostPing
Can we test connectivity using ping?
Definition: mythdbparams.h:22
string hostname
Definition: caa.py:17
void TempMainWindow(bool languagePrompt=true)
Setup a minimal themed main window, and prompt for user&#39;s language.
void Init(QString forcedpainter=QString())
QString m_masterhostname
master backend hostname
QString m_DBhostCp
dbHostName backup
QString getResponse(const QString &query, const QString &def)
In an interactive shell, prompt the user to input a string.
static bool prompt(bool force=false)
Ask the user for the language to use.
uint myth_system(const QString &command, uint flags, uint timeout)
static const QString _Location
Definition: mythcontext.cpp:61
bool LoadDatabaseSettings(void)
Load database and host settings from config.xml, or set some defaults.
bool IsValid(const QString &source=QString("Unknown")) const
MythUIHelper * GetMythUI()
void SilenceDBerrors(void)
Cause MSqlDatabase::OpenDatabase() and MSqlQuery to fail silently.
int wolReconnect
seconds to wait for reconnect
Definition: mythdbparams.h:33
bool HasMythMainWindow(void)
MythMainWindow * GetMythMainWindow(void)
void clearSettingsCacheOverride(void)
int elapsed(void) const
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:90
bool m_Exit
Definition: guistartup.h:54
static MThreadPool * globalInstance(void)
static void exec_program_cb(const QString &cmd)
bool SaveDatabaseParams(const DatabaseParams &params)
int Register(void *from)
An application can register in which case it will be assigned a reusable screen, which can be modifie...
bool event(QEvent *)
int GetNumSetting(const QString &key, int defaultval=0)
static const QString settingsToSave[]
bool UPnPconnect(const DeviceLocation *device, const QString &PIN)
Query a backend via UPnP for its database connection parameters.
Structure containing the basic Database parameters.
Definition: mythdbparams.h:9
QString m_sLocation
Definition: upnpdevice.h:232
QString dbHostName
database server
Definition: mythdbparams.h:21
void LoadDefaults(void)
Load sensible connection defaults.
Definition: mythdbparams.cpp:5
static SSDP * Instance()
Definition: ssdp.cpp:54
bool forceSave
set to true to force a save of the settings file
Definition: mythdbparams.h:37
const QString & ExtraData(int idx=0) const
Definition: mythevent.h:58
void(* eject)(void)
Definition: mythuihelper.h:39
void logStop(void)
Entry point for stopping logging for an application.
Definition: logging.cpp:953
Configuration * m_pConfig
UPnPResultCode GetConnectionInfo(const QString &sPin, DatabaseParams *pParams, QString &sMsg)
QTcpSocket * m_socket
void(* plugin)(const QString &cmd)
Definition: mythuihelper.h:38
const QString kDefaultPIN
Definition: backendselect.h:25
void ClearSettingsCache(const QString &myKey=QString(""))
static MythPluginManager * pmanager
bool IsWOLAllowed() const
bool saveSettingsCache(void)
MythDB * GetDB(void)
MDBManager * GetDBManager(void)
void loadSettingsCacheOverride(void)
static const QString LOC
void HideConnectionFailurePopup(void)
virtual void PopScreen(MythScreenType *screen=NULL, bool allowFade=true, bool deleteScreen=true)
const QString kDefaultUSN
Definition: backendselect.h:26
int ExtraDataCount() const
Definition: mythevent.h:60
bool m_Search
Definition: guistartup.h:57
MythUIHelper * m_ui
static SSDPCacheEntries * Find(const QString &sURI)
Definition: ssdp.h:129
const QString kDefaultMFE
Definition: backendselect.h:24
void(* exec_program_tv)(const QString &cmd)
Definition: mythuihelper.h:36
void ResetDatabase(void)
Called when the user changes the DB connection settings.
const QString & Message() const
Definition: mythevent.h:57
QString localHostName
name used for loading/saving settings
Definition: mythdbparams.h:30
void ActivateSettingsCache(bool activate=true)
int dbPort
database port
Definition: mythdbparams.h:23
void processEvents(void)
GUIStartup * m_guiStartup
void ShowConnectionFailurePopup(bool persistent)
__s32 value
Definition: videodev2.h:1042
void ShowVersionMismatchPopup(uint remoteVersion)
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
void CloseDatabases(void)
Definition: mythdbcon.cpp:483
virtual ~MythContext()
int wolRetry
times to retry to reconnect
Definition: mythdbparams.h:34
bool DefaultUPnP(QString &error)
Get the default backend from config.xml, use UPnP to find it.
static QString confdir
Definition: mythdirs.cpp:20
This class contains the runtime context for MythTV.
static void Shutdown()
Definition: ssdp.cpp:64
MythNotificationCenter * GetNotificationCenter(void)
bool run_plugin(const QString &plugname)
Definition: mythplugin.cpp:184
void InitializeMythDirs(void)
Definition: mythdirs.cpp:26
virtual void SetValue(const QString &sSetting, int value)=0
bool m_gui
Should this context use GUI elements?