Added multi-threaded support

along with the main thread, the project now supports 3
additional threads.

-the Session object operates in it's own thread that
 will take data directly from the host, process and
 direct it to various parts of the client.

-the main GUI and client command objects will continue
 to operate on the main thread.

-the GenFile object which is dedicated to processing
 GEN_FILE data to or from the host will operate in
 it's own thread.

-last thread is for a new object called TextWorker.
 this object will take all of the text buffered from
 all of other objects and then send the text to be
 displayed by the main GUI in a slower, controlled
 manner.

by building out all of these threads, the main GUI
will not lag even when the host or the client itself
is outputting an excessive amount of data.

fixed a bug that prevented the client from being able
to totally unhook a genfile command of it crashes.

also reduced the default max lines from 5000 to 1000.
This commit is contained in:
Maurice ONeal 2019-12-04 22:01:52 -05:00
parent 51c2e63a24
commit ac364c1e8f
20 changed files with 468 additions and 224 deletions

View File

@ -43,6 +43,16 @@ CmdLine::CmdLine(QWidget *parent) : QComboBox(parent)
connect(lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(checkForHistReset(QString))); connect(lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(checkForHistReset(QString)));
} }
void CmdLine::cacheTxt(quint8 typeId, QString txt)
{
Shared::cacheTxt(Shared::TXT_IN, typeId, txt);
if (!(*Shared::activeDisp))
{
emit txtInCache();
}
}
void CmdLine::setFlags(int flgs) void CmdLine::setFlags(int flgs)
{ {
flags |= flgs; flags |= flgs;
@ -50,7 +60,7 @@ void CmdLine::setFlags(int flgs)
void CmdLine::unsetFlags(int flgs) void CmdLine::unsetFlags(int flgs)
{ {
flags ^= flgs; flags &= ~flgs;
} }
void CmdLine::selectionCheck() void CmdLine::selectionCheck()
@ -105,7 +115,7 @@ void CmdLine::echo(const QString &line)
{ {
if (!line.trimmed().isEmpty()) if (!line.trimmed().isEmpty())
{ {
emit mainTxtOut(line + "\n\n"); cacheTxt(TEXT, line + "\n\n");
} }
} }
@ -162,7 +172,7 @@ void CmdLine::toHost(const QString &cmdName, const QString &args)
if (!Shared::hostCmds->values().contains(cmdName)) if (!Shared::hostCmds->values().contains(cmdName))
{ {
emit errTxtOut("err: No such command: " + cmdName + "\n\n"); cacheTxt(ERR, "err: No such command: " + cmdName + "\n\n");
} }
else if (Shared::genfileCmds->contains(cmdId)) else if (Shared::genfileCmds->contains(cmdId))
{ {

View File

@ -35,6 +35,7 @@ private:
void echo(const QString &line); void echo(const QString &line);
void syncHistToFile(); void syncHistToFile();
void syncHistFromFile(); void syncHistFromFile();
void cacheTxt(quint8 typeId, QString txt);
void duplicateScan(const QString &txt); void duplicateScan(const QString &txt);
void toHost(const QString &cmdName, const QString &args); void toHost(const QString &cmdName, const QString &args);
void toLocalCmd(const QString &cmdName, const QString &args); void toLocalCmd(const QString &cmdName, const QString &args);
@ -64,8 +65,7 @@ signals:
void dataToHookedHost(const QByteArray &data, uchar dType); void dataToHookedHost(const QByteArray &data, uchar dType);
void dataToGenFile(quint16 cmdId, const QByteArray &data); void dataToGenFile(quint16 cmdId, const QByteArray &data);
void dataToHookedGenFile(const QByteArray &data); void dataToHookedGenFile(const QByteArray &data);
void mainTxtOut(const QString &txt); void txtInCache();
void errTxtOut(const QString &txt);
}; };
#endif // CMDLINE_H #endif // CMDLINE_H

View File

@ -91,7 +91,7 @@ void SaveBookmark::run(const QString &name, QStringList &args)
} }
else else
{ {
emit errTxtOut("err: Could not open the bookmark file for writing, reason: " + file.errorString() + "\n"); cacheTxt(ERR, "err: Could not open the bookmark file for writing, reason: " + file.errorString() + "\n");
} }
file.close(); file.close();
@ -99,7 +99,8 @@ void SaveBookmark::run(const QString &name, QStringList &args)
void SaveBookmark::askOverwrite() void SaveBookmark::askOverwrite()
{ {
emit mainTxtOut("'" + baseName + "' already exists. do you want to overwrite? (y/n): "); cacheTxt(TEXT, "'" + baseName + "' already exists. do you want to overwrite? (y/n): ");
emit setUserIO(LOCAL_HOOK); emit setUserIO(LOCAL_HOOK);
} }
@ -129,7 +130,7 @@ void SaveBookmark::dataIn(const QString &argsLine)
if (name.isEmpty()) if (name.isEmpty())
{ {
emit errTxtOut("err: Bookmark name (-name) not given.\n"); cacheTxt(ERR, "err: Bookmark name (-name) not given.\n");
} }
else else
{ {
@ -151,21 +152,21 @@ void SaveBookmark::dataIn(const QString &argsLine)
void ListBookmarks::dataIn(const QString &argsLine) void ListBookmarks::dataIn(const QString &argsLine)
{ {
Q_UNUSED(argsLine); Q_UNUSED(argsLine)
QStringList list = QDir(appDataDir() + BOOKMARK_FOLDER).entryList(QStringList() << "*.json", QDir::Files, QDir::Name); QStringList list = QDir(appDataDir() + BOOKMARK_FOLDER).entryList(QStringList() << "*.json", QDir::Files, QDir::Name);
if (list.isEmpty()) if (list.isEmpty())
{ {
emit mainTxtOut("Empty...\n"); cacheTxt(TEXT, "Empty...\n");
} }
else else
{ {
emit mainTxtOut("Bookmarks:\n\n"); cacheTxt(TEXT, "Bookmarks:\n\n");
for (int i = 0; i < list.size(); ++i) for (int i = 0; i < list.size(); ++i)
{ {
emit mainTxtOut(" " + QFileInfo(list[i]).baseName() + "\n"); cacheTxt(TEXT, " " + QFileInfo(list[i]).baseName() + "\n");
} }
} }
} }
@ -177,7 +178,7 @@ void DeleteBookmark::dataIn(const QString &argsLine)
if (name.isEmpty()) if (name.isEmpty())
{ {
emit errTxtOut("err: Bookmark name (-name) not given.\n"); cacheTxt(ERR, "err: Bookmark name (-name) not given.\n");
} }
else else
{ {
@ -185,7 +186,7 @@ void DeleteBookmark::dataIn(const QString &argsLine)
if (!QFile::remove(path)) if (!QFile::remove(path))
{ {
emit errTxtOut("err: Could not delete the bookmark, the file might not exist or you don't have write permissions.\n"); cacheTxt(ERR, "err: Could not delete the bookmark, the file might not exist or you don't have write permissions.\n");
} }
} }
} }
@ -197,7 +198,7 @@ void SeeBookmark::dataIn(const QString &argsLine)
if (name.isEmpty()) if (name.isEmpty())
{ {
emit errTxtOut("err: Bookmark name (-name) not given.\n"); cacheTxt(ERR, "err: Bookmark name (-name) not given.\n");
} }
else else
{ {
@ -209,12 +210,12 @@ void SeeBookmark::dataIn(const QString &argsLine)
{ {
QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
emit mainTxtOut("address: " + doc.object().value("address").toString() + "\n"); cacheTxt(TEXT, "address: " + doc.object().value("address").toString() + "\n");
emit mainTxtOut("port: " + QString::number(doc.object().value("port").toInt()) + "\n"); cacheTxt(TEXT, "port: " + QString::number(doc.object().value("port").toInt()) + "\n");
} }
else else
{ {
emit errTxtOut("err: Could not open the requested bookmark file for reading, reason: " + file.errorString() + '\n'); cacheTxt(ERR, "err: Could not open the requested bookmark file for reading, reason: " + file.errorString() + '\n');
} }
file.close(); file.close();

View File

@ -21,10 +21,7 @@ Command::Command(QObject *parent) : QObject(parent)
// the QObject::objectName property determines the command // the QObject::objectName property determines the command
// name for any object inheriting this object. avoid using // name for any object inheriting this object. avoid using
// spaces and keep in mind that all command names are case // spaces and keep in mind that all command names are case
// insensitive. avoid starting the command with the char // insensitive.
// defined in CMD_ESCAPE, this char is used to send
// commands directly to the host in case of naming
// conflicts with the host commands.
setObjectName("do_nothing"); setObjectName("do_nothing");
@ -32,6 +29,16 @@ Command::Command(QObject *parent) : QObject(parent)
connect(this, &Command::unsetUserIO, this, &Command::unsetHook); connect(this, &Command::unsetUserIO, this, &Command::unsetHook);
} }
void Command::cacheTxt(quint8 typeId, QString txt)
{
Shared::cacheTxt(Shared::TXT_IN, typeId, txt);
if (!(*Shared::activeDisp))
{
emit txtInCache();
}
}
void Command::setHook(int flgs) void Command::setHook(int flgs)
{ {
if (flgs & LOCAL_HOOK) if (flgs & LOCAL_HOOK)
@ -112,5 +119,5 @@ void Command::hookedCmdCall(const QString &argsLine)
void Command::postExec() void Command::postExec()
{ {
emit mainTxtOut("\nFinished: " + objectName() + "\n\n"); cacheTxt(TEXT, "\nFinished: " + objectName() + "\n\n");
} }

View File

@ -31,6 +31,7 @@ private slots:
protected: protected:
bool activeHook(); bool activeHook();
void cacheTxt(quint8 typeId, QString txt);
public: public:
@ -54,9 +55,6 @@ public slots:
signals: signals:
void mainTxtOut(const QString &txt);
void errTxtOut(const QString &txt);
void bigTxtOut(const QString &txt);
void setUserIO(int flgs); void setUserIO(int flgs);
void unsetUserIO(int flgs); void unsetUserIO(int flgs);
void setMaxLines(int value); void setMaxLines(int value);
@ -68,6 +66,7 @@ signals:
void disconnectHost(); void disconnectHost();
void colorsChanged(); void colorsChanged();
void fontChanged(); void fontChanged();
void txtInCache();
}; };
#endif // COMMAND_H #endif // COMMAND_H

