#include "connectionpane.h" #include "ui_connectionpane.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "connectiondata.h" struct CommandData { public: QString Module; QString HelpText; QString LongHelp; QString Description; ConnectionPane *instance; void (*fn)(QString module, ConnectionPane *instance, QStringList args); }; Q_DECLARE_METATYPE (CommandData) ConnectionPane::ConnectionPane(ConnectionData *c, QHostAddress addr, QWidget *parent) : QWidget(parent), ui(new Ui::ConnectionPane) { ui->setupUi(this); Name = c->Name; Host = c->Host; Port = c->Port; User = c->User; Pass = c->Pass; loggedIn = false; QDnsLookup lookup; if (!addr.isNull()) { lookup.setNameserver(addr); QHostAddress dest(Host); if (dest.isNull()) { lookup.setName(Host); lookup.setType(QDnsLookup::A); QEventLoop loop; connect(&lookup, SIGNAL(finished()), &loop, SLOT(quit())); lookup.lookup(); loop.exec(); if (lookup.error() == QDnsLookup::NoError) Host = lookup.hostAddressRecords().first().value().toString(); } } // Construct the URLs urlStart.setScheme(QString("http")); urlStart.setHost(Host); urlStart.setPort(Port); urlClose = urlStart; urlCommand = urlStart; urlPoll = urlStart; urlStart.setPath(QString("/StartSession/")); urlClose.setPath(QString("/CloseSession/")); urlCommand.setPath(QString("/SessionCommand/")); // Construct the manager manager = new QNetworkAccessManager(this); pollReply = 0; loginReply = 0; cmdReply = 0; int id = QFontDatabase::addApplicationFont(":/fonts/Consolas.ttf"); QString family = QFontDatabase::applicationFontFamilies(id).at(0); QSettings settings; QString styleSheet; if (!settings.value("system_font", false).toBool()) styleSheet += "font-family: " + family + ";"; if (settings.value("black_on_white", false).toBool()) styleSheet += "background-color: black; color: white;"; else styleSheet += "background-color: #fcfcfc; color: black;"; styleSheet += "font-size: 18pt;"; ui->mainPane->setStyleSheet(styleSheet); } ConnectionPane::~ConnectionPane() { QNetworkAccessManager *m = manager; manager = 0; delete m; delete ui; } void ConnectionPane::CommandReply() { QByteArray result = cmdReply->readAll(); cmdReply->deleteLater(); cmdReply = 0; ui->textEntry->setText(QString("")); TextChanged(""); } void ConnectionPane::LoginReply() { QByteArray result = loginReply->readAll(); loginReply->deleteLater(); if (result.size() == 0) { ui->mainPane->setHtml("Connecting ...
Error!"); QMessageBox::critical(0, QString("Connection error"), QString("Connection to host failed")); return; } QDomDocument doc; doc.setContent(result, false); QDomElement root = doc.documentElement(); // Get session ID QDomNodeList sessionL = root.elementsByTagName(QString("SessionID")); QDomNode sessionNode = sessionL.at(0); sessionID = sessionNode.toElement().text(); urlPoll.setPath(QString("/ReadResponses/")+sessionID+QString("/")); QDomNodeList helpL = root.elementsByTagName(QString("HelpTree")); QDomNode helpNode = helpL.at(0); ui->mainPane->setHtml(ui->mainPane->toHtml() + QString("Connected")); tree.clear(); tree = ProcessTreeLevel(helpNode, tree); QMap nextLevel; if (tree.contains("help")) nextLevel = tree["help"].toMap(); CommandData cmd; cmd.Module = "Local"; cmd.HelpText = "help []"; cmd.LongHelp = "Provide help for commands"; cmd.Description = "Provide help for commands"; cmd.instance = this; cmd.fn = Help; QVariant v; v.setValue(cmd); nextLevel[""] = v; tree["help"] = nextLevel; nextLevel.clear(); if (tree.contains("quit:")) nextLevel = tree["quit"].toMap(); cmd.Module = "Local"; cmd.HelpText = "quit"; cmd.LongHelp = "Quit console session"; cmd.Description = "Quit console session"; cmd.instance = this; cmd.fn = Quit; v.setValue(cmd); nextLevel[""] = v; tree["quit"] = nextLevel; // Construct the poll request QString data = ""; QNetworkRequest request(urlPoll); request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded")); // Start poll pollReply = manager->post(request, data.toLatin1()); connect(pollReply, SIGNAL(finished()), this, SLOT(PollReply())); ui->textEntry->setFocus(); TextChanged(QString("")); connect(ui->textEntry, SIGNAL(returnPressed()), this, SLOT(ReturnPressed())); connect(ui->textEntry, SIGNAL(textChanged(QString)), this, SLOT(TextChanged(QString))); loggedIn = true; } void ConnectionPane::PollReply() { if (manager == 0) return; QByteArray result = pollReply->readAll(); //qDebug() << QString(result); pollReply->deleteLater(); QString fullText; if (result.size() != 0) { QDomDocument doc; doc.setContent(result, false); QDomElement root = doc.documentElement(); QDomNodeList lineL = root.elementsByTagName(QString("Line")); for (int i = 0 ; i < lineL.count() ; i++) { QDomElement e = lineL.at(i).toElement(); QString level; bool prompt = false; bool command = false; bool input = false; if (e.hasAttribute("Level")) level = e.attributeNode("Level").value(); if (e.hasAttribute("Prompt")) { if (e.attributeNode("Prompt").value() == "true") prompt = true; } if (e.hasAttribute("Command")) { if (e.attributeNode("Command").value() == "true") command = true; } if (e.hasAttribute("Input")) { if (e.attributeNode("Input").value() == "true") input = true; } QString line = e.text(); if (!input) fullText += QString("
"); fullText += FormatLine(line.trimmed(), level).replace("\n", "
"); if (fullText.endsWith("
")) fullText = fullText.mid(fullText.length() - 4); if (prompt || command) { expectingInput = true; if (command) expectingCommand = true; } } } textContent += fullText; if (textContent.length() > 131400) textContent = textContent.right(131400); ui->mainPane->setHtml(textContent); ui->mainPane->moveCursor(QTextCursor::End); ui->mainPane->ensureCursorVisible(); if (!loggedIn) return; TextChanged(ui->textEntry->text()); // Construct the poll request QString data = ""; QNetworkRequest request(urlPoll); request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded")); // Poll again pollReply = manager->post(request, data.toLatin1()); connect(pollReply, SIGNAL(finished()), this, SLOT(PollReply())); } void ConnectionPane::TextChanged(QString text) { if (!expectingInput) ui->helpArea->hide(); else if (!expectingCommand) ui->helpArea->hide(); else ui->helpArea->show(); ui->mainPane->moveCursor(QTextCursor::End); ui->mainPane->ensureCursorVisible(); QStringList words = Parse(text); bool trailingSpace = text.right(1) == " "; QStringList opts = FindNextOption(words, trailingSpace); if (opts.size() == 0) { ui->helpArea->setText(QString("")); } else { QString first = opts.at(0); if (first.indexOf(QString("Command help:")) == 0) ui->helpArea->setText(first); else if (text != "") { QString output; output.sprintf("Options: %s", opts.join(" ").toLocal8Bit().data()); ui->helpArea->setText(output); } else { QString output; output.sprintf("Commands: %s", opts.join(" ").toLocal8Bit().data()); ui->helpArea->setText(output); } } } void ConnectionPane::ReturnPressed() { // Construct the command QString cmd = ui->textEntry->text(); if ((!expectingCommand) && expectingInput) { if (SendCommand(cmd)) { ui->textEntry->setText(QString("")); TextChanged(ui->textEntry->text()); } } QStringList resolved = Resolve(Parse(cmd)); QString historyEntry = resolved.join(" "); } void ConnectionPane::Login() { QUrlQuery queryString; queryString.addQueryItem("USER", User); queryString.addQueryItem("PASS", Pass); // Construct the login request QString data = queryString.query(QUrl::FullyEncoded).toUtf8(); QNetworkRequest request(urlStart); request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded")); // Log in ui->mainPane->setHtml(ui->mainPane->toHtml() + QString("Connecting ...")); loginReply = manager->post(request, data.toLatin1()); connect(loginReply, SIGNAL(finished()), this, SLOT(LoginReply())); } void ConnectionPane::CloseConnection() { close(); } void ConnectionPane::ClearScrollback() { ui->mainPane->setHtml(QString("")); } void ConnectionPane::Copy() { ui->mainPane->copy(); } void ConnectionPane::RestartServer() { if (!loggedIn) return; SendCommand("quit"); ui->mainPane->setHtml(ui->mainPane->toHtml() + QString("Disconnected")); pollReply->abort(); loggedIn = false; QTimer::singleShot(5000, this, SLOT(Login())); } bool ConnectionPane::IsLoggedIn() { return loggedIn; } QStringList ConnectionPane::CollectHelp(QStringList helpParts) { QString originalHelpRequest = helpParts.join(" "); QStringList help; QMap dict = tree; while (helpParts.size() > 0) { QString helpPart = helpParts.at(0); if (!dict.contains(helpPart)) break; QVariant val = dict[helpPart]; if (QString(val.typeName()) == QString("QVariantMap")) { dict = val.toMap(); } helpParts.removeFirst(); } if (dict.contains(QString(""))) { QVariant v = dict[QString("")]; CommandData ci = v.value(); help.append(ci.HelpText); help.append(ci.LongHelp); // help.append(ci.Description); } else { help.append(QString("No help is available for ") + originalHelpRequest); } return help;} QStringList ConnectionPane::Parse(QString text) { QStringList result; int index = 0; QStringList unquoted = text.split("\""); for (index = 0 ; index < unquoted.size() ; index++) { if ((index % 2) == 0) { QStringList words = unquoted.at(index).split(" "); for (int i = 0 ; i < words.size() ; i++) { QString w = words.at(i); if (w != QString("")) result.append(w); } } else { result.append(unquoted.at(index)); } } return result; } QStringList ConnectionPane::Resolve(QStringList cmd) { QStringList result(cmd); int index = -1; QMap current = tree; for (int i = 0 ; i < cmd.size() ; i++) { QString s = cmd.at(i); index++; QStringList found; for (QMap::iterator it = current.begin() ; it != current.end() ; it++) { QString opt = it.key(); if (opt == s) { found.clear(); found.append(opt); break; } if (opt.indexOf(s) == 0) { found.append(opt); } } if (found.size() == 1) { result[index] = found.at(0); current = current[found.at(0)].toMap(); } else if (found.size() > 0) { QStringList blank; return blank; } else { break; } } if (current.contains(QString(""))) { QVariant v = current[QString("")]; CommandData ci = v.value(); if (!ci.fn) return QStringList(); (*ci.fn)(ci.Module, ci.instance, result); return result; } return QStringList(); } QStringList ConnectionPane::FindNextOption(QStringList cmd, bool term) { QMap current = tree; int remaining = cmd.size(); for (int i = 0 ; i < cmd.size() ; i++) { QString s = cmd.at(i); remaining--; QStringList found; for (QMap::iterator it = current.begin() ; it != current.end() ; it++) { QString opt = it.key(); if (remaining > 0 && opt == s) { found.clear(); found.append(opt); break; } if (opt.indexOf(s) == 0) { found.append(opt); } } if (found.size() == 1 && ((remaining != 0) || term)) { current = current[found.at(0)].toMap(); } else if (found.size() > 0) { return found; } else { break; } } if (current.size() > 1) { QStringList choices; bool addcr = false; for (QMap::iterator it = current.begin() ; it != current.end() ; it++) { QString s = it.key(); if (s == QString("")) { QVariant v = current[""]; CommandData ci = v.value(); if (ci.fn) addcr = true; } else choices.append(s); } if (addcr) choices.append(""); return choices; } if (current.contains(QString(""))) { QVariant v = current[""]; CommandData ci = v.value(); QStringList ch; ch.append(QString("Command help: ") + ci.HelpText); return ch; } QList kl = current.keys(); QStringList ksl(kl); return ksl; } void ConnectionPane::Help(QString, ConnectionPane *instance, QStringList args) { instance->ui->mainPane->setHtml(instance->ui->mainPane->toHtml()+instance->OutputLine(QString("# ") + args.join(" "), "command")); instance->ui->mainPane->moveCursor(QTextCursor::End); instance->ui->mainPane->ensureCursorVisible(); QStringList help; QStringList helpParts(args); helpParts.removeFirst(); instance->ui->textEntry->setText(QString("")); instance->ui->helpArea->setText(QString("")); if (helpParts.size() == 0) help = instance->CollectHelp(help, instance->tree); else help = help + instance->CollectHelp(helpParts); for (int i = 0 ; i < help.size() ; i++) { instance->ui->mainPane->setHtml(instance->ui->mainPane->toHtml()+instance->OutputLine(help.at(i), "normal")); } instance->ui->mainPane->moveCursor(QTextCursor::End); instance->ui->mainPane->ensureCursorVisible(); } void ConnectionPane::Quit(QString, ConnectionPane *instance, QStringList) { instance->ui->mainPane->setHtml(instance->ui->mainPane->toHtml()+instance->OutputLine("# quit", "command")); instance->ui->mainPane->setHtml(instance->ui->mainPane->toHtml()+instance->OutputLine("Use the toolbar button to close session", "error")); instance->ui->mainPane->moveCursor(QTextCursor::End); instance->ui->mainPane->ensureCursorVisible(); instance->ui->textEntry->setText(QString("")); instance->ui->helpArea->setText(QString("")); } QStringList ConnectionPane::CollectHelp(QStringList help, QMap level) { for (QMap::iterator it = level.begin() ; it != level.end() ; it++) { QString key = it.key(); QVariant val = it.value(); if (QString(val.typeName()) == QString("QVariantMap")) { QMap nextLevel = val.toMap(); help = CollectHelp(help, nextLevel); } else { CommandData cmd = val.value(); QString item = cmd.HelpText + QString(" - ") + cmd.LongHelp; help.append(item); } } return help; } void ConnectionPane::CommandHandler(QString, ConnectionPane *instance, QStringList args) { QString cmd = args.join(" "); if(instance->SendCommand(cmd)) { //instance->ui->mainPane->setHtml(instance->ui->mainPane->toHtml()+instance->OutputLine(QString("# ") + args.join(" "), "command")); //instance->ui->mainPane->moveCursor(QTextCursor::End); //instance->ui->mainPane->ensureCursorVisible(); //instance->ui->textEntry->setText(QString("")); //instance->ui->helpArea->setText(QString("")); } } QString ConnectionPane::FormatLine(QString line, QString level) { if (level == "") return line; QRegExp re(QString("^(.*)\\[(.*)\\](.*)$")); QString ret; if (re.exactMatch(line)) { QString color = GetColor(re.cap(2)); ret = re.cap(1)+QString("[")+re.cap(2)+QString("]"); line = re.cap(3); } if (level == QString("error")) { ret += QString("") + QString(line.toHtmlEscaped()) + QString(""); } else if (level == QString("warn")) { ret += QString("") + QString(line.toHtmlEscaped()) + QString(""); } else if (level == QString("command")) { ret += QString("") + QString(line.toHtmlEscaped()) + QString(""); } else { ret += QString(line.toHtmlEscaped()); } return ret; } QString ConnectionPane::OutputLine(QString line, QString level) { QString ret; if (level == QString("error")) { ret += QString("") + QString(line.toHtmlEscaped()) + QString(""); } else if (level == QString("warn")) { ret += QString("") + QString(line.toHtmlEscaped()) + QString(""); } else if (level == QString("command")) { ret += QString("") + QString(line.toHtmlEscaped()) + QString(""); } else { ret += QString(line.toHtmlEscaped()); } return ret; } QString ConnectionPane::GetColor(QString text) { QList colors; colors.append(QString("#7f7f7f")); colors.append(QString("#0000ff")); colors.append(QString("#00cf00")); colors.append(QString("#00cfcf")); colors.append(QString("#cf00cf")); colors.append(QString("#cfcf00")); return colors.at(qHash(text.toUpper()) % colors.size()); } /* void ConnectionPane::DumpTree(QMap level) { QMap::iterator it; for (it = level.begin() ; it != level.end() ; it++) { QVariant val = it.value(); QString key = it.key(); if (QString(val.typeName()) == QString("QVariantMap")) { printf("Level: %s\n", key.toAscii().data()); QMap nextLevel = val.toMap(); DumpTree(nextLevel); } else { CommandData cmd = val.value(); printf("%s\n", cmd.HelpText.toAscii().data()); } } } */ bool ConnectionPane::SendCommand(QString cmd) { if (cmdReply) return false; QUrlQuery queryString; queryString.addQueryItem("ID", sessionID); queryString.addQueryItem("COMMAND", cmd); QString data = queryString.query(QUrl::FullyEncoded).toUtf8(); QNetworkRequest request(urlCommand); // Send it cmdReply = manager->post(request, data.toLatin1()); connect(cmdReply, SIGNAL(finished()), this, SLOT(CommandReply())); return true; } QMap ConnectionPane::ProcessTreeLevel(QDomNode node, QMap level) { QDomNodeList levelL = node.childNodes(); for (int i = 0 ; i < levelL.count() ; i++) { QDomNode n = levelL.at(i); if (n.isElement()) { QDomElement e = n.toElement(); if (e.tagName() == QString("Level")) { QDomNode a = e.attributeNode(QString("Name")); QDomAttr att = a.toAttr(); QString name = att.value(); QMap nextLevel; level[name] = ProcessTreeLevel(n, nextLevel); } else if (e.tagName() == QString("Command")) { CommandData cmd; QDomNodeList cmdL = n.childNodes(); for (int j = 0 ; j < cmdL.count() ; j++) { QDomNode cmdN = cmdL.at(j); QDomElement cmdE = cmdN.toElement(); if (cmdE.tagName() == QString("Module")) cmd.Module = cmdE.text(); else if(cmdE.tagName() == QString("HelpText")) cmd.HelpText = cmdE.text(); else if(cmdE.tagName() == QString("LongHelp")) cmd.LongHelp = cmdE.text(); else if(cmdE.tagName() == QString("Description")) cmd.Description = cmdE.text(); } cmd.fn = CommandHandler; cmd.instance = this; level[QString("")].setValue(cmd); } } } return level; }