diff --git a/CMakeLists.txt b/CMakeLists.txt
index c83979b..dea9e62 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.10.1)
 
 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/SMSubProcess.cpp b/SMSubProcess.cpp
index 9a67656..9b19b51 100644
--- a/SMSubProcess.cpp
+++ b/SMSubProcess.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 * smsub Server Manager Subprocess
-* Copyright (C) 2020-2021 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,55 +18,79 @@
 
 #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) :
-    termTimeout(termTimeout)
+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);
     process.setArguments(arguments);
     process.setWorkingDirectory(workingDirectory);
 
-    // stdout and stderr in same IO stream
+    // manage input channel
+    process.setInputChannelMode(QProcess::ManagedInputChannel);
+
+    // stdout and stderr in same I/O 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, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [=](int exitCode) {
-        // Exit with the same exit code as the process
-        emit processStopped();
-        QCoreApplication::exit(exitCode);
+    QObject::connect(&process, &QProcess::started, this, [=]() {
+        QTextStream(stderr) << "Subprocess started!" << smsub_endl;
+        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, QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
+        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
-    while (process.canReadLine()) {
-        const QByteArray readData = process.readLine().trimmed();
-        emit outputWritten(readData + '\n');
+    if (buffReads) {
+        while (process.bytesAvailable()) {
+#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;
+#endif
+            const QByteArray readData = process.readLine().trimmed();
+            emit outputWritten(readData + '\n');
+        }
     }
 }
 
 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);
+        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);
     }
 }
 
@@ -81,24 +105,33 @@ 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)
 {
+#ifdef SMSUB_IODEBUG
+    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 dedd81c..0402192 100644
--- a/SMSubProcess.h
+++ b/SMSubProcess.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 * smsub Server Manager Subprocess
-* Copyright (C) 2020-2021 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:
@@ -26,17 +26,19 @@ 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 buffReads = false, const bool keepAlive = false);
 
 private:
     QProcess process;
     int termTimeout;
+    bool buffReads;
+    bool keepAlive;
 
 public slots:
     void aboutToQuit();
-    void killProcess();
+    void startProcess();
     void stopProcess();
+    void killProcess();
     void writeInput(const QByteArray &input);
 
 private slots:
@@ -45,8 +47,7 @@ private slots:
 
 signals:
     void outputWritten(const QByteArray &output);
-    void processStopped();
-
+    void statusUpdated(const bool status, const qint64 time);
 };
 
 #endif // SMSUBPROCESS_H
diff --git a/SMSubServer.cpp b/SMSubServer.cpp
index 962829a..6ea0b0f 100644
--- a/SMSubServer.cpp
+++ b/SMSubServer.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 * smsub Server Manager Subprocess
-* Copyright (C) 2020-2021 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:
@@ -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)
 {
@@ -32,22 +38,31 @@ 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)
 {
     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);
 
     type = ServerType::WebSocket;
     server = webSocketServer;
