From 684e3962de16d39c785d0d24d4b9b85df9a558c3 Mon Sep 17 00:00:00 2001
From: Syping <schiedelrafael@keppe.org>
Date: Thu, 8 Jul 2021 02:57:49 +0200
Subject: [PATCH 01/10] envMode now finally working

---
 main.cpp | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/main.cpp b/main.cpp
index 1baf24b..d35eef6 100644
--- a/main.cpp
+++ b/main.cpp
@@ -135,7 +135,7 @@ int main(int argc, char *argv[])
 {
     QCoreApplication a(argc, argv);
     a.setApplicationName("Server Manager Subprocess");
-    a.setApplicationVersion("0.5");
+    a.setApplicationVersion("0.5.1");
 
 #ifdef Q_OS_UNIX
     catchUnixSignals({SIGINT, SIGHUP, SIGQUIT, SIGTERM});
@@ -164,6 +164,7 @@ int main(int argc, char *argv[])
     if (unlikely(envEnvironmentMode == "1" || envEnvironmentMode.toLower() == "true")) {
         if (likely(envExecutable.isEmpty() && envArguments.isEmpty())) {
             QStringList arguments = a.arguments();
+            arguments.removeFirst();
             executable = arguments.takeFirst();
             argumentList = arguments;
         }
@@ -227,13 +228,14 @@ int main(int argc, char *argv[])
 
         if (unlikely(!envRemotePort.isEmpty())) {
             bool ok;
-            rport = envRemotePort.toUShort(&ok);
-            if (!ok) {
-                QTextStream(stderr) << "WebSockets port is not valid in environment!" << smsub_endl;
-                return 1;
+            const quint16 _rport = envRemotePort.toUShort(&ok);
+            if (ok) {
+                rport = _rport;
+                rportSet = true;
             }
             else {
-                rportSet = true;
+                QTextStream(stderr) << "WebSockets port is not valid in environment!" << smsub_endl;
+                return 1;
             }
         }
     }
@@ -448,24 +450,26 @@ int main(int argc, char *argv[])
 
         if (unlikely(commandLineParser.isSet(subprocessRemotePort))) {
             bool ok;
-            rport = commandLineParser.value(subprocessRemotePort).toUShort(&ok);
-            if (!ok) {
-                QTextStream(stderr) << "WebSockets port is not valid in arguments!" << smsub_endl;
-                return 1;
+            const quint16 _rport = commandLineParser.value(subprocessRemotePort).toUShort(&ok);
+            if (ok) {
+                rport = _rport;
+                rportSet = true;
             }
             else {
-                rportSet = true;
+                QTextStream(stderr) << "WebSockets port is not valid in arguments!" << smsub_endl;
+                return 1;
             }
         }
         else if (!envRemotePort.isEmpty()) {
             bool ok;
-            rport = envRemotePort.toUShort(&ok);
-            if (!ok) {
-                QTextStream(stderr) << "WebSockets port is not valid in environment!" << smsub_endl;
-                return 1;
+            const quint16 _rport = envRemotePort.toUShort(&ok);
+            if (ok) {
+                rport = _rport;
+                rportSet = true;
             }
             else {
-                rportSet = true;
+                QTextStream(stderr) << "WebSockets port is not valid in arguments!" << smsub_endl;
+                return 1;
             }
         }
     }

From 529a4a8be9a8a3403b8bcb2e1689012a9a43ed10 Mon Sep 17 00:00:00 2001
From: Syping <syping@syping.de>
Date: Mon, 20 Mar 2023 08:28:37 +0100
Subject: [PATCH 02/10] improve debugging, fix likely mess

---
 SMSubProcess.cpp |  20 ++++++++-
 SMSubProcess.h   |   2 +-
 SMSubServer.cpp  |  40 +++++++++++------
 SMSubServer.h    |   2 +-
 main.cpp         | 109 ++++++++++++++++++++++++-----------------------
 smsub.h          |  20 +--------
 6 files changed, 105 insertions(+), 88 deletions(-)

diff --git a/SMSubProcess.cpp b/SMSubProcess.cpp
index 9a67656..7ee45cc 100644
--- a/SMSubProcess.cpp
+++ b/SMSubProcess.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 * smsub Server Manager Subprocess
-* Copyright (C) 2020-2021 Syping
+* Copyright (C) 2020-2023 Syping
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
@@ -30,13 +30,20 @@ SMSubProcess::SMSubProcess(const QString &executable, const QStringList &argumen
     process.setArguments(arguments);
     process.setWorkingDirectory(workingDirectory);
 
+    // manage input channel
+    process.setInputChannelMode(QProcess::ManagedInputChannel);
+
     // stdout and stderr in same IO stream
     process.setProcessChannelMode(QProcess::MergedChannels);
 
     // Connect process signal handlers
     QObject::connect(&process, &QProcess::readyRead, this, &SMSubProcess::readyRead);
     QObject::connect(&process, &QProcess::errorOccurred, this, &SMSubProcess::processError);
+    QObject::connect(&process, &QProcess::started, this, [=]() {
+        QTextStream(stderr) << "Subprocess started!" << smsub_endl;
+    });
     QObject::connect(&process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [=](int exitCode) {
+        QTextStream(stderr) << "Subprocess exited!" << smsub_endl;
         // Exit with the same exit code as the process
         emit processStopped();
         QCoreApplication::exit(exitCode);
@@ -50,8 +57,14 @@ void SMSubProcess::start()
 
 void SMSubProcess::readyRead()
 {
+#ifdef SMSUB_IODEBUG
+    QTextStream(stderr) << "Subprocess I/O RR!" << smsub_endl;
+#endif
     // Read process output and emit event
     while (process.canReadLine()) {
+#ifdef SMSUB_IODEBUG
+        QTextStream(stderr) << "Subprocess I/O WL!" << smsub_endl;
+#endif
         const QByteArray readData = process.readLine().trimmed();
         emit outputWritten(readData + '\n');
     }
@@ -60,7 +73,7 @@ void SMSubProcess::readyRead()
 void SMSubProcess::processError(QProcess::ProcessError error)
 {
     // Handle process errors
-    if (likely(error == QProcess::FailedToStart)) {
+    if (Q_LIKELY(error == QProcess::FailedToStart)) {
         QTextStream(stderr) << "Process failed to start!" << smsub_endl;
         QCoreApplication::exit(1);
     }
@@ -99,6 +112,9 @@ void SMSubProcess::stopProcess()
 
 void SMSubProcess::writeInput(const QByteArray &input)
 {
+#ifdef SMSUB_IODEBUG
+    QTextStream(stderr) << "Subprocess I/O IN!" << smsub_endl;
+#endif
     // Write input from Unix/IPC socket to process
     process.write(input);
 }
diff --git a/SMSubProcess.h b/SMSubProcess.h
index dedd81c..5f36a0f 100644
--- a/SMSubProcess.h
+++ b/SMSubProcess.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 * smsub Server Manager Subprocess
-* Copyright (C) 2020-2021 Syping
+* Copyright (C) 2020-2023 Syping
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
diff --git a/SMSubServer.cpp b/SMSubServer.cpp
index 962829a..dd92038 100644
--- a/SMSubServer.cpp
+++ b/SMSubServer.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 * smsub Server Manager Subprocess
-* Copyright (C) 2020-2021 Syping
+* Copyright (C) 2020-2023 Syping
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
@@ -47,7 +47,7 @@ SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &ser
 
 bool SMSubServer::isListening()
 {
-    if (likely(type == ServerType::Local)) {
+    if (Q_LIKELY(type == ServerType::Local)) {
         return static_cast<QLocalServer*>(server)->isListening();
     }
     else if (type == ServerType::WebSocket) {
@@ -59,12 +59,13 @@ bool SMSubServer::isListening()
 void SMSubServer::newConnection()
 {
     QObject *socket;
-    if (likely(type == ServerType::Local)) {
+    if (Q_LIKELY(type == ServerType::Local)) {
         QLocalSocket *localSocket = static_cast<QLocalServer*>(server)->nextPendingConnection();
         QObject::connect(localSocket, &QLocalSocket::readyRead, this, &SMSubServer::lsReadyRead);
         QObject::connect(localSocket, &QLocalSocket::disconnected, this, &SMSubServer::deleteSocket);
         localSocket->write(QString("SMSub Version %1\n").arg(QCoreApplication::applicationVersion()).toUtf8());
         socket = localSocket;
+        QTextStream(stderr) << "LocalSocket connected!" << smsub_endl;
     }
     else if (type == ServerType::WebSocket) {
         QWebSocket *webSocket = static_cast<QWebSocketServer*>(server)->nextPendingConnection();
@@ -72,6 +73,7 @@ void SMSubServer::newConnection()
         QObject::connect(webSocket, &QWebSocket::disconnected, this, &SMSubServer::deleteSocket);
         webSocket->sendBinaryMessage(QString("SMSub Version %1\n").arg(QCoreApplication::applicationVersion()).toUtf8());
         socket = webSocket;
+        QTextStream(stderr) << QString("WebSocket %1:%2 connected!").arg(webSocket->peerName(), QString::number(webSocket->peerPort())) << smsub_endl;
     }
     else {
         // Just for being sure
@@ -92,7 +94,7 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
 {
     // Only allow commands being sent if authenticated
     const bool isAuthenticated = socket->property("Authenticated").toBool();
-    if (likely(isAuthenticated)) {
+    if (Q_LIKELY(isAuthenticated)) {
         if (message.startsWith("+dbg")) {
             socket->setProperty("ReceiveDbgMsg", true);
             sendMessage(socket, "Debug messages enabled!\n");
@@ -110,7 +112,7 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
             debugOutput(socket, "Log output disabled!");
         }
         else if (message.startsWith("+reg")) {
-            if (likely(serverSettings->canRegister)) {
+            if (Q_LIKELY(serverSettings->canRegister)) {
                 QByteArray authUuid = QUuid::createUuid().toByteArray(QUuid::Id128);
                 authUuid = QByteArray::fromHex(authUuid).toBase64(QByteArray::OmitTrailingEquals);
                 emit tokenRegistered(QString::fromUtf8(authUuid));
@@ -141,7 +143,7 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
     }
     else {
         // Authenticate when token is valid, otherwise disconnect
-        if (unlikely(tokens.contains(QString::fromUtf8(message)))) {
+        if (Q_UNLIKELY(tokens.contains(QString::fromUtf8(message)))) {
             // Set client as authenticated and add it to vector
             socket->setProperty("Authenticated", true);
             sendMessage(socket, "Login successful!\n");
@@ -149,7 +151,7 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
         }
         else {
             // Stop receiving data and disconnect socket
-            if (likely(type == ServerType::Local)) {
+            if (Q_LIKELY(type == ServerType::Local)) {
                 QLocalSocket *localSocket = static_cast<QLocalSocket*>(socket);
                 QObject::disconnect(localSocket, &QLocalSocket::readyRead, this, &SMSubServer::lsReadyRead);
                 localSocket->write("Incorrect token!\n");
@@ -177,7 +179,13 @@ void SMSubServer::wsMessageReceived(const QByteArray &message)
 void SMSubServer::lsReadyRead()
 {
     QLocalSocket *socket = static_cast<QLocalSocket*>(sender());
+#ifdef SMSUB_IODEBUG
+    QTextStream(stderr) << "LocalSocket I/O RR!" << smsub_endl;
+#endif
     while (socket->canReadLine()) {
+#ifdef SMSUB_IODEBUG
+        QTextStream(stderr) << "LocalSocket I/O WL!" << smsub_endl;
+#endif
         const QByteArray message = socket->readLine().trimmed();
         if (!messageReceived(socket, message))
             return;
@@ -196,9 +204,13 @@ void SMSubServer::debugOutput(QObject *socket, const QByteArray &message)
 {
     // Only send debug messages when the client opted-in
     const QVariant variant = socket->property("ReceiveDbgMsg");
-    if (unlikely(variant.type() == QVariant::Bool)) {
+#if QT_VERSION >= 0x060000
+    if (Q_UNLIKELY(variant.typeId() == QMetaType::Bool)) {
+#else
+    if (Q_UNLIKELY(variant.type() == QVariant::Bool)) {
+#endif
         bool receiveDbgMsg = variant.toBool();
-        if (likely(receiveDbgMsg)) {
+        if (Q_LIKELY(receiveDbgMsg)) {
             sendMessage(socket, message + '\n');
         }
     }
@@ -209,9 +221,13 @@ void SMSubServer::writeOutput(const QByteArray &output)
     // Read process output when client opted-in for log
     for (auto it = sockets.constBegin(); it != sockets.constEnd(); it++) {
         const QVariant variant = (*it)->property("ReceiveLog");
-        if (unlikely(variant.type() == QVariant::Bool)) {
+#if QT_VERSION >= 0x060000
+        if (Q_UNLIKELY(variant.typeId() == QMetaType::Bool)) {
+#else
+        if (Q_UNLIKELY(variant.type() == QVariant::Bool)) {
+#endif
             bool receiveLog = variant.toBool();
-            if (likely(receiveLog)) {
+            if (Q_LIKELY(receiveLog)) {
                 sendMessage(*it, output);
             }
         }
@@ -220,7 +236,7 @@ void SMSubServer::writeOutput(const QByteArray &output)
 
 void SMSubServer::sendMessage(QObject *socket, const QByteArray &message)
 {
-    if (likely(type == ServerType::Local)) {
+    if (Q_LIKELY(type == ServerType::Local)) {
         QLocalSocket *localSocket = static_cast<QLocalSocket*>(socket);
         localSocket->write(message);
     }
diff --git a/SMSubServer.h b/SMSubServer.h
index f5f9936..29de80a 100644
--- a/SMSubServer.h
+++ b/SMSubServer.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 * smsub Server Manager Subprocess
-* Copyright (C) 2020-2021 Syping
+* Copyright (C) 2020-2023 Syping
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
diff --git a/main.cpp b/main.cpp
index d35eef6..8575ff7 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 * smsub Server Manager Subprocess
-* Copyright (C) 2020-2021 Syping
+* Copyright (C) 2020-2023 Syping
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
@@ -33,7 +33,6 @@
 #ifdef Q_OS_UNIX
 #include <initializer_list>
 #include "signal.h"
-#include "unistd.h"
 #endif
 
 #ifdef Q_OS_UNIX
@@ -135,7 +134,7 @@ int main(int argc, char *argv[])
 {
     QCoreApplication a(argc, argv);
     a.setApplicationName("Server Manager Subprocess");
-    a.setApplicationVersion("0.5.1");
+    a.setApplicationVersion("0.6");
 
 #ifdef Q_OS_UNIX
     catchUnixSignals({SIGINT, SIGHUP, SIGQUIT, SIGTERM});
@@ -151,25 +150,25 @@ int main(int argc, char *argv[])
     QString workingDirectory;
     QStringList argumentList;
 
-    QByteArray envEnvironmentMode = qgetenv("SMSUB_ENVIRONMENT_MODE");
-    QByteArray envManifest = qgetenv("SMSUB_JSON");
-    QByteArray envExecutable = qgetenv("SMSUB_EXEC");
-    QByteArray envArguments = qgetenv("SMSUB_ARGS");
-    QByteArray envSocket = qgetenv("SMSUB_SOCK");
-    QByteArray envRemotePort = qgetenv("SMSUB_RPORT");
-    QByteArray envRemoteSocket = qgetenv("SMSUB_RSOCK");
-    QByteArray envTimeout = qgetenv("SMSUB_TIMEOUT");
-    QByteArray envWorkDir = qgetenv("SMSUB_WORKDIR");
+    const QByteArray envEnvironmentMode = qgetenv("SMSUB_ENVIRONMENT_MODE");
+    const QByteArray envManifest = qgetenv("SMSUB_JSON");
+    const QByteArray envExecutable = qgetenv("SMSUB_EXEC");
+    const QByteArray envArguments = qgetenv("SMSUB_ARGS");
+    const QByteArray envSocket = qgetenv("SMSUB_SOCK");
+    const QByteArray envRemotePort = qgetenv("SMSUB_RPORT");
+    const QByteArray envRemoteSocket = qgetenv("SMSUB_RSOCK");
+    const QByteArray envTimeout = qgetenv("SMSUB_TIMEOUT");
+    const QByteArray envWorkDir = qgetenv("SMSUB_WORKDIR");
 
-    if (unlikely(envEnvironmentMode == "1" || envEnvironmentMode.toLower() == "true")) {
-        if (likely(envExecutable.isEmpty() && envArguments.isEmpty())) {
+    if (envEnvironmentMode == "1" || envEnvironmentMode.toLower() == "true") {
+        if (envExecutable.isEmpty() && envArguments.isEmpty()) {
             QStringList arguments = a.arguments();
             arguments.removeFirst();
             executable = arguments.takeFirst();
             argumentList = arguments;
         }
         else {
-            if (likely(!envExecutable.isEmpty())) {
+            if (!envExecutable.isEmpty()) {
                 executable = QString::fromUtf8(envExecutable);
             }
             else {
@@ -177,7 +176,7 @@ int main(int argc, char *argv[])
                 return 1;
             }
 
-            if (likely(!envArguments.isEmpty())) {
+            if (!envArguments.isEmpty()) {
                 argumentList = parseStringArguments(QString::fromUtf8(envArguments));
                 if (argumentList.empty()) {
                     QTextStream(stderr) << "Arguments can't be parsed properly!" << smsub_endl;
@@ -190,7 +189,7 @@ int main(int argc, char *argv[])
             }
         }
 
-        if (unlikely(!envTimeout.isEmpty())) {
+        if (!envTimeout.isEmpty()) {
             bool ok;
             const int _termTimeout = envTimeout.toInt(&ok);
             if (ok) {
@@ -203,14 +202,14 @@ int main(int argc, char *argv[])
             }
         }
 
-        if (unlikely(!envWorkDir.isEmpty())) {
+        if (!envWorkDir.isEmpty()) {
             workingDirectory = QString::fromUtf8(envWorkDir);
         }
         else {
             workingDirectory = QFileInfo(executable).absolutePath();
         }
 
-        if (likely(!envSocket.isEmpty())) {
+        if (!envSocket.isEmpty()) {
             socket = QString::fromUtf8(envSocket);
         }
         else {
@@ -222,11 +221,11 @@ int main(int argc, char *argv[])
             return 1;
         }
 
-        if (unlikely(!envRemoteSocket.isEmpty())) {
+        if (!envRemoteSocket.isEmpty()) {
             rsocket = QString::fromUtf8(envRemoteSocket);
         }
 
-        if (unlikely(!envRemotePort.isEmpty())) {
+        if (!envRemotePort.isEmpty()) {
             bool ok;
             const quint16 _rport = envRemotePort.toUShort(&ok);
             if (ok) {
@@ -275,26 +274,26 @@ int main(int argc, char *argv[])
 
         commandLineParser.process(a);
 
-        if (unlikely(commandLineParser.isSet(processManifest) && commandLineParser.isSet(processExecutable) ||
+        if (commandLineParser.isSet(processManifest) && commandLineParser.isSet(processExecutable) ||
                      !envManifest.isEmpty() && !envExecutable.isEmpty() ||
                      commandLineParser.isSet(processManifest) && !envExecutable.isEmpty() ||
-                     !envManifest.isEmpty() && commandLineParser.isSet(processExecutable))) {
+                     !envManifest.isEmpty() && commandLineParser.isSet(processExecutable)) {
             QTextStream(stderr) << "You can't define a Process executable and a JSON process manifest at the same time!" << smsub_endl;
             return 1;
         }
 
-        if (unlikely(commandLineParser.isSet(processManifest) && commandLineParser.isSet(processArguments) ||
+        if (commandLineParser.isSet(processManifest) && commandLineParser.isSet(processArguments) ||
                      !envManifest.isEmpty() && !envArguments.isEmpty() ||
                      commandLineParser.isSet(processManifest) && !envArguments.isEmpty() ||
-                     !envManifest.isEmpty() && commandLineParser.isSet(processArguments))) {
+                     !envManifest.isEmpty() && commandLineParser.isSet(processArguments)) {
             QTextStream(stderr) << "You can't define a Process arguments and a JSON process manifest at the same time!" << smsub_endl;
             return 1;
         }
 
-        if (unlikely(commandLineParser.isSet(subprocessRemotePort) && commandLineParser.isSet(subprocessRemoteSocket) ||
+        if (commandLineParser.isSet(subprocessRemotePort) && commandLineParser.isSet(subprocessRemoteSocket) ||
                      !envRemotePort.isEmpty() && !envRemoteSocket.isEmpty() ||
                      commandLineParser.isSet(subprocessRemotePort) && !envRemoteSocket.isEmpty() ||
-                     !envRemotePort.isEmpty() && commandLineParser.isSet(subprocessRemoteSocket))) {
+                     !envRemotePort.isEmpty() && commandLineParser.isSet(subprocessRemoteSocket)) {
 #ifdef Q_OS_WIN
             QTextStream(stderr) << "You can't define a WebSockets port and a IPC socket at same time!" << smsub_endl;
 #else
@@ -303,7 +302,7 @@ int main(int argc, char *argv[])
             return 1;
         }
 
-        if (unlikely(commandLineParser.isSet(processTimeout))) {
+        if (commandLineParser.isSet(processTimeout)) {
             bool ok;
             const int _termTimeout = commandLineParser.value(processTimeout).toInt(&ok);
             if (ok) {
@@ -315,7 +314,7 @@ int main(int argc, char *argv[])
                 return 1;
             }
         }
-        else if (unlikely(!envTimeout.isEmpty())) {
+        else if (!envTimeout.isEmpty()) {
             bool ok;
             const int _termTimeout = envTimeout.toInt(&ok);
             if (ok) {
@@ -328,14 +327,14 @@ int main(int argc, char *argv[])
             }
         }
 
-        if (unlikely(commandLineParser.isSet(processExecutable))) {
+        if (commandLineParser.isSet(processExecutable)) {
             executable = commandLineParser.value(processExecutable);
         }
-        else if (unlikely(!envExecutable.isEmpty())) {
+        else if (!envExecutable.isEmpty()) {
             executable = QString::fromUtf8(envExecutable);
         }
 
-        if (unlikely(!envWorkDir.isEmpty())) {
+        if (!envWorkDir.isEmpty()) {
             workingDirectory = QString::fromUtf8(envWorkDir);
         }
         else {
@@ -343,23 +342,23 @@ int main(int argc, char *argv[])
         }
 
         QString manifestPath;
-        if (likely(commandLineParser.isSet(processManifest))) {
+        if (commandLineParser.isSet(processManifest)) {
             manifestPath = commandLineParser.value(processManifest);
         }
         else if (!envManifest.isEmpty()) {
             manifestPath = QString::fromUtf8(envManifest);
         }
 
-        if (likely(!manifestPath.isEmpty())) {
+        if (!manifestPath.isEmpty()) {
             QFile manifestFile(manifestPath);
-            if (likely(manifestFile.open(QIODevice::ReadOnly))) {
+            if (manifestFile.open(QIODevice::ReadOnly)) {
                 const QByteArray jsonData = manifestFile.readAll();
                 QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonData);
                 QJsonObject jsonObject = jsonDocument.object();
 
-                if (likely(jsonObject.contains("Executable"))) {
+                if (jsonObject.contains("Executable")) {
                     const QJsonValue jsonExecutable = jsonObject.value("Executable");
-                    if (unlikely(!jsonExecutable.isString())) {
+                    if (!jsonExecutable.isString()) {
                         QTextStream(stderr) << "Executable is not a string in manifest, aborting!" << smsub_endl;
                         manifestFile.close();
                         return 1;
@@ -372,9 +371,9 @@ int main(int argc, char *argv[])
                     return 1;
                 }
 
-                if (likely(jsonObject.contains("WorkingDirectory"))) {
+                if (jsonObject.contains("WorkingDirectory")) {
                     const QJsonValue jsonWorkingDirectory = jsonObject.value("WorkingDirectory");
-                    if (unlikely(!jsonWorkingDirectory.isString())) {
+                    if (!jsonWorkingDirectory.isString()) {
                         QTextStream(stderr) << "Working Directory is not a string in manifest, aborting!" << smsub_endl;
                         manifestFile.close();
                         return 1;
@@ -382,9 +381,9 @@ int main(int argc, char *argv[])
                     workingDirectory = jsonWorkingDirectory.toString();
                 }
 
-                if (likely(jsonObject.contains("Arguments"))) {
+                if (jsonObject.contains("Arguments")) {
                     const QJsonValue jsonArguments = jsonObject.value("Arguments");
-                    if (likely(jsonArguments.isArray())) {
+                    if (jsonArguments.isArray()) {
                         const QJsonArray jsonArray = jsonArguments.toArray();
                         for (auto it = jsonArray.constBegin(); it != jsonArray.constEnd(); it++) {
                             argumentList << it->toString();
@@ -397,9 +396,9 @@ int main(int argc, char *argv[])
                     }
                 }
 
-                if (unlikely(!timeoutSet && jsonObject.contains("TerminationTimeout"))) {
+                if (!timeoutSet && jsonObject.contains("TerminationTimeout")) {
                     const QJsonValue jsonTimeout = jsonObject.value("TerminationTimeout");
-                    if (unlikely(!jsonTimeout.isDouble())) {
+                    if (!jsonTimeout.isDouble()) {
                         termTimeout = qRound(jsonTimeout.toDouble());
                     }
                     else {
@@ -411,14 +410,14 @@ int main(int argc, char *argv[])
                 manifestFile.close();
             }
         }
-        else if (unlikely(commandLineParser.isSet(processArguments))) {
+        else if (commandLineParser.isSet(processArguments)) {
             argumentList = parseStringArguments(commandLineParser.value(processArguments));
             if (argumentList.empty()) {
                 QTextStream(stderr) << "Arguments can't be parsed properly!" << smsub_endl;
                 return 1;
             }
         }
-        else if (unlikely(!envArguments.isEmpty())) {
+        else if (!envArguments.isEmpty()) {
             argumentList = parseStringArguments(QString::fromUtf8(envArguments));
             if (argumentList.empty()) {
                 QTextStream(stderr) << "Arguments can't be parsed properly!" << smsub_endl;
@@ -426,7 +425,7 @@ int main(int argc, char *argv[])
             }
         }
 
-        if (likely(commandLineParser.isSet(subprocessSocket))) {
+        if (commandLineParser.isSet(subprocessSocket)) {
             socket = commandLineParser.value(subprocessSocket);
         }
         else if (!envSocket.isEmpty()) {
@@ -441,14 +440,14 @@ int main(int argc, char *argv[])
             return 1;
         }
 
-        if (unlikely(commandLineParser.isSet(subprocessRemoteSocket))) {
+        if (commandLineParser.isSet(subprocessRemoteSocket)) {
             rsocket = commandLineParser.value(subprocessRemoteSocket);
         }
-        else if (unlikely(!envRemoteSocket.isEmpty())) {
+        else if (!envRemoteSocket.isEmpty()) {
             rsocket = QString::fromUtf8(envRemoteSocket);
         }
 
-        if (unlikely(commandLineParser.isSet(subprocessRemotePort))) {
+        if (commandLineParser.isSet(subprocessRemotePort)) {
             bool ok;
             const quint16 _rport = commandLineParser.value(subprocessRemotePort).toUShort(&ok);
             if (ok) {
@@ -478,7 +477,7 @@ int main(int argc, char *argv[])
     localSettings.isLocal = true;
 
     SMSubServer subLocal(&localSettings, socket);
-    if (unlikely(!subLocal.isListening())) {
+    if (!subLocal.isListening()) {
 #ifdef Q_OS_WIN
         QTextStream(stderr) << "Failed to start local IPC socket!" << smsub_endl;
 #else
@@ -493,9 +492,9 @@ int main(int argc, char *argv[])
     remoteSettings.canRegister = false;
     remoteSettings.isLocal = false;
 
-    if (unlikely(!rsocket.isEmpty())) {
+    if (!rsocket.isEmpty()) {
         SMSubServer *subRemote = new SMSubServer(&remoteSettings, rsocket);
-        if (unlikely(!subRemote->isListening())) {
+        if (!subRemote->isListening()) {
 #ifdef Q_OS_WIN
             QTextStream(stderr) << "Failed to start remote IPC socket!" << smsub_endl;
 #else
@@ -510,9 +509,9 @@ int main(int argc, char *argv[])
         QObject::connect(subRemote, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess);
         QObject::connect(subRemote, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess);
     }
-    else if (unlikely(rportSet)) {
+    else if (rportSet) {
         SMSubServer *subRemote = new SMSubServer(&remoteSettings, QString(), rport);
-        if (unlikely(!subRemote->isListening())) {
+        if (!subRemote->isListening()) {
             QTextStream(stderr) << "Failed to start remote WebSockets server!" << smsub_endl;
             return 1;
         }
@@ -535,5 +534,7 @@ int main(int argc, char *argv[])
 
     subProcess.start();
 
+    QTextStream(stderr) << QString("SMSub Version %1 initialized!").arg(QCoreApplication::applicationVersion()) << smsub_endl;
+
     return a.exec();
 }
diff --git a/smsub.h b/smsub.h
index d05e8bc..9b93a6b 100644
--- a/smsub.h
+++ b/smsub.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 * smsub Server Manager Subprocess
-* Copyright (C) 2020-2021 Syping
+* Copyright (C) 2020-2023 Syping
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
@@ -20,23 +20,7 @@
 #define SMSUB_H
 #include <QtGlobal>
 
-#ifndef SMSUB_WITHOUT_EXPECT
-#ifndef likely
-#define likely(x)       __builtin_expect((x),1)
-#endif
-#ifndef unlikely
-#define unlikely(x)     __builtin_expect((x),0)
-#endif
-#else
-#ifndef likely
-#define likely(x)       (x)
-#endif
-#ifndef unlikely
-#define unlikely(x)     (x)
-#endif
-#endif
-
-#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
+#if QT_VERSION >= 0x050F00
 #define smsub_endl Qt::endl
 #else
 #define smsub_endl endl

From 95db23458ff7af8cb376e1979fb3154d404fd9e7 Mon Sep 17 00:00:00 2001
From: Syping <schiedelrafael@keppe.org>
Date: Wed, 9 Aug 2023 20:58:21 +0200
Subject: [PATCH 03/10] add KeepAlive, Status and Buffered Reads

---
 CMakeLists.txt   |  2 +-
 SMSubProcess.cpp | 52 ++++++++++++++++++++++++++++++------------------
 SMSubProcess.h   | 10 +++++-----
 SMSubServer.cpp  | 29 ++++++++++++++++++++++++---
 SMSubServer.h    |  5 ++++-
 main.cpp         | 44 +++++++++++++++++++++++++++++++++-------
 6 files changed, 106 insertions(+), 36 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index c83979b..d25973c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-project(smsub LANGUAGES CXX)
+project(smsub LANGUAGES CXX VERSION 0.7)
 
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
diff --git a/SMSubProcess.cpp b/SMSubProcess.cpp
index 7ee45cc..14ef091 100644
--- a/SMSubProcess.cpp
+++ b/SMSubProcess.cpp
@@ -22,8 +22,8 @@
 #include "smsub.h"
 #include <QDebug>
 
-SMSubProcess::SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int &termTimeout) :
-    termTimeout(termTimeout)
+SMSubProcess::SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int &termTimeout, const bool &keepAlive) :
+    termTimeout(termTimeout), keepAlive(keepAlive)
 {
     // Set process executable, arguments and working directory
     process.setProgram(executable);
@@ -41,26 +41,31 @@ SMSubProcess::SMSubProcess(const QString &executable, const QStringList &argumen
     QObject::connect(&process, &QProcess::errorOccurred, this, &SMSubProcess::processError);
     QObject::connect(&process, &QProcess::started, this, [=]() {
         QTextStream(stderr) << "Subprocess started!" << smsub_endl;
+        emit statusUpdated(true);
     });
     QObject::connect(&process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [=](int exitCode) {
         QTextStream(stderr) << "Subprocess exited!" << smsub_endl;
         // Exit with the same exit code as the process
-        emit processStopped();
-        QCoreApplication::exit(exitCode);
+        emit statusUpdated(false);
+        if (!keepAlive)
+            QCoreApplication::exit(exitCode);
     });
 }
 
-void SMSubProcess::start()
-{
-    process.start(QIODevice::ReadWrite);
-}
-
 void SMSubProcess::readyRead()
 {
 #ifdef SMSUB_IODEBUG
     QTextStream(stderr) << "Subprocess I/O RR!" << smsub_endl;
 #endif
     // Read process output and emit event
+#ifdef SMSUB_BUFFERED_READS
+#ifdef SMSUB_IODEBUG
+    QTextStream(stderr) << "Subprocess I/O W!" << smsub_endl;
+#endif
+    const QByteArray readData = process.read(1024);
+    if (!readData.isEmpty())
+        emit outputWritten(readData);
+#else
     while (process.canReadLine()) {
 #ifdef SMSUB_IODEBUG
         QTextStream(stderr) << "Subprocess I/O WL!" << smsub_endl;
@@ -68,6 +73,7 @@ void SMSubProcess::readyRead()
         const QByteArray readData = process.readLine().trimmed();
         emit outputWritten(readData + '\n');
     }
+#endif
 }
 
 void SMSubProcess::processError(QProcess::ProcessError error)
@@ -75,11 +81,13 @@ void SMSubProcess::processError(QProcess::ProcessError error)
     // Handle process errors
     if (Q_LIKELY(error == QProcess::FailedToStart)) {
         QTextStream(stderr) << "Process failed to start!" << smsub_endl;
-        QCoreApplication::exit(1);
+        if (!keepAlive)
+            QCoreApplication::exit(1);
     }
     else if (error == QProcess::UnknownError) {
         QTextStream(stderr) << "Unknown error occurred!" << smsub_endl;
-        QCoreApplication::exit(1);
+        if (!keepAlive)
+            QCoreApplication::exit(1);
     }
 }
 
@@ -94,20 +102,25 @@ void SMSubProcess::aboutToQuit()
     }
 }
 
-void SMSubProcess::killProcess()
+void SMSubProcess::startProcess()
 {
-    // Kill process as requested
-    if (process.state() == QProcess::Running) {
-        process.kill();
-    }
+    // Start process as requested
+    if (process.state() == QProcess::NotRunning)
+        process.start(QIODevice::ReadWrite);
 }
 
 void SMSubProcess::stopProcess()
 {
     // Terminate process as requested
-    if (process.state() == QProcess::Running) {
+    if (process.state() == QProcess::Running)
         process.terminate();
-    }
+}
+
+void SMSubProcess::killProcess()
+{
+    // Kill process as requested
+    if (process.state() == QProcess::Running)
+        process.kill();
 }
 
 void SMSubProcess::writeInput(const QByteArray &input)
@@ -116,5 +129,6 @@ void SMSubProcess::writeInput(const QByteArray &input)
     QTextStream(stderr) << "Subprocess I/O IN!" << smsub_endl;
 #endif
     // Write input from Unix/IPC socket to process
-    process.write(input);
+    if (process.state() == QProcess::Running)
+        process.write(input);
 }
diff --git a/SMSubProcess.h b/SMSubProcess.h
index 5f36a0f..cd2dddc 100644
--- a/SMSubProcess.h
+++ b/SMSubProcess.h
@@ -26,17 +26,18 @@ class SMSubProcess : public QObject
 {
     Q_OBJECT
 public:
-    SMSubProcess(const QString &executable, const QStringList &arguments, const QString& workingDirectory, const int &termTimeout = 60000);
-    void start();
+    SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int &termTimeout = 60000, const bool &keepAlive = false);
 
 private:
     QProcess process;
     int termTimeout;
+    bool keepAlive;
 
 public slots:
     void aboutToQuit();
-    void killProcess();
+    void startProcess();
     void stopProcess();
+    void killProcess();
     void writeInput(const QByteArray &input);
 
 private slots:
@@ -45,8 +46,7 @@ private slots:
 
 signals:
     void outputWritten(const QByteArray &output);
-    void processStopped();
-
+    void statusUpdated(const bool status);
 };
 
 #endif // SMSUBPROCESS_H
diff --git a/SMSubServer.cpp b/SMSubServer.cpp
index dd92038..c753b79 100644
--- a/SMSubServer.cpp
+++ b/SMSubServer.cpp
@@ -32,6 +32,7 @@ SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &soc
 
     type = ServerType::Local;
     server = localServer;
+    status = false;
 }
 
 SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &serverName, const quint16 &port) : serverSettings(serverSettings)
@@ -43,6 +44,7 @@ SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &ser
 
     type = ServerType::WebSocket;
     server = webSocketServer;
+    status = false;
 }
 
 bool SMSubServer::isListening()
@@ -122,14 +124,30 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
                 sendMessage(socket, "Permission denied!\n");
             }
         }
-        else if (message.startsWith("kill")) {
-            emit killRequested();
-            debugOutput(socket, "Killing server!");
+        else if (message.startsWith("status")) {
+            if (status) {
+                sendMessage(socket, "Status: on\n");
+            }
+            else {
+                sendMessage(socket, "Status: off\n");
+            }
+        }
+        else if (message.startsWith("start")) {
+            emit startRequested();
+            debugOutput(socket, "Starting server!");
         }
         else if (message.startsWith("stop")) {
             emit stopRequested();
             debugOutput(socket, "Stopping server!");
         }
+        else if (message.startsWith("kill")) {
+            emit killRequested();
+            debugOutput(socket, "Killing server!");
+        }
+        else if (message.startsWith("quit")) {
+            QTimer::singleShot(0, qApp, &QCoreApplication::quit);
+            debugOutput(socket, "Qutting smsub!");
+        }
         else if (message.startsWith("wl")) {
             const QByteArray writeData = message.mid(3);
             emit inputWritten(writeData + '\n');
@@ -254,3 +272,8 @@ void SMSubServer::registerToken(const QString &token)
         tokens.removeAll(token);
     });
 }
+
+void SMSubServer::statusUpdated(const bool status_)
+{
+    status = status_;
+}
diff --git a/SMSubServer.h b/SMSubServer.h
index 29de80a..daabb22 100644
--- a/SMSubServer.h
+++ b/SMSubServer.h
@@ -45,6 +45,7 @@ public:
 public slots:
     void writeOutput(const QByteArray &output);
     void registerToken(const QString &token);
+    void statusUpdated(const bool status);
 
 private slots:
     void wsMessageReceived(const QByteArray &message);
@@ -61,12 +62,14 @@ private:
     QVector<QString> tokens;
     ServerType type;
     QObject *server;
+    bool status;
 
 signals:
     void tokenRegistered(const QString &password);
     void inputWritten(const QByteArray &input);
-    void killRequested();
+    void startRequested();
     void stopRequested();
+    void killRequested();
 };
 
 #endif // SMSUBSERVER_H
diff --git a/main.cpp b/main.cpp
index 8575ff7..aebda4d 100644
--- a/main.cpp
+++ b/main.cpp
@@ -134,13 +134,14 @@ int main(int argc, char *argv[])
 {
     QCoreApplication a(argc, argv);
     a.setApplicationName("Server Manager Subprocess");
-    a.setApplicationVersion("0.6");
+    a.setApplicationVersion("0.7");
 
 #ifdef Q_OS_UNIX
     catchUnixSignals({SIGINT, SIGHUP, SIGQUIT, SIGTERM});
 #endif
 
     bool rportSet = false;
+    bool keepAlive = false;
     bool timeoutSet = false;
     int termTimeout = 60000;
     quint16 rport;
@@ -151,6 +152,7 @@ int main(int argc, char *argv[])
     QStringList argumentList;
 
     const QByteArray envEnvironmentMode = qgetenv("SMSUB_ENVIRONMENT_MODE");
+    const QByteArray envKeepAlive = qgetenv("SMSUB_KEEPALIVE");
     const QByteArray envManifest = qgetenv("SMSUB_JSON");
     const QByteArray envExecutable = qgetenv("SMSUB_EXEC");
     const QByteArray envArguments = qgetenv("SMSUB_ARGS");
@@ -160,7 +162,7 @@ int main(int argc, char *argv[])
     const QByteArray envTimeout = qgetenv("SMSUB_TIMEOUT");
     const QByteArray envWorkDir = qgetenv("SMSUB_WORKDIR");
 
-    if (envEnvironmentMode == "1" || envEnvironmentMode.toLower() == "true") {
+    if (envEnvironmentMode == "1" || envEnvironmentMode.toLower() == "true" || envEnvironmentMode.toLower() == "yes") {
         if (envExecutable.isEmpty() && envArguments.isEmpty()) {
             QStringList arguments = a.arguments();
             arguments.removeFirst();
@@ -202,6 +204,12 @@ int main(int argc, char *argv[])
             }
         }
 
+        if (!envKeepAlive.isEmpty()) {
+            if (envKeepAlive == "1" || envKeepAlive.toLower() == "true" || envKeepAlive.toLower() == "yes") {
+                keepAlive = true;
+            }
+        }
+
         if (!envWorkDir.isEmpty()) {
             workingDirectory = QString::fromUtf8(envWorkDir);
         }
@@ -334,6 +342,12 @@ int main(int argc, char *argv[])
             executable = QString::fromUtf8(envExecutable);
         }
 
+        if (!envKeepAlive.isEmpty()) {
+            if (envKeepAlive == "1" || envKeepAlive.toLower() == "true" || envKeepAlive.toLower() == "yes") {
+                keepAlive = true;
+            }
+        }
+
         if (!envWorkDir.isEmpty()) {
             workingDirectory = QString::fromUtf8(envWorkDir);
         }
@@ -371,6 +385,16 @@ int main(int argc, char *argv[])
                     return 1;
                 }
 
+                if (jsonObject.contains("KeepAlive")) {
+                    const QJsonValue jsonKeepAlive = jsonObject.value("KeepAlive");
+                    if (!jsonKeepAlive.isBool()) {
+                        QTextStream(stderr) << "KeepAlive is not a bool in manifest, aborting!" << smsub_endl;
+                        manifestFile.close();
+                        return 1;
+                    }
+                    keepAlive = jsonKeepAlive.toBool();
+                }
+
                 if (jsonObject.contains("WorkingDirectory")) {
                     const QJsonValue jsonWorkingDirectory = jsonObject.value("WorkingDirectory");
                     if (!jsonWorkingDirectory.isString()) {
@@ -486,7 +510,7 @@ int main(int argc, char *argv[])
         return 1;
     }
 
-    SMSubProcess subProcess(executable, argumentList, workingDirectory, termTimeout);
+    SMSubProcess subProcess(executable, argumentList, workingDirectory, termTimeout, keepAlive);
 
     SMSubServerSettings remoteSettings;
     remoteSettings.canRegister = false;
@@ -505,9 +529,11 @@ int main(int argc, char *argv[])
         localSettings.canRegister = true;
         QObject::connect(&subLocal, &SMSubServer::tokenRegistered, subRemote, &SMSubServer::registerToken);
         QObject::connect(&subProcess, &SMSubProcess::outputWritten, subRemote, &SMSubServer::writeOutput);
+        QObject::connect(&subProcess, &SMSubProcess::statusUpdated, subRemote, &SMSubServer::statusUpdated);
         QObject::connect(subRemote, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput);
-        QObject::connect(subRemote, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess);
+        QObject::connect(subRemote, &SMSubServer::startRequested, &subProcess, &SMSubProcess::startProcess);
         QObject::connect(subRemote, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess);
+        QObject::connect(subRemote, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess);
     }
     else if (rportSet) {
         SMSubServer *subRemote = new SMSubServer(&remoteSettings, QString(), rport);
@@ -518,21 +544,25 @@ int main(int argc, char *argv[])
         localSettings.canRegister = true;
         QObject::connect(&subLocal, &SMSubServer::tokenRegistered, subRemote, &SMSubServer::registerToken);
         QObject::connect(&subProcess, &SMSubProcess::outputWritten, subRemote, &SMSubServer::writeOutput);
+        QObject::connect(&subProcess, &SMSubProcess::statusUpdated, subRemote, &SMSubServer::statusUpdated);
         QObject::connect(subRemote, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput);
-        QObject::connect(subRemote, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess);
+        QObject::connect(subRemote, &SMSubServer::startRequested, &subProcess, &SMSubProcess::startProcess);
         QObject::connect(subRemote, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess);
+        QObject::connect(subRemote, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess);
     }
     else {
         localSettings.canRegister = false;
     }
 
     QObject::connect(&subProcess, &SMSubProcess::outputWritten, &subLocal, &SMSubServer::writeOutput);
+    QObject::connect(&subProcess, &SMSubProcess::statusUpdated, &subLocal, &SMSubServer::statusUpdated);
     QObject::connect(&subLocal, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput);
-    QObject::connect(&subLocal, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess);
+    QObject::connect(&subLocal, &SMSubServer::startRequested, &subProcess, &SMSubProcess::startProcess);
     QObject::connect(&subLocal, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess);
+    QObject::connect(&subLocal, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess);
     QObject::connect(&a, &QCoreApplication::aboutToQuit, &subProcess, &SMSubProcess::aboutToQuit);
 
-    subProcess.start();
+    subProcess.startProcess();
 
     QTextStream(stderr) << QString("SMSub Version %1 initialized!").arg(QCoreApplication::applicationVersion()) << smsub_endl;
 

From d37369ad4f989102a08f5986cf6115313497ad35 Mon Sep 17 00:00:00 2001
From: Syping <schiedelrafael@keppe.org>
Date: Thu, 25 Apr 2024 23:11:46 +0200
Subject: [PATCH 04/10] add AutoStart option, Last Start and Last Stop

---
 CMakeLists.txt   |  2 +-
 SMSubProcess.cpp |  8 ++++----
 SMSubProcess.h   |  4 ++--
 SMSubServer.cpp  | 13 +++++++++----
 SMSubServer.h    |  6 ++++--
 main.cpp         | 31 ++++++++++++++++++++++++++++---
 6 files changed, 48 insertions(+), 16 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index d25973c..bf8df83 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-project(smsub LANGUAGES CXX VERSION 0.7)
+project(smsub LANGUAGES CXX VERSION 0.8)
 
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
diff --git a/SMSubProcess.cpp b/SMSubProcess.cpp
index 14ef091..e9016c6 100644
--- a/SMSubProcess.cpp
+++ b/SMSubProcess.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 * smsub Server Manager Subprocess
-* Copyright (C) 2020-2023 Syping
+* Copyright (C) 2020-2024 Syping
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
@@ -18,9 +18,9 @@
 
 #include <QCoreApplication>
 #include <QTextStream>
+#include <QDateTime>
 #include "SMSubProcess.h"
 #include "smsub.h"
-#include <QDebug>
 
 SMSubProcess::SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int &termTimeout, const bool &keepAlive) :
     termTimeout(termTimeout), keepAlive(keepAlive)
@@ -41,12 +41,12 @@ SMSubProcess::SMSubProcess(const QString &executable, const QStringList &argumen
     QObject::connect(&process, &QProcess::errorOccurred, this, &SMSubProcess::processError);
     QObject::connect(&process, &QProcess::started, this, [=]() {
         QTextStream(stderr) << "Subprocess started!" << smsub_endl;
-        emit statusUpdated(true);
+        emit statusUpdated(true, QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
     });
     QObject::connect(&process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [=](int exitCode) {
         QTextStream(stderr) << "Subprocess exited!" << smsub_endl;
         // Exit with the same exit code as the process
-        emit statusUpdated(false);
+        emit statusUpdated(false, QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
         if (!keepAlive)
             QCoreApplication::exit(exitCode);
     });
diff --git a/SMSubProcess.h b/SMSubProcess.h
index cd2dddc..568cf9a 100644
--- a/SMSubProcess.h
+++ b/SMSubProcess.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 * smsub Server Manager Subprocess
-* Copyright (C) 2020-2023 Syping
+* Copyright (C) 2020-2024 Syping
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
@@ -46,7 +46,7 @@ private slots:
 
 signals:
     void outputWritten(const QByteArray &output);
-    void statusUpdated(const bool status);
+    void statusUpdated(const bool status, const qint64 time);
 };
 
 #endif // SMSUBPROCESS_H
diff --git a/SMSubServer.cpp b/SMSubServer.cpp
index c753b79..3e8402a 100644
--- a/SMSubServer.cpp
+++ b/SMSubServer.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 * smsub Server Manager Subprocess
-* Copyright (C) 2020-2023 Syping
+* Copyright (C) 2020-2024 Syping
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
@@ -33,6 +33,8 @@ SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &soc
     type = ServerType::Local;
     server = localServer;
     status = false;
+    startTime = QDateTime::currentDateTimeUtc().toSecsSinceEpoch();
+    stopTime = startTime;
 }
 
 SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &serverName, const quint16 &port) : serverSettings(serverSettings)
@@ -45,6 +47,8 @@ SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &ser
     type = ServerType::WebSocket;
     server = webSocketServer;
     status = false;
+    startTime = QDateTime::currentDateTimeUtc().toSecsSinceEpoch();
+    stopTime = startTime;
 }
 
 bool SMSubServer::isListening()
@@ -126,10 +130,10 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
         }
         else if (message.startsWith("status")) {
             if (status) {
-                sendMessage(socket, "Status: on\n");
+                sendMessage(socket, QString("Status: on\nLast Start: %1\nLast Stop: %2\n").arg(QString::number(startTime), QString::number(stopTime)).toUtf8());
             }
             else {
-                sendMessage(socket, "Status: off\n");
+                sendMessage(socket, QString("Status: off\nLast Start: %1\nLast Stop: %2\n").arg(QString::number(startTime), QString::number(stopTime)).toUtf8());
             }
         }
         else if (message.startsWith("start")) {
@@ -273,7 +277,8 @@ void SMSubServer::registerToken(const QString &token)
     });
 }
 
-void SMSubServer::statusUpdated(const bool status_)
+void SMSubServer::statusUpdated(const bool status_, const qint64 time)
 {
     status = status_;
+    status ? (startTime = time) : (stopTime = time);
 }
diff --git a/SMSubServer.h b/SMSubServer.h
index daabb22..dc1b743 100644
--- a/SMSubServer.h
+++ b/SMSubServer.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 * smsub Server Manager Subprocess
-* Copyright (C) 2020-2023 Syping
+* Copyright (C) 2020-2024 Syping
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
@@ -45,7 +45,7 @@ public:
 public slots:
     void writeOutput(const QByteArray &output);
     void registerToken(const QString &token);
-    void statusUpdated(const bool status);
+    void statusUpdated(const bool status, const qint64 time);
 
 private slots:
     void wsMessageReceived(const QByteArray &message);
@@ -60,6 +60,8 @@ private:
     SMSubServerSettings *serverSettings;
     QVector<QObject*> sockets;
     QVector<QString> tokens;
+    qint64 startTime;
+    qint64 stopTime;
     ServerType type;
     QObject *server;
     bool status;
diff --git a/main.cpp b/main.cpp
index aebda4d..adf5f7b 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 * smsub Server Manager Subprocess
-* Copyright (C) 2020-2023 Syping
+* Copyright (C) 2020-2024 Syping
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
@@ -134,13 +134,14 @@ int main(int argc, char *argv[])
 {
     QCoreApplication a(argc, argv);
     a.setApplicationName("Server Manager Subprocess");
-    a.setApplicationVersion("0.7");
+    a.setApplicationVersion("0.8");
 
 #ifdef Q_OS_UNIX
     catchUnixSignals({SIGINT, SIGHUP, SIGQUIT, SIGTERM});
 #endif
 
     bool rportSet = false;
+    bool autoStart = true;
     bool keepAlive = false;
     bool timeoutSet = false;
     int termTimeout = 60000;
@@ -152,6 +153,7 @@ int main(int argc, char *argv[])
     QStringList argumentList;
 
     const QByteArray envEnvironmentMode = qgetenv("SMSUB_ENVIRONMENT_MODE");
+    const QByteArray envAutoStart = qgetenv("SMSUB_AUTOSTART");
     const QByteArray envKeepAlive = qgetenv("SMSUB_KEEPALIVE");
     const QByteArray envManifest = qgetenv("SMSUB_JSON");
     const QByteArray envExecutable = qgetenv("SMSUB_EXEC");
@@ -204,6 +206,12 @@ int main(int argc, char *argv[])
             }
         }
 
+        if (!envAutoStart.isEmpty()) {
+            if (envAutoStart == "0" || envAutoStart.toLower() == "false" || envAutoStart.toLower() == "no") {
+                autoStart = false;
+            }
+        }
+
         if (!envKeepAlive.isEmpty()) {
             if (envKeepAlive == "1" || envKeepAlive.toLower() == "true" || envKeepAlive.toLower() == "yes") {
                 keepAlive = true;
@@ -342,6 +350,12 @@ int main(int argc, char *argv[])
             executable = QString::fromUtf8(envExecutable);
         }
 
+        if (!envAutoStart.isEmpty()) {
+            if (envAutoStart == "0" || envAutoStart.toLower() == "false" || envAutoStart.toLower() == "no") {
+                autoStart = false;
+            }
+        }
+
         if (!envKeepAlive.isEmpty()) {
             if (envKeepAlive == "1" || envKeepAlive.toLower() == "true" || envKeepAlive.toLower() == "yes") {
                 keepAlive = true;
@@ -385,6 +399,16 @@ int main(int argc, char *argv[])
                     return 1;
                 }
 
+                if (jsonObject.contains("AutoStart")) {
+                    const QJsonValue jsonAutoStart = jsonObject.value("AutoStart");
+                    if (!jsonAutoStart.isBool()) {
+                        QTextStream(stderr) << "AutoStart is not a bool in manifest, aborting!" << smsub_endl;
+                        manifestFile.close();
+                        return 1;
+                    }
+                    autoStart = jsonAutoStart.toBool();
+                }
+
                 if (jsonObject.contains("KeepAlive")) {
                     const QJsonValue jsonKeepAlive = jsonObject.value("KeepAlive");
                     if (!jsonKeepAlive.isBool()) {
@@ -562,7 +586,8 @@ int main(int argc, char *argv[])
     QObject::connect(&subLocal, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess);
     QObject::connect(&a, &QCoreApplication::aboutToQuit, &subProcess, &SMSubProcess::aboutToQuit);
 
-    subProcess.startProcess();
+    if (autoStart)
+        subProcess.startProcess();
 
     QTextStream(stderr) << QString("SMSub Version %1 initialized!").arg(QCoreApplication::applicationVersion()) << smsub_endl;
 

From 1ddc4ff755484dd850dc45de16c0eac81fa1b73a Mon Sep 17 00:00:00 2001
From: Syping <schiedelrafael@keppe.org>
Date: Tue, 7 May 2024 17:29:23 +0200
Subject: [PATCH 05/10] add BufferedReads, add AutoStart and KeepAlive command
 line options

---
 CMakeLists.txt   |  2 +-
 SMSubProcess.cpp | 33 ++++++++++++++++++---------------
 SMSubProcess.h   |  3 ++-
 SMSubServer.cpp  | 33 +++++++++++++++++----------------
 main.cpp         | 48 ++++++++++++++++++++++++++++++++++++++++--------
 5 files changed, 78 insertions(+), 41 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index bf8df83..9486a27 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-project(smsub LANGUAGES CXX VERSION 0.8)
+project(smsub LANGUAGES CXX VERSION 0.9)
 
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
diff --git a/SMSubProcess.cpp b/SMSubProcess.cpp
index e9016c6..9b19b51 100644
--- a/SMSubProcess.cpp
+++ b/SMSubProcess.cpp
@@ -22,8 +22,8 @@
 #include "SMSubProcess.h"
 #include "smsub.h"
 
-SMSubProcess::SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int &termTimeout, const bool &keepAlive) :
-    termTimeout(termTimeout), keepAlive(keepAlive)
+SMSubProcess::SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int termTimeout, const bool buffReads, const bool keepAlive) :
+    termTimeout(termTimeout), buffReads(buffReads), keepAlive(keepAlive)
 {
     // Set process executable, arguments and working directory
     process.setProgram(executable);
@@ -33,7 +33,7 @@ SMSubProcess::SMSubProcess(const QString &executable, const QStringList &argumen
     // manage input channel
     process.setInputChannelMode(QProcess::ManagedInputChannel);
 
-    // stdout and stderr in same IO stream
+    // stdout and stderr in same I/O stream
     process.setProcessChannelMode(QProcess::MergedChannels);
 
     // Connect process signal handlers
@@ -58,22 +58,25 @@ void SMSubProcess::readyRead()
     QTextStream(stderr) << "Subprocess I/O RR!" << smsub_endl;
 #endif
     // Read process output and emit event
-#ifdef SMSUB_BUFFERED_READS
+    if (buffReads) {
+        while (process.bytesAvailable()) {
 #ifdef SMSUB_IODEBUG
-    QTextStream(stderr) << "Subprocess I/O W!" << smsub_endl;
+            QTextStream(stderr) << "Subprocess I/O W!" << smsub_endl;
 #endif
-    const QByteArray readData = process.read(1024);
-    if (!readData.isEmpty())
-        emit outputWritten(readData);
-#else
-    while (process.canReadLine()) {
-#ifdef SMSUB_IODEBUG
-        QTextStream(stderr) << "Subprocess I/O WL!" << smsub_endl;
-#endif
-        const QByteArray readData = process.readLine().trimmed();
-        emit outputWritten(readData + '\n');
+            const QByteArray readData = process.read(1024);
+            if (!readData.isEmpty())
+                emit outputWritten(readData);
+        }
     }
+    else {
+        while (process.canReadLine()) {
+#ifdef SMSUB_IODEBUG
+            QTextStream(stderr) << "Subprocess I/O WL!" << smsub_endl;
 #endif
+            const QByteArray readData = process.readLine().trimmed();
+            emit outputWritten(readData + '\n');
+        }
+    }
 }
 
 void SMSubProcess::processError(QProcess::ProcessError error)
diff --git a/SMSubProcess.h b/SMSubProcess.h
index 568cf9a..0402192 100644
--- a/SMSubProcess.h
+++ b/SMSubProcess.h
@@ -26,11 +26,12 @@ class SMSubProcess : public QObject
 {
     Q_OBJECT
 public:
-    SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int &termTimeout = 60000, const bool &keepAlive = false);
+    SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int termTimeout = 60000, const bool buffReads = false, const bool keepAlive = false);
 
 private:
     QProcess process;
     int termTimeout;
+    bool buffReads;
     bool keepAlive;
 
 public slots:
diff --git a/SMSubServer.cpp b/SMSubServer.cpp
index 3e8402a..d08f727 100644
--- a/SMSubServer.cpp
+++ b/SMSubServer.cpp
@@ -79,7 +79,7 @@ void SMSubServer::newConnection()
         QObject::connect(webSocket, &QWebSocket::disconnected, this, &SMSubServer::deleteSocket);
         webSocket->sendBinaryMessage(QString("SMSub Version %1\n").arg(QCoreApplication::applicationVersion()).toUtf8());
         socket = webSocket;
-        QTextStream(stderr) << QString("WebSocket %1:%2 connected!").arg(webSocket->peerName(), QString::number(webSocket->peerPort())) << smsub_endl;
+        QTextStream(stderr) << QString("WebSocket %1:%2 connected!").arg(webSocket->peerAddress().toString(), QString::number(webSocket->peerPort())) << smsub_endl;
     }
     else {
         // Just for being sure
@@ -101,25 +101,26 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
     // Only allow commands being sent if authenticated
     const bool isAuthenticated = socket->property("Authenticated").toBool();
     if (Q_LIKELY(isAuthenticated)) {
-        if (message.startsWith("+dbg")) {
+        if (message == "+dbg") {
             socket->setProperty("ReceiveDbgMsg", true);
             sendMessage(socket, "Debug messages enabled!\n");
         }
-        else if (message.startsWith("-dbg")) {
+        else if (message == "-dbg") {
             socket->setProperty("ReceiveDbgMsg", false);
             sendMessage(socket, "Debug messages disabled!\n");
         }
-        else if (message.startsWith("+log")) {
+        else if (message == "+log") {
             socket->setProperty("ReceiveLog", true);
             debugOutput(socket, "Log output enabled!");
         }
-        else if (message.startsWith("-log")) {
+        else if (message == "-log") {
             socket->setProperty("ReceiveLog", false);
             debugOutput(socket, "Log output disabled!");
         }
-        else if (message.startsWith("+reg")) {
+        else if (message == "+reg") {
             if (Q_LIKELY(serverSettings->canRegister)) {
-                QByteArray authUuid = QUuid::createUuid().toByteArray(QUuid::Id128);
+                QByteArray authUuid = QUuid::createUuid().toByteArray(QUuid::Id128) +
+                                      QUuid::createUuid().toByteArray(QUuid::Id128);
                 authUuid = QByteArray::fromHex(authUuid).toBase64(QByteArray::OmitTrailingEquals);
                 emit tokenRegistered(QString::fromUtf8(authUuid));
                 sendMessage(socket, "Token: " + authUuid + '\n');
@@ -128,7 +129,7 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
                 sendMessage(socket, "Permission denied!\n");
             }
         }
-        else if (message.startsWith("status")) {
+        else if (message == "status") {
             if (status) {
                 sendMessage(socket, QString("Status: on\nLast Start: %1\nLast Stop: %2\n").arg(QString::number(startTime), QString::number(stopTime)).toUtf8());
             }
@@ -136,31 +137,31 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
                 sendMessage(socket, QString("Status: off\nLast Start: %1\nLast Stop: %2\n").arg(QString::number(startTime), QString::number(stopTime)).toUtf8());
             }
         }
-        else if (message.startsWith("start")) {
+        else if (message == "start") {
             emit startRequested();
             debugOutput(socket, "Starting server!");
         }
-        else if (message.startsWith("stop")) {
+        else if (message == "stop") {
             emit stopRequested();
             debugOutput(socket, "Stopping server!");
         }
-        else if (message.startsWith("kill")) {
+        else if (message == "kill") {
             emit killRequested();
             debugOutput(socket, "Killing server!");
         }
-        else if (message.startsWith("quit")) {
+        else if (message == "quit") {
             QTimer::singleShot(0, qApp, &QCoreApplication::quit);
             debugOutput(socket, "Qutting smsub!");
         }
-        else if (message.startsWith("wl")) {
+        else if (message.startsWith("wl ")) {
             const QByteArray writeData = message.mid(3);
             emit inputWritten(writeData + '\n');
-            debugOutput(socket, "Write line \"" + writeData + "\"!");
+            debugOutput(socket, "Write line: " + writeData);
         }
-        else if (message.startsWith("w")) {
+        else if (message.startsWith("w ")) {
             const QByteArray writeData = message.mid(2);
             emit inputWritten(writeData);
-            debugOutput(socket, "Write \"" + writeData + "\"!");
+            debugOutput(socket, "Write: " + writeData);
         }
     }
     else {
diff --git a/main.cpp b/main.cpp
index adf5f7b..3b52d92 100644
--- a/main.cpp
+++ b/main.cpp
@@ -134,7 +134,7 @@ int main(int argc, char *argv[])
 {
     QCoreApplication a(argc, argv);
     a.setApplicationName("Server Manager Subprocess");
-    a.setApplicationVersion("0.8");
+    a.setApplicationVersion("0.9");
 
 #ifdef Q_OS_UNIX
     catchUnixSignals({SIGINT, SIGHUP, SIGQUIT, SIGTERM});
@@ -142,9 +142,10 @@ int main(int argc, char *argv[])
 
     bool rportSet = false;
     bool autoStart = true;
+    bool buffReads = false;
     bool keepAlive = false;
     bool timeoutSet = false;
-    int termTimeout = 60000;
+    size_t termTimeout = 60000;
     quint16 rport;
     QString socket;
     QString rsocket;
@@ -154,6 +155,7 @@ int main(int argc, char *argv[])
 
     const QByteArray envEnvironmentMode = qgetenv("SMSUB_ENVIRONMENT_MODE");
     const QByteArray envAutoStart = qgetenv("SMSUB_AUTOSTART");
+    const QByteArray envBuffReads = qgetenv("SMSUB_BUFFERED_READS");
     const QByteArray envKeepAlive = qgetenv("SMSUB_KEEPALIVE");
     const QByteArray envManifest = qgetenv("SMSUB_JSON");
     const QByteArray envExecutable = qgetenv("SMSUB_EXEC");
@@ -212,6 +214,12 @@ int main(int argc, char *argv[])
             }
         }
 
+        if (!envBuffReads.isEmpty()) {
+            if (envBuffReads == "1" || envBuffReads.toLower() == "true" || envBuffReads.toLower() == "yes") {
+                buffReads = true;
+            }
+        }
+
         if (!envKeepAlive.isEmpty()) {
             if (envKeepAlive == "1" || envKeepAlive.toLower() == "true" || envKeepAlive.toLower() == "yes") {
                 keepAlive = true;
@@ -285,6 +293,12 @@ int main(int argc, char *argv[])
 #endif
         commandLineParser.addOption(subprocessRemoteSocket);
 
+        QCommandLineOption processAutoStart("autostart", "SMSub autostart mode setting.", "autostart");
+        commandLineParser.addOption(processAutoStart);
+
+        QCommandLineOption processKeepAlive("keepalive", "SMSub keepalive mode setting.", "keepalive");
+        commandLineParser.addOption(processKeepAlive);
+
         QCommandLineOption processTimeout("timeout", "SMSub termination timeout.", "timeout");
         commandLineParser.addOption(processTimeout);
 
@@ -302,7 +316,7 @@ int main(int argc, char *argv[])
                      !envManifest.isEmpty() && !envArguments.isEmpty() ||
                      commandLineParser.isSet(processManifest) && !envArguments.isEmpty() ||
                      !envManifest.isEmpty() && commandLineParser.isSet(processArguments)) {
-            QTextStream(stderr) << "You can't define a Process arguments and a JSON process manifest at the same time!" << smsub_endl;
+            QTextStream(stderr) << "You can't define Process arguments and a JSON process manifest at the same time!" << smsub_endl;
             return 1;
         }
 
@@ -320,7 +334,7 @@ int main(int argc, char *argv[])
 
         if (commandLineParser.isSet(processTimeout)) {
             bool ok;
-            const int _termTimeout = commandLineParser.value(processTimeout).toInt(&ok);
+            const int _termTimeout = commandLineParser.value(processTimeout).toInt(&ok, 10);
             if (ok) {
                 termTimeout = _termTimeout;
                 timeoutSet = true;
@@ -332,7 +346,7 @@ int main(int argc, char *argv[])
         }
         else if (!envTimeout.isEmpty()) {
             bool ok;
-            const int _termTimeout = envTimeout.toInt(&ok);
+            const int _termTimeout = envTimeout.toInt(&ok, 10);
             if (ok) {
                 termTimeout = _termTimeout;
                 timeoutSet = true;
@@ -350,13 +364,31 @@ int main(int argc, char *argv[])
             executable = QString::fromUtf8(envExecutable);
         }
 
-        if (!envAutoStart.isEmpty()) {
+        if (commandLineParser.isSet(processAutoStart)) {
+            const QString claAutoStart = commandLineParser.value(processAutoStart);
+            if (claAutoStart == "0" || claAutoStart.toLower() == "false" || claAutoStart.toLower() == "no") {
+                autoStart = false;
+            }
+        }
+        else if (!envAutoStart.isEmpty()) {
             if (envAutoStart == "0" || envAutoStart.toLower() == "false" || envAutoStart.toLower() == "no") {
                 autoStart = false;
             }
         }
 
-        if (!envKeepAlive.isEmpty()) {
+        if (!envBuffReads.isEmpty()) {
+            if (envBuffReads == "1" || envBuffReads.toLower() == "true" || envBuffReads.toLower() == "yes") {
+                buffReads = true;
+            }
+        }
+
+        if (commandLineParser.isSet(processKeepAlive)) {
+            const QString claKeepAlive = commandLineParser.value(processKeepAlive);
+            if (claKeepAlive != "0" || claKeepAlive.toLower() != "false" || claKeepAlive.toLower() != "no") {
+                keepAlive = true;
+            }
+        }
+        else if (!envKeepAlive.isEmpty()) {
             if (envKeepAlive == "1" || envKeepAlive.toLower() == "true" || envKeepAlive.toLower() == "yes") {
                 keepAlive = true;
             }
@@ -534,7 +566,7 @@ int main(int argc, char *argv[])
         return 1;
     }
 
-    SMSubProcess subProcess(executable, argumentList, workingDirectory, termTimeout, keepAlive);
+    SMSubProcess subProcess(executable, argumentList, workingDirectory, termTimeout, buffReads, keepAlive);
 
     SMSubServerSettings remoteSettings;
     remoteSettings.canRegister = false;

From 9e2518fa9bfaf204a775d9d3c51b9b2439010c4a Mon Sep 17 00:00:00 2001
From: Syping <schiedelrafael@keppe.org>
Date: Tue, 7 May 2024 17:39:45 +0200
Subject: [PATCH 06/10] change command line KeepAlive implementation

---
 main.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/main.cpp b/main.cpp
index 3b52d92..619be37 100644
--- a/main.cpp
+++ b/main.cpp
@@ -293,10 +293,10 @@ int main(int argc, char *argv[])
 #endif
         commandLineParser.addOption(subprocessRemoteSocket);
 
-        QCommandLineOption processAutoStart("autostart", "SMSub autostart mode setting.", "autostart");
+        QCommandLineOption processAutoStart("autostart", "SMSub autostart mode.", "autostart");
         commandLineParser.addOption(processAutoStart);
 
-        QCommandLineOption processKeepAlive("keepalive", "SMSub keepalive mode setting.", "keepalive");
+        QCommandLineOption processKeepAlive("keepalive", "SMSub keepalive mode.", "keepalive");
         commandLineParser.addOption(processKeepAlive);
 
         QCommandLineOption processTimeout("timeout", "SMSub termination timeout.", "timeout");
@@ -384,7 +384,7 @@ int main(int argc, char *argv[])
 
         if (commandLineParser.isSet(processKeepAlive)) {
             const QString claKeepAlive = commandLineParser.value(processKeepAlive);
-            if (claKeepAlive != "0" || claKeepAlive.toLower() != "false" || claKeepAlive.toLower() != "no") {
+            if (claKeepAlive == "1" || claKeepAlive.toLower() == "true" || claKeepAlive.toLower() == "yes") {
                 keepAlive = true;
             }
         }

From 4981372e8fca8f30e20e73a5d0ada27d0313e21f Mon Sep 17 00:00:00 2001
From: Syping <schiedelrafael@keppe.org>
Date: Thu, 9 May 2024 21:16:50 +0200
Subject: [PATCH 07/10] add +json -json +status -status

---
 CMakeLists.txt  |  24 +++++---
 SMSubServer.cpp | 154 ++++++++++++++++++++++++++++++++++++++++--------
 SMSubServer.h   |   1 +
 main.cpp        |   2 +-
 4 files changed, 149 insertions(+), 32 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9486a27..1655bc2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-project(smsub LANGUAGES CXX VERSION 0.9)
+project(smsub LANGUAGES CXX VERSION 0.10)
 
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
@@ -18,6 +18,18 @@ else()
     find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
 endif()
 find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Network WebSockets REQUIRED)
+set(SMSUB_LIBS Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::WebSockets)
+
+option(WITH_BOOST "Use Boost library" ON)
+if(WITH_BOOST)
+    find_package(Boost COMPONENTS json REQUIRED)
+    list(APPEND SMSUB_LIBS
+        Boost::json
+    )
+    list(APPEND SMSUB_DEFINES
+        BOOST_JSON
+    )
+endif()
 
 set(SMSUB_SOURCES
     main.cpp
@@ -31,11 +43,7 @@ set(SMSUB_HEADERS
     SMSubServer.h
 )
 
-add_executable(smsub
-    ${SMSUB_HEADERS}
-    ${SMSUB_SOURCES}
-)
-
-target_link_libraries(smsub PRIVATE Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::WebSockets)
-
+add_executable(smsub ${SMSUB_HEADERS} ${SMSUB_SOURCES})
+target_compile_definitions(smsub PRIVATE ${SMSUB_DEFINES})
+target_link_libraries(smsub PRIVATE ${SMSUB_LIBS})
 install(TARGETS smsub DESTINATION bin)
diff --git a/SMSubServer.cpp b/SMSubServer.cpp
index d08f727..8548165 100644
--- a/SMSubServer.cpp
+++ b/SMSubServer.cpp
@@ -21,6 +21,12 @@
 #include <QUuid>
 #include "SMSubServer.h"
 #include "smsub.h"
+#ifdef BOOST_JSON
+#include <boost/json.hpp>
+#else
+#include <QJsonDocument>
+#include <QJsonObject>
+#endif
 
 SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &socket) : serverSettings(serverSettings)
 {
@@ -40,6 +46,7 @@ SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &soc
 SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &serverName, const quint16 &port) : serverSettings(serverSettings)
 {
     QWebSocketServer *webSocketServer = new QWebSocketServer(serverName, QWebSocketServer::NonSecureMode, this);
+    webSocketServer->setSupportedSubprotocols(QStringList() << "smsub" << "smsub_json");
     webSocketServer->listen(QHostAddress::LocalHost, port);
 
     QObject::connect(webSocketServer, &QWebSocketServer::newConnection, this, &SMSubServer::newConnection);
@@ -53,7 +60,7 @@ SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &ser
 
 bool SMSubServer::isListening()
 {
-    if (Q_LIKELY(type == ServerType::Local)) {
+    if (type == ServerType::Local) {
         return static_cast<QLocalServer*>(server)->isListening();
     }
     else if (type == ServerType::WebSocket) {
@@ -80,6 +87,9 @@ void SMSubServer::newConnection()
         webSocket->sendBinaryMessage(QString("SMSub Version %1\n").arg(QCoreApplication::applicationVersion()).toUtf8());
         socket = webSocket;
         QTextStream(stderr) << QString("WebSocket %1:%2 connected!").arg(webSocket->peerAddress().toString(), QString::number(webSocket->peerPort())) << smsub_endl;
+
+        if (webSocket->subprotocol() == "smsub_json")
+            socket->setProperty("ReceiveJson", true);
     }
     else {
         // Just for being sure
@@ -100,7 +110,7 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
 {
     // Only allow commands being sent if authenticated
     const bool isAuthenticated = socket->property("Authenticated").toBool();
-    if (Q_LIKELY(isAuthenticated)) {
+    if (isAuthenticated) {
         if (message == "+dbg") {
             socket->setProperty("ReceiveDbgMsg", true);
             sendMessage(socket, "Debug messages enabled!\n");
@@ -109,6 +119,14 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
             socket->setProperty("ReceiveDbgMsg", false);
             sendMessage(socket, "Debug messages disabled!\n");
         }
+        else if (message == "+json") {
+            socket->setProperty("ReceiveJson", true);
+            debugOutput(socket, "JSON output enabled!");
+        }
+        else if (message == "-json") {
+            socket->setProperty("ReceiveJson", false);
+            debugOutput(socket, "JSON output disabled!");
+        }
         else if (message == "+log") {
             socket->setProperty("ReceiveLog", true);
             debugOutput(socket, "Log output enabled!");
@@ -117,8 +135,16 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
             socket->setProperty("ReceiveLog", false);
             debugOutput(socket, "Log output disabled!");
         }
+        else if (message == "+status") {
+            socket->setProperty("ReceiveStatus", true);
+            debugOutput(socket, "Status updates enabled!");
+        }
+        else if (message == "-status") {
+            socket->setProperty("ReceiveStatus", false);
+            debugOutput(socket, "Status updates disabled!");
+        }
         else if (message == "+reg") {
-            if (Q_LIKELY(serverSettings->canRegister)) {
+            if (serverSettings->canRegister) {
                 QByteArray authUuid = QUuid::createUuid().toByteArray(QUuid::Id128) +
                                       QUuid::createUuid().toByteArray(QUuid::Id128);
                 authUuid = QByteArray::fromHex(authUuid).toBase64(QByteArray::OmitTrailingEquals);
@@ -130,11 +156,26 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
             }
         }
         else if (message == "status") {
-            if (status) {
-                sendMessage(socket, QString("Status: on\nLast Start: %1\nLast Stop: %2\n").arg(QString::number(startTime), QString::number(stopTime)).toUtf8());
+            if (isVariantTrue(socket->property("ReceiveJson"))) {
+#ifdef BOOST_JSON
+                boost::json::object object;
+                object["type"] = "status";
+                object["status"] = status ? "on" : "off";
+                object["start"] = startTime;
+                object["stop"] = stopTime;
+                const std::string json = boost::json::serialize(object) + '\n';
+                sendMessage(socket, QByteArray::fromRawData(json.data(), json.size()));
+#else
+                QJsonObject object;
+                object["type"] = "status";
+                object["status"] = status ? "on" : "off";
+                object["start"] = startTime;
+                object["stop"] = stopTime;
+                sendMessage(socket, QJsonDocument(object).toJson(QJsonDocument::Compact) + '\n');
+#endif
             }
             else {
-                sendMessage(socket, QString("Status: off\nLast Start: %1\nLast Stop: %2\n").arg(QString::number(startTime), QString::number(stopTime)).toUtf8());
+                sendMessage(socket, QString("Status: %1\nLast Start: %2\nLast Stop: %3\n").arg(status ? "on" : "off", QString::number(startTime), QString::number(stopTime)).toUtf8());
             }
         }
         else if (message == "start") {
@@ -153,20 +194,24 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
             QTimer::singleShot(0, qApp, &QCoreApplication::quit);
             debugOutput(socket, "Qutting smsub!");
         }
+        else if (message == "wl") {
+            emit inputWritten("\n");
+            debugOutput(socket, "Writing line!");
+        }
         else if (message.startsWith("wl ")) {
             const QByteArray writeData = message.mid(3);
             emit inputWritten(writeData + '\n');
-            debugOutput(socket, "Write line: " + writeData);
+            debugOutput(socket, "Writing line: " + writeData);
         }
         else if (message.startsWith("w ")) {
             const QByteArray writeData = message.mid(2);
             emit inputWritten(writeData);
-            debugOutput(socket, "Write: " + writeData);
+            debugOutput(socket, "Writing: " + writeData);
         }
     }
     else {
         // Authenticate when token is valid, otherwise disconnect
-        if (Q_UNLIKELY(tokens.contains(QString::fromUtf8(message)))) {
+        if (tokens.contains(QString::fromUtf8(message))) {
             // Set client as authenticated and add it to vector
             socket->setProperty("Authenticated", true);
             sendMessage(socket, "Login successful!\n");
@@ -174,7 +219,7 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
         }
         else {
             // Stop receiving data and disconnect socket
-            if (Q_LIKELY(type == ServerType::Local)) {
+            if (type == ServerType::Local) {
                 QLocalSocket *localSocket = static_cast<QLocalSocket*>(socket);
                 QObject::disconnect(localSocket, &QLocalSocket::readyRead, this, &SMSubServer::lsReadyRead);
                 localSocket->write("Incorrect token!\n");
@@ -193,6 +238,18 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
     return true;
 }
 
+bool SMSubServer::isVariantTrue(const QVariant &variant)
+{
+#if QT_VERSION >= 0x060000
+    if (variant.typeId() == QMetaType::Bool) {
+#else
+    if (variant.type() == QVariant::Bool) {
+#endif
+        return variant.toBool();
+    }
+    return false;
+}
+
 void SMSubServer::wsMessageReceived(const QByteArray &message)
 {
     QWebSocket *socket = static_cast<QWebSocket*>(sender());
@@ -226,14 +283,22 @@ void SMSubServer::deleteSocket()
 void SMSubServer::debugOutput(QObject *socket, const QByteArray &message)
 {
     // Only send debug messages when the client opted-in
-    const QVariant variant = socket->property("ReceiveDbgMsg");
-#if QT_VERSION >= 0x060000
-    if (Q_UNLIKELY(variant.typeId() == QMetaType::Bool)) {
+    if (isVariantTrue(socket->property("ReceiveDbgMsg"))) {
+        if (isVariantTrue(socket->property("ReceiveJson"))) {
+#ifdef BOOST_JSON
+            boost::json::object object;
+            object["type"] = "debug";
+            object["message"] = message.toBase64(QByteArray::OmitTrailingEquals).constData();
+            const std::string json = boost::json::serialize(object) + '\n';
+            sendMessage(socket, QByteArray::fromRawData(json.data(), json.size()));
 #else
-    if (Q_UNLIKELY(variant.type() == QVariant::Bool)) {
+            QJsonObject object;
+            object["type"] = "debug";
+            object["message"] = QString::fromUtf8(message.toBase64(QByteArray::OmitTrailingEquals));
+            sendMessage(socket, QJsonDocument(object).toJson(QJsonDocument::Compact) + '\n');
 #endif
-        bool receiveDbgMsg = variant.toBool();
-        if (Q_LIKELY(receiveDbgMsg)) {
+        }
+        else {
             sendMessage(socket, message + '\n');
         }
     }
@@ -242,15 +307,26 @@ void SMSubServer::debugOutput(QObject *socket, const QByteArray &message)
 void SMSubServer::writeOutput(const QByteArray &output)
 {
     // Read process output when client opted-in for log
+    QByteArray json_output;
     for (auto it = sockets.constBegin(); it != sockets.constEnd(); it++) {
-        const QVariant variant = (*it)->property("ReceiveLog");
-#if QT_VERSION >= 0x060000
-        if (Q_UNLIKELY(variant.typeId() == QMetaType::Bool)) {
+        if (isVariantTrue((*it)->property("ReceiveLog"))) {
+            if (isVariantTrue((*it)->property("ReceiveJson"))) {
+                if (json_output.isEmpty()) {
+#ifdef BOOST_JSON
+                    boost::json::object object;
+                    object["type"] = "log";
+                    object["message"] = output.toBase64(QByteArray::OmitTrailingEquals).constData();
+                    json_output = QByteArray::fromStdString(boost::json::serialize(object) + '\n');
 #else
-        if (Q_UNLIKELY(variant.type() == QVariant::Bool)) {
+                    QJsonObject object;
+                    object["type"] = "log";
+                    object["message"] = QString::fromUtf8(output.toBase64(QByteArray::OmitTrailingEquals));
+                    json_output = QJsonDocument(object).toJson(QJsonDocument::Compact) + '\n';
 #endif
-            bool receiveLog = variant.toBool();
-            if (Q_LIKELY(receiveLog)) {
+                }
+                sendMessage(*it, json_output);
+            }
+            else {
                 sendMessage(*it, output);
             }
         }
@@ -259,7 +335,7 @@ void SMSubServer::writeOutput(const QByteArray &output)
 
 void SMSubServer::sendMessage(QObject *socket, const QByteArray &message)
 {
-    if (Q_LIKELY(type == ServerType::Local)) {
+    if (type == ServerType::Local) {
         QLocalSocket *localSocket = static_cast<QLocalSocket*>(socket);
         localSocket->write(message);
     }
@@ -282,4 +358,36 @@ void SMSubServer::statusUpdated(const bool status_, const qint64 time)
 {
     status = status_;
     status ? (startTime = time) : (stopTime = time);
+
+    QByteArray output, json_output;
+    for (auto it = sockets.constBegin(); it != sockets.constEnd(); it++) {
+        if (isVariantTrue((*it)->property("ReceiveStatus"))) {
+            if (isVariantTrue((*it)->property("ReceiveJson"))) {
+                if (json_output.isEmpty()) {
+#ifdef BOOST_JSON
+                    boost::json::object object;
+                    object["type"] = "status";
+                    object["status"] = status ? "on" : "off";
+                    object["start"] = startTime;
+                    object["stop"] = stopTime;
+                    json_output = QByteArray::fromStdString(boost::json::serialize(object) + '\n');
+#else
+                    QJsonObject object;
+                    object["type"] = "status";
+                    object["status"] = status ? "on" : "off";
+                    object["start"] = startTime;
+                    object["stop"] = stopTime;
+                    json_output = QJsonDocument(object).toJson(QJsonDocument::Compact) + '\n';
+#endif
+                }
+                sendMessage(*it, json_output);
+            }
+            else {
+                if (output.isEmpty()) {
+                    output = QString("Status: %1\nLast Start: %2\nLast Stop: %3\n").arg(status ? "on" : "off", QString::number(startTime), QString::number(stopTime)).toUtf8();
+                }
+                sendMessage(*it, json_output);
+            }
+        }
+    }
 }
diff --git a/SMSubServer.h b/SMSubServer.h
index dc1b743..f86786e 100644
--- a/SMSubServer.h
+++ b/SMSubServer.h
@@ -57,6 +57,7 @@ private:
     inline void debugOutput(QObject *socket, const QByteArray &message);
     inline void sendMessage(QObject *socket, const QByteArray &message);
     bool messageReceived(QObject *socket, const QByteArray &message);
+    inline bool isVariantTrue(const QVariant &variant);
     SMSubServerSettings *serverSettings;
     QVector<QObject*> sockets;
     QVector<QString> tokens;
diff --git a/main.cpp b/main.cpp
index 619be37..815a281 100644
--- a/main.cpp
+++ b/main.cpp
@@ -134,7 +134,7 @@ int main(int argc, char *argv[])
 {
     QCoreApplication a(argc, argv);
     a.setApplicationName("Server Manager Subprocess");
-    a.setApplicationVersion("0.9");
+    a.setApplicationVersion("0.10");
 
 #ifdef Q_OS_UNIX
     catchUnixSignals({SIGINT, SIGHUP, SIGQUIT, SIGTERM});

From 6595738d64ad4dd9a8caedec7b6708f3d56f996c Mon Sep 17 00:00:00 2001
From: Syping <schiedelrafael@keppe.org>
Date: Thu, 9 May 2024 21:27:58 +0200
Subject: [PATCH 08/10] restore compatibility with older Qt

---
 SMSubServer.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/SMSubServer.cpp b/SMSubServer.cpp
index 8548165..aa1cf6e 100644
--- a/SMSubServer.cpp
+++ b/SMSubServer.cpp
@@ -46,7 +46,9 @@ SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &soc
 SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &serverName, const quint16 &port) : serverSettings(serverSettings)
 {
     QWebSocketServer *webSocketServer = new QWebSocketServer(serverName, QWebSocketServer::NonSecureMode, this);
+#if QT_VERSION >= 0x060400
     webSocketServer->setSupportedSubprotocols(QStringList() << "smsub" << "smsub_json");
+#endif
     webSocketServer->listen(QHostAddress::LocalHost, port);
 
     QObject::connect(webSocketServer, &QWebSocketServer::newConnection, this, &SMSubServer::newConnection);
@@ -88,8 +90,10 @@ void SMSubServer::newConnection()
         socket = webSocket;
         QTextStream(stderr) << QString("WebSocket %1:%2 connected!").arg(webSocket->peerAddress().toString(), QString::number(webSocket->peerPort())) << smsub_endl;
 
+#if QT_VERSION >= 0x060400
         if (webSocket->subprotocol() == "smsub_json")
             socket->setProperty("ReceiveJson", true);
+#endif
     }
     else {
         // Just for being sure

From 0198da65952ecbd9c924d881bbc1e04411f9f9e2 Mon Sep 17 00:00:00 2001
From: Syping <schiedelrafael@keppe.org>
Date: Thu, 9 May 2024 21:59:57 +0200
Subject: [PATCH 09/10] fix JSON status bool

---
 SMSubServer.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/SMSubServer.cpp b/SMSubServer.cpp
index aa1cf6e..20a5672 100644
--- a/SMSubServer.cpp
+++ b/SMSubServer.cpp
@@ -164,7 +164,7 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
 #ifdef BOOST_JSON
                 boost::json::object object;
                 object["type"] = "status";
-                object["status"] = status ? "on" : "off";
+                object["status"] = status;
                 object["start"] = startTime;
                 object["stop"] = stopTime;
                 const std::string json = boost::json::serialize(object) + '\n';
@@ -172,7 +172,7 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
 #else
                 QJsonObject object;
                 object["type"] = "status";
-                object["status"] = status ? "on" : "off";
+                object["status"] = status;
                 object["start"] = startTime;
                 object["stop"] = stopTime;
                 sendMessage(socket, QJsonDocument(object).toJson(QJsonDocument::Compact) + '\n');
@@ -371,14 +371,14 @@ void SMSubServer::statusUpdated(const bool status_, const qint64 time)
 #ifdef BOOST_JSON
                     boost::json::object object;
                     object["type"] = "status";
-                    object["status"] = status ? "on" : "off";
+                    object["status"] = status;
                     object["start"] = startTime;
                     object["stop"] = stopTime;
                     json_output = QByteArray::fromStdString(boost::json::serialize(object) + '\n');
 #else
                     QJsonObject object;
                     object["type"] = "status";
-                    object["status"] = status ? "on" : "off";
+                    object["status"] = status;
                     object["start"] = startTime;
                     object["stop"] = stopTime;
                     json_output = QJsonDocument(object).toJson(QJsonDocument::Compact) + '\n';

From fd57796114177c36cc08b1be2c63a2aa6c423c20 Mon Sep 17 00:00:00 2001
From: Syping <schiedelrafael@keppe.org>
Date: Sat, 18 May 2024 05:06:56 +0200
Subject: [PATCH 10/10] store tokens in QByteArray, minor fixes

---
 CMakeLists.txt  |  2 +-
 SMSubServer.cpp | 12 ++++++------
 SMSubServer.h   |  6 +++---
 main.cpp        |  2 +-
 4 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1655bc2..dea9e62 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-project(smsub LANGUAGES CXX VERSION 0.10)
+project(smsub LANGUAGES CXX VERSION 0.10.1)
 
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
diff --git a/SMSubServer.cpp b/SMSubServer.cpp
index 20a5672..6ea0b0f 100644
--- a/SMSubServer.cpp
+++ b/SMSubServer.cpp
@@ -113,15 +113,15 @@ void SMSubServer::newConnection()
 bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
 {
     // Only allow commands being sent if authenticated
-    const bool isAuthenticated = socket->property("Authenticated").toBool();
+    const bool isAuthenticated = isVariantTrue(socket->property("Authenticated"));
     if (isAuthenticated) {
         if (message == "+dbg") {
             socket->setProperty("ReceiveDbgMsg", true);
-            sendMessage(socket, "Debug messages enabled!\n");
+            debugOutput(socket, "Debug messages enabled!");
         }
         else if (message == "-dbg") {
+            debugOutput(socket, "Debug messages disabled!");
             socket->setProperty("ReceiveDbgMsg", false);
-            sendMessage(socket, "Debug messages disabled!\n");
         }
         else if (message == "+json") {
             socket->setProperty("ReceiveJson", true);
@@ -152,7 +152,7 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
                 QByteArray authUuid = QUuid::createUuid().toByteArray(QUuid::Id128) +
                                       QUuid::createUuid().toByteArray(QUuid::Id128);
                 authUuid = QByteArray::fromHex(authUuid).toBase64(QByteArray::OmitTrailingEquals);
-                emit tokenRegistered(QString::fromUtf8(authUuid));
+                emit tokenRegistered(authUuid);
                 sendMessage(socket, "Token: " + authUuid + '\n');
             }
             else {
@@ -215,7 +215,7 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
     }
     else {
         // Authenticate when token is valid, otherwise disconnect
-        if (tokens.contains(QString::fromUtf8(message))) {
+        if (tokens.contains(message)) {
             // Set client as authenticated and add it to vector
             socket->setProperty("Authenticated", true);
             sendMessage(socket, "Login successful!\n");
@@ -349,7 +349,7 @@ void SMSubServer::sendMessage(QObject *socket, const QByteArray &message)
     }
 }
 
-void SMSubServer::registerToken(const QString &token)
+void SMSubServer::registerToken(const QByteArray &token)
 {
     // Register temporary token for a secure remote connection
     tokens << token;
diff --git a/SMSubServer.h b/SMSubServer.h
index f86786e..d7f452a 100644
--- a/SMSubServer.h
+++ b/SMSubServer.h
@@ -44,7 +44,7 @@ public:
 
 public slots:
     void writeOutput(const QByteArray &output);
-    void registerToken(const QString &token);
+    void registerToken(const QByteArray &token);
     void statusUpdated(const bool status, const qint64 time);
 
 private slots:
@@ -60,7 +60,7 @@ private:
     inline bool isVariantTrue(const QVariant &variant);
     SMSubServerSettings *serverSettings;
     QVector<QObject*> sockets;
-    QVector<QString> tokens;
+    QVector<QByteArray> tokens;
     qint64 startTime;
     qint64 stopTime;
     ServerType type;
@@ -68,7 +68,7 @@ private:
     bool status;
 
 signals:
-    void tokenRegistered(const QString &password);
+    void tokenRegistered(const QByteArray &token);
     void inputWritten(const QByteArray &input);
     void startRequested();
     void stopRequested();
diff --git a/main.cpp b/main.cpp
index 815a281..a3d8eee 100644
--- a/main.cpp
+++ b/main.cpp
@@ -134,7 +134,7 @@ int main(int argc, char *argv[])
 {
     QCoreApplication a(argc, argv);
     a.setApplicationName("Server Manager Subprocess");
-    a.setApplicationVersion("0.10");
+    a.setApplicationVersion("0.10.1");
 
 #ifdef Q_OS_UNIX
     catchUnixSignals({SIGINT, SIGHUP, SIGQUIT, SIGTERM});