00001
00002 #include <QApplication>
00003 #include <QFileInfo>
00004 #include <QRunnable>
00005
00006 #include "mythcorecontext.h"
00007 #include "mthreadpool.h"
00008 #include "mythsystem.h"
00009 #include "mythsystemevent.h"
00010 #include "programinfo.h"
00011 #include "remoteutil.h"
00012 #include "exitcodes.h"
00013 #include "mythlogging.h"
00014
00015 #define LOC QString("MythSystemEventHandler: ")
00016
00026 class SystemEventThread : public QRunnable
00027 {
00028 public:
00035 SystemEventThread(const QString cmd, QString eventName = "")
00036 : m_command(cmd), m_event(eventName) {};
00037
00043 void run(void)
00044 {
00045 uint flags = kMSDontBlockInputDevs;
00046
00047 m_event.detach();
00048 m_command.detach();
00049
00050 uint result = myth_system(m_command, flags);
00051
00052 if (result != GENERIC_EXIT_OK)
00053 LOG(VB_GENERAL, LOG_WARNING, LOC +
00054 QString("Command '%1' returned %2")
00055 .arg(m_command).arg(result));
00056
00057 if (m_event.isEmpty())
00058 return;
00059
00060 gCoreContext->SendMessage(
00061 QString("SYSTEM_EVENT_RESULT %1 SENDER %2 RESULT %3")
00062 .arg(m_event).arg(gCoreContext->GetHostName()).arg(result));
00063 }
00064
00065 private:
00066
00067 QString m_command;
00068 QString m_event;
00069 };
00070
00071
00077 MythSystemEventHandler::MythSystemEventHandler(void)
00078 {
00079 gCoreContext->addListener(this);
00080 }
00081
00087 MythSystemEventHandler::~MythSystemEventHandler()
00088 {
00089 gCoreContext->removeListener(this);
00090 }
00091
00105 void MythSystemEventHandler::SubstituteMatches(const QStringList &tokens,
00106 QString &command)
00107 {
00108 if (command.isEmpty())
00109 return;
00110
00111 LOG(VB_FILE, LOG_DEBUG, LOC + QString("SubstituteMatches: BEFORE: %1")
00112 .arg(command));
00113 QString args;
00114 uint chanid = 0;
00115 QDateTime recstartts;
00116 QString sender;
00117
00118 QStringList::const_iterator it = tokens.begin();
00119 ++it;
00120 command.replace(QString("%EVENTNAME%"), *it);
00121
00122 ++it;
00123 while (it != tokens.end())
00124 {
00125 if (!args.isEmpty())
00126 args += " ";
00127 args += *it;
00128
00129
00130
00131 if ((*it == "CARDID") ||
00132 (*it == "RECSTATUS") ||
00133 (*it == "HOSTNAME") ||
00134 (*it == "SECS") ||
00135 (*it == "SENDER") ||
00136 (*it == "PATH"))
00137 {
00138 QString token = *it;
00139
00140 if (++it == tokens.end())
00141 break;
00142
00143 if (token == "SENDER")
00144 sender = *it;
00145
00146
00147
00148 command.replace(QString("%" "%1" "%").arg(token), *it);
00149
00150 if (!args.isEmpty())
00151 args += " ";
00152 args += *it;
00153 }
00154
00155
00156
00157 if (*it == "CHANID")
00158 {
00159 if (++it == tokens.end())
00160 break;
00161
00162 chanid = (*it).toUInt();
00163
00164 if (!args.isEmpty())
00165 args += " ";
00166 args += *it;
00167 }
00168
00169 if (*it == "STARTTIME")
00170 {
00171 if (++it == tokens.end())
00172 break;
00173
00174 recstartts = QDateTime::fromString(*it, Qt::ISODate);
00175
00176 if (!args.isEmpty())
00177 args += " ";
00178 args += *it;
00179 }
00180
00181 ++it;
00182 }
00183
00184 command.replace(QString("%ARGS%"), args);
00185
00186 ProgramInfo pginfo(chanid, recstartts);
00187 bool pginfo_loaded = pginfo.GetChanID();
00188 if (!pginfo_loaded)
00189 {
00190 RecordingInfo::LoadStatus status;
00191 pginfo = RecordingInfo(chanid, recstartts, false, 0, &status);
00192 pginfo_loaded = RecordingInfo::kFoundProgram == status;
00193 }
00194
00195 if (pginfo_loaded)
00196 {
00197 pginfo.SubstituteMatches(command);
00198 }
00199 else
00200 {
00201 command.replace(QString("%CHANID%"), QString::number(chanid));
00202 command.replace(QString("%STARTTIME%"),
00203 recstartts.toString("yyyyMMddhhmmss"));
00204 command.replace(QString("%STARTTIMEISO%"),
00205 recstartts.toString(Qt::ISODate));
00206 }
00207
00208 command.replace(QString("%VERBOSELEVEL%"), QString("%1").arg(verboseMask));
00209
00210 LOG(VB_FILE, LOG_DEBUG, LOC + QString("SubstituteMatches: AFTER : %1")
00211 .arg(command));
00212 }
00213
00223 QString MythSystemEventHandler::EventNameToSetting(const QString &name)
00224 {
00225 QString result("EventCmd");
00226 QStringList parts = name.toLower().split('_', QString::SkipEmptyParts);
00227
00228 QStringList::Iterator it = parts.begin();
00229 while (it != parts.end())
00230 {
00231 result += (*it).left(1).toUpper();
00232 result += (*it).mid(1);
00233
00234 ++it;
00235 }
00236
00237 return result;
00238 }
00239
00255 void MythSystemEventHandler::customEvent(QEvent *e)
00256 {
00257 if ((MythEvent::Type)(e->type()) == MythEvent::MythEventMessage)
00258 {
00259 MythEvent *me = (MythEvent *)e;
00260 QString msg = me->Message().simplified();
00261
00262 if (msg == "CLEAR_SETTINGS_CACHE")
00263 msg = "SYSTEM_EVENT SETTINGS_CACHE_CLEARED";
00264
00265
00266
00267 if (msg.startsWith("GLOBAL_SYSTEM_EVENT "))
00268 {
00269 gCoreContext->SendMessage(msg.mid(7) +
00270 QString(" SENDER %1").arg(gCoreContext->GetHostName()));
00271 return;
00272 }
00273
00274 if ((!msg.startsWith("SYSTEM_EVENT ")) &&
00275 (!msg.startsWith("LOCAL_SYSTEM_EVENT ")))
00276 return;
00277
00278 QStringList tokens = msg.split(' ', QString::SkipEmptyParts);
00279
00280
00281 if ((tokens.size() >= 4) &&
00282 (tokens[2] == "HOST") &&
00283 (tokens[3] != gCoreContext->GetHostName()))
00284 return;
00285
00286 QString cmd;
00287
00288
00289 cmd = gCoreContext->GetSetting("EventCmdAll");
00290 if (!cmd.isEmpty())
00291 {
00292 SubstituteMatches(tokens, cmd);
00293
00294 SystemEventThread *eventThread = new SystemEventThread(cmd);
00295 MThreadPool::globalInstance()->startReserved(
00296 eventThread, "SystemEvent");
00297 }
00298
00299
00300 cmd = gCoreContext->GetSetting(EventNameToSetting(tokens[1]));
00301 if (!cmd.isEmpty())
00302 {
00303 SubstituteMatches(tokens, cmd);
00304
00305 SystemEventThread *eventThread =
00306 new SystemEventThread(cmd, tokens[1]);
00307 MThreadPool::globalInstance()->startReserved(
00308 eventThread, "SystemEvent");
00309 }
00310 }
00311 }
00312
00313
00314
00321 void SendMythSystemRecEvent(const QString msg, const RecordingInfo *pginfo)
00322 {
00323 if (pginfo)
00324 gCoreContext->SendSystemEvent(
00325 QString("%1 CARDID %2 CHANID %3 STARTTIME %4 RECSTATUS %5")
00326 .arg(msg).arg(pginfo->GetCardID())
00327 .arg(pginfo->GetChanID())
00328 .arg(pginfo->GetRecordingStartTime(ISODate))
00329 .arg(pginfo->GetRecordingStatus()));
00330 else
00331 LOG(VB_GENERAL, LOG_ERR, LOC + "SendMythSystemRecEvent() called with "
00332 "empty RecordingInfo");
00333 }
00334
00341 void SendMythSystemPlayEvent(const QString msg, const ProgramInfo *pginfo)
00342 {
00343 if (pginfo)
00344 gCoreContext->SendSystemEvent(
00345 QString("%1 HOSTNAME %2 CHANID %3 STARTTIME %4")
00346 .arg(msg).arg(gCoreContext->GetHostName())
00347 .arg(pginfo->GetChanID())
00348 .arg(pginfo->GetRecordingStartTime(ISODate)));
00349 else
00350 LOG(VB_GENERAL, LOG_ERR, LOC + "SendMythSystemPlayEvent() called with "
00351 "empty ProgramInfo");
00352 }
00353
00354
00355
00367 MythSystemEventEditor::MythSystemEventEditor(MythScreenStack *parent,
00368 const char *name)
00369 : RawSettingsEditor(parent, name)
00370 {
00371 m_title = tr("System Event Command Editor");
00372
00373 m_settings["EventCmdRecPending"] = tr("Recording pending");
00374 m_settings["EventCmdRecStarted"] = tr("Recording started");
00375 m_settings["EventCmdRecFinished"] = tr("Recording finished");
00376 m_settings["EventCmdRecDeleted"] = tr("Recording deleted");
00377 m_settings["EventCmdRecExpired"] = tr("Recording expired");
00378 m_settings["EventCmdLivetvStarted"] = tr("LiveTV started");
00379 m_settings["EventCmdPlayStarted"] = tr("Playback started");
00380 m_settings["EventCmdPlayStopped"] = tr("Playback stopped");
00381 m_settings["EventCmdPlayPaused"] = tr("Playback paused");
00382 m_settings["EventCmdPlayUnpaused"] = tr("Playback unpaused");
00383 m_settings["EventCmdPlayChanged"] = tr("Playback program changed");
00384 m_settings["EventCmdMasterStarted"] = tr("Master backend started");
00385 m_settings["EventCmdMasterShutdown"] = tr("Master backend shutdown");
00386 m_settings["EventCmdClientConnected"] = tr("Client connected to master backend");
00387 m_settings["EventCmdClientDisconnected"] = tr("Client disconnected from master backend");
00388 m_settings["EventCmdSlaveConnected"] = tr("Slave backend connected to master");
00389 m_settings["EventCmdSlaveDisconnected"] = tr("Slave backend disconnected from master");
00390 m_settings["EventCmdNetCtrlConnected"] = tr("Network Control client connected");
00391 m_settings["EventCmdNetCtrlDisconnected"] = tr("Network Control client disconnected");
00392 m_settings["EventCmdMythfilldatabaseRan"] = tr("mythfilldatabase ran");
00393 m_settings["EventCmdSchedulerRan"] = tr("Scheduler ran");
00394 m_settings["EventCmdSettingsCacheCleared"] = tr("Settings cache cleared");
00395 m_settings["EventCmdScreenType"] = tr("Screen created or destroyed");
00396 m_settings["EventCmdKey01"] = tr("Keystroke event #1");
00397 m_settings["EventCmdKey02"] = tr("Keystroke event #2");
00398 m_settings["EventCmdKey03"] = tr("Keystroke event #3");
00399 m_settings["EventCmdKey04"] = tr("Keystroke event #4");
00400 m_settings["EventCmdKey05"] = tr("Keystroke event #5");
00401 m_settings["EventCmdKey06"] = tr("Keystroke event #6");
00402 m_settings["EventCmdKey07"] = tr("Keystroke event #7");
00403 m_settings["EventCmdKey08"] = tr("Keystroke event #8");
00404 m_settings["EventCmdKey09"] = tr("Keystroke event #9");
00405 m_settings["EventCmdKey10"] = tr("Keystroke event #10");
00406 m_settings["EventCmdAll"] = tr("Any event");
00407 }
00408
00409