View File

@ -115,7 +115,7 @@ void Connect::dataIn(const QString &argsLine)
} }
else else
{ {
emit errTxtOut("err: Could not open the requested bookmark for reading, reason: " + file.errorString() + "\n"); cacheTxt(ERR, "err: Could not open the requested bookmark for reading, reason: " + file.errorString() + "\n");
} }
file.close(); file.close();
@ -123,15 +123,15 @@ void Connect::dataIn(const QString &argsLine)
if (Shared::hostAddress->isEmpty()) if (Shared::hostAddress->isEmpty())
{ {
emit errTxtOut("err: Host address is empty.\n"); cacheTxt(ERR, "err: Host address is empty.\n");
} }
else if (QHostAddress(*Shared::hostAddress).isNull()) else if (QHostAddress(*Shared::hostAddress).isNull())
{ {
emit errTxtOut("err: '" + *Shared::hostAddress + "' is not a valid address.\n"); cacheTxt(ERR, "err: '" + *Shared::hostAddress + "' is not a valid address.\n");
} }
else if (*Shared::hostPort == 0) else if (*Shared::hostPort == 0)
{ {
emit errTxtOut("err: The host port cannot be 0.\n"); cacheTxt(ERR, "err: The host port cannot be 0.\n");
} }
else else
{ {
@ -160,6 +160,8 @@ void Term::dataIn(const QString &argsLine)
{ {
Q_UNUSED(argsLine) Q_UNUSED(argsLine)
Shared::cacheTxt(Shared::TXT_CLEAR);
emit termHostCmd(); emit termHostCmd();
} }

View File

@ -39,7 +39,7 @@ void About::dispInfo(Command *cmdObj)
txtOut << "" << endl; txtOut << "" << endl;
wordWrap("usage: ", txtOut, cmdObj->longText(), Shared::mainWidget); wordWrap("usage: ", txtOut, cmdObj->longText(), Shared::mainWidget);
emit mainTxtOut(txt); cacheTxt(TEXT, txt);
} }
bool About::dispClientCmd(const QString &cmdName) bool About::dispClientCmd(const QString &cmdName)
@ -108,7 +108,7 @@ void About::dataIn(const QString &argsLine)
if (!dispInfo(cmdName)) if (!dispInfo(cmdName))
{ {
emit errTxtOut("err: No such command: '" + cmdName + "'\n"); cacheTxt(ERR, "err: No such command: '" + cmdName + "'\n");
} }
} }
else else
@ -136,7 +136,7 @@ void About::dataIn(const QString &argsLine)
txtOut << endl << endl << "for more detailed information about a command type: about <command>" << endl << endl; txtOut << endl << endl << "for more detailed information about a command type: about <command>" << endl << endl;
emit mainTxtOut(txt); cacheTxt(TEXT, txt);
} }
} }

View File

@ -66,5 +66,5 @@ void Status::dataIn(const QString &argsLine)
} }
} }
emit mainTxtOut(txt); cacheTxt(TEXT, txt);
} }

View File

