12 #include "mythconfig.h"
15 #include <sys/ioctl.h>
21 #else // if !__linux__
22 # include <sys/param.h>
24 # include <sys/mount.h>
25 # endif // USING_MINGW
28 #include <QCoreApplication>
32 #include <QWaitCondition>
38 #include <QNetworkInterface>
39 #include <QNetworkProxy>
62 #include "ringbuffer.h"
78 #define PRT_TIMEOUT 10
80 #define PRT_STARTUP_THREAD_COUNT 5
82 #define LOC QString("MainServer: ")
83 #define LOC_WARN QString("MainServer, Warning: ")
84 #define LOC_ERR QString("MainServer, Error: ")
88 int delete_file_immediately(
const QString &filename,
89 bool followLinks,
bool checkexists)
92 QFile checkFile(filename);
93 int success1, success2;
95 LOG(VB_FILE, LOG_INFO, QString(
"About to delete file: %1").arg(filename));
100 QFileInfo finfo(filename);
101 if (finfo.isSymLink())
105 QFile target(linktext);
106 if (!(success1 = target.remove()))
108 LOG(VB_GENERAL, LOG_ERR, QString(
"Error deleting '%1' -> '%2'")
109 .arg(filename).arg(linktext) + ENO);
113 if ((!checkexists || checkFile.exists()) &&
114 !(success2 = checkFile.remove()))
116 LOG(VB_GENERAL, LOG_ERR, QString(
"Error deleting '%1': %2")
117 .arg(filename).arg(strerror(errno)));
119 return success1 && success2 ? 0 : -1;
131 m_parent(parent), m_sock(sock)
147 m_parent.ProcessRequest(m_sock);
161 m_parent(parent), m_dorun(
true), m_running(
true)
163 m_lastRequest.start();
167 QMutexLocker locker(&m_parent.masterFreeSpaceListLock);
168 m_parent.masterFreeSpaceListUpdater = NULL;
169 m_parent.masterFreeSpaceListWait.wakeAll();
179 m_parent.BackendQueryDiskSpace(list,
true,
true);
181 QMutexLocker locker(&m_parent.masterFreeSpaceListLock);
182 m_parent.masterFreeSpaceList = list;
184 QMutexLocker locker(&
m_lock);
185 int left = kRequeryTimeout - t.
elapsed();
186 if (m_lastRequest.elapsed() + left > kExitTimeout)
194 m_wait.wait(locker.mutex(), left);
198 bool KeepRunning(
bool dorun)
200 QMutexLocker locker(&
m_lock);
201 if (dorun && m_running)
204 m_lastRequest.restart();
227 QMap<int, EncoderLink *> *
tvList,
229 encoderList(tvList), mythserver(NULL),
230 masterFreeSpaceListUpdater(NULL),
231 masterServerReconnect(NULL),
232 masterServer(NULL), ismaster(master), threadPool(
"ProcessRequestPool"),
233 masterBackendOverride(
false),
234 m_sched(sched), m_expirer(expirer), deferredDeleteTimer(NULL),
235 autoexpireUpdateTimer(NULL), m_exitCode(GENERIC_EXIT_OK),
253 bool v4IsSet = config_v4.isNull() ?
false :
true;
254 #if !defined(QT_NO_IPV6)
256 bool v6IsSet = config_v6.isNull() ?
false :
true;
260 #if !defined(QT_NO_IPV6)
261 if (v6IsSet && !listenAddrs.contains(config_v6))
262 LOG(VB_GENERAL, LOG_WARNING,
"Unable to find IPv6 address to bind");
265 if (v4IsSet && !listenAddrs.contains(config_v4))
266 LOG(VB_GENERAL, LOG_WARNING,
"Unable to find IPv4 address to bind");
268 if ((v4IsSet && !listenAddrs.contains(config_v4))
269 #
if !defined(QT_NO_IPV6)
270 && (v6IsSet && !listenAddrs.contains(config_v6))
274 LOG(VB_GENERAL, LOG_ERR,
"Unable to find either IPv4 or IPv6 "
275 "address we can bind to, exiting");
392 vector<PlaybackSock *>::iterator it =
playbackList.begin();
433 LOG(VB_GENERAL, LOG_INFO,
"readyRead ignoring, expecting reply");
439 "ProcessRequest", PRT_TIMEOUT);
441 QCoreApplication::processEvents();
449 LOG(VB_GENERAL, LOG_INFO, QString(
"No data on sock %1")
455 QStringList listline;
458 LOG(VB_GENERAL, LOG_INFO,
"No data in ProcessRequestWork()");
462 QString line = listline[0];
464 line = line.simplified();
465 QStringList tokens = line.split(
' ', QString::SkipEmptyParts);
466 QString command = tokens[0];
467 if (command ==
"MYTH_PROTO_VERSION")
469 if (tokens.size() < 2)
470 LOG(VB_GENERAL, LOG_CRIT,
"Bad MYTH_PROTO_VERSION command");
475 else if (command ==
"ANN")
480 else if (command ==
"DONE")
491 LOG(VB_GENERAL, LOG_ERR,
"ProcessRequest unknown socket");
497 if (command ==
"QUERY_FILETRANSFER")
499 if (tokens.size() != 2)
500 LOG(VB_GENERAL, LOG_ERR,
"Bad QUERY_FILETRANSFER");
504 else if (command ==
"QUERY_RECORDINGS")
506 if (tokens.size() != 2)
507 LOG(VB_GENERAL, LOG_ERR,
"Bad QUERY_RECORDINGS query");
511 else if (command ==
"QUERY_RECORDING")
515 else if (command ==
"GO_TO_SLEEP")
519 else if (command ==
"QUERY_FREE_SPACE")
523 else if (command ==
"QUERY_FREE_SPACE_LIST")
527 else if (command ==
"QUERY_FREE_SPACE_SUMMARY")
531 else if (command ==
"QUERY_LOAD")
535 else if (command ==
"QUERY_UPTIME")
539 else if (command ==
"QUERY_HOSTNAME")
543 else if (command ==
"QUERY_MEMSTATS")
547 else if (command ==
"QUERY_TIME_ZONE")
551 else if (command ==
"QUERY_CHECKFILE")
555 else if (command ==
"QUERY_FILE_EXISTS")
557 if (listline.size() < 2)
558 LOG(VB_GENERAL, LOG_ERR,
"Bad QUERY_FILE_EXISTS command");
562 else if (command ==
"QUERY_FILE_HASH")
564 if (listline.size() < 3)
565 LOG(VB_GENERAL, LOG_ERR,
"Bad QUERY_FILE_HASH command");
569 else if (command ==
"QUERY_GUIDEDATATHROUGH")
573 else if (command ==
"DELETE_FILE")
575 if (listline.size() < 3)
576 LOG(VB_GENERAL, LOG_ERR,
"Bad DELETE_FILE command");
580 else if (command ==
"STOP_RECORDING")
584 else if (command ==
"CHECK_RECORDING")
588 else if (command ==
"DELETE_RECORDING")
590 if (3 <= tokens.size() && tokens.size() <= 5)
592 bool force = (tokens.size() >= 4) && (tokens[3] ==
"FORCE");
593 bool forget = (tokens.size() >= 5) && (tokens[4] ==
"FORGET");
599 else if (command ==
"FORCE_DELETE_RECORDING")
603 else if (command ==
"UNDELETE_RECORDING")
607 else if (command ==
"RESCHEDULE_RECORDINGS")
609 listline.pop_front();
612 else if (command ==
"FORGET_RECORDING")
616 else if (command ==
"QUERY_GETALLPENDING")
618 if (tokens.size() == 1)
620 else if (tokens.size() == 2)
625 else if (command ==
"QUERY_GETALLSCHEDULED")
629 else if (command ==
"QUERY_GETCONFLICTING")
633 else if (command ==
"QUERY_GETEXPIRING")
637 else if (command ==
"QUERY_SG_GETFILELIST")
641 else if (command ==
"QUERY_SG_FILEQUERY")
645 else if (command ==
"GET_FREE_RECORDER")
649 else if (command ==
"GET_FREE_RECORDER_COUNT")
653 else if (command ==
"GET_FREE_RECORDER_LIST")
657 else if (command ==
"GET_NEXT_FREE_RECORDER")
661 else if (command ==
"QUERY_RECORDER")
663 if (tokens.size() != 2)
664 LOG(VB_GENERAL, LOG_ERR,
"Bad QUERY_RECORDER");
668 else if (command ==
"QUERY_RECORDING_DEVICE")
672 else if (command ==
"QUERY_RECORDING_DEVICES")
676 else if (command ==
"SET_NEXT_LIVETV_DIR")
678 if (tokens.size() != 3)
679 LOG(VB_GENERAL, LOG_ERR,
"Bad SET_NEXT_LIVETV_DIR");
683 else if (command ==
"SET_CHANNEL_INFO")
687 else if (command ==
"QUERY_REMOTEENCODER")
689 if (tokens.size() != 2)
690 LOG(VB_GENERAL, LOG_ERR,
"Bad QUERY_REMOTEENCODER");
694 else if (command ==
"GET_RECORDER_FROM_NUM")
698 else if (command ==
"GET_RECORDER_NUM")
702 else if (command ==
"QUERY_GENPIXMAP2")
706 else if (command ==
"QUERY_PIXMAP_LASTMODIFIED")
710 else if (command ==
"QUERY_PIXMAP_GET_IF_MODIFIED")
714 else if (command ==
"QUERY_ISRECORDING")
718 else if (command ==
"MESSAGE")
720 if ((listline.size() >= 2) && (listline[1].startsWith(
"SET_VERBOSE")))
722 else if ((listline.size() >= 2) &&
723 (listline[1].startsWith(
"SET_LOG_LEVEL")))
728 else if (command ==
"FILL_PROGRAM_INFO")
732 else if (command ==
"LOCK_TUNER")
734 if (tokens.size() == 1)
736 else if (tokens.size() == 2)
739 LOG(VB_GENERAL, LOG_ERR,
"Bad LOCK_TUNER query");
741 else if (command ==
"FREE_TUNER")
743 if (tokens.size() != 2)
744 LOG(VB_GENERAL, LOG_ERR,
"Bad FREE_TUNER query");
748 else if (command ==
"QUERY_ACTIVE_BACKENDS")
752 else if (command ==
"QUERY_IS_ACTIVE_BACKEND")
754 if (tokens.size() != 1)
755 LOG(VB_GENERAL, LOG_ERR,
"Bad QUERY_IS_ACTIVE_BACKEND");
759 else if (command ==
"QUERY_COMMBREAK")
761 if (tokens.size() != 3)
762 LOG(VB_GENERAL, LOG_ERR,
"Bad QUERY_COMMBREAK");
766 else if (command ==
"QUERY_CUTLIST")
768 if (tokens.size() != 3)
769 LOG(VB_GENERAL, LOG_ERR,
"Bad QUERY_CUTLIST");
773 else if (command ==
"QUERY_BOOKMARK")
775 if (tokens.size() != 3)
776 LOG(VB_GENERAL, LOG_ERR,
"Bad QUERY_BOOKMARK");
780 else if (command ==
"SET_BOOKMARK")
782 if (tokens.size() != 5)
783 LOG(VB_GENERAL, LOG_ERR,
"Bad SET_BOOKMARK");
787 else if (command ==
"QUERY_SETTING")
789 if (tokens.size() != 3)
790 LOG(VB_GENERAL, LOG_ERR,
"Bad QUERY_SETTING");
794 else if (command ==
"SET_SETTING")
796 if (tokens.size() != 4)
797 LOG(VB_GENERAL, LOG_ERR,
"Bad SET_SETTING");
801 else if (command ==
"SCAN_VIDEOS")
805 else if (command ==
"ALLOW_SHUTDOWN")
807 if (tokens.size() != 1)
808 LOG(VB_GENERAL, LOG_ERR,
"Bad ALLOW_SHUTDOWN");
812 else if (command ==
"BLOCK_SHUTDOWN")
814 if (tokens.size() != 1)
815 LOG(VB_GENERAL, LOG_ERR,
"Bad BLOCK_SHUTDOWN");
819 else if (command ==
"SHUTDOWN_NOW")
821 if (tokens.size() != 1)
822 LOG(VB_GENERAL, LOG_ERR,
"Bad SHUTDOWN_NOW query");
826 if (listline.size() >= 2)
827 halt_cmd = listline[1];
829 if (!halt_cmd.isEmpty())
831 LOG(VB_GENERAL, LOG_NOTICE,
832 "Going down now as of Mainserver request!");
836 LOG(VB_GENERAL, LOG_WARNING,
837 "Received an empty SHUTDOWN_NOW query!");
840 else if (command ==
"BACKEND_MESSAGE")
842 QString message = listline[1];
843 QStringList extra( listline[2] );
844 for (
int i = 3; i < listline.size(); i++)
845 extra << listline[i];
849 else if ((command ==
"DOWNLOAD_FILE") ||
850 (command ==
"DOWNLOAD_FILE_NOW"))
852 if (listline.size() != 4)
853 LOG(VB_GENERAL, LOG_ERR, QString(
"Bad %1 command").arg(command));
857 else if (command ==
"REFRESH_BACKEND")
859 LOG(VB_GENERAL, LOG_INFO ,
"Reloading backend settings");
862 else if (command ==
"OK")
864 LOG(VB_GENERAL, LOG_ERR,
"Got 'OK' out of sequence.");
866 else if (command ==
"UNKNOWN_COMMAND")
868 LOG(VB_GENERAL, LOG_ERR,
"Got 'UNKNOWN_COMMAND' out of sequence.");
872 LOG(VB_GENERAL, LOG_ERR,
"Unknown command: " + command);
877 strlist <<
"UNKNOWN_COMMAND";
887 QStringList broadcast;
888 QSet<QString> receivers;
908 QString message = me->
Message();
910 if ((message ==
"PREVIEW_SUCCESS" || message ==
"PREVIEW_QUEUED") &&
919 if (message ==
"PREVIEW_QUEUED")
921 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Preview Queued: '%1' '%2'")
922 .arg(pginfokey).arg(filename));
926 QFile file(filename);
927 ok = ok && file.open(QIODevice::ReadOnly);
931 QByteArray
data = file.readAll();
932 QStringList extra(
"OK");
933 extra.push_back(pginfokey);
934 extra.push_back(msg);
935 extra.push_back(datetime);
936 extra.push_back(QString::number(data.size()));
938 QString::number(qChecksum(data.constData(), data.size())));
939 extra.push_back(QString(data.toBase64()));
944 extra.push_back(token);
948 receivers.insert(*it);
953 if (receivers.empty())
955 LOG(VB_GENERAL, LOG_ERR,
LOC +
956 "PREVIEW_SUCCESS but no receivers.");
960 broadcast.push_back(
"BACKEND_MESSAGE");
961 broadcast.push_back(
"GENERATED_PIXMAP");
966 message =
"PREVIEW_FAILED";
967 error = QString(
"Failed to read '%1'").arg(filename);
968 LOG(VB_GENERAL, LOG_ERR,
LOC + error);
977 QStringList extra(
"ERROR");
978 extra.push_back(pginfokey);
979 extra.push_back(msg);
983 extra.push_back(token);
987 receivers.insert(*it);
992 if (receivers.empty())
994 LOG(VB_GENERAL, LOG_ERR,
LOC +
995 "PREVIEW_FAILED but no receivers.");
999 broadcast.push_back(
"BACKEND_MESSAGE");
1000 broadcast.push_back(
"GENERATED_PIXMAP");
1004 if (me->
Message().startsWith(
"AUTO_EXPIRE"))
1006 QStringList tokens = me->
Message()
1007 .split(
" ", QString::SkipEmptyParts);
1009 if (tokens.size() != 3)
1011 LOG(VB_GENERAL, LOG_ERR,
"Bad AUTO_EXPIRE message");
1035 QString msg = QString(
"Cannot find program info for '%1', "
1036 "while attempting to Auto-Expire.")
1038 LOG(VB_GENERAL, LOG_ERR,
LOC + msg);
1044 if (me->
Message().startsWith(
"QUERY_NEXT_LIVETV_DIR") &&
m_sched)
1046 QStringList tokens = me->
Message()
1047 .split(
" ", QString::SkipEmptyParts);
1049 if (tokens.size() != 2)
1051 LOG(VB_GENERAL, LOG_ERR,
1052 QString(
"Bad %1 message").arg(tokens[0]));
1060 if ((me->
Message().startsWith(
"DELETE_RECORDING")) ||
1061 (me->
Message().startsWith(
"FORCE_DELETE_RECORDING")))
1063 QStringList tokens = me->
Message()
1064 .split(
" ", QString::SkipEmptyParts);
1066 if (tokens.size() != 3)
1068 LOG(VB_GENERAL, LOG_ERR,
1069 QString(
"Bad %1 message").arg(tokens[0]));
1078 if (tokens[0] ==
"FORCE_DELETE_RECORDING")
1085 LOG(VB_GENERAL, LOG_ERR,
1086 QString(
"Cannot find program info for '%1' while "
1087 "attempting to delete.").arg(me->
Message()));
1093 if (me->
Message().startsWith(
"RESCHEDULE_RECORDINGS") &&
m_sched)
1100 if (me->
Message().startsWith(
"SCHEDULER_ADD_RECORDING") &&
m_sched)
1103 if (!pi.GetChanID())
1105 LOG(VB_GENERAL, LOG_ERR,
"Bad SCHEDULER_ADD_RECORDING message");
1113 if (me->
Message().startsWith(
"UPDATE_RECORDING_STATUS") &&
m_sched)
1115 QStringList tokens = me->
Message()
1116 .split(
" ", QString::SkipEmptyParts);
1118 if (tokens.size() != 6)
1120 LOG(VB_GENERAL, LOG_ERR,
"Bad UPDATE_RECORDING_STATUS message");
1124 uint cardid = tokens[1].toUInt();
1125 uint chanid = tokens[2].toUInt();
1130 recstatus, recendts);
1134 if (me->
Message().startsWith(
"LIVETV_EXITED"))
1144 if (me->
Message() ==
"CLEAR_SETTINGS_CACHE")
1150 if (me->
Message() ==
"LOCAL_RECONNECT_TO_MASTER")
1153 if (me->
Message() ==
"LOCAL_SLAVE_BACKEND_ENCODERS_OFFLINE")
1156 if (me->
Message().startsWith(
"LOCAL_"))
1160 if (me->
Message().startsWith(
"MASTER_UPDATE_PROG_INFO"))
1162 QStringList tokens = me->
Message().simplified().split(
" ");
1164 QDateTime recstartts;
1165 if (tokens.size() >= 3)
1167 chanid = tokens[1].toUInt();
1182 mod_me =
MythEvent(
"RECORDING_LIST_CHANGE UPDATE", list);
1191 if (me->
Message().startsWith(
"DOWNLOAD_FILE"))
1194 QString localFile = extraDataList[1];
1195 QFile file(localFile);
1196 QStringList tokens = me->
Message().simplified().split(
" ");
1204 if ((tokens.size() >= 2) && (tokens[1] ==
"FINISHED"))
1211 if (broadcast.empty())
1213 broadcast.push_back(
"BACKEND_MESSAGE");
1214 broadcast.push_back(me->
Message());
1219 if (!broadcast.empty())
1222 vector<PlaybackSock *> localPBSList;
1224 vector<PlaybackSock *>::iterator it =
playbackList.begin();
1228 localPBSList.push_back(*it);
1232 bool sendGlobal =
false;
1233 if (
ismaster && broadcast[1].startsWith(
"GLOBAL_"))
1235 broadcast[1].replace(
"GLOBAL_",
"LOCAL_");
1236 MythEvent me(broadcast[1], broadcast[2]);
1242 QSet<PlaybackSock*> sentSet;
1244 bool isSystemEvent = broadcast[1].startsWith(
"SYSTEM_EVENT ");
1247 vector<PlaybackSock*>::const_iterator iter;
1248 for (iter = localPBSList.begin(); iter != localPBSList.end(); ++iter)
1255 if (!receivers.empty() && !receivers.contains(pbs->
getHostname()))
1258 sentSet.insert(pbs);
1260 bool reallysendit =
false;
1262 if (broadcast[1] ==
"CLEAR_SETTINGS_CACHE")
1266 reallysendit =
true;
1268 else if (sendGlobal)
1271 reallysendit =
true;
1275 reallysendit =
true;
1288 if (sentSetSystemEvent.contains(pbs->
getHostname()))
1304 for (iter = localPBSList.begin(); iter != localPBSList.end(); ++iter)
1322 QStringList retlist;
1324 if (version != MYTH_PROTO_VERSION)
1326 LOG(VB_GENERAL, LOG_CRIT,
1327 "MainServer::HandleVersion - Client speaks protocol version " +
1328 version +
" but we speak " + MYTH_PROTO_VERSION +
'!');
1329 retlist <<
"REJECT" << MYTH_PROTO_VERSION;
1335 if (slist.size() < 3)
1337 LOG(VB_GENERAL, LOG_CRIT,
1338 "MainServer::HandleVersion - Client did not pass protocol "
1339 "token. Refusing connection!");
1340 retlist <<
"REJECT" << MYTH_PROTO_VERSION;
1346 QString token = slist[2];
1347 if (token != MYTH_PROTO_TOKEN)
1349 LOG(VB_GENERAL, LOG_CRIT,
1350 "MainServer::HandleVersion - Client sent incorrect protocol"
1351 " token for protocol version. Refusing connection!");
1352 retlist <<
"REJECT" << MYTH_PROTO_VERSION;
1358 retlist <<
"ACCEPT" << MYTH_PROTO_VERSION;
1377 QStringList retlist(
"OK" );
1378 QStringList errlist(
"ERROR" );
1380 if (commands.size() < 3 || commands.size() > 6)
1383 if (commands.size() == 2)
1384 info = QString(
" %1").arg(commands[1]);
1386 LOG(VB_GENERAL, LOG_ERR, QString(
"Received malformed ANN%1 query")
1389 errlist <<
"malformed_ann_query";
1395 vector<PlaybackSock *>::iterator iter =
playbackList.begin();
1401 LOG(VB_GENERAL, LOG_WARNING,
1402 QString(
"Client %1 is trying to announce a socket "
1412 if (commands[1] ==
"Playback" || commands[1] ==
"Monitor")
1414 if (commands.size() < 4)
1416 LOG(VB_GENERAL, LOG_ERR, QString(
"Received malformed ANN %1 query")
1419 errlist <<
"malformed_ann_query";
1428 LOG(VB_GENERAL, LOG_INFO, QString(
"MainServer::ANN %1")
1430 LOG(VB_GENERAL, LOG_INFO, QString(
"adding: %1 as a client (events: %2)")
1431 .arg(commands[2]).arg(eventsMode));
1443 QString(
"CLIENT_CONNECTED HOSTNAME %1").arg(commands[2]));
1445 else if (commands[1] ==
"MediaServer")
1447 if (commands.size() < 3)
1449 LOG(VB_GENERAL, LOG_ERR,
1450 "Received malformed ANN MediaServer query");
1451 errlist <<
"malformed_ann_query";
1466 QString(
"CLIENT_CONNECTED HOSTNAME %1").arg(commands[2]));
1468 else if (commands[1] ==
"SlaveBackend")
1470 if (commands.size() < 4)
1472 LOG(VB_GENERAL, LOG_ERR, QString(
"Received malformed ANN %1 query")
1474 errlist <<
"malformed_ann_query";
1479 LOG(VB_GENERAL, LOG_INFO,
1480 QString(
"adding: %1 as a slave backend server")
1485 pbs->
setIP(commands[3]);
1490 QStringList::const_iterator sit = slist.
begin()+1;
1491 while (sit != slist.end())
1504 bool wasAsleep =
true;
1505 QMap<int, EncoderLink *>::Iterator iter =
encoderList->begin();
1520 QString message = QString(
"LOCAL_SLAVE_BACKEND_ONLINE %2")
1535 QString(
"SLAVE_CONNECTED HOSTNAME %1").arg(commands[2]));
1537 else if (commands[1] ==
"FileTransfer")
1539 if (slist.size() < 3)
1541 LOG(VB_GENERAL, LOG_ERR,
"Received malformed FileTransfer command");
1542 errlist <<
"malformed_filetransfer_command";
1547 LOG(VB_GENERAL, LOG_INFO,
"MainServer::HandleAnnounce FileTransfer");
1548 LOG(VB_GENERAL, LOG_INFO,
1549 QString(
"adding: %1 as a remote file transfer") .arg(commands[2]));
1550 QStringList::const_iterator it = slist.begin();
1551 QUrl qurl = *(++it);
1552 QString wantgroup = *(++it);
1554 QStringList checkfiles;
1555 for (++it; it != slist.end(); ++it)
1559 bool writemode =
false;
1560 bool usereadahead =
true;
1561 int timeout_ms = 2000;
1562 if (commands.size() > 3)
1563 writemode = commands[3].toInt();
1565 if (commands.size() > 4)
1566 usereadahead = commands[4].toInt();
1568 if (commands.size() > 5)
1569 timeout_ms = commands[5].toInt();
1573 if (wantgroup.isEmpty())
1574 wantgroup =
"Default";
1580 LOG(VB_GENERAL, LOG_ERR,
"Unable to determine directory "
1581 "to write to in FileTransfer write command");
1582 errlist <<
"filetransfer_directory_not_found";
1587 QString basename = qurl.path();
1588 if (qurl.hasFragment())
1589 basename +=
"#" + qurl.fragment();
1591 if (basename.isEmpty())
1593 LOG(VB_GENERAL, LOG_ERR,
1594 QString(
"FileTransfer write filename is empty in url '%1'.")
1595 .arg(qurl.toString()));
1596 errlist <<
"filetransfer_filename_empty";
1601 if ((basename.contains(
"/../")) ||
1602 (basename.startsWith(
"../")))
1604 LOG(VB_GENERAL, LOG_ERR,
1605 QString(
"FileTransfer write filename '%1' does not pass "
1606 "sanity checks.") .arg(basename));
1607 errlist <<
"filetransfer_filename_dangerous";
1612 filename = dir +
"/" + basename;
1617 if (filename.isEmpty())
1619 LOG(VB_GENERAL, LOG_ERR,
"Empty filename, cowardly aborting!");
1620 errlist <<
"filetransfer_filename_empty";
1626 QFileInfo finfo(filename);
1629 LOG(VB_GENERAL, LOG_ERR,
1630 QString(
"FileTransfer filename '%1' is actually a directory, "
1631 "cannot transfer.") .arg(filename));
1632 errlist <<
"filetransfer_filename_is_a_directory";
1639 QString dirPath = finfo.absolutePath();
1643 if (!qdir.mkpath(dirPath))
1645 LOG(VB_GENERAL, LOG_ERR,
1646 QString(
"FileTransfer filename '%1' is in a "
1647 "subdirectory which does not exist, and can "
1648 "not be created.") .arg(filename));
1649 errlist <<
"filetransfer_unable_to_create_subdirectory";
1658 ft =
new FileTransfer(filename, socket, usereadahead, timeout_ms);
1673 if (checkfiles.size())
1675 QFileInfo fi(filename);
1676 QDir dir = fi.absoluteDir();
1677 for (it = checkfiles.begin(); it != checkfiles.end(); ++it)
1679 if (dir.exists(*it) &&
1680 QFileInfo(dir, *it).size() >= kReadTestSize)
1710 bool do_write =
false;
1725 LOG(VB_GENERAL, LOG_ERR,
1726 "SendResponse: Unable to write to client socket, as it's no "
1744 QMap<QString,ProgramInfo*> recMap;
1749 QMap<QString,bool> isJobRunning =
1755 if ((type ==
"Ascending") || (type ==
"Play"))
1757 else if ((type ==
"Descending") || (type ==
"Delete"))
1762 destination, (type ==
"Recording"),
1763 inUseMap, isJobRunning, recMap, sort);
1765 QMap<QString,ProgramInfo*>::iterator mit = recMap.begin();
1766 for (; mit != recMap.end(); mit = recMap.erase(mit))
1769 QStringList outputlist(QString::number(destination.
size()));
1770 QMap<QString, QString> backendIpMap;
1771 QMap<QString, QString> backendPortMap;
1776 for (it = destination.
begin(); it != destination.
end(); ++it)
1791 if (tmpURL.startsWith(
'/'))
1793 QFile checkFile(tmpURL);
1794 if (!tmpURL.isEmpty() && checkFile.exists())
1811 LOG(VB_GENERAL, LOG_ERR,
LOC +
1812 QString(
"HandleQueryRecordings() "
1813 "Couldn't find backend for:\n\t\t\t%1")
1826 LOG(VB_GENERAL, LOG_ERR,
1827 "MainServer::HandleQueryRecordings()"
1828 "\n\t\t\tCould not fill program info "
1873 if (slist.size() < 3)
1875 LOG(VB_GENERAL, LOG_ERR,
"Bad QUERY_RECORDING query");
1880 QString command = slist[1].toUpper();
1883 if (command ==
"BASENAME")
1887 else if (command ==
"TIMESLOT")
1889 if (slist.size() < 4)
1891 LOG(VB_GENERAL, LOG_ERR,
"Bad QUERY_RECORDING query");
1896 pginfo =
new ProgramInfo(slist[2].toUInt(), recstartts);
1899 QStringList strlist;
1920 QString playbackhost = slist[1];
1922 QStringList::const_iterator it = slist.begin() + 2;
1925 if (pginfo.HasPathname())
1932 pginfo.SetPathname(lpath);
1936 const QFileInfo info(lpath);
1937 pginfo.SetFilesize(info.size());
1940 QStringList strlist;
1942 pginfo.ToStringList(strlist);
1963 QString logInfo = QString(
"chanid %1 at %2")
1967 QString
name = QString(
"deleteThread%1%2").arg(getpid()).arg(
random());
1972 QString msg = QString(
"ERROR opening database connection for Delete "
1973 "Thread for chanid %1 recorded at %2. Program "
1974 "will NOT be deleted.")
1977 LOG(VB_GENERAL, LOG_ERR, msg);
1987 QString msg = QString(
"ERROR retrieving program info when trying to "
1988 "delete program for chanid %1 recorded at %2. "
1989 "Recording will NOT be deleted.")
1992 LOG(VB_GENERAL, LOG_ERR, msg);
2002 if ((!checkFile.exists()) && pginfo.
GetFilesize() &&
2005 LOG(VB_GENERAL, LOG_ERR,
2006 QString(
"ERROR when trying to delete file: %1. File "
2007 "doesn't exist. Database metadata will not be removed.")
2025 bool errmsg =
false;
2036 if ((fd < 0) && checkFile.exists())
2041 delete_file_immediately(ds->
m_filename, followLinks,
false);
2043 if (checkFile.exists())
2049 LOG(VB_GENERAL, LOG_ERR,
2050 QString(
"Error deleting file: %1. Keeping metadata in database.")
2061 QString nameFilter = fInfo.fileName() +
"*.png";
2065 nameFilter.replace(QRegExp(
"( |;)"),
"?");
2066 QDir dir ( fInfo.path(), nameFilter );
2068 for (
uint nIdx = 0; nIdx < dir.count(); nIdx++)
2070 QString sFileName = QString(
"%1/%2" )
2071 .arg( fInfo.path() )
2072 .arg( dir[ nIdx ] );
2074 delete_file_immediately( sFileName, followLinks,
true);
2083 if (slowDeletes && fd >= 0)
2089 QString logInfo = QString(
"chanid %1 at %2")
2094 query.
prepare(
"SELECT basename, hostname, storagegroup FROM recordedfile "
2095 "WHERE chanid = :CHANID AND starttime = :STARTTIME;");
2102 LOG(VB_GENERAL, LOG_ERR,
2103 QString(
"Error querying recordedfiles for %1.") .arg(logInfo));
2108 QString storagegroup;
2110 while (query.
next())
2112 basename = query.
value(0).toString();
2113 hostname = query.
value(1).toString();
2114 storagegroup = query.
value(2).toString();
2121 LOG(VB_FILE, LOG_INFO,
2122 QString(
"DeleteRecordedFiles(%1), deleting '%2'")
2123 .arg(logInfo).arg(query.
value(0).toString()));
2126 QString localFile = sgroup.
FindFile(basename);
2135 (!localFile.isEmpty())) &&
2138 (localFile.isEmpty())) &&
2147 update.
prepare(
"DELETE FROM recordedfile "
2148 "WHERE chanid = :CHANID "
2149 "AND starttime = :STARTTIME "
2150 "AND basename = :BASENAME ;");
2153 update.
bindValue(
":BASENAME", basename);
2157 LOG(VB_GENERAL, LOG_ERR,
2158 QString(
"Error querying recordedfile (%1) for %2.")
2159 .arg(query.
value(1).toString())
2168 QString logInfo = QString(
"chanid %1 at %2")
2172 query.
prepare(
"DELETE FROM recorded WHERE chanid = :CHANID AND "
2173 "title = :TITLE AND starttime = :STARTTIME;");
2181 LOG(VB_GENERAL, LOG_ERR,
2182 QString(
"Error deleting recorded entry for %1.") .arg(logInfo));
2188 QString msg = QString(
"RECORDING_LIST_CHANGE DELETE %1 %2")
2195 query.
prepare(
"DELETE FROM recordedmarkup "
2196 "WHERE chanid = :CHANID AND starttime = :STARTTIME;");
2203 LOG(VB_GENERAL, LOG_ERR,
2204 QString(
"Error deleting recordedmarkup for %1.") .arg(logInfo));
2207 query.
prepare(
"DELETE FROM recordedseek "
2208 "WHERE chanid = :CHANID AND starttime = :STARTTIME;");
2215 LOG(VB_GENERAL, LOG_ERR, QString(
"Error deleting recordedseek for %1.")
2230 bool deleteBrokenSymlinks)
2232 QFileInfo finfo(filename);
2233 int fd = -1, err = 0;
2234 QString linktext =
"";
2235 QByteArray fname = filename.toLocal8Bit();
2237 LOG(VB_FILE, LOG_INFO, QString(
"About to unlink/delete file: '%1'")
2238 .arg(fname.constData()));
2240 QString errmsg = QString(
"Delete Error '%1'").arg(fname.constData());
2241 if (finfo.isSymLink())
2244 QByteArray alink = linktext.toLocal8Bit();
2245 errmsg += QString(
" -> '%2'").arg(alink.constData());
2248 if (followLinks && finfo.isSymLink())
2250 if (!finfo.exists() && deleteBrokenSymlinks)
2251 err = unlink(fname.constData());
2256 err = unlink(fname.constData());
2259 else if (!finfo.isSymLink())
2265 err = unlink(fname.constData());
2271 LOG(VB_GENERAL, LOG_ERR, errmsg + ENO);
2287 QByteArray fname = filename.toLocal8Bit();
2288 QString msg = QString(
"Error deleting '%1'").arg(fname.constData());
2289 int fd =
open(fname.constData(), O_WRONLY);
2293 LOG(VB_GENERAL, LOG_ERR, msg +
" could not open " + ENO);
2297 if (unlink(fname.constData()))
2299 LOG(VB_GENERAL, LOG_ERR, msg +
" could not unlink " + ENO);
2316 const QString &filename, off_t fsize)
2329 query.
prepare(
"SELECT COUNT(cardid) FROM capturecard;");
2331 cards = query.
value(0).toInt();
2335 const size_t sleep_time = 500;
2336 const size_t min_tps = 8 * 1024 * 1024;
2337 const size_t calc_tps = (size_t) (cards * 1.2 * (22200000LL / 8));
2338 const size_t tps = max(min_tps, calc_tps);
2339 const size_t increment = (size_t) (tps * (sleep_time * 0.001f));
2341 LOG(VB_FILE, LOG_INFO,
2342 QString(
"Truncating '%1' by %2 MB every %3 milliseconds")
2344 .arg(increment / (1024.0 * 1024.0), 0,
'f', 2)
2347 GetMythDB()->GetDBManager()->PurgeIdleConnections(
false);
2353 LOG(VB_FILE, LOG_DEBUG, QString(
"Truncating '%1' to %2 MB")
2354 .arg(filename).arg(fsize / (1024.0 * 1024.0), 0,
'f', 2));
2357 int err = ftruncate(fd, fsize);
2360 LOG(VB_GENERAL, LOG_ERR, QString(
"Error truncating '%1'")
2361 .arg(filename) + ENO);
2364 return 0 ==
close(fd);
2369 if (pginfo && ((count % 100) == 0))
2374 usleep(sleep_time * 1000);
2377 bool ok = (0 ==
close(fd));
2382 LOG(VB_FILE, LOG_INFO, QString(
"Finished truncating '%1'").arg(filename));
2394 QStringList::const_iterator it = slist.begin() + 1;
2410 QMap<int, EncoderLink *>::Iterator iter =
encoderList->begin();
2416 result = iter.key();
2420 QStringList outputlist( QString::number(result) );
2429 QStringList::const_iterator it = slist.begin() + 1;
2431 if (recinfo.GetChanID())
2460 (*encoderList)[num]->StopRecording();
2466 QStringList outputlist(
"0" );
2487 QMap<int, EncoderLink *>::Iterator iter =
encoderList->begin();
2494 recnum = iter.key();
2514 QStringList outputlist( QString::number(recnum) );
2521 bool forceMetadataDelete,
2527 if (!recinfo.GetChanID())
2533 QStringList outputlist( QString::number(0) );
2543 bool forceMetadataDelete)
2545 QStringList::const_iterator it = slist.begin() + 1;
2547 if (recinfo.GetChanID())
2553 bool forceMetadataDelete,
bool expirer,
bool forgetHistory)
2555 int resultCode = -1;
2560 bool justexpire = expirer ?
false :
2566 if (filename.isEmpty())
2568 LOG(VB_GENERAL, LOG_ERR,
2569 QString(
"ERROR when trying to delete file for %1. Unable "
2570 "to determine filename of recording.")
2576 QStringList outputlist(QString::number(resultCode));
2586 if (justexpire && !forceMetadataDelete &&
2595 QStringList outputlist( QString::number(0) );
2619 QStringList outputlist( QString::number(num) );
2628 QFile checkFile(filename);
2629 bool fileExists = checkFile.exists();
2632 QFile checkFileUTF8(QString::fromUtf8(filename.toLatin1().constData()));
2633 fileExists = checkFileUTF8.exists();
2635 filename = QString::fromUtf8(filename.toLatin1().constData());
2642 if (fileExists || !recinfo.
GetFilesize() || forceMetadataDelete)
2649 forceMetadataDelete);
2650 deleteThread->
start();
2654 QString logInfo = QString(
"chanid %1")
2657 LOG(VB_GENERAL, LOG_ERR,
2658 QString(
"ERROR when trying to delete file: %1. File doesn't "
2659 "exist. Database metadata will not be removed.")
2666 QStringList outputlist( QString::number(resultCode) );
2678 if (fileExists || !recinfo.
GetFilesize() || forceMetadataDelete)
2681 QString(
"REC_DELETED CHANID %1 STARTTIME %2")
2691 if (slist.size() == 3)
2698 else if (slist.size() >= (1 + NUMPROGRAMLINES))
2700 QStringList::const_iterator it = slist.begin()+1;
2702 if (recinfo.GetChanID())
2730 QStringList outputlist( QString::number(ret) );
2741 result = QStringList( QString::number(1) );
2744 result = QStringList( QString::number(0) );
2756 QStringList::const_iterator it = slist.begin() + 1;
2758 if (recinfo.GetChanID())
2766 QStringList outputlist( QString::number(0) );
2778 QStringList strlist;
2781 if (!sleepCmd.isEmpty())
2785 LOG(VB_GENERAL, LOG_NOTICE,
2786 "Received GO_TO_SLEEP command from master, running SleepCommand.");
2791 strlist <<
"ERROR: SleepCommand is empty";
2792 LOG(VB_GENERAL, LOG_ERR,
2793 "ERROR: in HandleGoToSleep(), but no SleepCommand found!");
2809 QStringList strlist;
2841 QStringList strlist;
2860 QStringList shortlist;
2861 if (strlist.size() < 4)
2863 shortlist << QString(
"0");
2864 shortlist << QString(
"0");
2868 unsigned int index = (
uint)(strlist.size()) - 2;
2869 shortlist << strlist[index++];
2870 shortlist << strlist[index++];
2886 QStringList strlist;
2889 if (getloadavg(loads,3) == -1)
2892 strlist <<
"getloadavg() failed";
2895 strlist << QString::number(loads[0])
2896 << QString::number(loads[1])
2897 << QString::number(loads[2]);
2910 QStringList strlist;
2914 strlist << QString::number(uptime);
2918 strlist <<
"Could not determine uptime.";
2932 QStringList strlist;
2947 QStringList strlist;
2948 int totalMB, freeMB, totalVM, freeVM;
2950 if (
getMemStats(totalMB, freeMB, totalVM, freeVM))
2951 strlist << QString::number(totalMB) << QString::number(freeMB)
2952 << QString::number(totalVM) << QString::number(freeVM);
2956 strlist <<
"Could not determine memory stats.";
2970 QStringList strlist;
2985 bool checkSlaves = slist[1].toInt();
2987 QStringList::const_iterator it = slist.begin() + 2;
2992 if (recinfo.HasPathname() && (
ismaster) &&
3003 QStringList outputlist( QString::number(exists) );
3005 outputlist << recinfo.GetPathname();
3015 if (recinfo.HasPathname())
3018 exists = QFileInfo(pburl).exists();
3023 QStringList strlist( QString::number(exists) );
3035 QString storageGroup =
"Default";
3037 QString filename =
"";
3040 switch (slist.size()) {
3042 if (!slist[3].isEmpty())
3043 hostname = slist[3];
3045 if (slist[2].isEmpty())
3046 storageGroup = slist[2];
3048 filename = slist[1];
3049 if (filename.isEmpty() ||
3050 filename.contains(
"/../") ||
3051 filename.startsWith(
"../"))
3053 LOG(VB_GENERAL, LOG_ERR,
3054 QString(
"ERROR checking for file, filename '%1' "
3055 "fails sanity checks").arg(filename));
3062 LOG(VB_GENERAL, LOG_ERR,
"ERROR, invalid input count for QUERY_FILE_HASH");
3073 QString fullname = sgroup.
FindFile(filename);
3081 hash = slave->
GetFileHash(filename, storageGroup);
3087 query.
prepare(
"SELECT hostname FROM settings "
3088 "WHERE value='BackendServerIP' "
3089 "OR value='BackendServerIP6' "
3090 "AND data=:HOSTNAME;");
3095 hostname = query.
value(0).toString();
3099 hash = slave->
GetFileHash(filename, storageGroup);
3116 QString filename = slist[1];
3117 QString storageGroup =
"Default";
3118 QStringList retlist;
3120 if (slist.size() > 2)
3121 storageGroup = slist[2];
3123 if ((filename.isEmpty()) ||
3124 (filename.contains(
"/../")) ||
3125 (filename.startsWith(
"../")))
3127 LOG(VB_GENERAL, LOG_ERR,
3128 QString(
"ERROR checking for file, filename '%1' "
3129 "fails sanity checks").arg(filename));
3135 if (storageGroup.isEmpty())
3136 storageGroup =
"Default";
3140 QString fullname = sgroup.
FindFile(filename);
3142 if (!fullname.isEmpty())
3145 retlist << fullname;
3147 struct stat fileinfo;
3148 if (stat(fullname.toLocal8Bit().constData(), &fileinfo) >= 0)
3150 retlist << QString::number(fileinfo.st_dev);
3151 retlist << QString::number(fileinfo.st_ino);
3152 retlist << QString::number(fileinfo.st_mode);
3153 retlist << QString::number(fileinfo.st_nlink);
3154 retlist << QString::number(fileinfo.st_uid);
3155 retlist << QString::number(fileinfo.st_gid);
3156 retlist << QString::number(fileinfo.st_rdev);
3157 retlist << QString::number(fileinfo.st_size);
3162 retlist << QString::number(fileinfo.st_blksize);
3163 retlist << QString::number(fileinfo.st_blocks);
3165 retlist << QString::number(fileinfo.st_atime);
3166 retlist << QString::number(fileinfo.st_mtime);
3167 retlist << QString::number(fileinfo.st_ctime);
3179 query.
prepare(
"SELECT MAX(endtime) FROM program WHERE manualid = 0;");
3189 QDateTime GuideDataThrough;
3191 QStringList strlist;
3195 if (GuideDataThrough.isNull())
3196 strlist << QString(
"0000-00-00 00:00");
3198 strlist << QDateTime(GuideDataThrough).toString(
"yyyy-MM-dd hh:mm");
3204 QString tmptable,
int recordid)
3208 QStringList strList;
3212 if (tmptable.isEmpty())
3225 query.
prepare(
"SELECT NULL FROM record "
3226 "WHERE recordid = :RECID;");
3233 if (record->
Load() &&
3239 query.
prepare(
"DELETE FROM program WHERE manualid = :RECID;");
3249 strList << QString::number(0);
3250 strList << QString::number(0);
3260 QStringList strList;
3265 strList << QString::number(0);
3275 QStringList::const_iterator it = slist.begin() + 1;
3278 QStringList strlist;
3280 if (
m_sched && recinfo.GetChanID())
3283 strlist << QString::number(0);
3292 QStringList strList;
3297 strList << QString::number(0);
3306 QStringList strList;
3308 if ((sList.size() < 4) || (sList.size() > 5))
3310 LOG(VB_GENERAL, LOG_ERR,
3311 QString(
"HandleSGGetFileList: Invalid Request. %1")
3312 .arg(sList.join(
"[]:[]")));
3313 strList <<
"EMPTY LIST";
3319 QString wantHost = sList.at(1);
3320 QString groupname = sList.at(2);
3321 QString path = sList.at(3);
3322 bool fileNamesOnly =
false;
3324 if (sList.size() >= 5)
3325 fileNamesOnly = sList.at(4).toInt();
3327 bool slaveUnreachable =
false;
3329 LOG(VB_FILE, LOG_INFO, QString(
"HandleSGGetFileList: group = %1 host = %2 "
3330 " path = %3 wanthost = %4")
3331 .arg(groupname).arg(host).arg(path).arg(wantHost));
3333 if ((host.toLower() == wantHost.toLower()) ||
3338 LOG(VB_FILE, LOG_INFO,
"HandleSGGetFileList: Getting local info");
3349 LOG(VB_FILE, LOG_INFO,
"HandleSGGetFileList: Getting remote info");
3353 slaveUnreachable =
false;
3357 LOG(VB_FILE, LOG_INFO,
3358 QString(
"HandleSGGetFileList: Failed to grab slave socket "
3359 ": %1 :").arg(wantHost));
3360 slaveUnreachable =
true;
3365 if (slaveUnreachable)
3366 strList <<
"SLAVE UNREACHABLE: " << host;
3368 if (strList.isEmpty() || (strList.at(0) ==
"0"))
3369 strList <<
"EMPTY LIST";
3378 QStringList strList;
3380 if (sList.size() != 4)
3382 LOG(VB_GENERAL, LOG_ERR,
3383 QString(
"HandleSGFileQuery: Invalid Request. %1")
3384 .arg(sList.join(
"[]:[]")));
3385 strList <<
"EMPTY LIST";
3390 QString wantHost = sList.at(1);
3391 QString groupname = sList.at(2);
3392 QString filename = sList.at(3);
3394 bool slaveUnreachable =
false;
3396 LOG(VB_FILE, LOG_INFO, QString(
"HandleSGFileQuery: %1")
3403 LOG(VB_FILE, LOG_INFO,
"HandleSGFileQuery: Getting local info");
3412 LOG(VB_FILE, LOG_INFO,
"HandleSGFileQuery: Getting remote info");
3415 slaveUnreachable =
false;
3419 LOG(VB_FILE, LOG_INFO,
3420 QString(
"HandleSGFileQuery: Failed to grab slave socket : %1 :")
3422 slaveUnreachable =
true;
3427 if (slaveUnreachable)
3428 strList <<
"SLAVE UNREACHABLE: " << wantHost;
3430 if (strList.count() == 0 || (strList.at(0) ==
"0"))
3431 strList <<
"EMPTY LIST";
3441 QStringList strlist;
3447 QMap<int, EncoderLink *>::Iterator iter =
encoderList->begin();
3453 if ((cardid != -1) && (cardid != elink->
GetCardID()))
3461 if ((enchost == pbshost) &&
3477 QString msg = QString(
"Cardid %1 LOCKed for external use on %2.")
3478 .arg(retval).arg(pbshost);
3479 LOG(VB_GENERAL, LOG_INFO, msg);
3482 query.
prepare(
"SELECT videodevice, audiodevice, "
3485 "WHERE cardid = :CARDID ;");
3491 strlist << QString::number(retval)
3492 << query.
value(0).toString()
3493 << query.
value(1).toString()
3494 << query.
value(2).toString();
3503 LOG(VB_GENERAL, LOG_ERR,
3504 "MainServer::LockTuner(): Could not find "
3505 "card info in database");
3510 strlist <<
"-2" <<
"" <<
"" <<
"";
3516 strlist <<
"-1" <<
"" <<
"" <<
"";
3523 QStringList strlist;
3526 QMap<int, EncoderLink *>::Iterator iter =
encoderList->find(cardid);
3529 LOG(VB_GENERAL, LOG_ERR,
"MainServer::HandleFreeTuner() " +
3530 QString(
"Unknown encoder: %1").arg(cardid));
3531 strlist <<
"FAILED";
3538 QString msg = QString(
"Cardid %1 FREED from external use on %2.")
3540 LOG(VB_GENERAL, LOG_INFO, msg);
3556 vector<uint> excluded_cardids;
3557 QStringList strlist;
3564 QMap<int, EncoderLink *>::Iterator iter =
encoderList->begin();
3574 LOG(VB_RECORD, LOG_INFO,
3575 QString(
"Checking card %1. Best card so far %2")
3576 .arg(iter.key()).arg(retval));
3581 vector<InputInfo> inputs = elink->
GetFreeInputs(excluded_cardids);
3583 for (
uint i = 0; i < inputs.size(); ++i)
3585 if (!encoder || inputs[i].livetvorder < bestorder)
3587 retval = iter.key();
3589 bestorder = inputs[i].livetvorder;
3594 LOG(VB_RECORD, LOG_INFO,
3595 QString(
"Best card is %1").arg(retval));
3597 strlist << QString::number(retval);
3615 strlist <<
"nohost";
3626 vector<uint> excluded_cardids;
3627 QStringList strlist;
3630 QMap<int, EncoderLink *>::Iterator iter =
encoderList->begin();
3642 strlist << QString::number(count);
3656 vector<uint> excluded_cardids;
3657 vector<InputInfo> allinputs;
3659 QMap<int, EncoderLink *>::Iterator iter =
encoderList->begin();
3667 vector<InputInfo> inputs = elink->
GetFreeInputs(excluded_cardids);
3668 allinputs.insert(allinputs.end(), inputs.begin(), inputs.end());
3673 QStringList strlist;
3674 QMap<int, bool> cardidused;
3675 for (
uint i = 0; i < allinputs.size(); ++i)
3677 uint cardid = allinputs[i].cardid;
3678 if (!cardidused[cardid])
3680 strlist << QString::number(cardid);
3681 cardidused[cardid] =
true;
3685 if (strlist.size() == 0)
3697 QStringList strlist;
3699 int currrec = slist[1].toInt();
3704 LOG(VB_RECORD, LOG_INFO, QString(
"Getting next free recorder after : %1")
3708 QMap<int, EncoderLink *>::Iterator iter, curr =
encoderList->find(currrec);
3712 vector<uint> excluded_cardids;
3713 excluded_cardids.push_back(currrec);
3733 retval = iter.key();
3748 strlist << QString::number(retval);
3766 strlist <<
"nohost";
3792 if (commands.size() < 2 || slist.size() < 2)
3795 int recnum = commands[1].toInt();
3797 QMap<int, EncoderLink *>::Iterator iter =
encoderList->find(recnum);
3800 LOG(VB_GENERAL, LOG_ERR,
"MainServer::HandleRecorderQuery() " +
3801 QString(
"Unknown encoder: %1").arg(recnum));
3802 QStringList retlist(
"bad" );
3807 QString command = slist[1];
3809 QStringList retlist;
3814 LOG(VB_GENERAL, LOG_ERR,
" MainServer::HandleRecorderQuery() " +
3815 QString(
"Command %1 for unconnected encoder %2")
3816 .arg(command).arg(recnum));
3822 if (command ==
"IS_RECORDING")
3826 else if (command ==
"GET_FRAMERATE")
3830 else if (command ==
"GET_FRAMES_WRITTEN")
3834 else if (command ==
"GET_FILE_POSITION")
3838 else if (command ==
"GET_MAX_BITRATE")
3842 else if (command ==
"GET_CURRENT_RECORDING")
3856 else if (command ==
"GET_KEYFRAME_POS")
3858 long long desired = slist[2].toLongLong();
3861 else if (command ==
"FILL_POSITION_MAP")
3863 int64_t start = slist[2].toLongLong();
3864 int64_t end = slist[3].toLongLong();
3873 frm_pos_map_t::const_iterator it = map.begin();
3874 for (; it != map.end(); ++it)
3876 retlist += QString::number(it.key());
3877 retlist += QString::number(*it);
3879 if (retlist.empty())
3883 else if (command ==
"FILL_DURATION_MAP")
3885 int64_t start = slist[2].toLongLong();
3886 int64_t end = slist[3].toLongLong();
3895 frm_pos_map_t::const_iterator it = map.begin();
3896 for (; it != map.end(); ++it)
3898 retlist += QString::number(it.key());
3899 retlist += QString::number(*it);
3901 if (retlist.empty())
3905 else if (command ==
"GET_RECORDING")
3919 else if (command ==
"FRONTEND_READY")
3924 else if (command ==
"CANCEL_NEXT_RECORDING")
3926 QString cancel = slist[2];
3927 LOG(VB_GENERAL, LOG_NOTICE,
3928 QString(
"Received: CANCEL_NEXT_RECORDING %1").arg(cancel));
3932 else if (command ==
"SPAWN_LIVETV")
3934 QString chainid = slist[2];
3945 enc->
SpawnLiveTV(chain, slist[3].toInt(), slist[4]);
3948 else if (command ==
"STOP_LIVETV")
3965 else if (command ==
"PAUSE")
3970 else if (command ==
"FINISH_RECORDING")
3975 else if (command ==
"SET_LIVE_RECORDING")
3977 int recording = slist[2].toInt();
3981 else if (command ==
"GET_FREE_INPUTS")
3983 vector<uint> excluded_cardids;
3984 for (
int i = 2; i < slist.size(); i++)
3985 excluded_cardids.push_back(slist[i].toUInt());
3987 vector<InputInfo> inputs = enc->
GetFreeInputs(excluded_cardids);
3990 retlist <<
"EMPTY_LIST";
3993 for (
uint i = 0; i < inputs.size(); i++)
3994 inputs[i].ToStringList(retlist);
3997 else if (command ==
"GET_INPUT")
4000 ret = (ret.isEmpty()) ?
"UNKNOWN" : ret;
4003 else if (command ==
"SET_INPUT")
4005 QString input = slist[2];
4006 QString ret = enc->
SetInput(input);
4007 ret = (ret.isEmpty()) ?
"UNKNOWN" : ret;
4010 else if (command ==
"TOGGLE_CHANNEL_FAVORITE")
4012 QString changroup = slist[2];
4016 else if (command ==
"CHANGE_CHANNEL")
4023 else if (command ==
"SET_CHANNEL")
4025 QString
name = slist[2];
4029 else if (command ==
"SET_SIGNAL_MONITORING_RATE")
4031 int rate = slist[2].toInt();
4032 int notifyFrontend = slist[3].toInt();
4034 retlist << QString::number(oldrate);
4036 else if (command ==
"GET_COLOUR")
4039 retlist << QString::number(ret);
4041 else if (command ==
"GET_CONTRAST")
4044 retlist << QString::number(ret);
4046 else if (command ==
"GET_BRIGHTNESS")
4049 retlist << QString::number(ret);
4051 else if (command ==
"GET_HUE")
4054 retlist << QString::number(ret);
4056 else if (command ==
"CHANGE_COLOUR")
4058 int type = slist[2].toInt();
4059 bool up = slist[3].toInt();
4062 retlist << QString::number(ret);
4064 else if (command ==
"CHANGE_CONTRAST")
4066 int type = slist[2].toInt();
4067 bool up = slist[3].toInt();
4070 retlist << QString::number(ret);
4072 else if (command ==
"CHANGE_BRIGHTNESS")
4074 int type= slist[2].toInt();
4075 bool up = slist[3].toInt();
4078 retlist << QString::number(ret);
4080 else if (command ==
"CHANGE_HUE")
4082 int type= slist[2].toInt();
4083 bool up = slist[3].toInt();
4086 retlist << QString::number(ret);
4088 else if (command ==
"CHECK_CHANNEL")
4090 QString
name = slist[2];
4091 retlist << QString::number((
int)(enc->
CheckChannel(name)));
4093 else if (command ==
"SHOULD_SWITCH_CARD")
4095 QString chanid = slist[2];
4098 else if (command ==
"CHECK_CHANNEL_PREFIX")
4100 QString needed_spacer;
4101 QString
prefix = slist[2];
4102 uint is_complete_valid_channel_on_rec = 0;
4103 bool is_extra_char_useful =
false;
4106 prefix, is_complete_valid_channel_on_rec,
4107 is_extra_char_useful, needed_spacer);
4109 retlist << QString::number((
int)match);
4110 retlist << QString::number(is_complete_valid_channel_on_rec);
4111 retlist << QString::number((
int)is_extra_char_useful);
4112 retlist << ((needed_spacer.isEmpty()) ? QString(
"X") : needed_spacer);
4114 else if (command ==
"GET_NEXT_PROGRAM_INFO" && (slist.size() >= 6))
4116 QString channelname = slist[2];
4117 uint chanid = slist[3].toUInt();
4119 QString starttime = slist[5];
4121 QString title =
"", subtitle =
"", desc =
"", category =
"";
4122 QString endtime =
"", callsign =
"", iconpath =
"";
4123 QString seriesid =
"", programid =
"";
4126 title, subtitle, desc, category, starttime,
4127 endtime, callsign, iconpath, channelname, chanid,
4128 seriesid, programid);
4139 retlist << QString::number(chanid);
4143 else if (command ==
"GET_CHANNEL_INFO")
4145 uint chanid = slist[2].toUInt();
4147 QString callsign =
"", channum =
"", channame =
"", xmltv =
"";
4150 callsign, channum, channame, xmltv);
4152 retlist << QString::number(chanid);
4153 retlist << QString::number(sourceid);
4161 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown command: %1").arg(command));
4173 int recnum = commands[1].toInt();
4175 QMap<int, EncoderLink *>::Iterator iter =
encoderList->find(recnum);
4178 LOG(VB_GENERAL, LOG_ERR,
"MainServer::HandleSetNextLiveTVDir() " +
4179 QString(
"Unknown encoder: %1").arg(recnum));
4180 QStringList retlist(
"bad" );
4188 QStringList retlist(
"OK" );
4196 uint chanid = slist[1].toUInt();
4197 uint sourceid = slist[2].toUInt();
4198 QString oldcnum =
cleanup(slist[3]);
4199 QString callsign =
cleanup(slist[4]);
4200 QString channum =
cleanup(slist[5]);
4201 QString channame =
cleanup(slist[6]);
4202 QString xmltv =
cleanup(slist[7]);
4204 QStringList retlist;
4205 if (!chanid || !sourceid)
4212 QMap<int, EncoderLink *>::iterator it =
encoderList->begin();
4217 ok &= (*it)->SetChannelInfo(chanid, sourceid, oldcnum,
4218 callsign, channum, channame, xmltv);
4222 retlist << ((ok) ?
"1" :
"0");
4231 int recnum = commands[1].toInt();
4232 QStringList retlist;
4234 QMap<int, EncoderLink *>::Iterator iter =
encoderList->find(recnum);
4237 LOG(VB_GENERAL, LOG_ERR,
"MainServer: " +
4238 QString(
"HandleRemoteEncoder(cmd %1) ").arg(slist[1]) +
4239 QString(
"Unknown encoder: %1").arg(recnum));
4247 QString command = slist[1];
4249 if (command ==
"GET_STATE")
4251 retlist << QString::number((
int)enc->
GetState());
4253 else if (command ==
"GET_SLEEPSTATUS")
4257 else if (command ==
"GET_FLAGS")
4259 retlist << QString::number(enc->
GetFlags());
4261 else if (command ==
"IS_BUSY")
4263 int time_buffer = (slist.size() >= 3) ? slist[2].toInt() : 5;
4265 retlist << QString::number((
int)enc->
IsBusy(&busy_input, time_buffer));
4268 else if (command ==
"MATCHES_RECORDING" &&
4269 slist.size() >= (2 + NUMPROGRAMLINES))
4271 QStringList::const_iterator it = slist.begin() + 2;
4276 else if (command ==
"START_RECORDING" &&
4277 slist.size() >= (2 + NUMPROGRAMLINES))
4279 QStringList::const_iterator it = slist.begin() + 2;
4284 else if (command ==
"GET_RECORDING_STATUS")
4288 else if (command ==
"RECORD_PENDING" &&
4289 (slist.size() >= 4 + NUMPROGRAMLINES))
4291 int secsleft = slist[2].toInt();
4292 int haslater = slist[3].toInt();
4293 QStringList::const_iterator it = slist.begin() + 4;
4300 else if (command ==
"CANCEL_NEXT_RECORDING" &&
4301 (slist.size() >= 3))
4303 bool cancel = (
bool) slist[2].toInt();
4307 else if (command ==
"STOP_RECORDING")
4312 else if (command ==
"GET_MAX_BITRATE")
4316 else if (command ==
"GET_CURRENT_RECORDING")
4330 else if (command ==
"GET_FREE_INPUTS")
4332 vector<uint> excluded_cardids;
4333 for (
int i = 2; i < slist.size(); i++)
4334 excluded_cardids.push_back(slist[i].toUInt());
4336 vector<InputInfo> inputs = enc->
GetFreeInputs(excluded_cardids);
4339 retlist <<
"EMPTY_LIST";
4342 for (
uint i = 0; i < inputs.size(); i++)
4343 inputs[i].ToStringList(retlist);
4357 vector<PlaybackSock*>::iterator it;
4360 if ((*it)->isMediaServer())
4362 hostname = (*it)->getHostname();
4363 if (!hosts.contains(hostname))
4371 QStringList retlist;
4373 retlist.push_front(QString::number(retlist.size()));
4380 QStringList retlist;
4381 QString queryhostname = slist[1];
4402 QString fskey = fsInfo->getHostname() +
":" + fsInfo->getPath();
4412 size_t totalKBperMin = 0;
4414 QMap<int, EncoderLink*>::iterator it =
encoderList->begin();
4424 maxBitrate = 19500000LL;
4425 long long thisKBperMin = (((size_t)maxBitrate)*((size_t)15))>>11;
4426 totalKBperMin += thisKBperMin;
4427 LOG(VB_FILE, LOG_INFO, QString(
"Cardid %1: max bitrate %2 KB/min")
4428 .arg(enc->
GetCardID()).arg(thisKBperMin));
4431 LOG(VB_FILE, LOG_INFO,
4432 QString(
"Maximal bitrate of busy encoders is %1 KB/min")
4433 .arg(totalKBperMin));
4435 return totalKBperMin;
4442 int64_t totalKB = -1, usedKB = -1;
4443 QMap <QString, bool>foundDirs;
4445 QString localStr =
"1";
4448 groups.removeAll(
"LiveTV");
4449 QString specialGroups = groups.join(
"', '");
4450 QString sql = QString(
"SELECT MIN(id),dirname "
4451 "FROM storagegroup "
4452 "WHERE hostname = :HOSTNAME "
4453 "AND groupname NOT IN ( '%1' ) "
4454 "GROUP BY dirname;").arg(specialGroups);
4465 query.
prepare(
"SELECT MIN(id),dirname "
4466 "FROM storagegroup "
4467 "WHERE groupname = :GROUP "
4468 "GROUP BY dirname;");
4478 while (query.
next())
4480 dirID = query.
value(0).toString();
4484 currentDir = QString::fromUtf8(query.
value(1)
4485 .toByteArray().constData());
4486 if (currentDir.endsWith(
"/"))
4487 currentDir.remove(currentDir.length() - 1, 1);
4489 checkDir.setPath(currentDir);
4490 if (!foundDirs.contains(currentDir))
4492 if (checkDir.exists())
4494 QByteArray cdir = currentDir.toLatin1();
4496 memset(&statbuf, 0,
sizeof(statbuf));
4500 if (!
statfs(currentDir.toLocal8Bit().constData(), &statbuf))
4503 char *fstypename = statbuf.f_fstypename;
4504 if ((!strcmp(fstypename,
"nfs")) ||
4505 (!strcmp(fstypename,
"afpfs")) ||
4506 (!strcmp(fstypename,
"smbfs")))
4509 long fstype = statbuf.f_type;
4510 if ((fstype == 0x6969) ||
4511 (fstype == 0x517B) ||
4512 (fstype == (
long)0xFF534D42))
4519 strlist << currentDir;
4520 strlist << localStr;
4523 strlist << QString::number(bSize);
4524 strlist << QString::number(totalKB);
4525 strlist << QString::number(usedKB);
4527 foundDirs[currentDir] =
true;
4530 foundDirs[currentDir] =
false;
4537 QMap <QString, bool> backendsCounted;
4540 list<PlaybackSock *> localPlaybackList;
4544 vector<PlaybackSock *>::iterator pbsit =
playbackList.begin();
4557 localPlaybackList.push_back(pbs);
4563 for (list<PlaybackSock *>::iterator
p = localPlaybackList.begin() ;
4564 p != localPlaybackList.end() ; ++
p) {
4565 (*p)->GetDiskSpace(strlist);
4574 QList<FileSystemInfo> fsInfos;
4576 QStringList::const_iterator it = strlist.begin();
4577 while (it != strlist.end())
4581 fsInfo.
setLocal((*(it++)).toInt() > 0);
4588 fsInfos.push_back(fsInfo);
4594 maxWriteFiveSec = max((int64_t)2048, maxWriteFiveSec);
4595 QList<FileSystemInfo>::iterator it1, it2;
4597 for (it1 = fsInfos.begin(); it1 != fsInfos.end(); ++it1)
4599 if (it1->getFSysID() == -1)
4603 it1->getHostname().section(
".", 0, 0) +
":" + it1->getPath());
4606 for (it2 = it1 + 1; it2 != fsInfos.end(); ++it2)
4610 bSize = max(32, max(it1->getBlockSize(), it2->getBlockSize()) / 1024);
4611 int64_t diffSize = it1->getTotalSpace() - it2->getTotalSpace();
4612 int64_t diffUsed = it1->getUsedSpace() - it2->getUsedSpace();
4614 diffSize = 0 - diffSize;
4616 diffUsed = 0 - diffUsed;
4618 if (it2->getFSysID() == -1 && (diffSize <= bSize) &&
4619 (diffUsed <= maxWriteFiveSec))
4621 if (!it1->getHostname().contains(it2->getHostname()))
4622 it1->setHostname(it1->getHostname() +
"," + it2->getHostname());
4623 it1->setPath(it1->getPath() +
"," +
4624 it2->getHostname().section(
".", 0, 0) +
":" + it2->getPath());
4634 for (it1 = fsInfos.begin(); it1 != fsInfos.end(); ++it1)
4636 strlist << it1->getHostname();
4637 strlist << it1->getPath();
4638 strlist << QString::number(it1->isLocal());
4639 strlist << QString::number(it1->getFSysID());
4640 strlist << QString::number(it1->getGroupID());
4641 strlist << QString::number(it1->getBlockSize());
4642 strlist << QString::number(it1->getTotalSpace());
4643 strlist << QString::number(it1->getUsedSpace());
4645 totalKB += it1->getTotalSpace();
4646 usedKB += it1->getUsedSpace();
4651 strlist << allHostList;
4652 strlist <<
"TotalDiskSpace";
4657 strlist << QString::number(totalKB);
4658 strlist << QString::number(usedKB);
4664 QStringList strlist;
4671 QStringList::const_iterator it = strlist.begin();
4672 while (it != strlist.end())
4676 fsInfo.
setLocal((*(it++)).toInt() > 0);
4684 fsInfos.push_back(fsInfo);
4687 LOG(VB_SCHEDULE | VB_FILE, LOG_DEBUG,
"Determining unique filesystems");
4690 maxWriteFiveSec = max((
size_t)2048, maxWriteFiveSec);
4694 QList<FileSystemInfo>::iterator it1;
4695 if (VERBOSE_LEVEL_CHECK(VB_FILE | VB_SCHEDULE, LOG_INFO))
4697 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
4698 "--- GetFilesystemInfos directory list start ---");
4699 for (it1 = fsInfos.begin(); it1 != fsInfos.end(); ++it1)
4701 QString msg = QString(
"Dir: %1:%2")
4702 .arg(it1->getHostname()).arg(it1->getPath());
4703 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO, msg) ;
4704 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO, QString(
" Location: %1")
4705 .arg(it1->isLocal() ?
"Local" :
"Remote"));
4706 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO, QString(
" fsID : %1")
4707 .arg(it1->getFSysID()));
4708 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO, QString(
" dirID : %1")
4709 .arg(it1->getGroupID()));
4710 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO, QString(
" BlkSize : %1")
4711 .arg(it1->getBlockSize()));
4712 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO, QString(
" TotalKB : %1")
4713 .arg(it1->getTotalSpace()));
4714 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO, QString(
" UsedKB : %1")
4715 .arg(it1->getUsedSpace()));
4716 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO, QString(
" FreeKB : %1")
4717 .arg(it1->getFreeSpace()));
4719 LOG(VB_FILE | VB_SCHEDULE, LOG_INFO,
4720 "--- GetFilesystemInfos directory list end ---");
4752 QStringList retlist;
4754 if ((filename.isEmpty()) ||
4755 (filename.contains(
"/../")) ||
4756 (filename.startsWith(
"../")))
4758 LOG(VB_GENERAL, LOG_ERR, QString(
"ERROR deleting file, filename '%1' "
4759 "fails sanity checks").arg(filename));
4768 QString fullfile = sgroup.
FindFile(filename);
4770 if (fullfile.isEmpty()) {
4771 LOG(VB_GENERAL, LOG_ERR,
4772 QString(
"Unable to find %1 in HandleDeleteFile()") .arg(filename));
4781 QFile checkFile(fullfile);
4789 const QFileInfo info(fullfile);
4793 if ((fd < 0) && checkFile.exists())
4795 LOG(VB_GENERAL, LOG_ERR, QString(
"Error deleting file: %1.")
4817 truncateThread->
run();
4825 const QString &starttime,
4833 frm_dir_map_t::const_iterator it;
4835 QStringList retlist;
4838 const ProgramInfo pginfo(chanid.toUInt(), recstartdt);
4840 if (pginfo.GetChanID())
4845 pginfo.QueryCutList(markMap);
4847 for (it = markMap.begin(); it != markMap.end(); ++it)
4850 QString intstr = QString(
"%1").arg(*it);
4852 retlist << QString::number(it.key());
4857 retlist.prepend(QString(
"%1").arg(rowcnt));
4868 const QString &starttime,
4883 const QString &starttime,
4899 const QString &starttime,
4915 chanid.toUInt(), recstartts);
4917 QStringList retlist;
4918 retlist << QString::number(bookmark);
4941 QString chanid = tokens[1];
4942 QString starttime = tokens[2];
4943 long long bookmark = tokens[3].toLongLong();
4946 QStringList retlist;
4950 if (pginfo.GetChanID())
4956 retlist <<
"FAILED";
4973 QString hostname = tokens[1];
4974 QString setting = tokens[2];
4975 QStringList retlist;
4979 retlist << retvalue;
4989 bool synchronous = (command[0] ==
"DOWNLOAD_FILE_NOW");
4990 QString srcURL = command[1];
4991 QString storageGroup = command[2];
4992 QString filename = command[3];
4996 QStringList retlist;
5002 if (filename.isEmpty())
5004 QFileInfo finfo(srcURL);
5005 filename = finfo.fileName();
5008 if (outDir.isEmpty())
5010 LOG(VB_GENERAL, LOG_ERR,
5011 QString(
"Unable to determine directory "
5012 "to write to in %1 write command").arg(command[0]));
5013 retlist <<
"downloadfile_directory_not_found";
5019 if ((filename.contains(
"/../")) ||
5020 (filename.startsWith(
"../")))
5022 LOG(VB_GENERAL, LOG_ERR,
5023 QString(
"ERROR: %1 write filename '%2' does not pass "
5024 "sanity checks.") .arg(command[0]).arg(filename));
5025 retlist <<
"downloadfile_filename_dangerous";
5031 outFile = outDir +
"/" + filename;
5068 QString hostname = tokens[1];
5069 QString setting = tokens[2];
5070 QString svalue = tokens[3];
5071 QStringList retlist;
5088 QStringList retlist;
5105 QStringList &commands,
5110 int recnum = commands[1].toInt();
5111 QString command = slist[1];
5113 QStringList retlist;
5119 if (command ==
"DONE")
5127 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown file transfer socket: %1")
5129 retlist << QString(
"ERROR: Unknown file transfer socket: %1")
5141 if (command ==
"REQUEST_BLOCK")
5143 int size = slist[2].toInt();
5147 else if (command ==
"WRITE_BLOCK")
5149 int size = slist[2].toInt();
5151 retlist << QString::number(ft->
WriteBlock(size));
5153 else if (command ==
"SEEK")
5155 long long pos = slist[2].toLongLong();
5156 int whence = slist[3].toInt();
5157 long long curpos = slist[4].toLongLong();
5159 long long ret = ft->
Seek(curpos, pos, whence);
5160 retlist << QString::number(ret);
5162 else if (command ==
"IS_OPEN")
5164 bool isopen = ft->
isOpen();
5166 retlist << QString::number(isopen);
5168 else if (command ==
"REOPEN")
5170 retlist << QString::number(ft->
ReOpen(slist[2]));
5172 else if (command ==
"DONE")
5177 else if (command ==
"SET_TIMEOUT")
5179 bool fast = slist[2].toInt();
5185 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown command: %1").arg(command));
5200 QStringList::const_iterator it = slist.begin() + 1;
5205 QMap<int, EncoderLink *>::Iterator iter =
encoderList->begin();
5212 retval = iter.key();
5217 QStringList strlist( QString::number(retval) );
5221 if (encoder->IsLocal())
5230 encoder->GetHostName(),
"-1");
5235 strlist <<
"nohost";
5247 int recordernum = slist[1].toInt();
5249 QStringList strlist;
5251 QMap<int, EncoderLink *>::Iterator iter =
encoderList->find(recordernum);
5272 strlist <<
"nohost";
5281 if (slist.size() < 2)
5286 QString message = slist[1];
5287 QStringList extra_data;
5288 for (
uint i = 2; i < (
uint) slist.size(); i++)
5289 extra_data.push_back(slist[i]);
5291 if (extra_data.empty())
5302 QStringList retlist(
"OK" );
5310 QStringList retlist;
5312 QString newverbose = slist[1];
5313 int len = newverbose.length();
5319 LOG(VB_GENERAL, LOG_NOTICE,
5320 QString(
"Verbose mask changed, new mask is: %1")
5327 LOG(VB_GENERAL, LOG_ERR, QString(
"Invalid SET_VERBOSE string: '%1'")
5329 retlist <<
"Failed";
5338 QStringList retlist;
5339 QString newstring = slist[1];
5340 LogLevel_t newlevel = LOG_UNKNOWN;
5342 int len = newstring.length();
5346 if (newlevel != LOG_UNKNOWN)
5350 LOG(VB_GENERAL, LOG_NOTICE,
5351 QString(
"Log level changed, new level is: %1")
5358 if (newlevel == LOG_UNKNOWN)
5360 LOG(VB_GENERAL, LOG_ERR, QString(
"Invalid SET_VERBOSE string: '%1'")
5362 retlist <<
"Failed";
5373 int RecordingsInProgress = 0;
5374 int LiveTVRecordingsInProgress = 0;
5375 QStringList retlist;
5377 QMap<int, EncoderLink *>::Iterator iter =
encoderList->begin();
5382 RecordingsInProgress++;
5386 LiveTVRecordingsInProgress++;
5392 retlist << QString::number(RecordingsInProgress);
5393 retlist << QString::number(LiveTVRecordingsInProgress);
5402 if (slist.size() < 3)
5404 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Too few params in pixmap request");
5405 QStringList outputlist(
"ERROR");
5406 outputlist +=
"TOO_FEW_PARAMS";
5411 bool time_fmt_sec =
true;
5412 long long time = -1;
5416 bool has_extra_data =
false;
5418 QString token = slist[1];
5419 if (token.isEmpty())
5421 LOG(VB_GENERAL, LOG_ERR,
LOC +
5422 "Failed to parse pixmap request. Token absent");
5423 QStringList outputlist(
"ERROR");
5424 outputlist +=
"TOKEN_ABSENT";
5429 QStringList::const_iterator it = slist.begin() + 2;
5430 QStringList::const_iterator end = slist.end();
5435 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to parse pixmap request. "
5436 "ProgramInfo missing pathname");
5437 QStringList outputlist(
"BAD");
5438 outputlist +=
"NO_PATHNAME";
5442 if (token.toLower() ==
"do_not_care")
5444 token = QString(
"%1:%2")
5447 if (it != slist.end())
5448 (time_fmt_sec = ((*it).toLower() ==
"s")), ++it;
5449 if (it != slist.end())
5450 (time = (*it).toLongLong()), ++it;
5451 if (it != slist.end())
5452 (outputfile = *it), ++it;
5453 outputfile = (outputfile ==
"<EMPTY>") ? QString::null : outputfile;
5454 if (it != slist.end())
5456 width = (*it).toInt(&ok); ++it;
5457 width = (ok) ? width : -1;
5459 if (it != slist.end())
5461 height = (*it).toInt(&ok); ++it;
5462 height = (ok) ? height : -1;
5463 has_extra_data =
true;
5465 QSize outputsize = QSize(width, height);
5469 LOG(VB_PLAYBACK, LOG_INFO,
5470 QString(
"HandleGenPreviewPixmap got extra data\n\t\t\t"
5472 .arg(time).arg(time_fmt_sec?
"s":
"f")
5473 .arg(width).arg(height).arg(outputfile));
5488 QStringList outputlist;
5492 token, &pginfo, time_fmt_sec, time, outputfile, outputsize);
5501 if (outputlist.empty() || outputlist[0] !=
"OK")
5507 LOG(VB_GENERAL, LOG_ERR,
LOC +
5508 QString(
"HandleGenPreviewPixmap() "
5509 "Couldn't find backend for:\n\t\t\t%1")
5515 LOG(VB_GENERAL, LOG_ERR,
LOC +
"HandleGenPreviewPixmap: Unable to "
5516 "find file locally, unable to make preview image.");
5517 QStringList outputlist(
"ERROR" );
5518 outputlist +=
"FILE_INACCESSIBLE";
5527 pginfo, outputsize, outputfile, time, time_fmt_sec, token);
5534 QStringList outputlist(
"OK");
5535 if (!outputfile.isEmpty())
5536 outputlist += outputfile;
5544 QStringList::const_iterator it = slist.begin() + 1;
5549 QStringList strlist;
5562 strlist = (slavetime.isValid()) ?
5563 QStringList(QString::number(slavetime.toTime_t())) :
5571 LOG(VB_GENERAL, LOG_ERR,
LOC +
5572 QString(
"HandlePixmapLastModified() "
5573 "Couldn't find backend for:\n\t\t\t%1")
5578 if (!pginfo.IsLocal())
5580 LOG(VB_GENERAL, LOG_ERR,
5581 "MainServer: HandlePixmapLastModified: Unable to "
5582 "find file locally, unable to get last modified date.");
5583 QStringList outputlist(
"BAD" );
5588 QString filename = pginfo.GetPathname() +
".png";
5590 QFileInfo finfo(filename);
5594 QDateTime lastmodified = finfo.lastModified();
5595 strlist = QStringList(QString::number(lastmodified.toTime_t()));
5598 strlist = QStringList(
"BAD" );
5606 QStringList strlist;
5609 if (slist.size() < (3 + NUMPROGRAMLINES))
5611 strlist = QStringList(
"ERROR");
5612 strlist +=
"1: Parameter list too short";
5617 QDateTime cachemodified;
5618 if (slist[1].toInt() != -1)
5621 int max_file_size = slist[2].toInt();
5623 QStringList::const_iterator it = slist.begin() + 3;
5626 if (!pginfo.HasPathname())
5628 strlist = QStringList(
"ERROR");
5629 strlist +=
"2: Invalid ProgramInfo";
5635 if (pginfo.IsLocal())
5637 QFileInfo finfo(pginfo.GetPathname());
5640 size_t fsize = finfo.size();
5641 QDateTime lastmodified = finfo.lastModified();
5642 bool out_of_date = !cachemodified.isValid() ||
5643 (lastmodified > cachemodified);
5645 if (out_of_date && (fsize > 0) && ((
ssize_t)fsize < max_file_size))
5648 QFile file(pginfo.GetPathname());
5649 bool open_ok = file.open(QIODevice::ReadOnly);
5651 data = file.readAll();
5655 LOG(VB_FILE, LOG_INFO, QString(
"Read preview file '%1'")
5656 .arg(pginfo.GetPathname()));
5657 strlist += QString::number(lastmodified.toTime_t());
5658 strlist += QString::number(data.size());
5659 strlist += QString::number(qChecksum(data.constData(),
5661 strlist += QString(data.toBase64());
5665 LOG(VB_GENERAL, LOG_ERR,
5666 QString(
"Failed to read preview file '%1'")
5667 .arg(pginfo.GetPathname()));
5669 strlist = QStringList(
"ERROR");
5671 QString(
"3: Failed to read preview file '%1'%2")
5672 .arg(pginfo.GetPathname())
5673 .arg((open_ok) ?
"" :
" open failed");
5676 else if (out_of_date && (max_file_size > 0))
5678 if (fsize >= (
size_t) max_file_size)
5680 strlist = QStringList(
"WARNING");
5681 strlist += QString(
"1: Preview file too big %1 > %2")
5682 .arg(fsize).arg(max_file_size);
5686 strlist = QStringList(
"ERROR");
5687 strlist +=
"4: Preview file is invalid";
5692 strlist += QString::number(lastmodified.toTime_t());
5706 strlist = QStringList(
"ERROR");
5708 "5: Could not locate mythbackend that made this recording";
5717 if (!strlist.empty())
5724 strlist = QStringList(
"WARNING");
5725 strlist +=
"2: Could not locate requested file";
5731 QStringList retlist(
"OK" );
5740 QStringList retlist(
"OK" );
5782 vector<PlaybackSock *>::iterator it =
playbackList.begin();
5793 MythEvent me(
"LOCAL_RECONNECT_TO_MASTER");
5797 else if (sock == socket)
5799 QList<uint> disconnectedSlaves;
5800 bool needsReschedule =
false;
5804 LOG(VB_GENERAL, LOG_ERR,
5805 QString(
"Slave backend: %1 no longer connected")
5808 bool isFallingAsleep =
true;
5809 QMap<int, EncoderLink *>::Iterator iter =
encoderList->begin();
5816 isFallingAsleep =
false;
5820 disconnectedSlaves.push_back(elink->
GetCardID());
5823 if (
m_sched && !isFallingAsleep)
5824 needsReschedule =
true;
5826 QString message = QString(
"LOCAL_SLAVE_BACKEND_OFFLINE %1")
5835 QString(
"SLAVE_DISCONNECTED HOSTNAME %1")
5841 QString(
"CLIENT_DISCONNECTED HOSTNAME %1")
5851 QMap<int, EncoderLink *>::iterator it =
5877 LOG(VB_GENERAL, LOG_ERR,
"Playback sock still exists?");
5915 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5916 QString(
"Unknown socket closing MythSocket(0x%1)")
5917 .arg((intptr_t)socket,0,16));
5927 vector<PlaybackSock *>::iterator iter =
playbackList.begin();
5932 ((pbs->
getHostname().toLower() == hostname.toLower()) ||
5953 vector<PlaybackSock *>::iterator iter =
playbackList.begin();
5958 ((pbs->
getHostname().toLower() == hostname.toLower()) ||
5974 vector<PlaybackSock *>::iterator it =
playbackList.begin();
5977 if (sock == (*it)->getSocket())
5995 if (
id == (*it)->getSocket()->GetSocketDescriptor())
6013 if (sock == (*it)->getSocket())
6027 vector<LiveTVChain*>::iterator it =
liveTVChains.begin();
6030 if ((*it)->GetID() == id)
6041 vector<LiveTVChain*>::iterator it =
liveTVChains.begin();
6044 if ((*it)->IsHostSocket(sock))
6055 vector<LiveTVChain*>::iterator it =
liveTVChains.begin();
6058 if ((*it)->ProgramIsAt(pginfo) >= 0)
6080 vector<LiveTVChain*> newChains;
6082 vector<LiveTVChain*>::iterator it =
liveTVChains.begin();
6086 newChains.push_back(*it);
6096 if (closeApplication)
6102 QString lpath = url.path();
6104 if (url.hasFragment())
6105 lpath +=
"#" + url.fragment();
6107 if (lpath.section(
'/', -2, -2) ==
"channels")
6112 QString file = lpath.section(
'/', -1);
6116 query.
prepare(
"SELECT icon FROM channel WHERE icon LIKE :FILENAME ;");
6117 query.
bindValue(
":FILENAME", QString(
"%/") + file);
6121 lpath = query.
value(0).toString();
6130 lpath = lpath.section(
'/', -1);
6132 QString fpath = lpath;
6133 if (fpath.endsWith(
".png"))
6134 fpath = fpath.left(fpath.length() - 4);
6140 if (pburl.startsWith(
"/"))
6142 lpath = pburl.section(
'/', 0, -2) +
"/" + lpath;
6143 LOG(VB_FILE, LOG_INFO,
6144 QString(
"Local file path: %1").arg(lpath));
6148 LOG(VB_GENERAL, LOG_ERR,
6149 QString(
"ERROR: LocalFilePath unable to find local "
6150 "path for '%1', found '%2' instead.")
6151 .arg(lpath).arg(pburl));
6155 else if (!lpath.isEmpty())
6158 QString opath = lpath;
6161 if (!wantgroup.isEmpty())
6163 sgroup.
Init(wantgroup);
6164 lpath = url.toString();
6168 lpath = QFileInfo(lpath).fileName();
6171 QString tmpFile = sgroup.
FindFile(lpath);
6172 if (!tmpFile.isEmpty())
6175 LOG(VB_FILE, LOG_INFO,
6176 QString(
"LocalFilePath(%1 '%2'), found file through "
6177 "exhaustive search at '%3'")
6178 .arg(url.toString()).arg(opath).arg(lpath));
6182 LOG(VB_GENERAL, LOG_ERR, QString(
"ERROR: LocalFilePath "
6183 "unable to find local path for '%1'.") .arg(opath));
6204 LOG(VB_GENERAL, LOG_NOTICE, QString(
"Connecting to master server: %1:%2")
6205 .arg(server).arg(port));
6209 LOG(VB_GENERAL, LOG_NOTICE,
"Connection to master server timed out.");
6215 LOG(VB_GENERAL, LOG_NOTICE,
"Connected successfully");
6217 QString str = QString(
"ANN SlaveBackend %1 %2")
6221 QStringList strlist( str );
6223 QMap<int, EncoderLink *>::Iterator iter =
encoderList->begin();
6242 (strlist[0] ==
"ERROR"))
6245 masterServerSock = NULL;
6246 if (strlist.empty())
6248 LOG(VB_GENERAL, LOG_ERR,
LOC +
6249 "Failed to open master server socket, timeout");
6253 LOG(VB_GENERAL, LOG_ERR,
LOC +
6254 "Failed to open master server socket" +
6255 ((strlist.size() >= 2) ?
6256 QString(
", error was %1").arg(strlist[1]) :
6257 QString(
", remote error")));
6276 bool foundClient =
false;
6282 vector<PlaybackSock *>::iterator it =
playbackList.begin();
6283 for (; !foundClient && (it !=
playbackList.end()); ++it)
6287 if (!(*it)->isSlaveBackend() && (*it)->getBlockShutdown())
6293 return (foundClient);
6302 QStringList bcast(
"SHUTDOWN_NOW" );
6307 vector<PlaybackSock *>::iterator it =
playbackList.begin();
6310 if ((*it)->isSlaveBackend())
6311 (*it)->getSocket()->WriteStringList(bcast);
6321 bool needsReschedule =
event.ExtraData(0).toUInt();
6322 for (
int i = 1; i <
event.ExtraDataCount(); i++)
6325 if (needsReschedule)
6331 const QList<uint> &cardids,
bool needsReschedule)
6333 QStringList extraData;
6334 extraData.push_back(