/* GNU General Public License version 3 notice Copyright (C) 2012 Mihawk . All rights reserved. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see < http://www.gnu.org/licenses/ >. */ #include "SshClient.h" #include #include #include #include #include #include SshClient::SshClient(QObject *parent) : QObject(parent), myProcess(new QProcess(this)), myCommandRegex(new QRegExp("^([0-9]{4}-[0-9]{2}-[0-9]{2}\\s[0-9]{2}:[0-9]{2}:[0-9]{2}\\s\\+[0-9]{4}):\\s([A-Za-z]+):?\\s?(.*)$")), myConnectedFlag(false), myConnectionTimerID(0), myPingTimerID(0), myPongTimerID(0), myClients(new QStringList()) { connect(myProcess, SIGNAL(readyRead()), SLOT(read())); connect(myProcess, SIGNAL(finished(int)), SLOT(exited(int))); } SshClient::~SshClient() { delete myCommandRegex; delete myClients; } bool SshClient::isConnected() const { return myConnectedFlag; } void SshClient::read() { QString data(myProcess->readAll().trimmed()); if(data.isEmpty()) return; QStringList lines = data.split("\n", QString::SkipEmptyParts); QString line; foreach(line, lines) { line = line.trimmed(); if(myCommandRegex->indexIn(line) != -1) { QDateTime time = QDateTime::fromString(myCommandRegex->capturedTexts().at(1).section(' ', 0, 1), "yyyy-MM-dd HH:mm:ss"); parse(time, myCommandRegex->capturedTexts().at(2), myCommandRegex->capturedTexts().at(3) ); } } } void SshClient::exited(int exitCode) { qDebug() << "finished" << exitCode; } void SshClient::ping() { write("PING\n"); myPingTimerID = startTimer(30000); } void SshClient::pong() { killTimer(myPingTimerID); myPongTimerID = startTimer(30000); } void SshClient::write(const QString &data) { myProcess->write(data.toAscii()); myProcess->waitForBytesWritten(); } void SshClient::parse(const QDateTime &time, const QString &command, const QString &commandData) { QString cmdData = commandData.trimmed(); if(cmdData.startsWith(": ")) cmdData.remove(0, 2); /* JOINED - Another user has just joined central */ if(command == "JOINED") { QRegExp a("^User '([a-zA-Z]+)'.+$"); if(a.indexIn(commandData) == -1) { if(!myClients->contains(a.capturedTexts().at(1))) myClients->push_back(a.capturedTexts().at(1)); } return; } /* PARTED - Another user has left central */ if(command == "PARTED") { QRegExp a("^User '([a-zA-Z]+)'.+$"); if(a.indexIn(commandData) == -1) myClients->removeAll(a.capturedTexts().at(1)); return; } /* HELLO - Server acknowledge */ if(command == "HELLO") { ping(); myConnectedFlag = true; killTimer(myConnectionTimerID); emit connected(); return; } /* PING PONG - The connection is still up */ if(command == "PONG") { pong(); return; } /* SYS - Central generic message */ if(command == "SYS") { qDebug() << "Central Message" << commandData; return; } /* BC - Broadcast order from central */ if(command == "BC") { QRegExp a("^([A-Za-z0-9]+) (.+),(.+),(.+),'(.+)','(.+)'$"); if(a.indexIn(commandData) == -1) return; qDebug() << "Broadcast Request" << commandData; // BC 0x0hash hash QDEV,-dev-,qw://123.123,'testuser','test, with '',``twists''$ hehe' return; } qDebug() << time << command << cmdData; } bool SshClient::connectToHost(const QString &user, const QString &host) { myProcess->start("ssh", QStringList() << user + "@" + host); bool r = myProcess->waitForStarted(); if(!r) return false; else { myConnectionTimerID = startTimer(30000); return true; } } void SshClient::disconnectFromHost() { killTimer(myConnectionTimerID); killTimer(myPingTimerID); killTimer(myPongTimerID); myProcess->terminate(); myProcess->waitForFinished(); myConnectedFlag = false; } void SshClient::timerEvent(QTimerEvent *e) { if(e->timerId() == myConnectionTimerID) { disconnectFromHost(); emit error(ConnectionTimedOutError); return; } if(e->timerId() == myPingTimerID) { disconnectFromHost(); emit error(ConnectionTimedOutError); return; } if(e->timerId() == myPongTimerID) { killTimer(myPongTimerID); ping(); return; } }