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