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 <QRegExp>
9 #include <QStringList>
10 #include <QTextStream>
11 #include <QDir>
12 #include <QKeyEvent>
13 #include <QEvent>
14 #include <QMap>
15 
16 #include "mythcorecontext.h"
17 #include "mythmiscutil.h"
18 #include "mythversion.h"
19 #include "programinfo.h"
20 #include "remoteutil.h"
21 #include "previewgenerator.h"
22 #include "compat.h"
23 #include "mythsystemevent.h"
24 #include "mythdirs.h"
25 #include "mythlogging.h"
26 
27 // libmythui
28 #include "mythmainwindow.h"
29 #include "mythuihelper.h"
30 #include "mythuigroup.h"
31 #include "mythuiclock.h"
32 #include "mythuishape.h"
33 #include "mythuibutton.h"
34 #include "mythuitextedit.h"
35 #include "mythuibuttontree.h"
36 #include "mythuivideo.h"
37 #include "mythuiguidegrid.h"
38 #include "mythuicheckbox.h"
39 #include "mythuispinbox.h"
40 
41 #if CONFIG_QTWEBKIT
42 #include "mythuiwebbrowser.h"
43 #endif
44 
45 #include "mythuiprogressbar.h"
46 #include "mythuiscrollbar.h"
47 #include "mythuieditbar.h"
48 #include "mythuiimage.h"
49 
50 #define LOC QString("NetworkControl: ")
51 #define LOC_ERR QString("NetworkControl Error: ")
52 
53 #define FE_SHORT_TO 2000
54 #define FE_LONG_TO 10000
55 
56 static QEvent::Type kNetworkControlDataReadyEvent =
57  (QEvent::Type) QEvent::registerEventType();
59  (QEvent::Type) QEvent::registerEventType();
60 
68 static bool is_abbrev(QString const& command,
69  QString const& test, int minchars = 1)
70 {
71  if (test.length() < minchars)
72  return command.toLower() == test.toLower();
73  return test.toLower() == command.left(test.length()).toLower();
74 }
75 
77  m_commandThread(new MThread("NetworkControl", this))
78 {
79  // Eventually this map should be in the jumppoints table
80  m_jumpMap["channelpriorities"] = "Channel Recording Priorities";
81  m_jumpMap["livetv"] = "Live TV";
82  m_jumpMap["mainmenu"] = "Main Menu";
83  m_jumpMap["managerecordings"] = "Manage Recordings / Fix Conflicts";
84  m_jumpMap["mythgallery"] = "MythGallery";
85  m_jumpMap["mythvideo"] = "Video Default";
86  m_jumpMap["mythweather"] = "MythWeather";
87  m_jumpMap["mythgame"] = "MythGame";
88  m_jumpMap["mythnews"] = "MythNews";
89  m_jumpMap["playdvd"] = "Play Disc";
90  m_jumpMap["playmusic"] = "Play music";
91  m_jumpMap["playlistview"] = "Play music";
92  m_jumpMap["programfinder"] = "Program Finder";
93  m_jumpMap["programguide"] = "Program Guide";
94  m_jumpMap["ripcd"] = "Rip CD";
95  m_jumpMap["musicplaylists"] = "Select music playlists";
96  m_jumpMap["playbackrecordings"] = "TV Recording Playback";
97  m_jumpMap["videobrowser"] = "Video Browser";
98  m_jumpMap["videogallery"] = "Video Gallery";
99  m_jumpMap["videolistings"] = "Video Listings";
100  m_jumpMap["videomanager"] = "Video Manager";
101  m_jumpMap["zoneminderconsole"] = "ZoneMinder Console";
102  m_jumpMap["zoneminderliveview"] = "ZoneMinder Live View";
103  m_jumpMap["zoneminderevents"] = "ZoneMinder Events";
104 
105  m_jumpMap["channelrecpriority"] = "Channel Recording Priorities";
106  m_jumpMap["viewscheduled"] = "Manage Recordings / Fix Conflicts";
107  m_jumpMap["previousbox"] = "Previously Recorded";
108  m_jumpMap["progfinder"] = "Program Finder";
109  m_jumpMap["guidegrid"] = "Program Guide";
110  m_jumpMap["managerecrules"] = "Manage Recording Rules";
111  m_jumpMap["statusbox"] = "Status Screen";
112  m_jumpMap["playbackbox"] = "TV Recording Playback";
113  m_jumpMap["pbb"] = "TV Recording Playback";
114 
115  m_jumpMap["reloadtheme"] = "Reload Theme";
116  m_jumpMap["showborders"] = "Toggle Show Widget Borders";
117  m_jumpMap["shownames"] = "Toggle Show Widget Names";
118 
119  m_keyMap["up"] = Qt::Key_Up;
120  m_keyMap["down"] = Qt::Key_Down;
121  m_keyMap["left"] = Qt::Key_Left;
122  m_keyMap["right"] = Qt::Key_Right;
123  m_keyMap["home"] = Qt::Key_Home;
124  m_keyMap["end"] = Qt::Key_End;
125  m_keyMap["enter"] = Qt::Key_Enter;
126  m_keyMap["return"] = Qt::Key_Return;
127  m_keyMap["pageup"] = Qt::Key_PageUp;
128  m_keyMap["pagedown"] = Qt::Key_PageDown;
129  m_keyMap["escape"] = Qt::Key_Escape;
130  m_keyMap["tab"] = Qt::Key_Tab;
131  m_keyMap["backtab"] = Qt::Key_Backtab;
132  m_keyMap["space"] = Qt::Key_Space;
133  m_keyMap["backspace"] = Qt::Key_Backspace;
134  m_keyMap["insert"] = Qt::Key_Insert;
135  m_keyMap["delete"] = Qt::Key_Delete;
136  m_keyMap["plus"] = Qt::Key_Plus;
137  m_keyMap["+"] = Qt::Key_Plus;
138  m_keyMap["comma"] = Qt::Key_Comma;
139  m_keyMap[","] = Qt::Key_Comma;
140  m_keyMap["minus"] = Qt::Key_Minus;
141  m_keyMap["-"] = Qt::Key_Minus;
142  m_keyMap["underscore"] = Qt::Key_Underscore;
143  m_keyMap["_"] = Qt::Key_Underscore;
144  m_keyMap["period"] = Qt::Key_Period;
145  m_keyMap["."] = Qt::Key_Period;
146  m_keyMap["numbersign"] = Qt::Key_NumberSign;
147  m_keyMap["poundsign"] = Qt::Key_NumberSign;
148  m_keyMap["hash"] = Qt::Key_NumberSign;
149  m_keyMap["#"] = Qt::Key_NumberSign;
150  m_keyMap["bracketleft"] = Qt::Key_BracketLeft;
151  m_keyMap["["] = Qt::Key_BracketLeft;
152  m_keyMap["bracketright"] = Qt::Key_BracketRight;
153  m_keyMap["]"] = Qt::Key_BracketRight;
154  m_keyMap["backslash"] = Qt::Key_Backslash;
155  m_keyMap["\\"] = Qt::Key_Backslash;
156  m_keyMap["dollar"] = Qt::Key_Dollar;
157  m_keyMap["$"] = Qt::Key_Dollar;
158  m_keyMap["percent"] = Qt::Key_Percent;
159  m_keyMap["%"] = Qt::Key_Percent;
160  m_keyMap["ampersand"] = Qt::Key_Ampersand;
161  m_keyMap["&"] = Qt::Key_Ampersand;
162  m_keyMap["parenleft"] = Qt::Key_ParenLeft;
163  m_keyMap["("] = Qt::Key_ParenLeft;
164  m_keyMap["parenright"] = Qt::Key_ParenRight;
165  m_keyMap[")"] = Qt::Key_ParenRight;
166  m_keyMap["asterisk"] = Qt::Key_Asterisk;
167  m_keyMap["*"] = Qt::Key_Asterisk;
168  m_keyMap["question"] = Qt::Key_Question;
169  m_keyMap["?"] = Qt::Key_Question;
170  m_keyMap["slash"] = Qt::Key_Slash;
171  m_keyMap["/"] = Qt::Key_Slash;
172  m_keyMap["colon"] = Qt::Key_Colon;
173  m_keyMap[":"] = Qt::Key_Colon;
174  m_keyMap["semicolon"] = Qt::Key_Semicolon;
175  m_keyMap[";"] = Qt::Key_Semicolon;
176  m_keyMap["less"] = Qt::Key_Less;
177  m_keyMap["<"] = Qt::Key_Less;
178  m_keyMap["equal"] = Qt::Key_Equal;
179  m_keyMap["="] = Qt::Key_Equal;
180  m_keyMap["greater"] = Qt::Key_Greater;
181  m_keyMap[">"] = Qt::Key_Greater;
182  m_keyMap["bar"] = Qt::Key_Bar;
183  m_keyMap["pipe"] = Qt::Key_Bar;
184  m_keyMap["|"] = Qt::Key_Bar;
185  m_keyMap["f1"] = Qt::Key_F1;
186  m_keyMap["f2"] = Qt::Key_F2;
187  m_keyMap["f3"] = Qt::Key_F3;
188  m_keyMap["f4"] = Qt::Key_F4;
189  m_keyMap["f5"] = Qt::Key_F5;
190  m_keyMap["f6"] = Qt::Key_F6;
191  m_keyMap["f7"] = Qt::Key_F7;
192  m_keyMap["f8"] = Qt::Key_F8;
193  m_keyMap["f9"] = Qt::Key_F9;
194  m_keyMap["f10"] = Qt::Key_F10;
195  m_keyMap["f11"] = Qt::Key_F11;
196  m_keyMap["f12"] = Qt::Key_F12;
197  m_keyMap["f13"] = Qt::Key_F13;
198  m_keyMap["f14"] = Qt::Key_F14;
199  m_keyMap["f15"] = Qt::Key_F15;
200  m_keyMap["f16"] = Qt::Key_F16;
201  m_keyMap["f17"] = Qt::Key_F17;
202  m_keyMap["f18"] = Qt::Key_F18;
203  m_keyMap["f19"] = Qt::Key_F19;
204  m_keyMap["f20"] = Qt::Key_F20;
205  m_keyMap["f21"] = Qt::Key_F21;
206  m_keyMap["f22"] = Qt::Key_F22;
207  m_keyMap["f23"] = Qt::Key_F23;
208  m_keyMap["f24"] = Qt::Key_F24;
209 
210  m_keyTextMap[Qt::Key_Space] = " ";
211  m_keyTextMap[Qt::Key_Plus] = "+";
212  m_keyTextMap[Qt::Key_Comma] = ",";
213  m_keyTextMap[Qt::Key_Minus] = "-";
214  m_keyTextMap[Qt::Key_Underscore] = "_";
215  m_keyTextMap[Qt::Key_Period] = ".";
216  m_keyTextMap[Qt::Key_NumberSign] = "#";
217  m_keyTextMap[Qt::Key_BracketLeft] = "[";
218  m_keyTextMap[Qt::Key_BracketRight] = "]";
219  m_keyTextMap[Qt::Key_Backslash] = "\\";
220  m_keyTextMap[Qt::Key_Dollar] = "$";
221  m_keyTextMap[Qt::Key_Percent] = "%";
222  m_keyTextMap[Qt::Key_Ampersand] = "&";
223  m_keyTextMap[Qt::Key_ParenLeft] = "(";
224  m_keyTextMap[Qt::Key_ParenRight] = ")";
225  m_keyTextMap[Qt::Key_Asterisk] = "*";
226  m_keyTextMap[Qt::Key_Question] = "?";
227  m_keyTextMap[Qt::Key_Slash] = "/";
228  m_keyTextMap[Qt::Key_Colon] = ":";
229  m_keyTextMap[Qt::Key_Semicolon] = ";";
230  m_keyTextMap[Qt::Key_Less] = "<";
231  m_keyTextMap[Qt::Key_Equal] = "=";
232  m_keyTextMap[Qt::Key_Greater] = ">";
233  m_keyTextMap[Qt::Key_Bar] = "|";
234 
236 
237  gCoreContext->addListener(this);
238 
239  connect(this, SIGNAL(newConnection(QTcpSocket*)),
240  this, SLOT(newConnection(QTcpSocket*)));
241 }
242 
244 {
246 
247  m_clientLock.lock();
248  while (!m_clients.isEmpty())
249  {
250  NetworkControlClient *ncc = m_clients.takeFirst();
251  delete ncc;
252  }
253  m_clientLock.unlock();
254 
255  m_nrLock.lock();
256  m_networkControlReplies.push_back(new NetworkCommand(nullptr,
257  "mythfrontend shutting down, connection closing..."));
258  m_nrLock.unlock();
259 
261 
262  m_ncLock.lock();
263  m_stopCommandThread = true;
264  m_ncCond.wakeOne();
265  m_ncLock.unlock();
267  delete m_commandThread;
268  m_commandThread = nullptr;
269 }
270 
272 {
273  QMutexLocker locker(&m_ncLock);
274  while (!m_stopCommandThread)
275  {
277  m_ncCond.wait(&m_ncLock);
278  if (!m_stopCommandThread)
279  {
281  m_networkControlCommands.pop_front();
282  locker.unlock();
284  locker.relock();
285  }
286  }
287 }
288 
290 {
291  QMutexLocker locker(&m_clientLock);
292  QString result;
293 
294  int clientID = m_clients.indexOf(nc->getClient());
295 
296  if (is_abbrev("jump", nc->getArg(0)))
297  result = processJump(nc);
298  else if (is_abbrev("key", nc->getArg(0)))
299  result = processKey(nc);
300  else if (is_abbrev("play", nc->getArg(0)))
301  result = processPlay(nc, clientID);
302  else if (is_abbrev("query", nc->getArg(0)))
303  result = processQuery(nc);
304  else if (is_abbrev("set", nc->getArg(0)))
305  result = processSet(nc);
306  else if (is_abbrev("screenshot", nc->getArg(0)))
307  result = saveScreenshot(nc);
308  else if (is_abbrev("help", nc->getArg(0)))
309  result = processHelp(nc);
310  else if (is_abbrev("message", nc->getArg(0)))
311  result = processMessage(nc);
312  else if (is_abbrev("notification", nc->getArg(0)))
313  result = processNotification(nc);
314  else if (is_abbrev("theme", nc->getArg(0)))
315  result = processTheme(nc);
316  else if ((nc->getArg(0).toLower() == "exit") || (nc->getArg(0).toLower() == "quit"))
317  {
318  QCoreApplication::postEvent(this,
320  }
321  else if (! nc->getArg(0).isEmpty())
322  {
323  result = QString("INVALID command '%1', try 'help' for more info")
324  .arg(nc->getArg(0));
325  }
326 
327  m_nrLock.lock();
328  m_networkControlReplies.push_back(new NetworkCommand(nc->getClient(),result));
329  m_nrLock.unlock();
330 
332 }
333 
335 {
336  LOG(VB_GENERAL, LOG_INFO, LOC + "Client Socket disconnected");
337  QMutexLocker locker(&m_clientLock);
338 
339  gCoreContext->SendSystemEvent("NET_CTRL_DISCONNECTED");
340 
341  QList<NetworkControlClient *>::const_iterator it;
342  for (it = m_clients.begin(); it != m_clients.end(); ++it)
343  {
344  NetworkControlClient *ncc = *it;
345  if (ncc->getSocket()->state() == QTcpSocket::UnconnectedState)
346  {
347  deleteClient(ncc);
348  return;
349  }
350  }
351 }
352 
354 {
355  int index = m_clients.indexOf(ncc);
356  if (index >= 0)
357  {
358  m_clients.removeAt(index);
359 
360  delete ncc;
361  }
362  else
363  LOG(VB_GENERAL, LOG_ERR, LOC + QString("deleteClient(%1), unable to "
364  "locate specified NetworkControlClient").arg((long long)ncc));
365 }
366 
367 void NetworkControl::newConnection(QTcpSocket *client)
368 {
369  QString welcomeStr;
370 
371  LOG(VB_GENERAL, LOG_INFO, LOC + QString("New connection established."));
372 
373  gCoreContext->SendSystemEvent("NET_CTRL_CONNECTED");
374 
375  auto *ncc = new NetworkControlClient(client);
376 
377  QMutexLocker locker(&m_clientLock);
378  m_clients.push_back(ncc);
379 
380  connect(ncc, SIGNAL(commandReceived(QString&)), this,
381  SLOT(receiveCommand(QString&)));
382  connect(client, SIGNAL(disconnected()), this, SLOT(deleteClient()));
383 
384  welcomeStr = "MythFrontend Network Control\r\n";
385  welcomeStr += "Type 'help' for usage information\r\n"
386  "---------------------------------";
387  m_nrLock.lock();
388  m_networkControlReplies.push_back(new NetworkCommand(ncc,welcomeStr));
389  m_nrLock.unlock();
390 
392 }
393 
395 {
396  m_socket = s;
397  m_textStream = new QTextStream(s);
398  m_textStream->setCodec("UTF-8");
399  connect(m_socket, SIGNAL(readyRead()), this, SLOT(readClient()));
400 }
401 
403 {
404  m_socket->close();
405  m_socket->deleteLater();
406 
407  delete m_textStream;
408 }
409 
411 {
412  auto *socket = (QTcpSocket *)sender();
413  if (!socket)
414  return;
415 
416  QString lineIn;
417  while (socket->canReadLine())
418  {
419  lineIn = socket->readLine();
420 #if 0
421  lineIn.replace(QRegExp("[^-a-zA-Z0-9\\s\\.:_#/$%&()*+,;<=>?\\[\\]\\|]"),
422  "");
423 #endif
424 
425  // TODO: can this be replaced with lineIn.simplify()?
426  lineIn.replace(QRegExp("[\r\n]"), "");
427  lineIn.replace(QRegExp("^\\s"), "");
428 
429  if (lineIn.isEmpty())
430  continue;
431 
432  LOG(VB_NETWORK, LOG_INFO, LOC +
433  QString("emit commandReceived(%1)").arg(lineIn));
434  emit commandReceived(lineIn);
435  }
436 }
437 
438 void NetworkControl::receiveCommand(QString &command)
439 {
440  LOG(VB_NETWORK, LOG_INFO, LOC +
441  QString("NetworkControl::receiveCommand(%1)").arg(command));
442  auto *ncc = dynamic_cast<NetworkControlClient *>(sender());
443  if (!ncc)
444  return;
445 
446  m_ncLock.lock();
447  m_networkControlCommands.push_back(new NetworkCommand(ncc,command));
448  m_ncCond.wakeOne();
449  m_ncLock.unlock();
450 }
451 
453 {
454  QString result = "OK";
455 
456  if ((nc->getArgCount() < 2) || (!m_jumpMap.contains(nc->getArg(1))))
457  return QString("ERROR: See 'help %1' for usage information")
458  .arg(nc->getArg(0));
459 
461 
462  // Fixme, should do some better checking here, but that would
463  // depend on all Locations matching their jumppoints
464  QElapsedTimer timer;
465  timer.start();
466  while (!timer.hasExpired(FE_SHORT_TO) &&
467  (GetMythUI()->GetCurrentLocation().toLower() != nc->getArg(1)))
468  std::this_thread::sleep_for(std::chrono::milliseconds(10));
469 
470  return result;
471 }
472 
474 {
475  QString result = "OK";
476  QKeyEvent *event = nullptr;
477 
478  if (nc->getArgCount() < 2)
479  return QString("ERROR: See 'help %1' for usage information")
480  .arg(nc->getArg(0));
481 
482  QObject *keyDest = nullptr;
483 
484  if (GetMythMainWindow())
485  keyDest = GetMythMainWindow();
486  else
487  return QString("ERROR: Application has no main window!\n");
488 
489  int curToken = 1;
490  while (curToken < nc->getArgCount())
491  {
492  int tokenLen = nc->getArg(curToken).length();
493 
494  if (nc->getArg(curToken) == "sleep")
495  {
496  std::this_thread::sleep_for(std::chrono::seconds(1));
497  }
498  else if (m_keyMap.contains(nc->getArg(curToken)))
499  {
500  int keyCode = m_keyMap[nc->getArg(curToken)];
501  QString keyText;
502 
503  if (m_keyTextMap.contains(keyCode))
504  keyText = m_keyTextMap[keyCode];
505 
507 
508  event = new QKeyEvent(QEvent::KeyPress, keyCode, Qt::NoModifier,
509  keyText);
510  QCoreApplication::postEvent(keyDest, event);
511 
512  event = new QKeyEvent(QEvent::KeyRelease, keyCode, Qt::NoModifier,
513  keyText);
514  QCoreApplication::postEvent(keyDest, event);
515  }
516  else if (((tokenLen == 1) &&
517  (nc->getArg(curToken)[0].isLetterOrNumber())) ||
518  ((tokenLen >= 1) &&
519  (nc->getArg(curToken).contains("+"))))
520  {
521  QKeySequence a(nc->getArg(curToken));
522  int keyCode = a[0];
523  Qt::KeyboardModifiers modifiers = Qt::NoModifier;
524 
525  if (tokenLen > 1)
526  {
527  QStringList tokenParts = nc->getArg(curToken).split('+');
528 
529  int partNum = 0;
530  while (partNum < (tokenParts.size() - 1))
531  {
532  if (tokenParts[partNum].toUpper() == "CTRL")
533  modifiers |= Qt::ControlModifier;
534  if (tokenParts[partNum].toUpper() == "SHIFT")
535  modifiers |= Qt::ShiftModifier;
536  if (tokenParts[partNum].toUpper() == "ALT")
537  modifiers |= Qt::AltModifier;
538  if (tokenParts[partNum].toUpper() == "META")
539  modifiers |= Qt::MetaModifier;
540 
541  partNum++;
542  }
543  }
544  else
545  {
546  if (nc->getArg(curToken) == nc->getArg(curToken).toUpper())
547  modifiers = Qt::ShiftModifier;
548  }
549 
551 
552  event = new QKeyEvent(QEvent::KeyPress, keyCode, modifiers,
553  nc->getArg(curToken));
554  QCoreApplication::postEvent(keyDest, event);
555 
556  event = new QKeyEvent(QEvent::KeyRelease, keyCode, modifiers,
557  nc->getArg(curToken));
558  QCoreApplication::postEvent(keyDest, event);
559  }
560  else
561  {
562  return QString("ERROR: Invalid syntax at '%1', see 'help %2' for "
563  "usage information")
564  .arg(nc->getArg(curToken)).arg(nc->getArg(0));
565  }
566 
567  curToken++;
568  }
569 
570  return result;
571 }
572 
573 QString NetworkControl::processPlay(NetworkCommand *nc, int clientID)
574 {
575  QString result = "OK";
576  QString message;
577 
578  if (nc->getArgCount() < 2)
579  return QString("ERROR: See 'help %1' for usage information")
580  .arg(nc->getArg(0));
581 
582  if ((nc->getArgCount() >= 3) &&
583  (is_abbrev("file", nc->getArg(1))))
584  {
585  if (GetMythUI()->GetCurrentLocation().toLower() != "mainmenu")
586  {
587  GetMythMainWindow()->JumpTo(m_jumpMap["mainmenu"]);
588 
589  QElapsedTimer timer;
590  timer.start();
591  while (!timer.hasExpired(FE_LONG_TO) &&
592  (GetMythUI()->GetCurrentLocation().toLower() != "mainmenu"))
593  std::this_thread::sleep_for(std::chrono::milliseconds(10));
594  }
595 
596  if (GetMythUI()->GetCurrentLocation().toLower() == "mainmenu")
597  {
598  QStringList args;
599  args << nc->getFrom(2);
600  auto *me = new MythEvent(ACTION_HANDLEMEDIA, args);
601  qApp->postEvent(GetMythMainWindow(), me);
602  }
603  else
604  return QString("Unable to change to main menu to start playback!");
605  }
606  else if ((nc->getArgCount() >= 4) &&
607  (is_abbrev("program", nc->getArg(1))) &&
608  (nc->getArg(2).contains(QRegExp("^\\d+$"))) &&
609  (nc->getArg(3).contains(QRegExp(
610  R"(^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d$)"))))
611  {
612  if (GetMythUI()->GetCurrentLocation().toLower() == "playback")
613  {
614  QString msg = QString("NETWORK_CONTROL STOP");
615  MythEvent me(msg);
616  gCoreContext->dispatch(me);
617 
618  QElapsedTimer timer;
619  timer.start();
620  while (!timer.hasExpired(FE_LONG_TO) &&
621  (GetMythUI()->GetCurrentLocation().toLower() == "playback"))
622  std::this_thread::sleep_for(std::chrono::milliseconds(10));
623  }
624 
625  if (GetMythUI()->GetCurrentLocation().toLower() != "playbackbox")
626  {
627  GetMythMainWindow()->JumpTo(m_jumpMap["playbackbox"]);
628 
629  QElapsedTimer timer;
630  timer.start();
631  while (!timer.hasExpired(10000) &&
632  (GetMythUI()->GetCurrentLocation().toLower() != "playbackbox"))
633  std::this_thread::sleep_for(std::chrono::milliseconds(10));
634 
635  timer.start();
636  while (!timer.hasExpired(10000) &&
638  std::this_thread::sleep_for(std::chrono::milliseconds(10));
639  }
640 
641  if (GetMythUI()->GetCurrentLocation().toLower() == "playbackbox")
642  {
643  QString action = "PLAY";
644  if (nc->getArgCount() == 5 && nc->getArg(4) == "resume")
645  action = "RESUME";
646 
647  QString msg = QString("NETWORK_CONTROL %1 PROGRAM %2 %3 %4")
648  .arg(action).arg(nc->getArg(2))
649  .arg(nc->getArg(3).toUpper()).arg(clientID);
650 
651  result.clear();
652  m_gotAnswer = false;
653  QElapsedTimer timer;
654  timer.start();
655 
656  MythEvent me(msg);
657  gCoreContext->dispatch(me);
658 
659  while (!timer.hasExpired(FE_LONG_TO) && !m_gotAnswer)
660  std::this_thread::sleep_for(std::chrono::milliseconds(10));
661 
662  if (m_gotAnswer)
663  result += m_answer;
664  else
665  result = "ERROR: Timed out waiting for reply from player";
666 
667  }
668  else
669  {
670  result = QString("ERROR: Unable to change to PlaybackBox from "
671  "%1, cannot play requested file.")
672  .arg(GetMythUI()->GetCurrentLocation());
673  }
674  }
675  else if (is_abbrev("music", nc->getArg(1)))
676  {
677 #if 0
678  if (GetMythUI()->GetCurrentLocation().toLower() != "playmusic")
679  {
680  return QString("ERROR: You are in %1 mode and this command is "
681  "only for MythMusic")
682  .arg(GetMythUI()->GetCurrentLocation());
683  }
684 #endif
685 
686  QString hostname = gCoreContext->GetHostName();
687 
688  if (nc->getArgCount() == 3)
689  {
690  if (is_abbrev("play", nc->getArg(2)))
691  message = QString("MUSIC_COMMAND %1 PLAY").arg(hostname);
692  else if (is_abbrev("pause", nc->getArg(2)))
693  message = QString("MUSIC_COMMAND %1 PAUSE").arg(hostname);
694  else if (is_abbrev("stop", nc->getArg(2)))
695  message = QString("MUSIC_COMMAND %1 STOP").arg(hostname);
696  else if (is_abbrev("getvolume", nc->getArg(2)))
697  {
698  m_gotAnswer = false;
699 
700  MythEvent me(QString("MUSIC_COMMAND %1 GET_VOLUME").arg(hostname));
701  gCoreContext->dispatch(me);
702 
703  QElapsedTimer timer;
704  timer.start();
705  while (!timer.hasExpired(FE_SHORT_TO) && !m_gotAnswer)
706  {
707  qApp->processEvents();
708  std::this_thread::sleep_for(std::chrono::milliseconds(10));
709  }
710 
711  if (m_gotAnswer)
712  return m_answer;
713 
714  return "unknown";
715  }
716  else if (is_abbrev("getmeta", nc->getArg(2)))
717  {
718  m_gotAnswer = false;
719 
720  MythEvent me(QString("MUSIC_COMMAND %1 GET_METADATA").arg(hostname));
721  gCoreContext->dispatch(me);
722 
723  QElapsedTimer timer;
724  timer.start();
725  while (!timer.hasExpired(FE_SHORT_TO) && !m_gotAnswer)
726  {
727  qApp->processEvents();
728  std::this_thread::sleep_for(std::chrono::milliseconds(10));
729  }
730 
731  if (m_gotAnswer)
732  return m_answer;
733 
734  return "unknown";
735  }
736  else if (is_abbrev("getstatus", nc->getArg(2)))
737  {
738  m_gotAnswer = false;
739 
740  MythEvent me(QString("MUSIC_COMMAND %1 GET_STATUS").arg(hostname));
741  gCoreContext->dispatch(me);
742 
743  QElapsedTimer timer;
744  timer.start();
745  while (!timer.hasExpired(FE_SHORT_TO) && !m_gotAnswer)
746  {
747  qApp->processEvents();
748  std::this_thread::sleep_for(std::chrono::milliseconds(10));
749  }
750 
751  if (m_gotAnswer)
752  return m_answer;
753 
754  return "unknown";
755  }
756  else
757  return QString("ERROR: Invalid 'play music' command");
758  }
759  else if (nc->getArgCount() > 3)
760  {
761  if (is_abbrev("setvolume", nc->getArg(2)))
762  {
763  message = QString("MUSIC_COMMAND %1 SET_VOLUME %2")
764  .arg(hostname)
765  .arg(nc->getArg(3));
766  }
767  else if (is_abbrev("track", nc->getArg(2)))
768  {
769  message = QString("MUSIC_COMMAND %1 PLAY_TRACK %2")
770  .arg(hostname)
771  .arg(nc->getArg(3));
772  }
773  else if (is_abbrev("url", nc->getArg(2)))
774  {
775  message = QString("MUSIC_COMMAND %1 PLAY_URL %2")
776  .arg(hostname)
777  .arg(nc->getArg(3));
778  }
779  else if (is_abbrev("file", nc->getArg(2)))
780  {
781  message = QString("MUSIC_COMMAND %1 PLAY_FILE '%2'")
782  .arg(hostname)
783  .arg(nc->getFrom(3));
784  }
785  else
786  {
787  return QString("ERROR: Invalid 'play music' command");
788  }
789  }
790  else
791  return QString("ERROR: Invalid 'play music' command");
792  }
793  // Everything below here requires us to be in playback mode so check to
794  // see if we are
795  else if (GetMythUI()->GetCurrentLocation().toLower() != "playback")
796  {
797  return QString("ERROR: You are in %1 mode and this command is only "
798  "for playback mode")
799  .arg(GetMythUI()->GetCurrentLocation());
800  }
801  else if (is_abbrev("chanid", nc->getArg(1), 5))
802  {
803  if (nc->getArg(2).contains(QRegExp("^\\d+$")))
804  message = QString("NETWORK_CONTROL CHANID %1").arg(nc->getArg(2));
805  else
806  return QString("ERROR: See 'help %1' for usage information")
807  .arg(nc->getArg(0));
808  }
809  else if (is_abbrev("channel", nc->getArg(1), 5))
810  {
811  if (nc->getArgCount() < 3)
812  return "ERROR: See 'help play' for usage information";
813 
814  if (is_abbrev("up", nc->getArg(2)))
815  message = "NETWORK_CONTROL CHANNEL UP";
816  else if (is_abbrev("down", nc->getArg(2)))
817  message = "NETWORK_CONTROL CHANNEL DOWN";
818  else if (nc->getArg(2).contains(QRegExp("^[-\\.\\d_#]+$")))
819  message = QString("NETWORK_CONTROL CHANNEL %1").arg(nc->getArg(2));
820  else
821  return QString("ERROR: See 'help %1' for usage information")
822  .arg(nc->getArg(0));
823  }
824  else if (is_abbrev("seek", nc->getArg(1), 2))
825  {
826  if (nc->getArgCount() < 3)
827  return QString("ERROR: See 'help %1' for usage information")
828  .arg(nc->getArg(0));
829 
830  if (is_abbrev("beginning", nc->getArg(2)))
831  message = "NETWORK_CONTROL SEEK BEGINNING";
832  else if (is_abbrev("forward", nc->getArg(2)))
833  message = "NETWORK_CONTROL SEEK FORWARD";
834  else if (is_abbrev("rewind", nc->getArg(2)) ||
835  is_abbrev("backward", nc->getArg(2)))
836  message = "NETWORK_CONTROL SEEK BACKWARD";
837  else if (nc->getArg(2).contains(QRegExp(R"(^\d\d:\d\d:\d\d$)")))
838  {
839  int hours = nc->getArg(2).mid(0, 2).toInt();
840  int minutes = nc->getArg(2).mid(3, 2).toInt();
841  int seconds = nc->getArg(2).mid(6, 2).toInt();
842  message = QString("NETWORK_CONTROL SEEK POSITION %1")
843  .arg((hours * 3600) + (minutes * 60) + seconds);
844  }
845  else
846  return QString("ERROR: See 'help %1' for usage information")
847  .arg(nc->getArg(0));
848  }
849  else if (is_abbrev("speed", nc->getArg(1), 2))
850  {
851  if (nc->getArgCount() < 3)
852  return QString("ERROR: See 'help %1' for usage information")
853  .arg(nc->getArg(0));
854 
855  QString token2 = nc->getArg(2).toLower();
856  if ((token2.contains(QRegExp("^\\-*\\d+x$"))) ||
857  (token2.contains(QRegExp(R"(^\-*\d+\/\d+x$)"))) ||
858  (token2.contains(QRegExp(R"(^\-*\d*\.\d+x$)"))))
859  message = QString("NETWORK_CONTROL SPEED %1").arg(token2);
860  else if (is_abbrev("normal", token2))
861  message = QString("NETWORK_CONTROL SPEED normal");
862  else if (is_abbrev("pause", token2))
863  message = QString("NETWORK_CONTROL SPEED 0x");
864  else
865  return QString("ERROR: See 'help %1' for usage information")
866  .arg(nc->getArg(0));
867  }
868  else if (is_abbrev("save", nc->getArg(1), 2))
869  {
870  if (is_abbrev("screenshot", nc->getArg(2), 2))
871  return saveScreenshot(nc);
872  }
873  else if (is_abbrev("stop", nc->getArg(1), 2))
874  message = QString("NETWORK_CONTROL STOP");
875  else if (is_abbrev("volume", nc->getArg(1), 2))
876  {
877  if ((nc->getArgCount() < 3) ||
878  (!nc->getArg(2).toLower().contains(QRegExp("^\\d+%?$"))))
879  {
880  return QString("ERROR: See 'help %1' for usage information")
881  .arg(nc->getArg(0));
882  }
883 
884  message = QString("NETWORK_CONTROL VOLUME %1")
885  .arg(nc->getArg(2).toLower());
886  }
887  else if (is_abbrev("subtitles", nc->getArg(1), 2))
888  {
889  if (nc->getArgCount() < 3)
890  message = QString("NETWORK_CONTROL SUBTITLES 0");
891  else if (!nc->getArg(2).toLower().contains(QRegExp("^\\d+$")))
892  {
893  return QString("ERROR: See 'help %1' for usage information")
894  .arg(nc->getArg(0));
895  }
896  else
897  {
898  message = QString("NETWORK_CONTROL SUBTITLES %1")
899  .arg(nc->getArg(2));
900  }
901  }
902  else
903  return QString("ERROR: See 'help %1' for usage information")
904  .arg(nc->getArg(0));
905 
906  if (!message.isEmpty())
907  {
908  MythEvent me(message);
909  gCoreContext->dispatch(me);
910  }
911 
912  return result;
913 }
914 
916 {
917  QString result = "OK";
918 
919  if (nc->getArgCount() < 2)
920  return QString("ERROR: See 'help %1' for usage information")
921  .arg(nc->getArg(0));
922 
923  if (is_abbrev("location", nc->getArg(1)))
924  {
925  bool fullPath = false;
926  bool mainStackOnly = true;
927 
928  if (nc->getArgCount() > 2)
929  fullPath = (nc->getArg(2).toLower() == "true" || nc->getArg(2) == "1");
930  if (nc->getArgCount() > 3)
931  mainStackOnly = (nc->getArg(3).toLower() == "true" || nc->getArg(3) == "1");
932 
933  QString location = GetMythUI()->GetCurrentLocation(fullPath, mainStackOnly);
934  result = location;
935 
936  // if we're playing something, then find out what
937  if (location == "Playback")
938  {
939  result += " ";
940  m_gotAnswer = false;
941  QString message = QString("NETWORK_CONTROL QUERY POSITION");
942  MythEvent me(message);
943  gCoreContext->dispatch(me);
944 
945  QElapsedTimer timer;
946  timer.start();
947  while (!timer.hasExpired(FE_SHORT_TO) && !m_gotAnswer)
948  std::this_thread::sleep_for(std::chrono::milliseconds(10));
949 
950  if (m_gotAnswer)
951  result += m_answer;
952  else
953  result = "ERROR: Timed out waiting for reply from player";
954  }
955  }
956  else if (is_abbrev("verbose", nc->getArg(1)))
957  {
958  return verboseString;
959  }
960  else if (is_abbrev("liveTV", nc->getArg(1)))
961  {
962  if(nc->getArgCount() == 3) // has a channel ID
963  return listSchedule(nc->getArg(2));
964  return listSchedule();
965  }
966  else if (is_abbrev("version", nc->getArg(1)))
967  {
968  int dbSchema = gCoreContext->GetNumSetting("DBSchemaVer");
969 
970  return QString("VERSION: %1/%2 %3 %4 QT/%5 DBSchema/%6")
971  .arg(GetMythSourceVersion())
972  .arg(GetMythSourcePath())
973  .arg(MYTH_BINARY_VERSION)
974  .arg(MYTH_PROTO_VERSION)
975  .arg(QT_VERSION_STR)
976  .arg(dbSchema);
977 
978  }
979  else if(is_abbrev("time", nc->getArg(1)))
981  else if (is_abbrev("uptime", nc->getArg(1)))
982  {
983  QString str;
984  time_t uptime = 0;
985 
986  if (getUptime(uptime))
987  str = QString::number(uptime);
988  else
989  str = QString("Could not determine uptime.");
990  return str;
991  }
992  else if (is_abbrev("load", nc->getArg(1)))
993  {
994  QString str;
995  loadArray loads = getLoadAvgs();
996  if (loads[0] == -1)
997  str = QString("getloadavg() failed");
998  else
999  str = QString("%1 %2 %3").arg(loads[0]).arg(loads[1]).arg(loads[2]);
1000  return str;
1001  }
1002  else if (is_abbrev("memstats", nc->getArg(1)))
1003  {
1004  QString str;
1005  int totalMB = 0;
1006  int freeMB = 0;
1007  int totalVM = 0;
1008  int freeVM = 0;
1009 
1010  if (getMemStats(totalMB, freeMB, totalVM, freeVM))
1011  {
1012  str = QString("%1 %2 %3 %4")
1013  .arg(totalMB).arg(freeMB).arg(totalVM).arg(freeVM);
1014  }
1015  else
1016  {
1017  str = QString("Could not determine memory stats.");
1018  }
1019  return str;
1020  }
1021  else if (is_abbrev("volume", nc->getArg(1)))
1022  {
1023  QString str = "0%";
1024 
1025  QString location = GetMythUI()->GetCurrentLocation(false, false);
1026 
1027  if (location != "Playback")
1028  return str;
1029 
1030  m_gotAnswer = false;
1031  QString message = QString("NETWORK_CONTROL QUERY VOLUME");
1032  MythEvent me(message);
1033  gCoreContext->dispatch(me);
1034 
1035  QElapsedTimer timer;
1036  timer.start();
1037  while (!timer.hasExpired(FE_SHORT_TO) && !m_gotAnswer)
1038  std::this_thread::sleep_for(std::chrono::milliseconds(10));
1039 
1040  if (m_gotAnswer)
1041  str = m_answer;
1042  else
1043  str = "ERROR: Timed out waiting for reply from player";
1044 
1045  return str;
1046  }
1047  else if ((nc->getArgCount() == 4) &&
1048  is_abbrev("recording", nc->getArg(1)) &&
1049  (nc->getArg(2).contains(QRegExp("^\\d+$"))) &&
1050  (nc->getArg(3).contains(QRegExp(
1051  R"(^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d$)"))))
1052  return listRecordings(nc->getArg(2), nc->getArg(3).toUpper());
1053  else if (is_abbrev("recordings", nc->getArg(1)))
1054  return listRecordings();
1055  else if (is_abbrev("channels", nc->getArg(1)))
1056  {
1057  if (nc->getArgCount() == 2)
1058  return listChannels(0, 0); // give us all you can
1059  if (nc->getArgCount() == 4)
1060  return listChannels(nc->getArg(2).toLower().toUInt(),
1061  nc->getArg(3).toLower().toUInt());
1062  return QString("ERROR: See 'help %1' for usage information "
1063  "(parameters mismatch)").arg(nc->getArg(0));
1064  }
1065  else
1066  return QString("ERROR: See 'help %1' for usage information")
1067  .arg(nc->getArg(0));
1068 
1069  return result;
1070 }
1071 
1073 {
1074  if (nc->getArgCount() == 1)
1075  return QString("ERROR: See 'help %1' for usage information")
1076  .arg(nc->getArg(0));
1077 
1078  if (nc->getArg(1) == "verbose")
1079  {
1080  if (nc->getArgCount() < 3)
1081  return QString("ERROR: Missing filter name.");
1082 
1083  if (nc->getArgCount() > 3)
1084  {
1085  return QString("ERROR: Separate filters with commas with no "
1086  "space: playback,audio\r\n See 'help %1' for usage "
1087  "information").arg(nc->getArg(0));
1088  }
1089 
1090  QString oldVerboseString = verboseString;
1091  QString result = "OK";
1092 
1093  int pva_result = verboseArgParse(nc->getArg(2));
1094 
1095  if (pva_result != 0 /*GENERIC_EXIT_OK */)
1096  result = "Failed";
1097 
1098  result += "\r\n";
1099  result += " Previous filter: " + oldVerboseString + "\r\n";
1100  result += " New Filter: " + verboseString + "\r\n";
1101 
1102  LOG(VB_GENERAL, LOG_NOTICE,
1103  QString("Verbose mask changed, new level is: %1")
1104  .arg(verboseString));
1105 
1106  return result;
1107  }
1108 
1109  return QString("ERROR: See 'help %1' for usage information")
1110  .arg(nc->getArg(0));
1111 }
1112 
1114 {
1115  if (dynamic_cast<MythUIText *>(type))
1116  return "MythUIText";
1117  if (dynamic_cast<MythUITextEdit *>(type))
1118  return "MythUITextEdit";
1119  if (dynamic_cast<MythUIGroup *>(type))
1120  return "MythUIGroup";
1121  if (dynamic_cast<MythUIButton *>(type))
1122  return "MythUIButton";
1123  if (dynamic_cast<MythUICheckBox *>(type))
1124  return "MythUICheckBox";
1125  if (dynamic_cast<MythUIShape *>(type))
1126  return "MythUIShape";
1127  if (dynamic_cast<MythUIButtonList *>(type))
1128  return "MythUIButtonList";
1129  if (dynamic_cast<MythUIImage *>(type))
1130  return "MythUIImage";
1131  if (dynamic_cast<MythUISpinBox *>(type))
1132  return "MythUISpinBox";
1133 #if CONFIG_QTWEBKIT
1134  if (dynamic_cast<MythUIWebBrowser *>(type))
1135  return "MythUIWebBrowser";
1136 #endif
1137  if (dynamic_cast<MythUIClock *>(type))
1138  return "MythUIClock";
1139  if (dynamic_cast<MythUIStateType *>(type))
1140  return "MythUIStateType";
1141  if (dynamic_cast<MythUIProgressBar *>(type))
1142  return "MythUIProgressBar";
1143  if (dynamic_cast<MythUIButtonTree *>(type))
1144  return "MythUIButtonTree";
1145  if (dynamic_cast<MythUIScrollBar *>(type))
1146  return "MythUIScrollBar";
1147  if (dynamic_cast<MythUIVideo *>(type))
1148  return "MythUIVideo";
1149  if (dynamic_cast<MythUIGuideGrid *>(type))
1150  return "MythUIGuideGrid";
1151  if (dynamic_cast<MythUIEditBar *>(type))
1152  return "MythUIEditBar";
1153 
1154  return "Unknown";
1155 }
1156 
1158 {
1159  if (nc->getArgCount() == 1)
1160  return QString("ERROR: See 'help %1' for usage information")
1161  .arg(nc->getArg(0));
1162 
1163  if (nc->getArg(1) == "getthemeinfo")
1164  {
1165  QString themeName = GetMythUI()->GetThemeName();
1166  QString themeDir = GetMythUI()->GetThemeDir();
1167  return QString("%1 - %2").arg(themeName).arg(themeDir);
1168  }
1169  if (nc->getArg(1) == "reload")
1170  {
1171  GetMythMainWindow()->JumpTo(m_jumpMap["reloadtheme"]);
1172 
1173  return "OK";
1174  }
1175  if (nc->getArg(1) == "showborders")
1176  {
1177  GetMythMainWindow()->JumpTo(m_jumpMap["showborders"]);
1178 
1179  return "OK";
1180  }
1181  if (nc->getArg(1) == "shownames")
1182  {
1183  GetMythMainWindow()->JumpTo(m_jumpMap["shownames"]);
1184 
1185  return "OK";
1186  }
1187  if (nc->getArg(1) == "getwidgetnames")
1188  {
1189  QStringList path;
1190 
1191  if (nc->getArgCount() >= 3)
1192  path = nc->getArg(2).split('/');
1193 
1194  MythScreenStack *stack = GetMythMainWindow()->GetStack("popup stack");
1195  MythScreenType *topScreen = stack->GetTopScreen();
1196 
1197  if (!topScreen)
1198  {
1199  stack = GetMythMainWindow()->GetMainStack();
1200  topScreen = stack->GetTopScreen();
1201  }
1202 
1203  if (!topScreen)
1204  return QString("ERROR: no top screen found!");
1205 
1206  auto *currType = dynamic_cast<MythUIType*>(topScreen);
1207  if (currType == nullptr)
1208  return QString("ERROR: cannot cast top screen!");
1209 
1210  while (!path.isEmpty())
1211  {
1212  QString childName = path.takeFirst();
1213  currType = currType->GetChild(childName);
1214  if (!currType)
1215  return QString("ERROR: Failed to find child '%1'").arg(childName);
1216  }
1217 
1218  QList<MythUIType*> *children = currType->GetAllChildren();
1219  QString result;
1220 
1221  for (int i = 0; i < children->count(); i++)
1222  {
1223  MythUIType *type = children->at(i);
1224  QString widgetName = type->objectName();
1225  QString widgetType = getWidgetType(type);
1226  result += QString("%1 - %2\n\r").arg(widgetName, -20).arg(widgetType);
1227  }
1228 
1229  return result;
1230  }
1231  if (nc->getArg(1) == "getarea")
1232  {
1233  if (nc->getArgCount() < 3)
1234  return QString("ERROR: Missing widget name.");
1235 
1236  QString widgetName = nc->getArg(2);
1237  QStringList path = widgetName.split('/');
1238 
1239  MythScreenStack *stack = GetMythMainWindow()->GetStack("popup stack");
1240  MythScreenType *topScreen = stack->GetTopScreen();
1241 
1242  if (!topScreen)
1243  {
1244  stack = GetMythMainWindow()->GetMainStack();
1245  topScreen = stack->GetTopScreen();
1246  }
1247 
1248  if (!topScreen)
1249  return QString("ERROR: no top screen found!");
1250 
1251  auto *currType = dynamic_cast<MythUIType*>(topScreen);
1252  if (currType == nullptr)
1253  return QString("ERROR: cannot cast top screen!");
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  auto *currType = dynamic_cast<MythUIType*>(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).arg(x).arg(y).arg(w).arg(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  QRegExp crlfRegEx("\r\n$");
1551  QRegExp 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  QList<NetworkControlClient *>::const_iterator it;
1637  for (it = m_clients.begin(); it != m_clients.end(); ++it)
1638  {
1639  NetworkControlClient *ncc2 = *it;
1640  if (ncc2)
1641  sendReplyToClient(ncc2, reply);
1642  }
1643  }
1644  delete nc;
1645  }
1646  }
1647  else if (e->type() == NetworkControlCloseEvent::kEventType)
1648  {
1649  auto *ncce = dynamic_cast<NetworkControlCloseEvent*>(e);
1650  if (ncce == nullptr)
1651  return;
1652 
1653  NetworkControlClient *ncc = ncce->getClient();
1654  deleteClient(ncc);
1655  }
1656 }
1657 
1658 QString NetworkControl::listSchedule(const QString& chanID)
1659 {
1660  QString result("");
1662  bool appendCRLF = true;
1663  QString queryStr("SELECT chanid, starttime, endtime, title, subtitle "
1664  "FROM program "
1665  "WHERE starttime < :START AND endtime > :END ");
1666 
1667  if (!chanID.isEmpty())
1668  {
1669  queryStr += " AND chanid = :CHANID";
1670  appendCRLF = false;
1671  }
1672 
1673  queryStr += " ORDER BY starttime, endtime, chanid";
1674 
1675  query.prepare(queryStr);
1676  query.bindValue(":START", MythDate::current());
1677  query.bindValue(":END", MythDate::current());
1678  if (!chanID.isEmpty())
1679  {
1680  query.bindValue(":CHANID", chanID);
1681  }
1682 
1683  if (query.exec())
1684  {
1685  while (query.next())
1686  {
1687  QString title = query.value(3).toString();
1688  QString subtitle = query.value(4).toString();
1689 
1690  if (!subtitle.isEmpty())
1691  title += QString(" -\"%1\"").arg(subtitle);
1692  QByteArray atitle = title.toLocal8Bit();
1693 
1694  result +=
1695  QString("%1 %2 %3 %4")
1696  .arg(QString::number(query.value(0).toInt())
1697  .rightJustified(5, ' '))
1698  .arg(MythDate::as_utc(query.value(1).toDateTime()).toString(Qt::ISODate))
1699  .arg(MythDate::as_utc(query.value(2).toDateTime()).toString(Qt::ISODate))
1700  .arg(atitle.constData());
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;
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\"")
1746  .arg(title)
1747  .arg(subtitle);
1748  }
1749  else
1750  {
1751  episode = title;
1752  }
1753 
1754  result +=
1755  QString("%1 %2 %3").arg(query.value(0).toInt())
1756  .arg(MythDate::as_utc(query.value(1).toDateTime()).toString(Qt::ISODate))
1757  .arg(episode);
1758 
1759  if (appendCRLF)
1760  result += "\r\n";
1761  }
1762  }
1763  else
1764  result = "ERROR: Unable to retrieve recordings list.";
1765 
1766  return result;
1767 }
1768 
1769 QString NetworkControl::listChannels(const uint start, const uint limit)
1770 {
1771  QString result;
1773  QString queryStr;
1774  uint sqlStart = start;
1775 
1776  // sql starts at zero, we want to start at 1
1777  if (sqlStart > 0)
1778  sqlStart--;
1779 
1780  queryStr = "select chanid, callsign, name from channel "
1781  "where deleted IS NULL and visible > 0 "
1782  "ORDER BY callsign";
1783 
1784  if (limit > 0) // only if a limit is specified, we limit the results
1785  {
1786  QString limitStr = QString(" LIMIT %1,%2").arg(sqlStart).arg(limit);
1787  queryStr += limitStr;
1788  }
1789 
1790  query.prepare(queryStr);
1791  if (!query.exec())
1792  {
1793  result = "ERROR: Unable to retrieve channel list.";
1794  return result;
1795  }
1796 
1797  uint maxcnt = query.size();
1798  uint cnt = 0;
1799  if (maxcnt == 0) // Feedback we have no usefull information
1800  {
1801  result += QString(R"(0:0 0 "Invalid" "Invalid")");
1802  return result;
1803  }
1804 
1805  while (query.next())
1806  {
1807  // Feedback is as follow:
1808  // <current line count>:<max line count to expect> <channelid> <callsign name> <channel name>\r\n
1809  cnt++;
1810  result += QString("%1:%2 %3 \"%4\" \"%5\"\r\n")
1811  .arg(cnt).arg(maxcnt).arg(query.value(0).toInt())
1812  .arg(query.value(1).toString())
1813  .arg(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 
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:783
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:126
build_compdb.args
args
Definition: build_compdb.py:11
MythMainWindow::GetMainStack
MythScreenStack * GetMainStack()
Definition: mythmainwindow.cpp:304
e
QDomElement e
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:1417
NetworkCommand
Definition: networkcontrol.h:46
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:203
MythEvent::MythEventMessage
static Type MythEventMessage
Definition: mythevent.h:73
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:292
mythuiprogressbar.h
NetworkControl::m_networkControlCommands
QList< NetworkCommand * > m_networkControlCommands
Definition: networkcontrol.h:148
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:98
NetworkControl::notifyDataAvailable
void notifyDataAvailable(void)
Definition: networkcontrol.cpp:1534
mythuivideo.h
MythMainWindow::JumpTo
void JumpTo(const QString &destination, bool pop=true)
Definition: mythmainwindow.cpp:1450
NetworkControl::m_ncLock
QMutex m_ncLock
Definition: networkcontrol.h:149
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:54
NetworkControl::m_keyMap
QMap< QString, int > m_keyMap
Definition: networkcontrol.h:142
NetworkControl::sendReplyToClient
void sendReplyToClient(NetworkControlClient *ncc, QString &reply)
Definition: networkcontrol.cpp:1540
title
QString title
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:633
NetworkControlClient::m_textStream
QTextStream * m_textStream
Definition: networkcontrol.h:42
NetworkControlClient::readClient
void readClient()
Definition: networkcontrol.cpp:410
NetworkControl::receiveCommand
void receiveCommand(QString &command)
Definition: networkcontrol.cpp:438
NetworkControl::getWidgetType
static QString getWidgetType(MythUIType *type)
Definition: networkcontrol.cpp:1113
MythUIEditBar
A narrow purpose widget used to represent cut positions and regions when editing a video.
Definition: mythuieditbar.h:17
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:17
getLoadAvgs
loadArray getLoadAvgs(void)
Returns the system load averages.
Definition: mythmiscutil.cpp:177
NetworkCommand::getFrom
QString getFrom(int arg)
Definition: networkcontrol.cpp:1847
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:198
MythScreenStack
Definition: mythscreenstack.h:16
arg
arg(title).arg(filename).arg(doDelete))
NetworkControlClient::commandReceived
void commandReceived(QString &)
NetworkControl::m_gotAnswer
bool m_gotAnswer
Definition: networkcontrol.h:139
MythNotification
Definition: mythnotification.h:27
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:33
MythUIGroup
Create a group of widgets.
Definition: mythuigroup.h:12
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
NetworkControlClient
Definition: networkcontrol.h:25
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:45
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:26
MythRect
Wrapper around QRect allowing us to handle percentage and other relative values for areas in mythui.
Definition: mythrect.h:18
mythuieditbar.h
networkcontrol.h
remoteutil.h
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &stackname)
Definition: mythmainwindow.cpp:309
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
MythEvent::MythUserMessage
static Type MythUserMessage
Definition: mythevent.h:74
NetworkControl::processSet
static QString processSet(NetworkCommand *nc)
Definition: networkcontrol.cpp:1072
mythversion.h
MythObservable::addListener
void addListener(QObject *listener)
Add a listener to the observable.
Definition: mythobservable.cpp:38
verboseString
QString verboseString
Definition: logging.cpp:105
NetworkControl::processHelp
QString processHelp(NetworkCommand *nc)
Definition: networkcontrol.cpp:1324
programinfo.h
NetworkControl::m_stopCommandThread
bool m_stopCommandThread
Definition: networkcontrol.h:156
mythlogging.h
NetworkControlCloseEvent
Definition: networkcontrol.h:79
NetworkControl::deleteClient
void deleteClient(void)
Definition: networkcontrol.cpp:334
MythUIHelper::GetCurrentLocation
QString GetCurrentLocation(bool fullPath=false, bool mainStackOnly=true)
Definition: mythuihelper.cpp:1448
ACTION_HANDLEMEDIA
#define ACTION_HANDLEMEDIA
Definition: mythuiactions.h:21
MythUIProgressBar
Progress bar widget.
Definition: mythuiprogressbar.h:13
MythCoreContext::SendSystemEvent
void SendSystemEvent(const QString &msg)
Definition: mythcorecontext.cpp:1553
NetworkControl::listChannels
static QString listChannels(uint start, uint limit)
Definition: networkcontrol.cpp:1769
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
compat.h
kNetworkControlDataReadyEvent
static QEvent::Type kNetworkControlDataReadyEvent
Definition: networkcontrol.cpp:56
NetworkControlClient::m_socket
QTcpSocket * m_socket
Definition: networkcontrol.h:41
NetworkControl::processNetworkControlCommand
void processNetworkControlCommand(NetworkCommand *nc)
Definition: networkcontrol.cpp:289
MythUIButton
A single button widget.
Definition: mythuibutton.h:22
NetworkControl::~NetworkControl
~NetworkControl() override
Definition: networkcontrol.cpp:243
MythUIButtonTree
A tree widget for displaying and navigating a MythGenericTree()
Definition: mythuibuttontree.h:17
loadArray
std::array< double, 3 > loadArray
Definition: mythmiscutil.h:21
NetworkControl::processQuery
QString processQuery(NetworkCommand *nc)
Definition: networkcontrol.cpp:915
uint
unsigned int uint
Definition: compat.h:140
MythUIScrollBar
Scroll bar widget.
Definition: mythuiscrollbar.h:16
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
MythUICheckBox
A checkbox widget supporting three check states - on,off,half and two conditions - selected and unsel...
Definition: mythuicheckbox.h:16
NetworkControl::m_keyTextMap
QMap< int, QString > m_keyTextMap
Definition: networkcontrol.h:143
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:930
NetworkControl::m_nrLock
QMutex m_nrLock
Definition: networkcontrol.h:153
GetMythSourcePath
const char * GetMythSourcePath()
Definition: mythcoreutil.cpp:320
getUptime
bool getUptime(time_t &uptime)
Returns uptime statistics.
Definition: mythmiscutil.cpp:65
mythuigroup.h
MythUIType
The base class on which all widgets and screens are based.
Definition: mythuitype.h:64
MythUIShape
A widget for rendering primitive shapes and lines.
Definition: mythuishape.h:22
verboseArgParse
int verboseArgParse(const QString &arg)
Parse the –verbose commandline argument and set the verbose level.
Definition: logging.cpp:982
NetworkCommand::getArgCount
int getArgCount()
Definition: networkcontrol.h:69
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:402
MYTH_BINARY_VERSION
#define MYTH_BINARY_VERSION
Update this whenever the plug-in ABI changes.
Definition: mythversion.h:15
MythUIHelper::IsTopScreenInitialized
static bool IsTopScreenInitialized(void)
Definition: mythuihelper.cpp:314
NetworkCommand::m_command
QString m_command
Definition: networkcontrol.h:73
MYTH_PROTO_VERSION
#define MYTH_PROTO_VERSION
Increment this whenever the MythTV network protocol changes.
Definition: mythversion.h:47
NetworkControl::m_commandThread
MThread * m_commandThread
Definition: networkcontrol.h:155
MythUIText
All purpose text widget, displays a text string.
Definition: mythuitext.h:29
NetworkControl::m_prompt
QString m_prompt
Definition: networkcontrol.h:138
NetworkControlClient::NetworkControlClient
NetworkControlClient(QTcpSocket *s)
Definition: networkcontrol.cpp:394
mythmiscutil.h
MythUIHelper::GetThemeName
QString GetThemeName(void)
Definition: mythuihelper.cpp:1069
NetworkControlClient::getTextStream
QTextStream * getTextStream()
Definition: networkcontrol.h:32
MythUIVideo
Video widget, displays raw image data.
Definition: mythuivideo.h:15
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:864
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:14
NetworkControl::m_jumpMap
QMap< QString, QString > m_jumpMap
Definition: networkcontrol.h:141
FE_SHORT_TO
#define FE_SHORT_TO
Definition: networkcontrol.cpp:53
MythUIHelper::GetThemeDir
QString GetThemeDir(void)
Definition: mythuihelper.cpp:1064
NetworkControl::NetworkControl
NetworkControl()
Definition: networkcontrol.cpp:76
MythUIHelper::ResetScreensaver
static void ResetScreensaver(void)
Definition: mythuihelper.cpp:1380
GetNotificationCenter
MythNotificationCenter * GetNotificationCenter(void)
Definition: mythmainwindow.cpp:127
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:49
NetworkControl::processKey
QString processKey(NetworkCommand *nc)
Definition: networkcontrol.cpp:473
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:107
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:17
NetworkControl::processTheme
QString processTheme(NetworkCommand *nc)
Definition: networkcontrol.cpp:1157
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:271
NetworkControl::m_ncCond
QWaitCondition m_ncCond
Definition: networkcontrol.h:150
NetworkControl::processMessage
static QString processMessage(NetworkCommand *nc)
Definition: networkcontrol.cpp:1509
LOC
#define LOC
Definition: networkcontrol.cpp:50
NetworkControl::m_answer
QString m_answer
Definition: networkcontrol.h:140
NetworkControl::listSchedule
static QString listSchedule(const QString &chanID="")
Definition: networkcontrol.cpp:1658
mythuibutton.h
NetworkCommand::getClient
NetworkControlClient * getClient()
Definition: networkcontrol.h:67
GetMythSourceVersion
const char * GetMythSourceVersion()
Definition: mythcoreutil.cpp:315
NetworkControl::processJump
QString processJump(NetworkCommand *nc)
Definition: networkcontrol.cpp:452
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:856
getMemStats
bool getMemStats(int &totalMB, int &freeMB, int &totalVM, int &freeVM)
Returns memory statistics in megabytes.
Definition: mythmiscutil.cpp:110
NetworkControlCloseEvent::kEventType
static Type kEventType
Definition: networkcontrol.h:86
musicbrainzngs.caa.hostname
string hostname
Definition: caa.py:17
NetworkControl::m_clients
QList< NetworkControlClient * > m_clients
Definition: networkcontrol.h:146
MythUIWebBrowser
Web browsing widget.
Definition: mythuiwebbrowser.h:133
NetworkControl::processPlay
QString processPlay(NetworkCommand *nc, int clientID)
Definition: networkcontrol.cpp:573
MThread::wait
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:309
mythuicheckbox.h
previewgenerator.h
NetworkCommand::getCommand
QString getCommand()
Definition: networkcontrol.h:66
GetMythUI
MythUIHelper * GetMythUI()
Definition: mythuihelper.cpp:81
MythUIButtonList
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
Definition: mythuibuttonlist.h:144
mythuiwebbrowser.h
mythmainwindow.h
NetworkControl::customEvent
void customEvent(QEvent *e) override
Definition: networkcontrol.cpp:1569
NetworkCommand::getArg
QString getArg(int arg)
Definition: networkcontrol.h:68
query
MSqlQuery query(MSqlQuery::InitCon())
NetworkControlClient::getSocket
QTcpSocket * getSocket()
Definition: networkcontrol.h:31
MythCoreContext::dispatch
void dispatch(const MythEvent &event)
Definition: mythcorecontext.cpp:1733
MythObservable::removeListener
void removeListener(QObject *listener)
Remove a listener to the observable.
Definition: mythobservable.cpp:55
NetworkControl::m_clientLock
QMutex m_clientLock
Definition: networkcontrol.h:145
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:68
MythMainWindow
Definition: mythmainwindow.h:33
mythuishape.h
MythUIStateType
This widget is used for grouping other widgets for display when a particular named state is called....
Definition: mythuistatetype.h:23
NetworkControl::newConnection
void newConnection(QTcpSocket *client)
Definition: networkcontrol.cpp:367
NetworkControl::m_networkControlReplies
QList< NetworkCommand * > m_networkControlReplies
Definition: networkcontrol.h:152
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:808
MythScreenStack::GetTopScreen
virtual MythScreenType * GetTopScreen(void) const
Definition: mythscreenstack.cpp:179
MythNotificationCenter::Queue
bool Queue(const MythNotification &notification)
Queue a notification Queue() is thread-safe and can be called from anywhere.
Definition: mythnotificationcenter.cpp:1351