16 #include <sys/ioctl.h> 18 #if CONFIG_SYSTEMD_NOTIFY 19 #include <systemd/sd-daemon.h> 25 #else // if !__linux__ 26 # include <sys/param.h> 28 # include <sys/mount.h> 32 #include <QCoreApplication> 36 #include <QWaitCondition> 37 #include <QWriteLocker> 42 #include <QNetworkInterface> 43 #include <QNetworkProxy> 44 #include <QHostAddress> 67 #include "ringbuffer.h" 91 #define PRT_TIMEOUT 10 93 #define PRT_STARTUP_THREAD_COUNT 5 95 #define LOC QString("MainServer: ") 96 #define LOC_WARN QString("MainServer, Warning: ") 97 #define LOC_ERR QString("MainServer, Error: ") 101 int delete_file_immediately(
const QString &filename,
102 bool followLinks,
bool checkexists)
105 QFile checkFile(filename);
106 int success1, success2;
108 LOG(VB_FILE, LOG_INFO,
LOC +
109 QString(
"About to delete file: %1").arg(filename));
114 QFileInfo finfo(filename);
115 if (finfo.isSymLink())
119 QFile target(linktext);
120 if (!(success1 = target.remove()))
122 LOG(VB_GENERAL, LOG_ERR,
LOC +
123 QString(
"Error deleting '%1' -> '%2'")
124 .arg(filename).arg(linktext) +
ENO);
128 if ((!checkexists || checkFile.exists()) &&
129 !(success2 = checkFile.remove()))
131 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Error deleting '%1': %2")
132 .arg(filename).arg(strerror(errno)));
134 return success1 && success2 ? 0 : -1;
146 m_parent(parent), m_sock(sock)
162 m_parent.ProcessRequest(m_sock);
176 m_parent(parent), m_dorun(
true), m_running(
true)
178 m_lastRequest.start();
182 QMutexLocker locker(&m_parent.masterFreeSpaceListLock);
183 m_parent.masterFreeSpaceListUpdater =
nullptr;
184 m_parent.masterFreeSpaceListWait.wakeAll();
194 m_parent.BackendQueryDiskSpace(list,
true,
true);
196 QMutexLocker locker(&m_parent.masterFreeSpaceListLock);
197 m_parent.masterFreeSpaceList = list;
199 QMutexLocker locker(&m_lock);
200 int left = kRequeryTimeout -
t.elapsed();
201 if (m_lastRequest.elapsed() + left > kExitTimeout)
209 m_wait.wait(locker.mutex(), left);
215 QMutexLocker locker(&m_lock);
216 if (dorun && m_running)
219 m_lastRequest.restart();
242 QMap<int, EncoderLink *> *_tvList,
244 encoderList(_tvList), mythserver(nullptr),
245 metadatafactory(nullptr),
246 masterFreeSpaceListUpdater(nullptr),
247 masterServerReconnect(nullptr),
248 masterServer(nullptr), ismaster(master), threadPool(
"ProcessRequestPool"),
249 masterBackendOverride(
false),
250 m_sched(
sched), m_expirer(_expirer), m_addChildInputLock(),
251 deferredDeleteTimer(nullptr),
276 bool v4IsSet = config_v4.isNull() ?
false :
true;
281 bool v6IsSet = config_v6.isNull() ?
false :
true;
283 if (v6IsSet && !listenAddrs.contains(config_v6))
284 LOG(VB_GENERAL, LOG_WARNING,
LOC +
285 "Unable to find IPv6 address to bind");
287 if (v4IsSet && !listenAddrs.contains(config_v4))
288 LOG(VB_GENERAL, LOG_WARNING,
LOC +
289 "Unable to find IPv4 address to bind");
291 if ((v4IsSet && !listenAddrs.contains(config_v4))
292 && (v6IsSet && !listenAddrs.contains(config_v6))
295 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unable to find either IPv4 or IPv6 " 296 "address we can bind to, exiting");
329 QList<FileSystemInfo> fsInfos;
419 vector<PlaybackSock *>::iterator it =
playbackList.begin();
462 QCoreApplication::processEvents();
470 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"No data on sock %1")
484 QStringList listline;
487 if (!
pbs->ReadStringList(listline) || listline.empty())
490 LOG(VB_GENERAL, LOG_INFO,
"No data in ProcessRequestWork()");
495 else if (!bIsControl)
502 LOG(VB_GENERAL, LOG_INFO,
LOC +
"No data in ProcessRequestWork()");
506 QString line = listline[0];
508 line = line.simplified();
509 QStringList tokens = line.split(
' ', QString::SkipEmptyParts);
510 QString command = tokens[0];
512 if (command ==
"MYTH_PROTO_VERSION")
514 if (tokens.size() < 2)
520 else if (command ==
"ANN")
525 else if (command ==
"DONE")
536 LOG(VB_GENERAL, LOG_ERR,
LOC +
"ProcessRequest unknown socket");
542 if (command ==
"QUERY_FILETRANSFER")
544 if (tokens.size() != 2)
549 else if (command ==
"QUERY_RECORDINGS")
551 if (tokens.size() != 2)
556 else if (command ==
"QUERY_RECORDING")
560 else if (command ==
"GO_TO_SLEEP")
564 else if (command ==
"QUERY_FREE_SPACE")
568 else if (command ==
"QUERY_FREE_SPACE_LIST")
572 else if (command ==
"QUERY_FREE_SPACE_SUMMARY")
576 else if (command ==
"QUERY_LOAD")
580 else if (command ==
"QUERY_UPTIME")
584 else if (command ==
"QUERY_HOSTNAME")
588 else if (command ==
"QUERY_MEMSTATS")
592 else if (command ==
"QUERY_TIME_ZONE")
596 else if (command ==
"QUERY_CHECKFILE")
600 else if (command ==
"QUERY_FILE_EXISTS")
602 if (listline.size() < 2)
607 else if (command ==
"QUERY_FINDFILE")
609 if (listline.size() < 4)
614 else if (command ==
"QUERY_FILE_HASH")
616 if (listline.size() < 3)
621 else if (command ==
"QUERY_GUIDEDATATHROUGH")
625 else if (command ==
"DELETE_FILE")
627 if (listline.size() < 3)
632 else if (command ==
"MOVE_FILE")
634 if (listline.size() < 4)
639 else if (command ==
"STOP_RECORDING")
643 else if (command ==
"CHECK_RECORDING")
647 else if (command ==
"DELETE_RECORDING")
649 if (3 <= tokens.size() && tokens.size() <= 5)
651 bool force = (tokens.size() >= 4) && (tokens[3] ==
"FORCE");
652 bool forget = (tokens.size() >= 5) && (tokens[4] ==
"FORGET");
658 else if (command ==
"FORCE_DELETE_RECORDING")
662 else if (command ==
"UNDELETE_RECORDING")
666 else if (command ==
"ADD_CHILD_INPUT")
671 LOG(VB_GENERAL, LOG_ERR,
LOC +
672 "ADD_CHILD_INPUT command received in master context");
673 reslist << QString(
"ERROR: Called in master context");
675 else if (tokens.size() != 2)
676 reslist <<
"ERROR: Bad ADD_CHILD_INPUT request";
680 reslist << QString(
"ERROR: Failed to add child input");
683 else if (command ==
"RESCHEDULE_RECORDINGS")
685 listline.pop_front();
688 else if (command ==
"FORGET_RECORDING")
692 else if (command ==
"QUERY_GETALLPENDING")
694 if (tokens.size() == 1)
696 else if (tokens.size() == 2)
701 else if (command ==
"QUERY_GETALLSCHEDULED")
705 else if (command ==
"QUERY_GETCONFLICTING")
709 else if (command ==
"QUERY_GETEXPIRING")
713 else if (command ==
"QUERY_SG_GETFILELIST")
717 else if (command ==
"QUERY_SG_FILEQUERY")
721 else if (command ==
"GET_FREE_INPUT_INFO")
723 if (tokens.size() != 2)
728 else if (command ==
"QUERY_RECORDER")
730 if (tokens.size() != 2)
735 else if (command ==
"QUERY_RECORDING_DEVICE")
739 else if (command ==
"QUERY_RECORDING_DEVICES")
743 else if (command ==
"SET_NEXT_LIVETV_DIR")
745 if (tokens.size() != 3)
750 else if (command ==
"SET_CHANNEL_INFO")
754 else if (command ==
"QUERY_REMOTEENCODER")
756 if (tokens.size() != 2)
761 else if (command ==
"GET_RECORDER_FROM_NUM")
765 else if (command ==
"GET_RECORDER_NUM")
769 else if (command ==
"QUERY_GENPIXMAP2")
773 else if (command ==
"QUERY_PIXMAP_LASTMODIFIED")
777 else if (command ==
"QUERY_PIXMAP_GET_IF_MODIFIED")
781 else if (command ==
"QUERY_ISRECORDING")
785 else if (command ==
"MESSAGE")
787 if ((listline.size() >= 2) && (listline[1].startsWith(
"SET_VERBOSE")))
789 else if ((listline.size() >= 2) &&
790 (listline[1].startsWith(
"SET_LOG_LEVEL")))
795 else if (command ==
"FILL_PROGRAM_INFO")
799 else if (command ==
"LOCK_TUNER")
801 if (tokens.size() == 1)
803 else if (tokens.size() == 2)
808 else if (command ==
"FREE_TUNER")
810 if (tokens.size() != 2)
815 else if (command ==
"QUERY_ACTIVE_BACKENDS")
819 else if (command ==
"QUERY_IS_ACTIVE_BACKEND")
821 if (tokens.size() != 1)
826 else if (command ==
"QUERY_COMMBREAK")
828 if (tokens.size() != 3)
833 else if (command ==
"QUERY_CUTLIST")
835 if (tokens.size() != 3)
840 else if (command ==
"QUERY_BOOKMARK")
842 if (tokens.size() != 3)
847 else if (command ==
"SET_BOOKMARK")
849 if (tokens.size() != 4)
854 else if (command ==
"QUERY_SETTING")
856 if (tokens.size() != 3)
861 else if (command ==
"SET_SETTING")
863 if (tokens.size() != 4)
868 else if (command ==
"SCAN_VIDEOS")
872 else if (command ==
"SCAN_MUSIC")
876 else if (command ==
"MUSIC_TAG_UPDATE_VOLATILE")
878 if (listline.size() != 6)
883 else if (command ==
"MUSIC_CALC_TRACK_LENGTH")
885 if (listline.size() != 3)
890 else if (command ==
"MUSIC_TAG_UPDATE_METADATA")
892 if (listline.size() != 3)
897 else if (command ==
"MUSIC_FIND_ALBUMART")
899 if (listline.size() != 4)
904 else if (command ==
"MUSIC_TAG_GETIMAGE")
906 if (listline.size() < 4)
911 else if (command ==
"MUSIC_TAG_ADDIMAGE")
913 if (listline.size() < 5)
918 else if (command ==
"MUSIC_TAG_REMOVEIMAGE")
920 if (listline.size() < 4)
925 else if (command ==
"MUSIC_TAG_CHANGEIMAGE")
927 if (listline.size() < 5)
932 else if (command ==
"MUSIC_LYRICS_FIND")
934 if (listline.size() < 3)
939 else if (command ==
"MUSIC_LYRICS_GETGRABBERS")
943 else if (command ==
"MUSIC_LYRICS_SAVE")
945 if (listline.size() < 3)
950 else if (command ==
"IMAGE_SCAN")
953 QStringList reply = (listline.size() == 2)
955 : QStringList(
"ERROR") <<
"Bad: " << listline;
959 else if (command ==
"IMAGE_COPY")
962 QStringList reply = (listline.size() >= 2)
964 : QStringList(
"ERROR") <<
"Bad: " << listline;
968 else if (command ==
"IMAGE_MOVE")
971 QStringList reply = (listline.size() == 4)
973 HandleDbMove(listline[1], listline[2], listline[3])
974 : QStringList(
"ERROR") <<
"Bad: " << listline;
978 else if (command ==
"IMAGE_DELETE")
981 QStringList reply = (listline.size() == 2)
983 : QStringList(
"ERROR") <<
"Bad: " << listline;
987 else if (command ==
"IMAGE_HIDE")
990 QStringList reply = (listline.size() == 3)
992 HandleHide(listline[1].toInt(), listline[2])
993 : QStringList(
"ERROR") <<
"Bad: " << listline;
997 else if (command ==
"IMAGE_TRANSFORM")
1000 QStringList reply = (listline.size() == 3)
1002 HandleTransform(listline[1].toInt(), listline[2])
1003 : QStringList(
"ERROR") <<
"Bad: " << listline;
1007 else if (command ==
"IMAGE_RENAME")
1010 QStringList reply = (listline.size() == 3)
1012 : QStringList(
"ERROR") <<
"Bad: " << listline;
1016 else if (command ==
"IMAGE_CREATE_DIRS")
1019 QStringList reply = (listline.size() >= 4)
1021 HandleDirs(listline[1], listline[2].toInt(), listline.mid(3))
1022 : QStringList(
"ERROR") <<
"Bad: " << listline;
1026 else if (command ==
"IMAGE_COVER")
1029 QStringList reply = (listline.size() == 3)
1031 HandleCover(listline[1].toInt(), listline[2].toInt())
1032 : QStringList(
"ERROR") <<
"Bad: " << listline;
1036 else if (command ==
"IMAGE_IGNORE")
1039 QStringList reply = (listline.size() == 2)
1041 : QStringList(
"ERROR") <<
"Bad: " << listline;
1045 else if (command ==
"ALLOW_SHUTDOWN")
1047 if (tokens.size() != 1)
1052 else if (command ==
"BLOCK_SHUTDOWN")
1054 if (tokens.size() != 1)
1059 else if (command ==
"SHUTDOWN_NOW")
1061 if (tokens.size() != 1)
1066 if (listline.size() >= 2)
1067 halt_cmd = listline[1];
1069 if (!halt_cmd.isEmpty())
1071 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
1072 "Going down now as of Mainserver request!");
1079 else if (command ==
"BACKEND_MESSAGE")
1081 QString message = listline[1];
1082 QStringList extra( listline[2] );
1083 for (
int i = 3; i < listline.size(); i++)
1084 extra << listline[i];
1088 else if ((command ==
"DOWNLOAD_FILE") ||
1089 (command ==
"DOWNLOAD_FILE_NOW"))
1091 if (listline.size() != 4)
1096 else if (command ==
"REFRESH_BACKEND")
1098 LOG(VB_GENERAL, LOG_INFO ,
LOC +
"Reloading backend settings");
1101 else if (command ==
"OK")
1103 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Got 'OK' out of sequence.");
1105 else if (command ==
"UNKNOWN_COMMAND")
1107 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Got 'UNKNOWN_COMMAND' out of sequence.");
1111 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unknown command: " + command);
1115 QStringList strlist;
1116 strlist <<
"UNKNOWN_COMMAND";
1129 QStringList broadcast;
1130 QSet<QString> receivers;
1148 MythEvent *me = static_cast<MythEvent *>(e);
1150 QString message = me->
Message();
1152 if ((message ==
"PREVIEW_SUCCESS" || message ==
"PREVIEW_QUEUED") &&
1161 if (message ==
"PREVIEW_QUEUED")
1163 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
1164 QString(
"Preview Queued: '%1' '%2'")
1165 .arg(recordingID).arg(filename));
1169 QFile file(filename);
1170 ok = ok && file.open(QIODevice::ReadOnly);
1174 QByteArray data = file.readAll();
1175 QStringList extra(
"OK");
1176 extra.push_back(QString::number(recordingID));
1177 extra.push_back(msg);
1178 extra.push_back(datetime);
1179 extra.push_back(QString::number(data.size()));
1181 QString::number(qChecksum(data.constData(), data.size())));
1182 extra.push_back(QString(data.toBase64()));
1187 extra.push_back(token);
1191 receivers.insert(*it);
1196 if (receivers.empty())
1198 LOG(VB_GENERAL, LOG_ERR,
LOC +
1199 "PREVIEW_SUCCESS but no receivers.");
1203 broadcast.push_back(
"BACKEND_MESSAGE");
1204 broadcast.push_back(
"GENERATED_PIXMAP");
1209 message =
"PREVIEW_FAILED";
1210 error = QString(
"Failed to read '%1'").arg(filename);
1220 QStringList extra(
"ERROR");
1221 extra.push_back(pginfokey);
1222 extra.push_back(msg);
1226 extra.push_back(token);
1230 receivers.insert(*it);
1235 if (receivers.empty())
1237 LOG(VB_GENERAL, LOG_ERR,
LOC +
1238 "PREVIEW_FAILED but no receivers.");
1242 broadcast.push_back(
"BACKEND_MESSAGE");
1243 broadcast.push_back(
"GENERATED_PIXMAP");
1247 if (me->
Message().startsWith(
"AUTO_EXPIRE"))
1249 QStringList tokens = me->
Message()
1250 .split(
" ", QString::SkipEmptyParts);
1252 if (tokens.size() != 3)
1254 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad AUTO_EXPIRE message");
1278 QString msg = QString(
"Cannot find program info for '%1', " 1279 "while attempting to Auto-Expire.")
1281 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
1287 if (me->
Message().startsWith(
"QUERY_NEXT_LIVETV_DIR") &&
m_sched)
1289 QStringList tokens = me->
Message()
1290 .split(
" ", QString::SkipEmptyParts);
1292 if (tokens.size() != 2)
1294 LOG(VB_GENERAL, LOG_ERR,
LOC +
1295 QString(
"Bad %1 message").arg(tokens[0]));
1303 if (me->
Message().startsWith(
"STOP_RECORDING"))
1305 QStringList tokens = me->
Message().split(
" ",
1306 QString::SkipEmptyParts);
1309 if (tokens.size() < 3 || tokens.size() > 3)
1311 LOG(VB_GENERAL, LOG_ERR,
LOC +
1312 QString(
"Bad STOP_RECORDING message: %1")
1326 LOG(VB_GENERAL, LOG_ERR,
LOC +
1327 QString(
"Cannot find program info for '%1' while " 1328 "attempting to stop recording.").arg(me->
Message()));
1334 if ((me->
Message().startsWith(
"DELETE_RECORDING")) ||
1335 (me->
Message().startsWith(
"FORCE_DELETE_RECORDING")))
1337 QStringList tokens = me->
Message()
1338 .split(
" ", QString::SkipEmptyParts);
1341 if (tokens.size() < 3 || tokens.size() > 5)
1343 LOG(VB_GENERAL, LOG_ERR,
LOC +
1344 QString(
"Bad %1 message").arg(tokens[0]));
1348 bool force = (tokens.size() >= 4) && (tokens[3] ==
"FORCE");
1349 bool forget = (tokens.size() >= 5) && (tokens[4] ==
"FORGET");
1356 if (tokens[0] ==
"FORCE_DELETE_RECORDING")
1363 LOG(VB_GENERAL, LOG_ERR,
LOC +
1364 QString(
"Cannot find program info for '%1' while " 1365 "attempting to delete.").arg(me->
Message()));
1371 if (me->
Message().startsWith(
"UNDELETE_RECORDING"))
1373 QStringList tokens = me->
Message().split(
" ",
1374 QString::SkipEmptyParts);
1377 if (tokens.size() < 3 || tokens.size() > 3)
1379 LOG(VB_GENERAL, LOG_ERR,
LOC +
1380 QString(
"Bad UNDELETE_RECORDING message: %1")
1394 LOG(VB_GENERAL, LOG_ERR,
LOC +
1395 QString(
"Cannot find program info for '%1' while " 1396 "attempting to undelete.").arg(me->
Message()));
1402 if (me->
Message().startsWith(
"ADD_CHILD_INPUT"))
1404 QStringList tokens = me->
Message()
1405 .split(
" ", QString::SkipEmptyParts);
1407 LOG(VB_GENERAL, LOG_ERR,
LOC +
1408 "ADD_CHILD_INPUT event received in slave context");
1409 else if (tokens.size() != 2)
1410 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad ADD_CHILD_INPUT message");
1416 if (me->
Message().startsWith(
"RESCHEDULE_RECORDINGS") &&
m_sched)
1423 if (me->
Message().startsWith(
"SCHEDULER_ADD_RECORDING") &&
m_sched)
1426 if (!pi.GetChanID())
1428 LOG(VB_GENERAL, LOG_ERR,
LOC +
1429 "Bad SCHEDULER_ADD_RECORDING message");
1437 if (me->
Message().startsWith(
"UPDATE_RECORDING_STATUS") &&
m_sched)
1439 QStringList tokens = me->
Message()
1440 .split(
" ", QString::SkipEmptyParts);
1442 if (tokens.size() != 6)
1444 LOG(VB_GENERAL, LOG_ERR,
LOC +
1445 "Bad UPDATE_RECORDING_STATUS message");
1449 uint cardid = tokens[1].toUInt();
1450 uint chanid = tokens[2].toUInt();
1455 recstatus, recendts);
1461 if (me->
Message().startsWith(
"LIVETV_EXITED"))
1471 if (me->
Message() ==
"CLEAR_SETTINGS_CACHE")
1477 if (me->
Message() ==
"LOCAL_RECONNECT_TO_MASTER")
1480 if (me->
Message() ==
"LOCAL_SLAVE_BACKEND_ENCODERS_OFFLINE")
1483 if (me->
Message().startsWith(
"LOCAL_"))
1486 if (me->
Message() ==
"CREATE_THUMBNAILS")
1489 if (me->
Message() ==
"IMAGE_GET_METADATA")
1493 if (me->
Message().startsWith(
"MASTER_UPDATE_REC_INFO"))
1495 QStringList tokens = me->
Message().simplified().split(
" ");
1496 uint recordedid = 0;
1497 if (tokens.size() >= 2)
1498 recordedid = tokens[1].toUInt();
1511 mod_me =
MythEvent(
"RECORDING_LIST_CHANGE UPDATE", list);
1520 if (me->
Message().startsWith(
"DOWNLOAD_FILE"))
1523 QString localFile = extraDataList[1];
1524 QFile file(localFile);
1525 QStringList tokens = me->
Message().simplified().split(
" ");
1533 if ((tokens.size() >= 2) && (tokens[1] ==
"FINISHED"))
1540 if (broadcast.empty())
1542 broadcast.push_back(
"BACKEND_MESSAGE");
1543 broadcast.push_back(me->
Message());
1548 if (!broadcast.empty())
1551 vector<PlaybackSock *> localPBSList;
1553 vector<PlaybackSock *>::iterator it =
playbackList.begin();
1557 localPBSList.push_back(*it);
1561 bool sendGlobal =
false;
1562 if (
ismaster && broadcast[1].startsWith(
"GLOBAL_"))
1564 broadcast[1].replace(
"GLOBAL_",
"LOCAL_");
1565 MythEvent me(broadcast[1], broadcast[2]);
1571 QSet<PlaybackSock*> sentSet;
1573 bool isSystemEvent = broadcast[1].startsWith(
"SYSTEM_EVENT ");
1576 vector<PlaybackSock*>::const_iterator iter;
1577 for (iter = localPBSList.begin(); iter != localPBSList.end(); ++iter)
1581 if (sentSet.contains(
pbs) ||
pbs->IsDisconnected())
1584 if (!receivers.empty() && !receivers.contains(
pbs->getHostname()))
1587 sentSet.insert(
pbs);
1589 bool reallysendit =
false;
1591 if (broadcast[1] ==
"CLEAR_SETTINGS_CACHE")
1594 (
pbs->isSlaveBackend() ||
pbs->wantsEvents()))
1595 reallysendit =
true;
1597 else if (sendGlobal)
1599 if (
pbs->isSlaveBackend())
1600 reallysendit =
true;
1602 else if (
pbs->wantsEvents())
1604 reallysendit =
true;
1611 if (!
pbs->wantsSystemEvents())
1615 else if (!
pbs->wantsOnlySystemEvents())
1617 if (sentSetSystemEvent.contains(
pbs->getHostname()))
1620 sentSetSystemEvent <<
pbs->getHostname();
1623 else if (
pbs->wantsOnlySystemEvents())
1633 for (iter = localPBSList.begin(); iter != localPBSList.end(); ++iter)
1651 QStringList retlist;
1655 LOG(VB_GENERAL, LOG_CRIT,
LOC +
1656 "MainServer::HandleVersion - Client speaks protocol version " +
1664 if (slist.size() < 3)
1666 LOG(VB_GENERAL, LOG_CRIT,
LOC +
1667 "MainServer::HandleVersion - Client did not pass protocol " 1668 "token. Refusing connection!");
1675 QString token = slist[2];
1678 LOG(VB_GENERAL, LOG_CRIT,
LOC +
1679 QString(
"MainServer::HandleVersion - Client sent incorrect " 1680 "protocol token \"%1\" for protocol version. Refusing " 1681 "connection!").arg(token));
1717 QStringList retlist(
"OK" );
1718 QStringList errlist(
"ERROR" );
1720 if (commands.size() < 3 || commands.size() > 6)
1723 if (commands.size() == 2)
1724 info = QString(
" %1").arg(commands[1]);
1726 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Received malformed ANN%1 query")
1729 errlist <<
"malformed_ann_query";
1738 if (
pbs->getSocket() == socket)
1740 LOG(VB_GENERAL, LOG_WARNING,
LOC +
1741 QString(
"Client %1 is trying to announce a socket " 1751 if (commands[1] ==
"Playback" || commands[1] ==
"Monitor" ||
1752 commands[1] ==
"Frontend")
1754 if (commands.size() < 4)
1756 LOG(VB_GENERAL, LOG_ERR,
LOC +
1757 QString(
"Received malformed ANN %1 query")
1760 errlist <<
"malformed_ann_query";
1779 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"MainServer::ANN %1")
1781 LOG(VB_GENERAL, LOG_INFO,
LOC +
1782 QString(
"adding: %1(%2) as a client (events: %3)")
1784 .arg(quintptr(socket),0,16)
1786 pbs->setBlockShutdown((commands[1] ==
"Playback") ||
1787 (commands[1] ==
"Frontend"));
1789 if (commands[1] ==
"Frontend")
1791 pbs->SetAsFrontend();
1793 frontend->
name = commands[2];
1808 else if (commands[1] ==
"MediaServer")
1810 if (commands.size() < 3)
1812 LOG(VB_GENERAL, LOG_ERR,
LOC +
1813 "Received malformed ANN MediaServer query");
1814 errlist <<
"malformed_ann_query";
1824 pbs->setAsMediaServer();
1825 pbs->setBlockShutdown(
false);
1830 QString(
"CLIENT_CONNECTED HOSTNAME %1").arg(commands[2]));
1832 else if (commands[1] ==
"SlaveBackend")
1834 if (commands.size() < 4)
1836 LOG(VB_GENERAL, LOG_ERR,
LOC +
1837 QString(
"Received malformed ANN %1 query")
1839 errlist <<
"malformed_ann_query";
1852 LOG(VB_GENERAL, LOG_INFO,
LOC +
1853 QString(
"adding: %1 as a slave backend server")
1855 pbs->setAsSlaveBackend();
1856 pbs->setIP(commands[3]);
1861 QStringList::const_iterator sit = slist.
begin()+1;
1862 while (sit != slist.end())
1875 bool wasAsleep =
true;
1892 QString message = QString(
"LOCAL_SLAVE_BACKEND_ONLINE %2")
1897 pbs->setBlockShutdown(
false);
1902 QString(
"SLAVE_CONNECTED HOSTNAME %1").arg(commands[2]));
1904 else if (commands[1] ==
"FileTransfer")
1906 if (slist.size() < 3)
1908 LOG(VB_GENERAL, LOG_ERR,
LOC +
1909 "Received malformed FileTransfer command");
1910 errlist <<
"malformed_filetransfer_command";
1915 LOG(VB_NETWORK, LOG_INFO,
LOC +
1916 "MainServer::HandleAnnounce FileTransfer");
1917 LOG(VB_NETWORK, LOG_INFO,
LOC +
1918 QString(
"adding: %1 as a remote file transfer") .arg(commands[2]));
1919 QStringList::const_iterator it = slist.begin();
1920 QString path = *(++it);
1921 QString wantgroup = *(++it);
1923 QStringList checkfiles;
1925 for (++it; it != slist.end(); ++it)
1929 bool writemode =
false;
1930 bool usereadahead =
true;
1931 int timeout_ms = 2000;
1932 if (commands.size() > 3)
1933 writemode = commands[3].toInt();
1935 if (commands.size() > 4)
1936 usereadahead = commands[4].toInt();
1938 if (commands.size() > 5)
1939 timeout_ms = commands[5].toInt();
1943 if (wantgroup.isEmpty())
1944 wantgroup =
"Default";
1950 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unable to determine directory " 1951 "to write to in FileTransfer write command");
1952 errlist <<
"filetransfer_directory_not_found";
1959 LOG(VB_GENERAL, LOG_ERR,
LOC +
1960 QString(
"FileTransfer write filename is empty in path '%1'.")
1962 errlist <<
"filetransfer_filename_empty";
1967 if ((path.contains(
"/../")) ||
1968 (path.startsWith(
"../")))
1970 LOG(VB_GENERAL, LOG_ERR,
LOC +
1971 QString(
"FileTransfer write filename '%1' does not pass " 1972 "sanity checks.") .arg(path));
1973 errlist <<
"filetransfer_filename_dangerous";
1978 filename = dir +
"/" + path;
1983 if (filename.isEmpty())
1985 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Empty filename, cowardly aborting!");
1986 errlist <<
"filetransfer_filename_empty";
1992 QFileInfo finfo(filename);
1995 LOG(VB_GENERAL, LOG_ERR,
LOC +
1996 QString(
"FileTransfer filename '%1' is actually a directory, " 1997 "cannot transfer.") .arg(filename));
1998 errlist <<
"filetransfer_filename_is_a_directory";
2005 QString dirPath = finfo.absolutePath();
2009 if (!qdir.mkpath(dirPath))
2011 LOG(VB_GENERAL, LOG_ERR,
LOC +
2012 QString(
"FileTransfer filename '%1' is in a " 2013 "subdirectory which does not exist, and can " 2014 "not be created.") .arg(filename));
2015 errlist <<
"filetransfer_unable_to_create_subdirectory";
2030 ft =
new FileTransfer(filename, socket, usereadahead, timeout_ms);
2035 LOG(VB_GENERAL, LOG_ERR,
LOC +
2036 QString(
"Can't open %1").arg(filename));
2037 errlist <<
"filetransfer_unable_to_open_file";
2044 LOG(VB_GENERAL, LOG_INFO,
LOC +
2045 QString(
"adding: %1(%2) as a file transfer")
2047 .arg(quintptr(socket),0,16));
2055 if (checkfiles.size())
2057 QFileInfo fi(filename);
2058 QDir dir = fi.absoluteDir();
2059 for (it = checkfiles.begin(); it != checkfiles.end(); ++it)
2061 if (dir.exists(*it) &&
2062 ((*it).endsWith(
".srt") ||
2095 QStringList strList(
"ERROR");
2110 bool do_write =
false;
2125 LOG(VB_GENERAL, LOG_ERR,
LOC +
2126 "SendResponse: Unable to write to client socket, as it's no " 2142 QString playbackhost =
pbs->getHostname();
2144 QMap<QString,ProgramInfo*> recMap;
2149 QMap<QString,bool> isJobRunning =
2155 if ((
type ==
"Ascending") || (
type ==
"Play"))
2157 else if ((
type ==
"Descending") || (
type ==
"Delete"))
2162 destination, (
type ==
"Recording"),
2163 inUseMap, isJobRunning, recMap, sort);
2165 QMap<QString,ProgramInfo*>::iterator mit = recMap.begin();
2166 for (; mit != recMap.end(); mit = recMap.erase(mit))
2169 QStringList outputlist(QString::number(destination.
size()));
2170 QMap<QString, QString> backendPortMap;
2176 for (it = destination.
begin(); it != destination.
end(); ++it)
2191 if (tmpURL.startsWith(
'/'))
2193 QFile checkFile(tmpURL);
2194 if (!tmpURL.isEmpty() && checkFile.exists())
2211 LOG(VB_GENERAL, LOG_ERR,
LOC +
2212 QString(
"HandleQueryRecordings() " 2213 "Couldn't find backend for:\n\t\t\t%1")
2226 LOG(VB_GENERAL, LOG_ERR,
LOC +
2227 "MainServer::HandleQueryRecordings()" 2228 "\n\t\t\tCould not fill program info " 2245 if (!backendPortMap.contains(
hostname))
2270 if (slist.size() < 3)
2272 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad QUERY_RECORDING query");
2277 QString command = slist[1].toUpper();
2280 if (command ==
"BASENAME")
2284 else if (command ==
"TIMESLOT")
2286 if (slist.size() < 4)
2288 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Bad QUERY_RECORDING query");
2293 pginfo =
new ProgramInfo(slist[2].toUInt(), recstartts);
2296 QStringList strlist;
2317 QString playbackhost = slist[1];
2319 QStringList::const_iterator it = slist.begin() + 2;
2322 if (pginfo.HasPathname())
2329 pginfo.SetPathname(lpath);
2333 const QFileInfo info(lpath);
2334 pginfo.SetFilesize(info.size());
2337 QStringList strlist;
2339 pginfo.ToStringList(strlist);
2355 std::this_thread::sleep_for(std::chrono::seconds(3));
2356 std::this_thread::sleep_for(std::chrono::milliseconds(
random()%2));
2360 QString logInfo = QString(
"recording id %1 (chanid %2 at %3)")
2365 QString
name = QString(
"deleteThread%1%2").arg(getpid()).arg(
random());
2370 QString msg = QString(
"ERROR opening database connection for Delete " 2371 "Thread for chanid %1 recorded at %2. Program " 2372 "will NOT be deleted.")
2375 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2385 QString msg = QString(
"ERROR retrieving program info when trying to " 2386 "delete program for chanid %1 recorded at %2. " 2387 "Recording will NOT be deleted.")
2390 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
2400 if ((!checkFile.exists()) && pginfo.
GetFilesize() &&
2403 LOG(VB_GENERAL, LOG_ERR,
LOC +
2404 QString(
"ERROR when trying to delete file: %1. File " 2405 "doesn't exist. Database metadata will not be removed.")
2423 bool errmsg =
false;
2438 if ((fd < 0) && checkFile.exists())
2443 delete_file_immediately(ds->
m_filename, followLinks,
false);
2444 std::this_thread::sleep_for(std::chrono::seconds(2));
2445 if (checkFile.exists())
2451 LOG(VB_GENERAL, LOG_ERR,
LOC +
2452 QString(
"Error deleting file: %1. Keeping metadata in database.")
2467 QStringList nameFilters;
2468 nameFilters.push_back(fInfo.fileName() +
"*.png");
2469 nameFilters.push_back(fInfo.fileName() +
"*.jpg");
2470 nameFilters.push_back(fInfo.fileName() +
".tmp");
2471 nameFilters.push_back(fInfo.fileName() +
".old");
2472 nameFilters.push_back(fInfo.fileName() +
".map");
2473 nameFilters.push_back(fInfo.fileName() +
".tmp.map");
2474 nameFilters.push_back(fInfo.baseName() +
".srt");
2476 QDir dir (fInfo.path());
2477 QFileInfoList miscFiles = dir.entryInfoList(nameFilters);
2479 for (
int nIdx = 0; nIdx < miscFiles.size(); nIdx++)
2481 QString sFileName = miscFiles.at(nIdx).absoluteFilePath();
2482 delete_file_immediately( sFileName, followLinks,
true);
2493 if (slowDeletes && fd >= 0)
2499 QString logInfo = QString(
"recording id %1 filename %2")
2502 LOG(VB_GENERAL, LOG_NOTICE,
"DeleteRecordedFiles - " + logInfo);
2506 query.
prepare(
"SELECT basename, hostname, storagegroup FROM recordedfile " 2507 "WHERE recordedid = :RECORDEDID;");
2510 if (!query.
exec() || !query.
size())
2513 LOG(VB_GENERAL, LOG_ERR,
LOC +
2514 QString(
"Error querying recordedfiles for %1.") .arg(logInfo));
2519 QString storagegroup;
2520 while (query.
next())
2522 basename = query.
value(0).toString();
2524 storagegroup = query.
value(2).toString();
2525 bool deleteInDB =
false;
2527 if (basename == QFileInfo(ds->
m_filename).fileName())
2556 update.
prepare(
"DELETE FROM recordedfile " 2557 "WHERE recordedid = :RECORDEDID " 2558 "AND basename = :BASENAME ;");
2560 update.
bindValue(
":BASENAME", basename);
2564 LOG(VB_GENERAL, LOG_ERR,
LOC +
2565 QString(
"Error querying recordedfile (%1) for %2.")
2566 .arg(query.
value(1).toString())
2575 QString logInfo = QString(
"recording id %1 (chanid %2 at %3)")
2579 LOG(VB_GENERAL, LOG_NOTICE,
"DoDeleteINDB - " + logInfo);
2582 query.
prepare(
"DELETE FROM recorded WHERE recordedid = :RECORDEDID AND " 2587 if (!query.
exec() || !query.
size())
2590 LOG(VB_GENERAL, LOG_ERR,
LOC +
2591 QString(
"Error deleting recorded entry for %1.") .arg(logInfo));
2594 std::this_thread::sleep_for(std::chrono::seconds(1));
2597 QString msg = QString(
"RECORDING_LIST_CHANGE DELETE %1")
2602 std::this_thread::sleep_for(std::chrono::seconds(3));
2604 query.
prepare(
"DELETE FROM recordedmarkup " 2605 "WHERE chanid = :CHANID AND starttime = :STARTTIME;");
2612 LOG(VB_GENERAL, LOG_ERR,
LOC +
2613 QString(
"Error deleting recordedmarkup for %1.") .arg(logInfo));
2616 query.
prepare(
"DELETE FROM recordedseek " 2617 "WHERE chanid = :CHANID AND starttime = :STARTTIME;");
2624 LOG(VB_GENERAL, LOG_ERR,
LOC +
2625 QString(
"Error deleting recordedseek for %1.")
2640 bool deleteBrokenSymlinks)
2642 QFileInfo finfo(filename);
2643 int fd = -1, err = 0;
2644 QString linktext =
"";
2645 QByteArray fname = filename.toLocal8Bit();
2647 LOG(VB_FILE, LOG_INFO,
LOC +
2648 QString(
"About to unlink/delete file: '%1'")
2649 .arg(fname.constData()));
2651 QString errmsg = QString(
"Delete Error '%1'").arg(fname.constData());
2652 if (finfo.isSymLink())
2655 QByteArray alink = linktext.toLocal8Bit();
2656 errmsg += QString(
" -> '%2'").arg(alink.constData());
2659 if (followLinks && finfo.isSymLink())
2661 if (!finfo.exists() && deleteBrokenSymlinks)
2662 err = unlink(fname.constData());
2667 err = unlink(fname.constData());
2670 else if (!finfo.isSymLink())
2676 err = unlink(fname.constData());
2682 LOG(VB_GENERAL, LOG_ERR,
LOC + errmsg +
ENO);
2698 QByteArray fname = filename.toLocal8Bit();
2699 QString msg = QString(
"Error deleting '%1'").arg(fname.constData());
2700 int fd = open(fname.constData(), O_WRONLY);
2704 LOG(VB_GENERAL, LOG_ERR,
LOC + msg +
" could not open " +
ENO);
2708 if (unlink(fname.constData()))
2710 LOG(VB_GENERAL, LOG_ERR,
LOC + msg +
" could not unlink " +
ENO);
2727 const QString &filename,
off_t fsize)
2740 query.
prepare(
"SELECT COUNT(cardid) FROM capturecard;");
2742 cards = query.
value(0).toInt();
2746 const size_t sleep_time = 500;
2747 const size_t min_tps = 8 * 1024 * 1024;
2748 const size_t calc_tps = (size_t) (cards * 1.2 * (22200000LL / 8));
2749 const size_t tps = max(min_tps, calc_tps);
2750 const size_t increment = (size_t) (tps * (sleep_time * 0.001f));
2752 LOG(VB_FILE, LOG_INFO,
LOC +
2753 QString(
"Truncating '%1' by %2 MB every %3 milliseconds")
2755 .arg(increment / (1024.0 * 1024.0), 0,
'f', 2)
2758 GetMythDB()->GetDBManager()->PurgeIdleConnections(
false);
2764 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"Truncating '%1' to %2 MB")
2765 .arg(filename).arg(fsize / (1024.0 * 1024.0), 0,
'f', 2));
2768 int err = ftruncate(fd, fsize);
2771 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Error truncating '%1'")
2772 .arg(filename) +
ENO);
2775 return 0 ==
close(fd);
2780 if (pginfo && ((count % 100) == 0))
2785 std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time));
2788 bool ok = (0 ==
close(fd));
2793 LOG(VB_FILE, LOG_INFO,
LOC +
2794 QString(
"Finished truncating '%1'").arg(filename));
2804 pbssock =
pbs->getSocket();
2806 QStringList::const_iterator it = slist.begin() + 1;
2823 QMap<int, EncoderLink *>::Iterator iter =
encoderList->begin();
2829 result = iter.key();
2834 QStringList outputlist( QString::number(result) );
2843 QStringList::const_iterator it = slist.begin() + 1;
2845 if (recinfo.GetChanID())
2855 bool hasConflicts =
false;
2857 for(
uint n = 0; n < schedList.
size(); n++)
2863 && recinfo.IsSameProgram(*pInfo))
2876 pbssock =
pbs->getSocket();
2899 (*encoderList)[num]->StopRecording();
2907 QStringList outputlist(
"0" );
2929 QMap<int, EncoderLink *>::Iterator iter =
encoderList->begin();
2936 recnum = iter.key();
2943 std::this_thread::sleep_for(std::chrono::microseconds(100));
2957 QStringList outputlist( QString::number(recnum) );
2964 bool forceMetadataDelete,
2970 if (!recinfo.GetRecordingID())
2972 qDebug() <<
"HandleDeleteRecording(chanid, starttime) Empty Recording ID";
2975 if (!recinfo.GetChanID())
2979 pbssock =
pbs->getSocket();
2981 QStringList outputlist( QString::number(0) );
2991 bool forceMetadataDelete)
2993 QStringList::const_iterator it = slist.begin() + 1;
2996 if (!recinfo.GetRecordingID())
2998 qDebug() <<
"HandleDeleteRecording(QStringList) Empty Recording ID";
3001 if (recinfo.GetChanID())
3007 bool forceMetadataDelete,
bool lexpirer,
bool forgetHistory)
3009 int resultCode = -1;
3012 pbssock =
pbs->getSocket();
3014 bool justexpire = lexpirer ?
false :
3020 if (filename.isEmpty())
3022 LOG(VB_GENERAL, LOG_ERR,
LOC +
3023 QString(
"ERROR when trying to delete file for %1. Unable " 3024 "to determine filename of recording.")
3030 QStringList outputlist(QString::number(resultCode));
3040 if (justexpire && !forceMetadataDelete &&
3049 QStringList outputlist( QString::number(0) );
3073 QStringList outputlist( QString::number(num) );
3082 QFile checkFile(filename);
3083 bool fileExists = checkFile.exists();
3086 QFile checkFileUTF8(QString::fromUtf8(filename.toLatin1().constData()));
3087 fileExists = checkFileUTF8.exists();
3089 filename = QString::fromUtf8(filename.toLatin1().constData());
3096 if (fileExists || !recinfo.
GetFilesize() || forceMetadataDelete)
3102 qDebug() <<
"DoHandleDeleteRecording() Empty Recording ID";
3109 forceMetadataDelete);
3110 deleteThread->
start();
3114 QString logInfo = QString(
"chanid %1")
3117 LOG(VB_GENERAL, LOG_ERR,
LOC +
3118 QString(
"ERROR when trying to delete file: %1. File doesn't " 3119 "exist. Database metadata will not be removed.")
3126 QStringList outputlist( QString::number(resultCode) );
3138 if (fileExists || !recinfo.
GetFilesize() || forceMetadataDelete)
3141 QString(
"REC_DELETED CHANID %1 STARTTIME %2")
3151 if (slist.size() == 3)
3160 QStringList::const_iterator it = slist.begin()+1;
3162 if (recinfo.GetChanID())
3174 pbssock =
pbs->getSocket();
3190 QStringList outputlist( QString::number(ret) );
3227 result = QStringList(QString::number(1));
3230 result = QStringList(QString::number(0));
3248 LOG(VB_GENERAL, LOG_INFO,
LOC +
"HandleAddChildInput: Already locked");
3252 LOG(VB_GENERAL, LOG_INFO,
LOC +
3253 QString(
"HandleAddChildInput: Handling input %1").arg(inputid));
3263 LOG(VB_GENERAL, LOG_ERR,
LOC +
3264 QString(
"HandleAddChildInput: " 3265 "Failed to add child to input %1").arg(inputid));
3271 LOG(VB_GENERAL, LOG_INFO,
LOC +
3272 QString(
"HandleAddChildInput: Added child input %1").arg(childid));
3281 if (!tv || !tv->
Init())
3283 LOG(VB_GENERAL, LOG_ERR,
LOC +
3284 QString(
"HandleAddChildInput: " 3285 "Failed to initialize input %1").arg(childid));
3292 (*encoderList)[childid] = enc;
3299 LOG(VB_GENERAL, LOG_ERR,
LOC +
3300 QString(
"HandleAddChildInput: " 3301 "Failed to add remote input %1").arg(childid));
3309 (*encoderList)[childid] = enc;
3319 if (!tv || !tv->
Init())
3321 LOG(VB_GENERAL, LOG_ERR,
LOC +
3322 QString(
"HandleAddChildInput: " 3323 "Failed to initialize input %1").arg(inputid));
3329 (*encoderList)[inputid] = enc;
3335 LOG(VB_GENERAL, LOG_ERR,
LOC +
3336 QString(
"HandleAddChildInput: " 3337 "Succesffuly handled input %1").arg(inputid));
3344 QStringList::const_iterator it = slist.begin() + 1;
3346 if (recinfo.GetChanID())
3351 pbssock =
pbs->getSocket();
3354 QStringList outputlist( QString::number(0) );
3366 QStringList strlist;
3369 if (!sleepCmd.isEmpty())
3373 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
3374 "Received GO_TO_SLEEP command from master, running SleepCommand.");
3379 strlist <<
"ERROR: SleepCommand is empty";
3380 LOG(VB_GENERAL, LOG_ERR,
LOC +
3381 "ERROR: in HandleGoToSleep(), but no SleepCommand found!");
3397 QStringList strlist;
3429 QStringList strlist;
3448 QStringList shortlist;
3449 if (strlist.size() < 4)
3451 shortlist << QString(
"0");
3452 shortlist << QString(
"0");
3456 unsigned int index = (
uint)(strlist.size()) - 2;
3457 shortlist << strlist[index++];
3458 shortlist << strlist[index++];
3474 QStringList strlist;
3477 strlist <<
"0" <<
"0" <<
"0";
3483 strlist <<
"getloadavg() failed";
3486 strlist << QString::number(loads[0])
3487 << QString::number(loads[1])
3488 << QString::number(loads[2]);
3502 QStringList strlist;
3506 strlist << QString::number(uptime);
3510 strlist <<
"Could not determine uptime.";
3524 QStringList strlist;
3539 QStringList strlist;
3540 int totalMB, freeMB, totalVM, freeVM;
3542 if (
getMemStats(totalMB, freeMB, totalVM, freeVM))
3543 strlist << QString::number(totalMB) << QString::number(freeMB)
3544 << QString::number(totalVM) << QString::number(freeVM);
3548 strlist <<
"Could not determine memory stats.";
3562 QStringList strlist;
3577 bool checkSlaves = slist[1].toInt();
3579 QStringList::const_iterator it = slist.begin() + 2;
3584 if (recinfo.HasPathname() && (
ismaster) &&
3595 QStringList outputlist( QString::number(exists) );
3597 outputlist << recinfo.GetPathname();
3607 if (recinfo.HasPathname())
3610 exists = QFileInfo(pburl).exists();
3615 QStringList strlist( QString::number(exists) );
3627 QString storageGroup =
"Default";
3629 QString filename =
"";
3632 switch (slist.size()) {
3634 if (!slist[3].isEmpty())
3636 [[clang::fallthrough]];
3638 if (slist[2].isEmpty())
3639 storageGroup = slist[2];
3640 [[clang::fallthrough]];
3642 filename = slist[1];
3643 if (filename.isEmpty() ||
3644 filename.contains(
"/../") ||
3645 filename.startsWith(
"../"))
3647 LOG(VB_GENERAL, LOG_ERR,
LOC +
3648 QString(
"ERROR checking for file, filename '%1' " 3649 "fails sanity checks").arg(filename));
3656 LOG(VB_GENERAL, LOG_ERR,
LOC +
3657 "ERROR, invalid input count for QUERY_FILE_HASH");
3668 QString fullname = sgroup.
FindFile(filename);
3676 hash = slave->
GetFileHash(filename, storageGroup);
3694 QString filename = slist[1];
3695 QString storageGroup =
"Default";
3696 QStringList retlist;
3698 if (slist.size() > 2)
3699 storageGroup = slist[2];
3701 if ((filename.isEmpty()) ||
3702 (filename.contains(
"/../")) ||
3703 (filename.startsWith(
"../")))
3705 LOG(VB_GENERAL, LOG_ERR,
LOC +
3706 QString(
"ERROR checking for file, filename '%1' " 3707 "fails sanity checks").arg(filename));
3713 if (storageGroup.isEmpty())
3714 storageGroup =
"Default";
3718 QString fullname = sgroup.
FindFile(filename);
3720 if (!fullname.isEmpty())
3723 retlist << fullname;
3725 struct stat fileinfo;
3726 if (stat(fullname.toLocal8Bit().constData(), &fileinfo) >= 0)
3728 retlist << QString::number(fileinfo.st_dev);
3729 retlist << QString::number(fileinfo.st_ino);
3730 retlist << QString::number(fileinfo.st_mode);
3731 retlist << QString::number(fileinfo.st_nlink);
3732 retlist << QString::number(fileinfo.st_uid);
3733 retlist << QString::number(fileinfo.st_gid);
3734 retlist << QString::number(fileinfo.st_rdev);
3735 retlist << QString::number(fileinfo.st_size);
3740 retlist << QString::number(fileinfo.st_blksize);
3741 retlist << QString::number(fileinfo.st_blocks);
3743 retlist << QString::number(fileinfo.st_atime);
3744 retlist << QString::number(fileinfo.st_mtime);
3745 retlist << QString::number(fileinfo.st_ctime);
3757 query.
prepare(
"SELECT MAX(endtime) FROM program WHERE manualid = 0;");
3767 QDateTime GuideDataThrough;
3769 QStringList strlist;
3773 if (GuideDataThrough.isNull())
3774 strlist << QString(
"0000-00-00 00:00");
3776 strlist << GuideDataThrough.toString(
"yyyy-MM-dd hh:mm");
3782 QString tmptable,
int recordid)
3786 QStringList strList;
3790 if (tmptable.isEmpty())
3803 query.
prepare(
"SELECT NULL FROM record " 3804 "WHERE recordid = :RECID;");
3811 if (record->
Load() &&
3817 query.
prepare(
"DELETE FROM program WHERE manualid = :RECID;");
3827 strList << QString::number(0);
3828 strList << QString::number(0);
3838 QStringList strList;
3843 strList << QString::number(0);
3853 QStringList::const_iterator it = slist.begin() + 1;
3856 QStringList strlist;
3858 if (
m_sched && recinfo.GetChanID())
3861 strlist << QString::number(0);
3870 QStringList strList;
3875 strList << QString::number(0);
3884 QStringList strList;
3886 if ((sList.size() < 4) || (sList.size() > 5))
3888 LOG(VB_GENERAL, LOG_ERR,
LOC +
3889 QString(
"HandleSGGetFileList: Invalid Request. %1")
3890 .arg(sList.join(
"[]:[]")));
3891 strList <<
"EMPTY LIST";
3897 QString wantHost = sList.at(1);
3898 QHostAddress wantHostaddr(wantHost);
3899 QString groupname = sList.at(2);
3900 QString path = sList.at(3);
3901 bool fileNamesOnly =
false;
3903 if (sList.size() >= 5)
3904 fileNamesOnly = sList.at(4).toInt();
3906 bool slaveUnreachable =
false;
3908 LOG(VB_FILE, LOG_INFO,
LOC +
3909 QString(
"HandleSGGetFileList: group = %1 host = %2 " 3910 " path = %3 wanthost = %4")
3911 .arg(groupname).arg(host).arg(path).arg(wantHost));
3915 if ((host.toLower() == wantHost.toLower()) ||
3916 (!addr.isEmpty() && addr == wantHostaddr.toString()))
3919 LOG(VB_FILE, LOG_INFO,
LOC +
"HandleSGGetFileList: Getting local info");
3930 LOG(VB_FILE, LOG_INFO,
LOC +
3931 "HandleSGGetFileList: Getting remote info");
3935 slaveUnreachable =
false;
3939 LOG(VB_FILE, LOG_INFO,
LOC +
3940 QString(
"HandleSGGetFileList: Failed to grab slave socket " 3941 ": %1 :").arg(wantHost));
3942 slaveUnreachable =
true;
3947 if (slaveUnreachable)
3948 strList <<
"SLAVE UNREACHABLE: " << host;
3950 if (strList.isEmpty() || (strList.at(0) ==
"0"))
3951 strList <<
"EMPTY LIST";
3961 QString storageGroup = slist[2];
3962 QString filename = slist[3];
3963 bool allowFallback =
true;
3964 bool useRegex =
false;
3965 QStringList fileList;
3967 if (!QHostAddress(
hostname).isNull())
3968 LOG(VB_GENERAL, LOG_ERR, QString(
"Mainserver: QUERY_FINDFILE called " 3969 "with IP (%1) instead of hostname. " 3970 "This is invalid.").arg(
hostname));
3975 if (storageGroup.isEmpty())
3976 storageGroup =
"Default";
3978 if (filename.isEmpty() || filename.contains(
"/../") ||
3979 filename.startsWith(
"../"))
3981 LOG(VB_GENERAL, LOG_ERR,
LOC +
3982 QString(
"ERROR QueryFindFile, filename '%1' " 3983 "fails sanity checks").arg(filename));
3984 fileList <<
"ERROR: Bad/Missing Filename";
3989 if (slist.size() >= 5)
3990 useRegex = (slist[4].toInt() > 0);
3992 if (slist.size() >= 6)
3993 allowFallback = (slist[5].toInt() > 0);
3995 LOG(VB_FILE, LOG_INFO,
LOC +
3996 QString(
"Looking for file '%1' on host '%2' in group '%3' (useregex: %4, allowfallback: %5")
3997 .arg(filename).arg(
hostname).arg(storageGroup).arg(useRegex).arg(allowFallback));
4009 QFileInfo fi(filename);
4010 QStringList files = sgroup.GetFileList(
'/' + fi.path());
4012 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Looking in dir '%1' for '%2'").arg(fi.path()).arg(fi.fileName()));
4014 for (
int x = 0; x < files.size(); x++)
4016 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Found '%1 - %2'").arg(x).arg(files[x]));
4019 QStringList filteredFiles = files.filter(QRegExp(fi.fileName()));
4020 for (
int x = 0; x < filteredFiles.size(); x++)
4024 fi.path() +
'/' + filteredFiles[x],
4030 if (!sgroup.FindFile(filename).isEmpty())
4034 filename, storageGroup);
4040 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Checking remote host '%1' for file").arg(
hostname));
4048 if (!slaveFiles.isEmpty() && slaveFiles[0] !=
"NOT FOUND" && !slaveFiles[0].startsWith(
"ERROR: "))
4049 fileList += slaveFiles;
4055 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Slave '%1' was unreachable").arg(
hostname));
4056 fileList << QString(
"ERROR: SLAVE UNREACHABLE: %1").arg(
hostname);
4064 if (
ismaster && fileList.isEmpty() && allowFallback)
4069 QString sql =
"SELECT DISTINCT hostname " 4070 "FROM storagegroup " 4071 "WHERE groupname = :GROUP " 4072 "AND hostname != :HOSTNAME";
4074 query.
bindValue(
":GROUP", storageGroup);
4080 fileList <<
"ERROR: failed to get host list";
4095 QFileInfo fi(filename);
4096 QStringList files = sgroup.
GetFileList(
'/' + fi.path());
4098 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Looking in dir '%1' for '%2'").arg(fi.path()).arg(fi.fileName()));
4100 for (
int x = 0; x < files.size(); x++)
4102 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Found '%1 - %2'").arg(x).arg(files[x]));
4105 QStringList filteredFiles = files.filter(QRegExp(fi.fileName()));
4107 for (
int x = 0; x < filteredFiles.size(); x++)
4111 fi.path() +
'/' + filteredFiles[x],
4117 QString fname = sgroup.
FindFile(filename);
4118 if (!fname.isEmpty())
4122 filename, storageGroup);
4133 if (!slaveFiles.isEmpty() && slaveFiles[0] !=
"NOT FOUND" && !slaveFiles[0].startsWith(
"ERROR: "))
4134 fileList += slaveFiles;
4140 if (!fileList.isEmpty())
4145 if (fileList.isEmpty())
4147 fileList <<
"NOT FOUND";
4148 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"File was not found"));
4152 for (
int x = 0; x < fileList.size(); x++)
4154 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"File %1 was found at: '%2'").arg(x).arg(fileList[0]));
4167 QStringList strList;
4169 if (sList.size() < 4)
4171 LOG(VB_GENERAL, LOG_ERR,
LOC +
4172 QString(
"HandleSGFileQuery: Invalid Request. %1")
4173 .arg(sList.join(
"[]:[]")));
4174 strList <<
"EMPTY LIST";
4180 QString wantHost = sList.at(1);
4181 QHostAddress wantHostaddr(wantHost);
4182 QString groupname = sList.at(2);
4183 QString filename = sList.at(3);
4185 bool allowFallback =
true;
4186 if (sList.size() >= 5)
4187 allowFallback = (sList.at(4).toInt() > 0);
4188 LOG(VB_FILE, LOG_ERR, QString(
"HandleSGFileQuery - allowFallback: %1").arg(allowFallback));
4190 bool slaveUnreachable =
false;
4192 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"HandleSGFileQuery: %1")
4197 if ((host.toLower() == wantHost.toLower()) ||
4198 (!addr.isEmpty() && addr == wantHostaddr.toString()))
4200 LOG(VB_FILE, LOG_INFO,
LOC +
"HandleSGFileQuery: Getting local info");
4209 LOG(VB_FILE, LOG_INFO,
LOC +
4210 "HandleSGFileQuery: Getting remote info");
4213 slaveUnreachable =
false;
4217 LOG(VB_FILE, LOG_INFO,
LOC +
4218 QString(
"HandleSGFileQuery: Failed to grab slave socket : %1 :")
4220 slaveUnreachable =
true;
4225 if (slaveUnreachable)
4226 strList <<
"SLAVE UNREACHABLE: " << wantHost;
4228 if (strList.count() == 0 || (strList.at(0) ==
"0"))
4229 strList <<
"EMPTY LIST";
4237 QString pbshost =
pbs->getHostname();
4239 QStringList strlist;
4245 QMap<int, EncoderLink *>::Iterator iter =
encoderList->begin();
4251 if ((cardid != -1) && (cardid != elink->
GetInputID()))
4259 if ((enchost == pbshost) &&
4276 QString msg = QString(
"Cardid %1 LOCKed for external use on %2.")
4277 .arg(retval).arg(pbshost);
4278 LOG(VB_GENERAL, LOG_INFO,
LOC + msg);
4281 query.
prepare(
"SELECT videodevice, audiodevice, " 4284 "WHERE cardid = :CARDID ;");
4290 strlist << QString::number(retval)
4291 << query.
value(0).toString()
4292 << query.
value(1).toString()
4293 << query.
value(2).toString();
4302 LOG(VB_GENERAL, LOG_ERR,
LOC +
4303 "MainServer::LockTuner(): Could not find " 4304 "card info in database");
4309 strlist <<
"-2" <<
"" <<
"" <<
"";
4315 strlist <<
"-1" <<
"" <<
"" <<
"";
4322 QStringList strlist;
4326 QMap<int, EncoderLink *>::Iterator iter =
encoderList->find(cardid);
4329 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MainServer::HandleFreeTuner() " +
4330 QString(
"Unknown encoder: %1").arg(cardid));
4331 strlist <<
"FAILED";
4338 QString msg = QString(
"Cardid %1 FREED from external use on %2.")
4339 .arg(cardid).arg(
pbs->getHostname());
4340 LOG(VB_GENERAL, LOG_INFO,
LOC + msg);
4360 uint excluded_input)
4362 LOG(VB_CHANNEL, LOG_INFO,
4363 LOC + QString(
"Excluding input %1")
4364 .arg(excluded_input));
4367 vector<InputInfo> busyinputs;
4368 vector<InputInfo> freeinputs;
4369 QMap<uint, QSet<uint> > groupids;
4374 QMap<int, EncoderLink *>::Iterator iter =
encoderList->begin();
4383 LOG(VB_CHANNEL, LOG_INFO,
4384 LOC + QString(
"Input %1 is locked or not connected")
4389 vector<uint> infogroups;
4391 for (
uint i = 0; i < infogroups.size(); ++i)
4392 groupids[info.
inputid].insert(infogroups[i]);
4395 if (info.
inputid != excluded_input && elink->
IsBusy(&busyinfo))
4397 LOG(VB_CHANNEL, LOG_DEBUG,
4398 LOC + QString(
"Input %1 is busy on %2/%3")
4402 busyinputs.push_back(info);
4406 LOG(VB_CHANNEL, LOG_DEBUG,
4407 LOC + QString(
"Input %1 is free")
4409 freeinputs.push_back(info);
4416 vector<InputInfo>::iterator busyiter = busyinputs.begin();
4417 for (; busyiter != busyinputs.end(); ++busyiter)
4421 vector<InputInfo>::iterator freeiter = freeinputs.begin();
4422 while (freeiter != freeinputs.end())
4435 LOG(VB_CHANNEL, LOG_DEBUG,
4436 LOC + QString(
"Input %1 is limited to %2/%3 by input %4")
4445 LOG(VB_CHANNEL, LOG_DEBUG,
4446 LOC + QString(
"Input %1 is unavailable by input %2")
4448 freeiter = freeinputs.erase(freeiter);
4454 QStringList strlist;
4455 for (
uint i = 0; i < freeinputs.size(); ++i)
4457 LOG(VB_CHANNEL, LOG_INFO,
4458 LOC + QString(
"Input %1 is available on %2/%3")
4459 .arg(freeinputs[i].inputid).arg(freeinputs[i].chanid)
4460 .arg(freeinputs[i].mplexid));
4461 freeinputs[i].ToStringList(strlist);
4464 if (strlist.empty())
4489 if (commands.size() < 2 || slist.size() < 2)
4492 int recnum = commands[1].toInt();
4495 QMap<int, EncoderLink *>::Iterator iter =
encoderList->find(recnum);
4499 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MainServer::HandleRecorderQuery() " +
4500 QString(
"Unknown encoder: %1").arg(recnum));
4501 QStringList retlist(
"bad" );
4507 QString command = slist[1];
4509 QStringList retlist;
4514 LOG(VB_GENERAL, LOG_ERR,
LOC +
" MainServer::HandleRecorderQuery() " +
4515 QString(
"Command %1 for unconnected encoder %2")
4516 .arg(command).arg(recnum));
4522 if (command ==
"IS_RECORDING")
4526 else if (command ==
"GET_FRAMERATE")
4530 else if (command ==
"GET_FRAMES_WRITTEN")
4534 else if (command ==
"GET_FILE_POSITION")
4538 else if (command ==
"GET_MAX_BITRATE")
4542 else if (command ==
"GET_CURRENT_RECORDING")
4557 else if (command ==
"GET_KEYFRAME_POS")
4559 long long desired = slist[2].toLongLong();
4562 else if (command ==
"FILL_POSITION_MAP")
4564 int64_t start = slist[2].toLongLong();
4565 int64_t end = slist[3].toLongLong();
4574 frm_pos_map_t::const_iterator it = map.begin();
4575 for (; it != map.end(); ++it)
4577 retlist += QString::number(it.key());
4578 retlist += QString::number(*it);
4580 if (retlist.empty())
4584 else if (command ==
"FILL_DURATION_MAP")
4586 int64_t start = slist[2].toLongLong();
4587 int64_t end = slist[3].toLongLong();
4596 frm_pos_map_t::const_iterator it = map.begin();
4597 for (; it != map.end(); ++it)
4599 retlist += QString::number(it.key());
4600 retlist += QString::number(*it);
4602 if (retlist.empty())
4606 else if (command ==
"GET_RECORDING")
4621 else if (command ==
"FRONTEND_READY")
4626 else if (command ==
"CANCEL_NEXT_RECORDING")
4628 QString cancel = slist[2];
4629 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
4630 QString(
"Received: CANCEL_NEXT_RECORDING %1").arg(cancel));
4634 else if (command ==
"SPAWN_LIVETV")
4636 QString chainid = slist[2];
4647 enc->
SpawnLiveTV(chain, slist[3].toInt(), slist[4]);
4650 else if (command ==
"STOP_LIVETV")
4667 else if (command ==
"PAUSE")
4672 else if (command ==
"FINISH_RECORDING")
4677 else if (command ==
"SET_LIVE_RECORDING")
4679 int recording = slist[2].toInt();
4683 else if (command ==
"GET_INPUT")
4686 ret = (ret.isEmpty()) ?
"UNKNOWN" : ret;
4689 else if (command ==
"SET_INPUT")
4691 QString input = slist[2];
4692 QString ret = enc->
SetInput(input);
4693 ret = (ret.isEmpty()) ?
"UNKNOWN" : ret;
4696 else if (command ==
"TOGGLE_CHANNEL_FAVORITE")
4698 QString changroup = slist[2];
4702 else if (command ==
"CHANGE_CHANNEL")
4709 else if (command ==
"SET_CHANNEL")
4711 QString
name = slist[2];
4715 else if (command ==
"SET_SIGNAL_MONITORING_RATE")
4717 int rate = slist[2].toInt();
4718 int notifyFrontend = slist[3].toInt();
4720 retlist << QString::number(oldrate);
4722 else if (command ==
"GET_COLOUR")
4725 retlist << QString::number(ret);
4727 else if (command ==
"GET_CONTRAST")
4730 retlist << QString::number(ret);
4732 else if (command ==
"GET_BRIGHTNESS")
4735 retlist << QString::number(ret);
4737 else if (command ==
"GET_HUE")
4740 retlist << QString::number(ret);
4742 else if (command ==
"CHANGE_COLOUR")
4744 int type = slist[2].toInt();
4745 bool up = slist[3].toInt();
4748 retlist << QString::number(ret);
4750 else if (command ==
"CHANGE_CONTRAST")
4752 int type = slist[2].toInt();
4753 bool up = slist[3].toInt();
4756 retlist << QString::number(ret);
4758 else if (command ==
"CHANGE_BRIGHTNESS")
4760 int type= slist[2].toInt();
4761 bool up = slist[3].toInt();
4764 retlist << QString::number(ret);
4766 else if (command ==
"CHANGE_HUE")
4768 int type= slist[2].toInt();
4769 bool up = slist[3].toInt();
4772 retlist << QString::number(ret);
4774 else if (command ==
"CHECK_CHANNEL")
4776 QString
name = slist[2];
4779 else if (command ==
"SHOULD_SWITCH_CARD")
4781 QString chanid = slist[2];
4784 else if (command ==
"CHECK_CHANNEL_PREFIX")
4786 QString needed_spacer;
4787 QString
prefix = slist[2];
4788 uint is_complete_valid_channel_on_rec = 0;
4789 bool is_extra_char_useful =
false;
4792 prefix, is_complete_valid_channel_on_rec,
4793 is_extra_char_useful, needed_spacer);
4795 retlist << QString::number((
int)match);
4796 retlist << QString::number(is_complete_valid_channel_on_rec);
4797 retlist << QString::number((
int)is_extra_char_useful);
4798 retlist << ((needed_spacer.isEmpty()) ? QString(
"X") : needed_spacer);
4800 else if (command ==
"GET_NEXT_PROGRAM_INFO" && (slist.size() >= 6))
4802 QString channelname = slist[2];
4803 uint chanid = slist[3].toUInt();
4805 QString starttime = slist[5];
4807 QString title =
"", subtitle =
"", desc =
"", category =
"";
4808 QString endtime =
"", callsign =
"", iconpath =
"";
4809 QString seriesid =
"", programid =
"";
4812 title, subtitle, desc, category, starttime,
4813 endtime, callsign, iconpath, channelname, chanid,
4814 seriesid, programid);
4825 retlist << QString::number(chanid);
4829 else if (command ==
"GET_CHANNEL_INFO")
4831 uint chanid = slist[2].toUInt();
4833 QString callsign =
"", channum =
"", channame =
"", xmltv =
"";
4836 callsign, channum, channame, xmltv);
4838 retlist << QString::number(chanid);
4839 retlist << QString::number(sourceid);
4847 LOG(VB_GENERAL, LOG_ERR,
LOC +
4848 QString(
"Unknown command: %1").arg(command));
4860 int recnum = commands[1].toInt();
4863 QMap<int, EncoderLink *>::Iterator iter =
encoderList->find(recnum);
4867 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MainServer::HandleSetNextLiveTVDir() " +
4868 QString(
"Unknown encoder: %1").arg(recnum));
4869 QStringList retlist(
"bad" );
4878 QStringList retlist(
"OK" );
4886 uint chanid = slist[1].toUInt();
4887 uint sourceid = slist[2].toUInt();
4888 QString oldcnum =
cleanup(slist[3]);
4889 QString callsign =
cleanup(slist[4]);
4890 QString channum =
cleanup(slist[5]);
4891 QString channame =
cleanup(slist[6]);
4892 QString xmltv =
cleanup(slist[7]);
4894 QStringList retlist;
4895 if (!chanid || !sourceid)
4903 QMap<int, EncoderLink *>::iterator it =
encoderList->begin();
4908 ok &= (*it)->SetChannelInfo(chanid, sourceid, oldcnum,
4909 callsign, channum, channame, xmltv);
4914 retlist << ((ok) ?
"1" :
"0");
4923 int recnum = commands[1].toInt();
4924 QStringList retlist;
4927 QMap<int, EncoderLink *>::Iterator iter =
encoderList->find(recnum);
4931 LOG(VB_GENERAL, LOG_ERR,
LOC +
4932 QString(
"HandleRemoteEncoder(cmd %1) ").arg(slist[1]) +
4933 QString(
"Unknown encoder: %1").arg(recnum));
4942 QString command = slist[1];
4944 if (command ==
"GET_STATE")
4946 retlist << QString::number((
int)enc->
GetState());
4948 else if (command ==
"GET_SLEEPSTATUS")
4952 else if (command ==
"GET_FLAGS")
4954 retlist << QString::number(enc->
GetFlags());
4956 else if (command ==
"IS_BUSY")
4958 int time_buffer = (slist.size() >= 3) ? slist[2].toInt() : 5;
4960 retlist << QString::number((
int)enc->
IsBusy(&busy_input, time_buffer));
4963 else if (command ==
"MATCHES_RECORDING" &&
4966 QStringList::const_iterator it = slist.begin() + 2;
4971 else if (command ==
"START_RECORDING" &&
4974 QStringList::const_iterator it = slist.begin() + 2;
4978 retlist << QString::number(pginfo.GetRecordingID());
4979 #if QT_VERSION < QT_VERSION_CHECK(5,8,0) 4980 retlist << QString::number(pginfo.GetRecordingStartTime().toTime_t());
4982 retlist << QString::number(pginfo.GetRecordingStartTime().toSecsSinceEpoch());
4985 else if (command ==
"GET_RECORDING_STATUS")
4989 else if (command ==
"RECORD_PENDING" &&
4992 int secsleft = slist[2].toInt();
4993 int haslater = slist[3].toInt();
4994 QStringList::const_iterator it = slist.begin() + 4;
5001 else if (command ==
"CANCEL_NEXT_RECORDING" &&
5002 (slist.size() >= 3))
5004 bool cancel = (
bool) slist[2].toInt();
5008 else if (command ==
"STOP_RECORDING")
5013 else if (command ==
"GET_MAX_BITRATE")
5017 else if (command ==
"GET_CURRENT_RECORDING")
5043 vector<PlaybackSock*>::iterator it;
5046 if ((*it)->isMediaServer())
5057 QStringList retlist;
5059 retlist.push_front(QString::number(retlist.size()));
5066 QStringList retlist;
5067 QString queryhostname = slist[1];
5072 if (slave !=
nullptr)
5088 QString fskey = fsInfo->getHostname() +
":" + fsInfo->getPath();
5098 size_t totalKBperMin = 0;
5101 QMap<int, EncoderLink*>::iterator it =
encoderList->begin();
5111 maxBitrate = 19500000LL;
5112 long long thisKBperMin = (((size_t)maxBitrate)*((size_t)15))>>11;
5113 totalKBperMin += thisKBperMin;
5114 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Cardid %1: max bitrate %2 KB/min")
5119 LOG(VB_FILE, LOG_INFO,
LOC +
5120 QString(
"Maximal bitrate of busy encoders is %1 KB/min")
5121 .arg(totalKBperMin));
5123 return totalKBperMin;
5130 int64_t totalKB = -1, usedKB = -1;
5131 QMap <QString, bool>foundDirs;
5133 QString localStr =
"1";
5136 groups.removeAll(
"LiveTV");
5137 QString specialGroups = groups.join(
"', '");
5138 QString sql = QString(
"SELECT MIN(id),dirname " 5139 "FROM storagegroup " 5140 "WHERE hostname = :HOSTNAME " 5141 "AND groupname NOT IN ( '%1' ) " 5142 "GROUP BY dirname;").arg(specialGroups);
5153 query.
prepare(
"SELECT MIN(id),dirname " 5154 "FROM storagegroup " 5155 "WHERE groupname = :GROUP " 5156 "GROUP BY dirname;");
5166 while (query.
next())
5168 dirID = query.
value(0).toString();
5172 currentDir = QString::fromUtf8(query.
value(1)
5173 .toByteArray().constData());
5174 if (currentDir.endsWith(
"/"))
5175 currentDir.remove(currentDir.length() - 1, 1);
5177 checkDir.setPath(currentDir);
5178 if (!foundDirs.contains(currentDir))
5180 if (checkDir.exists())
5182 QByteArray cdir = currentDir.toLatin1();
5184 memset(&statbuf, 0,
sizeof(statbuf));
5188 if (!
statfs(currentDir.toLocal8Bit().constData(), &statbuf))
5191 char *fstypename = statbuf.f_fstypename;
5192 if ((!strcmp(fstypename,
"nfs")) ||
5193 (!strcmp(fstypename,
"afpfs")) ||
5194 (!strcmp(fstypename,
"smbfs")))
5197 long fstype = statbuf.f_type;
5198 if ((fstype == 0x6969) ||
5199 (fstype == 0x517B) ||
5200 (fstype == (
long)0xFF534D42))
5207 strlist << currentDir;
5208 strlist << localStr;
5211 strlist << QString::number(bSize);
5212 strlist << QString::number(totalKB);
5213 strlist << QString::number(usedKB);
5215 foundDirs[currentDir] =
true;
5218 foundDirs[currentDir] =
false;
5225 QMap <QString, bool> backendsCounted;
5228 list<PlaybackSock *> localPlaybackList;
5232 vector<PlaybackSock *>::iterator pbsit =
playbackList.begin();
5237 if ((
pbs->IsDisconnected()) ||
5238 (!
pbs->isMediaServer()) ||
5240 (backendsCounted.contains(
pbs->getHostname())))
5243 backendsCounted[
pbs->getHostname()] =
true;
5245 localPlaybackList.push_back(
pbs);
5246 allHostList +=
"," +
pbs->getHostname();
5251 for (list<PlaybackSock *>::iterator p = localPlaybackList.begin() ;
5252 p != localPlaybackList.end() ; ++p) {
5253 (*p)->GetDiskSpace(strlist);
5262 QList<FileSystemInfo> fsInfos;
5264 QStringList::const_iterator it = strlist.begin();
5265 while (it != strlist.end())
5269 fsInfo.
setLocal((*(it++)).toInt() > 0);
5276 fsInfos.push_back(fsInfo);
5282 maxWriteFiveSec = max((int64_t)2048, maxWriteFiveSec);
5283 QList<FileSystemInfo>::iterator it1, it2;
5285 for (it1 = fsInfos.begin(); it1 != fsInfos.end(); ++it1)
5287 if (it1->getFSysID() == -1)
5291 it1->getHostname().section(
".", 0, 0) +
":" + it1->getPath());
5294 for (it2 = it1 + 1; it2 != fsInfos.end(); ++it2)
5298 bSize = max(32, max(it1->getBlockSize(), it2->getBlockSize()) / 1024);
5299 int64_t diffSize = it1->getTotalSpace() - it2->getTotalSpace();
5300 int64_t diffUsed = it1->getUsedSpace() - it2->getUsedSpace();
5302 diffSize = 0 - diffSize;
5304 diffUsed = 0 - diffUsed;
5306 if (it2->getFSysID() == -1 && (diffSize <= bSize) &&
5307 (diffUsed <= maxWriteFiveSec))
5309 if (!it1->getHostname().contains(it2->getHostname()))
5310 it1->setHostname(it1->getHostname() +
"," + it2->getHostname());
5311 it1->setPath(it1->getPath() +
"," +
5312 it2->getHostname().section(
".", 0, 0) +
":" + it2->getPath());
5322 for (it1 = fsInfos.begin(); it1 != fsInfos.end(); ++it1)
5324 strlist << it1->getHostname();
5325 strlist << it1->getPath();
5326 strlist << QString::number(it1->isLocal());
5327 strlist << QString::number(it1->getFSysID());
5328 strlist << QString::number(it1->getGroupID());
5329 strlist << QString::number(it1->getBlockSize());
5330 strlist << QString::number(it1->getTotalSpace());
5331 strlist << QString::number(it1->getUsedSpace());
5333 totalKB += it1->getTotalSpace();
5334 usedKB += it1->getUsedSpace();
5339 strlist << allHostList;
5340 strlist <<
"TotalDiskSpace";
5345 strlist << QString::number(totalKB);
5346 strlist << QString::number(usedKB);
5361 QStringList strlist;
5368 QStringList::const_iterator it = strlist.begin();
5369 while (it != strlist.end())
5373 fsInfo.
setLocal((*(it++)).toInt() > 0);
5381 fsInfos.push_back(fsInfo);
5384 LOG(VB_SCHEDULE | VB_FILE, LOG_DEBUG,
LOC +
5385 "Determining unique filesystems");
5388 maxWriteFiveSec = max((
size_t)2048, maxWriteFiveSec);
5392 QList<FileSystemInfo>::iterator it1;
5395 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5396 "--- GetFilesystemInfos directory list start ---");
5397 for (it1 = fsInfos.begin(); it1 != fsInfos.end(); ++it1)
5400 QString(
"Dir: %1:%2")
5401 .arg(it1->getHostname())
5402 .arg(it1->getPath());
5403 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC + msg) ;
5404 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5405 QString(
" Location: %1")
5406 .arg(it1->isLocal() ?
"Local" :
"Remote"));
5407 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5408 QString(
" fsID : %1")
5409 .arg(it1->getFSysID()));
5410 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5411 QString(
" dirID : %1")
5412 .arg(it1->getGroupID()));
5413 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5414 QString(
" BlkSize : %1")
5415 .arg(it1->getBlockSize()));
5416 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5417 QString(
" TotalKB : %1")
5418 .arg(it1->getTotalSpace()));
5419 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5420 QString(
" UsedKB : %1")
5421 .arg(it1->getUsedSpace()));
5422 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5423 QString(
" FreeKB : %1")
5424 .arg(it1->getFreeSpace()));
5426 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
LOC +
5427 "--- GetFilesystemInfos directory list end ---");
5436 const QString &src,
const QString &dst)
5439 QStringList retlist;
5441 if (src.isEmpty() || dst.isEmpty()
5442 || src.contains(
"..") || dst.contains(
".."))
5444 LOG(VB_GENERAL, LOG_ERR,
LOC +
5445 QString(
"HandleMoveFile: ERROR moving file '%1' -> '%2', " 5446 "a path fails sanity checks").arg(src, dst));
5447 retlist <<
"0" <<
"Invalid path";
5452 QString srcAbs = sgroup.
FindFile(src);
5453 if (srcAbs.isEmpty())
5455 LOG(VB_GENERAL, LOG_ERR,
LOC +
5456 QString(
"HandleMoveFile: Unable to find %1").arg(src));
5457 retlist <<
"0" <<
"Source file not found";
5465 QString dstAbs = sgroup.
FindFile(dst);
5466 if (!dstAbs.isEmpty() && QFileInfo(dstAbs).isFile())
5468 LOG(VB_GENERAL, LOG_ERR,
LOC +
5469 QString(
"HandleMoveFile: Destination exists at %1").arg(dstAbs));
5470 retlist <<
"0" <<
"Destination file exists";
5476 int sgPathSize = srcAbs.size() - src.size();
5477 dstAbs = srcAbs.mid(0, sgPathSize) + dst;
5491 LOG(VB_FILE, LOG_INFO, QString(
"MainServer::RenameThread: Renaming %1 -> %2")
5494 QStringList retlist;
5495 QFileInfo fi(
m_dst);
5497 if (QDir().mkpath(fi.path()) && QFile::rename(
m_src,
m_dst))
5503 retlist <<
"0" <<
"Rename failed";
5504 LOG(VB_FILE, LOG_ERR,
"MainServer::DoRenameThread: Rename failed");
5537 QStringList retlist;
5539 if ((filename.isEmpty()) ||
5540 (filename.contains(
"/../")) ||
5541 (filename.startsWith(
"../")))
5543 LOG(VB_GENERAL, LOG_ERR,
LOC +
5544 QString(
"ERROR deleting file, filename '%1' " 5545 "fails sanity checks").arg(filename));
5554 QString fullfile = sgroup.
FindFile(filename);
5556 if (fullfile.isEmpty()) {
5557 LOG(VB_GENERAL, LOG_ERR,
LOC +
5558 QString(
"Unable to find %1 in HandleDeleteFile()") .arg(filename));
5567 QFile checkFile(fullfile);
5574 const QFileInfo info(fullfile);
5578 if ((fd < 0) && checkFile.exists())
5580 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Error deleting file: %1.")
5602 truncateThread->
run();
5610 const QString &starttime,
5615 pbssock =
pbs->getSocket();
5618 frm_dir_map_t::const_iterator it;
5619 #if QT_VERSION < QT_VERSION_CHECK(5,8,0) 5620 QDateTime recstartdt = MythDate::fromTime_t(starttime.toULongLong());
5624 QStringList retlist;
5627 const ProgramInfo pginfo(chanid.toUInt(), recstartdt);
5629 if (pginfo.GetChanID())
5634 pginfo.QueryCutList(markMap);
5636 for (it = markMap.begin(); it != markMap.end(); ++it)
5639 QString intstr = QString(
"%1").arg(*it);
5641 retlist << QString::number(it.key());
5646 retlist.prepend(QString(
"%1").arg(rowcnt));
5657 const QString &starttime,
5672 const QString &starttime,
5688 const QString &starttime,
5699 pbssock =
pbs->getSocket();
5701 #if QT_VERSION < QT_VERSION_CHECK(5,8,0) 5702 QDateTime recstartts = MythDate::fromTime_t(starttime.toULongLong());
5708 chanid.toUInt(), recstartts);
5710 QStringList retlist;
5711 retlist << QString::number(bookmark);
5732 pbssock =
pbs->getSocket();
5734 QString chanid = tokens[1];
5735 QString starttime = tokens[2];
5736 long long bookmark = tokens[3].toLongLong();
5738 #if QT_VERSION < QT_VERSION_CHECK(5,8,0) 5739 QDateTime recstartts = MythDate::fromTime_t(starttime.toULongLong());
5743 QStringList retlist;
5747 if (pginfo.GetChanID())
5753 retlist <<
"FAILED";
5768 pbssock =
pbs->getSocket();
5771 QString setting = tokens[2];
5772 QStringList retlist;
5776 retlist << retvalue;
5786 bool synchronous = (command[0] ==
"DOWNLOAD_FILE_NOW");
5787 QString srcURL = command[1];
5788 QString storageGroup = command[2];
5789 QString filename = command[3];
5793 QStringList retlist;
5797 pbssock =
pbs->getSocket();
5799 if (filename.isEmpty())
5801 QFileInfo finfo(srcURL);
5802 filename = finfo.fileName();
5805 if (outDir.isEmpty())
5807 LOG(VB_GENERAL, LOG_ERR,
LOC +
5808 QString(
"Unable to determine directory " 5809 "to write to in %1 write command").arg(command[0]));
5810 retlist <<
"downloadfile_directory_not_found";
5816 if ((filename.contains(
"/../")) ||
5817 (filename.startsWith(
"../")))
5819 LOG(VB_GENERAL, LOG_ERR,
LOC +
5820 QString(
"ERROR: %1 write filename '%2' does not pass " 5821 "sanity checks.") .arg(command[0]).arg(filename));
5822 retlist <<
"downloadfile_filename_dangerous";
5828 outFile = outDir +
"/" + filename;
5863 pbssock =
pbs->getSocket();
5866 QString setting = tokens[2];
5867 QString svalue = tokens[3];
5868 QStringList retlist;
5885 QStringList retlist;
5905 QStringList strlist;
5911 QString sql =
"SELECT DISTINCT hostname " 5912 "FROM storagegroup " 5913 "WHERE groupname = 'Music'";
5925 LOG(VB_GENERAL, LOG_INFO,
LOC +
5926 QString(
"HandleScanMusic: running filescanner on master BE '%1'").arg(
hostname));
5938 LOG(VB_GENERAL, LOG_INFO,
LOC +
5939 QString(
"HandleScanMusic: asking slave '%1' to run file scanner").arg(
hostname));
5945 LOG(VB_GENERAL, LOG_INFO,
LOC +
5946 QString(
"HandleScanMusic: Failed to grab slave socket on '%1'").arg(
hostname));
5955 LOG(VB_GENERAL, LOG_INFO,
LOC +
5956 QString(
"HandleScanMusic: running filescanner on slave BE '%1'")
5974 QStringList strlist;
5986 LOG(VB_GENERAL, LOG_INFO,
LOC +
5987 QString(
"HandleMusicTagUpdateVolatile: asking slave '%1' to update the metadata").arg(
hostname));
5998 LOG(VB_GENERAL, LOG_INFO,
LOC +
5999 QString(
"HandleMusicTagUpdateVolatile: Failed to grab slave socket on '%1'").arg(
hostname));
6001 strlist <<
"ERROR: slave not found";
6012 QStringList paramList;
6013 paramList.append(QString(
"--songid='%1'").arg(slist[2]));
6014 paramList.append(QString(
"--rating='%1'").arg(slist[3]));
6015 paramList.append(QString(
"--playcount='%1'").arg(slist[4]));
6016 paramList.append(QString(
"--lastplayed='%1'").arg(slist[5]));
6018 QString command =
GetAppBinDir() +
"mythutil --updatemeta " + paramList.join(
" ");
6020 LOG(VB_GENERAL, LOG_INFO,
LOC +
6021 QString(
"HandleMusicTagUpdateVolatile: running %1'").arg(command));
6038 QStringList strlist;
6050 LOG(VB_GENERAL, LOG_INFO,
LOC +
6051 QString(
"HandleMusicCalcTrackLen: asking slave '%1' to update the track length").arg(
hostname));
6062 LOG(VB_GENERAL, LOG_INFO,
LOC +
6063 QString(
"HandleMusicCalcTrackLen: Failed to grab slave socket on '%1'").arg(
hostname));
6065 strlist <<
"ERROR: slave not found";
6076 QStringList paramList;
6077 paramList.append(QString(
"--songid='%1'").arg(slist[2]));
6079 QString command =
GetAppBinDir() +
"mythutil --calctracklen " + paramList.join(
" ");
6081 LOG(VB_GENERAL, LOG_INFO,
LOC +
6082 QString(
"HandleMusicCalcTrackLen: running %1'").arg(command));
6100 QStringList strlist;
6112 LOG(VB_GENERAL, LOG_INFO,
LOC +
6113 QString(
"HandleMusicTagUpdateMetadata: asking slave '%1' " 6114 "to update the metadata").arg(
hostname));
6125 LOG(VB_GENERAL, LOG_INFO,
LOC +
6126 QString(
"HandleMusicTagUpdateMetadata: Failed to grab " 6127 "slave socket on '%1'").arg(
hostname));
6129 strlist <<
"ERROR: slave not found";
6140 int songID = slist[2].toInt();
6146 LOG(VB_GENERAL, LOG_ERR,
LOC +
6147 QString(
"HandleMusicTagUpdateMetadata: " 6148 "Cannot find metadata for trackid: %1")
6151 strlist <<
"ERROR: track not found";
6164 LOG(VB_GENERAL, LOG_ERR,
LOC +
6165 QString(
"HandleMusicTagUpdateMetadata: " 6166 "Failed to write to tag for trackid: %1")
6169 strlist <<
"ERROR: write to tag failed";
6190 QStringList strlist;
6202 LOG(VB_GENERAL, LOG_INFO,
LOC +
6203 QString(
"HandleMusicFindAlbumArt: asking slave '%1' " 6204 "to update the albumart").arg(
hostname));
6215 LOG(VB_GENERAL, LOG_INFO,
LOC +
6216 QString(
"HandleMusicFindAlbumArt: Failed to grab " 6217 "slave socket on '%1'").arg(
hostname));
6219 strlist <<
"ERROR: slave not found";
6230 int songID = slist[2].toInt();
6231 bool updateDatabase = (slist[3].toInt() == 1);
6237 LOG(VB_GENERAL, LOG_ERR,
LOC +
6238 QString(
"HandleMusicFindAlbumArt: " 6239 "Cannot find metadata for trackid: %1").arg(songID));
6241 strlist <<
"ERROR: track not found";
6251 QDir dir = fi.absoluteDir();
6254 "*.png;*.jpg;*.jpeg;*.gif;*.bmp");
6255 dir.setNameFilters(nameFilter.split(
";"));
6257 QStringList files = dir.entryList();
6262 fi.setFile(mdata->
Filename(
false));
6263 QString startDir = fi.path();
6265 for (
int x = 0; x < files.size(); x++)
6267 fi.setFile(files.at(x));
6269 image->
filename = startDir +
'/' + fi.fileName();
6286 for (
int x = 0; x < artList.count(); x++)
6298 LOG(VB_GENERAL, LOG_ERR,
LOC +
6299 QString(
"HandleMusicFindAlbumArt: " 6300 "Failed to find a tagger for trackid: %1").arg(songID));
6313 strlist.append(QString(
"%1").arg(image->
id));
6314 strlist.append(QString(
"%1").arg((
int)image->
imageType));
6315 strlist.append(QString(