MythTV  master
networkcontrol.cpp
Go to the documentation of this file.
1 
2 #include "networkcontrol.h"
3 
4 #include <chrono> // for milliseconds
5 #include <thread> // for sleep_for
6 
7 #include <QCoreApplication>
8 #include <QRegularExpression>
9 #include <QStringList>
10 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
11 #include <QStringConverter>
12 #endif
13 #include <QTextStream>
14 #include <QDir>
15 #include <QKeyEvent>
16 #include <QEvent>
17 #include <QMap>
18 
19 #include "mythcorecontext.h"
20 #include "mythmiscutil.h"
21 #include "mythversion.h"
22 #include "programinfo.h"
23 #include "remoteutil.h"
24 #include "previewgenerator.h"
25 #include "compat.h"
26 #include "mythsystemevent.h"
27 #include "mythdirs.h"
28 #include "mythlogging.h"
29 
30 // libmythui
31 #include "mythmainwindow.h"
32 #include "mythuihelper.h"
33 #include "mythuigroup.h"
34 #include "mythuiclock.h"
35 #include "mythuishape.h"
36 #include "mythuibutton.h"
37 #include "mythuitextedit.h"
38 #include "mythuibuttontree.h"
39 #include "mythuivideo.h"
40 #include "mythuiguidegrid.h"
41 #include "mythuicheckbox.h"
42 #include "mythuispinbox.h"
43 
44 #if CONFIG_QTWEBKIT
45 #include "mythuiwebbrowser.h"
46 #endif
47 
48 #include "mythuiprogressbar.h"
49 #include "mythuiscrollbar.h"
50 #include "mythuieditbar.h"
51 #include "mythuiimage.h"
52 
53 #define LOC QString("NetworkControl: ")
54 #define LOC_ERR QString("NetworkControl Error: ")
55 
56 #define FE_SHORT_TO 2000
57 #define FE_LONG_TO 10000
58 
59 static QEvent::Type kNetworkControlDataReadyEvent =
60  (QEvent::Type) QEvent::registerEventType();
62  (QEvent::Type) QEvent::registerEventType();
63 
71 static bool is_abbrev(QString const& command,
72  QString const& test, int minchars = 1)
73 {
74  if (test.length() < minchars)
75  return command.toLower() == test.toLower();
76  return test.toLower() == command.left(test.length()).toLower();
77 }
78 
80  m_commandThread(new MThread("NetworkControl", this))
81 {
82  // Eventually this map should be in the jumppoints table
83  m_jumpMap["channelpriorities"] = "Channel Recording Priorities";
84  m_jumpMap["livetv"] = "Live TV";
85  m_jumpMap["mainmenu"] = "Main Menu";
86  m_jumpMap["managerecordings"] = "Manage Recordings / Fix Conflicts";
87  m_jumpMap["mythgallery"] = "MythGallery";
88  m_jumpMap["mythvideo"] = "Video Default";
89  m_jumpMap["mythweather"] = "MythWeather";
90  m_jumpMap["mythgame"] = "MythGame";
91  m_jumpMap["mythnews"] = "MythNews";
92  m_jumpMap["playdvd"] = "Play Disc";
93  m_jumpMap["playmusic"] = "Play music";
94  m_jumpMap["playlistview"] = "Play music";
95  m_jumpMap["programfinder"] = "Program Finder";
96  m_jumpMap["programguide"] = "Program Guide";
97  m_jumpMap["ripcd"] = "Rip CD";
98  m_jumpMap["musicplaylists"] = "Select music playlists";
99  m_jumpMap["playbackrecordings"] = "TV Recording Playback";
100  m_jumpMap["videobrowser"] = "Video Browser";
101  m_jumpMap["videogallery"] = "Video Gallery";
102  m_jumpMap["videolistings"] = "Video Listings";
103  m_jumpMap["videomanager"] = "Video Manager";
104  m_jumpMap["zoneminderconsole"] = "ZoneMinder Console";
105  m_jumpMap["zoneminderliveview"] = "ZoneMinder Live View";
106  m_jumpMap["zoneminderevents"] = "ZoneMinder Events";
107 
108  m_jumpMap["channelrecpriority"] = "Channel Recording Priorities";
109  m_jumpMap["viewscheduled"] = "Manage Recordings / Fix Conflicts";
110  m_jumpMap["previousbox"] = "Previously Recorded";
111  m_jumpMap["progfinder"] = "Program Finder";
112  m_jumpMap["guidegrid"] = "Program Guide";
113  m_jumpMap["managerecrules"] = "Manage Recording Rules";
114  m_jumpMap["statusbox"] = "Status Screen";
115  m_jumpMap["playbackbox"] = "TV Recording Playback";
116  m_jumpMap["pbb"] = "TV Recording Playback";
117 
118  m_jumpMap["reloadtheme"] = "Reload Theme";
119  m_jumpMap["showborders"] = "Toggle Show Widget Borders";
120  m_jumpMap["shownames"] = "Toggle Show Widget Names";
121 
122  m_keyMap["up"] = Qt::Key_Up;
123  m_keyMap["down"] = Qt::Key_Down;
124  m_keyMap["left"] = Qt::Key_Left;
125  m_keyMap["right"] = Qt::Key_Right;
126  m_keyMap["home"] = Qt::Key_Home;
127  m_keyMap["end"] = Qt::Key_End;
128  m_keyMap["enter"] = Qt::Key_Enter;
129  m_keyMap["return"] = Qt::Key_Return;
130  m_keyMap["pageup"] = Qt::Key_PageUp;
131  m_keyMap["pagedown"] = Qt::Key_PageDown;
132  m_keyMap["escape"] = Qt::Key_Escape;
133  m_keyMap["tab"] = Qt::Key_Tab;
134  m_keyMap["backtab"] = Qt::Key_Backtab;
135  m_keyMap["space"] = Qt::Key_Space;
136  m_keyMap["backspace"] = Qt::Key_Backspace;
137  m_keyMap["insert"] = Qt::Key_Insert;
138  m_keyMap["delete"] = Qt::Key_Delete;
139  m_keyMap["plus"] = Qt::Key_Plus;
140  m_keyMap["+"] = Qt::Key_Plus;
141  m_keyMap["comma"] = Qt::Key_Comma;
142  m_keyMap[","] = Qt::Key_Comma;
143  m_keyMap["minus"] = Qt::Key_Minus;
144  m_keyMap["-"] = Qt::Key_Minus;
145  m_keyMap["underscore"] = Qt::Key_Underscore;
146  m_keyMap["_"] = Qt::Key_Underscore;
147  m_keyMap["period"] = Qt::Key_Period;
148  m_keyMap["."] = Qt::Key_Period;
149  m_keyMap["numbersign"] = Qt::Key_NumberSign;
150  m_keyMap["poundsign"] = Qt::Key_NumberSign;
151  m_keyMap["hash"] = Qt::Key_NumberSign;
152  m_keyMap["#"] = Qt::Key_NumberSign;
153  m_keyMap["bracketleft"] = Qt::Key_BracketLeft;
154  m_keyMap["["] = Qt::Key_BracketLeft;
155  m_keyMap["bracketright"] = Qt::Key_BracketRight;
156  m_keyMap["]"] = Qt::Key_BracketRight;
157  m_keyMap["backslash"] = Qt::Key_Backslash;
158  m_keyMap["\\"] = Qt::Key_Backslash;
159  m_keyMap["dollar"] = Qt::Key_Dollar;
160  m_keyMap["$"] = Qt::Key_Dollar;
161  m_keyMap["percent"] = Qt::Key_Percent;
162  m_keyMap["%"] = Qt::Key_Percent;
163  m_keyMap["ampersand"] = Qt::Key_Ampersand;
164  m_keyMap["&"] = Qt::Key_Ampersand;
165  m_keyMap["parenleft"] = Qt::Key_ParenLeft;
166  m_keyMap["("] = Qt::Key_ParenLeft;
167  m_keyMap["parenright"] = Qt::Key_ParenRight;
168  m_keyMap[")"] = Qt::Key_ParenRight;
169  m_keyMap["asterisk"] = Qt::Key_Asterisk;
170  m_keyMap["*"] = Qt::Key_Asterisk;
171  m_keyMap["question"] = Qt::Key_Question;
172  m_keyMap["?"] = Qt::Key_Question;
173  m_keyMap["slash"] = Qt::Key_Slash;
174  m_keyMap["/"] = Qt::Key_Slash;
175  m_keyMap["colon"] = Qt::Key_Colon;
176  m_keyMap[":"] = Qt::Key_Colon;
177  m_keyMap["semicolon"] = Qt::Key_Semicolon;
178  m_keyMap[";"] = Qt::Key_Semicolon;
179  m_keyMap["less"] = Qt::Key_Less;
180  m_keyMap["<"] = Qt::Key_Less;
181  m_keyMap["equal"] = Qt::Key_Equal;
182  m_keyMap["="] = Qt::Key_Equal;
183  m_keyMap["greater"] = Qt::Key_Greater;
184  m_keyMap[">"] = Qt::Key_Greater;
185  m_keyMap["bar"] = Qt::Key_Bar;
186  m_keyMap["pipe"] = Qt::Key_Bar;
187  m_keyMap["|"] = Qt::Key_Bar;
188  m_keyMap["f1"] = Qt::Key_F1;
189  m_keyMap["f2"] = Qt::Key_F2;
190  m_keyMap["f3"] = Qt::Key_F3;
191  m_keyMap["f4"] = Qt::Key_F4;
192  m_keyMap["f5"] = Qt::Key_F5;
193  m_keyMap["f6"] = Qt::Key_F6;
194  m_keyMap["f7"] = Qt::Key_F7;
195  m_keyMap["f8"] = Qt::Key_F8;
196  m_keyMap["f9"] = Qt::Key_F9;
197  m_keyMap["f10"] = Qt::Key_F10;
198  m_keyMap["f11"] = Qt::Key_F11;
199  m_keyMap["f12"] = Qt::Key_F12;
200  m_keyMap["f13"] = Qt::Key_F13;
201  m_keyMap["f14"] = Qt::Key_F14;
202  m_keyMap["f15"] = Qt::Key_F15;
203  m_keyMap["f16"] = Qt::Key_F16;
204  m_keyMap["f17"] = Qt::Key_F17;
205  m_keyMap["f18"] = Qt::Key_F18;
206  m_keyMap["f19"] = Qt::Key_F19;
207  m_keyMap["f20"] = Qt::Key_F20;
208  m_keyMap["f21"] = Qt::Key_F21;
209  m_keyMap["f22"] = Qt::Key_F22;
210  m_keyMap["f23"] = Qt::Key_F23;
211  m_keyMap["f24"] = Qt::Key_F24;
212 
213  m_keyTextMap[Qt::Key_Space] = " ";
214  m_keyTextMap[Qt::Key_Plus] = "+";
215  m_keyTextMap[Qt::Key_Comma] = ",";
216  m_keyTextMap[Qt::Key_Minus] = "-";
217  m_keyTextMap[Qt::Key_Underscore] = "_";
218  m_keyTextMap[Qt::Key_Period] = ".";
219  m_keyTextMap[Qt::Key_NumberSign] = "#";
220  m_keyTextMap[Qt::Key_BracketLeft] = "[";
221  m_keyTextMap[Qt::Key_BracketRight] = "]";
222  m_keyTextMap[Qt::Key_Backslash] = "\\";
223  m_keyTextMap[Qt::Key_Dollar] = "$";
224  m_keyTextMap[Qt::Key_Percent] = "%";
225  m_keyTextMap[Qt::Key_Ampersand] = "&";
226  m_keyTextMap[Qt::Key_ParenLeft] = "(";
227  m_keyTextMap[Qt::Key_ParenRight] = ")";
228  m_keyTextMap[Qt::Key_Asterisk] = "*";
229  m_keyTextMap[Qt::Key_Question] = "?";
230  m_keyTextMap[Qt::Key_Slash] = "/";
231  m_keyTextMap[Qt::Key_Colon] = ":";
232  m_keyTextMap[Qt::Key_Semicolon] = ";";
233  m_keyTextMap[Qt::Key_Less] = "<";
234  m_keyTextMap[Qt::Key_Equal] = "=";
235  m_keyTextMap[Qt::Key_Greater] = ">";
236  m_keyTextMap[Qt::Key_Bar] = "|";
237 
239 
240  gCoreContext->addListener(this);
241 
242  connect(this, &ServerPool::newConnection,
244 }
245 
247 {
249 
250  m_clientLock.lock();
251  while (!m_clients.isEmpty())
252  {
253  NetworkControlClient *ncc = m_clients.takeFirst();
254  delete ncc;
255  }
256  m_clientLock.unlock();
257 
258  m_nrLock.lock();
259  m_networkControlReplies.push_back(new NetworkCommand(nullptr,
260  "mythfrontend shutting down, connection closing..."));
261  m_nrLock.unlock();
262 
264 
265  m_ncLock.lock();
266  m_stopCommandThread = true;
267  m_ncCond.wakeOne();
268  m_ncLock.unlock();
270  delete m_commandThread;
271  m_commandThread = nullptr;
272 }
273 
275 {
276  QMutexLocker locker(&m_ncLock);
277  while (!m_stopCommandThread)
278  {
280  m_ncCond.wait(&m_ncLock);
281  if (!m_stopCommandThread)
282  {
284  m_networkControlCommands.pop_front();
285  locker.unlock();
287  locker.relock();
288  }
289  }
290 }
291 
293 {
294  QMutexLocker locker(&m_clientLock);
295  QString result;
296 
297  int clientID = m_clients.indexOf(nc->getClient());
298 
299  if (is_abbrev("jump", nc->getArg(0)))
300  result = processJump(nc);
301  else if (is_abbrev("key", nc->getArg(0)))
302  result = processKey(nc);
303  else if (is_abbrev("play", nc->getArg(0)))
304  result = processPlay(nc, clientID);
305  else if (is_abbrev("query", nc->getArg(0)))
306  result = processQuery(nc);
307  else if (is_abbrev("set", nc->getArg(0)))
308  result = processSet(nc);
309  else if (is_abbrev("screenshot", nc->getArg(0)))
310  result = saveScreenshot(nc);
311  else if (is_abbrev("help", nc->getArg(0)))
312  result = processHelp(nc);
313  else if (is_abbrev("message", nc->getArg(0)))
314  result = processMessage(nc);
315  else if (is_abbrev("notification", nc->getArg(0)))
316  result = processNotification(nc);
317  else if (is_abbrev("theme", nc->getArg(0)))
318  result = processTheme(nc);
319  else if ((nc->getArg(0).toLower() == "exit") || (nc->getArg(0).toLower() == "quit"))
320  {
321  QCoreApplication::postEvent(this,
323  }
324  else if (! nc->getArg(0).isEmpty())
325  {
326  result = QString("INVALID command '%1', try 'help' for more info")
327  .arg(nc->getArg(0));
328  }
329 
330  m_nrLock.lock();
331  m_networkControlReplies.push_back(new NetworkCommand(nc->getClient(),result));
332  m_nrLock.unlock();
333 
335 }
336 
338 {
339  LOG(VB_GENERAL, LOG_INFO, LOC + "Client Socket disconnected");
340  QMutexLocker locker(&m_clientLock);
341 
342  gCoreContext->SendSystemEvent("NET_CTRL_DISCONNECTED");
343 
344  for (auto * ncc : qAsConst(m_clients))
345  {
346  if (ncc->getSocket()->state() == QTcpSocket::UnconnectedState)
347  {
348  deleteClient(ncc);
349  return;
350  }
351  }
352 }
353 
355 {
356  int index = m_clients.indexOf(ncc);
357  if (index >= 0)
358  {
359  m_clients.removeAt(index);
360 
361  delete ncc;
362  }
363  else
364  LOG(VB_GENERAL, LOG_ERR, LOC + QString("deleteClient(%1), unable to "
365  "locate specified NetworkControlClient").arg((long long)ncc));
366 }
367 
368 void NetworkControl::newControlConnection(QTcpSocket *client)
369 {
370  QString welcomeStr;
371 
372  LOG(VB_GENERAL, LOG_INFO, LOC + QString("New connection established."));
373 
374  gCoreContext->SendSystemEvent("NET_CTRL_CONNECTED");
375 
376  auto *ncc = new NetworkControlClient(client);
377 
378  QMutexLocker locker(&m_clientLock);
379  m_clients.push_back(ncc);
380 
383  connect(client, &QAbstractSocket::disconnected,
384  this, qOverload<>(&NetworkControl::deleteClient));
385 
386  welcomeStr = "MythFrontend Network Control\r\n";
387  welcomeStr += "Type 'help' for usage information\r\n"
388  "---------------------------------";
389  m_nrLock.lock();
390  m_networkControlReplies.push_back(new NetworkCommand(ncc,welcomeStr));
391  m_nrLock.unlock();
392 
394 }
395 
397 {
398  m_socket = s;
399  m_textStream = new QTextStream(s);
400 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
401  m_textStream->setCodec("UTF-8");
402 #else
403  m_textStream->setEncoding(QStringConverter::Utf8);
404 #endif
405  connect(m_socket, &QIODevice::readyRead, this, &NetworkControlClient::readClient);
406 }
407 
409 {
410  m_socket->close();
411  m_socket->deleteLater();
412 
413  delete m_textStream;
414 }
415 
417 {
418  auto *socket = (QTcpSocket *)sender();
419  if (!socket)
420  return;
421 
422  while (socket->canReadLine())
423  {
424  QString lineIn = socket->readLine();
425 #if 0
426  static const QRegularExpression badChars
427  { "[^-a-zA-Z0-9\\s\\.:_#/$%&()*+,;<=>?\\[\\]\\|]" };
428  lineIn.remove(badChars);
429 #endif
430 
431  lineIn = lineIn.simplified();
432  if (lineIn.isEmpty())
433  continue;
434 
435  LOG(VB_NETWORK, LOG_INFO, LOC +
436  QString("emit commandReceived(%1)").arg(lineIn));
437  emit commandReceived(lineIn);
438  }
439 }
440 
441 void NetworkControl::receiveCommand(QString &command)
442 {
443  LOG(VB_NETWORK, LOG_INFO, LOC +
444  QString("NetworkControl::receiveCommand(%1)").arg(command));
445  auto *ncc = qobject_cast<NetworkControlClient *>(sender());
446  if (!ncc)
447  return;
448 
449  m_ncLock.lock();
450  m_networkControlCommands.push_back(new NetworkCommand(ncc,command));
451  m_ncCond.wakeOne();
452  m_ncLock.unlock();
453 }
454 
456 {
457  QString result = "OK";
458 
459  if ((nc->getArgCount() < 2) || (!m_jumpMap.contains(nc->getArg(1))))
460  return QString("ERROR: See 'help %1' for usage information")
461  .arg(nc->getArg(0));
462 
464 
465  // Fixme, should do some better checking here, but that would
466  // depend on all Locations matching their jumppoints
467  QElapsedTimer timer;
468  timer.start();
469  while (!timer.hasExpired(FE_SHORT_TO) &&
470  (GetMythUI()->GetCurrentLocation().toLower() != nc->getArg(1)))
471  std::this_thread::sleep_for(10ms);
472 
473  return result;
474 }
475 
477 {
478  QString result = "OK";
479  QKeyEvent *event = nullptr;
480 
481  if (nc->getArgCount() < 2)
482  return QString("ERROR: See 'help %1' for usage information")
483  .arg(nc->getArg(0));
484 
485  QObject *keyDest = nullptr;
486 
487  if (GetMythMainWindow())
488  keyDest = GetMythMainWindow();
489  else
490  return QString("ERROR: Application has no main window!\n");
491 
492  int curToken = 1;
493  while (curToken < nc->getArgCount())
494  {
495  int tokenLen = nc->getArg(curToken).length();
496 
497  if (nc->getArg(curToken) == "sleep")
498  {
499  std::this_thread::sleep_for(1s);
500  }
501  else if (m_keyMap.contains(nc->getArg(curToken)))
502  {
503  int keyCode = m_keyMap[nc->getArg(curToken)];
504  QString keyText;
505 
506  if (m_keyTextMap.contains(keyCode))
507  keyText = m_keyTextMap[keyCode];
508 
510 
511  event = new QKeyEvent(QEvent::KeyPress, keyCode, Qt::NoModifier,
512  keyText);
513  QCoreApplication::postEvent(keyDest, event);
514 
515  event = new QKeyEvent(QEvent::KeyRelease, keyCode, Qt::NoModifier,
516  keyText);
517  QCoreApplication::postEvent(keyDest, event);
518  }
519  else if (((tokenLen == 1) &&
520  (nc->getArg(curToken).at(0).isLetterOrNumber())) ||
521  ((tokenLen >= 1) &&
522  (nc->getArg(curToken).contains("+"))))
523  {
524  QKeySequence a(nc->getArg(curToken));
525 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
526  int keyCode = a[0];
527  Qt::KeyboardModifiers modifiers = Qt::NoModifier;
528 
529  if (tokenLen > 1)
530  {
531  QStringList tokenParts = nc->getArg(curToken).split('+');
532 
533  int partNum = 0;
534  while (partNum < (tokenParts.size() - 1))
535  {
536  if (tokenParts[partNum].toUpper() == "CTRL")
537  modifiers |= Qt::ControlModifier;
538  if (tokenParts[partNum].toUpper() == "SHIFT")
539  modifiers |= Qt::ShiftModifier;
540  if (tokenParts[partNum].toUpper() == "ALT")
541  modifiers |= Qt::AltModifier;
542  if (tokenParts[partNum].toUpper() == "META")
543  modifiers |= Qt::MetaModifier;
544 
545  partNum++;
546  }
547  }
548 #else
549  int keyCode = a[0].key();
550  Qt::KeyboardModifiers modifiers = a[0].keyboardModifiers();
551 #endif
552  if (tokenLen == 1)
553  {
554  if (nc->getArg(curToken) == nc->getArg(curToken).toUpper())
555  modifiers |= Qt::ShiftModifier;
556  }
557 
559 
560  event = new QKeyEvent(QEvent::KeyPress, keyCode, modifiers,
561  nc->getArg(curToken));
562  QCoreApplication::postEvent(keyDest, event);
563 
564  event = new QKeyEvent(QEvent::KeyRelease, keyCode, modifiers,
565  nc->getArg(curToken));
566  QCoreApplication::postEvent(keyDest, event);
567  }
568  else
569  {
570  return QString("ERROR: Invalid syntax at '%1', see 'help %2' for "
571  "usage information")
572  .arg(nc->getArg(curToken), nc->getArg(0));
573  }
574 
575  curToken++;
576  }
577 
578  return result;
579 }
580 
581 QString NetworkControl::processPlay(NetworkCommand *nc, int clientID)
582 {
583  QString result = "OK";
584  QString message;
585 
586  if (nc->getArgCount() < 2)
587  return QString("ERROR: See 'help %1' for usage information")
588  .arg(nc->getArg(0));
589 
590  if ((nc->getArgCount() >= 3) &&
591  (is_abbrev("file", nc->getArg(1))))
592  {
593  if (GetMythUI()->GetCurrentLocation().toLower() != "mainmenu")
594  {
595  GetMythMainWindow()->JumpTo(m_jumpMap["mainmenu"]);
596 
597  QElapsedTimer timer;
598  timer.start();
599  while (!timer.hasExpired(FE_LONG_TO) &&
600  (GetMythUI()->GetCurrentLocation().toLower() != "mainmenu"))
601  std::this_thread::sleep_for(10ms);
602  }
603 
604  if (GetMythUI()->GetCurrentLocation().toLower() == "mainmenu")
605  {
606  QStringList args;
607  args << nc->getFrom(2);
608  auto *me = new MythEvent(ACTION_HANDLEMEDIA, args);
609  qApp->postEvent(GetMythMainWindow(), me);
610  }
611  else
612  return QString("Unable to change to main menu to start playback!");
613  }
614  else if ((nc->getArgCount() >= 4) &&
615  (is_abbrev("program", nc->getArg(1))) &&
616  (nc->getArg(2).contains(QRegularExpression("^\\d+$"))) &&
617  (nc->getArg(3).contains(QRegularExpression(
618  R"(^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ?$)"))))
619  {
620  if (GetMythUI()->GetCurrentLocation().toLower() == "playback")
621  {
622  QString msg = QString("NETWORK_CONTROL STOP");
623  MythEvent me(msg);
624  gCoreContext->dispatch(me);
625 
626  QElapsedTimer timer;
627  timer.start();
628  while (!timer.hasExpired(FE_LONG_TO) &&
629  (GetMythUI()->GetCurrentLocation().toLower() == "playback"))
630  std::this_thread::sleep_for(10ms);
631  }
632 
633  if (GetMythUI()->GetCurrentLocation().toLower() != "playbackbox")
634  {
635  GetMythMainWindow()->JumpTo(m_jumpMap["playbackbox"]);
636 
637  QElapsedTimer timer;
638  timer.start();
639  while (!timer.hasExpired(10000) &&
640  (GetMythUI()->GetCurrentLocation().toLower() != "playbackbox"))
641  std::this_thread::sleep_for(10ms);
642 
643  timer.start();
644  while (!timer.hasExpired(10000) && (!MythMainWindow::IsTopScreenInitialized()))
645  std::this_thread::sleep_for(10ms);
646  }
647 
648  if (GetMythUI()->GetCurrentLocation().toLower() == "playbackbox")
649  {
650  QString action = "PLAY";
651  if (nc->getArgCount() == 5 && nc->getArg(4) == "resume")
652  action = "RESUME";
653 
654  QString msg = QString("NETWORK_CONTROL %1 PROGRAM %2 %3 %4")
655  .arg(action, nc->getArg(2),
656  nc->getArg(3).toUpper(),
657  QString::number(clientID));
658 
659  result.clear();
660  m_gotAnswer = false;
661  QElapsedTimer timer;
662  timer.start();
663 
664  MythEvent me(msg);
665  gCoreContext->dispatch(me);
666 
667  while (!timer.hasExpired(FE_LONG_TO) && !m_gotAnswer)
668  std::this_thread::sleep_for(10ms);
669 
670  if (m_gotAnswer)
671  result += m_answer;
672  else
673  result = "ERROR: Timed out waiting for reply from player";
674 
675  }
676  else
677  {
678  result = QString("ERROR: Unable to change to PlaybackBox from "
679  "%1, cannot play requested file.")
680  .arg(GetMythUI()->GetCurrentLocation());
681  }
682  }
683  else if (is_abbrev("music", nc->getArg(1)))
684  {
685 #if 0
686  if (GetMythUI()->GetCurrentLocation().toLower() != "playmusic")
687  {
688  return QString("ERROR: You are in %1 mode and this command is "
689  "only for MythMusic")
690  .arg(GetMythUI()->GetCurrentLocation());
691  }
692 #endif
693 
694  QString hostname = gCoreContext->GetHostName();
695 
696  if (nc->getArgCount() == 3)
697  {
698  if (is_abbrev("play", nc->getArg(2)))
699  message = QString("MUSIC_COMMAND %1 PLAY").arg(hostname);
700  else if (is_abbrev("pause", nc->getArg(2)))
701  message = QString("MUSIC_COMMAND %1 PAUSE").arg(hostname);
702  else if (is_abbrev("stop", nc->getArg(2)))
703  message = QString("MUSIC_COMMAND %1 STOP").arg(hostname);
704  else if (is_abbrev("getvolume", nc->getArg(2)))
705  {
706  m_gotAnswer = false;
707 
708  MythEvent me(QString("MUSIC_COMMAND %1 GET_VOLUME").arg(hostname));
709  gCoreContext->dispatch(me);
710 
711  QElapsedTimer timer;
712  timer.start();
713  while (!timer.hasExpired(FE_SHORT_TO) && !m_gotAnswer)
714  {
715  qApp->processEvents();
716  std::this_thread::sleep_for(10ms);
717  }
718 
719  if (m_gotAnswer)
720  return m_answer;
721 
722  return "unknown";
723  }
724  else if (is_abbrev("getmeta", nc->getArg(2)))
725  {
726  m_gotAnswer = false;
727 
728  MythEvent me(QString("MUSIC_COMMAND %1 GET_METADATA").arg(hostname));
729  gCoreContext->dispatch(me);
730 
731  QElapsedTimer timer;
732  timer.start();
733  while (!timer.hasExpired(FE_SHORT_TO) && !m_gotAnswer)
734  {
735  qApp->processEvents();
736  std::this_thread::sleep_for(10ms);
737  }
738 
739  if (m_gotAnswer)
740  return m_answer;
741 
742  return "unknown";
743  }
744  else if (is_abbrev("getstatus", nc->getArg(2)))
745  {
746  m_gotAnswer = false;
747 
748  MythEvent me(QString("MUSIC_COMMAND %1 GET_STATUS").arg(hostname));
749  gCoreContext->dispatch(me);
750 
751  QElapsedTimer timer;
752  timer.start();
753  while (!timer.hasExpired(FE_SHORT_TO) && !m_gotAnswer)
754  {
755  qApp->processEvents();
756  std::this_thread::sleep_for(10ms);
757  }
758 
759  if (m_gotAnswer)
760  return m_answer;
761 
762  return "unknown";
763  }
764  else
765  return QString("ERROR: Invalid 'play music' command");
766  }
767  else if (nc->getArgCount() > 3)
768  {
769  if (is_abbrev("setvolume", nc->getArg(2)))
770  {
771  message = QString("MUSIC_COMMAND %1 SET_VOLUME %2")
772  .arg(hostname, nc->getArg(3));
773  }
774  else if (is_abbrev("track", nc->getArg(2)))
775  {
776  message = QString("MUSIC_COMMAND %1 PLAY_TRACK %2")
777  .arg(hostname, nc->getArg(3));
778  }
779  else if (is_abbrev("url", nc->getArg(2)))
780  {
781  message = QString("MUSIC_COMMAND %1 PLAY_URL %2")
782  .arg(hostname, nc->getArg(3));
783  }
784  else if (is_abbrev("file", nc->getArg(2)))
785  {
786  message = QString("MUSIC_COMMAND %1 PLAY_FILE '%2'")
787  .arg(hostname, nc->getFrom(3));
788  }
789  else
790  {
791  return QString("ERROR: Invalid 'play music' command");
792  }
793  }
794  else
795  return QString("ERROR: Invalid 'play music' command");
796  }
797  // Everything below here requires us to be in playback mode so check to
798  // see if we are
799  else if (GetMythUI()->GetCurrentLocation().toLower() != "playback")
800  {
801  return QString("ERROR: You are in %1 mode and this command is only "
802  "for playback mode")
803  .arg(GetMythUI()->GetCurrentLocation());
804  }
805  else if (is_abbrev("chanid", nc->getArg(1), 5))
806  {
807  if (nc->getArg(2).contains(QRegularExpression("^\\d+$")))
808  message = QString("NETWORK_CONTROL CHANID %1").arg(nc->getArg(2));
809  else
810  return QString("ERROR: See 'help %1' for usage information")
811  .arg(nc->getArg(0));
812  }
813  else if (is_abbrev("channel", nc->getArg(1), 5))
814  {
815  if (nc->getArgCount() < 3)
816  return "ERROR: See 'help play' for usage information";
817 
818  if (is_abbrev("up", nc->getArg(2)))
819  message = "NETWORK_CONTROL CHANNEL UP";
820  else if (is_abbrev("down", nc->getArg(2)))
821  message = "NETWORK_CONTROL CHANNEL DOWN";
822  else if (nc->getArg(2).contains(QRegularExpression("^[-\\.\\d_#]+$")))
823  message = QString("NETWORK_CONTROL CHANNEL %1").arg(nc->getArg(2));
824  else
825  return QString("ERROR: See 'help %1' for usage information")
826  .arg(nc->getArg(0));
827  }
828  else if (is_abbrev("seek", nc->getArg(1), 2))
829  {
830  if (nc->getArgCount() < 3)
831  return QString("ERROR: See 'help %1' for usage information")
832  .arg(nc->getArg(0));
833 
834  if (is_abbrev("beginning", nc->getArg(2)))
835  message = "NETWORK_CONTROL SEEK BEGINNING";
836  else if (is_abbrev("forward", nc->getArg(2)))
837  message = "NETWORK_CONTROL SEEK FORWARD";
838  else if (is_abbrev("rewind", nc->getArg(2)) ||
839  is_abbrev("backward", nc->getArg(2)))
840  message = "NETWORK_CONTROL SEEK BACKWARD";
841  else if (nc->getArg(2).contains(QRegularExpression(R"(^\d\d:\d\d:\d\d$)")))
842  {
843  int hours = nc->getArg(2).mid(0, 2).toInt();
844  int minutes = nc->getArg(2).mid(3, 2).toInt();
845  int seconds = nc->getArg(2).mid(6, 2).toInt();
846  message = QString("NETWORK_CONTROL SEEK POSITION %1")
847  .arg((hours * 3600) + (minutes * 60) + seconds);
848  }
849  else
850  return QString("ERROR: See 'help %1' for usage information")
851  .arg(nc->getArg(0));
852  }
853  else if (is_abbrev("speed", nc->getArg(1), 2))
854  {
855  if (nc->getArgCount() < 3)
856  return QString("ERROR: See 'help %1' for usage information")
857  .arg(nc->getArg(0));
858 
859  QString token2 = nc->getArg(2).toLower();
860  if ((token2.contains(QRegularExpression(R"(^\-*\d+x$)"))) ||
861  (token2.contains(QRegularExpression(R"(^\-*\d+\/\d+x$)"))) ||
862  (token2.contains(QRegularExpression(R"(^\-*\d*\.\d+x$)"))))
863  message = QString("NETWORK_CONTROL SPEED %1").arg(token2);
864  else if (is_abbrev("normal", token2))
865  message = QString("NETWORK_CONTROL SPEED normal");
866  else if (is_abbrev("pause", token2))
867  message = QString("NETWORK_CONTROL SPEED 0x");
868  else
869  return QString("ERROR: See 'help %1' for usage information")
870  .arg(nc->getArg(0));
871  }
872  else if (is_abbrev("save", nc->getArg(1), 2))
873  {
874  if (is_abbrev("screenshot", nc->getArg(2), 2))
875  return saveScreenshot(nc);
876  }
877  else if (is_abbrev("stop", nc->getArg(1), 2))
878  message = QString("NETWORK_CONTROL STOP");
879  else if (is_abbrev("volume", nc->getArg(1), 2))
880  {
881  if ((nc->getArgCount() < 3) ||
882  (!nc->getArg(2).toLower().contains(QRegularExpression("^\\d+%?$"))))
883  {
884  return QString("ERROR: See 'help %1' for usage information")
885  .arg(nc->getArg(0));
886  }
887 
888  message = QString("NETWORK_CONTROL VOLUME %1")
889  .arg(nc->getArg(2).toLower());
890  }
891  else if (is_abbrev("subtitles", nc->getArg(1), 2))
892  {
893  if (nc->getArgCount() < 3)
894  message = QString("NETWORK_CONTROL SUBTITLES 0");
895  else if (!nc->getArg(2).toLower().contains(QRegularExpression("^\\d+$")))
896  {
897  return QString("ERROR: See 'help %1' for usage information")
898  .arg(nc->getArg(0));
899  }
900  else
901  {
902  message = QString("NETWORK_CONTROL SUBTITLES %1")
903  .arg(nc->getArg(2));
904  }
905  }
906  else
907  return QString("ERROR: See 'help %1' for usage information")
908  .arg(nc->getArg(0));
909 
910  if (!message.isEmpty())
911  {
912  MythEvent me(message);
913  gCoreContext->dispatch(me);
914  }
915 
916  return result;
917 }
918 
920 {
921  QString result = "OK";
922 
923  if (nc->getArgCount() < 2)
924  return QString("ERROR: See 'help %1' for usage information")
925  .arg(nc->getArg(0));
926 
927  if (is_abbrev("location", nc->getArg(1)))
928  {
929  bool fullPath = false;
930  bool mainStackOnly = true;
931 
932  if (nc->getArgCount() > 2)
933  fullPath = (nc->getArg(2).toLower() == "true" || nc->getArg(2) == "1");
934  if (nc->getArgCount() > 3)
935  mainStackOnly = (nc->getArg(3).toLower() == "true" || nc->getArg(3) == "1");
936 
937  QString location = GetMythUI()->GetCurrentLocation(fullPath, mainStackOnly);
938  result = location;
939 
940  // if we're playing something, then find out what
941  if (location == "Playback")
942  {
943  result += " ";
944  m_gotAnswer = false;
945  QString message = QString("NETWORK_CONTROL QUERY POSITION");
946  MythEvent me(message);
947  gCoreContext->dispatch(me);
948 
949  QElapsedTimer timer;
950  timer.start();
951  while (!timer.hasExpired(FE_SHORT_TO) && !m_gotAnswer)
952  std::this_thread::sleep_for(10ms);
953 
954  if (m_gotAnswer)
955  result += m_answer;
956  else
957  result = "ERROR: Timed out waiting for reply from player";
958  }
959  }
960  else if (is_abbrev("verbose", nc->getArg(1)))
961  {
962  return verboseString;
963  }
964  else if (is_abbrev("liveTV", nc->getArg(1)))
965  {
966  if(nc->getArgCount() == 3) // has a channel ID
967  return listSchedule(nc->getArg(2));
968  return listSchedule();
969  }
970  else if (is_abbrev("version", nc->getArg(1)))
971  {
972  int dbSchema = gCoreContext->GetNumSetting("DBSchemaVer");
973 
974  return QString("VERSION: %1/%2 %3 %4 QT/%5 DBSchema/%6")
975  .arg(GetMythSourceVersion(),
979  QT_VERSION_STR,
980  QString::number(dbSchema));
981 
982  }
983  else if(is_abbrev("time", nc->getArg(1)))
985  else if (is_abbrev("uptime", nc->getArg(1)))
986  {
987  QString str;
988  std::chrono::seconds uptime = 0s;
989 
990  if (getUptime(uptime))
991  str = QString::number(uptime.count());
992  else
993  str = QString("Could not determine uptime.");
994  return str;
995  }
996  else if (is_abbrev("load", nc->getArg(1)))
997  {
998  QString str;
999  loadArray loads = getLoadAvgs();
1000  if (loads[0] == -1)
1001  str = QString("getloadavg() failed");
1002  else
1003  str = QString("%1 %2 %3").arg(loads[0]).arg(loads[1]).arg(loads[2]);
1004  return str;
1005  }
1006  else if (is_abbrev("memstats", nc->getArg(1)))
1007  {
1008  QString str;
1009  int totalMB = 0;
1010  int freeMB = 0;
1011  int totalVM = 0;
1012  int freeVM = 0;
1013 
1014  if (getMemStats(totalMB, freeMB, totalVM, freeVM))
1015  {
1016  str = QString("%1 %2 %3 %4")
1017  .arg(totalMB).arg(freeMB).arg(totalVM).arg(freeVM);
1018  }
1019  else
1020  {
1021  str = QString("Could not determine memory stats.");
1022  }
1023  return str;
1024  }
1025  else if (is_abbrev("volume", nc->getArg(1)))
1026  {
1027  QString str = "0%";
1028 
1029  QString location = GetMythUI()->GetCurrentLocation(false, false);
1030 
1031  if (location != "Playback")
1032  return str;
1033 
1034  m_gotAnswer = false;
1035  QString message = QString("NETWORK_CONTROL QUERY VOLUME");
1036  MythEvent me(message);
1037  gCoreContext->dispatch(me);
1038 
1039  QElapsedTimer timer;
1040  timer.start();
1041  while (!timer.hasExpired(FE_SHORT_TO) && !m_gotAnswer)
1042  std::this_thread::sleep_for(10ms);
1043 
1044  if (m_gotAnswer)
1045  str = m_answer;
1046  else
1047  str = "ERROR: Timed out waiting for reply from player";
1048 
1049  return str;
1050  }
1051  else if ((nc->getArgCount() == 4) &&
1052  is_abbrev("recording", nc->getArg(1)) &&
1053  (nc->getArg(2).contains(QRegularExpression("^\\d+$"))) &&
1054  (nc->getArg(3).contains(QRegularExpression(
1055  R"(^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ?$)"))))
1056  return listRecordings(nc->getArg(2), nc->getArg(3).toUpper());
1057  else if (is_abbrev("recordings", nc->getArg(1)))
1058  return listRecordings();
1059  else if (is_abbrev("channels", nc->getArg(1)))
1060  {
1061  if (nc->getArgCount() == 2)
1062  return listChannels(0, 0); // give us all you can
1063  if (nc->getArgCount() == 4)
1064  return listChannels(nc->getArg(2).toLower().toUInt(),
1065  nc->getArg(3).toLower().toUInt());
1066  return QString("ERROR: See 'help %1' for usage information "
1067  "(parameters mismatch)").arg(nc->getArg(0));
1068  }
1069  else
1070  return QString("ERROR: See 'help %1' for usage information")
1071  .arg(nc->getArg(0));
1072 
1073  return result;
1074 }
1075 
1077 {
1078  if (nc->getArgCount() == 1)
1079  return QString("ERROR: See 'help %1' for usage information")
1080  .arg(nc->getArg(0));
1081 
1082  if (nc->getArg(1) == "verbose")
1083  {
1084  if (nc->getArgCount() < 3)
1085  return QString("ERROR: Missing filter name.");
1086 
1087  if (nc->getArgCount() > 3)
1088  {
1089  return QString("ERROR: Separate filters with commas with no "
1090  "space: playback,audio\r\n See 'help %1' for usage "
1091  "information").arg(nc->getArg(0));
1092  }
1093 
1094  QString oldVerboseString = verboseString;
1095  QString result = "OK";
1096 
1097  int pva_result = verboseArgParse(nc->getArg(2));
1098 
1099  if (pva_result != 0 /*GENERIC_EXIT_OK */)
1100  result = "Failed";
1101 
1102  result += "\r\n";
1103  result += " Previous filter: " + oldVerboseString + "\r\n";
1104  result += " New Filter: " + verboseString + "\r\n";
1105 
1106  LOG(VB_GENERAL, LOG_NOTICE,
1107  QString("Verbose mask changed, new level is: %1")
1108  .arg(verboseString));
1109 
1110  return result;
1111  }
1112 
1113  return QString("ERROR: See 'help %1' for usage information")
1114  .arg(nc->getArg(0));
1115 }
1116 
1118 {
1119  if (dynamic_cast<MythUIText *>(type))
1120  return "MythUIText";
1121  if (dynamic_cast<MythUITextEdit *>(type))
1122  return "MythUITextEdit";
1123  if (dynamic_cast<MythUIGroup *>(type))
1124  return "MythUIGroup";
1125  if (dynamic_cast<MythUIButton *>(type))
1126  return "MythUIButton";
1127  if (dynamic_cast<MythUICheckBox *>(type))
1128  return "MythUICheckBox";
1129  if (dynamic_cast<MythUIShape *>(type))
1130  return "MythUIShape";
1131  if (dynamic_cast<MythUIButtonList *>(type))
1132  return "MythUIButtonList";
1133  if (dynamic_cast<MythUIImage *>(type))
1134  return "MythUIImage";
1135  if (dynamic_cast<MythUISpinBox *>(type))
1136  return "MythUISpinBox";
1137 #if CONFIG_QTWEBKIT
1138  if (dynamic_cast<MythUIWebBrowser *>(type))
1139  return "MythUIWebBrowser";
1140 #endif
1141  if (dynamic_cast<MythUIClock *>(type))
1142  return "MythUIClock";
1143  if (dynamic_cast<MythUIStateType *>(type))
1144  return "MythUIStateType";
1145  if (dynamic_cast<MythUIProgressBar *>(type))
1146  return "MythUIProgressBar";
1147  if (dynamic_cast<MythUIButtonTree *>(type))
1148  return "MythUIButtonTree";
1149  if (dynamic_cast<MythUIScrollBar *>(type))
1150  return "MythUIScrollBar";
1151  if (dynamic_cast<MythUIVideo *>(type))
1152  return "MythUIVideo";
1153  if (dynamic_cast<MythUIGuideGrid *>(type))
1154  return "MythUIGuideGrid";
1155  if (dynamic_cast<MythUIEditBar *>(type))
1156  return "MythUIEditBar";
1157 
1158  return "Unknown";
1159 }
1160 
1162 {
1163  if (nc->getArgCount() == 1)
1164  return QString("ERROR: See 'help %1' for usage information")
1165  .arg(nc->getArg(0));
1166 
1167  if (nc->getArg(1) == "getthemeinfo")
1168  {
1169  QString themeName = GetMythUI()->GetThemeName();
1170  QString themeDir = GetMythUI()->GetThemeDir();
1171  return QString("%1 - %2").arg(themeName, themeDir);
1172  }
1173  if (nc->getArg(1) == "reload")
1174  {
1175  GetMythMainWindow()->JumpTo(m_jumpMap["reloadtheme"]);
1176 
1177  return "OK";
1178  }
1179  if (nc->getArg(1) == "showborders")
1180  {
1181  GetMythMainWindow()->JumpTo(m_jumpMap["showborders"]);
1182 
1183  return "OK";
1184  }
1185  if (nc->getArg(1) == "shownames")
1186  {
1187  GetMythMainWindow()->JumpTo(m_jumpMap["shownames"]);
1188 
1189  return "OK";
1190  }
1191  if (nc->getArg(1) == "getwidgetnames")
1192  {
1193  QStringList path;
1194 
1195  if (nc->getArgCount() >= 3)
1196  path = nc->getArg(2).split('/');
1197 
1198  MythScreenStack *stack = GetMythMainWindow()->GetStack("popup stack");
1199  MythScreenType *topScreen = stack->GetTopScreen();
1200 
1201  if (!topScreen)
1202  {
1203  stack = GetMythMainWindow()->GetMainStack();
1204  topScreen = stack->GetTopScreen();
1205  }
1206 
1207  if (!topScreen)
1208  return QString("ERROR: no top screen found!");
1209 
1210  MythUIType *currType = topScreen;
1211 
1212  while (!path.isEmpty())
1213  {
1214  QString childName = path.takeFirst();
1215  currType = currType->GetChild(childName);
1216  if (!currType)
1217  return QString("ERROR: Failed to find child '%1'").arg(childName);
1218  }
1219 
1220  QList<MythUIType*> *children = currType->GetAllChildren();
1221  QString result;
1222 
1223  for (int i = 0; i < children->count(); i++)
1224  {
1225  MythUIType *type = children->at(i);
1226  QString widgetName = type->objectName();
1227  QString widgetType = getWidgetType(type);
1228  result += QString("%1 - %2\n\r").arg(widgetName, -20).arg(widgetType);
1229  }
1230 
1231  return result;
1232  }
1233  if (nc->getArg(1) == "getarea")
1234  {
1235  if (nc->getArgCount() < 3)
1236  return QString("ERROR: Missing widget name.");
1237 
1238  QString widgetName = nc->getArg(2);
1239  QStringList path = widgetName.split('/');
1240 
1241  MythScreenStack *stack = GetMythMainWindow()->GetStack("popup stack");
1242  MythScreenType *topScreen = stack->GetTopScreen();
1243 
1244  if (!topScreen)
1245  {
1246  stack = GetMythMainWindow()->GetMainStack();
1247  topScreen = stack->GetTopScreen();
1248  }
1249 
1250  if (!topScreen)
1251  return QString("ERROR: no top screen found!");
1252 
1253  MythUIType *currType = topScreen;
1254 
1255  while (path.count() > 1)
1256  {
1257  QString childName = path.takeFirst();
1258  currType = currType->GetChild(childName);
1259  if (!currType)
1260  return QString("ERROR: Failed to find child '%1'").arg(childName);
1261  }
1262 
1263  MythUIType* type = currType->GetChild(path.first());
1264  if (!type)
1265  return QString("ERROR: widget '%1' not found!").arg(widgetName);
1266 
1267  int x = type->GetFullArea().x();
1268  int y = type->GetFullArea().y();
1269  int w = type->GetFullArea().width();
1270  int h = type->GetFullArea().height();
1271  return QString("The area of '%1' is x:%2, y:%3, w:%4, h:%5")
1272  .arg(widgetName).arg(x).arg(y).arg(w).arg(h);
1273  }
1274  if (nc->getArg(1) == "setarea")
1275  {
1276  if (nc->getArgCount() < 3)
1277  return QString("ERROR: Missing widget name.");
1278 
1279  if (nc->getArgCount() < 7)
1280  return QString("ERROR: Missing X, Y, Width or Height.");
1281 
1282  QString widgetName = nc->getArg(2);
1283  QStringList path = widgetName.split('/');
1284  QString x = nc->getArg(3);
1285  QString y = nc->getArg(4);
1286  QString w = nc->getArg(5);
1287  QString h = nc->getArg(6);
1288 
1289  MythScreenStack *stack = GetMythMainWindow()->GetStack("popup stack");
1290  MythScreenType *topScreen = stack->GetTopScreen();
1291 
1292  if (!topScreen)
1293  {
1294  stack = GetMythMainWindow()->GetMainStack();
1295  topScreen = stack->GetTopScreen();
1296  }
1297 
1298  MythUIType *currType = topScreen;
1299  if (!topScreen)
1300  return QString("ERROR: no top screen found!");
1301 
1302  while (path.count() > 1)
1303  {
1304  QString childName = path.takeFirst();
1305  currType = currType->GetChild(childName);
1306  if (!currType)
1307  return QString("ERROR: Failed to find child '%1'").arg(childName);
1308  }
1309 
1310  MythUIType* type = currType->GetChild(path.first());
1311  if (!type)
1312  return QString("ERROR: widget '%1' not found!").arg(widgetName);
1313 
1314  type->SetArea(MythRect(x, y, w, h));
1315 
1316  return QString("Changed area of '%1' to x:%2, y:%3, w:%4, h:%5")
1317  .arg(widgetName, x, y, w, h);
1318  }
1319 
1320  return QString("ERROR: See 'help %1' for usage information")
1321  .arg(nc->getArg(0));
1322 }
1323 
1325 {
1326  QString command;
1327  QString helpText;
1328 
1329  if (nc->getArgCount() >= 1)
1330  {
1331  if (is_abbrev("help", nc->getArg(0)))
1332  {
1333  if (nc->getArgCount() >= 2)
1334  command = nc->getArg(1);
1335  else
1336  command.clear();
1337  }
1338  else
1339  {
1340  command = nc->getArg(0);
1341  }
1342  }
1343 
1344  if (is_abbrev("jump", command))
1345  {
1346  QMap<QString, QString>::Iterator it;
1347  helpText +=
1348  "Usage: jump JUMPPOINT\r\n"
1349  "\r\n"
1350  "Where JUMPPOINT is one of the following:\r\n";
1351 
1352  for (it = m_jumpMap.begin(); it != m_jumpMap.end(); ++it)
1353  {
1354  helpText += it.key().leftJustified(20, ' ', true) + " - " +
1355  *it + "\r\n";
1356  }
1357  }
1358  else if (is_abbrev("key", command))
1359  {
1360  helpText +=
1361  "key LETTER - Send the letter key specified\r\n"
1362  "key NUMBER - Send the number key specified\r\n"
1363  "key CODE - Send one of the following key codes\r\n"
1364  "\r\n";
1365 
1366  QMap<QString, int>::Iterator it;
1367  bool first = true;
1368  for (it = m_keyMap.begin(); it != m_keyMap.end(); ++it)
1369  {
1370  if (first)
1371  first = false;
1372  else
1373  helpText += ", ";
1374 
1375  helpText += it.key();
1376  }
1377  helpText += "\r\n";
1378  }
1379  else if (is_abbrev("play", command))
1380  {
1381  helpText +=
1382  "play volume NUMBER% - Change volume to given percentage value\r\n"
1383  "play channel up - Change channel Up\r\n"
1384  "play channel down - Change channel Down\r\n"
1385  "play channel NUMBER - Change to a specific channel number\r\n"
1386  "play chanid NUMBER - Change to a specific channel id (chanid)\r\n"
1387  "play file FILENAME - Play FILENAME (FILENAME may be a file or a myth:// URL)\r\n"
1388  "play program CHANID yyyy-MM-ddThh:mm:ss\r\n"
1389  " - Play program with chanid & starttime\r\n"
1390  "play program CHANID yyyy-MM-ddThh:mm:ss resume\r\n"
1391  " - Resume program with chanid & starttime\r\n"
1392  "play save preview\r\n"
1393  " - Save preview image from current position\r\n"
1394  "play save preview FILENAME\r\n"
1395  " - Save preview image to FILENAME\r\n"
1396  "play save preview FILENAME WxH\r\n"
1397  " - Save preview image of size WxH\r\n"
1398  "play seek beginning - Seek to the beginning of the recording\r\n"
1399  "play seek forward - Skip forward in the video\r\n"
1400  "play seek backward - Skip backwards in the video\r\n"
1401  "play seek HH:MM:SS - Seek to a specific position\r\n"
1402  "play speed pause - Pause playback\r\n"
1403  "play speed normal - Playback at normal speed\r\n"
1404  "play speed 1x - Playback at normal speed\r\n"
1405  "play speed SPEEDx - Playback where SPEED must be a decimal\r\n"
1406  "play speed 1/8x - Playback at 1/8x speed\r\n"
1407  "play speed 1/4x - Playback at 1/4x speed\r\n"
1408  "play speed 1/3x - Playback at 1/3x speed\r\n"
1409  "play speed 1/2x - Playback at 1/2x speed\r\n"
1410  "play stop - Stop playback\r\n"
1411  "play subtitles [#] - Switch on indicated subtitle tracks\r\n"
1412  "play music play - Resume playback (MythMusic)\r\n"
1413  "play music pause - Pause playback (MythMusic)\r\n"
1414  "play music stop - Stop Playback (MythMusic)\r\n"
1415  "play music setvolume N - Set volume to number (MythMusic)\r\n"
1416  "play music getvolume - Get current volume (MythMusic)\r\n"
1417  "play music getmeta - Get metadata for current track (MythMusic)\r\n"
1418  "play music getstatus - Get music player status playing/paused/stopped (MythMusic)\r\n"
1419  "play music file NAME - Play specified file (MythMusic)\r\n"
1420  "play music track N - Switch to specified track (MythMusic)\r\n"
1421  "play music url URL - Play specified URL (MythMusic)\r\n";
1422  }
1423  else if (is_abbrev("query", command))
1424  {
1425  helpText +=
1426  "query location - Query current screen or location\r\n"
1427  "query volume - Query the current playback volume\r\n"
1428  "query recordings - List currently available recordings\r\n"
1429  "query recording CHANID STARTTIME\r\n"
1430  " - List info about the specified program\r\n"
1431  "query liveTV - List current TV schedule\r\n"
1432  "query liveTV CHANID - Query current program for specified channel\r\n"
1433  "query load - List 1/5/15 load averages\r\n"
1434  "query memstats - List free and total, physical and swap memory\r\n"
1435  "query time - Query current time on frontend\r\n"
1436  "query uptime - Query machine uptime\r\n"
1437  "query verbose - Get current VERBOSE mask\r\n"
1438  "query version - Query Frontend version details\r\n"
1439  "query channels - Query available channels\r\n"
1440  "query channels START LIMIT - Query available channels from START and limit results to LIMIT lines\r\n";
1441  }
1442  else if (is_abbrev("set", command))
1443  {
1444  helpText +=
1445  "set verbose debug-mask - "
1446  "Change the VERBOSE mask to 'debug-mask'\r\n"
1447  " (i.e. 'set verbose playback,audio')\r\n"
1448  " use 'set verbose default' to revert\r\n"
1449  " back to the default level of\r\n";
1450  }
1451  else if (is_abbrev("screenshot", command))
1452  {
1453  helpText +=
1454  "screenshot - Takes a screenshot and saves it as screenshot.png\r\n"
1455  "screenshot WxH - Saves the screenshot as a WxH size image\r\n";
1456  }
1457  else if (command == "exit")
1458  {
1459  helpText +=
1460  "exit - Terminates session\r\n\r\n";
1461  }
1462  else if ((is_abbrev("message", command)))
1463  {
1464  helpText +=
1465  "message - Displays a simple text message popup\r\n";
1466  }
1467  else if ((is_abbrev("notification", command)))
1468  {
1469  helpText +=
1470  "notification - Displays a simple text message notification\r\n";
1471  }
1472  else if (is_abbrev("theme", command))
1473  {
1474  helpText +=
1475  "theme getthemeinfo - Display the name and location of the current theme\r\n"
1476  "theme reload - Reload the theme\r\n"
1477  "theme showborders - Toggle showing widget borders\r\n"
1478  "theme shownames ON/OFF - Toggle showing widget names\r\n"
1479  "theme getwidgetnames PATH - Display the name and type of all the child widgets from PATH\r\n"
1480  "theme getarea WIDGETNAME - Get the area of widget WIDGET on the active screen\r\n"
1481  "theme setarea WIDGETNAME X Y W H - Change the area of widget WIDGET to X Y W H on the active screen\r\n";
1482  }
1483 
1484  if (!helpText.isEmpty())
1485  return helpText;
1486 
1487  if (!command.isEmpty())
1488  helpText += QString("Unknown command '%1'\r\n\r\n").arg(command);
1489 
1490  helpText +=
1491  "Valid Commands:\r\n"
1492  "---------------\r\n"
1493  "jump - Jump to a specified location in Myth\r\n"
1494  "key - Send a keypress to the program\r\n"
1495  "play - Playback related commands\r\n"
1496  "query - Queries\r\n"
1497  "set - Changes\r\n"
1498  "screenshot - Capture screenshot\r\n"
1499  "message - Display a simple text message\r\n"
1500  "notification - Display a simple text notification\r\n"
1501  "theme - Theme related commands\r\n"
1502  "exit - Exit Network Control\r\n"
1503  "\r\n"
1504  "Type 'help COMMANDNAME' for help on any specific command.\r\n";
1505 
1506  return helpText;
1507 }
1508 
1510 {
1511  if (nc->getArgCount() < 2)
1512  return QString("ERROR: See 'help %1' for usage information")
1513  .arg(nc->getArg(0));
1514 
1515  QString message = nc->getCommand().remove(0, 7).trimmed();
1516  MythMainWindow *window = GetMythMainWindow();
1517  auto* me = new MythEvent(MythEvent::MythUserMessage, message);
1518  qApp->postEvent(window, me);
1519  return QString("OK");
1520 }
1521 
1523 {
1524  if (nc->getArgCount() < 2)
1525  return QString("ERROR: See 'help %1' for usage information")
1526  .arg(nc->getArg(0));
1527 
1528  QString message = nc->getCommand().remove(0, 12).trimmed();
1529  MythNotification n(message, tr("Network Control"));
1531  return QString("OK");
1532 }
1533 
1535 {
1536  QCoreApplication::postEvent(
1537  this, new QEvent(kNetworkControlDataReadyEvent));
1538 }
1539 
1541  QString &reply)
1542 {
1543  if (!m_clients.contains(ncc))
1544  {
1545  // NetworkControl instance is unaware of control client
1546  // assume connection to client has been terminated and bail
1547  return;
1548  }
1549 
1550  QRegularExpression crlfRegEx("\r\n$");
1551  QRegularExpression crlfcrlfRegEx("\r\n.*\r\n");
1552 
1553  QTcpSocket *client = ncc->getSocket();
1554  QTextStream *clientStream = ncc->getTextStream();
1555 
1556  if (client && clientStream && client->state() == QTcpSocket::ConnectedState)
1557  {
1558  *clientStream << reply;
1559 
1560  if ((!reply.contains(crlfRegEx)) ||
1561  ( reply.contains(crlfcrlfRegEx)))
1562  *clientStream << "\r\n" << m_prompt;
1563 
1564  clientStream->flush();
1565  client->flush();
1566  }
1567 }
1568 
1570 {
1571  if (e->type() == MythEvent::MythEventMessage)
1572  {
1573  auto *me = dynamic_cast<MythEvent *>(e);
1574  if (me == nullptr)
1575  return;
1576 
1577  const QString& message = me->Message();
1578 
1579  if (message.startsWith("MUSIC_CONTROL"))
1580  {
1581  QStringList tokens = message.simplified().split(" ");
1582  if ((tokens.size() >= 4) &&
1583  (tokens[1] == "ANSWER") &&
1584  (tokens[2] == gCoreContext->GetHostName()))
1585  {
1586  m_answer = tokens[3];
1587  for (int i = 4; i < tokens.size(); i++)
1588  m_answer += QString(" ") + tokens[i];
1589  m_gotAnswer = true;
1590  }
1591 
1592  }
1593  else if (message.startsWith("NETWORK_CONTROL"))
1594  {
1595  QStringList tokens = message.simplified().split(" ");
1596  if ((tokens.size() >= 3) &&
1597  (tokens[1] == "ANSWER"))
1598  {
1599  m_answer = tokens[2];
1600  for (int i = 3; i < tokens.size(); i++)
1601  m_answer += QString(" ") + tokens[i];
1602  m_gotAnswer = true;
1603  }
1604  else if ((tokens.size() >= 4) &&
1605  (tokens[1] == "RESPONSE"))
1606  {
1607 // int clientID = tokens[2].toInt();
1608  m_answer = tokens[3];
1609  for (int i = 4; i < tokens.size(); i++)
1610  m_answer += QString(" ") + tokens[i];
1611  m_gotAnswer = true;
1612  }
1613  }
1614  }
1615  else if (e->type() == kNetworkControlDataReadyEvent)
1616  {
1617  QString reply;
1618 
1619  QMutexLocker locker(&m_clientLock);
1620  QMutexLocker nrLocker(&m_nrLock);
1621 
1622  while (!m_networkControlReplies.isEmpty())
1623  {
1625  m_networkControlReplies.pop_front();
1626 
1627  reply = nc->getCommand();
1628 
1629  NetworkControlClient * ncc = nc->getClient();
1630  if (ncc)
1631  {
1632  sendReplyToClient(ncc, reply);
1633  }
1634  else //send to all clients
1635  {
1636  for (auto * ncc2 : qAsConst(m_clients))
1637  {
1638  if (ncc2)
1639  sendReplyToClient(ncc2, reply);
1640  }
1641  }
1642  delete nc;
1643  }
1644  }
1645  else if (e->type() == NetworkControlCloseEvent::kEventType)
1646  {
1647  auto *ncce = dynamic_cast<NetworkControlCloseEvent*>(e);
1648  if (ncce == nullptr)
1649  return;
1650 
1651  NetworkControlClient *ncc = ncce->getClient();
1652  deleteClient(ncc);
1653  }
1654 }
1655 
1656 QString NetworkControl::listSchedule(const QString& chanID)
1657 {
1658  QString result("");
1659  MSqlQuery query(MSqlQuery::InitCon());
1660  bool appendCRLF = true;
1661  QString queryStr("SELECT chanid, starttime, endtime, title, subtitle "
1662  "FROM program "
1663  "WHERE starttime < :START AND endtime > :END ");
1664 
1665  if (!chanID.isEmpty())
1666  {
1667  queryStr += " AND chanid = :CHANID";
1668  appendCRLF = false;
1669  }
1670 
1671  queryStr += " ORDER BY starttime, endtime, chanid";
1672 
1673  query.prepare(queryStr);
1674  query.bindValue(":START", MythDate::current());
1675  query.bindValue(":END", MythDate::current());
1676  if (!chanID.isEmpty())
1677  {
1678  query.bindValue(":CHANID", chanID);
1679  }
1680 
1681  if (query.exec())
1682  {
1683  while (query.next())
1684  {
1685  QString title = query.value(3).toString();
1686  QString subtitle = query.value(4).toString();
1687 
1688  if (!subtitle.isEmpty())
1689  title += QString(" -\"%1\"").arg(subtitle);
1690  QByteArray atitle = title.toLocal8Bit();
1691 
1692  result +=
1693  QString("%1 %2 %3 %4")
1694  .arg(QString::number(query.value(0).toInt()).rightJustified(5, ' '),
1695  MythDate::as_utc(query.value(1).toDateTime()).toString(Qt::ISODate),
1696  MythDate::as_utc(query.value(2).toDateTime()).toString(Qt::ISODate),
1697  atitle);
1698 
1699  if (appendCRLF)
1700  result += "\r\n";
1701  }
1702  }
1703  else
1704  {
1705  result = "ERROR: Unable to retrieve current schedule list.";
1706  }
1707  return result;
1708 }
1709 
1710 QString NetworkControl::listRecordings(const QString& chanid, const QString& starttime)
1711 {
1712  QString result;
1713  MSqlQuery query(MSqlQuery::InitCon());
1714  QString queryStr;
1715  bool appendCRLF = true;
1716 
1717  queryStr = "SELECT chanid, starttime, title, subtitle "
1718  "FROM recorded WHERE deletepending = 0 ";
1719 
1720  if ((!chanid.isEmpty()) && (!starttime.isEmpty()))
1721  {
1722  queryStr += "AND chanid = " + chanid + " "
1723  "AND starttime = '" + starttime + "' ";
1724  appendCRLF = false;
1725  }
1726 
1727  queryStr += "ORDER BY starttime, title;";
1728 
1729  query.prepare(queryStr);
1730  if (query.exec())
1731  {
1732  QString episode;
1733  QString title;
1734  QString subtitle;
1735  while (query.next())
1736  {
1737  title = query.value(2).toString();
1738  subtitle = query.value(3).toString();
1739 
1740  if (!subtitle.isEmpty())
1741  {
1742  episode = QString("%1 -\"%2\"").arg(title, subtitle);
1743  }
1744  else
1745  {
1746  episode = title;
1747  }
1748 
1749  result +=
1750  QString("%1 %2 %3")
1751  .arg(query.value(0).toString(),
1752  MythDate::as_utc(query.value(1).toDateTime()).toString(Qt::ISODate),
1753  episode);
1754 
1755  if (appendCRLF)
1756  result += "\r\n";
1757  }
1758  }
1759  else
1760  result = "ERROR: Unable to retrieve recordings list.";
1761 
1762  return result;
1763 }
1764 
1765 QString NetworkControl::listChannels(const uint start, const uint limit)
1766 {
1767  QString result;
1768  MSqlQuery query(MSqlQuery::InitCon());
1769  QString queryStr;
1770  uint sqlStart = start;
1771 
1772  // sql starts at zero, we want to start at 1
1773  if (sqlStart > 0)
1774  sqlStart--;
1775 
1776  queryStr = "select chanid, callsign, name from channel "
1777  "where deleted IS NULL and visible > 0 "
1778  "ORDER BY callsign";
1779 
1780  if (limit > 0) // only if a limit is specified, we limit the results
1781  {
1782  QString limitStr = QString(" LIMIT %1,%2").arg(sqlStart).arg(limit);
1783  queryStr += limitStr;
1784  }
1785 
1786  query.prepare(queryStr);
1787  if (!query.exec())
1788  {
1789  result = "ERROR: Unable to retrieve channel list.";
1790  return result;
1791  }
1792 
1793  uint maxcnt = query.size();
1794  uint cnt = 0;
1795  if (maxcnt == 0) // Feedback we have no usefull information
1796  {
1797  result += QString(R"(0:0 0 "Invalid" "Invalid")");
1798  return result;
1799  }
1800 
1801  while (query.next())
1802  {
1803  // Feedback is as follow:
1804  // <current line count>:<max line count to expect> <channelid> <callsign name> <channel name>\r\n
1805  cnt++;
1806  result += QString("%1:%2 %3 \"%4\" \"%5\"\r\n")
1807  .arg(cnt).arg(maxcnt)
1808  .arg(query.value(0).toString(),
1809  query.value(1).toString(),
1810  query.value(2).toString());
1811  }
1812 
1813  return result;
1814 }
1815 
1817 {
1818  int width = 0;
1819  int height = 0;
1820 
1821  if (nc->getArgCount() == 2)
1822  {
1823  QStringList size = nc->getArg(1).split('x');
1824  if (size.size() == 2)
1825  {
1826  width = size[0].toInt();
1827  height = size[1].toInt();
1828  }
1829  }
1830 
1831  MythMainWindow *window = GetMythMainWindow();
1832  QStringList args;
1833  if (width && height)
1834  {
1835  args << QString::number(width);
1836  args << QString::number(height);
1837  }
1838  auto *me = new MythEvent(MythEvent::MythEventMessage,
1840  qApp->postEvent(window, me);
1841  return "OK";
1842 }
1843 
1844 QString NetworkCommand::getFrom(int arg)
1845 {
1846  QString c = m_command;
1847  for(int i=0 ; i<arg ; i++) {
1848  QString argstr = c.simplified().split(" ")[0];
1849  c = c.mid(argstr.length()).trimmed();
1850  }
1851  return c;
1852 }
1853 
1854 /* vim: set expandtab tabstop=4 shiftwidth=4: */
mythuibuttontree.h
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:802
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:124
build_compdb.args
args
Definition: build_compdb.py:11
MythMainWindow::GetMainStack
MythScreenStack * GetMainStack()
Definition: mythmainwindow.cpp:317
NetworkCommand
Definition: networkcontrol.h:47
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:211
MythEvent::MythEventMessage
static Type MythEventMessage
Definition: mythevent.h:78
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:286
NetworkControl::newControlConnection
void newControlConnection(QTcpSocket *client)
Definition: networkcontrol.cpp:368
mythuiprogressbar.h
NetworkControl::m_networkControlCommands
QList< NetworkCommand * > m_networkControlCommands
Definition: networkcontrol.h:154
NetworkControl::saveScreenshot
static QString saveScreenshot(NetworkCommand *nc)
Definition: networkcontrol.cpp:1816
MythUIImage
Image widget, displays a single image or multiple images in sequence.
Definition: mythuiimage.h:97
NetworkControl::notifyDataAvailable
void notifyDataAvailable(void)
Definition: networkcontrol.cpp:1534
mythuivideo.h
NetworkControl::m_ncLock
QMutex m_ncLock
Definition: networkcontrol.h:155
MythDate::as_utc
QDateTime as_utc(const QDateTime &old_dt)
Returns copy of QDateTime with TimeSpec set to UTC.
Definition: mythdate.cpp:23
FE_LONG_TO
#define FE_LONG_TO
Definition: networkcontrol.cpp:57
MythUIThemeHelper::GetThemeName
QString GetThemeName()
Definition: mythuithemehelper.cpp:145
NetworkControl::m_keyMap
QMap< QString, int > m_keyMap
Definition: networkcontrol.h:144
NetworkControl::sendReplyToClient
void sendReplyToClient(NetworkControlClient *ncc, QString &reply)
Definition: networkcontrol.cpp:1540
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:303
NetworkControlClient::m_textStream
QTextStream * m_textStream
Definition: networkcontrol.h:44
MythUIType::GetChild
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:131
NetworkControlClient::readClient
void readClient()
Definition: networkcontrol.cpp:416
NetworkControl::receiveCommand
void receiveCommand(QString &command)
Definition: networkcontrol.cpp:441
MythMainWindow::JumpTo
void JumpTo(const QString &Destination, bool Pop=true)
Definition: mythmainwindow.cpp:1460
NetworkControl::getWidgetType
static QString getWidgetType(MythUIType *type)
Definition: networkcontrol.cpp:1117
MythUIEditBar
A narrow purpose widget used to represent cut positions and regions when editing a video.
Definition: mythuieditbar.h:16
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
getLoadAvgs
loadArray getLoadAvgs(void)
Returns the system load averages.
Definition: mythmiscutil.cpp:178
NetworkCommand::getFrom
QString getFrom(int arg)
Definition: networkcontrol.cpp:1844
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:201
MythScreenStack
Definition: mythscreenstack.h:16
NetworkControlClient::commandReceived
void commandReceived(QString &)
NetworkControl::m_gotAnswer
bool m_gotAnswer
Definition: networkcontrol.h:141
MythNotification
Definition: mythnotification.h:29
mythuiscrollbar.h
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
MythUITextEdit
A text entry and edit widget.
Definition: mythuitextedit.h:32
MythUIGroup
Create a group of widgets.
Definition: mythuigroup.h:11
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
NetworkControlClient
Definition: networkcontrol.h:26
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:44
MythUIType::GetAllChildren
QList< MythUIType * > * GetAllChildren(void)
Return a list of all child widgets.
Definition: mythuitype.cpp:195
badChars
static const QRegularExpression badChars
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:378
mythsystemevent.h
mythdirs.h
ACTION_SCREENSHOT
#define ACTION_SCREENSHOT
Definition: mythuiactions.h:22
MythUIGuideGrid
A narrow purpose widget used to show television programs and the timeslots they occupy on channels....
Definition: mythuiguidegrid.h:41
MythUIClock
A simple text clock widget.
Definition: mythuiclock.h:25
MythRect
Wrapper around QRect allowing us to handle percentage and other relative values for areas in mythui.
Definition: mythrect.h:17
mythuieditbar.h
networkcontrol.h
remoteutil.h
mythuiimage.h
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
mythuiclock.h
MythEvent::Message
const QString & Message() const
Definition: mythevent.h:65
mythuiguidegrid.h
ServerPool::newConnection
void newConnection(QTcpSocket *)
MythEvent::MythUserMessage
static Type MythUserMessage
Definition: mythevent.h:79
NetworkControl::processSet
static QString processSet(NetworkCommand *nc)
Definition: networkcontrol.cpp:1076
mythversion.h
MythObservable::addListener
void addListener(QObject *listener)
Add a listener to the observable.
Definition: mythobservable.cpp:38
verboseString
QString verboseString
Definition: logging.cpp:101
NetworkControl::processHelp
QString processHelp(NetworkCommand *nc)
Definition: networkcontrol.cpp:1324
programinfo.h
NetworkControl::m_stopCommandThread
bool m_stopCommandThread
Definition: networkcontrol.h:162
mythlogging.h
NetworkControlCloseEvent
Definition: networkcontrol.h:80
NetworkControl::deleteClient
void deleteClient(void)
Definition: networkcontrol.cpp:337
ACTION_HANDLEMEDIA
#define ACTION_HANDLEMEDIA
Definition: mythuiactions.h:21
MythUIProgressBar
Progress bar widget.
Definition: mythuiprogressbar.h:12
MythCoreContext::SendSystemEvent
void SendSystemEvent(const QString &msg)
Definition: mythcorecontext.cpp:1556
NetworkControl::listChannels
static QString listChannels(uint start, uint limit)
Definition: networkcontrol.cpp:1765
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
MythUIThemeHelper::GetThemeDir
QString GetThemeDir()
Definition: mythuithemehelper.cpp:140
compat.h
kNetworkControlDataReadyEvent
static QEvent::Type kNetworkControlDataReadyEvent
Definition: networkcontrol.cpp:59
NetworkControlClient::m_socket
QTcpSocket * m_socket
Definition: networkcontrol.h:43
NetworkControl::processNetworkControlCommand
void processNetworkControlCommand(NetworkCommand *nc)
Definition: networkcontrol.cpp:292
MythUIButton
A single button widget.
Definition: mythuibutton.h:21
NetworkControl::~NetworkControl
~NetworkControl() override
Definition: networkcontrol.cpp:246
MythUIButtonTree
A tree widget for displaying and navigating a MythGenericTree()
Definition: mythuibuttontree.h:16
loadArray
std::array< double, 3 > loadArray
Definition: mythmiscutil.h:33
MythMainWindow::IsTopScreenInitialized
static bool IsTopScreenInitialized()
Definition: mythmainwindow.cpp:605
NetworkControl::processQuery
QString processQuery(NetworkCommand *nc)
Definition: networkcontrol.cpp:919
uint
unsigned int uint
Definition: compat.h:140
MythUILocation::GetCurrentLocation
QString GetCurrentLocation(bool FullPath=false, bool MainStackOnly=true)
Definition: mythuilocation.cpp:20
MythUIScrollBar
Scroll bar widget.
Definition: mythuiscrollbar.h:15
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
MythUICheckBox
A checkbox widget supporting three check states - on,off,half and two conditions - selected and unsel...
Definition: mythuicheckbox.h:15
NetworkControl::m_keyTextMap
QMap< int, QString > m_keyTextMap
Definition: networkcontrol.h:145
getUptime
bool getUptime(std::chrono::seconds &uptime)
Definition: mythmiscutil.cpp:68
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:936
NetworkControl::m_nrLock
QMutex m_nrLock
Definition: networkcontrol.h:159
GetMythSourcePath
const char * GetMythSourcePath()
Definition: mythcoreutil.cpp:297
mythuigroup.h
MythUIType
The base class on which all widgets and screens are based.
Definition: mythuitype.h:84
MythUIShape
A widget for rendering primitive shapes and lines.
Definition: mythuishape.h:21
verboseArgParse
int verboseArgParse(const QString &arg)
Parse the –verbose commandline argument and set the verbose level.
Definition: logging.cpp:942
NetworkCommand::getArgCount
int getArgCount()
Definition: networkcontrol.h:71
mythuispinbox.h
mythburn.themeName
string themeName
Definition: mythburn.py:218
NetworkControl::listRecordings
static QString listRecordings(const QString &chanid="", const QString &starttime="")
Definition: networkcontrol.cpp:1710
mythuihelper.h
NetworkControlClient::~NetworkControlClient
~NetworkControlClient() override
Definition: networkcontrol.cpp:408
MYTH_BINARY_VERSION
#define MYTH_BINARY_VERSION
Update this whenever the plug-in ABI changes.
Definition: mythversion.h:15
NetworkCommand::m_command
QString m_command
Definition: networkcontrol.h:75
MYTH_PROTO_VERSION
#define MYTH_PROTO_VERSION
Increment this whenever the MythTV network protocol changes.
Definition: mythversion.h:47
NetworkControl::m_clientLock
QRecursiveMutex m_clientLock
Definition: networkcontrol.h:150
NetworkControl::m_commandThread
MThread * m_commandThread
Definition: networkcontrol.h:161
MythUIText
All purpose text widget, displays a text string.
Definition: mythuitext.h:30
NetworkControl::m_prompt
QString m_prompt
Definition: networkcontrol.h:140
NetworkControlClient::NetworkControlClient
NetworkControlClient(QTcpSocket *s)
Definition: networkcontrol.cpp:396
mythmiscutil.h
NetworkControlClient::getTextStream
QTextStream * getTextStream()
Definition: networkcontrol.h:34
MythUIVideo
Video widget, displays raw image data.
Definition: mythuivideo.h:14
mythcorecontext.h
mythuitextedit.h
NetworkControl::processNotification
static QString processNotification(NetworkCommand *nc)
Definition: networkcontrol.cpp:1522
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:878
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
NetworkControl::m_jumpMap
QMap< QString, QString > m_jumpMap
Definition: networkcontrol.h:143
FE_SHORT_TO
#define FE_SHORT_TO
Definition: networkcontrol.cpp:56
NetworkControl::NetworkControl
NetworkControl()
Definition: networkcontrol.cpp:79
GetNotificationCenter
MythNotificationCenter * GetNotificationCenter(void)
Definition: mythmainwindow.cpp:124
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
NetworkControl::processKey
QString processKey(NetworkCommand *nc)
Definition: networkcontrol.cpp:476
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:104
build_compdb.action
action
Definition: build_compdb.py:9
MythUISpinBox
A widget for offering a range of numerical values where only the the bounding values and interval are...
Definition: mythuispinbox.h:16
NetworkControl::processTheme
QString processTheme(NetworkCommand *nc)
Definition: networkcontrol.cpp:1161
MythDate::current_iso_string
QString current_iso_string(bool stripped)
Returns current Date and Time in UTC as a string.
Definition: mythdate.cpp:18
NetworkControl::run
void run(void) override
Definition: networkcontrol.cpp:274
NetworkControl::m_ncCond
QWaitCondition m_ncCond
Definition: networkcontrol.h:156
NetworkControl::processMessage
static QString processMessage(NetworkCommand *nc)
Definition: networkcontrol.cpp:1509
LOC
#define LOC
Definition: networkcontrol.cpp:53
NetworkControl::m_answer
QString m_answer
Definition: networkcontrol.h:142
NetworkControl::listSchedule
static QString listSchedule(const QString &chanID="")
Definition: networkcontrol.cpp:1656
mythuibutton.h
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:322
NetworkCommand::getClient
NetworkControlClient * getClient()
Definition: networkcontrol.h:69
GetMythSourceVersion
const char * GetMythSourceVersion()
Definition: mythcoreutil.cpp:292
NetworkControl::processJump
QString processJump(NetworkCommand *nc)
Definition: networkcontrol.cpp:455
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:862
getMemStats
bool getMemStats(int &totalMB, int &freeMB, int &totalVM, int &freeVM)
Returns memory statistics in megabytes.
Definition: mythmiscutil.cpp:111
NetworkControlCloseEvent::kEventType
static Type kEventType
Definition: networkcontrol.h:88
musicbrainzngs.caa.hostname
string hostname
Definition: caa.py:17
NetworkControl::m_clients
QList< NetworkControlClient * > m_clients
Definition: networkcontrol.h:152
MythUIWebBrowser
Web browsing widget.
Definition: mythuiwebbrowser.h:132
NetworkControl::processPlay
QString processPlay(NetworkCommand *nc, int clientID)
Definition: networkcontrol.cpp:581
MythMainWindow::ResetScreensaver
static void ResetScreensaver()
Definition: mythmainwindow.cpp:588
mythuicheckbox.h
previewgenerator.h
NetworkCommand::getCommand
QString getCommand()
Definition: networkcontrol.h:68
GetMythUI
MythUIHelper * GetMythUI()
Definition: mythuihelper.cpp:66
MythUIButtonList
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
Definition: mythuibuttonlist.h:151
mythuiwebbrowser.h
mythmainwindow.h
NetworkControl::customEvent
void customEvent(QEvent *e) override
Definition: networkcontrol.cpp:1569
NetworkCommand::getArg
QString getArg(int arg)
Definition: networkcontrol.h:70
NetworkControlClient::getSocket
QTcpSocket * getSocket()
Definition: networkcontrol.h:33
MythCoreContext::dispatch
void dispatch(const MythEvent &event)
Definition: mythcorecontext.cpp:1737
MythObservable::removeListener
void removeListener(QObject *listener)
Remove a listener to the observable.
Definition: mythobservable.cpp:55
is_abbrev
static bool is_abbrev(QString const &command, QString const &test, int minchars=1)
Is test an abbreviation of command ? The test substring must be at least minchars long.
Definition: networkcontrol.cpp:71
MythMainWindow
Definition: mythmainwindow.h:35
mythuishape.h
MythUIStateType
This widget is used for grouping other widgets for display when a particular named state is called....
Definition: mythuistatetype.h:22
NetworkControl::m_networkControlReplies
QList< NetworkCommand * > m_networkControlReplies
Definition: networkcontrol.h:158
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:827
MythScreenStack::GetTopScreen
virtual MythScreenType * GetTopScreen(void) const
Definition: mythscreenstack.cpp:180
MythNotificationCenter::Queue
bool Queue(const MythNotification &notification)
Queue a notification Queue() is thread-safe and can be called from anywhere.
Definition: mythnotificationcenter.cpp:1351