@ -117,9 +117,9 @@ void SetColors::dataIn(const QString &argsLine)
QJsonObject obj = localData->value("text_settings").toObject(); QJsonObject obj = localData->value("text_settings").toObject();
emit mainTxtOut("text: " + obj.value("text_color").toString() + "\n"); cacheTxt(TEXT, "text: " + obj.value("text_color").toString() + "\n");
emit mainTxtOut("error: " + obj.value("err_color").toString() + "\n"); cacheTxt(TEXT, "error: " + obj.value("err_color").toString() + "\n");
emit mainTxtOut("bg: " + obj.value("bg_color").toString() + "\n"); cacheTxt(TEXT, "bg: " + obj.value("bg_color").toString() + "\n");
if (changed) emit colorsChanged(); if (changed) emit colorsChanged();
} }
@ -134,8 +134,8 @@ void SetFont::dataIn(const QString &argsLine)
QJsonObject obj = localData->value("text_settings").toObject(); QJsonObject obj = localData->value("text_settings").toObject();
emit mainTxtOut("family: " + obj.value("font_family").toString() + "\n"); cacheTxt(TEXT, "family: " + obj.value("font_family").toString() + "\n");
emit mainTxtOut("size: " + obj.value("font_size").toString() + "\n"); cacheTxt(TEXT, "size: " + obj.value("font_size").toString() + "\n");
if (changed) emit fontChanged(); if (changed) emit fontChanged();
} }
@ -147,7 +147,7 @@ void SetMaxLines::dataIn(const QString &argsLine)
if (valStr.isEmpty()) if (valStr.isEmpty())
{ {
emit mainTxtOut(QString::number(localData->value("max_lines").toInt()) + "\n"); cacheTxt(TEXT, QString::number(localData->value("max_lines").toInt()) + "\n");
} }
else else
{ {
@ -156,11 +156,11 @@ void SetMaxLines::dataIn(const QString &argsLine)
if (!ok) if (!ok)
{ {
emit errTxtOut("err: '" + valStr + "' is not a valid integer.\n"); cacheTxt(ERR, "err: '" + valStr + "' is not a valid integer.\n");
} }
else if ((val < 50) || (val > 100000)) else if ((val < 50) || (val > 100000))
{ {
emit errTxtOut("err: The value must range 50 - 100000.\n"); cacheTxt(ERR, "err: The value must range 50 - 100000.\n");
} }
else else
{ {

View File

@ -383,6 +383,7 @@ bool argExists(const QString &key, const QStringList &args)
} }
bool *Shared::connectedToHost = nullptr; bool *Shared::connectedToHost = nullptr;
bool *Shared::activeDisp = nullptr;
QJsonObject *Shared::localData = nullptr; QJsonObject *Shared::localData = nullptr;
QHash<QString, Command*> *Shared::clientCmds = nullptr; QHash<QString, Command*> *Shared::clientCmds = nullptr;
QHash<quint16, QString> *Shared::hostCmds = nullptr; QHash<quint16, QString> *Shared::hostCmds = nullptr;
@ -403,5 +404,75 @@ Genfile *Shared::genFile = nullptr;
MainWindow *Shared::mainWin = nullptr; MainWindow *Shared::mainWin = nullptr;
Session *Shared::session = nullptr; Session *Shared::session = nullptr;
TextBody *Shared::textBody = nullptr; TextBody *Shared::textBody = nullptr;
TextWorker *Shared::textWorker = nullptr;
ContextReloader *Shared::contextReloader = nullptr; ContextReloader *Shared::contextReloader = nullptr;
QWidget *Shared::mainWidget = nullptr; QWidget *Shared::mainWidget = nullptr;
QList<quint8> *Shared::idCache = nullptr;
QList<QString> *Shared::txtCache = nullptr;
ThreadKiller *Shared::theadKiller = nullptr;
bool Shared::cacheTxt(CacheOp op, quint8 &typeId, QString &txt)
{
QMutex mutex;
bool ret = false;
mutex.lock();
if (op == TXT_IN)
{
if ((typeId == TEXT) || (typeId == ERR) || (typeId == BIG_TEXT) || (typeId == PRIV_TEXT))
{
idCache->append(typeId);
txtCache->append(txt);
ret = true;
}
}
else if (op == TXT_OUT)
{
if (!idCache->isEmpty() && !txtCache->isEmpty())
{
typeId = idCache->takeFirst();
txt = txtCache->takeFirst();
ret = true;
}
}
else if (op == TXT_CLEAR)
{
*Shared::activeDisp = false;
idCache->clear();
txtCache->clear();
}
else if (op == TXT_IS_EMPTY)
{
ret = idCache->isEmpty() && txtCache->isEmpty();
}
mutex.unlock();
return ret;
}
bool Shared::cacheTxt(CacheOp op)
{
quint8 unusedId = 0;
QString unusedTxt;
return cacheTxt(op, unusedId, unusedTxt);
}
ThreadKiller::ThreadKiller(QObject *parent) : QObject(parent)
{
threadCount = 3;
}
void ThreadKiller::threadFinished()
{
threadCount--;
if (threadCount == 0)
{
QCoreApplication::instance()->quit();
}
}

View File

@ -62,18 +62,19 @@
#include <QFile> #include <QFile>
#include <QRegExp> #include <QRegExp>
#include <QFileInfo> #include <QFileInfo>
#include <QMutex>
#include "cmd_objs/long_txt.h" #include "cmd_objs/long_txt.h"
#define DEFAULT_HIST_LIMIT 100 #define DEFAULT_HIST_LIMIT 100
#define DEFAULT_MAX_LINES 5000 #define DEFAULT_MAX_LINES 1000
#define RDBUFF 128000 #define RDBUFF 128000
#define TXT_CODEC "UTF-16LE" #define TXT_CODEC "UTF-16LE"
#define BOOKMARK_FOLDER "bookmarks" #define BOOKMARK_FOLDER "bookmarks"
#define CONFIG_FILENAME "config.json" #define CONFIG_FILENAME "config.json"
#define APP_NAME "Cmdr" #define APP_NAME "Cmdr"
#define APP_TARGET "cmdr" #define APP_TARGET "cmdr"
#define APP_VERSION "2.0.0" #define APP_VERSION "2.1.0"
enum TypeID : quint8 enum TypeID : quint8
{ {
@ -177,8 +178,10 @@ class Genfile;
class MainWindow; class MainWindow;
class Session; class Session;
class TextBody; class TextBody;
class TextWorker;
class ContextReloader; class ContextReloader;
class HostDoc; class HostDoc;
class ThreadKiller;
class Shared : public QObject class Shared : public QObject
{ {
@ -187,6 +190,7 @@ class Shared : public QObject
public: public:
static bool *connectedToHost; static bool *connectedToHost;
static bool *activeDisp;
static QByteArray *sessionId; static QByteArray *sessionId;
static ushort *servMajor; static ushort *servMajor;
static ushort *servMinor; static ushort *servMinor;
@ -200,6 +204,8 @@ public:
static QHash<quint16, QString> *hostCmds; static QHash<quint16, QString> *hostCmds;
static QHash<quint16, QString> *genfileCmds; static QHash<quint16, QString> *genfileCmds;
static QHash<QString, Command*> *hostDocs; static QHash<QString, Command*> *hostDocs;
static QList<quint8> *idCache;
static QList<QString> *txtCache;
static QJsonObject *localData; static QJsonObject *localData;
static quint16 *termCmdId; static quint16 *termCmdId;
static CmdLine *cmdLine; static CmdLine *cmdLine;
@ -207,8 +213,21 @@ public:
static MainWindow *mainWin; static MainWindow *mainWin;
static Session *session; static Session *session;
static TextBody *textBody; static TextBody *textBody;
static TextWorker *textWorker;
static ContextReloader *contextReloader; static ContextReloader *contextReloader;
static QWidget *mainWidget; static QWidget *mainWidget;
static ThreadKiller *theadKiller;
enum CacheOp
{
TXT_IN,
TXT_OUT,
TXT_CLEAR,
TXT_IS_EMPTY
};
static bool cacheTxt(CacheOp op);
static bool cacheTxt(CacheOp op, quint8 &typeId, QString &txt);
explicit Shared(QObject *parent = nullptr); explicit Shared(QObject *parent = nullptr);
}; };
@ -226,5 +245,26 @@ public slots:
void reloadCmdLine(); void reloadCmdLine();
}; };
class ThreadKiller : public QObject
{
Q_OBJECT
private:
int threadCount;
public:
explicit ThreadKiller(QObject *parent = nullptr);
public slots:
void threadFinished();
signals:
void quitThreads();
};
#endif // COMMON_H #endif // COMMON_H

View File

@ -16,16 +16,27 @@
// along with Cmdr under the LICENSE.md file. If not, see // along with Cmdr under the LICENSE.md file. If not, see
// <http://www.gnu.org/licenses/>. // <http://www.gnu.org/licenses/>.
Genfile::Genfile(QObject *parent) : QObject(parent) Genfile::Genfile(QObject *parent) : QObject(nullptr)
{ {
file = new QFile(this); file = new QFile(this);
hook = 0; hook = 0;
finished(); finished();
connect(parent, &QObject::destroyed, this, &QObject::deleteLater);
connect(this, &Genfile::rdFileLoop, this, &Genfile::hookedDataIn); connect(this, &Genfile::rdFileLoop, this, &Genfile::hookedDataIn);
} }
void Genfile::cacheTxt(quint8 typeId, QString txt)
{
Shared::cacheTxt(Shared::TXT_IN, typeId, txt);
if (!(*Shared::activeDisp))
{
emit txtInCache();
}
}
void Genfile::finished() void Genfile::finished()
{ {
flags = 0; flags = 0;
@ -42,6 +53,7 @@ void Genfile::finished()
file->close(); file->close();
} }
emit unsetUserIO(GEN_HOOK);
emit enableGenFile(false); emit enableGenFile(false);
} }
@ -50,7 +62,7 @@ void Genfile::askOverwrite()
flags |= CONFIRM_NEEDED; flags |= CONFIRM_NEEDED;
emit setUserIO(GEN_HOOK); emit setUserIO(GEN_HOOK);
emit mainTxtOut("About to overwrite file: '" + localFile + "' do you want to continue? (y/n): "); emit cacheTxt(TEXT, "About to overwrite file: '" + localFile + "' do you want to continue? (y/n): ");
} }
bool Genfile::seekToOffset() bool Genfile::seekToOffset()
@ -68,7 +80,7 @@ bool Genfile::seekToOffset()
if (!ok) if (!ok)
{ {
emit errTxtOut("err: Invalid offset was provided: " + offs + "\n"); cacheTxt(ERR, "err: Invalid offset was provided: " + offs + "\n");
} }
ret = file->seek(pos); ret = file->seek(pos);
@ -88,7 +100,7 @@ bool Genfile::lenOk()
} }
else if (len.isEmpty()) else if (len.isEmpty())
{ {
emit errTxtOut("err: The -len parameter is empty.\n"); cacheTxt(ERR, "err: The -len parameter is empty.\n");
} }
else else
{ {
@ -113,20 +125,17 @@ void Genfile::setupForWriting()
if (!file->open(mode)) if (!file->open(mode))
{ {
emit errTxtOut("err: Could not open the client file for writing. reason: " + file->errorString() + "\n"); cacheTxt(ERR, "err: Could not open the client file for writing. reason: " + file->errorString() + "\n");
finished(); finished();
} }
else if (!seekToOffset()) else if (!seekToOffset())
{ {
emit errTxtOut("err: Could not seek to offset postion: " + offs + " of the client file.\n"); cacheTxt(ERR, "err: Could not seek to offset postion: " + offs + " of the client file.\n");
finished(); finished();
} }
else if (!lenOk()) else if (!lenOk())
{ {
emit errTxtOut("err: The -len parameter (" + len + ") is invalid.\n"); cacheTxt(ERR, "err: The -len parameter (" + len + ") is invalid.\n");
finished(); finished();
} }
else else
@ -143,20 +152,17 @@ void Genfile::setupForReading()
if (!file->open(QFile::ReadOnly)) if (!file->open(QFile::ReadOnly))
{ {
emit errTxtOut("err: Could not open the client file for reading. reason: " + file->errorString() + "\n"); cacheTxt(ERR, "err: Could not open the client file for reading. reason: " + file->errorString() + "\n");
finished(); finished();
} }
else if (!seekToOffset()) else if (!seekToOffset())
{ {
emit errTxtOut("err: Could not seek to offset postion: " + offs + " of the client file.\n"); cacheTxt(ERR, "err: Could not seek to offset postion: " + offs + " of the client file.\n");
finished(); finished();
} }
else if (!lenOk()) else if (!lenOk())
{ {
emit errTxtOut("err: The -len parameter (" + len + ") is invalid.\n"); cacheTxt(ERR, "err: The -len parameter (" + len + ") is invalid.\n");
finished(); finished();
} }
} }
@ -187,7 +193,7 @@ bool Genfile::wrToFile(const QByteArray &data)
} }
else else
{ {
emit errTxtOut("err: Client write failure - " + file->errorString() + "\n"); cacheTxt(ERR, "err: Client write failure - " + file->errorString() + "\n");
} }
return ret; return ret;
@ -231,7 +237,7 @@ bool Genfile::rdFromFile()
} }
else else
{ {
emit errTxtOut("err: Client read failure - " + file->errorString() + "\n"); cacheTxt(ERR, "err: Client read failure - " + file->errorString() + "\n");
} }
return ret; return ret;
@ -322,8 +328,7 @@ void Genfile::dataIn(quint16 cmdId, const QByteArray &data)
} }
else else
{ {
emit errTxtOut("err: The host did not return -to_host or -from_host, making this command call ambiguous.\n"); cacheTxt(ERR, "err: The host did not return -to_host or -from_host, making this command call ambiguous.\n");
finished(); finished();
} }
} }

