MythTV  master
mythsystemevent.cpp
Go to the documentation of this file.
1 
2 #include <QApplication>
3 #include <QFileInfo>
4 #include <QRunnable>
5 #include <utility>
6 
13 #include "libmythbase/remoteutil.h"
14 
15 #include "cardutil.h"
16 #include "mythsystemevent.h"
17 
18 #define LOC QString("MythSystemEventHandler: ")
19 
29 class SystemEventThread : public QRunnable
30 {
31  public:
38  explicit SystemEventThread(QString cmd, QString eventName = "")
39  : m_command(std::move(cmd)), m_event(std::move(eventName)) {};
40 
46  void run(void) override // QRunnable
47  {
49  uint result = myth_system(m_command, flags);
50 
51  LOG(VB_GENERAL,
52  (result == GENERIC_EXIT_OK ? LOG_INFO : LOG_WARNING), LOC +
53  QString("Finished '%1' result %2")
54  .arg(m_command).arg(result));
55 
56  if (m_event.isEmpty())
57  return;
58 
60  QString("SYSTEM_EVENT_RESULT %1 SENDER %2 RESULT %3")
62  QString::number(result)));
63  }
64 
65  private:
66  // Private data storage
67  QString m_command;
68  QString m_event;
69 };
70 
71 
78 {
79  setObjectName("MythSystemEventHandler");
81 }
82 
89 {
91 }
92 
106 void MythSystemEventHandler::SubstituteMatches(const QStringList &tokens,
107  QString &command)
108 {
109  if (command.isEmpty())
110  return;
111 
112  LOG(VB_FILE, LOG_DEBUG, LOC + QString("SubstituteMatches: BEFORE: %1")
113  .arg(command));
114  QString args;
115  uint chanid = 0;
116  QDateTime recstartts;
117 
118  QStringList::const_iterator it = tokens.begin();
119  ++it;
120  command.replace(QString("%EVENTNAME%"), *it);
121 
122  ++it;
123  while (it != tokens.end())
124  {
125  if (!args.isEmpty())
126  args += " ";
127  args += *it;
128 
129  // Check for some token names that we substitute one for one as
130  // %MATCH% type variables.
131  if ((*it == "CARDID") ||
132  (*it == "COMMAND") ||
133  (*it == "RECSTATUS") ||
134  (*it == "HOSTNAME") ||
135  (*it == "SECS") ||
136  (*it == "SENDER") ||
137  (*it == "PATH") ||
138  (*it == "VIDEODEVICE") ||
139  (*it == "VBIDEVICE"))
140  {
141  QString token = *it;
142 
143  if (++it == tokens.end())
144  break;
145 
146  // The following string is broken up on purpose to indicate
147  // what we're replacing is the token surrounded by percent signs
148  command.replace(QString("%" "%1" "%").arg(token), *it);
149 
150  if (!args.isEmpty())
151  args += " ";
152  args += *it;
153  }
154 
155  // Remember any chanid and starttime so we can lookup info about
156  // the recording from the database.
157  if (*it == "CHANID")
158  {
159  if (++it == tokens.end())
160  break;
161 
162  chanid = (*it).toUInt();
163 
164  if (!args.isEmpty())
165  args += " ";
166  args += *it;
167  }
168 
169  if (*it == "STARTTIME")
170  {
171  if (++it == tokens.end())
172  break;
173 
174  recstartts = MythDate::fromString(*it);
175 
176  if (!args.isEmpty())
177  args += " ";
178  args += *it;
179  }
180 
181  ++it;
182  }
183 
184  command.replace(QString("%ARGS%"), args);
185 
186  // 1st, try loading RecordingInfo / ProgramInfo
187  RecordingInfo recinfo(chanid, recstartts);
188  bool loaded = recinfo.GetChanID() != 0U;
189  if (loaded)
190  recinfo.SubstituteMatches(command);
191  else
192  {
193  // 2rd Try searching for RecordingInfo
195  RecordingInfo recinfo2(chanid, recstartts, false, 0h, &status);
196  if (status == RecordingInfo::kFoundProgram)
197  recinfo2.SubstituteMatches(command);
198  else
199  {
200  // 3th just use what we know
201  command.replace(QString("%CHANID%"), QString::number(chanid));
202  command.replace(QString("%STARTTIME%"),
203  MythDate::toString(recstartts,
205  command.replace(QString("%STARTTIMEISO%"),
206  recstartts.toString(Qt::ISODate));
207  }
208  }
209 
210  command.replace(QString("%VERBOSELEVEL%"), QString("%1").arg(verboseMask));
211  command.replace("%VERBOSEMODE%", QString("%1").arg(logPropagateArgs));
212 
213  LOG(VB_FILE, LOG_DEBUG, LOC + QString("SubstituteMatches: AFTER : %1")
214  .arg(command));
215 }
216 
226 QString MythSystemEventHandler::EventNameToSetting(const QString &name)
227 {
228  QString result("EventCmd");
229  QStringList parts = name.toLower().split('_', Qt::SkipEmptyParts);
230  for (const auto & part : std::as_const(parts))
231  {
232  result += part.at(0).toUpper();
233  result += part.mid(1);
234  }
235 
236  return result;
237 }
238 
255 {
256  if (e->type() == MythEvent::kMythEventMessage)
257  {
258  auto *me = dynamic_cast<MythEvent *>(e);
259  if (me == nullptr)
260  return;
261  QString msg = me->Message().simplified();
262 
263  if (msg == "CLEAR_SETTINGS_CACHE")
264  msg = "SYSTEM_EVENT SETTINGS_CACHE_CLEARED";
265 
266  // Listen for any GLOBAL_SYSTEM_EVENT messages and resend to
267  // the master backend as regular SYSTEM_EVENT messages.
268  if (msg.startsWith("GLOBAL_SYSTEM_EVENT "))
269  {
270  gCoreContext->SendMessage(msg.mid(7) +
271  QString(" SENDER %1").arg(gCoreContext->GetHostName()));
272  return;
273  }
274 
275  if ((!msg.startsWith("SYSTEM_EVENT ")) &&
276  (!msg.startsWith("LOCAL_SYSTEM_EVENT ")))
277  return;
278 
279  QStringList tokens = msg.split(' ', Qt::SkipEmptyParts);
280 
281  // Return if this event is for another host
282  if ((tokens.size() >= 4) &&
283  (tokens[2] == "HOST") &&
284  (tokens[3] != gCoreContext->GetHostName()))
285  return;
286 
287  QString cmd;
288 
289  // See if this system has a command that runs for all system events
290  cmd = gCoreContext->GetSetting("EventCmdAll");
291  if (!cmd.isEmpty())
292  {
293  SubstituteMatches(tokens, cmd);
294 
295  auto *eventThread = new SystemEventThread(cmd);
297  eventThread, "SystemEvent");
298  }
299 
300  // Check for an EventCmd for this particular event
301  cmd = gCoreContext->GetSetting(EventNameToSetting(tokens[1]));
302  if (!cmd.isEmpty())
303  {
304  SubstituteMatches(tokens, cmd);
305 
306  LOG(VB_GENERAL, LOG_INFO, LOC +
307  QString("Starting thread for command '%1'").arg(cmd));
308 
309  auto *eventThread = new SystemEventThread(cmd, tokens[1]);
311  eventThread, "SystemEvent");
312  }
313  }
314 }
315 
316 /****************************************************************************/
317 
324 void SendMythSystemRecEvent(const QString &msg, const RecordingInfo *pginfo)
325 {
326  if (pginfo)
327  {
328  uint cardid = pginfo->GetInputID();
330  QString("%1 CARDID %2 CHANID %3 STARTTIME %4 RECSTATUS %5 "
331  "VIDEODEVICE %6 VBIDEVICE %7")
332  .arg(msg).arg(cardid)
333  .arg(pginfo->GetChanID())
335  .arg(pginfo->GetRecordingStatus())
336  .arg(CardUtil::GetVideoDevice(cardid),
337  CardUtil::GetVBIDevice(cardid)));
338  }
339  else
340  {
341  LOG(VB_GENERAL, LOG_ERR, LOC +
342  "SendMythSystemRecEvent() called with empty RecordingInfo");
343  }
344 }
345 
352 void SendMythSystemPlayEvent(const QString &msg, const ProgramInfo *pginfo)
353 {
354  if (pginfo)
355  {
357  QString("%1 HOSTNAME %2 CHANID %3 STARTTIME %4")
358  .arg(msg, gCoreContext->GetHostName())
359  .arg(pginfo->GetChanID())
361  }
362  else
363  {
364  LOG(VB_GENERAL, LOG_ERR, LOC + "SendMythSystemPlayEvent() called with "
365  "empty ProgramInfo");
366  }
367 }
368 
369 /****************************************************************************/
370 
383  const char *name)
384  : RawSettingsEditor(parent, name)
385 {
386  m_title = tr("System Event Command Editor");
388 
389 }
390  void MythSystemEventEditor::createSettingList(QMap <QString, QString> &settings)
391 {
392  // Event names are programmatically converted to settings names in
393  // EventNameToSetting(). For convenience of searching the code
394  // base, the event names are listed in comments.
395  settings["EventCmdRecPending"] = // REC_PENDING
396  tr("Recording pending");
397  settings["EventCmdRecPreFail"] = // REC_PREFAIL
398  tr("Recording about to fail");
399  settings["EventCmdRecFailing"] = // REC_FAILING
400  tr("Recording failing");
401  settings["EventCmdRecStarted"] = // REC_STARTED
402  tr("Recording started");
403  settings["EventCmdRecStartedWriting"] = // REC_STARTED_WRITING
404  tr("Recording started writing");
405  settings["EventCmdRecFinished"] = // REC_FINISHED
406  tr("Recording finished");
407  settings["EventCmdRecDeleted"] = // REC_DELETED
408  tr("Recording deleted");
409  settings["EventCmdRecExpired"] = // REC_EXPIRED
410  tr("Recording expired");
411  settings["EventCmdLivetvStarted"] = // LIVETV_STARTED
412  tr("LiveTV started");
413  settings["EventCmdLivetvEnded"] = // LIVETV_ENDED
414  tr("LiveTV ended");
415  settings["EventCmdPlayStarted"] = // PLAY_STARTED
416  tr("Playback started");
417  settings["EventCmdPlayStopped"] = // PLAY_STOPPED
418  tr("Playback stopped");
419  settings["EventCmdPlayPaused"] = // PLAY_PAUSED
420  tr("Playback paused");
421  settings["EventCmdPlayUnpaused"] = // PLAY_UNPAUSED
422  tr("Playback unpaused");
423  settings["EventCmdPlayChanged"] = // PLAY_CHANGED
424  tr("Playback program changed");
425  settings["EventCmdTuningSignalTimeout"] = // TUNING_SIGNAL_TIMEOUT
426  tr("Tuning signal waiting");
427  settings["EventCmdMasterStarted"] = // MASTER_STARTED
428  tr("Master backend started");
429  settings["EventCmdMasterShutdown"] = // MASTER_SHUTDOWN
430  tr("Master backend shutdown");
431  settings["EventCmdClientConnected"] = // CLIENT_CONNECTED
432  tr("Client connected to master backend");
433  settings["EventCmdClientDisconnected"] = // CLIENT_DISCONNECTED
434  tr("Client disconnected from master backend");
435  settings["EventCmdSlaveConnected"] = // SLAVE_CONNECTED
436  tr("Slave backend connected to master");
437  settings["EventCmdSlaveDisconnected"] = // SLAVE_DISCONNECTED
438  tr("Slave backend disconnected from master");
439  settings["EventCmdNetCtrlConnected"] = // NET_CTRL_CONNECTED
440  tr("Network Control client connected");
441  settings["EventCmdNetCtrlDisconnected"] = // NET_CTRL_DISCONNECTED
442  tr("Network Control client disconnected");
443  settings["EventCmdMythfilldatabaseRan"] = // MYTHFILLDATABASE_RAN
444  tr("mythfilldatabase ran");
445  settings["EventCmdSchedulerRan"] = // SCHEDULER_RAN
446  tr("Scheduler ran");
447  settings["EventCmdSettingsCacheCleared"] = // SETTINGS_CACHE_CLEARED
448  tr("Settings cache cleared");
449  settings["EventCmdScreenType"] = // SCREEN_TYPE
450  tr("Screen created or destroyed");
451  settings["EventCmdKey01"] = // KEY_%1
452  tr("Keystroke event #1");
453  settings["EventCmdKey02"] = // KEY_%1
454  tr("Keystroke event #2");
455  settings["EventCmdKey03"] = // KEY_%1
456  tr("Keystroke event #3");
457  settings["EventCmdKey04"] = // KEY_%1
458  tr("Keystroke event #4");
459  settings["EventCmdKey05"] = // KEY_%1
460  tr("Keystroke event #5");
461  settings["EventCmdKey06"] = // KEY_%1
462  tr("Keystroke event #6");
463  settings["EventCmdKey07"] = // KEY_%1
464  tr("Keystroke event #7");
465  settings["EventCmdKey08"] = // KEY_%1
466  tr("Keystroke event #8");
467  settings["EventCmdKey09"] = // KEY_%1
468  tr("Keystroke event #9");
469  settings["EventCmdKey10"] = // KEY_%1
470  tr("Keystroke event #10");
471  settings["EventCmdCecCommandReceived"] = // CEC_COMMAND_RECEIVED
472  tr("CEC command received");
473  settings["EventCmdAll"] = // EventCmdAll
474  tr("Any event");
475 }
476 
477 /* vim: set expandtab tabstop=4 shiftwidth=4: */
build_compdb.args
args
Definition: build_compdb.py:11
MythSystemEventHandler::MythSystemEventHandler
MythSystemEventHandler()
Null Constructor.
Definition: mythsystemevent.cpp:77
MythCoreContext::SendMessage
void SendMessage(const QString &message)
Definition: mythcorecontext.cpp:1527
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:93
MythEvent::kMythEventMessage
static const Type kMythEventMessage
Definition: mythevent.h:79
kMSDontBlockInputDevs
@ kMSDontBlockInputDevs
avoid blocking LIRC & Joystick Menu
Definition: mythsystem.h:36
RecordingInfo::kFoundProgram
@ kFoundProgram
Definition: recordinginfo.h:182
RecordingInfo
Holds information on a TV Program one might wish to record.
Definition: recordinginfo.h:35
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
RawSettingsEditor
An editor screen that allows manipulation of raw settings values.
Definition: rawsettingseditor.h:25
MythScreenStack
Definition: mythscreenstack.h:16
RawSettingsEditor::m_title
QString m_title
Definition: rawsettingseditor.h:51
LOC
#define LOC
Definition: mythsystemevent.cpp:18
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythSystemEventHandler::SubstituteMatches
static void SubstituteMatches(const QStringList &tokens, QString &command)
Substitutes MATCH% variables in given command line.
Definition: mythsystemevent.cpp:106
mythsystemevent.h
myth_system
uint myth_system(const QString &command, uint flags, std::chrono::seconds timeout)
Definition: mythsystemlegacy.cpp:506
MThreadPool::startReserved
void startReserved(QRunnable *runnable, const QString &debugName, std::chrono::milliseconds waitForAvailMS=0ms)
Definition: mthreadpool.cpp:361
remoteutil.h
MythEvent::Message
const QString & Message() const
Definition: mythevent.h:65
ProgramInfo::GetRecordingStartTime
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:405
SystemEventThread
QRunnable class for running MythSystemEvent handler commands.
Definition: mythsystemevent.cpp:29
mythsystemlegacy.h
MythObservable::addListener
void addListener(QObject *listener)
Add a listener to the observable.
Definition: mythobservable.cpp:38
RecordingInfo::kNoProgram
@ kNoProgram
Definition: recordinginfo.h:181
MythSystemEventHandler::EventNameToSetting
static QString EventNameToSetting(const QString &name)
Convert an MythSystemEvent name to a database setting name.
Definition: mythsystemevent.cpp:226
programinfo.h
mythlogging.h
ProgramInfo::GetRecordingStatus
RecStatus::Type GetRecordingStatus(void) const
Definition: programinfo.h:451
MythDate::kFilename
@ kFilename
Default UTC, "yyyyMMddhhmmss".
Definition: mythdate.h:18
MythCoreContext::SendSystemEvent
void SendSystemEvent(const QString &msg)
Definition: mythcorecontext.cpp:1554
SystemEventThread::SystemEventThread
SystemEventThread(QString cmd, QString eventName="")
Constructor for creating a SystemEventThread.
Definition: mythsystemevent.cpp:38
verboseMask
uint64_t verboseMask
Definition: logging.cpp:97
GENERIC_EXIT_OK
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:39
SystemEventThread::m_event
QString m_event
Definition: mythsystemevent.cpp:68
ProgramInfo::GetInputID
uint GetInputID(void) const
Definition: programinfo.h:467
mthreadpool.h
ProgramInfo::GetChanID
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:373
SystemEventThread::m_command
QString m_command
Definition: mythsystemevent.cpp:67
RecordingInfo::SubstituteMatches
void SubstituteMatches(QString &str) override
Replace MATCH% vars in the specified string.
Definition: recordinginfo.cpp:1693
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:67
RecordingInfo::LoadStatus
LoadStatus
Definition: recordinginfo.h:180
RawSettingsEditor::m_settings
QMap< QString, QString > m_settings
Definition: rawsettingseditor.h:52
mythcorecontext.h
SendMythSystemPlayEvent
void SendMythSystemPlayEvent(const QString &msg, const ProgramInfo *pginfo)
Definition: mythsystemevent.cpp:352
MythSystemEventHandler::customEvent
void customEvent(QEvent *e) override
Custom Event handler for receiving and processing System Events.
Definition: mythsystemevent.cpp:254
cardutil.h
MythSystemEventEditor::MythSystemEventEditor
MythSystemEventEditor(MythScreenStack *parent, const char *name=nullptr)
Constructor for the MythSystemEvent settings editor.
Definition: mythsystemevent.cpp:382
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
MythSystemEventEditor::createSettingList
static void createSettingList(QMap< QString, QString > &settings)
Definition: mythsystemevent.cpp:390
CardUtil::GetVBIDevice
static QString GetVBIDevice(uint inputid)
Definition: cardutil.h:298
SendMythSystemRecEvent
void SendMythSystemRecEvent(const QString &msg, const RecordingInfo *pginfo)
Definition: mythsystemevent.cpp:324
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:844
SystemEventThread::run
void run(void) override
Runs the System Event handler command.
Definition: mythsystemevent.cpp:46
logPropagateArgs
QString logPropagateArgs
Definition: logging.cpp:82
MythSystemEventHandler::~MythSystemEventHandler
~MythSystemEventHandler() override
Destructor.
Definition: mythsystemevent.cpp:88
exitcodes.h
MThreadPool::globalInstance
static MThreadPool * globalInstance(void)
Definition: mthreadpool.cpp:307
MythObservable::removeListener
void removeListener(QObject *listener)
Remove a listener to the observable.
Definition: mythobservable.cpp:55
CardUtil::GetVideoDevice
static QString GetVideoDevice(uint inputid)
Definition: cardutil.h:294
uint
unsigned int uint
Definition: freesurround.h:24
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:904