MythTV  master
myth.cpp
Go to the documentation of this file.
1 // Program Name: myth.cpp
3 // Created : Jan. 19, 2010
4 //
5 // Copyright (c) 2010 David Blain <dblain@mythtv.org>
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 //
25 
26 #include "myth.h"
27 #include <backendcontext.h>
28 
29 #include <QDir>
30 #include <QFileInfo>
31 #include <QCryptographicHash>
32 #include <QHostAddress>
33 #include <QUdpSocket>
34 
35 #include "config.h"
36 #include "version.h"
37 #include "mythversion.h"
38 #include "mythcorecontext.h"
39 #include "mythcoreutil.h"
40 #include "mythdbcon.h"
41 #include "mythlogging.h"
42 #include "storagegroup.h"
43 #include "dbutil.h"
44 #include "hardwareprofile.h"
45 #include "mythtimezone.h"
46 #include "mythdate.h"
47 #include "mythversion.h"
48 #include "serviceUtil.h"
49 
51 //
53 
55 {
56  QString sSecurityPin = gCoreContext->GetSetting( "SecurityPin", "");
57 
58  if ( sSecurityPin.isEmpty() )
59  throw( QString( "No Security Pin assigned. Run mythtv-setup to set one." ));
60  //SB: UPnPResult_HumanInterventionRequired,
61 
62  if ((sSecurityPin != "0000" ) && ( sPin != sSecurityPin ))
63  throw( QString( "Not Authorized" ));
64  //SB: UPnPResult_ActionNotAuthorized );
65 
67 
68  // ----------------------------------------------------------------------
69  // Check for DBHostName of "localhost" and change to public name or IP
70  // ----------------------------------------------------------------------
71 
72  QString sServerIP = gCoreContext->GetBackendServerIP();
73  //QString sPeerIP = pRequest->GetPeerAddress();
74 
75  if ((params.dbHostName.compare("localhost",Qt::CaseInsensitive)==0
76  || params.dbHostName == "127.0.0.1"
77  || params.dbHostName == "::1")
78  && !sServerIP.isEmpty()) // &&
79  //(sServerIP != sPeerIP ))
80  {
81  params.dbHostName = sServerIP;
82  }
83 
84  // If dbHostName is an IPV6 address with scope,
85  // remove the scope. Unescaped % signs are an
86  // xml violation
87  QString dbHostName(params.dbHostName);
88  QHostAddress addr;
89  if (addr.setAddress(dbHostName))
90  {
91  addr.setScopeId(QString());
92  dbHostName = addr.toString();
93  }
94  // ----------------------------------------------------------------------
95  // Create and populate a ConnectionInfo object
96  // ----------------------------------------------------------------------
97 
99  DTC::DatabaseInfo *pDatabase = pInfo->Database();
100  DTC::WOLInfo *pWOL = pInfo->WOL();
101  DTC::VersionInfo *pVersion = pInfo->Version();
102 
103  pDatabase->setHost ( dbHostName );
104  pDatabase->setPing ( params.dbHostPing );
105  pDatabase->setPort ( params.dbPort );
106  pDatabase->setUserName ( params.dbUserName );
107  pDatabase->setPassword ( params.dbPassword );
108  pDatabase->setName ( params.dbName );
109  pDatabase->setType ( params.dbType );
110  pDatabase->setLocalEnabled ( params.localEnabled );
111  pDatabase->setLocalHostName( params.localHostName );
112 
113  pWOL->setEnabled ( params.wolEnabled );
114  pWOL->setReconnect ( params.wolReconnect );
115  pWOL->setRetry ( params.wolRetry );
116  pWOL->setCommand ( params.wolCommand );
117 
118  pVersion->setVersion ( MYTH_SOURCE_VERSION );
119  pVersion->setBranch ( MYTH_SOURCE_PATH );
120  pVersion->setProtocol ( MYTH_PROTO_VERSION );
121  pVersion->setBinary ( MYTH_BINARY_VERSION );
122  pVersion->setSchema ( MYTH_DATABASE_VERSION );
123 
124  // ----------------------------------------------------------------------
125  // Return the pointer... caller is responsible to delete it!!!
126  // ----------------------------------------------------------------------
127 
128  return pInfo;
129 }
130 
132 //
134 
136 {
137  if (!gCoreContext)
138  throw( QString( "No MythCoreContext in GetHostName." ));
139 
140  return gCoreContext->GetHostName();
141 }
143 //
145 
146 QStringList Myth::GetHosts( )
147 {
148  MSqlQuery query(MSqlQuery::InitCon());
149 
150  if (!query.isConnected())
151  throw( QString( "Database not open while trying to load list of hosts" ));
152 
153  query.prepare(
154  "SELECT DISTINCTROW hostname "
155  "FROM settings "
156  "WHERE (not isNull( hostname ))");
157 
158  if (!query.exec())
159  {
160  MythDB::DBError("MythAPI::GetHosts()", query);
161 
162  throw( QString( "Database Error executing query." ));
163  }
164 
165  // ----------------------------------------------------------------------
166  // return the results of the query
167  // ----------------------------------------------------------------------
168 
169  QStringList oList;
170 
171  while (query.next())
172  oList.append( query.value(0).toString() );
173 
174  return oList;
175 }
176 
178 //
180 
181 QStringList Myth::GetKeys()
182 {
183  MSqlQuery query(MSqlQuery::InitCon());
184 
185  if (!query.isConnected())
186  throw( QString("Database not open while trying to load settings"));
187 
188  query.prepare("SELECT DISTINCTROW value FROM settings;" );
189 
190  if (!query.exec())
191  {
192  MythDB::DBError("MythAPI::GetKeys()", query);
193 
194  throw( QString( "Database Error executing query." ));
195  }
196 
197  // ----------------------------------------------------------------------
198  // return the results of the query
199  // ----------------------------------------------------------------------
200 
201  QStringList oResults;
202 
203  //pResults->setObjectName( "KeyList" );
204 
205  while (query.next())
206  oResults.append( query.value(0).toString() );
207 
208  return oResults;
209 }
210 
212 //
214 
216  const QString &sHostName )
217 {
218  MSqlQuery query(MSqlQuery::InitCon());
219 
220  if (!query.isConnected())
221  throw( QString("Database not open while trying to list "
222  "Storage Group Dirs"));
223 
224  if (!sGroupName.isEmpty() && !sHostName.isEmpty())
225  {
226  query.prepare("SELECT id, groupname, hostname, dirname "
227  "FROM storagegroup "
228  "WHERE groupname = :GROUP AND hostname = :HOST "
229  "ORDER BY groupname, hostname, dirname" );
230  query.bindValue(":HOST", sHostName);
231  query.bindValue(":GROUP", sGroupName);
232  }
233  else if (!sHostName.isEmpty())
234  {
235  query.prepare("SELECT id, groupname, hostname, dirname "
236  "FROM storagegroup "
237  "WHERE hostname = :HOST "
238  "ORDER BY groupname, hostname, dirname" );
239  query.bindValue(":HOST", sHostName);
240  }
241  else if (!sGroupName.isEmpty())
242  {
243  query.prepare("SELECT id, groupname, hostname, dirname "
244  "FROM storagegroup "
245  "WHERE groupname = :GROUP "
246  "ORDER BY groupname, hostname, dirname" );
247  query.bindValue(":GROUP", sGroupName);
248  }
249  else
250  query.prepare("SELECT id, groupname, hostname, dirname "
251  "FROM storagegroup "
252  "ORDER BY groupname, hostname, dirname" );
253 
254  if (!query.exec())
255  {
256  MythDB::DBError("MythAPI::GetStorageGroupDirs()", query);
257 
258  throw( QString( "Database Error executing query." ));
259  }
260 
261  // ----------------------------------------------------------------------
262  // return the results of the query plus R/W and size information
263  // ----------------------------------------------------------------------
264 
266 
267  while (query.next())
268  {
269  DTC::StorageGroupDir *pStorageGroupDir = pList->AddNewStorageGroupDir();
270  QFileInfo fi(query.value(3).toString());
271  int64_t free, total, used;
272 
273  free = getDiskSpace(query.value(3).toString(), total, used);
274 
275  pStorageGroupDir->setId ( query.value(0).toInt() );
276  pStorageGroupDir->setGroupName ( query.value(1).toString() );
277  pStorageGroupDir->setHostName ( query.value(2).toString() );
278  pStorageGroupDir->setDirName ( query.value(3).toString() );
279  pStorageGroupDir->setDirRead ( fi.isReadable() );
280  pStorageGroupDir->setDirWrite ( fi.isWritable() );
281  pStorageGroupDir->setKiBFree ( free );
282  }
283 
284  return pList;
285 }
286 
288 //
290 
291 bool Myth::AddStorageGroupDir( const QString &sGroupName,
292  const QString &sDirName,
293  const QString &sHostName )
294 {
295  MSqlQuery query(MSqlQuery::InitCon());
296 
297  if (!query.isConnected())
298  throw( QString("Database not open while trying to add Storage Group "
299  "dir"));
300 
301  if (sGroupName.isEmpty())
302  throw ( QString( "Storage Group Required" ));
303 
304  if (sDirName.isEmpty())
305  throw ( QString( "Directory Name Required" ));
306 
307  if (sHostName.isEmpty())
308  throw ( QString( "HostName Required" ));
309 
310  query.prepare("SELECT COUNT(*) "
311  "FROM storagegroup "
312  "WHERE groupname = :GROUPNAME "
313  "AND dirname = :DIRNAME "
314  "AND hostname = :HOSTNAME;");
315  query.bindValue(":GROUPNAME", sGroupName );
316  query.bindValue(":DIRNAME" , sDirName );
317  query.bindValue(":HOSTNAME" , sHostName );
318  if (!query.exec())
319  {
320  MythDB::DBError("MythAPI::AddStorageGroupDir()", query);
321 
322  throw( QString( "Database Error executing query." ));
323  }
324 
325  if (query.next())
326  {
327  if (query.value(0).toInt() > 0)
328  return false;
329  }
330 
331  query.prepare("INSERT storagegroup "
332  "( groupname, dirname, hostname ) "
333  "VALUES "
334  "( :GROUPNAME, :DIRNAME, :HOSTNAME );");
335  query.bindValue(":GROUPNAME", sGroupName );
336  query.bindValue(":DIRNAME" , sDirName );
337  query.bindValue(":HOSTNAME" , sHostName );
338 
339  if (!query.exec())
340  {
341  MythDB::DBError("MythAPI::AddStorageGroupDir()", query);
342 
343  throw( QString( "Database Error executing query." ));
344  }
345 
346  return true;
347 }
348 
350 //
352 
353 bool Myth::RemoveStorageGroupDir( const QString &sGroupName,
354  const QString &sDirName,
355  const QString &sHostName )
356 {
357  MSqlQuery query(MSqlQuery::InitCon());
358 
359  if (!query.isConnected())
360  throw( QString("Database not open while trying to remove Storage "
361  "Group dir"));
362 
363  if (sGroupName.isEmpty())
364  throw ( QString( "Storage Group Required" ));
365 
366  if (sDirName.isEmpty())
367  throw ( QString( "Directory Name Required" ));
368 
369  if (sHostName.isEmpty())
370  throw ( QString( "HostName Required" ));
371 
372  query.prepare("DELETE "
373  "FROM storagegroup "
374  "WHERE groupname = :GROUPNAME "
375  "AND dirname = :DIRNAME "
376  "AND hostname = :HOSTNAME;");
377  query.bindValue(":GROUPNAME", sGroupName );
378  query.bindValue(":DIRNAME" , sDirName );
379  query.bindValue(":HOSTNAME" , sHostName );
380  if (!query.exec())
381  {
382  MythDB::DBError("MythAPI::AddStorageGroupDir()", query);
383 
384  throw( QString( "Database Error executing query." ));
385  }
386 
387  return true;
388 }
389 
391 //
393 
395 {
396  DTC::TimeZoneInfo *pResults = new DTC::TimeZoneInfo();
397 
398  pResults->setTimeZoneID( MythTZ::getTimeZoneID() );
399  pResults->setUTCOffset( MythTZ::calc_utc_offset() );
400  pResults->setCurrentDateTime( MythDate::current(true) );
401 
402  return pResults;
403 }
404 
406 //
408 
409 QString Myth::GetFormatDate(const QDateTime Date, bool ShortDate)
410 {
411  uint dateFormat;
412  if (ShortDate)
414  else
416 
417  return MythDate::toString(Date, dateFormat);
418 }
419 
421 //
423 
424 QString Myth::GetFormatDateTime(const QDateTime DateTime, bool ShortDate)
425 {
426  uint dateFormat;
427  if (ShortDate)
429  else
431 
432  return MythDate::toString(DateTime, dateFormat);
433 }
434 
436 //
438 
439 QString Myth::GetFormatTime(const QDateTime Time)
440 {
441  return MythDate::toString(Time, MythDate::kTime);
442 }
443 
445 //
447 
448 QDateTime Myth::ParseISODateString(const QString& DateTimeString)
449 {
450  QDateTime dateTime = QDateTime::fromString(DateTimeString, Qt::ISODate);
451 
452  if (!dateTime.isValid())
453  throw QString( "Unable to parse DateTimeString" );
454 
455  return dateTime;
456 }
457 
459 //
461 
462 DTC::LogMessageList *Myth::GetLogs( const QString &HostName,
463  const QString &Application,
464  int PID,
465  int TID,
466  const QString &Thread,
467  const QString &Filename,
468  int Line,
469  const QString &Function,
470  const QDateTime &FromTime,
471  const QDateTime &ToTime,
472  const QString &Level,
473  const QString &MsgContains )
474 {
476 
477  MSqlQuery query(MSqlQuery::InitCon());
478 
479  // Get host name list
480  QString sql = "SELECT DISTINCT host FROM logging ORDER BY host ASC";
481  if (!query.exec(sql))
482  {
483  MythDB::DBError("Retrieving log host names", query);
484  delete pList;
485  throw( QString( "Database Error executing query." ));
486  }
487  while (query.next())
488  {
489  DTC::LabelValue *pLabelValue = pList->AddNewHostName();
490  QString availableHostName = query.value(0).toString();
491  pLabelValue->setValue ( availableHostName );
492  pLabelValue->setActive ( availableHostName == HostName );
493  pLabelValue->setSelected( availableHostName == HostName );
494  }
495  // Get application list
496  sql = "SELECT DISTINCT application FROM logging ORDER BY application ASC";
497  if (!query.exec(sql))
498  {
499  MythDB::DBError("Retrieving log applications", query);
500  delete pList;
501  throw( QString( "Database Error executing query." ));
502  }
503  while (query.next())
504  {
505  DTC::LabelValue *pLabelValue = pList->AddNewApplication();
506  QString availableApplication = query.value(0).toString();
507  pLabelValue->setValue ( availableApplication );
508  pLabelValue->setActive ( availableApplication == Application );
509  pLabelValue->setSelected( availableApplication == Application );
510  }
511 
512  if (!HostName.isEmpty() && !Application.isEmpty())
513  {
514  // Get log messages
515  sql = "SELECT host, application, pid, tid, thread, filename, "
516  " line, function, msgtime, level, message "
517  " FROM logging "
518  " WHERE host = COALESCE(:HOSTNAME, host) "
519  " AND application = COALESCE(:APPLICATION, application) "
520  " AND pid = COALESCE(:PID, pid) "
521  " AND tid = COALESCE(:TID, tid) "
522  " AND thread = COALESCE(:THREAD, thread) "
523  " AND filename = COALESCE(:FILENAME, filename) "
524  " AND line = COALESCE(:LINE, line) "
525  " AND function = COALESCE(:FUNCTION, function) "
526  " AND msgtime >= COALESCE(:FROMTIME, msgtime) "
527  " AND msgtime <= COALESCE(:TOTIME, msgtime) "
528  " AND level <= COALESCE(:LEVEL, level) "
529  ;
530  if (!MsgContains.isEmpty())
531  {
532  sql.append(" AND message LIKE :MSGCONTAINS ");
533  }
534  sql.append(" ORDER BY msgtime ASC;");
535 
536  query.prepare(sql);
537 
538  query.bindValue(":HOSTNAME", (HostName.isEmpty()) ? QString() : HostName);
539  query.bindValue(":APPLICATION", (Application.isEmpty()) ? QString() :
540  Application);
541  query.bindValue(":PID", ( PID == 0 ) ? QVariant(QVariant::ULongLong) :
542  (qint64)PID);
543  query.bindValue(":TID", ( TID == 0 ) ? QVariant(QVariant::ULongLong) :
544  (qint64)TID);
545  query.bindValue(":THREAD", (Thread.isEmpty()) ? QString() : Thread);
546  query.bindValue(":FILENAME", (Filename.isEmpty()) ? QString() : Filename);
547  query.bindValue(":LINE", ( Line == 0 ) ? QVariant(QVariant::ULongLong) :
548  (qint64)Line);
549  query.bindValue(":FUNCTION", (Function.isEmpty()) ? QString() : Function);
550  query.bindValue(":FROMTIME", (FromTime.isValid()) ? FromTime : QDateTime());
551  query.bindValue(":TOTIME", (ToTime.isValid()) ? ToTime : QDateTime());
552  query.bindValue(":LEVEL", (Level.isEmpty()) ?
553  QVariant(QVariant::ULongLong) :
554  (qint64)logLevelGet(Level));
555 
556  if (!MsgContains.isEmpty())
557  {
558  query.bindValue(":MSGCONTAINS", "%" + MsgContains + "%" );
559  }
560 
561  if (!query.exec())
562  {
563  MythDB::DBError("Retrieving log messages", query);
564  delete pList;
565  throw( QString( "Database Error executing query." ));
566  }
567 
568  while (query.next())
569  {
570  DTC::LogMessage *pLogMessage = pList->AddNewLogMessage();
571 
572  pLogMessage->setHostName( query.value(0).toString() );
573  pLogMessage->setApplication( query.value(1).toString() );
574  pLogMessage->setPID( query.value(2).toInt() );
575  pLogMessage->setTID( query.value(3).toInt() );
576  pLogMessage->setThread( query.value(4).toString() );
577  pLogMessage->setFilename( query.value(5).toString() );
578  pLogMessage->setLine( query.value(6).toInt() );
579  pLogMessage->setFunction( query.value(7).toString() );
580  pLogMessage->setTime(MythDate::as_utc(query.value(8).toDateTime()));
581  pLogMessage->setLevel( logLevelGetName(
582  (LogLevel_t)query.value(9).toInt()) );
583  pLogMessage->setMessage( query.value(10).toString() );
584  }
585  }
586 
587  return pList;
588 }
589 
591 //
593 
595 {
596  DTC::FrontendList *pList = new DTC::FrontendList();
597  QMap<QString, Frontend*> frontends;
598  if (OnLine)
599  frontends = gBackendContext->GetConnectedFrontends();
600  else
601  frontends = gBackendContext->GetFrontends();
602 
603  QMap<QString, Frontend*>::const_iterator it;
604  for (it = frontends.begin(); it != frontends.end(); ++it)
605  {
606  DTC::Frontend *pFrontend = pList->AddNewFrontend();
607  pFrontend->setName((*it)->m_name);
608  pFrontend->setIP((*it)->m_ip.toString());
609  int port = gCoreContext->GetNumSettingOnHost("FrontendStatusPort",
610  (*it)->m_name, 6547);
611  pFrontend->setPort(port);
612  pFrontend->setOnLine((*it)->m_connectionCount > 0);
613  }
614 
615  return pList;
616 }
617 
619 //
621 
622 QString Myth::GetSetting( const QString &sHostName,
623  const QString &sKey,
624  const QString &sDefault )
625 {
626  if (sKey.isEmpty())
627  throw( QString("Missing or empty Key (settings.value)") );
628 
629  if (sHostName == "_GLOBAL_")
630  {
631  MSqlQuery query(MSqlQuery::InitCon());
632 
633  query.prepare("SELECT data FROM settings "
634  "WHERE value = :VALUE "
635  "AND (hostname IS NULL)" );
636 
637  query.bindValue(":VALUE", sKey );
638 
639  if (!query.exec())
640  {
641  MythDB::DBError("API Myth/GetSetting ", query);
642  throw( QString( "Database Error executing query." ));
643  }
644 
645  return query.next() ? query.value(0).toString() : sDefault;
646  }
647 
648  QString hostname = sHostName;
649 
650  if (sHostName.isEmpty())
652 
653  return gCoreContext->GetSettingOnHost(sKey, hostname, sDefault);
654 }
655 
657 //
659 
660 DTC::SettingList *Myth::GetSettingList(const QString &sHostName)
661 {
662 
663  MSqlQuery query(MSqlQuery::InitCon());
664 
665  if (!query.isConnected())
666  {
667  throw( QString("Database not open while trying to load settings for host: %1")
668  .arg( sHostName ));
669  }
670 
671  DTC::SettingList *pList = new DTC::SettingList();
672 
673  //pList->setObjectName( "Settings" );
674  pList->setHostName ( sHostName );
675 
676  // ------------------------------------------------------------------
677  // Looking to return all Setting for supplied hostname
678  // ------------------------------------------------------------------
679 
680  if (sHostName.isEmpty())
681  {
682  query.prepare("SELECT value, data FROM settings "
683  "WHERE (hostname IS NULL)" );
684  }
685  else
686  {
687  query.prepare("SELECT value, data FROM settings "
688  "WHERE (hostname = :HOSTNAME)" );
689 
690  query.bindValue(":HOSTNAME", sHostName );
691  }
692 
693  if (!query.exec())
694  {
695  // clean up unused object we created.
696 
697  delete pList;
698 
699  MythDB::DBError("MythAPI::GetSetting() w/o key ", query);
700  throw( QString( "Database Error executing query." ));
701  }
702 
703  while (query.next())
704  pList->Settings().insert( query.value(0).toString(), query.value(1) );
705 
706  return pList;
707 }
708 
710 //
712 
713 bool Myth::PutSetting( const QString &sHostName,
714  const QString &sKey,
715  const QString &sValue )
716 {
717  if (!sKey.isEmpty())
718  {
719  return gCoreContext->SaveSettingOnHost( sKey, sValue, sHostName );
720  }
721 
722  throw ( QString( "Key Required" ));
723 }
724 
726 //
728 
729 bool Myth::ChangePassword( const QString &sUserName,
730  const QString &sOldPassword,
731  const QString &sNewPassword )
732 {
733  LOG(VB_GENERAL, LOG_NOTICE, "ChangePassword is deprecated, use "
734  "ManageDigestUser.");
735 
736  return ( ManageDigestUser("ChangePassword", sUserName, sOldPassword,
737  sNewPassword, "") );
738 }
739 
741 //
743 
744 bool Myth::TestDBSettings( const QString &sHostName,
745  const QString &sUserName,
746  const QString &sPassword,
747  const QString &sDBName,
748  int dbPort)
749 {
750  bool bResult = false;
751 
752  QString db("mythconverg");
753  int port = 3306;
754 
755  if (!sDBName.isEmpty())
756  db = sDBName;
757 
758  if (dbPort != 0)
759  port = dbPort;
760 
761  bResult = TestDatabase(sHostName, sUserName, sPassword, db, port);
762 
763  return bResult;
764 }
765 
767 //
769 
770 bool Myth::SendMessage( const QString &sMessage,
771  const QString &sAddress,
772  int udpPort,
773  int Timeout)
774 {
775  bool bResult = false;
776 
777  if (sMessage.isEmpty())
778  return bResult;
779 
780  if (Timeout < 0 || Timeout > 999)
781  Timeout = 0;
782 
783  QString xmlMessage =
784  "<mythmessage version=\"1\">\n"
785  " <text>" + sMessage + "</text>\n"
786  " <timeout>" + QString::number(Timeout) + "</timeout>\n"
787  "</mythmessage>";
788 
789  QHostAddress address = QHostAddress::Broadcast;
790  unsigned short port = 6948;
791 
792  if (!sAddress.isEmpty())
793  address.setAddress(sAddress);
794 
795  if (udpPort != 0)
796  port = udpPort;
797 
798  QUdpSocket *sock = new QUdpSocket();
799  QByteArray utf8 = xmlMessage.toUtf8();
800  int size = utf8.length();
801 
802  if (sock->writeDatagram(utf8.constData(), size, address, port) < 0)
803  {
804  LOG(VB_GENERAL, LOG_ERR,
805  QString("Failed to send UDP/XML packet (Message: %1 "
806  "Address: %2 Port: %3")
807  .arg(sMessage).arg(sAddress).arg(port));
808  }
809  else
810  {
811  LOG(VB_GENERAL, LOG_DEBUG,
812  QString("UDP/XML packet sent! (Message: %1 Address: %2 Port: %3")
813  .arg(sMessage)
814  .arg(address.toString().toLocal8Bit().constData()).arg(port));
815  bResult = true;
816  }
817 
818  sock->deleteLater();
819 
820  return bResult;
821 }
822 
823 bool Myth::SendNotification( bool bError,
824  const QString &Type,
825  const QString &sMessage,
826  const QString &sOrigin,
827  const QString &sDescription,
828  const QString &sImage,
829  const QString &sExtra,
830  const QString &sProgressText,
831  float fProgress,
832  int Duration,
833  bool bFullscreen,
834  uint Visibility,
835  uint Priority,
836  const QString &sAddress,
837  int udpPort )
838 {
839  bool bResult = false;
840 
841  if (sMessage.isEmpty())
842  return bResult;
843 
844  if (Duration < 0 || Duration > 999)
845  Duration = -1;
846 
847  QString xmlMessage =
848  "<mythnotification version=\"1\">\n"
849  " <text>" + sMessage + "</text>\n"
850  " <origin>" + (sOrigin.isNull() ? tr("MythServices") : sOrigin) + "</origin>\n"
851  " <description>" + sDescription + "</description>\n"
852  " <timeout>" + QString::number(Duration) + "</timeout>\n"
853  " <image>" + sImage + "</image>\n"
854  " <extra>" + sExtra + "</extra>\n"
855  " <progress_text>" + sProgressText + "</progress_text>\n"
856  " <progress>" + QString::number(fProgress) + "</progress>\n"
857  " <fullscreen>" + (bFullscreen ? "true" : "false") + "</fullscreen>\n"
858  " <visibility>" + QString::number(Visibility) + "</visibility>\n"
859  " <priority>" + QString::number(Priority) + "</priority>\n"
860  " <type>" + (bError ? "error" : Type) + "</type>\n"
861  "</mythnotification>";
862 
863  QHostAddress address = QHostAddress::Broadcast;
864  unsigned short port = 6948;
865 
866  if (!sAddress.isEmpty())
867  address.setAddress(sAddress);
868 
869  if (udpPort != 0)
870  port = udpPort;
871 
872  QUdpSocket *sock = new QUdpSocket();
873  QByteArray utf8 = xmlMessage.toUtf8();
874  int size = utf8.length();
875 
876  if (sock->writeDatagram(utf8.constData(), size, address, port) < 0)
877  {
878  LOG(VB_GENERAL, LOG_ERR,
879  QString("Failed to send UDP/XML packet (Notification: %1 "
880  "Address: %2 Port: %3")
881  .arg(sMessage).arg(sAddress).arg(port));
882  }
883  else
884  {
885  LOG(VB_GENERAL, LOG_DEBUG,
886  QString("UDP/XML packet sent! (Notification: %1 Address: %2 Port: %3")
887  .arg(sMessage)
888  .arg(address.toString().toLocal8Bit().constData()).arg(port));
889  bResult = true;
890  }
891 
892  sock->deleteLater();
893 
894  return bResult;
895 }
896 
898 //
900 
902 {
903  bool bResult = false;
904 
905  DBUtil dbutil;
907  QString filename;
908 
909  LOG(VB_GENERAL, LOG_NOTICE, "Performing API invoked DB Backup.");
910 
911  status = dbutil.BackupDB(filename);
912 
913  if (status == kDB_Backup_Completed)
914  {
915  LOG(VB_GENERAL, LOG_NOTICE, "Database backup succeeded.");
916  bResult = true;
917  }
918  else
919  LOG(VB_GENERAL, LOG_ERR, "Database backup failed.");
920 
921  return bResult;
922 }
923 
925 //
927 
928 bool Myth::CheckDatabase( bool repair )
929 {
930  LOG(VB_GENERAL, LOG_NOTICE, "Performing API invoked DB Check.");
931 
932  bool bResult = DBUtil::CheckTables(repair);
933 
934  if (bResult)
935  LOG(VB_GENERAL, LOG_NOTICE, "Database check complete.");
936  else
937  LOG(VB_GENERAL, LOG_ERR, "Database check failed.");
938 
939  return bResult;
940 }
941 
943 //
945 
947 {
949  LOG(VB_GENERAL, LOG_NOTICE, "Profile Submission...");
950  profile.GenerateUUIDs();
951  bool bResult = profile.SubmitProfile();
952  if (bResult)
953  LOG(VB_GENERAL, LOG_NOTICE, "Profile Submitted.");
954 
955  return bResult;
956 }
957 
959 //
961 
963 {
965  LOG(VB_GENERAL, LOG_NOTICE, "Profile Deletion...");
966  profile.GenerateUUIDs();
967  bool bResult = profile.DeleteProfile();
968  if (bResult)
969  LOG(VB_GENERAL, LOG_NOTICE, "Profile Deleted.");
970 
971  return bResult;
972 }
973 
975 //
977 
979 {
980  QString sProfileURL;
981 
983  profile.GenerateUUIDs();
984  sProfileURL = profile.GetProfileURL();
985  LOG(VB_GENERAL, LOG_NOTICE, QString("ProfileURL: %1").arg(sProfileURL));
986 
987  return sProfileURL;
988 }
989 
991 //
993 
995 {
996  QString sProfileUpdate;
997 
999  profile.GenerateUUIDs();
1000  QDateTime tUpdated;
1001  tUpdated = profile.GetLastUpdate();
1002  sProfileUpdate = tUpdated.toString(
1003  gCoreContext->GetSetting( "DateFormat", "MM.dd.yyyy"));
1004 
1005  return sProfileUpdate;
1006 }
1007 
1009 //
1011 
1013 {
1014  QString sProfileText;
1015 
1017  sProfileText = profile.GetHardwareProfile();
1018 
1019  return sProfileText;
1020 }
1021 
1023 //
1025 
1027 {
1028 
1029  // ----------------------------------------------------------------------
1030  // Create and populate a Configuration object
1031  // ----------------------------------------------------------------------
1032 
1033  DTC::BackendInfo *pInfo = new DTC::BackendInfo();
1034  DTC::BuildInfo *pBuild = pInfo->Build();
1035  DTC::EnvInfo *pEnv = pInfo->Env();
1036  DTC::LogInfo *pLog = pInfo->Log();
1037 
1038  pBuild->setVersion ( MYTH_SOURCE_VERSION );
1039  pBuild->setLibX264 ( CONFIG_LIBX264 );
1040  pBuild->setLibDNS_SD ( CONFIG_LIBDNS_SD );
1041  pEnv->setLANG ( getenv("LANG") );
1042  pEnv->setLCALL ( getenv("LC_ALL") );
1043  pEnv->setLCCTYPE ( getenv("LC_CTYPE") );
1044  pEnv->setHOME ( getenv("HOME") );
1045  pEnv->setMYTHCONFDIR ( getenv("MYTHCONFDIR") );
1046  pLog->setLogArgs ( logPropagateArgs );
1047 
1048  // ----------------------------------------------------------------------
1049  // Return the pointer... caller is responsible to delete it!!!
1050  // ----------------------------------------------------------------------
1051 
1052  return pInfo;
1053 
1054 }
1055 
1057 //
1059 
1060 bool Myth::ManageDigestUser( const QString &sAction,
1061  const QString &sUserName,
1062  const QString &sPassword,
1063  const QString &sNewPassword,
1064  const QString &sAdminPassword )
1065 {
1066 
1067  DigestUserActions sessionAction;
1068 
1069  if (sAction == "Add")
1070  sessionAction = DIGEST_USER_ADD;
1071  else if (sAction == "Remove")
1072  sessionAction = DIGEST_USER_REMOVE;
1073  else if (sAction == "ChangePassword")
1074  sessionAction = DIGEST_USER_CHANGE_PW;
1075  else
1076  {
1077  LOG(VB_GENERAL, LOG_ERR, QString("Action must be Add, Remove or "
1078  "ChangePassword, not '%1'")
1079  .arg(sAction));
1080  return false;
1081  }
1082 
1083  return gCoreContext->GetSessionManager()->ManageDigestUser(sessionAction,
1084  sUserName,
1085  sPassword,
1086  sNewPassword,
1087  sAdminPassword);
1088 }
1089 
1091 //
1093 
1094 bool Myth::ManageUrlProtection( const QString &sServices,
1095  const QString &sAdminPassword )
1096 {
1097 
1098  MythSessionManager *sessionManager = gCoreContext->GetSessionManager();
1099 
1100  if (!sessionManager->IsValidUser("admin"))
1101  {
1102  LOG(VB_GENERAL, LOG_ERR, QString("Backend has no '%1' user!")
1103  .arg("admin"));
1104  return false;
1105  }
1106 
1107  if (MythSessionManager::CreateDigest("admin", sAdminPassword) !=
1108  sessionManager->GetPasswordDigest("admin"))
1109  {
1110  LOG(VB_GENERAL, LOG_ERR, QString("Incorrect password for user: %1")
1111  .arg("admin"));
1112  return false;
1113  }
1114 
1115  QStringList serviceList = sServices.split(",");
1116 
1117  serviceList.removeDuplicates();
1118 
1119  QStringList protectedURLs;
1120 
1121  if (serviceList.size() == 1 && serviceList.first() == "All")
1122  for (const QString& service : KnownServices)
1123  protectedURLs << '/' + service;
1124  else if (serviceList.size() == 1 && serviceList.first() == "None")
1125  protectedURLs << "Unprotected";
1126  else
1127  {
1128  for (const QString& service : serviceList)
1129  if (KnownServices.contains(service))
1130  protectedURLs << '/' + service;
1131  else
1132  LOG(VB_GENERAL, LOG_ERR, QString("Invalid service name: '%1'")
1133  .arg(service));
1134  }
1135 
1136  if (protectedURLs.isEmpty())
1137  {
1138  LOG(VB_GENERAL, LOG_ERR, "No valid Services were found");
1139  return false;
1140  }
1141 
1142  return gCoreContext->SaveSettingOnHost("HTTP/Protected/Urls",
1143  protectedURLs.join(';'), "");
1144 }
DTC::TimeZoneInfo * GetTimeZone() override
Definition: myth.cpp:394
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:782
QString logLevelGetName(LogLevel_t level)
Map a log level enumerated value back to the name.
Definition: logging.cpp:857
bool wolEnabled
true if wake-on-lan params are used
Definition: mythdbparams.h:33
DTC::LogMessageList * GetLogs(const QString &HostName, const QString &Application, int PID, int TID, const QString &Thread, const QString &Filename, int Line, const QString &Function, const QDateTime &FromTime, const QDateTime &ToTime, const QString &Level, const QString &MsgContains) override
Definition: myth.cpp:462
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:863
const QMap< QString, Frontend * > GetConnectedFrontends() const
QString wolCommand
command to use for wake-on-lan
Definition: mythdbparams.h:36
QString dbName
database name
Definition: mythdbparams.h:26
QDateTime ParseISODateString(const QString &DateTime) override
Definition: myth.cpp:448
bool ManageDigestUser(DigestUserActions action, const QString &username, const QString &password, const QString &newPassword, const QString &adminPassword)
Manage digest user entries.
DTC::ConnectionInfo * GetConnectionInfo(const QString &Pin) override
Definition: myth.cpp:54
QVariantMap Settings
Definition: settingList.h:34
bool TestDatabase(const QString &dbHostName, const QString &dbUserName, QString dbPassword, QString dbName, int dbPort)
Definition: mythdbcon.cpp:37
bool ChangePassword(const QString &UserName, const QString &OldPassword, const QString &NewPassword) override
Definition: myth.cpp:729
Default local time.
Definition: mythdate.h:17
QString GetBackendServerIP(void)
Returns the IP address of the locally defined backend IP.
QString GetFormatDateTime(QDateTime DateTime, bool ShortDate) override
Definition: myth.cpp:424
MythSessionManager * GetSessionManager(void)
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
bool PutSetting(const QString &HostName, const QString &Key, const QString &Value) override
Definition: myth.cpp:713
QString ProfileURL(void) override
Definition: myth.cpp:978
QString logPropagateArgs
Definition: logging.cpp:89
bool isConnected(void)
Only updated once during object creation.
Definition: mythdbcon.h:135
QString GetSettingOnHost(const QString &key, const QString &host, const QString &defaultval="")
DTC::FrontendList * GetFrontends(bool OnLine) override
Definition: myth.cpp:594
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Default local time.
Definition: mythdate.h:21
QList< LogMessage * > LogMessageList
bool localEnabled
true if localHostName is not default
Definition: mythdbparams.h:29
const QMap< QString, Frontend * > GetFrontends() const
bool SendNotification(bool Error, const QString &Type, const QString &Message, const QString &Origin, const QString &Description, const QString &Image, const QString &Extra, const QString &ProgressText, float Progress, int Duration, bool Fullscreen, uint Visibility, uint Priority, const QString &Address, int udpPort) override
Definition: myth.cpp:823
DTC::StorageGroupDirList * GetStorageGroupDirs(const QString &GroupName, const QString &HostName) override
Definition: myth.cpp:215
QDateTime as_utc(const QDateTime &old_dt)
Returns copy of QDateTime with TimeSpec set to UTC.
Definition: mythdate.cpp:23
bool CheckDatabase(bool Repair) override
Definition: myth.cpp:928
QString dbPassword
DB password.
Definition: mythdbparams.h:25
QVariant value(int i) const
Definition: mythdbcon.h:198
QString GetHostName() override
Definition: myth.cpp:135
bool IsValidUser(const QString &username)
Check if the given user exists but not whether there is a valid session open for them!
We use digest authentication because it protects the password over unprotected networks.
Definition: mythsession.h:98
int calc_utc_offset(void)
QString dbUserName
DB user name.
Definition: mythdbparams.h:24
Add year only if different from current year.
Definition: mythdate.h:25
StorageGroupDir * AddNewStorageGroupDir()
Default local time.
Definition: mythdate.h:19
LabelValue * AddNewHostName()
QString dbType
database type (MySQL, Postgres, etc.)
Definition: mythdbparams.h:27
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
QString GetSetting(const QString &key, const QString &defaultval="")
DTC::SettingList * GetSettingList(const QString &HostName) override
Definition: myth.cpp:660
QString ProfileText(void) override
Definition: myth.cpp:1012
Default local time.
Definition: mythdate.h:16
bool ManageUrlProtection(const QString &Services, const QString &AdminPassword) override
Definition: myth.cpp:1094
#define MYTH_PROTO_VERSION
Increment this whenever the MythTV network protocol changes.
Definition: mythversion.h:48
BackendContext * gBackendContext
bool dbHostPing
Can we test connectivity using ping?
Definition: mythdbparams.h:22
string hostname
Definition: caa.py:17
Frontend * AddNewFrontend()
Definition: frontendList.h:52
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
static QByteArray CreateDigest(const QString &username, const QString &password)
Generate a digest string.
Do Today/Yesterday/Tomorrow transform.
Definition: mythdate.h:23
QStringList GetHosts() override
Definition: myth.cpp:146
bool SendMessage(const QString &Message, const QString &Address, int udpPort, int Timeout) override
Definition: myth.cpp:770
int GetNumSettingOnHost(const QString &key, const QString &host, int defaultval=0)
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:101
QString GetFormatTime(QDateTime Time) override
Definition: myth.cpp:439
int wolReconnect
seconds to wait for reconnect
Definition: mythdbparams.h:34
int64_t getDiskSpace(const QString &file_on_disk, int64_t &total, int64_t &used)
QString GetPasswordDigest(const QString &username)
Load the password digest for comparison in the HTTP Auth code.
DTC::BackendInfo * GetBackendInfo(void) override
Definition: myth.cpp:1026
DigestUserActions
Definition: mythsession.h:10
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:807
bool BackupDatabase(void) override
Definition: myth.cpp:901
bool TestDBSettings(const QString &HostName, const QString &UserName, const QString &Password, const QString &DBName, int dbPort) override
Definition: myth.cpp:744
Structure containing the basic Database parameters.
Definition: mythdbparams.h:9
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QString dbHostName
database server
Definition: mythdbparams.h:21
bool RemoveStorageGroupDir(const QString &GroupName, const QString &DirName, const QString &HostName) override
Definition: myth.cpp:353
MythDBBackupStatus
Definition: dbutil.h:9
bool AddStorageGroupDir(const QString &GroupName, const QString &DirName, const QString &HostName) override
Definition: myth.cpp:291
DatabaseParams GetDatabaseParams(void)
Aggregates database and DBMS utility functions.
Definition: dbutil.h:30
Default local time.
Definition: mythdate.h:20
QString Filename(bool find=true)
QString GetFormatDate(QDateTime Date, bool ShortDate) override
Definition: myth.cpp:409
#define MYTH_BINARY_VERSION
Update this whenever the plug-in ABI changes.
Definition: mythversion.h:16
QString GetSetting(const QString &HostName, const QString &Key, const QString &Default) override
Definition: myth.cpp:622
bool ProfileSubmit(void) override
Definition: myth.cpp:946
QString ProfileUpdated(void) override
Definition: myth.cpp:994
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
LabelValue * AddNewApplication()
bool ProfileDelete(void) override
Definition: myth.cpp:962
bool SaveSettingOnHost(const QString &key, const QString &newValue, const QString &host)
LogMessage * AddNewLogMessage()
QStringList GetKeys() override
Definition: myth.cpp:181
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
QString getTimeZoneID(void)
Returns the zoneinfo time zone ID or as much time zone information as possible.
LogLevel_t logLevelGet(const QString &level)
Map a log level name back to the enumerated value.
Definition: logging.cpp:833
QString localHostName
name used for loading/saving settings
Definition: mythdbparams.h:30
const QStringList KnownServices
Definition: serviceUtil.h:49
int dbPort
database port
Definition: mythdbparams.h:23
QString GetHostName(void)
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
bool ManageDigestUser(const QString &Action, const QString &UserName, const QString &Password, const QString &NewPassword, const QString &AdminPassword) override
Definition: myth.cpp:1060
int wolRetry
times to retry to reconnect
Definition: mythdbparams.h:35
Default UTC.
Definition: mythdate.h:14
#define MYTH_DATABASE_VERSION
Increment this whenever the MythTV core database schema changes.
Definition: mythversion.h:78
MythDBBackupStatus BackupDB(QString &filename, bool disableRotation=false)
Requests a backup of the database.
Definition: dbutil.cpp:194
static bool CheckTables(const bool repair=false, const QString &options="QUICK")
Checks database tables.
Definition: dbutil.cpp:282