MythTV  0.26-pre
mythsystemevent.cpp
Go to the documentation of this file.
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     // Private data storage
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         // Check for some token names that we substitute one for one as
00130         // %MATCH% type variables.
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             // The following string is broken up on purpose to indicate
00147             // what we're replacing is the token surrounded by percent signs
00148             command.replace(QString("%" "%1" "%").arg(token), *it);
00149 
00150             if (!args.isEmpty())
00151                 args += " ";
00152             args += *it;
00153         }
00154 
00155         // Remember any chanid and starttime so we can lookup info about
00156         // the recording from the database.
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         // Listen for any GLOBAL_SYSTEM_EVENT messages and resend to
00266         // the master backend as regular SYSTEM_EVENT messages.
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         // Return if this event is for another host
00281         if ((tokens.size() >= 4) &&
00282             (tokens[2] == "HOST") &&
00283             (tokens[3] != gCoreContext->GetHostName()))
00284             return;
00285 
00286         QString cmd;
00287 
00288         // See if this system has a command that runs for all system events
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         // Check for an EventCmd for this particular event
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 /* vim: set expandtab tabstop=4 shiftwidth=4: */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends