4 #include <QCryptographicHash>
5 #include <QHostAddress>
18 #include "libmythbase/mythversion.h"
20 #include "libmythbase/version.h"
38 qRegisterMetaType<V2ConnectionInfo*>(
"V2ConnectionInfo");
39 qRegisterMetaType<V2VersionInfo*>(
"V2VersionInfo");
40 qRegisterMetaType<V2DatabaseInfo*>(
"V2DatabaseInfo");
41 qRegisterMetaType<V2WOLInfo*>(
"V2WOLInfo");
42 qRegisterMetaType<V2StorageGroupDirList*>(
"V2StorageGroupDirList");
43 qRegisterMetaType<V2StorageGroupDir*>(
"V2StorageGroupDir");
44 qRegisterMetaType<V2TimeZoneInfo*>(
"V2TimeZoneInfo");
45 qRegisterMetaType<V2LogMessage*>(
"V2LogMessage");
46 qRegisterMetaType<V2LogMessageList*>(
"V2LogMessageList");
47 qRegisterMetaType<V2LabelValue*>(
"V2LabelValue");
48 qRegisterMetaType<V2Frontend*>(
"V2Frontend");
49 qRegisterMetaType<V2FrontendList*>(
"V2FrontendList");
50 qRegisterMetaType<V2SettingList*>(
"V2SettingList");
51 qRegisterMetaType<V2BackendInfo*>(
"V2BackendInfo");
52 qRegisterMetaType<V2EnvInfo*>(
"V2EnvInfo");
53 qRegisterMetaType<V2LogInfo*>(
"V2LogInfo");
54 qRegisterMetaType<V2BuildInfo*>(
"V2BuildInfo");
71 if ( sSecurityPin.isEmpty() )
72 throw( QString(
"No Security Pin assigned. Run mythtv-setup to set one." ));
75 if ((sSecurityPin !=
"0000" ) && ( sPin != sSecurityPin ))
76 throw( QString(
"Not Authorized" ));
88 if ((params.
m_dbHostName.compare(
"localhost",Qt::CaseInsensitive)==0
91 && !sServerIP.isEmpty())
102 if (addr.setAddress(dbHostName))
104 addr.setScopeId(QString());
105 dbHostName = addr.toString();
116 pDatabase->setHost ( dbHostName );
118 pDatabase->setPort ( params.
m_dbPort );
121 pDatabase->setName ( params.
m_dbName );
122 pDatabase->setType ( params.
m_dbType );
131 pVersion->setVersion ( MYTH_SOURCE_VERSION );
132 pVersion->setBranch ( MYTH_SOURCE_PATH );
133 pVersion->setProtocol ( MYTH_PROTO_VERSION );
134 pVersion->setBinary ( MYTH_BINARY_VERSION );
135 pVersion->setSchema ( MYTH_DATABASE_VERSION );
149 bool bResult =
false;
151 QString db(
"mythconverg");
161 throw( QString(
"Database test failed. Not saving database connection information." ));
188 throw( QString(
"No MythCoreContext in GetHostName." ));
202 throw( QString(
"Database not open while trying to load list of hosts" ));
205 "SELECT DISTINCTROW hostname "
207 "WHERE (not isNull( hostname ))");
213 throw( QString(
"Database Error executing query." ));
223 oList.append( query.
value(0).toString() );
237 throw( QString(
"Database not open while trying to load settings"));
239 query.
prepare(
"SELECT DISTINCTROW value FROM settings;" );
245 throw( QString(
"Database Error executing query." ));
252 QStringList oResults;
257 oResults.append( query.
value(0).toString() );
268 QDir directory(DirName);
269 return directory.entryList(QDir::AllDirs|QDir::NoDotAndDotDot, QDir::Name);
277 const QString &sHostName )
282 throw( QString(
"Database not open while trying to list "
283 "Storage Group Dirs"));
285 if (!sGroupName.isEmpty() && !sHostName.isEmpty())
287 query.
prepare(
"SELECT id, groupname, hostname, dirname "
289 "WHERE groupname = :GROUP AND hostname = :HOST "
290 "ORDER BY groupname, hostname, dirname" );
294 else if (!sHostName.isEmpty())
296 query.
prepare(
"SELECT id, groupname, hostname, dirname "
298 "WHERE hostname = :HOST "
299 "ORDER BY groupname, hostname, dirname" );
302 else if (!sGroupName.isEmpty())
304 query.
prepare(
"SELECT id, groupname, hostname, dirname "
306 "WHERE groupname = :GROUP "
307 "ORDER BY groupname, hostname, dirname" );
312 query.
prepare(
"SELECT id, groupname, hostname, dirname "
314 "ORDER BY groupname, hostname, dirname" );
321 throw( QString(
"Database Error executing query." ));
333 QFileInfo fi(query.
value(3).toString());
340 pStorageGroupDir->setId ( query.
value(0).toInt() );
341 pStorageGroupDir->setGroupName ( query.
value(1).toString() );
342 pStorageGroupDir->setHostName ( query.
value(2).toString() );
343 pStorageGroupDir->setDirName ( query.
value(3).toString() );
344 pStorageGroupDir->setDirRead ( fi.isReadable() );
345 pStorageGroupDir->setDirWrite ( fi.isWritable() );
346 pStorageGroupDir->setKiBFree ( free );
357 const QString &sDirName,
358 const QString &sHostName )
363 throw( QString(
"Database not open while trying to add Storage Group "
366 if (sGroupName.isEmpty())
367 throw ( QString(
"Storage Group Required" ));
369 if (sDirName.isEmpty())
370 throw ( QString(
"Directory Name Required" ));
372 if (sHostName.isEmpty())
373 throw ( QString(
"HostName Required" ));
375 query.
prepare(
"SELECT COUNT(*) "
377 "WHERE groupname = :GROUPNAME "
378 "AND dirname = :DIRNAME "
379 "AND hostname = :HOSTNAME;");
380 query.
bindValue(
":GROUPNAME", sGroupName );
382 query.
bindValue(
":HOSTNAME" , sHostName );
387 throw( QString(
"Database Error executing query." ));
392 if (query.
value(0).toInt() > 0)
396 query.
prepare(
"INSERT storagegroup "
397 "( groupname, dirname, hostname ) "
399 "( :GROUPNAME, :DIRNAME, :HOSTNAME );");
400 query.
bindValue(
":GROUPNAME", sGroupName );
402 query.
bindValue(
":HOSTNAME" , sHostName );
408 throw( QString(
"Database Error executing query." ));
419 const QString &sDirName,
420 const QString &sHostName )
425 throw( QString(
"Database not open while trying to remove Storage "
428 if (sGroupName.isEmpty())
429 throw ( QString(
"Storage Group Required" ));
431 if (sDirName.isEmpty())
432 throw ( QString(
"Directory Name Required" ));
434 if (sHostName.isEmpty())
435 throw ( QString(
"HostName Required" ));
439 "WHERE groupname = :GROUPNAME "
440 "AND dirname = :DIRNAME "
441 "AND hostname = :HOSTNAME;");
442 query.
bindValue(
":GROUPNAME", sGroupName );
444 query.
bindValue(
":HOSTNAME" , sHostName );
449 throw( QString(
"Database Error executing query." ));
513 if (!dateTime.isValid())
514 throw QString(
"Unable to parse DateTime" );
524 const QString &Application,
527 const QString &Thread,
528 const QString &Filename,
530 const QString &Function,
531 const QDateTime &FromTime,
532 const QDateTime &ToTime,
533 const QString &Level,
534 const QString &MsgContains )
541 QString sql =
"SELECT DISTINCT host FROM logging ORDER BY host ASC";
542 if (!query.
exec(sql))
546 throw( QString(
"Database Error executing query." ));
551 QString availableHostName = query.
value(0).toString();
552 pLabelValue->setValue ( availableHostName );
553 pLabelValue->setActive ( availableHostName == HostName );
554 pLabelValue->setSelected( availableHostName == HostName );
557 sql =
"SELECT DISTINCT application FROM logging ORDER BY application ASC";
558 if (!query.
exec(sql))
562 throw( QString(
"Database Error executing query." ));
567 QString availableApplication = query.
value(0).toString();
568 pLabelValue->setValue ( availableApplication );
569 pLabelValue->setActive ( availableApplication == Application );
570 pLabelValue->setSelected( availableApplication == Application );
573 if (!HostName.isEmpty() && !Application.isEmpty())
576 sql =
"SELECT host, application, pid, tid, thread, filename, "
577 " line, function, msgtime, level, message "
579 " WHERE host = COALESCE(:HOSTNAME, host) "
580 " AND application = COALESCE(:APPLICATION, application) "
581 " AND pid = COALESCE(:PID, pid) "
582 " AND tid = COALESCE(:TID, tid) "
583 " AND thread = COALESCE(:THREAD, thread) "
584 " AND filename = COALESCE(:FILENAME, filename) "
585 " AND line = COALESCE(:LINE, line) "
586 " AND function = COALESCE(:FUNCTION, function) "
587 " AND msgtime >= COALESCE(:FROMTIME, msgtime) "
588 " AND msgtime <= COALESCE(:TOTIME, msgtime) "
589 " AND level <= COALESCE(:LEVEL, level) "
591 if (!MsgContains.isEmpty())
593 sql.append(
" AND message LIKE :MSGCONTAINS ");
595 sql.append(
" ORDER BY msgtime ASC;");
597 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
598 QVariant ullNull = QVariant(QVariant::ULongLong);
600 QVariant ullNull = QVariant(QMetaType(QMetaType::ULongLong));
604 query.
bindValue(
":HOSTNAME", (HostName.isEmpty()) ? QString() : HostName);
605 query.
bindValue(
":APPLICATION", (Application.isEmpty()) ? QString() :
608 query.
bindValue(
":TID", ( TID == 0 ) ? ullNull : (qint64)TID);
609 query.
bindValue(
":THREAD", (Thread.isEmpty()) ? QString() : Thread);
610 query.
bindValue(
":FILENAME", (Filename.isEmpty()) ? QString() : Filename);
611 query.
bindValue(
":LINE", ( Line == 0 ) ? ullNull : (qint64)Line);
612 query.
bindValue(
":FUNCTION", (Function.isEmpty()) ? QString() : Function);
613 query.
bindValue(
":FROMTIME", (FromTime.isValid()) ? FromTime : QDateTime());
614 query.
bindValue(
":TOTIME", (ToTime.isValid()) ? ToTime : QDateTime());
615 query.
bindValue(
":LEVEL", (Level.isEmpty()) ? ullNull :
618 if (!MsgContains.isEmpty())
620 query.
bindValue(
":MSGCONTAINS",
"%" + MsgContains +
"%" );
627 throw( QString(
"Database Error executing query." ));
634 pLogMessage->setHostName( query.
value(0).toString() );
635 pLogMessage->setApplication( query.
value(1).toString() );
636 pLogMessage->setPID( query.
value(2).toInt() );
637 pLogMessage->setTID( query.
value(3).toInt() );
638 pLogMessage->setThread( query.
value(4).toString() );
639 pLogMessage->setFilename( query.
value(5).toString() );
640 pLogMessage->setLine( query.
value(6).toInt() );
641 pLogMessage->setFunction( query.
value(7).toString() );
644 (LogLevel_t)query.
value(9).toInt()) );
645 pLogMessage->setMessage( query.
value(10).toString() );
671 const QString &sDefault )
674 throw( QString(
"Missing or empty Key (settings.value)") );
676 if (sHostName ==
"_GLOBAL_")
680 query.
prepare(
"SELECT data FROM settings "
681 "WHERE value = :VALUE "
682 "AND (hostname IS NULL)" );
689 throw( QString(
"Database Error executing query." ));
692 return query.
next() ? query.
value(0).toString() : sDefault;
697 if (sHostName.isEmpty())
714 throw( QString(
"Database not open while trying to load settings for host: %1")
720 pList->setHostName ( sHostName );
726 if (sHostName.isEmpty())
728 query.
prepare(
"SELECT value, data FROM settings "
729 "WHERE (hostname IS NULL)" );
733 query.
prepare(
"SELECT value, data FROM settings "
734 "WHERE (hostname = :HOSTNAME)" );
736 query.
bindValue(
":HOSTNAME", sHostName );
746 throw( QString(
"Database Error executing query." ));
750 pList->Settings().insert( query.
value(0).toString(), query.
value(1) );
761 const QString &sValue )
763 QString hostName = sHostName;
765 if (hostName ==
"_GLOBAL_")
773 throw ( QString(
"Key Required" ));
783 QString hostName = sHostName;
785 if (hostName ==
"_GLOBAL_")
793 throw ( QString(
"Key Required" ));
802 const QString &sUserName,
803 const QString &sPassword,
804 const QString &sDBName,
807 bool bResult =
false;
809 QString db(
"mythconverg");
812 if (!sDBName.isEmpty())
818 bResult =
TestDatabase(sHostName, sUserName, sPassword, db, port);
828 const QString &sAddress,
832 bool bResult =
false;
834 if (sMessage.isEmpty())
837 if (Timeout < 0 || Timeout > 999)
841 "<mythmessage version=\"1\">\n"
842 " <text>" + sMessage +
"</text>\n"
843 " <timeout>" + QString::number(Timeout) +
"</timeout>\n"
846 QHostAddress address = QHostAddress::Broadcast;
847 unsigned short port = 6948;
849 if (!sAddress.isEmpty())
850 address.setAddress(sAddress);
855 auto *sock =
new QUdpSocket();
856 QByteArray utf8 = xmlMessage.toUtf8();
857 int size = utf8.length();
859 if (sock->writeDatagram(utf8.constData(), size, address, port) < 0)
861 LOG(VB_GENERAL, LOG_ERR,
862 QString(
"Failed to send UDP/XML packet (Message: %1 "
863 "Address: %2 Port: %3")
864 .arg(sMessage, sAddress, QString::number(port)));
868 LOG(VB_GENERAL, LOG_DEBUG,
869 QString(
"UDP/XML packet sent! (Message: %1 Address: %2 Port: %3")
871 address.toString().toLocal8Bit(),
872 QString::number(port)));
883 const QString &sMessage,
884 const QString &sOrigin,
885 const QString &sDescription,
886 const QString &sImage,
887 const QString &sExtra,
888 const QString &sProgressText,
894 const QString &sAddress,
897 bool bResult =
false;
899 if (sMessage.isEmpty())
902 if (Timeout < 0 || Timeout > 999)
906 "<mythnotification version=\"1\">\n"
907 " <text>" + sMessage +
"</text>\n"
908 " <origin>" + (sOrigin.isNull() ? tr(
"MythServices") : sOrigin) +
"</origin>\n"
909 " <description>" + sDescription +
"</description>\n"
910 " <timeout>" + QString::number(Timeout) +
"</timeout>\n"
911 " <image>" + sImage +
"</image>\n"
912 " <extra>" + sExtra +
"</extra>\n"
913 " <progress_text>" + sProgressText +
"</progress_text>\n"
914 " <progress>" + QString::number(fProgress) +
"</progress>\n"
915 " <fullscreen>" + (bFullscreen ?
"true" :
"false") +
"</fullscreen>\n"
916 " <visibility>" + QString::number(Visibility) +
"</visibility>\n"
917 " <priority>" + QString::number(
Priority) +
"</priority>\n"
918 " <type>" + (bError ?
"error" : Type) +
"</type>\n"
919 "</mythnotification>";
921 QHostAddress address = QHostAddress::Broadcast;
922 unsigned short port = 6948;
924 if (!sAddress.isEmpty())
925 address.setAddress(sAddress);
930 auto *sock =
new QUdpSocket();
931 QByteArray utf8 = xmlMessage.toUtf8();
932 int size = utf8.length();
934 if (sock->writeDatagram(utf8.constData(), size, address, port) < 0)
936 LOG(VB_GENERAL, LOG_ERR,
937 QString(
"Failed to send UDP/XML packet (Notification: %1 "
938 "Address: %2 Port: %3")
939 .arg(sMessage, sAddress, QString::number(port)));
943 LOG(VB_GENERAL, LOG_DEBUG,
944 QString(
"UDP/XML packet sent! (Notification: %1 Address: %2 Port: %3")
946 address.toString().toLocal8Bit(), QString::number(port)));
961 bool bResult =
false;
967 LOG(VB_GENERAL, LOG_NOTICE,
"Performing API invoked DB Backup.");
973 LOG(VB_GENERAL, LOG_NOTICE,
"Database backup succeeded.");
977 LOG(VB_GENERAL, LOG_ERR,
"Database backup failed.");
988 LOG(VB_GENERAL, LOG_NOTICE,
"Performing API invoked DB Check.");
993 LOG(VB_GENERAL, LOG_NOTICE,
"Database check complete.");
995 LOG(VB_GENERAL, LOG_ERR,
"Database check failed.");
1003 if (scheduler ==
nullptr)
1006 LOG(VB_GENERAL, LOG_NOTICE,
"Shutdown delayed 5 minutes for external application.");
1017 LOG(VB_GENERAL, LOG_NOTICE,
"Profile Submission...");
1019 bool bResult =
profile.SubmitProfile();
1021 LOG(VB_GENERAL, LOG_NOTICE,
"Profile Submitted.");
1033 LOG(VB_GENERAL, LOG_NOTICE,
"Profile Deletion...");
1035 bool bResult =
profile.DeleteProfile();
1037 LOG(VB_GENERAL, LOG_NOTICE,
"Profile Deleted.");
1048 QString sProfileURL;
1052 sProfileURL =
profile.GetProfileURL();
1053 LOG(VB_GENERAL, LOG_NOTICE, QString(
"ProfileURL: %1").arg(sProfileURL));
1064 QString sProfileUpdate;
1069 tUpdated =
profile.GetLastUpdate();
1070 sProfileUpdate = tUpdated.toString(
1073 return sProfileUpdate;
1082 QString sProfileText;
1087 return sProfileText;
1106 pBuild->setVersion ( MYTH_SOURCE_VERSION );
1107 pBuild->setLibX264 ( CONFIG_LIBX264 );
1108 pBuild->setLibDNS_SD ( CONFIG_LIBDNS_SD );
1109 pEnv->setLANG ( qEnvironmentVariable(
"LANG") );
1110 pEnv->setLCALL ( qEnvironmentVariable(
"LC_ALL") );
1111 pEnv->setLCCTYPE ( qEnvironmentVariable(
"LC_CTYPE") );
1112 pEnv->setHOME ( qEnvironmentVariable(
"HOME") );
1114 pEnv->setUSER ( qEnvironmentVariable(
"USER",
1115 qEnvironmentVariable(
"USERNAME")) );
1116 pEnv->setMYTHCONFDIR ( qEnvironmentVariable(
"MYTHCONFDIR") );
1118 if (scheduler !=
nullptr)
1119 pEnv->setSchedulingEnabled(scheduler->QueryScheduling());
1137 const QString &sUserName,
1138 const QString &sPassword,
1139 const QString &sNewPassword,
1140 const QString &sAdminPassword )
1145 if (sAction ==
"Add")
1147 else if (sAction ==
"Remove")
1149 else if (sAction ==
"ChangePassword")
1153 LOG(VB_GENERAL, LOG_ERR, QString(
"Action must be Add, Remove or "
1154 "ChangePassword, not '%1'")
1160 sPassword, sNewPassword,
1169 const QString &sAdminPassword )
1171 LOG(VB_GENERAL, LOG_WARNING, QString(
"ManageUrlProtection is deprecated."
1172 "Protection unavailable in API V2."));
1176 LOG(VB_GENERAL, LOG_ERR, QString(
"Backend has no '%1' user!")
1184 LOG(VB_GENERAL, LOG_ERR, QString(
"Incorrect password for user: %1")
1189 QStringList serviceList = sServices.split(
",");
1191 serviceList.removeDuplicates();
1193 QStringList protectedURLs;
1195 if (serviceList.size() == 1 && serviceList.first() ==
"All")
1198 protectedURLs <<
'/' + service;
1200 else if (serviceList.size() == 1 && serviceList.first() ==
"None")
1202 protectedURLs <<
"Unprotected";
1206 for (
const QString& service : serviceList)
1209 protectedURLs <<
'/' + service;
1211 LOG(VB_GENERAL, LOG_ERR, QString(
"Invalid service name: '%1'")
1216 if (protectedURLs.isEmpty())
1218 LOG(VB_GENERAL, LOG_ERR,
"No valid Services were found");
1223 protectedURLs.join(
';'),
"");
1229 if (scheduler ==
nullptr)
1230 throw QString(
"Scheduler is null");
1232 if (Enable == Disable)
1235 scheduler->EnableScheduling();
1237 scheduler->DisableScheduling();
1240 while (iter.hasNext())
1243 auto *tvrec = iter.value();
1244 tvrec->EnableActiveScan(Enable);
1251 if (Retcode < 0 || Retcode > 255)
1260 QCoreApplication::exit(Retcode);