29 #include <QCryptographicHash>
30 #include <QHostAddress>
42 #include "libmythbase/mythversion.h"
44 #include "libmythbase/version.h"
60 if ( sSecurityPin.isEmpty() )
61 throw( QString(
"No Security Pin assigned. Run mythtv-setup to set one." ));
64 if ((sSecurityPin !=
"0000" ) && ( sPin != sSecurityPin ))
65 throw( QString(
"Not Authorized" ));
77 if ((params.
m_dbHostName.compare(
"localhost",Qt::CaseInsensitive)==0
80 && !sServerIP.isEmpty())
91 if (addr.setAddress(dbHostName))
93 addr.setScopeId(QString());
94 dbHostName = addr.toString();
105 pDatabase->setHost ( dbHostName );
107 pDatabase->setPort ( params.
m_dbPort );
110 pDatabase->setName ( params.
m_dbName );
111 pDatabase->setType ( params.
m_dbType );
120 pVersion->setVersion ( MYTH_SOURCE_VERSION );
121 pVersion->setBranch ( MYTH_SOURCE_PATH );
122 pVersion->setProtocol ( MYTH_PROTO_VERSION );
123 pVersion->setBinary ( MYTH_BINARY_VERSION );
124 pVersion->setSchema ( MYTH_DATABASE_VERSION );
140 throw( QString(
"No MythCoreContext in GetHostName." ));
153 throw( QString(
"Database not open while trying to load list of hosts" ));
156 "SELECT DISTINCTROW hostname "
158 "WHERE (not isNull( hostname ))");
164 throw( QString(
"Database Error executing query." ));
174 oList.append( query.
value(0).toString() );
188 throw( QString(
"Database not open while trying to load settings"));
190 query.
prepare(
"SELECT DISTINCTROW value FROM settings;" );
196 throw( QString(
"Database Error executing query." ));
203 QStringList oResults;
208 oResults.append( query.
value(0).toString() );
218 const QString &sHostName )
223 throw( QString(
"Database not open while trying to list "
224 "Storage Group Dirs"));
226 if (!sGroupName.isEmpty() && !sHostName.isEmpty())
228 query.
prepare(
"SELECT id, groupname, hostname, dirname "
230 "WHERE groupname = :GROUP AND hostname = :HOST "
231 "ORDER BY groupname, hostname, dirname" );
235 else if (!sHostName.isEmpty())
237 query.
prepare(
"SELECT id, groupname, hostname, dirname "
239 "WHERE hostname = :HOST "
240 "ORDER BY groupname, hostname, dirname" );
243 else if (!sGroupName.isEmpty())
245 query.
prepare(
"SELECT id, groupname, hostname, dirname "
247 "WHERE groupname = :GROUP "
248 "ORDER BY groupname, hostname, dirname" );
253 query.
prepare(
"SELECT id, groupname, hostname, dirname "
255 "ORDER BY groupname, hostname, dirname" );
262 throw( QString(
"Database Error executing query." ));
274 QFileInfo fi(query.
value(3).toString());
281 pStorageGroupDir->setId ( query.
value(0).toInt() );
282 pStorageGroupDir->setGroupName ( query.
value(1).toString() );
283 pStorageGroupDir->setHostName ( query.
value(2).toString() );
284 pStorageGroupDir->setDirName ( query.
value(3).toString() );
285 pStorageGroupDir->setDirRead ( fi.isReadable() );
286 pStorageGroupDir->setDirWrite ( fi.isWritable() );
287 pStorageGroupDir->setKiBFree ( free );
298 const QString &sDirName,
299 const QString &sHostName )
304 throw( QString(
"Database not open while trying to add Storage Group "
307 if (sGroupName.isEmpty())
308 throw ( QString(
"Storage Group Required" ));
310 if (sDirName.isEmpty())
311 throw ( QString(
"Directory Name Required" ));
313 if (sHostName.isEmpty())
314 throw ( QString(
"HostName Required" ));
316 query.
prepare(
"SELECT COUNT(*) "
318 "WHERE groupname = :GROUPNAME "
319 "AND dirname = :DIRNAME "
320 "AND hostname = :HOSTNAME;");
321 query.
bindValue(
":GROUPNAME", sGroupName );
323 query.
bindValue(
":HOSTNAME" , sHostName );
328 throw( QString(
"Database Error executing query." ));
333 if (query.
value(0).toInt() > 0)
337 query.
prepare(
"INSERT storagegroup "
338 "( groupname, dirname, hostname ) "
340 "( :GROUPNAME, :DIRNAME, :HOSTNAME );");
341 query.
bindValue(
":GROUPNAME", sGroupName );
343 query.
bindValue(
":HOSTNAME" , sHostName );
349 throw( QString(
"Database Error executing query." ));
360 const QString &sDirName,
361 const QString &sHostName )
366 throw( QString(
"Database not open while trying to remove Storage "
369 if (sGroupName.isEmpty())
370 throw ( QString(
"Storage Group Required" ));
372 if (sDirName.isEmpty())
373 throw ( QString(
"Directory Name Required" ));
375 if (sHostName.isEmpty())
376 throw ( QString(
"HostName Required" ));
380 "WHERE groupname = :GROUPNAME "
381 "AND dirname = :DIRNAME "
382 "AND hostname = :HOSTNAME;");
383 query.
bindValue(
":GROUPNAME", sGroupName );
385 query.
bindValue(
":HOSTNAME" , sHostName );
390 throw( QString(
"Database Error executing query." ));
454 if (!dateTime.isValid())
455 throw QString(
"Unable to parse DateTimeString" );
465 const QString &Application,
468 const QString &Thread,
471 const QString &Function,
472 const QDateTime &FromTime,
473 const QDateTime &ToTime,
474 const QString &Level,
475 const QString &MsgContains )
482 QString sql =
"SELECT DISTINCT host FROM logging ORDER BY host ASC";
483 if (!query.
exec(sql))
487 throw( QString(
"Database Error executing query." ));
492 QString availableHostName = query.
value(0).toString();
493 pLabelValue->setValue ( availableHostName );
494 pLabelValue->setActive ( availableHostName == HostName );
495 pLabelValue->setSelected( availableHostName == HostName );
498 sql =
"SELECT DISTINCT application FROM logging ORDER BY application ASC";
499 if (!query.
exec(sql))
503 throw( QString(
"Database Error executing query." ));
508 QString availableApplication = query.
value(0).toString();
509 pLabelValue->setValue ( availableApplication );
510 pLabelValue->setActive ( availableApplication == Application );
511 pLabelValue->setSelected( availableApplication == Application );
514 if (!HostName.isEmpty() && !Application.isEmpty())
517 sql =
"SELECT host, application, pid, tid, thread, filename, "
518 " line, `function`, msgtime, level, message "
520 " WHERE host = COALESCE(:HOSTNAME, host) "
521 " AND application = COALESCE(:APPLICATION, application) "
522 " AND pid = COALESCE(:PID, pid) "
523 " AND tid = COALESCE(:TID, tid) "
524 " AND thread = COALESCE(:THREAD, thread) "
525 " AND filename = COALESCE(:FILENAME, filename) "
526 " AND line = COALESCE(:LINE, line) "
527 " AND `function` = COALESCE(:FUNCTION, `function`) "
528 " AND msgtime >= COALESCE(:FROMTIME, msgtime) "
529 " AND msgtime <= COALESCE(:TOTIME, msgtime) "
530 " AND level <= COALESCE(:LEVEL, level) "
532 if (!MsgContains.isEmpty())
534 sql.append(
" AND message LIKE :MSGCONTAINS ");
536 sql.append(
" ORDER BY msgtime ASC;");
538 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
539 QVariant ullNull = QVariant(QVariant::ULongLong);
541 QVariant ullNull = QVariant(QMetaType(QMetaType::ULongLong));
545 query.
bindValue(
":HOSTNAME", (HostName.isEmpty()) ? QString() : HostName);
546 query.
bindValue(
":APPLICATION", (Application.isEmpty()) ? QString() :
549 query.
bindValue(
":TID", ( TID == 0 ) ? ullNull : (qint64)TID);
550 query.
bindValue(
":THREAD", (Thread.isEmpty()) ? QString() : Thread);
552 query.
bindValue(
":LINE", ( Line == 0 ) ? ullNull : (qint64)Line);
553 query.
bindValue(
":FUNCTION", (Function.isEmpty()) ? QString() : Function);
554 query.
bindValue(
":FROMTIME", (FromTime.isValid()) ? FromTime : QDateTime());
555 query.
bindValue(
":TOTIME", (ToTime.isValid()) ? ToTime : QDateTime());
556 query.
bindValue(
":LEVEL", (Level.isEmpty()) ? ullNull :
559 if (!MsgContains.isEmpty())
561 query.
bindValue(
":MSGCONTAINS",
"%" + MsgContains +
"%" );
568 throw( QString(
"Database Error executing query." ));
575 pLogMessage->setHostName( query.
value(0).toString() );
576 pLogMessage->setApplication( query.
value(1).toString() );
577 pLogMessage->setPID( query.
value(2).toInt() );
578 pLogMessage->setTID( query.
value(3).toInt() );
579 pLogMessage->setThread( query.
value(4).toString() );
580 pLogMessage->setFilename( query.
value(5).toString() );
581 pLogMessage->setLine( query.
value(6).toInt() );
582 pLogMessage->setFunction( query.
value(7).toString() );
585 (LogLevel_t)query.
value(9).toInt()) );
586 pLogMessage->setMessage( query.
value(10).toString() );
600 QMap<QString, Frontend*> frontends;
606 for (
auto * fe : qAsConst(frontends))
609 pFrontend->setName(fe->m_name);
610 pFrontend->setIP(fe->m_ip.toString());
613 pFrontend->setPort(port);
614 pFrontend->setOnLine(fe->m_connectionCount > 0);
626 const QString &sDefault )
629 throw( QString(
"Missing or empty Key (settings.value)") );
631 if (sHostName ==
"_GLOBAL_")
635 query.
prepare(
"SELECT data FROM settings "
636 "WHERE value = :VALUE "
637 "AND (hostname IS NULL)" );
644 throw( QString(
"Database Error executing query." ));
647 return query.
next() ? query.
value(0).toString() : sDefault;
652 if (sHostName.isEmpty())
669 throw( QString(
"Database not open while trying to load settings for host: %1")
676 pList->setHostName ( sHostName );
682 if (sHostName.isEmpty())
684 query.
prepare(
"SELECT value, data FROM settings "
685 "WHERE (hostname IS NULL)" );
689 query.
prepare(
"SELECT value, data FROM settings "
690 "WHERE (hostname = :HOSTNAME)" );
692 query.
bindValue(
":HOSTNAME", sHostName );
702 throw( QString(
"Database Error executing query." ));
706 pList->Settings().insert( query.
value(0).toString(), query.
value(1) );
717 const QString &sValue )
724 throw ( QString(
"Key Required" ));
732 const QString &sOldPassword,
733 const QString &sNewPassword )
735 LOG(VB_GENERAL, LOG_NOTICE,
"ChangePassword is deprecated, use "
736 "ManageDigestUser.");
747 const QString &sUserName,
748 const QString &sPassword,
749 const QString &sDBName,
752 bool bResult =
false;
754 QString db(
"mythconverg");
757 if (!sDBName.isEmpty())
763 bResult =
TestDatabase(sHostName, sUserName, sPassword, db, port);
773 const QString &sAddress,
777 bool bResult =
false;
779 if (sMessage.isEmpty())
782 if (Timeout < 0 || Timeout > 999)
786 "<mythmessage version=\"1\">\n"
787 " <text>" + sMessage +
"</text>\n"
788 " <timeout>" + QString::number(Timeout) +
"</timeout>\n"
791 QHostAddress address = QHostAddress::Broadcast;
792 unsigned short port = 6948;
794 if (!sAddress.isEmpty())
795 address.setAddress(sAddress);
800 auto *sock =
new QUdpSocket();
801 QByteArray utf8 = xmlMessage.toUtf8();
802 int size = utf8.length();
804 if (sock->writeDatagram(utf8.constData(), size, address, port) < 0)
806 LOG(VB_GENERAL, LOG_ERR,
807 QString(
"Failed to send UDP/XML packet (Message: %1 "
808 "Address: %2 Port: %3")
809 .arg(sMessage, sAddress, QString::number(port)));
813 LOG(VB_GENERAL, LOG_DEBUG,
814 QString(
"UDP/XML packet sent! (Message: %1 Address: %2 Port: %3")
816 address.toString().toLocal8Bit(),
817 QString::number(port)));
828 const QString &sMessage,
829 const QString &sOrigin,
830 const QString &sDescription,
831 const QString &sImage,
832 const QString &sExtra,
833 const QString &sProgressText,
839 const QString &sAddress,
842 bool bResult =
false;
844 if (sMessage.isEmpty())
847 if (Duration < 0 || Duration > 999)
851 "<mythnotification version=\"1\">\n"
852 " <text>" + sMessage +
"</text>\n"
853 " <origin>" + (sOrigin.isNull() ? tr(
"MythServices") : sOrigin) +
"</origin>\n"
854 " <description>" + sDescription +
"</description>\n"
855 " <timeout>" + QString::number(Duration) +
"</timeout>\n"
856 " <image>" + sImage +
"</image>\n"
857 " <extra>" + sExtra +
"</extra>\n"
858 " <progress_text>" + sProgressText +
"</progress_text>\n"
859 " <progress>" + QString::number(fProgress) +
"</progress>\n"
860 " <fullscreen>" + (bFullscreen ?
"true" :
"false") +
"</fullscreen>\n"
861 " <visibility>" + QString::number(Visibility) +
"</visibility>\n"
862 " <priority>" + QString::number(
Priority) +
"</priority>\n"
863 " <type>" + (bError ?
"error" : Type) +
"</type>\n"
864 "</mythnotification>";
866 QHostAddress address = QHostAddress::Broadcast;
867 unsigned short port = 6948;
869 if (!sAddress.isEmpty())
870 address.setAddress(sAddress);
875 auto *sock =
new QUdpSocket();
876 QByteArray utf8 = xmlMessage.toUtf8();
877 int size = utf8.length();
879 if (sock->writeDatagram(utf8.constData(), size, address, port) < 0)
881 LOG(VB_GENERAL, LOG_ERR,
882 QString(
"Failed to send UDP/XML packet (Notification: %1 "
883 "Address: %2 Port: %3")
884 .arg(sMessage, sAddress, QString::number(port)));
888 LOG(VB_GENERAL, LOG_DEBUG,
889 QString(
"UDP/XML packet sent! (Notification: %1 Address: %2 Port: %3")
891 address.toString().toLocal8Bit(), QString::number(port)));
906 bool bResult =
false;
912 LOG(VB_GENERAL, LOG_NOTICE,
"Performing API invoked DB Backup.");
918 LOG(VB_GENERAL, LOG_NOTICE,
"Database backup succeeded.");
922 LOG(VB_GENERAL, LOG_ERR,
"Database backup failed.");
933 LOG(VB_GENERAL, LOG_NOTICE,
"Performing API invoked DB Check.");
938 LOG(VB_GENERAL, LOG_NOTICE,
"Database check complete.");
940 LOG(VB_GENERAL, LOG_ERR,
"Database check failed.");
948 if (scheduler ==
nullptr)
951 LOG(VB_GENERAL, LOG_NOTICE,
"Shutdown delayed 5 minutes for external application.");
962 LOG(VB_GENERAL, LOG_NOTICE,
"Profile Submission...");
964 bool bResult =
profile.SubmitProfile();
966 LOG(VB_GENERAL, LOG_NOTICE,
"Profile Submitted.");
978 LOG(VB_GENERAL, LOG_NOTICE,
"Profile Deletion...");
980 bool bResult =
profile.DeleteProfile();
982 LOG(VB_GENERAL, LOG_NOTICE,
"Profile Deleted.");
997 sProfileURL =
profile.GetProfileURL();
998 LOG(VB_GENERAL, LOG_NOTICE, QString(
"ProfileURL: %1").arg(sProfileURL));
1009 QString sProfileUpdate;
1014 tUpdated =
profile.GetLastUpdate();
1015 sProfileUpdate = tUpdated.toString(
1018 return sProfileUpdate;
1027 QString sProfileText;
1032 return sProfileText;
1051 pBuild->setVersion ( MYTH_SOURCE_VERSION );
1052 pBuild->setLibX264 ( CONFIG_LIBX264 );
1053 pBuild->setLibDNS_SD ( CONFIG_LIBDNS_SD );
1054 pEnv->setLANG ( qEnvironmentVariable(
"LANG") );
1055 pEnv->setLCALL ( qEnvironmentVariable(
"LC_ALL") );
1056 pEnv->setLCCTYPE ( qEnvironmentVariable(
"LC_CTYPE") );
1057 pEnv->setHOME ( qEnvironmentVariable(
"HOME") );
1058 pEnv->setMYTHCONFDIR ( qEnvironmentVariable(
"MYTHCONFDIR") );
1074 const QString &sUserName,
1075 const QString &sPassword,
1076 const QString &sNewPassword,
1077 const QString &sAdminPassword )
1082 if (sAction ==
"Add")
1084 else if (sAction ==
"Remove")
1086 else if (sAction ==
"ChangePassword")
1090 LOG(VB_GENERAL, LOG_ERR, QString(
"Action must be Add, Remove or "
1091 "ChangePassword, not '%1'")
1097 sPassword, sNewPassword,
1106 const QString &sAdminPassword )
1110 LOG(VB_GENERAL, LOG_ERR, QString(
"Backend has no '%1' user!")
1118 LOG(VB_GENERAL, LOG_ERR, QString(
"Incorrect password for user: %1")
1123 QStringList serviceList = sServices.split(
",");
1125 serviceList.removeDuplicates();
1127 QStringList protectedURLs;
1129 if (serviceList.size() == 1 && serviceList.first() ==
"All")
1132 protectedURLs <<
'/' + service;
1134 else if (serviceList.size() == 1 && serviceList.first() ==
"None")
1136 protectedURLs <<
"Unprotected";
1140 for (
const QString& service : serviceList)
1143 protectedURLs <<
'/' + service;
1145 LOG(VB_GENERAL, LOG_ERR, QString(
"Invalid service name: '%1'")
1150 if (protectedURLs.isEmpty())
1152 LOG(VB_GENERAL, LOG_ERR,
"No valid Services were found");
1157 protectedURLs.join(
';'),
"");