+    status = false;
+    startTime = QDateTime::currentDateTimeUtc().toSecsSinceEpoch();
+    stopTime = startTime;
 }
 
 bool SMSubServer::isListening()
 {
-    if (likely(type == ServerType::Local)) {
+    if (type == ServerType::Local) {
         return static_cast<QLocalServer*>(server)->isListening();
     }
     else if (type == ServerType::WebSocket) {
@@ -59,12 +74,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 +88,12 @@ 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->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
@@ -91,57 +113,109 @@ 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();
-    if (likely(isAuthenticated)) {
-        if (message.startsWith("+dbg")) {
+    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.startsWith("-dbg")) {
+        else if (message == "-dbg") {
+            debugOutput(socket, "Debug messages disabled!");
             socket->setProperty("ReceiveDbgMsg", false);
-            sendMessage(socket, "Debug messages disabled!\n");
         }
-        else if (message.startsWith("+log")) {
+        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!");
         }
-        else if (message.startsWith("-log")) {
+        else if (message == "-log") {
             socket->setProperty("ReceiveLog", false);
             debugOutput(socket, "Log output disabled!");
         }
-        else if (message.startsWith("+reg")) {
-            if (likely(serverSettings->canRegister)) {
-                QByteArray authUuid = QUuid::createUuid().toByteArray(QUuid::Id128);
+        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 (serverSettings->canRegister) {
+                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 {
                 sendMessage(socket, "Permission denied!\n");
             }
         }
-        else if (message.startsWith("kill")) {
-            emit killRequested();
-            debugOutput(socket, "Killing server!");
+        else if (message == "status") {
+            if (isVariantTrue(socket->property("ReceiveJson"))) {
+#ifdef BOOST_JSON
+                boost::json::object object;
+                object["type"] = "status";
+                object["status"] = status;
+                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;
+                object["start"] = startTime;
+                object["stop"] = stopTime;
+                sendMessage(socket, QJsonDocument(object).toJson(QJsonDocument::Compact) + '\n');
+#endif
+            }
+            else {
+                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.startsWith("stop")) {
+        else if (message == "start") {
+            emit startRequested();
+            debugOutput(socket, "Starting server!");
+        }
+        else if (message == "stop") {
             emit stopRequested();
             debugOutput(socket, "Stopping server!");
         }
-        else if (message.startsWith("wl")) {
+        else if (message == "kill") {
+            emit killRequested();
+            debugOutput(socket, "Killing server!");
+        }
+        else if (message == "quit") {
+            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")) {
+        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 (unlikely(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");
@@ -149,7 +223,7 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
         }
         else {
             // Stop receiving data and disconnect socket
-            if (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");
@@ -168,6 +242,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());
@@ -177,7 +263,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;
@@ -195,10 +287,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 (unlikely(variant.type() == QVariant::Bool)) {
-        bool receiveDbgMsg = variant.toBool();
-        if (likely(receiveDbgMsg)) {
+    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
+            QJsonObject object;
+            object["type"] = "debug";
+            object["message"] = QString::fromUtf8(message.toBase64(QByteArray::OmitTrailingEquals));
+            sendMessage(socket, QJsonDocument(object).toJson(QJsonDocument::Compact) + '\n');
+#endif
+        }
+        else {
             sendMessage(socket, message + '\n');
         }
     }
@@ -207,11 +311,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 (unlikely(variant.type() == QVariant::Bool)) {
-            bool receiveLog = variant.toBool();
-            if (likely(receiveLog)) {
+        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
+                    QJsonObject object;
+                    object["type"] = "log";
+                    object["message"] = QString::fromUtf8(output.toBase64(QByteArray::OmitTrailingEquals));
+                    json_output = QJsonDocument(object).toJson(QJsonDocument::Compact) + '\n';
+#endif
+                }
+                sendMessage(*it, json_output);
+            }
+            else {
                 sendMessage(*it, output);
             }
         }
@@ -220,7 +339,7 @@ void SMSubServer::writeOutput(const QByteArray &output)
 
 void SMSubServer::sendMessage(QObject *socket, const QByteArray &message)
 {
-    if (likely(type == ServerType::Local)) {
+    if (type == ServerType::Local) {
         QLocalSocket *localSocket = static_cast<QLocalSocket*>(socket);
         localSocket->write(message);
     }
@@ -230,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;
@@ -238,3 +357,41 @@ void SMSubServer::registerToken(const QString &token)
         tokens.removeAll(token);
     });
 }
+
+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;
+                    object["start"] = startTime;
+                    object["stop"] = stopTime;
+                    json_output = QByteArray::fromStdString(boost::json::serialize(object) + '\n');
+#else
+                    QJsonObject object;
+                    object["type"] = "status";
+                    object["status"] = status;
+                    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 f5f9936..d7f452a 100644
--- a/SMSubServer.h
+++ b/SMSubServer.h
@@ -1,6 +1,6 @@
 /*****************************************************************************
 * smsub Server Manager Subprocess
-* Copyright (C) 2020-2021 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:
@@ -44,7 +44,8 @@ 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:
     void wsMessageReceived(const QByteArray &message);
@@ -56,17 +57,22 @@ 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;
+    QVector<QByteArray> tokens;
+    qint64 startTime;
+    qint64 stopTime;
     ServerType type;
     QObject *server;
+    bool status;
 
 signals:
-    void tokenRegistered(const QString &password);
+    void tokenRegistered(const QByteArray &token);
     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 1baf24b..a3d8eee 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************
 * smsub Server Manager Subprocess
-* Copyright (C) 2020-2021 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,7 +33,6 @@
 #ifdef Q_OS_UNIX
 #include <initializer_list>
 #include "signal.h"
-#include "unistd.h"
 #endif
 
 #ifdef Q_OS_UNIX
@@ -135,15 +134,18 @@ int main(int argc, char *argv[])
 {
     QCoreApplication a(argc, argv);
     a.setApplicationName("Server Manager Subprocess");
-    a.setApplicationVersion("0.5");
+    a.setApplicationVersion("0.10.1");
 
 #ifdef Q_OS_UNIX
     catchUnixSignals({SIGINT, SIGHUP, SIGQUIT, SIGTERM});
 #endif
 
     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;
@@ -151,24 +153,28 @@ 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 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");
+    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" || envEnvironmentMode.toLower() == "yes") {
+        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 {
@@ -176,7 +182,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;
@@ -189,7 +195,7 @@ int main(int argc, char *argv[])
             }
         }
 
-        if (unlikely(!envTimeout.isEmpty())) {
+        if (!envTimeout.isEmpty()) {
             bool ok;
             const int _termTimeout = envTimeout.toInt(&ok);
             if (ok) {
@@ -202,14 +208,32 @@ int main(int argc, char *argv[])
             }
         }
 
-        if (unlikely(!envWorkDir.isEmpty())) {
+        if (!envAutoStart.isEmpty()) {
+            if (envAutoStart == "0" || envAutoStart.toLower() == "false" || envAutoStart.toLower() == "no") {
+                autoStart = false;
+            }
+        }
+
+        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;
+            }
+        }
+
+        if (!envWorkDir.isEmpty()) {
             workingDirectory = QString::fromUtf8(envWorkDir);
         }
         else {
             workingDirectory = QFileInfo(executable).absolutePath();
         }
 
-        if (likely(!envSocket.isEmpty())) {
+        if (!envSocket.isEmpty()) {
             socket = QString::fromUtf8(envSocket);
         }
         else {
@@ -221,19 +245,20 @@ 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;
-            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;
             }
         }
     }
@@ -268,31 +293,37 @@ int main(int argc, char *argv[])
 #endif
         commandLineParser.addOption(subprocessRemoteSocket);
 
+        QCommandLineOption processAutoStart("autostart", "SMSub autostart mode.", "autostart");
+        commandLineParser.addOption(processAutoStart);
+
+        QCommandLineOption processKeepAlive("keepalive", "SMSub keepalive mode.", "keepalive");
+        commandLineParser.addOption(processKeepAlive);
+
         QCommandLineOption processTimeout("timeout", "SMSub termination timeout.", "timeout");
         commandLineParser.addOption(processTimeout);
 
         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))) {
-            QTextStream(stderr) << "You can't define a Process arguments and a JSON process manifest at the same time!" << smsub_endl;
+                     !envManifest.isEmpty() && commandLineParser.isSet(processArguments)) {
+            QTextStream(stderr) << "You can't define 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
@@ -301,9 +332,9 @@ 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);
+            const int _termTimeout = commandLineParser.value(processTimeout).toInt(&ok, 10);
             if (ok) {
                 termTimeout = _termTimeout;
                 timeoutSet = true;
@@ -313,9 +344,9 @@ 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);
+            const int _termTimeout = envTimeout.toInt(&ok, 10);
             if (ok) {
                 termTimeout = _termTimeout;
                 timeoutSet = true;
@@ -326,14 +357,44 @@ 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 (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 (!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 == "1" || claKeepAlive.toLower() == "true" || claKeepAlive.toLower() == "yes") {
+                keepAlive = true;
+            }
+        }
+        else if (!envKeepAlive.isEmpty()) {
+            if (envKeepAlive == "1" || envKeepAlive.toLower() == "true" || envKeepAlive.toLower() == "yes") {
+                keepAlive = true;
+            }
+        }
+
+        if (!envWorkDir.isEmpty()) {
             workingDirectory = QString::fromUtf8(envWorkDir);
         }
         else {
@@ -341,23 +402,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;
@@ -370,9 +431,29 @@ int main(int argc, char *argv[])
                     return 1;
                 }
 
-                if (likely(jsonObject.contains("WorkingDirectory"))) {
+                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()) {
+                        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 (unlikely(!jsonWorkingDirectory.isString())) {
+                    if (!jsonWorkingDirectory.isString()) {
                         QTextStream(stderr) << "Working Directory is not a string in manifest, aborting!" << smsub_endl;
                         manifestFile.close();
                         return 1;
@@ -380,9 +461,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();
@@ -395,9 +476,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 {
@@ -409,14 +490,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;
@@ -424,7 +505,7 @@ int main(int argc, char *argv[])
             }
         }
 
-        if (likely(commandLineParser.isSet(subprocessSocket))) {
+        if (commandLineParser.isSet(subprocessSocket)) {
             socket = commandLineParser.value(subprocessSocket);
         }
         else if (!envSocket.isEmpty()) {
@@ -439,33 +520,35 @@ 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;
-            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;
             }
         }
     }
@@ -474,7 +557,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
@@ -483,15 +566,15 @@ int main(int argc, char *argv[])
         return 1;
     }
 
-    SMSubProcess subProcess(executable, argumentList, workingDirectory, termTimeout);
+    SMSubProcess subProcess(executable, argumentList, workingDirectory, termTimeout, buffReads, keepAlive);
 
     SMSubServerSettings remoteSettings;
     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
@@ -502,34 +585,43 @@ 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 (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;
         }
         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();
+    if (autoStart)
+        subProcess.startProcess();
+
+    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