View File

@ -54,6 +54,7 @@ private:
void askOverwrite(); void askOverwrite();
void setupForWriting(); void setupForWriting();
void setupForReading(); void setupForReading();
void cacheTxt(quint8 typeId, QString txt);
QByteArray autoFill(const QByteArray &data); QByteArray autoFill(const QByteArray &data);
qint64 getRdBuff(); qint64 getRdBuff();
@ -69,9 +70,8 @@ public:
signals: signals:
void txtInCache();
void enableGenFile(bool state); void enableGenFile(bool state);
void mainTxtOut(const QString &txt);
void errTxtOut(const QString &txt);
void setUserIO(int flgs); void setUserIO(int flgs);
void unsetUserIO(int flgs); void unsetUserIO(int flgs);
void dataOut(quint16 cmdId, const QByteArray &data, uchar typeID = GEN_FILE); void dataOut(quint16 cmdId, const QByteArray &data, uchar typeID = GEN_FILE);

View File

@ -37,6 +37,7 @@ void setupClientCmds();
void setupCmdLine(); void setupCmdLine();
void setupGenFile(); void setupGenFile();
void setupSession(); void setupSession();
void setupText();
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@ -46,6 +47,7 @@ int main(int argc, char *argv[])
app.setApplicationVersion(APP_VERSION); app.setApplicationVersion(APP_VERSION);
bool connected = false; bool connected = false;
bool activeDisp = false;
ushort servMajor = 0; ushort servMajor = 0;
ushort servMinor = 0; ushort servMinor = 0;
ushort servPatch = 0; ushort servPatch = 0;
@ -59,6 +61,8 @@ int main(int argc, char *argv[])
QHash<QString, Command*> clientCmds; QHash<QString, Command*> clientCmds;
QHash<QString, Command*> hostDocs; QHash<QString, Command*> hostDocs;
QHash<quint16, QString> hostCmds; QHash<quint16, QString> hostCmds;
QList<quint8> idCache;
QList<QString> txtCache;
QJsonObject localData; QJsonObject localData;
loadLocalData(&localData); loadLocalData(&localData);
@ -79,9 +83,14 @@ int main(int argc, char *argv[])
Shared::termCmdId = &termCmdId; Shared::termCmdId = &termCmdId;
Shared::localData = &localData; Shared::localData = &localData;
Shared::clientHookedCmd = &clientHookCmd; Shared::clientHookedCmd = &clientHookCmd;
Shared::idCache = &idCache;
Shared::txtCache = &txtCache;
Shared::activeDisp = &activeDisp;
Shared::contextReloader = new ContextReloader(&app); Shared::contextReloader = new ContextReloader(&app);
Shared::theadKiller = new ThreadKiller(&app);
Shared::session = new Session(&app); Shared::session = new Session(&app);
Shared::mainWin = new MainWindow(); Shared::mainWin = new MainWindow();
Shared::textWorker = new TextWorker(&app);
Shared::textBody = new TextBody(Shared::mainWin); Shared::textBody = new TextBody(Shared::mainWin);
Shared::cmdLine = new CmdLine(Shared::mainWin); Shared::cmdLine = new CmdLine(Shared::mainWin);
Shared::genFile = new Genfile(&app); Shared::genFile = new Genfile(&app);
@ -109,6 +118,7 @@ int main(int argc, char *argv[])
setupCmdLine(); setupCmdLine();
setupGenFile(); setupGenFile();
setupSession(); setupSession();
setupText();
Shared::mainWin->setTextBody(Shared::textBody); Shared::mainWin->setTextBody(Shared::textBody);
Shared::mainWin->setCmdLine(Shared::cmdLine); Shared::mainWin->setCmdLine(Shared::cmdLine);
@ -138,18 +148,21 @@ void ContextReloader::reloadCmdLine()
void setupClientCmds() void setupClientCmds()
{ {
Session *session = Shared::session; Session *session = Shared::session;
CmdLine *cmdLine = Shared::cmdLine; CmdLine *cmdLine = Shared::cmdLine;
TextBody *textBody = Shared::textBody; TextWorker *textWorker = Shared::textWorker;
Genfile *genFile = Shared::genFile; TextBody *textBody = Shared::textBody;
MainWindow *mainWin = Shared::mainWin; Genfile *genFile = Shared::genFile;
ContextReloader *reloader = Shared::contextReloader; MainWindow *mainWin = Shared::mainWin;
ContextReloader *reloader = Shared::contextReloader;
ThreadKiller *killer = Shared::theadKiller;
QObject::connect(mainWin, &MainWindow::closeApp, killer, &ThreadKiller::quitThreads);
for (auto command : Shared::clientCmds->values()) for (auto command : Shared::clientCmds->values())
{ {
QObject::connect(command, &Command::mainTxtOut, textBody, &TextBody::addMainTxt); QObject::connect(command, &Command::colorsChanged, textWorker, &TextWorker::loadSettings);
QObject::connect(command, &Command::errTxtOut, textBody, &TextBody::addErrTxt); QObject::connect(command, &Command::txtInCache, textWorker, &TextWorker::dumpTxtCache);
QObject::connect(command, &Command::bigTxtOut, textBody, &TextBody::addBigTxt);
QObject::connect(cmdLine, &CmdLine::dataToCommandObj, command, &Command::cmdCall); QObject::connect(cmdLine, &CmdLine::dataToCommandObj, command, &Command::cmdCall);
QObject::connect(cmdLine, &CmdLine::dataToHookedCmdObj, command, &Command::hookedCmdCall); QObject::connect(cmdLine, &CmdLine::dataToHookedCmdObj, command, &Command::hookedCmdCall);
@ -164,7 +177,7 @@ void setupClientCmds()
QObject::connect(command, &Command::quitApp, session, &Session::disconnectFromServ); QObject::connect(command, &Command::quitApp, session, &Session::disconnectFromServ);
QObject::connect(command, &Command::disconnectHost, session, &Session::disconnectFromServ); QObject::connect(command, &Command::disconnectHost, session, &Session::disconnectFromServ);
QObject::connect(command, &Command::quitApp, QCoreApplication::instance(), &QCoreApplication::quit); QObject::connect(command, &Command::quitApp, killer, &ThreadKiller::quitThreads);
QObject::connect(command, &Command::termHostCmd, genFile, &Genfile::finished); QObject::connect(command, &Command::termHostCmd, genFile, &Genfile::finished);
QObject::connect(command, &Command::quitApp, genFile, &Genfile::finished); QObject::connect(command, &Command::quitApp, genFile, &Genfile::finished);
@ -182,27 +195,28 @@ void setupClientCmds()
void setupCmdLine() void setupCmdLine()
{ {
Session *session = Shared::session; Session *session = Shared::session;
CmdLine *cmdLine = Shared::cmdLine; CmdLine *cmdLine = Shared::cmdLine;
TextBody *textBody = Shared::textBody; TextWorker *textWorker = Shared::textWorker;
Genfile *genFile = Shared::genFile; Genfile *genFile = Shared::genFile;
QObject::connect(cmdLine, &CmdLine::dataToHost, session, &Session::binToServer); QObject::connect(cmdLine, &CmdLine::dataToHost, session, &Session::binToServer);
QObject::connect(cmdLine, &CmdLine::dataToHookedHost, session, &Session::hookedBinToServer); QObject::connect(cmdLine, &CmdLine::dataToHookedHost, session, &Session::hookedBinToServer);
QObject::connect(cmdLine, &CmdLine::mainTxtOut, textBody, &TextBody::addMainTxt);
QObject::connect(cmdLine, &CmdLine::errTxtOut, textBody, &TextBody::addErrTxt);
QObject::connect(cmdLine, &CmdLine::dataToGenFile, genFile, &Genfile::dataIn); QObject::connect(cmdLine, &CmdLine::dataToGenFile, genFile, &Genfile::dataIn);
QObject::connect(cmdLine, &CmdLine::dataToHookedGenFile, genFile, &Genfile::hookedDataIn); QObject::connect(cmdLine, &CmdLine::dataToHookedGenFile, genFile, &Genfile::hookedDataIn);
QObject::connect(cmdLine, &CmdLine::txtInCache, textWorker, &TextWorker::dumpTxtCache);
} }
void setupGenFile() void setupGenFile()
{ {
Session *session = Shared::session; Session *session = Shared::session;
CmdLine *cmdLine = Shared::cmdLine; CmdLine *cmdLine = Shared::cmdLine;
TextBody *textBody = Shared::textBody; TextWorker *textWorker = Shared::textWorker;
Genfile *genFile = Shared::genFile; Genfile *genFile = Shared::genFile;
ThreadKiller *killer = Shared::theadKiller;
QThread *genThr = new QThread(QCoreApplication::instance());
QObject::connect(genFile, &Genfile::dataOut, session, &Session::binToServer); QObject::connect(genFile, &Genfile::dataOut, session, &Session::binToServer);
QObject::connect(genFile, &Genfile::hookedDataOut, session, &Session::hookedBinToServer); QObject::connect(genFile, &Genfile::hookedDataOut, session, &Session::hookedBinToServer);
@ -211,19 +225,23 @@ void setupGenFile()
QObject::connect(genFile, &Genfile::setUserIO, cmdLine, &CmdLine::setFlags); QObject::connect(genFile, &Genfile::setUserIO, cmdLine, &CmdLine::setFlags);
QObject::connect(genFile, &Genfile::unsetUserIO, cmdLine, &CmdLine::unsetFlags); QObject::connect(genFile, &Genfile::unsetUserIO, cmdLine, &CmdLine::unsetFlags);
QObject::connect(genFile, &Genfile::mainTxtOut, textBody, &TextBody::addMainTxt); QObject::connect(genFile, &Genfile::txtInCache, textWorker, &TextWorker::dumpTxtCache);
QObject::connect(genFile, &Genfile::errTxtOut, textBody, &TextBody::addErrTxt);
QObject::connect(genThr, &QThread::finished, killer, &ThreadKiller::threadFinished);
QObject::connect(killer, &ThreadKiller::quitThreads, genThr, &QThread::quit);
genFile->moveToThread(genThr);
genThr->start();
} }
void setupSession() void setupSession()
{ {
Session *session = Shared::session; Session *session = Shared::session;
CmdLine *cmdLine = Shared::cmdLine; CmdLine *cmdLine = Shared::cmdLine;
TextBody *textBody = Shared::textBody; TextWorker *textWorker = Shared::textWorker;
Genfile *genFile = Shared::genFile; Genfile *genFile = Shared::genFile;
QThread *sesThr = new QThread(nullptr); ThreadKiller *killer = Shared::theadKiller;
QThread *sesThr = new QThread(QCoreApplication::instance());
QObject::connect(session, &Session::destroyed, sesThr, &QThread::quit);
QObject::connect(session, &Session::hostFinished, genFile, &Genfile::finished); QObject::connect(session, &Session::hostFinished, genFile, &Genfile::finished);
QObject::connect(session, &Session::toGenFile, genFile, &Genfile::hookedDataIn); QObject::connect(session, &Session::toGenFile, genFile, &Genfile::hookedDataIn);
@ -231,12 +249,31 @@ void setupSession()
QObject::connect(session, &Session::setUserIO, cmdLine, &CmdLine::setFlags); QObject::connect(session, &Session::setUserIO, cmdLine, &CmdLine::setFlags);
QObject::connect(session, &Session::unsetUserIO, cmdLine, &CmdLine::unsetFlags); QObject::connect(session, &Session::unsetUserIO, cmdLine, &CmdLine::unsetFlags);
QObject::connect(session, &Session::bigTxtOut, textBody, &TextBody::addBigTxt); QObject::connect(session, &Session::txtInCache, textWorker, &TextWorker::dumpTxtCache);
QObject::connect(session, &Session::mainTxtOut, textBody, &TextBody::addMainTxt);
QObject::connect(session, &Session::errTxtOut, textBody, &TextBody::addErrTxt);
QObject::connect(sesThr, &QThread::finished, sesThr, &QThread::deleteLater); QObject::connect(sesThr, &QThread::finished, killer, &ThreadKiller::threadFinished);
QObject::connect(killer, &ThreadKiller::quitThreads, sesThr, &QThread::quit);
session->moveToThread(sesThr); session->moveToThread(sesThr);
sesThr->start(); sesThr->start();
} }
void setupText()
{
TextWorker *textWorker = Shared::textWorker;
CmdLine *cmdLine = Shared::cmdLine;
TextBody *textBody = Shared::textBody;
ThreadKiller *killer = Shared::theadKiller;
QThread *txtThr = new QThread(QCoreApplication::instance());
QObject::connect(textWorker, &TextWorker::setUserIO, cmdLine, &CmdLine::setFlags);
QObject::connect(textWorker, &TextWorker::unsetUserIO, cmdLine, &CmdLine::unsetFlags);
QObject::connect(textWorker, &TextWorker::htmlOut, textBody, &TextBody::htmlIn);
QObject::connect(txtThr, &QThread::finished, killer, &ThreadKiller::threadFinished);
QObject::connect(killer, &ThreadKiller::quitThreads, txtThr, &QThread::quit);
textWorker->moveToThread(txtThr);
txtThr->start();
}

View File

@ -75,6 +75,13 @@ void MainWindow::resizeEvent(QResizeEvent *event)
QMainWindow::resizeEvent(event); QMainWindow::resizeEvent(event);
} }
void MainWindow::closeEvent(QCloseEvent *event)
{
emit closeApp();
event->ignore();
}
void MainWindow::setCmdLine(QWidget *widget) void MainWindow::setCmdLine(QWidget *widget)
{ {
widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);

View File

@ -29,6 +29,7 @@ private:
QVBoxLayout *mainLayout; QVBoxLayout *mainLayout;
void resizeEvent(QResizeEvent *event); void resizeEvent(QResizeEvent *event);
void closeEvent(QCloseEvent *event);
void saveWindowSize(); void saveWindowSize();
public: public:
@ -42,6 +43,7 @@ public:
signals: signals:
void startup(); void startup();
void closeApp();
}; };
#endif // USER_IO_H #endif // USER_IO_H

View File

@ -30,6 +30,7 @@ Session::Session(QObject *parent) : QSslSocket(nullptr)
connect(this, &Session::connected, this, &Session::isConnected); connect(this, &Session::connected, this, &Session::isConnected);
connect(this, &Session::disconnected, this, &Session::isDisconnected); connect(this, &Session::disconnected, this, &Session::isDisconnected);
connect(this, &Session::readyRead, this, &Session::dataIn); connect(this, &Session::readyRead, this, &Session::dataIn);
connect(this, &Session::loopDataIn, this, &Session::dataIn);
connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(sockerr(QAbstractSocket::SocketError))); connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(sockerr(QAbstractSocket::SocketError)));
} }
@ -42,7 +43,7 @@ void Session::hookedBinToServer(const QByteArray &data, quint8 typeId)
} }
else else
{ {
emit errTxtOut("err: not connected to a host.\n"); cacheTxt(ERR, "err: not connected to a host.\n");
} }
} }
@ -58,7 +59,7 @@ void Session::binToServer(quint16 cmdId, const QByteArray &data, quint8 typeId)
} }
else else
{ {
emit errTxtOut("err: not connected to a host.\n"); cacheTxt(ERR, "err: not connected to a host.\n");
} }
} }
@ -66,11 +67,11 @@ void Session::sockerr(QAbstractSocket::SocketError err)
{ {
if (err == QAbstractSocket::RemoteHostClosedError) if (err == QAbstractSocket::RemoteHostClosedError)
{ {
emit mainTxtOut("\nThe remote host closed the session.\n"); cacheTxt(TEXT, "\nThe remote host closed the session.\n");
} }
else else
{ {
emit errTxtOut("\nerr: " + errorString() + "\n"); cacheTxt(ERR, "\nerr: " + errorString() + "\n");
if (state() == QAbstractSocket::UnconnectedState) if (state() == QAbstractSocket::UnconnectedState)
{ {
@ -87,7 +88,7 @@ void Session::isConnected()
// appName = UTF16LE string (padded with 0x00) // appName = UTF16LE string (padded with 0x00)
// coName = UTF16LE string (padded with 0x00) // coName = UTF16LE string (padded with 0x00)
emit mainTxtOut("Connected.\n"); cacheTxt(TEXT, "Connected.\n");
QByteArray header; QByteArray header;
QString appName = QString(APP_NAME) + " v" + QString(APP_VERSION); QString appName = QString(APP_NAME) + " v" + QString(APP_VERSION);
@ -102,8 +103,7 @@ void Session::isConnected()
} }
else else
{ {
emit errTxtOut("\nerr: client bug! - header len not equal to " + QString::number(CLIENT_HEADER_LEN) + "\n"); cacheTxt(ERR, "\nerr: client bug! - header len not equal to " + QString::number(CLIENT_HEADER_LEN) + "\n");
disconnectFromHost(); disconnectFromHost();
} }
} }
@ -123,7 +123,7 @@ void Session::handShakeDone()
<< " #key_exchange - " << cipher.keyExchangeMethod() << endl << " #key_exchange - " << cipher.keyExchangeMethod() << endl
<< " #authentication - " << cipher.authenticationMethod() << endl; << " #authentication - " << cipher.authenticationMethod() << endl;
emit mainTxtOut(txt); cacheTxt(TEXT, txt);
} }
void Session::isDisconnected() void Session::isDisconnected()
@ -142,7 +142,7 @@ void Session::isDisconnected()
Shared::hostCmds->clear(); Shared::hostCmds->clear();
Shared::genfileCmds->clear(); Shared::genfileCmds->clear();
emit mainTxtOut("\nHost session ended. (disconnected)\n\n"); cacheTxt(TEXT, "\nHost session ended. (disconnected)\n\n");
if (reconnect) if (reconnect)
{ {
@ -162,8 +162,7 @@ void Session::connectToServ()
} }
else else
{ {
emit mainTxtOut("Connecting to address: " + *Shared::hostAddress + " port: " + QString::number(*Shared::hostPort) + "\n"); cacheTxt(TEXT, "Connecting to address: " + *Shared::hostAddress + " port: " + QString::number(*Shared::hostPort) + "\n");
connectToHost(*Shared::hostAddress, *Shared::hostPort); connectToHost(*Shared::hostAddress, *Shared::hostPort);
} }
} }
@ -174,8 +173,7 @@ void Session::disconnectFromServ()
if (state() == QAbstractSocket::ConnectedState) if (state() == QAbstractSocket::ConnectedState)
{ {
emit mainTxtOut("Disconnecting.\n"); cacheTxt(TEXT, "Disconnecting.\n");
disconnectFromHost(); disconnectFromHost();
} }
@ -225,22 +223,14 @@ bool Session::isAsync(quint16 id)
void Session::procAsync(const QByteArray &data) void Session::procAsync(const QByteArray &data)
{ {
if (dType == TEXT) if ((dType == TEXT) || (dType == BIG_TEXT) || (dType == ERR))
{ {
cacheTxt(dType, fromTEXT(data));
if (cmdId == ASYNC_RDY) if (cmdId == ASYNC_RDY)
{ {
hook = 0; hook = 0;
} }
emit mainTxtOut(fromTEXT(data));
}
else if (dType == BIG_TEXT)
{
emit bigTxtOut(fromTEXT(data));
}
else if (dType == ERR)
{
emit errTxtOut(fromTEXT(data));
} }
else if (cmdId == ASYNC_SYS_MSG) else if (cmdId == ASYNC_SYS_MSG)
{ {
@ -249,11 +239,11 @@ void Session::procAsync(const QByteArray &data)
QSslCertificate cert(data, QSsl::Pem); QSslCertificate cert(data, QSsl::Pem);
QSslError selfSigned(QSslError::SelfSignedCertificate, cert); QSslError selfSigned(QSslError::SelfSignedCertificate, cert);
emit mainTxtOut("SSL cert received.\n\n"); cacheTxt(TEXT, "SSL cert received.\n\n");
if (cert.isSelfSigned()) if (cert.isSelfSigned())
{ {
emit mainTxtOut("WARNING: the cert is self signed. be careful if in a public network.\n\n"); cacheTxt(TEXT, "WARNING: the host cert is self signed.\n\n");
} }
ignoreSslErrors(QList<QSslError>() << selfSigned); ignoreSslErrors(QList<QSslError>() << selfSigned);
@ -291,6 +281,16 @@ void Session::procAsync(const QByteArray &data)
} }
} }
void Session::cacheTxt(quint8 typeId, QString txt)
{
Shared::cacheTxt(Shared::TXT_IN, typeId, txt);
if (!(*Shared::activeDisp))
{
emit txtInCache();
}
}
void Session::dataFromHost(const QByteArray &data) void Session::dataFromHost(const QByteArray &data)
{ {
if (isAsync(cmdId)) if (isAsync(cmdId))
@ -299,22 +299,9 @@ void Session::dataFromHost(const QByteArray &data)
} }
else if ((cmdId == hook) && (branId == 0) && (hook != 0)) else if ((cmdId == hook) && (branId == 0) && (hook != 0))
{ {
if ((dType == TEXT) || (dType == PRIV_TEXT)) if ((dType == TEXT) || (dType == PRIV_TEXT) || (dType == BIG_TEXT) || (dType == ERR))
{ {
emit mainTxtOut(fromTEXT(data)); cacheTxt(dType, fromTEXT(data));
if (dType == PRIV_TEXT)
{
emit setUserIO(HIDDEN);
}
}
else if (dType == BIG_TEXT)
{
emit bigTxtOut(fromTEXT(data));
}
else if (dType == ERR)
{
emit errTxtOut(fromTEXT(data));
} }
else if (dType == IDLE) else if (dType == IDLE)
{ {
@ -325,11 +312,11 @@ void Session::dataFromHost(const QByteArray &data)
if (Shared::hostCmds->contains(cmdId)) if (Shared::hostCmds->contains(cmdId))
{ {
emit mainTxtOut("\nFinished: " + Shared::hostCmds->value(cmdId) + "\n\n"); cacheTxt(TEXT, "\nFinished: " + Shared::hostCmds->value(cmdId) + "\n\n");
} }
else else
{ {
emit mainTxtOut("\nFinished: Unknown\n\n"); cacheTxt(TEXT, "\nFinished: Unknown\n\n");
} }
} }
else if ((dType == GEN_FILE) && (flags & GEN_FILE_ON)) else if ((dType == GEN_FILE) && (flags & GEN_FILE_ON))
@ -348,7 +335,8 @@ void Session::dataIn()
flags ^= DSIZE_RDY; flags ^= DSIZE_RDY;
dataFromHost(read(dSize)); dataFromHost(read(dSize));
dataIn();
emit loopDataIn();
} }
} }
else if (flags & VER_OK) else if (flags & VER_OK)
@ -363,7 +351,7 @@ void Session::dataIn()
dSize = static_cast<quint32>(rdInt(header.mid(5, 3))); dSize = static_cast<quint32>(rdInt(header.mid(5, 3)));
flags |= DSIZE_RDY; flags |= DSIZE_RDY;
dataIn(); emit loopDataIn();
} }
} }
else if (bytesAvailable() >= SERVER_HEADER_LEN) else if (bytesAvailable() >= SERVER_HEADER_LEN)
@ -386,7 +374,7 @@ void Session::dataIn()
*Shared::servMinor = static_cast<quint16>(rdInt(read(2))); *Shared::servMinor = static_cast<quint16>(rdInt(read(2)));
*Shared::servPatch = static_cast<quint16>(rdInt(read(2))); *Shared::servPatch = static_cast<quint16>(rdInt(read(2)));
emit mainTxtOut("Detected host version: " + verText(*Shared::servMajor, *Shared::servMinor, *Shared::servPatch) + "\n"); cacheTxt(TEXT, "Detected host version: " + verText(*Shared::servMajor, *Shared::servMinor, *Shared::servPatch) + "\n");
if (*Shared::servMajor == 2) if (*Shared::servMajor == 2)
{ {
@ -395,35 +383,34 @@ void Session::dataIn()
flags |= VER_OK; flags |= VER_OK;
emit mainTxtOut("Host assigned session id: " + Shared::sessionId->toHex() + "\n"); cacheTxt(TEXT, "Host assigned session id: " + Shared::sessionId->toHex() + "\n");
if (reply == 2) if (reply == 2)
{ {
emit mainTxtOut("Awaiting SSL cert from the host.\n"); cacheTxt(TEXT, "Awaiting SSL cert from the host.\n");
} }
else else
{ {
emit mainTxtOut("The host claims SSL is not needed. the connection will not be encrypted.\n"); cacheTxt(TEXT, "The host claims SSL is not needed. the connection will not be encrypted.\n");
} }
} }
else else
{ {
emit errTxtOut("err: Host not compatible.\n"); cacheTxt(ERR, "err: Host not compatible.\n");
disconnectFromHost(); disconnectFromHost();
} }
} }
else if (reply == 4) else if (reply == 4)
{ {
emit errTxtOut("err: The host was unable to find a SSL cert for common name: " + *Shared::hostAddress + ".\n"); cacheTxt(ERR, "err: The host was unable to find a SSL cert for common name: " + *Shared::hostAddress + ".\n");
} }
else else
{ {
emit errTxtOut("err: Invalid reply id from the host: " + QString::number(reply) + ".\n"); cacheTxt(ERR, "err: Invalid reply id from the host: " + QString::number(reply) + ".\n");
} }
if ((reply != 1) && (reply != 2)) disconnectFromHost(); if ((reply != 1) && (reply != 2)) disconnectFromHost();
dataIn(); emit loopDataIn();
} }
} }

