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