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 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
230  QStringList parts = name.toLower().split('_', QString::SkipEmptyParts);
231 #else
232  QStringList parts = name.toLower().split('_', Qt::SkipEmptyParts);
233 #endif
234 
235  for (const auto & part : qAsConst(parts))
236  {
237  result += part.at(0).toUpper();
238  result += part.mid(1);
239  }
240 
241  return result;
242 }
243 
260 {
261  if (e->type() == MythEvent::kMythEventMessage)
262  {
263  auto *me = dynamic_cast<MythEvent *>(e);
264  if (me == nullptr)
265  return;
266  QString msg = me->Message().simplified();
267 
268  if (msg == "CLEAR_SETTINGS_CACHE")
269  msg = "SYSTEM_EVENT SETTINGS_CACHE_CLEARED";
270 
271  // Listen for any GLOBAL_SYSTEM_EVENT messages and resend to
272  // the master backend as regular SYSTEM_EVENT messages.
273  if (msg.startsWith("GLOBAL_SYSTEM_EVENT "))
274  {
275  gCoreContext->SendMessage(msg.mid(7) +
276  QString(" SENDER %1").arg(gCoreContext->GetHostName()));
277  return;
278  }
279 
280  if ((!msg.startsWith("SYSTEM_EVENT ")) &&
281  (!msg.startsWith("LOCAL_SYSTEM_EVENT ")))
282  return;
283 
284 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
285  QStringList tokens = msg.split(' ', QString::SkipEmptyParts);
286 #else
287  QStringList tokens = msg.split(' ', Qt::SkipEmptyParts);
288 #endif
289 
290  // Return if this event is for another host
291  if ((tokens.size() >= 4) &&
292  (tokens[2] == "HOST") &&
293  (tokens[3] != gCoreContext->GetHostName()))
294  return;
295 
296  QString cmd;
297 
298  // See if this system has a command that runs for all system events
299  cmd = gCoreContext->GetSetting("EventCmdAll");
300  if (!cmd.isEmpty())
301  {
302  SubstituteMatches(tokens, cmd);
303 
304  auto *eventThread = new SystemEventThread(cmd);
306  eventThread, "SystemEvent");
307  }
308 
309  // Check for an EventCmd for this particular event
310  cmd = gCoreContext->GetSetting(EventNameToSetting(tokens[1]));
311  if (!cmd.isEmpty())
312  {
313  SubstituteMatches(tokens, cmd);
314 
315  LOG(VB_GENERAL, LOG_INFO, LOC +
316  QString("Starting thread for command '%1'").arg(cmd));
317 
318  auto *eventThread = new SystemEventThread(cmd, tokens[1]);
320  eventThread, "SystemEvent");
321  }
322  }
323 }
324 
325 /****************************************************************************/
326 
333 void SendMythSystemRecEvent(const QString &msg, const RecordingInfo *pginfo)
334 {
335  if (pginfo)
336  {
337  uint cardid = pginfo->GetInputID();
339  QString("%1 CARDID %2 CHANID %3 STARTTIME %4 RECSTATUS %5 "
340  "VIDEODEVICE %6 VBIDEVICE %7")
341  .arg(msg).arg(cardid)
342  .arg(pginfo->GetChanID())
344  .arg(pginfo->GetRecordingStatus())
345  .arg(CardUtil::GetVideoDevice(cardid),
346  CardUtil::GetVBIDevice(cardid)));
347  }
348  else
349  {
350  LOG(VB_GENERAL, LOG_ERR, LOC +
351  "SendMythSystemRecEvent() called with empty RecordingInfo");
352  }
353 }
354 
361 void SendMythSystemPlayEvent(const QString &msg, const ProgramInfo *pginfo)
362 {
363  if (pginfo)
364  {
366  QString("%1 HOSTNAME %2 CHANID %3 STARTTIME %4")
367  .arg(msg, gCoreContext->GetHostName())
368  .arg(pginfo->GetChanID())
370  }
371  else
372  {
373  LOG(VB_GENERAL, LOG_ERR, LOC + "SendMythSystemPlayEvent() called with "
374  "empty ProgramInfo");
375  }
376 }
377 
378 /****************************************************************************/
379 
392  const char *name)
393  : RawSettingsEditor(parent, name)
394 {
395  m_title = tr("System Event Command Editor");
397 
398 }
399  void MythSystemEventEditor::createSettingList(QMap <QString, QString> &settings)
400 {
401  // Event names are programmatically converted to settings names in
402  // EventNameToSetting(). For convenience of searching the code
403  // base, the event names are listed in comments.
404  settings["EventCmdRecPending"] = // REC_PENDING
405  tr("Recording pending");
406  settings["EventCmdRecPreFail"] = // REC_PREFAIL
407  tr("Recording about to fail");
408  settings["EventCmdRecFailing"] = // REC_FAILING
409  tr("Recording failing");
410  settings["EventCmdRecStarted"] = // REC_STARTED
411  tr("Recording started");
412  settings["EventCmdRecStartedWriting"] = // REC_STARTED_WRITING
413  tr("Recording started writing");
414  settings["EventCmdRecFinished"] = // REC_FINISHED
415  tr("Recording finished");
416  settings["EventCmdRecDeleted"] = // REC_DELETED
417  tr("Recording deleted");
418  settings["EventCmdRecExpired"] = // REC_EXPIRED
419  tr("Recording expired");
420  settings["EventCmdLivetvStarted"] = // LIVETV_STARTED
421  tr("LiveTV started");
422  settings["EventCmdLivetvEnded"] = // LIVETV_ENDED
423  tr("LiveTV ended");
424  settings["EventCmdPlayStarted"] = // PLAY_STARTED
425  tr("Playback started");
426  settings["EventCmdPlayStopped"] = // PLAY_STOPPED
427  tr("Playback stopped");
428  settings["EventCmdPlayPaused"] = // PLAY_PAUSED
429  tr("Playback paused");
430  settings["EventCmdPlayUnpaused"] = // PLAY_UNPAUSED
431  tr("Playback unpaused");
432  settings["EventCmdPlayChanged"] = // PLAY_CHANGED
433  tr("Playback program changed");
434  settings["EventCmdTuningSignalTimeout"] = // TUNING_SIGNAL_TIMEOUT
435  tr("Tuning signal waiting");
436  settings["EventCmdMasterStarted"] = // MASTER_STARTED
437  tr("Master backend started");
438  settings["EventCmdMasterShutdown"] = // MASTER_SHUTDOWN
439  tr("Master backend shutdown");
440  settings["EventCmdClientConnected"] = // CLIENT_CONNECTED
441  tr("Client connected to master backend");
442  settings["EventCmdClientDisconnected"] = // CLIENT_DISCONNECTED
443  tr("Client disconnected from master backend");
444  settings["EventCmdSlaveConnected"] = // SLAVE_CONNECTED
445  tr("Slave backend connected to master");
446  settings["EventCmdSlaveDisconnected"] = // SLAVE_DISCONNECTED
447  tr("Slave backend disconnected from master");
448  settings["EventCmdNetCtrlConnected"] = // NET_CTRL_CONNECTED
449  tr("Network Control client connected");
450  settings["EventCmdNetCtrlDisconnected"] = // NET_CTRL_DISCONNECTED
451  tr("Network Control client disconnected");
452  settings["EventCmdMythfilldatabaseRan"] = // MYTHFILLDATABASE_RAN
453  tr("mythfilldatabase ran");
454  settings["EventCmdSchedulerRan"] = // SCHEDULER_RAN
455  tr("Scheduler ran");
456  settings["EventCmdSettingsCacheCleared"] = // SETTINGS_CACHE_CLEARED
457  tr("Settings cache cleared");
458  settings["EventCmdScreenType"] = // SCREEN_TYPE
459  tr("Screen created or destroyed");
460  settings["EventCmdKey01"] = // KEY_%1
461  tr("Keystroke event #1");
462  settings["EventCmdKey02"] = // KEY_%1
463  tr("Keystroke event #2");
464  settings["EventCmdKey03"] = // KEY_%1
465  tr("Keystroke event #3");
466  settings["EventCmdKey04"] = // KEY_%1
467  tr("Keystroke event #4");
468  settings["EventCmdKey05"] = // KEY_%1
469  tr("Keystroke event #5");
470  settings["EventCmdKey06"] = // KEY_%1
471  tr("Keystroke event #6");
472  settings["EventCmdKey07"] = // KEY_%1
473  tr("Keystroke event #7");
474  settings["EventCmdKey08"] = // KEY_%1
475  tr("Keystroke event #8");
476  settings["EventCmdKey09"] = // KEY_%1
477  tr("Keystroke event #9");
478  settings["EventCmdKey10"] = // KEY_%1
479  tr("Keystroke event #10");
480  settings["EventCmdCecCommandReceived"] = // CEC_COMMAND_RECEIVED
481  tr("CEC command received");
482  settings["EventCmdAll"] = // EventCmdAll
483  tr("Any event");
484 }
485 
486 /* 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:1516
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:84
MythEvent::kMythEventMessage
static const Type kMythEventMessage
Definition: mythevent.h:79
RecordingInfo::kFoundProgram
@ kFoundProgram
Definition: recordinginfo.h:182
kMSDontBlockInputDevs
@ kMSDontBlockInputDevs
avoid blocking LIRC & Joystick Menu
Definition: mythsystem.h:36
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
GENERIC_EXIT_OK
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:11
MThreadPool::startReserved
void startReserved(QRunnable *runnable, const QString &debugName, std::chrono::milliseconds waitForAvailMS=0ms)
Definition: mthreadpool.cpp:371
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:404
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
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:447
MythDate::kFilename
@ kFilename
Default UTC, "yyyyMMddhhmmss".
Definition: mythdate.h:18
MythCoreContext::SendSystemEvent
void SendSystemEvent(const QString &msg)
Definition: mythcorecontext.cpp:1543
SystemEventThread::SystemEventThread
SystemEventThread(QString cmd, QString eventName="")
Constructor for creating a SystemEventThread.
Definition: mythsystemevent.cpp:38
verboseMask
uint64_t verboseMask
Definition: logging.cpp:97
uint
unsigned int uint
Definition: compat.h:81
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
RecordingInfo::LoadStatus
LoadStatus
Definition: recordinginfo.h:180
RecordingInfo::kNoProgram
@ kNoProgram
Definition: recordinginfo.h:181
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:34
SystemEventThread::m_event
QString m_event
Definition: mythsystemevent.cpp:68
ProgramInfo::GetInputID
uint GetInputID(void) const
Definition: programinfo.h:463
mthreadpool.h
ProgramInfo::GetChanID
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:372
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:1669
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:67
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:361
MythSystemEventHandler::customEvent
void customEvent(QEvent *e) override
Custom Event handler for receiving and processing System Events.
Definition: mythsystemevent.cpp:259
cardutil.h
MythSystemEventEditor::MythSystemEventEditor
MythSystemEventEditor(MythScreenStack *parent, const char *name=nullptr)
Constructor for the MythSystemEvent settings editor.
Definition: mythsystemevent.cpp:391
std
Definition: mythchrono.h:23
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
MythSystemEventEditor::createSettingList
static void createSettingList(QMap< QString, QString > &settings)
Definition: mythsystemevent.cpp:399
CardUtil::GetVBIDevice
static QString GetVBIDevice(uint inputid)
Definition: cardutil.h:298
SendMythSystemRecEvent
void SendMythSystemRecEvent(const QString &msg, const RecordingInfo *pginfo)
Definition: mythsystemevent.cpp:333
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:837
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:317
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
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:897