View File

@ -58,6 +58,7 @@ private:
quint8 dType; quint8 dType;
bool reconnect; bool reconnect;
void cacheTxt(quint8 typeId, QString txt);
void dataFromHost(const QByteArray &data); void dataFromHost(const QByteArray &data);
void procAsync(const QByteArray &data); void procAsync(const QByteArray &data);
bool isAsync(quint16 id); bool isAsync(quint16 id);
@ -95,13 +96,12 @@ public slots:
signals: signals:
void hostFinished(); void hostFinished();
void txtInCache();
void loopDataIn();
void setUserIO(int flgs); void setUserIO(int flgs);
void unsetUserIO(int flgs); void unsetUserIO(int flgs);
void hostCmdRemoved(quint16 id); void hostCmdRemoved(quint16 id);
void toGenFile(const QByteArray &data); void toGenFile(const QByteArray &data);
void mainTxtOut(const QString &txt);
void errTxtOut(const QString &txt);
void bigTxtOut(const QString &txt);
}; };
#endif // SOCKET_H #endif // SOCKET_H

View File

@ -16,6 +16,97 @@
// along with Cmdr under the LICENSE.md file. If not, see // along with Cmdr under the LICENSE.md file. If not, see
// <http://www.gnu.org/licenses/>. // <http://www.gnu.org/licenses/>.
TextWorker::TextWorker(QObject *parent) : QObject(nullptr)
{
localData = Shared::localData;
connect(parent, &QObject::destroyed, this, &QObject::deleteLater);
connect(this, &TextWorker::loop, this, &TextWorker::dumpTxtCache);
loadSettings();
}
QString TextWorker::htmlEsc(const QString &txt)
{
QString ret = txt;
ret.replace(">", "&gt;");
ret.replace("<", "&lt;");
return ret;
}
void TextWorker::dumpTxtCache()
{
QString txt;
quint8 typeId;
if (Shared::cacheTxt(Shared::TXT_OUT, typeId, txt))
{
*Shared::activeDisp = !Shared::cacheTxt(Shared::TXT_IS_EMPTY);
if ((typeId == TEXT) || (typeId == PRIV_TEXT))
{
addMainTxt(txt);
if (typeId == PRIV_TEXT)
{
emit setUserIO(HIDDEN);
}
}
else if (typeId == ERR)
{
addErrTxt(txt);
}
else if (typeId == BIG_TEXT)
{
addBigTxt(txt);
}
if (*Shared::activeDisp)
{
emit loop();
}
}
}
void TextWorker::toHtmlLines(const QString &txt, const QString &color)
{
QStringList lines = htmlEsc(txt).split("\n");
for (int i = 0; i < lines.size(); ++i)
{
emit htmlOut("<div style=\"white-space: pre; color:" + color + ";\">" + lines[i] + "</div>", i == lines.size() - 1);
thread()->usleep(1000);
}
}
void TextWorker::addMainTxt(const QString &txt)
{
toHtmlLines(txt, mainColor);
}
void TextWorker::addErrTxt(const QString &txt)
{
toHtmlLines(txt, errColor);
}
void TextWorker::addBigTxt(const QString &txt)
{
QString lines;
QTextStream txtOut(&lines);
wordWrap("", txtOut, txt, Shared::mainWidget);
addMainTxt(lines);
}
void TextWorker::loadSettings()
{
mainColor = localData->value("text_settings").toObject().value("text_color").toString();
errColor = localData->value("text_settings").toObject().value("err_color").toString();
}
TextBody::TextBody(QWidget *parent) : QTextEdit(parent) TextBody::TextBody(QWidget *parent) : QTextEdit(parent)
{ {
localData = Shared::localData; localData = Shared::localData;
@ -31,66 +122,14 @@ TextBody::TextBody(QWidget *parent) : QTextEdit(parent)
void TextBody::loadTextBodySettings() void TextBody::loadTextBodySettings()
{ {
mainColor = localData->value("text_settings").toObject().value("text_color").toString();
errColor = localData->value("text_settings").toObject().value("err_color").toString();
txtDocument->setMaximumBlockCount(localData->value("max_lines").toInt()); txtDocument->setMaximumBlockCount(localData->value("max_lines").toInt());
} }
QString TextBody::htmlEsc(const QString &txt)
{
QString ret = txt;
ret.replace(">", "&gt;");
ret.replace("<", "&lt;");
return ret;
}
void TextBody::addTextBlock(const QString &txt, const QString &color)
{
moveCursor(QTextCursor::End);
QStringList lines = htmlEsc(txt).split("\n");
for (int i = 0; i < lines.size(); ++i)
{
txtCursor->insertHtml("<div style=\"white-space: pre; color:" + color + ";\">" + lines[i] + "</div>");
if (i != lines.size() - 1)
{
txtCursor->insertBlock();
}
}
ensureCursorVisible();
}
void TextBody::setMaxLines(int value) void TextBody::setMaxLines(int value)
{ {
txtDocument->setMaximumBlockCount(value); txtDocument->setMaximumBlockCount(value);
} }
void TextBody::addMainTxt(const QString &txt)
{
addTextBlock(txt, mainColor);
}
void TextBody::addErrTxt(const QString &txt)
{
addTextBlock(txt, errColor);
}
void TextBody::addBigTxt(const QString &txt)
{
QString lines;
QTextStream txtOut(&lines);
wordWrap("", txtOut, txt, Shared::mainWidget);
addMainTxt(lines);
}
void TextBody::reload() void TextBody::reload()
{ {
clear(); clear();
@ -108,3 +147,17 @@ void TextBody::contextMenuEvent(QContextMenuEvent *event)
menu->exec(event->globalPos()); menu->exec(event->globalPos());
menu->deleteLater(); menu->deleteLater();
} }
void TextBody::htmlIn(const QString &line, bool lastLine)
{
moveCursor(QTextCursor::End);
txtCursor->insertHtml(line);
if (!lastLine)
{
txtCursor->insertBlock();
}
ensureCursorVisible();
}

View File

@ -19,28 +19,53 @@
#include "common.h" #include "common.h"
class TextWorker : public QObject
{
Q_OBJECT
private:
QJsonObject *localData;
QString errColor;
QString mainColor;
QString htmlEsc(const QString &txt);
void toHtmlLines(const QString &txt, const QString &color);
void addMainTxt(const QString &txt);
void addErrTxt(const QString &txt);
void addBigTxt(const QString &txt);
public:
explicit TextWorker(QObject *parent = nullptr);
public slots:
void loadSettings();
void dumpTxtCache();
signals:
void htmlOut(const QString &line, bool lastLine);
void setUserIO(int flgs);
void unsetUserIO(int flgs);
void loop();
};
//-----------------------------------------
class TextBody : public QTextEdit class TextBody : public QTextEdit
{ {
Q_OBJECT Q_OBJECT
private: private:
enum TextType
{
ERROR,
MAIN
};
QTextDocument *txtDocument; QTextDocument *txtDocument;
QTextCursor *txtCursor; QTextCursor *txtCursor;
QJsonObject *localData; QJsonObject *localData;
QString errColor;
QString mainColor;
QString htmlEsc(const QString &txt); void loadTextBodySettings();
void loadTextBodySettings(); void contextMenuEvent(QContextMenuEvent *event);
void contextMenuEvent(QContextMenuEvent *event);
void addTextBlock(const QString &txt, const QString &color);
public: public:
@ -48,9 +73,7 @@ public:
public slots: public slots:
void addMainTxt(const QString &txt); void htmlIn(const QString &line, bool lastLine);
void addErrTxt(const QString &txt);
void addBigTxt(const QString &txt);
void setMaxLines(int value); void setMaxLines(int value);
void reload(); void reload();
}; };