Go to the documentation of this file.
31 #include <QCryptographicHash>
32 #include <QHostAddress>
51 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
52 #define qEnvironmentVariable getenv
63 if ( sSecurityPin.isEmpty() )
64 throw( QString(
"No Security Pin assigned. Run mythtv-setup to set one." ));
67 if ((sSecurityPin !=
"0000" ) && ( sPin != sSecurityPin ))
68 throw( QString(
"Not Authorized" ));
80 if ((params.
m_dbHostName.compare(
"localhost",Qt::CaseInsensitive)==0
83 && !sServerIP.isEmpty())
94 if (addr.setAddress(dbHostName))
96 addr.setScopeId(QString());
97 dbHostName = addr.toString();
108 pDatabase->setHost ( dbHostName );
110 pDatabase->setPort ( params.
m_dbPort );
113 pDatabase->setName ( params.
m_dbName );
114 pDatabase->setType ( params.
m_dbType );
123 pVersion->setVersion ( MYTH_SOURCE_VERSION );
124 pVersion->setBranch ( MYTH_SOURCE_PATH );
143 throw( QString(
"No MythCoreContext in GetHostName." ));
156 throw( QString(
"Database not open while trying to load list of hosts" ));
159 "SELECT DISTINCTROW hostname "
161 "WHERE (not isNull( hostname ))");
167 throw( QString(
"Database Error executing query." ));
191 throw( QString(
"Database not open while trying to load settings"));
193 query.
prepare(
"SELECT DISTINCTROW value FROM settings;" );
199 throw( QString(
"Database Error executing query." ));
206 QStringList oResults;
221 const QString &sHostName )
226 throw( QString(
"Database not open while trying to list "
227 "Storage Group Dirs"));
229 if (!sGroupName.isEmpty() && !sHostName.isEmpty())
231 query.
prepare(
"SELECT id, groupname, hostname, dirname "
233 "WHERE groupname = :GROUP AND hostname = :HOST "
234 "ORDER BY groupname, hostname, dirname" );
238 else if (!sHostName.isEmpty())
240 query.
prepare(
"SELECT id, groupname, hostname, dirname "
242 "WHERE hostname = :HOST "
243 "ORDER BY groupname, hostname, dirname" );
246 else if (!sGroupName.isEmpty())
248 query.
prepare(
"SELECT id, groupname, hostname, dirname "
250 "WHERE groupname = :GROUP "
251 "ORDER BY groupname, hostname, dirname" );
256 query.
prepare(
"SELECT id, groupname, hostname, dirname "
258 "ORDER BY groupname, hostname, dirname" );
265 throw( QString(
"Database Error executing query." ));
284 pStorageGroupDir->setId (
query.
value(0).toInt() );
285 pStorageGroupDir->setGroupName (
query.
value(1).toString() );
286 pStorageGroupDir->setHostName (
query.
value(2).toString() );
287 pStorageGroupDir->setDirName (
query.
value(3).toString() );
288 pStorageGroupDir->setDirRead ( fi.isReadable() );
289 pStorageGroupDir->setDirWrite ( fi.isWritable() );
290 pStorageGroupDir->setKiBFree ( free );
301 const QString &sDirName,
302 const QString &sHostName )
307 throw( QString(
"Database not open while trying to add Storage Group "
310 if (sGroupName.isEmpty())
311 throw ( QString(
"Storage Group Required" ));
313 if (sDirName.isEmpty())
314 throw ( QString(
"Directory Name Required" ));
316 if (sHostName.isEmpty())
317 throw ( QString(
"HostName Required" ));
321 "WHERE groupname = :GROUPNAME "
322 "AND dirname = :DIRNAME "
323 "AND hostname = :HOSTNAME;");
331 throw( QString(
"Database Error executing query." ));
341 "( groupname, dirname, hostname ) "
343 "( :GROUPNAME, :DIRNAME, :HOSTNAME );");
352 throw( QString(
"Database Error executing query." ));
363 const QString &sDirName,
364 const QString &sHostName )
369 throw( QString(
"Database not open while trying to remove Storage "
372 if (sGroupName.isEmpty())
373 throw ( QString(
"Storage Group Required" ));
375 if (sDirName.isEmpty())
376 throw ( QString(
"Directory Name Required" ));
378 if (sHostName.isEmpty())
379 throw ( QString(
"HostName Required" ));
383 "WHERE groupname = :GROUPNAME "
384 "AND dirname = :DIRNAME "
385 "AND hostname = :HOSTNAME;");
393 throw( QString(
"Database Error executing query." ));
457 if (!dateTime.isValid())
458 throw QString(
"Unable to parse DateTimeString" );
468 const QString &Application,
471 const QString &Thread,
474 const QString &Function,
475 const QDateTime &FromTime,
476 const QDateTime &ToTime,
477 const QString &Level,
478 const QString &MsgContains )
485 QString sql =
"SELECT DISTINCT host FROM logging ORDER BY host ASC";
490 throw( QString(
"Database Error executing query." ));
495 QString availableHostName =
query.
value(0).toString();
496 pLabelValue->setValue ( availableHostName );
497 pLabelValue->setActive ( availableHostName == HostName );
498 pLabelValue->setSelected( availableHostName == HostName );
501 sql =
"SELECT DISTINCT application FROM logging ORDER BY application ASC";
506 throw( QString(
"Database Error executing query." ));
511 QString availableApplication =
query.
value(0).toString();
512 pLabelValue->setValue ( availableApplication );
513 pLabelValue->setActive ( availableApplication == Application );
514 pLabelValue->setSelected( availableApplication == Application );
517 if (!HostName.isEmpty() && !Application.isEmpty())
520 sql =
"SELECT host, application, pid, tid, thread, filename, "
521 " line, function, msgtime, level, message "
523 " WHERE host = COALESCE(:HOSTNAME, host) "
524 " AND application = COALESCE(:APPLICATION, application) "
525 " AND pid = COALESCE(:PID, pid) "
526 " AND tid = COALESCE(:TID, tid) "
527 " AND thread = COALESCE(:THREAD, thread) "
528 " AND filename = COALESCE(:FILENAME, filename) "
529 " AND line = COALESCE(:LINE, line) "
530 " AND function = COALESCE(:FUNCTION, function) "
531 " AND msgtime >= COALESCE(:FROMTIME, msgtime) "
532 " AND msgtime <= COALESCE(:TOTIME, msgtime) "
533 " AND level <= COALESCE(:LEVEL, level) "
535 if (!MsgContains.isEmpty())
537 sql.append(
" AND message LIKE :MSGCONTAINS ");
539 sql.append(
" ORDER BY msgtime ASC;");
543 query.
bindValue(
":HOSTNAME", (HostName.isEmpty()) ? QString() : HostName);
544 query.
bindValue(
":APPLICATION", (Application.isEmpty()) ? QString() :
548 query.
bindValue(
":TID", ( TID == 0 ) ? QVariant(QVariant::ULongLong) :
550 query.
bindValue(
":THREAD", (Thread.isEmpty()) ? QString() : Thread);
552 query.
bindValue(
":LINE", ( Line == 0 ) ? QVariant(QVariant::ULongLong) :
554 query.
bindValue(
":FUNCTION", (Function.isEmpty()) ? QString() : Function);
555 query.
bindValue(
":FROMTIME", (FromTime.isValid()) ? FromTime : QDateTime());
556 query.
bindValue(
":TOTIME", (ToTime.isValid()) ? ToTime : QDateTime());
558 QVariant(QVariant::ULongLong) :
561 if (!MsgContains.isEmpty())
570 throw( QString(
"Database Error executing query." ));
577 pLogMessage->setHostName(
query.
value(0).toString() );
578 pLogMessage->setApplication(
query.
value(1).toString() );
579 pLogMessage->setPID(
query.
value(2).toInt() );
580 pLogMessage->setTID(
query.
value(3).toInt() );
581 pLogMessage->setThread(
query.
value(4).toString() );
582 pLogMessage->setFilename(
query.
value(5).toString() );
583 pLogMessage->setLine(
query.
value(6).toInt() );
584 pLogMessage->setFunction(
query.
value(7).toString() );
588 pLogMessage->setMessage(
query.
value(10).toString() );
602 QMap<QString, Frontend*> frontends;
608 for (
auto * fe : qAsConst(frontends))
611 pFrontend->setName(fe->m_name);
612 pFrontend->setIP(fe->m_ip.toString());
615 pFrontend->setPort(port);
616 pFrontend->setOnLine(fe->m_connectionCount > 0);
628 const QString &sDefault )
631 throw( QString(
"Missing or empty Key (settings.value)") );
633 if (sHostName ==
"_GLOBAL_")
638 "WHERE value = :VALUE "
639 "AND (hostname IS NULL)" );
646 throw( QString(
"Database Error executing query." ));
654 if (sHostName.isEmpty())
671 throw( QString(
"Database not open while trying to load settings for host: %1")
678 pList->setHostName ( sHostName );
684 if (sHostName.isEmpty())
687 "WHERE (hostname IS NULL)" );
692 "WHERE (hostname = :HOSTNAME)" );
704 throw( QString(
"Database Error executing query." ));
719 const QString &sValue )
726 throw ( QString(
"Key Required" ));
734 const QString &sOldPassword,
735 const QString &sNewPassword )
737 LOG(VB_GENERAL, LOG_NOTICE,
"ChangePassword is deprecated, use "
738 "ManageDigestUser.");
749 const QString &sUserName,
750 const QString &sPassword,
751 const QString &sDBName,
754 bool bResult =
false;
756 QString db(
"mythconverg");
759 if (!sDBName.isEmpty())
765 bResult =
TestDatabase(sHostName, sUserName, sPassword, db, port);
775 const QString &sAddress,
779 bool bResult =
false;
781 if (sMessage.isEmpty())
784 if (Timeout < 0 || Timeout > 999)
788 "<mythmessage version=\"1\">\n"
789 " <text>" + sMessage +
"</text>\n"
790 " <timeout>" + QString::number(Timeout) +
"</timeout>\n"
793 QHostAddress address = QHostAddress::Broadcast;
794 unsigned short port = 6948;
796 if (!sAddress.isEmpty())
797 address.setAddress(sAddress);
802 auto *sock =
new QUdpSocket();
803 QByteArray utf8 = xmlMessage.toUtf8();
804 int size = utf8.length();
806 if (sock->writeDatagram(utf8.constData(), size, address, port) < 0)
808 LOG(VB_GENERAL, LOG_ERR,
809 QString(
"Failed to send UDP/XML packet (Message: %1 "
810 "Address: %2 Port: %3")
815 LOG(VB_GENERAL, LOG_DEBUG,
816 QString(
"UDP/XML packet sent! (Message: %1 Address: %2 Port: %3")
818 .
arg(address.toString().toLocal8Bit().constData()).arg(port));
829 const QString &sMessage,
830 const QString &sOrigin,
831 const QString &sDescription,
832 const QString &sImage,
833 const QString &sExtra,
834 const QString &sProgressText,
840 const QString &sAddress,
843 bool bResult =
false;
845 if (sMessage.isEmpty())
848 if (Duration < 0 || Duration > 999)
852 "<mythnotification version=\"1\">\n"
853 " <text>" + sMessage +
"</text>\n"
854 " <origin>" + (sOrigin.isNull() ? tr(
"MythServices") : sOrigin) +
"</origin>\n"
855 " <description>" + sDescription +
"</description>\n"
856 " <timeout>" + QString::number(Duration) +
"</timeout>\n"
857 " <image>" + sImage +
"</image>\n"
858 " <extra>" + sExtra +
"</extra>\n"
859 " <progress_text>" + sProgressText +
"</progress_text>\n"
860 " <progress>" + QString::number(fProgress) +
"</progress>\n"
861 " <fullscreen>" + (bFullscreen ?
"true" :
"false") +
"</fullscreen>\n"
862 " <visibility>" + QString::number(Visibility) +
"</visibility>\n"
863 " <priority>" + QString::number(
Priority) +
"</priority>\n"
864 " <type>" + (bError ?
"error" : Type) +
"</type>\n"
865 "</mythnotification>";
867 QHostAddress address = QHostAddress::Broadcast;
868 unsigned short port = 6948;
870 if (!sAddress.isEmpty())
871 address.setAddress(sAddress);
876 auto *sock =
new QUdpSocket();
877 QByteArray utf8 = xmlMessage.toUtf8();
878 int size = utf8.length();
880 if (sock->writeDatagram(utf8.constData(), size, address, port) < 0)
882 LOG(VB_GENERAL, LOG_ERR,
883 QString(
"Failed to send UDP/XML packet (Notification: %1 "
884 "Address: %2 Port: %3")
889 LOG(VB_GENERAL, LOG_DEBUG,
890 QString(
"UDP/XML packet sent! (Notification: %1 Address: %2 Port: %3")
892 .
arg(address.toString().toLocal8Bit().constData()).arg(port));
907 bool bResult =
false;
913 LOG(VB_GENERAL, LOG_NOTICE,
"Performing API invoked DB Backup.");
919 LOG(VB_GENERAL, LOG_NOTICE,
"Database backup succeeded.");
923 LOG(VB_GENERAL, LOG_ERR,
"Database backup failed.");
934 LOG(VB_GENERAL, LOG_NOTICE,
"Performing API invoked DB Check.");
939 LOG(VB_GENERAL, LOG_NOTICE,
"Database check complete.");
941 LOG(VB_GENERAL, LOG_ERR,
"Database check failed.");
950 LOG(VB_GENERAL, LOG_NOTICE,
"Shutdown delayed 5 minutes for external application.");
961 LOG(VB_GENERAL, LOG_NOTICE,
"Profile Submission...");
963 bool bResult =
profile.SubmitProfile();
965 LOG(VB_GENERAL, LOG_NOTICE,
"Profile Submitted.");
977 LOG(VB_GENERAL, LOG_NOTICE,
"Profile Deletion...");
979 bool bResult =
profile.DeleteProfile();
981 LOG(VB_GENERAL, LOG_NOTICE,
"Profile Deleted.");
996 sProfileURL =
profile.GetProfileURL();
997 LOG(VB_GENERAL, LOG_NOTICE, QString(
"ProfileURL: %1").
arg(sProfileURL));
1008 QString sProfileUpdate;
1013 tUpdated =
profile.GetLastUpdate();
1014 sProfileUpdate = tUpdated.toString(
1017 return sProfileUpdate;
1026 QString sProfileText;
1031 return sProfileText;
1050 pBuild->setVersion ( MYTH_SOURCE_VERSION );
1051 pBuild->setLibX264 ( CONFIG_LIBX264 );
1052 pBuild->setLibDNS_SD ( CONFIG_LIBDNS_SD );
1053 pEnv->setLANG ( qEnvironmentVariable(
"LANG") );
1054 pEnv->setLCALL ( qEnvironmentVariable(
"LC_ALL") );
1055 pEnv->setLCCTYPE ( qEnvironmentVariable(
"LC_CTYPE") );
1056 pEnv->setHOME ( qEnvironmentVariable(
"HOME") );
1057 pEnv->setMYTHCONFDIR ( qEnvironmentVariable(
"MYTHCONFDIR") );
1073 const QString &sUserName,
1074 const QString &sPassword,
1075 const QString &sNewPassword,
1076 const QString &sAdminPassword )
1081 if (sAction ==
"Add")
1083 else if (sAction ==
"Remove")
1085 else if (sAction ==
"ChangePassword")
1089 LOG(VB_GENERAL, LOG_ERR, QString(
"Action must be Add, Remove or "
1090 "ChangePassword, not '%1'")
1096 sPassword, sNewPassword,
1105 const QString &sAdminPassword )
1109 LOG(VB_GENERAL, LOG_ERR, QString(
"Backend has no '%1' user!")
1117 LOG(VB_GENERAL, LOG_ERR, QString(
"Incorrect password for user: %1")
1122 QStringList serviceList = sServices.split(
",");
1124 serviceList.removeDuplicates();
1126 QStringList protectedURLs;
1128 if (serviceList.size() == 1 && serviceList.first() ==
"All")
1131 protectedURLs <<
'/' + service;
1133 else if (serviceList.size() == 1 && serviceList.first() ==
"None")
1135 protectedURLs <<
"Unprotected";
1139 for (
const QString& service : serviceList)
1142 protectedURLs <<
'/' + service;
1144 LOG(VB_GENERAL, LOG_ERR, QString(
"Invalid service name: '%1'")
1149 if (protectedURLs.isEmpty())
1151 LOG(VB_GENERAL, LOG_ERR,
"No valid Services were found");
1156 protectedURLs.join(
';'),
"");
DTC::BackendInfo * GetBackendInfo(void) override
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
static bool IsValidUser(const QString &username)
Check if the given user exists but not whether there is a valid session open for them!
QSqlQuery wrapper that fetches a DB connection from the connection pool.
static QString GetPasswordDigest(const QString &username)
Load the password digest for comparison in the HTTP Auth code.
const QStringList KnownServices
bool BackupDatabase(void) override
bool DelayShutdown(void) override
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
QString m_dbHostName
database server
DTC::StorageGroupDirList * GetStorageGroupDirs(const QString &GroupName, const QString &HostName) override
bool RemoveStorageGroupDir(const QString &GroupName, const QString &DirName, const QString &HostName) override
QString GetSetting(const QString &HostName, const QString &Key, const QString &Default) override
bool ProfileSubmit(void) override
MythScheduler * GetScheduler(void)
bool AddStorageGroupDir(const QString &GroupName, const QString &DirName, const QString &HostName) override
QList< LogMessage * > LogMessageList
int64_t getDiskSpace(const QString &file_on_disk, int64_t &total, int64_t &used)
QDateTime as_utc(const QDateTime &old_dt)
Returns copy of QDateTime with TimeSpec set to UTC.
QString getTimeZoneID(void)
Returns the zoneinfo time zone ID or as much time zone information as possible.
Structure containing the basic Database parameters.
QString GetHostName() override
QVariant value(int i) const
arg(title).arg(filename).arg(doDelete))
bool TestDatabase(const QString &dbHostName, const QString &dbUserName, QString dbPassword, QString dbName, int dbPort)
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
static QByteArray CreateDigest(const QString &username, const QString &password)
Generate a digest string.
bool SendMessage(const QString &Message, const QString &Address, int udpPort, int Timeout) override
static bool CheckTables(bool repair=false, const QString &options="QUICK")
Checks database tables.
QString m_dbType
database type (MySQL, Postgres, etc.)
DatabaseParams GetDatabaseParams(void)
QString GetFormatDate(const QDateTime &Date, bool ShortDate) override
BackendContext * gBackendContext
@ kDateTimeShort
Default local time.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
bool TestDBSettings(const QString &HostName, const QString &UserName, const QString &Password, const QString &DBName, int dbPort) override
DTC::ConnectionInfo * GetConnectionInfo(const QString &Pin) override
DTC::TimeZoneInfo * GetTimeZone() override
int m_wolReconnect
seconds to wait for reconnect
int m_dbPort
database port
QString logLevelGetName(LogLevel_t level)
Map a log level enumerated value back to the name.
static bool ManageDigestUser(DigestUserActions action, const QString &username, const QString &password, const QString &newPassword, const QString &adminPassword)
Manage digest user entries.
bool m_dbHostPing
Can we test connectivity using ping?
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
QString GetBackendServerIP(void)
Returns the IP address of the locally defined backend IP.
static void DBError(const QString &where, const MSqlQuery &query)
QMap< QString, Frontend * > GetFrontends() const
QString GetFormatDateTime(const QDateTime &DateTime, bool ShortDate) override
LogLevel_t logLevelGet(const QString &level)
Map a log level name back to the enumerated value.
QString ProfileUpdated(void) override
static QString GetHardwareProfile(void)
bool ProfileDelete(void) override
@ kAutoYear
Add year only if different from current year.
@ kDateShort
Default local time.
Aggregates database and DBMS utility functions.
int GetNumSettingOnHost(const QString &key, const QString &host, int defaultval=0)
static MythDBBackupStatus BackupDB(QString &filename, bool disableRotation=false)
Requests a backup of the database.
bool PutSetting(const QString &HostName, const QString &Key, const QString &Value) override
QString m_dbPassword
DB password.
Contains Packet Identifier numeric values.
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
int m_wolRetry
times to retry to reconnect
QString m_dbName
database name
bool isConnected(void) const
Only updated once during object creation.
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
QStringList GetKeys() override
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
@ kSimplify
Do Today/Yesterday/Tomorrow transform.
QMap< QString, Frontend * > GetConnectedFrontends() const
#define MYTH_BINARY_VERSION
Update this whenever the plug-in ABI changes.
#define MYTH_PROTO_VERSION
Increment this whenever the MythTV network protocol changes.
int calc_utc_offset(void)
bool CheckDatabase(bool Repair) override
bool ManageDigestUser(const QString &Action, const QString &UserName, const QString &Password, const QString &NewPassword, const QString &AdminPassword) override
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
QString m_wolCommand
command to use for wake-on-lan
QString GetSettingOnHost(const QString &key, const QString &host, const QString &defaultval="")
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
QString m_dbUserName
DB user name.
QDateTime ParseISODateString(const QString &DateTime) override
@ kDateFull
Default local time.
QString GetHostName(void)
#define MYTH_DATABASE_VERSION
Increment this whenever the MythTV core database schema changes.
DTC::SettingList * GetSettingList(const QString &HostName) override
bool ChangePassword(const QString &UserName, const QString &OldPassword, const QString &NewPassword) override
QStringList GetHosts() override
bool m_localEnabled
true if localHostName is not default
@ kDateTimeFull
Default local time.
bool ManageUrlProtection(const QString &Services, const QString &AdminPassword) override
@ kTime
Default local time.
QString ProfileText(void) override
bool m_wolEnabled
true if wake-on-lan params are used
QString m_localHostName
name used for loading/saving settings
MSqlQuery query(MSqlQuery::InitCon())
bool SaveSettingOnHost(const QString &key, const QString &newValue, const QString &host)
QString ProfileURL(void) override
QString GetFormatTime(const QDateTime &Time) override
QString GetSetting(const QString &key, const QString &defaultval="")
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
DTC::FrontendList * GetFrontends(bool OnLine) override