|
MythTV
0.26-pre
|
00001 #include <unistd.h> 00002 00003 #include <QCoreApplication> 00004 #include <QRegExp> 00005 #include <QStringList> 00006 #include <QTextStream> 00007 #include <QDir> 00008 #include <QKeyEvent> 00009 #include <QEvent> 00010 #include <QMap> 00011 00012 #include "mythcorecontext.h" 00013 #include "mythversion.h" 00014 #include "networkcontrol.h" 00015 #include "programinfo.h" 00016 #include "remoteutil.h" 00017 #include "previewgenerator.h" 00018 #include "compat.h" 00019 #include "mythsystemevent.h" 00020 #include "mythdirs.h" 00021 #include "mythlogging.h" 00022 00023 // libmythui 00024 #include "mythmainwindow.h" 00025 #include "mythuihelper.h" 00026 00027 #define LOC QString("NetworkControl: ") 00028 #define LOC_ERR QString("NetworkControl Error: ") 00029 00030 #define FE_SHORT_TO 2000 00031 #define FE_LONG_TO 10000 00032 00033 static QEvent::Type kNetworkControlDataReadyEvent = 00034 (QEvent::Type) QEvent::registerEventType(); 00035 QEvent::Type NetworkControlCloseEvent::kEventType = 00036 (QEvent::Type) QEvent::registerEventType(); 00037 00045 static bool is_abbrev(QString const& command, 00046 QString const& test, int minchars = 1) 00047 { 00048 if (test.length() < minchars) 00049 return command.toLower() == test.toLower(); 00050 else 00051 return test.toLower() == command.left(test.length()).toLower(); 00052 } 00053 00054 NetworkControl::NetworkControl() : 00055 ServerPool(), prompt("# "), 00056 gotAnswer(false), answer(""), 00057 clientLock(QMutex::Recursive), 00058 commandThread(new MThread("NetworkControl", this)), 00059 stopCommandThread(false) 00060 { 00061 // Eventually this map should be in the jumppoints table 00062 jumpMap["channelpriorities"] = "Channel Recording Priorities"; 00063 jumpMap["livetv"] = "Live TV"; 00064 jumpMap["livetvinguide"] = "Live TV In Guide"; 00065 jumpMap["mainmenu"] = "Main Menu"; 00066 jumpMap["managerecordings"] = "Manage Recordings / Fix Conflicts"; 00067 jumpMap["mythgallery"] = "MythGallery"; 00068 jumpMap["mythvideo"] = "Video Default"; 00069 jumpMap["mythweather"] = "MythWeather"; 00070 jumpMap["mythgame"] = "MythGame"; 00071 jumpMap["mythnews"] = "MythNews"; 00072 jumpMap["playdvd"] = "Play Disc"; 00073 jumpMap["playmusic"] = "Play music"; 00074 jumpMap["programfinder"] = "Program Finder"; 00075 jumpMap["programguide"] = "Program Guide"; 00076 jumpMap["recordingpriorities"] = "Program Recording Priorities"; 00077 jumpMap["ripcd"] = "Rip CD"; 00078 jumpMap["musicplaylists"] = "Select music playlists"; 00079 jumpMap["deleterecordings"] = "TV Recording Deletion"; 00080 jumpMap["playbackrecordings"] = "TV Recording Playback"; 00081 jumpMap["videobrowser"] = "Video Browser"; 00082 jumpMap["videogallery"] = "Video Gallery"; 00083 jumpMap["videolistings"] = "Video Listings"; 00084 jumpMap["videomanager"] = "Video Manager"; 00085 jumpMap["zoneminderconsole"] = "ZoneMinder Console"; 00086 jumpMap["zoneminderliveview"] = "ZoneMinder Live View"; 00087 jumpMap["zoneminderevents"] = "ZoneMinder Events"; 00088 00089 jumpMap["channelrecpriority"] = "Channel Recording Priorities"; 00090 jumpMap["viewscheduled"] = "Manage Recordings / Fix Conflicts"; 00091 jumpMap["previousbox"] = "Previously Recorded"; 00092 jumpMap["progfinder"] = "Program Finder"; 00093 jumpMap["guidegrid"] = "Program Guide"; 00094 jumpMap["programrecpriority"] = "Program Recording Priorities"; 00095 jumpMap["statusbox"] = "Status Screen"; 00096 jumpMap["deletebox"] = "TV Recording Deletion"; 00097 jumpMap["playbackbox"] = "TV Recording Playback"; 00098 jumpMap["pbb"] = "TV Recording Playback"; 00099 00100 keyMap["up"] = Qt::Key_Up; 00101 keyMap["down"] = Qt::Key_Down; 00102 keyMap["left"] = Qt::Key_Left; 00103 keyMap["right"] = Qt::Key_Right; 00104 keyMap["home"] = Qt::Key_Home; 00105 keyMap["end"] = Qt::Key_End; 00106 keyMap["enter"] = Qt::Key_Enter; 00107 keyMap["return"] = Qt::Key_Return; 00108 keyMap["pageup"] = Qt::Key_PageUp; 00109 keyMap["pagedown"] = Qt::Key_PageDown; 00110 keyMap["escape"] = Qt::Key_Escape; 00111 keyMap["tab"] = Qt::Key_Tab; 00112 keyMap["backtab"] = Qt::Key_Backtab; 00113 keyMap["space"] = Qt::Key_Space; 00114 keyMap["backspace"] = Qt::Key_Backspace; 00115 keyMap["insert"] = Qt::Key_Insert; 00116 keyMap["delete"] = Qt::Key_Delete; 00117 keyMap["plus"] = Qt::Key_Plus; 00118 keyMap["+"] = Qt::Key_Plus; 00119 keyMap["comma"] = Qt::Key_Comma; 00120 keyMap[","] = Qt::Key_Comma; 00121 keyMap["minus"] = Qt::Key_Minus; 00122 keyMap["-"] = Qt::Key_Minus; 00123 keyMap["underscore"] = Qt::Key_Underscore; 00124 keyMap["_"] = Qt::Key_Underscore; 00125 keyMap["period"] = Qt::Key_Period; 00126 keyMap["."] = Qt::Key_Period; 00127 keyMap["numbersign"] = Qt::Key_NumberSign; 00128 keyMap["poundsign"] = Qt::Key_NumberSign; 00129 keyMap["hash"] = Qt::Key_NumberSign; 00130 keyMap["#"] = Qt::Key_NumberSign; 00131 keyMap["bracketleft"] = Qt::Key_BracketLeft; 00132 keyMap["["] = Qt::Key_BracketLeft; 00133 keyMap["bracketright"] = Qt::Key_BracketRight; 00134 keyMap["]"] = Qt::Key_BracketRight; 00135 keyMap["backslash"] = Qt::Key_Backslash; 00136 keyMap["\\"] = Qt::Key_Backslash; 00137 keyMap["dollar"] = Qt::Key_Dollar; 00138 keyMap["$"] = Qt::Key_Dollar; 00139 keyMap["percent"] = Qt::Key_Percent; 00140 keyMap["%"] = Qt::Key_Percent; 00141 keyMap["ampersand"] = Qt::Key_Ampersand; 00142 keyMap["&"] = Qt::Key_Ampersand; 00143 keyMap["parenleft"] = Qt::Key_ParenLeft; 00144 keyMap["("] = Qt::Key_ParenLeft; 00145 keyMap["parenright"] = Qt::Key_ParenRight; 00146 keyMap[")"] = Qt::Key_ParenRight; 00147 keyMap["asterisk"] = Qt::Key_Asterisk; 00148 keyMap["*"] = Qt::Key_Asterisk; 00149 keyMap["question"] = Qt::Key_Question; 00150 keyMap["?"] = Qt::Key_Question; 00151 keyMap["slash"] = Qt::Key_Slash; 00152 keyMap["/"] = Qt::Key_Slash; 00153 keyMap["colon"] = Qt::Key_Colon; 00154 keyMap[":"] = Qt::Key_Colon; 00155 keyMap["semicolon"] = Qt::Key_Semicolon; 00156 keyMap[";"] = Qt::Key_Semicolon; 00157 keyMap["less"] = Qt::Key_Less; 00158 keyMap["<"] = Qt::Key_Less; 00159 keyMap["equal"] = Qt::Key_Equal; 00160 keyMap["="] = Qt::Key_Equal; 00161 keyMap["greater"] = Qt::Key_Greater; 00162 keyMap[">"] = Qt::Key_Greater; 00163 keyMap["bar"] = Qt::Key_Bar; 00164 keyMap["pipe"] = Qt::Key_Bar; 00165 keyMap["|"] = Qt::Key_Bar; 00166 keyMap["f1"] = Qt::Key_F1; 00167 keyMap["f2"] = Qt::Key_F2; 00168 keyMap["f3"] = Qt::Key_F3; 00169 keyMap["f4"] = Qt::Key_F4; 00170 keyMap["f5"] = Qt::Key_F5; 00171 keyMap["f6"] = Qt::Key_F6; 00172 keyMap["f7"] = Qt::Key_F7; 00173 keyMap["f8"] = Qt::Key_F8; 00174 keyMap["f9"] = Qt::Key_F9; 00175 keyMap["f10"] = Qt::Key_F10; 00176 keyMap["f11"] = Qt::Key_F11; 00177 keyMap["f12"] = Qt::Key_F12; 00178 keyMap["f13"] = Qt::Key_F13; 00179 keyMap["f14"] = Qt::Key_F14; 00180 keyMap["f15"] = Qt::Key_F15; 00181 keyMap["f16"] = Qt::Key_F16; 00182 keyMap["f17"] = Qt::Key_F17; 00183 keyMap["f18"] = Qt::Key_F18; 00184 keyMap["f19"] = Qt::Key_F19; 00185 keyMap["f20"] = Qt::Key_F20; 00186 keyMap["f21"] = Qt::Key_F21; 00187 keyMap["f22"] = Qt::Key_F22; 00188 keyMap["f23"] = Qt::Key_F23; 00189 keyMap["f24"] = Qt::Key_F24; 00190 00191 keyTextMap[Qt::Key_Plus] = "+"; 00192 keyTextMap[Qt::Key_Comma] = ","; 00193 keyTextMap[Qt::Key_Minus] = "-"; 00194 keyTextMap[Qt::Key_Underscore] = "_"; 00195 keyTextMap[Qt::Key_Period] = "."; 00196 keyTextMap[Qt::Key_NumberSign] = "#"; 00197 keyTextMap[Qt::Key_BracketLeft] = "["; 00198 keyTextMap[Qt::Key_BracketRight] = "]"; 00199 keyTextMap[Qt::Key_Backslash] = "\\"; 00200 keyTextMap[Qt::Key_Dollar] = "$"; 00201 keyTextMap[Qt::Key_Percent] = "%"; 00202 keyTextMap[Qt::Key_Ampersand] = "&"; 00203 keyTextMap[Qt::Key_ParenLeft] = "("; 00204 keyTextMap[Qt::Key_ParenRight] = ")"; 00205 keyTextMap[Qt::Key_Asterisk] = "*"; 00206 keyTextMap[Qt::Key_Question] = "?"; 00207 keyTextMap[Qt::Key_Slash] = "/"; 00208 keyTextMap[Qt::Key_Colon] = ":"; 00209 keyTextMap[Qt::Key_Semicolon] = ";"; 00210 keyTextMap[Qt::Key_Less] = "<"; 00211 keyTextMap[Qt::Key_Equal] = "="; 00212 keyTextMap[Qt::Key_Greater] = ">"; 00213 keyTextMap[Qt::Key_Bar] = "|"; 00214 00215 commandThread->start(); 00216 00217 gCoreContext->addListener(this); 00218 00219 connect(this, SIGNAL(newConnection(QTcpSocket*)), 00220 this, SLOT(newConnection(QTcpSocket*))); 00221 } 00222 00223 NetworkControl::~NetworkControl(void) 00224 { 00225 gCoreContext->removeListener(this); 00226 00227 clientLock.lock(); 00228 while (!clients.isEmpty()) 00229 { 00230 NetworkControlClient *ncc = clients.takeFirst(); 00231 delete ncc; 00232 } 00233 clientLock.unlock(); 00234 00235 nrLock.lock(); 00236 networkControlReplies.push_back(new NetworkCommand(NULL, 00237 "mythfrontend shutting down, connection closing...")); 00238 nrLock.unlock(); 00239 00240 notifyDataAvailable(); 00241 00242 ncLock.lock(); 00243 stopCommandThread = true; 00244 ncCond.wakeOne(); 00245 ncLock.unlock(); 00246 commandThread->wait(); 00247 delete commandThread; 00248 commandThread = NULL; 00249 } 00250 00251 void NetworkControl::run(void) 00252 { 00253 QMutexLocker locker(&ncLock); 00254 while (!stopCommandThread) 00255 { 00256 while (networkControlCommands.empty() && !stopCommandThread) 00257 ncCond.wait(&ncLock); 00258 if (!stopCommandThread) 00259 { 00260 NetworkCommand *nc = networkControlCommands.front(); 00261 networkControlCommands.pop_front(); 00262 locker.unlock(); 00263 processNetworkControlCommand(nc); 00264 locker.relock(); 00265 } 00266 } 00267 } 00268 00269 void NetworkControl::processNetworkControlCommand(NetworkCommand *nc) 00270 { 00271 QMutexLocker locker(&clientLock); 00272 QString result; 00273 00274 int clientID = clients.indexOf(nc->getClient()); 00275 00276 if (is_abbrev("jump", nc->getArg(0))) 00277 result = processJump(nc); 00278 else if (is_abbrev("key", nc->getArg(0))) 00279 result = processKey(nc); 00280 else if (is_abbrev("play", nc->getArg(0))) 00281 result = processPlay(nc, clientID); 00282 else if (is_abbrev("query", nc->getArg(0))) 00283 result = processQuery(nc); 00284 else if (is_abbrev("set", nc->getArg(0))) 00285 result = processSet(nc); 00286 else if (is_abbrev("screenshot", nc->getArg(0))) 00287 result = saveScreenshot(nc); 00288 else if (is_abbrev("help", nc->getArg(0))) 00289 result = processHelp(nc); 00290 else if (is_abbrev("message", nc->getArg(0))) 00291 result = processMessage(nc); 00292 else if ((nc->getArg(0).toLower() == "exit") || (nc->getArg(0).toLower() == "quit")) 00293 QCoreApplication::postEvent(this, 00294 new NetworkControlCloseEvent(nc->getClient())); 00295 else if (! nc->getArg(0).isEmpty()) 00296 result = QString("INVALID command '%1', try 'help' for more info") 00297 .arg(nc->getArg(0)); 00298 00299 nrLock.lock(); 00300 networkControlReplies.push_back(new NetworkCommand(nc->getClient(),result)); 00301 nrLock.unlock(); 00302 00303 notifyDataAvailable(); 00304 } 00305 00306 void NetworkControl::deleteClient(void) 00307 { 00308 LOG(VB_GENERAL, LOG_INFO, LOC + "Client Socket disconnected"); 00309 QMutexLocker locker(&clientLock); 00310 00311 gCoreContext->SendSystemEvent("NET_CTRL_DISCONNECTED"); 00312 00313 QList<NetworkControlClient *>::const_iterator it; 00314 for (it = clients.begin(); it != clients.end(); ++it) 00315 { 00316 NetworkControlClient *ncc = *it; 00317 if (ncc->getSocket()->state() == QTcpSocket::UnconnectedState) 00318 { 00319 deleteClient(ncc); 00320 return; 00321 } 00322 } 00323 } 00324 00325 void NetworkControl::deleteClient(NetworkControlClient *ncc) 00326 { 00327 int index = clients.indexOf(ncc); 00328 if (index >= 0) 00329 { 00330 clients.removeAt(index); 00331 00332 delete ncc; 00333 } 00334 else 00335 LOG(VB_GENERAL, LOG_ERR, LOC + QString("deleteClient(%1), unable to " 00336 "locate specified NetworkControlClient").arg((long long)ncc)); 00337 } 00338 00339 void NetworkControl::newConnection(QTcpSocket *client) 00340 { 00341 QString welcomeStr; 00342 00343 LOG(VB_GENERAL, LOG_INFO, LOC + QString("New connection established.")); 00344 00345 gCoreContext->SendSystemEvent("NET_CTRL_CONNECTED"); 00346 00347 NetworkControlClient *ncc = new NetworkControlClient(client); 00348 00349 QMutexLocker locker(&clientLock); 00350 clients.push_back(ncc); 00351 00352 connect(ncc, SIGNAL(commandReceived(QString&)), this, 00353 SLOT(receiveCommand(QString&))); 00354 connect(client, SIGNAL(disconnected()), this, SLOT(deleteClient())); 00355 00356 welcomeStr = "MythFrontend Network Control\r\n"; 00357 welcomeStr += "Type 'help' for usage information\r\n" 00358 "---------------------------------"; 00359 nrLock.lock(); 00360 networkControlReplies.push_back(new NetworkCommand(ncc,welcomeStr)); 00361 nrLock.unlock(); 00362 00363 notifyDataAvailable(); 00364 } 00365 00366 NetworkControlClient::NetworkControlClient(QTcpSocket *s) 00367 { 00368 m_socket = s; 00369 m_textStream = new QTextStream(s); 00370 m_textStream->setCodec("UTF-8"); 00371 connect(m_socket, SIGNAL(readyRead()), this, SLOT(readClient())); 00372 } 00373 00374 NetworkControlClient::~NetworkControlClient() 00375 { 00376 m_socket->close(); 00377 m_socket->deleteLater(); 00378 00379 delete m_textStream; 00380 } 00381 00382 void NetworkControlClient::readClient(void) 00383 { 00384 QTcpSocket *socket = (QTcpSocket *)sender(); 00385 if (!socket) 00386 return; 00387 00388 QString lineIn; 00389 while (socket->canReadLine()) 00390 { 00391 lineIn = socket->readLine(); 00392 #if 0 00393 lineIn.replace(QRegExp("[^-a-zA-Z0-9\\s\\.:_#/$%&()*+,;<=>?\\[\\]\\|]"), 00394 ""); 00395 #endif 00396 00397 // TODO: can this be replaced with lineIn.simplify()? 00398 lineIn.replace(QRegExp("[\r\n]"), ""); 00399 lineIn.replace(QRegExp("^\\s"), ""); 00400 00401 if (lineIn.isEmpty()) 00402 continue; 00403 00404 LOG(VB_NETWORK, LOG_INFO, LOC + 00405 QString("emit commandReceived(%1)").arg(lineIn)); 00406 emit commandReceived(lineIn); 00407 } 00408 } 00409 00410 void NetworkControl::receiveCommand(QString &command) 00411 { 00412 LOG(VB_NETWORK, LOG_INFO, LOC + 00413 QString("NetworkControl::receiveCommand(%1)").arg(command)); 00414 NetworkControlClient *ncc = static_cast<NetworkControlClient *>(sender()); 00415 if (!ncc) 00416 return; 00417 00418 ncLock.lock(); 00419 networkControlCommands.push_back(new NetworkCommand(ncc,command)); 00420 ncCond.wakeOne(); 00421 ncLock.unlock(); 00422 } 00423 00424 QString NetworkControl::processJump(NetworkCommand *nc) 00425 { 00426 QString result = "OK"; 00427 00428 if ((nc->getArgCount() < 2) || (!jumpMap.contains(nc->getArg(1)))) 00429 return QString("ERROR: See 'help %1' for usage information") 00430 .arg(nc->getArg(0)); 00431 00432 GetMythMainWindow()->JumpTo(jumpMap[nc->getArg(1)]); 00433 00434 // Fixme, should do some better checking here, but that would 00435 // depend on all Locations matching their jumppoints 00436 QTime timer; 00437 timer.start(); 00438 while ((timer.elapsed() < FE_SHORT_TO) && 00439 (GetMythUI()->GetCurrentLocation().toLower() != nc->getArg(1))) 00440 usleep(10000); 00441 00442 return result; 00443 } 00444 00445 QString NetworkControl::processKey(NetworkCommand *nc) 00446 { 00447 QString result = "OK"; 00448 QKeyEvent *event = NULL; 00449 00450 if (nc->getArgCount() < 2) 00451 return QString("ERROR: See 'help %1' for usage information") 00452 .arg(nc->getArg(0)); 00453 00454 QObject *keyDest = NULL; 00455 00456 if (GetMythMainWindow()) 00457 keyDest = GetMythMainWindow(); 00458 else 00459 return QString("ERROR: Application has no main window!\n"); 00460 00461 if (GetMythMainWindow()->currentWidget()) 00462 keyDest = GetMythMainWindow()->currentWidget()->focusWidget(); 00463 00464 int curToken = 1; 00465 int tokenLen = 0; 00466 while (curToken < nc->getArgCount()) 00467 { 00468 tokenLen = nc->getArg(curToken).length(); 00469 00470 if (nc->getArg(curToken) == "sleep") 00471 { 00472 sleep(1); 00473 } 00474 else if (keyMap.contains(nc->getArg(curToken))) 00475 { 00476 int keyCode = keyMap[nc->getArg(curToken)]; 00477 QString keyText; 00478 00479 if (keyTextMap.contains(keyCode)) 00480 keyText = keyTextMap[keyCode]; 00481 00482 GetMythUI()->ResetScreensaver(); 00483 00484 event = new QKeyEvent(QEvent::KeyPress, keyCode, Qt::NoModifier, 00485 keyText); 00486 QCoreApplication::postEvent(keyDest, event); 00487 00488 event = new QKeyEvent(QEvent::KeyRelease, keyCode, Qt::NoModifier, 00489 keyText); 00490 QCoreApplication::postEvent(keyDest, event); 00491 } 00492 else if (((tokenLen == 1) && 00493 (nc->getArg(curToken)[0].isLetterOrNumber())) || 00494 ((tokenLen >= 1) && 00495 (nc->getArg(curToken).contains("+")))) 00496 { 00497 QKeySequence a(nc->getArg(curToken)); 00498 int keyCode = a[0]; 00499 Qt::KeyboardModifiers modifiers = Qt::NoModifier; 00500 00501 if (tokenLen > 1) 00502 { 00503 QStringList tokenParts = nc->getArg(curToken).split('+'); 00504 00505 int partNum = 0; 00506 while (partNum < (tokenParts.size() - 1)) 00507 { 00508 if (tokenParts[partNum].toUpper() == "CTRL") 00509 modifiers |= Qt::ControlModifier; 00510 if (tokenParts[partNum].toUpper() == "SHIFT") 00511 modifiers |= Qt::ShiftModifier; 00512 if (tokenParts[partNum].toUpper() == "ALT") 00513 modifiers |= Qt::AltModifier; 00514 if (tokenParts[partNum].toUpper() == "META") 00515 modifiers |= Qt::MetaModifier; 00516 00517 partNum++; 00518 } 00519 } 00520 else 00521 { 00522 if (nc->getArg(curToken) == nc->getArg(curToken).toUpper()) 00523 modifiers = Qt::ShiftModifier; 00524 } 00525 00526 GetMythUI()->ResetScreensaver(); 00527 00528 event = new QKeyEvent(QEvent::KeyPress, keyCode, modifiers, 00529 nc->getArg(curToken)); 00530 QCoreApplication::postEvent(keyDest, event); 00531 00532 event = new QKeyEvent(QEvent::KeyRelease, keyCode, modifiers, 00533 nc->getArg(curToken)); 00534 QCoreApplication::postEvent(keyDest, event); 00535 } 00536 else 00537 return QString("ERROR: Invalid syntax at '%1', see 'help %2' for " 00538 "usage information") 00539 .arg(nc->getArg(curToken)).arg(nc->getArg(0)); 00540 00541 curToken++; 00542 } 00543 00544 return result; 00545 } 00546 00547 QString NetworkControl::processPlay(NetworkCommand *nc, int clientID) 00548 { 00549 QString result = "OK"; 00550 QString message; 00551 00552 if (nc->getArgCount() < 2) 00553 return QString("ERROR: See 'help %1' for usage information") 00554 .arg(nc->getArg(0)); 00555 00556 if ((nc->getArgCount() >= 3) && 00557 (is_abbrev("file", nc->getArg(1)))) 00558 { 00559 if (GetMythUI()->GetCurrentLocation().toLower() != "mainmenu") 00560 { 00561 GetMythMainWindow()->JumpTo(jumpMap["mainmenu"]); 00562 00563 QTime timer; 00564 timer.start(); 00565 while ((timer.elapsed() < FE_LONG_TO) && 00566 (GetMythUI()->GetCurrentLocation().toLower() != "mainmenu")) 00567 usleep(10000); 00568 } 00569 00570 if (GetMythUI()->GetCurrentLocation().toLower() == "mainmenu") 00571 { 00572 QStringList args; 00573 args << nc->getFrom(2); 00574 MythEvent *me = new MythEvent(ACTION_HANDLEMEDIA, args); 00575 qApp->postEvent(GetMythMainWindow(), me); 00576 } 00577 else 00578 return QString("Unable to change to main menu to start playback!"); 00579 } 00580 else if ((nc->getArgCount() >= 4) && 00581 (is_abbrev("program", nc->getArg(1))) && 00582 (nc->getArg(2).contains(QRegExp("^\\d+$"))) && 00583 (nc->getArg(3).contains(QRegExp( 00584 "^\\d\\d\\d\\d-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d$")))) 00585 { 00586 if (GetMythUI()->GetCurrentLocation().toLower() == "playback") 00587 { 00588 QString message = QString("NETWORK_CONTROL STOP"); 00589 MythEvent me(message); 00590 gCoreContext->dispatch(me); 00591 00592 QTime timer; 00593 timer.start(); 00594 while ((timer.elapsed() < FE_LONG_TO) && 00595 (GetMythUI()->GetCurrentLocation().toLower() == "playback")) 00596 usleep(10000); 00597 } 00598 00599 if (GetMythUI()->GetCurrentLocation().toLower() != "playbackbox") 00600 { 00601 GetMythMainWindow()->JumpTo(jumpMap["playbackbox"]); 00602 00603 QTime timer; 00604 timer.start(); 00605 while ((timer.elapsed() < 10000) && 00606 (GetMythUI()->GetCurrentLocation().toLower() != "playbackbox")) 00607 usleep(10000); 00608 00609 timer.start(); 00610 while ((timer.elapsed() < 10000) && 00611 (!GetMythUI()->IsTopScreenInitialized())) 00612 usleep(10000); 00613 } 00614 00615 if (GetMythUI()->GetCurrentLocation().toLower() == "playbackbox") 00616 { 00617 QString action = "PLAY"; 00618 if (nc->getArgCount() == 5 && nc->getArg(4) == "resume") 00619 action = "RESUME"; 00620 00621 QString message = QString("NETWORK_CONTROL %1 PROGRAM %2 %3 %4") 00622 .arg(action).arg(nc->getArg(2)) 00623 .arg(nc->getArg(3).toUpper()).arg(clientID); 00624 00625 result.clear(); 00626 gotAnswer = false; 00627 QTime timer; 00628 timer.start(); 00629 00630 MythEvent me(message); 00631 gCoreContext->dispatch(me); 00632 00633 while (timer.elapsed() < FE_LONG_TO && !gotAnswer) 00634 usleep(10000); 00635 00636 if (gotAnswer) 00637 result += answer; 00638 else 00639 result = "ERROR: Timed out waiting for reply from player"; 00640 00641 } 00642 else 00643 { 00644 result = QString("ERROR: Unable to change to PlaybackBox from " 00645 "%1, cannot play requested file.") 00646 .arg(GetMythUI()->GetCurrentLocation()); 00647 } 00648 } 00649 else if (is_abbrev("music", nc->getArg(1))) 00650 { 00651 #if 0 00652 if (GetMythUI()->GetCurrentLocation().toLower() != "playmusic") 00653 { 00654 return QString("ERROR: You are in %1 mode and this command is " 00655 "only for MythMusic") 00656 .arg(GetMythUI()->GetCurrentLocation()); 00657 } 00658 #endif 00659 00660 QString hostname = gCoreContext->GetHostName(); 00661 00662 if (nc->getArgCount() == 3) 00663 { 00664 if (is_abbrev("play", nc->getArg(2))) 00665 message = QString("MUSIC_COMMAND %1 PLAY").arg(hostname); 00666 else if (is_abbrev("pause", nc->getArg(2))) 00667 message = QString("MUSIC_COMMAND %1 PAUSE").arg(hostname); 00668 else if (is_abbrev("stop", nc->getArg(2))) 00669 message = QString("MUSIC_COMMAND %1 STOP").arg(hostname); 00670 else if (is_abbrev("getvolume", nc->getArg(2))) 00671 { 00672 gotAnswer = false; 00673 00674 MythEvent me(QString("MUSIC_COMMAND %1 GET_VOLUME").arg(hostname)); 00675 gCoreContext->dispatch(me); 00676 00677 QTime timer; 00678 timer.start(); 00679 while (timer.elapsed() < FE_SHORT_TO && !gotAnswer) 00680 { 00681 qApp->processEvents(); 00682 usleep(10000); 00683 } 00684 00685 if (gotAnswer) 00686 return answer; 00687 00688 return "unknown"; 00689 } 00690 else if (is_abbrev("getmeta", nc->getArg(2))) 00691 { 00692 gotAnswer = false; 00693 00694 MythEvent me(QString("MUSIC_COMMAND %1 GET_METADATA").arg(hostname)); 00695 gCoreContext->dispatch(me); 00696 00697 QTime timer; 00698 timer.start(); 00699 while (timer.elapsed() < FE_SHORT_TO && !gotAnswer) 00700 { 00701 qApp->processEvents(); 00702 usleep(10000); 00703 } 00704 00705 if (gotAnswer) 00706 return answer; 00707 00708 return "unknown"; 00709 } 00710 else 00711 return QString("ERROR: Invalid 'play music' command"); 00712 } 00713 else if (nc->getArgCount() > 3) 00714 { 00715 if (is_abbrev("setvolume", nc->getArg(2))) 00716 message = QString("MUSIC_COMMAND %1 SET_VOLUME %2") 00717 .arg(hostname) 00718 .arg(nc->getArg(3)); 00719 else if (is_abbrev("track", nc->getArg(2))) 00720 message = QString("MUSIC_COMMAND %1 PLAY_TRACK %2") 00721 .arg(hostname) 00722 .arg(nc->getArg(3)); 00723 else if (is_abbrev("url", nc->getArg(2))) 00724 message = QString("MUSIC_COMMAND %1 PLAY_URL %2") 00725 .arg(hostname) 00726 .arg(nc->getArg(3)); 00727 else if (is_abbrev("file", nc->getArg(2))) 00728 message = QString("MUSIC_COMMAND %1 PLAY_FILE '%2'") 00729 .arg(hostname) 00730 .arg(nc->getFrom(3)); 00731 else 00732 return QString("ERROR: Invalid 'play music' command"); 00733 } 00734 else 00735 return QString("ERROR: Invalid 'play music' command"); 00736 } 00737 // Everything below here requires us to be in playback mode so check to 00738 // see if we are 00739 else if (GetMythUI()->GetCurrentLocation().toLower() != "playback") 00740 { 00741 return QString("ERROR: You are in %1 mode and this command is only " 00742 "for playback mode") 00743 .arg(GetMythUI()->GetCurrentLocation()); 00744 } 00745 else if (is_abbrev("chanid", nc->getArg(1), 5)) 00746 { 00747 if (nc->getArg(2).contains(QRegExp("^\\d+$"))) 00748 message = QString("NETWORK_CONTROL CHANID %1").arg(nc->getArg(2)); 00749 else 00750 return QString("ERROR: See 'help %1' for usage information") 00751 .arg(nc->getArg(0)); 00752 } 00753 else if (is_abbrev("channel", nc->getArg(1), 5)) 00754 { 00755 if (nc->getArgCount() < 3) 00756 return "ERROR: See 'help play' for usage information"; 00757 00758 if (is_abbrev("up", nc->getArg(2))) 00759 message = "NETWORK_CONTROL CHANNEL UP"; 00760 else if (is_abbrev("down", nc->getArg(2))) 00761 message = "NETWORK_CONTROL CHANNEL DOWN"; 00762 else if (nc->getArg(2).contains(QRegExp("^[-\\.\\d_#]+$"))) 00763 message = QString("NETWORK_CONTROL CHANNEL %1").arg(nc->getArg(2)); 00764 else 00765 return QString("ERROR: See 'help %1' for usage information") 00766 .arg(nc->getArg(0)); 00767 } 00768 else if (is_abbrev("seek", nc->getArg(1), 2)) 00769 { 00770 if (nc->getArgCount() < 3) 00771 return QString("ERROR: See 'help %1' for usage information") 00772 .arg(nc->getArg(0)); 00773 00774 if (is_abbrev("beginning", nc->getArg(2))) 00775 message = "NETWORK_CONTROL SEEK BEGINNING"; 00776 else if (is_abbrev("forward", nc->getArg(2))) 00777 message = "NETWORK_CONTROL SEEK FORWARD"; 00778 else if (is_abbrev("rewind", nc->getArg(2)) || 00779 is_abbrev("backward", nc->getArg(2))) 00780 message = "NETWORK_CONTROL SEEK BACKWARD"; 00781 else if (nc->getArg(2).contains(QRegExp("^\\d\\d:\\d\\d:\\d\\d$"))) 00782 { 00783 int hours = nc->getArg(2).mid(0, 2).toInt(); 00784 int minutes = nc->getArg(2).mid(3, 2).toInt(); 00785 int seconds = nc->getArg(2).mid(6, 2).toInt(); 00786 message = QString("NETWORK_CONTROL SEEK POSITION %1") 00787 .arg((hours * 3600) + (minutes * 60) + seconds); 00788 } 00789 else 00790 return QString("ERROR: See 'help %1' for usage information") 00791 .arg(nc->getArg(0)); 00792 } 00793 else if (is_abbrev("speed", nc->getArg(1), 2)) 00794 { 00795 if (nc->getArgCount() < 3) 00796 return QString("ERROR: See 'help %1' for usage information") 00797 .arg(nc->getArg(0)); 00798 00799 QString token2 = nc->getArg(2).toLower(); 00800 if ((token2.contains(QRegExp("^\\-*\\d+x$"))) || 00801 (token2.contains(QRegExp("^\\-*\\d+\\/\\d+x$"))) || 00802 (token2.contains(QRegExp("^\\-*\\d*\\.\\d+x$")))) 00803 message = QString("NETWORK_CONTROL SPEED %1").arg(token2); 00804 else if (is_abbrev("normal", token2)) 00805 message = QString("NETWORK_CONTROL SPEED 1x"); 00806 else if (is_abbrev("pause", token2)) 00807 message = QString("NETWORK_CONTROL SPEED 0x"); 00808 else 00809 return QString("ERROR: See 'help %1' for usage information") 00810 .arg(nc->getArg(0)); 00811 } 00812 else if (is_abbrev("save", nc->getArg(1), 2)) 00813 { 00814 if (is_abbrev("screenshot", nc->getArg(2), 2)) 00815 return saveScreenshot(nc); 00816 } 00817 else if (is_abbrev("stop", nc->getArg(1), 2)) 00818 message = QString("NETWORK_CONTROL STOP"); 00819 else if (is_abbrev("volume", nc->getArg(1), 2)) 00820 { 00821 if ((nc->getArgCount() < 3) || 00822 (!nc->getArg(2).toLower().contains(QRegExp("^\\d+%?$")))) 00823 { 00824 return QString("ERROR: See 'help %1' for usage information") 00825 .arg(nc->getArg(0)); 00826 } 00827 00828 message = QString("NETWORK_CONTROL VOLUME %1") 00829 .arg(nc->getArg(2).toLower()); 00830 } 00831 else 00832 return QString("ERROR: See 'help %1' for usage information") 00833 .arg(nc->getArg(0)); 00834 00835 if (!message.isEmpty()) 00836 { 00837 MythEvent me(message); 00838 gCoreContext->dispatch(me); 00839 } 00840 00841 return result; 00842 } 00843 00844 QString NetworkControl::processQuery(NetworkCommand *nc) 00845 { 00846 QString result = "OK"; 00847 00848 if (nc->getArgCount() < 2) 00849 return QString("ERROR: See 'help %1' for usage information") 00850 .arg(nc->getArg(0)); 00851 00852 if (is_abbrev("location", nc->getArg(1))) 00853 { 00854 bool fullPath = false; 00855 bool mainStackOnly = true; 00856 00857 if (nc->getArgCount() > 2) 00858 fullPath = (nc->getArg(2).toLower() == "true" || nc->getArg(2) == "1"); 00859 if (nc->getArgCount() > 3) 00860 mainStackOnly = (nc->getArg(3).toLower() == "true" || nc->getArg(3) == "1"); 00861 00862 QString location = GetMythUI()->GetCurrentLocation(fullPath, mainStackOnly); 00863 result = location; 00864 00865 // if we're playing something, then find out what 00866 if (location == "Playback") 00867 { 00868 result += " "; 00869 gotAnswer = false; 00870 QString message = QString("NETWORK_CONTROL QUERY POSITION"); 00871 MythEvent me(message); 00872 gCoreContext->dispatch(me); 00873 00874 QTime timer; 00875 timer.start(); 00876 while (timer.elapsed() < FE_SHORT_TO && !gotAnswer) 00877 usleep(10000); 00878 00879 if (gotAnswer) 00880 result += answer; 00881 else 00882 result = "ERROR: Timed out waiting for reply from player"; 00883 } 00884 } 00885 else if (is_abbrev("verbose", nc->getArg(1))) 00886 { 00887 return verboseString; 00888 } 00889 else if (is_abbrev("liveTV", nc->getArg(1))) 00890 { 00891 if(nc->getArgCount() == 3) // has a channel ID 00892 return listSchedule(nc->getArg(2)); 00893 else 00894 return listSchedule(); 00895 } 00896 else if (is_abbrev("version", nc->getArg(1))) 00897 { 00898 int dbSchema = gCoreContext->GetNumSetting("DBSchemaVer"); 00899 00900 return QString("VERSION: %1/%2 %3 %4 QT/%5 DBSchema/%6") 00901 .arg(MYTH_SOURCE_VERSION) 00902 .arg(MYTH_SOURCE_PATH) 00903 .arg(MYTH_BINARY_VERSION) 00904 .arg(MYTH_PROTO_VERSION) 00905 .arg(QT_VERSION_STR) 00906 .arg(dbSchema); 00907 00908 } 00909 else if(is_abbrev("time", nc->getArg(1))) 00910 return QDateTime::currentDateTime().toString(Qt::ISODate); 00911 else if (is_abbrev("uptime", nc->getArg(1))) 00912 { 00913 QString str; 00914 time_t uptime; 00915 00916 if (getUptime(uptime)) 00917 str = QString::number(uptime); 00918 else 00919 str = QString("Could not determine uptime."); 00920 return str; 00921 } 00922 else if (is_abbrev("load", nc->getArg(1))) 00923 { 00924 QString str; 00925 double loads[3]; 00926 00927 if (getloadavg(loads,3) == -1) 00928 str = QString("getloadavg() failed"); 00929 else 00930 str = QString("%1 %2 %3").arg(loads[0]).arg(loads[1]).arg(loads[2]); 00931 return str; 00932 } 00933 else if (is_abbrev("memstats", nc->getArg(1))) 00934 { 00935 QString str; 00936 int totalMB, freeMB, totalVM, freeVM; 00937 00938 if (getMemStats(totalMB, freeMB, totalVM, freeVM)) 00939 str = QString("%1 %2 %3 %4") 00940 .arg(totalMB).arg(freeMB).arg(totalVM).arg(freeVM); 00941 else 00942 str = QString("Could not determine memory stats."); 00943 return str; 00944 } 00945 else if (is_abbrev("volume", nc->getArg(1))) 00946 { 00947 QString str = "0%"; 00948 00949 QString location = GetMythUI()->GetCurrentLocation(false, false); 00950 00951 if (location != "Playback") 00952 return str; 00953 00954 gotAnswer = false; 00955 QString message = QString("NETWORK_CONTROL QUERY VOLUME"); 00956 MythEvent me(message); 00957 gCoreContext->dispatch(me); 00958 00959 QTime timer; 00960 timer.start(); 00961 while (timer.elapsed() < FE_SHORT_TO && !gotAnswer) 00962 usleep(10000); 00963 00964 if (gotAnswer) 00965 str = answer; 00966 else 00967 str = "ERROR: Timed out waiting for reply from player"; 00968 00969 return str; 00970 } 00971 else if ((nc->getArgCount() == 4) && 00972 is_abbrev("recording", nc->getArg(1)) && 00973 (nc->getArg(2).contains(QRegExp("^\\d+$"))) && 00974 (nc->getArg(3).contains(QRegExp( 00975 "^\\d\\d\\d\\d-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d$")))) 00976 return listRecordings(nc->getArg(2), nc->getArg(3).toUpper()); 00977 else if (is_abbrev("recordings", nc->getArg(1))) 00978 return listRecordings(); 00979 else if (is_abbrev("channels", nc->getArg(1))) 00980 { 00981 if (nc->getArgCount() == 2) 00982 return listChannels(0, 0); // give us all you can 00983 else if (nc->getArgCount() == 4) 00984 return listChannels(nc->getArg(2).toLower().toUInt(), 00985 nc->getArg(3).toLower().toUInt()); 00986 else 00987 return QString("ERROR: See 'help %1' for usage information " 00988 "(parameters mismatch)").arg(nc->getArg(0)); 00989 } 00990 else 00991 return QString("ERROR: See 'help %1' for usage information") 00992 .arg(nc->getArg(0)); 00993 00994 return result; 00995 } 00996 00997 QString NetworkControl::processSet(NetworkCommand *nc) 00998 { 00999 if (nc->getArgCount() == 1) 01000 return QString("ERROR: See 'help %1' for usage information") 01001 .arg(nc->getArg(0)); 01002 01003 if (nc->getArg(1) == "verbose") 01004 { 01005 if (nc->getArgCount() > 3) 01006 return QString("ERROR: Separate filters with commas with no " 01007 "space: playback,audio\r\n See 'help %1' for usage " 01008 "information").arg(nc->getArg(0)); 01009 01010 QString oldVerboseString = verboseString; 01011 QString result = "OK"; 01012 01013 int pva_result = verboseArgParse(nc->getArg(2)); 01014 01015 if (pva_result != 0 /*GENERIC_EXIT_OK */) 01016 result = "Failed"; 01017 01018 result += "\r\n"; 01019 result += " Previous filter: " + oldVerboseString + "\r\n"; 01020 result += " New Filter: " + verboseString + "\r\n"; 01021 01022 LOG(VB_GENERAL, LOG_NOTICE, 01023 QString("Verbose mask changed, new level is: %1") 01024 .arg(verboseString)); 01025 01026 return result; 01027 } 01028 01029 return QString("ERROR: See 'help %1' for usage information") 01030 .arg(nc->getArg(0)); 01031 } 01032 01033 QString NetworkControl::processHelp(NetworkCommand *nc) 01034 { 01035 QString command, helpText; 01036 01037 if (nc->getArgCount() >= 1) 01038 { 01039 if (is_abbrev("help", nc->getArg(0))) 01040 { 01041 if (nc->getArgCount() >= 2) 01042 command = nc->getArg(1); 01043 else 01044 command.clear(); 01045 } 01046 else 01047 { 01048 command = nc->getArg(0); 01049 } 01050 } 01051 01052 if (is_abbrev("jump", command)) 01053 { 01054 QMap<QString, QString>::Iterator it; 01055 helpText += 01056 "Usage: jump JUMPPOINT\r\n" 01057 "\r\n" 01058 "Where JUMPPOINT is one of the following:\r\n"; 01059 01060 for (it = jumpMap.begin(); it != jumpMap.end(); ++it) 01061 { 01062 helpText += it.key().leftJustified(20, ' ', true) + " - " + 01063 *it + "\r\n"; 01064 } 01065 } 01066 else if (is_abbrev("key", command)) 01067 { 01068 helpText += 01069 "key LETTER - Send the letter key specified\r\n" 01070 "key NUMBER - Send the number key specified\r\n" 01071 "key CODE - Send one of the following key codes\r\n" 01072 "\r\n"; 01073 01074 QMap<QString, int>::Iterator it; 01075 bool first = true; 01076 for (it = keyMap.begin(); it != keyMap.end(); ++it) 01077 { 01078 if (first) 01079 first = false; 01080 else 01081 helpText += ", "; 01082 01083 helpText += it.key(); 01084 } 01085 helpText += "\r\n"; 01086 } 01087 else if (is_abbrev("play", command)) 01088 { 01089 helpText += 01090 "play volume NUMBER% - Change volume to given percentage value\r\n" 01091 "play channel up - Change channel Up\r\n" 01092 "play channel down - Change channel Down\r\n" 01093 "play channel NUMBER - Change to a specific channel number\r\n" 01094 "play chanid NUMBER - Change to a specific channel id (chanid)\r\n" 01095 "play file FILENAME - Play FILENAME (FILENAME may be a file or a myth:// URL)\r\n" 01096 "play program CHANID yyyy-MM-ddThh:mm:ss\r\n" 01097 " - Play program with chanid & starttime\r\n" 01098 "play program CHANID yyyy-MM-ddThh:mm:ss resume\r\n" 01099 " - Resume program with chanid & starttime\r\n" 01100 "play save preview\r\n" 01101 " - Save preview image from current position\r\n" 01102 "play save preview FILENAME\r\n" 01103 " - Save preview image to FILENAME\r\n" 01104 "play save preview FILENAME WxH\r\n" 01105 " - Save preview image of size WxH\r\n" 01106 "play seek beginning - Seek to the beginning of the recording\r\n" 01107 "play seek forward - Skip forward in the video\r\n" 01108 "play seek backward - Skip backwards in the video\r\n" 01109 "play seek HH:MM:SS - Seek to a specific position\r\n" 01110 "play speed pause - Pause playback\r\n" 01111 "play speed normal - Playback at normal speed\r\n" 01112 "play speed 1x - Playback at normal speed\r\n" 01113 "play speed SPEEDx - Playback where SPEED must be a decimal\r\n" 01114 "play speed 1/8x - Playback at 1/8x speed\r\n" 01115 "play speed 1/4x - Playback at 1/4x speed\r\n" 01116 "play speed 1/3x - Playback at 1/3x speed\r\n" 01117 "play speed 1/2x - Playback at 1/2x speed\r\n" 01118 "play stop - Stop playback\r\n" 01119 "play music play - Resume playback (MythMusic)\r\n" 01120 "play music pause - Pause playback (MythMusic)\r\n" 01121 "play music stop - Stop Playback (MythMusic)\r\n" 01122 "play music setvolume N - Set volume to number (MythMusic)\r\n" 01123 "play music getvolume - Get current volume (MythMusic)\r\n" 01124 "play music getmeta - Get metadata for current track (MythMusic)\r\n" 01125 "play music file NAME - Play specified file (MythMusic)\r\n" 01126 "play music track N - Switch to specified track (MythMusic)\r\n" 01127 "play music url URL - Play specified URL (MythMusic)\r\n"; 01128 } 01129 else if (is_abbrev("query", command)) 01130 { 01131 helpText += 01132 "query location - Query current screen or location\r\n" 01133 "query volume - Query the current playback volume\r\n" 01134 "query recordings - List currently available recordings\r\n" 01135 "query recording CHANID STARTTIME\r\n" 01136 " - List info about the specified program\r\n" 01137 "query liveTV - List current TV schedule\r\n" 01138 "query liveTV CHANID - Query current program for specified channel\r\n" 01139 "query load - List 1/5/15 load averages\r\n" 01140 "query memstats - List free and total, physical and swap memory\r\n" 01141 "query time - Query current time on frontend\r\n" 01142 "query uptime - Query machine uptime\r\n" 01143 "query verbose - Get current VERBOSE mask\r\n" 01144 "query version - Query Frontend version details\r\n" 01145 "query channels - Query available channels\r\n" 01146 "query channels START LIMIT - Query available channels from START and limit results to LIMIT lines\r\n"; 01147 } 01148 else if (is_abbrev("set", command)) 01149 { 01150 helpText += 01151 "set verbose debug-mask - " 01152 "Change the VERBOSE mask to 'debug-mask'\r\n" 01153 " (i.e. 'set verbose playback,audio')\r\n" 01154 " use 'set verbose default' to revert\r\n" 01155 " back to the default level of\r\n"; 01156 } 01157 else if (is_abbrev("screenshot", command)) 01158 { 01159 helpText += 01160 "screenshot - Takes a screenshot and saves it as screenshot.png\r\n" 01161 "screenshot WxH - Saves the screenshot as a WxH size image\r\n"; 01162 } 01163 else if (command == "exit") 01164 { 01165 helpText += 01166 "exit - Terminates session\r\n\r\n"; 01167 } 01168 else if ((is_abbrev("message", command))) 01169 { 01170 helpText += 01171 "message - Displays a simple text message popup\r\n"; 01172 } 01173 01174 if (!helpText.isEmpty()) 01175 return helpText; 01176 01177 if (!command.isEmpty()) 01178 helpText += QString("Unknown command '%1'\r\n\r\n").arg(command); 01179 01180 helpText += 01181 "Valid Commands:\r\n" 01182 "---------------\r\n" 01183 "jump - Jump to a specified location in Myth\r\n" 01184 "key - Send a keypress to the program\r\n" 01185 "play - Playback related commands\r\n" 01186 "query - Queries\r\n" 01187 "set - Changes\r\n" 01188 "screenshot - Capture screenshot\r\n" 01189 "message - Display a simple text message\r\n" 01190 "exit - Exit Network Control\r\n" 01191 "\r\n" 01192 "Type 'help COMMANDNAME' for help on any specific command.\r\n"; 01193 01194 return helpText; 01195 } 01196 01197 QString NetworkControl::processMessage(NetworkCommand *nc) 01198 { 01199 if (nc->getArgCount() < 2) 01200 return QString("ERROR: See 'help %1' for usage information") 01201 .arg(nc->getArg(0)); 01202 01203 QString message = nc->getCommand().remove(0, 7).trimmed(); 01204 MythMainWindow *window = GetMythMainWindow(); 01205 MythEvent* me = new MythEvent(MythEvent::MythUserMessage, message); 01206 qApp->postEvent(window, me); 01207 return QString("OK"); 01208 } 01209 01210 void NetworkControl::notifyDataAvailable(void) 01211 { 01212 QCoreApplication::postEvent( 01213 this, new QEvent(kNetworkControlDataReadyEvent)); 01214 } 01215 01216 void NetworkControl::sendReplyToClient(NetworkControlClient *ncc, 01217 QString &reply) 01218 { 01219 if (!clients.contains(ncc)) 01220 // NetworkControl instance is unaware of control client 01221 // assume connection to client has been terminated and bail 01222 return; 01223 01224 QRegExp crlfRegEx("\r\n$"); 01225 QRegExp crlfcrlfRegEx("\r\n.*\r\n"); 01226 01227 QTcpSocket *client = ncc->getSocket(); 01228 QTextStream *clientStream = ncc->getTextStream(); 01229 01230 if (client && clientStream && client->state() == QTcpSocket::ConnectedState) 01231 { 01232 *clientStream << reply; 01233 01234 if ((!reply.contains(crlfRegEx)) || 01235 ( reply.contains(crlfcrlfRegEx))) 01236 *clientStream << "\r\n" << prompt; 01237 01238 clientStream->flush(); 01239 client->flush(); 01240 } 01241 } 01242 01243 void NetworkControl::customEvent(QEvent *e) 01244 { 01245 if ((MythEvent::Type)(e->type()) == MythEvent::MythEventMessage) 01246 { 01247 MythEvent *me = (MythEvent *)e; 01248 QString message = me->Message(); 01249 01250 if (message.left(13) == "MUSIC_CONTROL") 01251 { 01252 QStringList tokens = message.simplified().split(" "); 01253 if ((tokens.size() >= 4) && 01254 (tokens[1] == "ANSWER") && 01255 (tokens[2] == gCoreContext->GetHostName())) 01256 { 01257 answer = tokens[3]; 01258 for (int i = 4; i < tokens.size(); i++) 01259 answer += QString(" ") + tokens[i]; 01260 gotAnswer = true; 01261 } 01262 01263 } 01264 else if (message.left(15) == "NETWORK_CONTROL") 01265 { 01266 QStringList tokens = message.simplified().split(" "); 01267 if ((tokens.size() >= 3) && 01268 (tokens[1] == "ANSWER")) 01269 { 01270 answer = tokens[2]; 01271 for (int i = 3; i < tokens.size(); i++) 01272 answer += QString(" ") + tokens[i]; 01273 gotAnswer = true; 01274 } 01275 else if ((tokens.size() >= 4) && 01276 (tokens[1] == "RESPONSE")) 01277 { 01278 // int clientID = tokens[2].toInt(); 01279 answer = tokens[3]; 01280 for (int i = 4; i < tokens.size(); i++) 01281 answer += QString(" ") + tokens[i]; 01282 gotAnswer = true; 01283 } 01284 } 01285 } 01286 else if (e->type() == kNetworkControlDataReadyEvent) 01287 { 01288 NetworkCommand *nc; 01289 QString reply; 01290 01291 QMutexLocker locker(&clientLock); 01292 QMutexLocker nrLocker(&nrLock); 01293 01294 while (!networkControlReplies.isEmpty()) 01295 { 01296 nc = networkControlReplies.front(); 01297 networkControlReplies.pop_front(); 01298 01299 reply = nc->getCommand(); 01300 01301 NetworkControlClient * ncc = nc->getClient(); 01302 if (ncc) 01303 { 01304 sendReplyToClient(ncc, reply); 01305 } 01306 else //send to all clients 01307 { 01308 QList<NetworkControlClient *>::const_iterator it; 01309 for (it = clients.begin(); it != clients.end(); ++it) 01310 { 01311 NetworkControlClient *ncc = *it; 01312 if (ncc) 01313 sendReplyToClient(ncc, reply); 01314 } 01315 } 01316 delete nc; 01317 } 01318 } 01319 else if (e->type() == NetworkControlCloseEvent::kEventType) 01320 { 01321 NetworkControlCloseEvent *ncce = static_cast<NetworkControlCloseEvent*>(e); 01322 NetworkControlClient *ncc = ncce->getClient(); 01323 01324 deleteClient(ncc); 01325 } 01326 } 01327 01328 QString NetworkControl::listSchedule(const QString& chanID) const 01329 { 01330 QString result(""); 01331 MSqlQuery query(MSqlQuery::InitCon()); 01332 bool appendCRLF = true; 01333 QString queryStr("SELECT chanid, starttime, endtime, title, subtitle " 01334 "FROM program " 01335 "WHERE starttime < :START AND endtime > :END "); 01336 01337 if (!chanID.isEmpty()) 01338 { 01339 queryStr += " AND chanid = :CHANID"; 01340 appendCRLF = false; 01341 } 01342 01343 queryStr += " ORDER BY starttime, endtime, chanid"; 01344 01345 query.prepare(queryStr); 01346 query.bindValue(":START", QDateTime::currentDateTime()); 01347 query.bindValue(":END", QDateTime::currentDateTime()); 01348 if (!chanID.isEmpty()) 01349 { 01350 query.bindValue(":CHANID", chanID); 01351 } 01352 01353 if (query.exec()) 01354 { 01355 while (query.next()) 01356 { 01357 QString title = query.value(3).toString(); 01358 QString subtitle = query.value(4).toString(); 01359 01360 if (!subtitle.isEmpty()) 01361 title += QString(" -\"%1\"").arg(subtitle); 01362 QByteArray atitle = title.toLocal8Bit(); 01363 01364 result += 01365 QString("%1 %2 %3 %4") 01366 .arg(QString::number(query.value(0).toInt()) 01367 .rightJustified(5, ' ')) 01368 .arg(query.value(1).toDateTime().toString(Qt::ISODate)) 01369 .arg(query.value(2).toDateTime().toString(Qt::ISODate)) 01370 .arg(atitle.constData()); 01371 01372 if (appendCRLF) 01373 result += "\r\n"; 01374 } 01375 } 01376 else 01377 { 01378 result = "ERROR: Unable to retrieve current schedule list."; 01379 } 01380 return result; 01381 } 01382 01383 QString NetworkControl::listRecordings(QString chanid, QString starttime) 01384 { 01385 QString result; 01386 MSqlQuery query(MSqlQuery::InitCon()); 01387 QString queryStr; 01388 bool appendCRLF = true; 01389 01390 queryStr = "SELECT chanid, starttime, title, subtitle " 01391 "FROM recorded WHERE deletepending = 0 "; 01392 01393 if ((!chanid.isEmpty()) && (!starttime.isEmpty())) 01394 { 01395 queryStr += "AND chanid = " + chanid + " " 01396 "AND starttime = '" + starttime + "' "; 01397 appendCRLF = false; 01398 } 01399 01400 queryStr += "ORDER BY starttime, title;"; 01401 01402 query.prepare(queryStr); 01403 if (query.exec()) 01404 { 01405 QString episode, title, subtitle; 01406 while (query.next()) 01407 { 01408 title = query.value(2).toString(); 01409 subtitle = query.value(3).toString(); 01410 01411 if (!subtitle.isEmpty()) 01412 episode = QString("%1 -\"%2\"") 01413 .arg(title) 01414 .arg(subtitle); 01415 else 01416 episode = title; 01417 01418 result += 01419 QString("%1 %2 %3").arg(query.value(0).toInt()) 01420 .arg(query.value(1).toDateTime().toString(Qt::ISODate)) 01421 .arg(episode); 01422 01423 if (appendCRLF) 01424 result += "\r\n"; 01425 } 01426 } 01427 else 01428 result = "ERROR: Unable to retrieve recordings list."; 01429 01430 return result; 01431 } 01432 01433 QString NetworkControl::listChannels(const uint start, const uint limit) const 01434 { 01435 QString result; 01436 MSqlQuery query(MSqlQuery::InitCon()); 01437 QString queryStr; 01438 uint cnt; 01439 uint maxcnt; 01440 uint sqlStart = start; 01441 01442 // sql starts at zero, we want to start at 1 01443 if (sqlStart > 0) 01444 sqlStart--; 01445 01446 queryStr = "select chanid, callsign, name from channel where visible=1"; 01447 queryStr += " ORDER BY callsign"; 01448 01449 if (limit > 0) // only if a limit is specified, we limit the results 01450 { 01451 QString limitStr = QString(" LIMIT %1,%2").arg(sqlStart).arg(limit); 01452 queryStr += limitStr; 01453 } 01454 01455 query.prepare(queryStr); 01456 if (!query.exec()) 01457 { 01458 result = "ERROR: Unable to retrieve channel list."; 01459 return result; 01460 } 01461 01462 maxcnt = query.size(); 01463 cnt = 0; 01464 if (maxcnt == 0) // Feedback we have no usefull information 01465 { 01466 result += QString("0:0 0 \"Invalid\" \"Invalid\""); 01467 return result; 01468 } 01469 01470 while (query.next()) 01471 { 01472 // Feedback is as follow: 01473 // <current line count>:<max line count to expect> <channelid> <callsign name> <channel name>\r\n 01474 cnt++; 01475 result += QString("%1:%2 %3 \"%4\" \"%5\"\r\n") 01476 .arg(cnt).arg(maxcnt).arg(query.value(0).toInt()) 01477 .arg(query.value(1).toString()) 01478 .arg(query.value(2).toString()); 01479 } 01480 01481 return result; 01482 } 01483 01484 QString NetworkControl::saveScreenshot(NetworkCommand *nc) 01485 { 01486 int width = 0; 01487 int height = 0; 01488 01489 if (nc->getArgCount() == 2) 01490 { 01491 QStringList size = nc->getArg(1).split('x'); 01492 if (size.size() == 2) 01493 { 01494 width = size[0].toInt(); 01495 height = size[1].toInt(); 01496 } 01497 } 01498 01499 MythMainWindow *window = GetMythMainWindow(); 01500 QStringList args; 01501 if (width && height) 01502 { 01503 args << QString::number(width); 01504 args << QString::number(height); 01505 } 01506 MythEvent* me = new MythEvent(MythEvent::MythEventMessage, 01507 ACTION_SCREENSHOT, args); 01508 qApp->postEvent(window, me); 01509 return "OK"; 01510 } 01511 01512 QString NetworkCommand::getFrom(int arg) 01513 { 01514 QString c = m_command; 01515 for(int i=0 ; i<arg ; i++) { 01516 QString arg = c.simplified().split(" ")[0]; 01517 c = c.mid(arg.length()).trimmed(); 01518 } 01519 return c; 01520 } 01521 01522 /* vim: set expandtab tabstop=4 shiftwidth=4: */ 01523
1.7.6.1