diff --git a/CMakeLists.txt b/CMakeLists.txt index 48aa5f9..2c36b8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.7) -project(xmppbot VERSION 0.4 LANGUAGES CXX) +project(xmppbot VERSION 0.5 LANGUAGES CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/xmppbot/main.cpp b/src/xmppbot/main.cpp index 252c8e4..cbfa02b 100644 --- a/src/xmppbot/main.cpp +++ b/src/xmppbot/main.cpp @@ -39,7 +39,7 @@ int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); app.setApplicationName(QLatin1String("xmppbot")); - app.setApplicationVersion(QLatin1String("0.4")); + app.setApplicationVersion(QLatin1String("0.5")); QCommandLineParser commandLineParser; commandLineParser.addPositionalArgument(QLatin1String("config"), QCoreApplication::translate("xmppbot", "Configuration file.")); @@ -64,7 +64,7 @@ int main(int argc, char *argv[]) app.setProperty("XmppClient", QVariant::fromValue(&client)); bool loginSet = false; - QString jid, jpw; + QString jid, jpw, script; QHash h_msg; QHash h_lua; QHash h_run; @@ -72,76 +72,81 @@ int main(int argc, char *argv[]) QSettings settings(settingsPath, QSettings::IniFormat); for (const QString &group : settings.childGroups()) { settings.beginGroup(group); - for (const QString &key : settings.childKeys()) { - if (key == QLatin1String("Password")) { - if (!loginSet) { - jid = group; - const QString instance = settings.value(QLatin1String("Instance"), QString()).toString(); - if (!instance.isEmpty()) { - jid += QLatin1String("/") + instance; + if (group == QLatin1String("xmppbot")) { + script = settings.value(QLatin1String("Script"), QString()).toString(); + } + else { + for (const QString &key : settings.childKeys()) { + if (key == QLatin1String("Password")) { + if (!loginSet) { + jid = group; + const QString instance = settings.value(QLatin1String("Instance"), QString()).toString(); + if (!instance.isEmpty()) { + jid += QLatin1String("/") + instance; + } + jpw = settings.value(key, QString()).toString(); + loginSet = true; + } + else { + QTextStream(stderr) << "xmppbot: Login password can only be set once!" << xendl; + return 1; } - jpw = settings.value(key, QString()).toString(); - loginSet = true; } - else { - QTextStream(stderr) << "xmppbot: Login password can only be set once!" << xendl; - return 1; + if (key == QLatin1String("Incoming")) { + const QString incoming = settings.value("Incoming", QString()).toString(); + if (incoming.startsWith(QLatin1String("message:"))) { + QTextStream(stderr) << QLatin1String("xmppbot: Account message incoming ") << group << QLatin1String(" initialised") << xendl; + h_msg.insert(group, incoming.mid(8)); + } + if (incoming.startsWith(QLatin1String("lua:"))) { + QTextStream(stderr) << QLatin1String("xmppbot: Account lua incoming ") << group << QLatin1String(" initialised") << xendl; + h_lua.insert(group, incoming.mid(4)); + } + if (incoming.startsWith(QLatin1String("run:"))) { + QTextStream(stderr) << QLatin1String("xmppbot: Account run incoming ") << group << QLatin1String(" initialised") << xendl; + h_run.insert(group, incoming.mid(4)); + } } - } - if (key == QLatin1String("Incoming")) { - const QString incoming = settings.value("Incoming", QString()).toString(); - if (incoming.startsWith(QLatin1String("message:"))) { - QTextStream(stderr) << QLatin1String("xmppbot: Account message incoming ") << group << QLatin1String(" initialised") << xendl; - h_msg.insert(group, incoming.mid(8)); - } - if (incoming.startsWith(QLatin1String("lua:"))) { - QTextStream(stderr) << QLatin1String("xmppbot: Account lua incoming ") << group << QLatin1String(" initialised") << xendl; - h_lua.insert(group, incoming.mid(4)); - } - if (incoming.startsWith(QLatin1String("run:"))) { - QTextStream(stderr) << QLatin1String("xmppbot: Account run incoming ") << group << QLatin1String(" initialised") << xendl; - h_run.insert(group, incoming.mid(4)); - } - } - if (key == QLatin1String(XmppSocketType)) { - XmppSocket *xmppSocket = new XmppSocket(&client, jid, group); + if (key == QLatin1String(XmppSocketType)) { + XmppSocket *xmppSocket = new XmppSocket(&client, jid, group); #ifdef Q_OS_UNIX - const QString permission = settings.value(QLatin1String("SocketPermission"), QString()).toString(); - if (permission == QLatin1String("UG") || permission == QLatin1String("UserGroup")) { - xmppSocket->setSocketOptions(QLocalServer::UserAccessOption | QLocalServer::GroupAccessOption); - } - if (permission == QLatin1String("UO") || permission == QLatin1String("UserOther")) { - xmppSocket->setSocketOptions(QLocalServer::UserAccessOption | QLocalServer::OtherAccessOption); - } - if (permission == QLatin1String("U") || permission == QLatin1String("User")) { - xmppSocket->setSocketOptions(QLocalServer::UserAccessOption); - } - if (permission == QLatin1String("GO") || permission == QLatin1String("GroupOther")) { - xmppSocket->setSocketOptions(QLocalServer::GroupAccessOption | QLocalServer::OtherAccessOption); - } - if (permission == QLatin1String("G") || permission == QLatin1String("Group")) { - xmppSocket->setSocketOptions(QLocalServer::GroupAccessOption); - } - if (permission == QLatin1String("O") || permission == QLatin1String("Other")) { - xmppSocket->setSocketOptions(QLocalServer::OtherAccessOption); - } - if (permission == QLatin1String("A") || permission == QLatin1String("All") || permission == QLatin1String("UGO") || permission == QLatin1String("UserGroupOther")) { - xmppSocket->setSocketOptions(QLocalServer::WorldAccessOption); - } + const QString permission = settings.value(QLatin1String("SocketPermission"), QString()).toString(); + if (permission == QLatin1String("UG") || permission == QLatin1String("UserGroup")) { + xmppSocket->setSocketOptions(QLocalServer::UserAccessOption | QLocalServer::GroupAccessOption); + } + if (permission == QLatin1String("UO") || permission == QLatin1String("UserOther")) { + xmppSocket->setSocketOptions(QLocalServer::UserAccessOption | QLocalServer::OtherAccessOption); + } + if (permission == QLatin1String("U") || permission == QLatin1String("User")) { + xmppSocket->setSocketOptions(QLocalServer::UserAccessOption); + } + if (permission == QLatin1String("GO") || permission == QLatin1String("GroupOther")) { + xmppSocket->setSocketOptions(QLocalServer::GroupAccessOption | QLocalServer::OtherAccessOption); + } + if (permission == QLatin1String("G") || permission == QLatin1String("Group")) { + xmppSocket->setSocketOptions(QLocalServer::GroupAccessOption); + } + if (permission == QLatin1String("O") || permission == QLatin1String("Other")) { + xmppSocket->setSocketOptions(QLocalServer::OtherAccessOption); + } + if (permission == QLatin1String("A") || permission == QLatin1String("All") || permission == QLatin1String("UGO") || permission == QLatin1String("UserGroupOther")) { + xmppSocket->setSocketOptions(QLocalServer::WorldAccessOption); + } #endif - const QString socketPath = settings.value(key, QString()).toString(); - bool listen = xmppSocket->listen(socketPath); + const QString socketPath = settings.value(key, QString()).toString(); + bool listen = xmppSocket->listen(socketPath); #ifdef Q_OS_UNIX - if (!listen) { - QLocalServer::removeServer(socketPath); - listen = xmppSocket->listen(socketPath); - } + if (!listen) { + QLocalServer::removeServer(socketPath); + listen = xmppSocket->listen(socketPath); + } #endif - if (listen) { - QTextStream(stderr) << QLatin1String("xmppbot: Account socket ") << group << QLatin1String(" initialised") << xendl; - } - else { - delete xmppSocket; + if (listen) { + QTextStream(stderr) << QLatin1String("xmppbot: Account socket ") << group << QLatin1String(" initialised") << xendl; + } + else { + delete xmppSocket; + } } } } @@ -160,12 +165,22 @@ int main(int argc, char *argv[]) QTextStream(stderr) << QLatin1String("xmppbot: Account login ") << jid << QLatin1String(" initialised") << xendl; + XmppBotLuaThread xmppBotLuaGlobalThread(script, QLatin1String("jidInitialised"), QVariantList() << jid, true); + if (!script.isEmpty() && QFile::exists(script)) { + xmppBotLuaGlobalThread.start(); + } + QObject::connect(&client, &QXmppClient::stateChanged, [&](QXmppClient::State state) { switch (state) { case QXmppClient::ConnectedState: { QTextStream(stderr) << QLatin1String("xmppbot: Account ") << jid << QLatin1String(" connected") << xendl; QXmppPresence xmppPresence(QXmppPresence::Available); client.setClientPresence(xmppPresence); + if (xmppBotLuaGlobalThread.isRunning()) { + const QString lua_function = QLatin1String("jidConnected"); + const QVariantList lua_args = QVariantList() << jid; + QMetaObject::invokeMethod(&xmppBotLuaGlobalThread, "executeLuaFunction", Qt::QueuedConnection, Q_ARG(QString, lua_function), Q_ARG(QVariantList, lua_args)); + } break; } case QXmppClient::ConnectingState: @@ -175,6 +190,11 @@ int main(int argc, char *argv[]) QTimer::singleShot(5000, &client, [&]() { client.connectToServer(jid, jpw); }); + if (xmppBotLuaGlobalThread.isRunning()) { + const QString lua_function = QLatin1String("jidDisconnected"); + const QVariantList lua_args = QVariantList() << jid; + QMetaObject::invokeMethod(&xmppBotLuaGlobalThread, "executeLuaFunction", Qt::QueuedConnection, Q_ARG(QString, lua_function), Q_ARG(QVariantList, lua_args)); + } break; default: break; @@ -211,6 +231,11 @@ int main(int argc, char *argv[]) QTextStream(stderr) << QLatin1String("xmppbot: Account ") << from_jid << QLatin1String(" executed pid ") << pid << xendl; } } + if (xmppBotLuaGlobalThread.isRunning()) { + const QString lua_function = QLatin1String("messageReceived"); + const QVariantList lua_args = QVariantList() << from << xmppMessage.to() << xmppMessage.body(); + QMetaObject::invokeMethod(&xmppBotLuaGlobalThread, "executeLuaFunction", Qt::QueuedConnection, Q_ARG(QString, lua_function), Q_ARG(QVariantList, lua_args)); + } }); QObject::connect(&client, &QXmppClient::presenceReceived, [&](const QXmppPresence &xmppPresence) { @@ -227,6 +252,11 @@ int main(int argc, char *argv[]) QObject::connect(xmppBotLuaThread, &XmppBotLuaThread::finished, xmppBotLuaThread, &XmppBotLuaThread::deleteLater); xmppBotLuaThread->start(); } + if (xmppBotLuaGlobalThread.isRunning()) { + const QString lua_function = QLatin1String("presenceReceived"); + const QVariantList lua_args = QVariantList() << from << static_cast(xmppPresence.type()) << static_cast(xmppPresence.availableStatusType()) << xmppPresence.statusText(); + QMetaObject::invokeMethod(&xmppBotLuaGlobalThread, "executeLuaFunction", Qt::QueuedConnection, Q_ARG(QString, lua_function), Q_ARG(QVariantList, lua_args)); + } }); client.connectToServer(jid, jpw); diff --git a/src/xmppbot/xmppbotlua.cpp b/src/xmppbot/xmppbotlua.cpp index 76ea812..88bb99f 100644 --- a/src/xmppbot/xmppbotlua.cpp +++ b/src/xmppbot/xmppbotlua.cpp @@ -17,6 +17,10 @@ *****************************************************************************/ #include +#include +#include +#include +#include #include #include "xmppbot.h" @@ -30,11 +34,11 @@ XmppBotLua::XmppBotLua(QObject *parent) : QObject(parent) L = luaL_newstate(); luaL_openlibs(L); - // Functions + // XMPP Functions pushFunction("jid", jid); pushFunction("jin", jin); pushFunction("sendMessage", sendMessage); - pushFunction("setPresence", setPresence); + pushFunction("setClientPresence", setClientPresence); // XMPP Presence pushVariant("PresenceAvailable", static_cast(QXmppPresence::Available)); @@ -48,6 +52,15 @@ XmppBotLua::XmppBotLua(QObject *parent) : QObject(parent) pushVariant("StatusSnooze", static_cast(QXmppPresence::XA)); pushVariant("StatusBusy", static_cast(QXmppPresence::DND)); pushVariant("StatusChat", static_cast(QXmppPresence::Chat)); + + // JSON + pushFunction("jsonToTable", jsonToTable); + pushFunction("tableToJson", tableToJson); + pushVariant("JsonCompact", static_cast(QJsonDocument::Compact)); + pushVariant("JsonIndented", static_cast(QJsonDocument::Indented)); + + // Process + pushFunction("executeProcess", executeProcess); } XmppBotLua::~XmppBotLua() @@ -371,7 +384,7 @@ int XmppBotLua::sendMessage(lua_State *L_p) return 1; } -int XmppBotLua::setPresence(lua_State *L_p) +int XmppBotLua::setClientPresence(lua_State *L_p) { bool presenceSet = false; if (getArgumentCount(L_p) >= 2 && getArgumentCount(L_p) <= 3) { @@ -390,3 +403,89 @@ int XmppBotLua::setPresence(lua_State *L_p) pushVariant(L_p, presenceSet); return 1; } + +int XmppBotLua::jsonToTable(lua_State *L_p) +{ + if (getArgumentCount(L_p) >= 1) { + const QJsonDocument jsonDocument = QJsonDocument::fromJson(getVariant(L_p, 1).toString().toUtf8()); + if (jsonDocument.isObject()) { + pushVariant(L_p, jsonDocument.object().toVariantMap()); + return 1; + } + else if (jsonDocument.isArray()) { + pushVariant(L_p, jsonDocument.array().toVariantList()); + return 1; + } + } + return 0; +} + +int XmppBotLua::tableToJson(lua_State *L_p) +{ + if (getArgumentCount(L_p) >= 1) { + QJsonDocument::JsonFormat jsonFormat = QJsonDocument::Compact; + if (getArgumentCount(L_p) >= 2) { + jsonFormat = static_cast(getVariant(L_p, 2).toInt()); + } + pushVariant(L_p, QString::fromUtf8(QJsonDocument(QJsonObject::fromVariantMap(getVariant(L_p, 1).toMap())).toJson(jsonFormat))); + return 1; + } + return 0; +} + +int XmppBotLua::executeProcess(lua_State *L_p) +{ + if (getArgumentCount(L_p) >= 1) { + int processReturn = 0; + bool runInBackground = false; + bool processSuccessed = false; + if (getArgumentCount(L_p) >= 2) { + QStringList processArguments; + QString processPath = getVariant(L_p, 1).toString(); + QVariant argument = getVariant(L_p, 2); + if (static_cast(argument.type()) == QMetaType::QVariantMap) { + const QVariantMap argumentMap = argument.toMap(); + for (auto it = argumentMap.constBegin(); it != argumentMap.constEnd(); it++) { + processArguments << it.value().toString(); + } + } + else if (argument.type() == QVariant::Bool) { + runInBackground = argument.toBool(); + } + else { + processArguments << argument.toString(); + } + if (getArgumentCount(L_p) >= 3) { + if (argument.type() == QVariant::Bool) { + processArguments << argument.toString(); + } + runInBackground = getVariant(L_p, 3).toBool(); + } + if (runInBackground) { + processSuccessed = QProcess::startDetached(processPath, processArguments); + } + else { + processReturn = QProcess::execute(processPath, processArguments); + } + } + else { +#if QT_VERSION >= 0x050F00 + processReturn = system(getVariant(L_p, 1).toString().toUtf8().constData()); +#else + processReturn = QProcess::execute(getVariant(L_p, 1).toString()); +#endif + } + if (runInBackground && !processSuccessed) { + processReturn = -2; + } + else if (!runInBackground && processReturn == 0) { + processSuccessed = true; + } + pushVariant(L_p, processSuccessed); + pushVariant(L_p, processReturn); + return 2; + } + pushVariant(L_p, false); + pushVariant(L_p, -2); + return 2; +} diff --git a/src/xmppbot/xmppbotlua.h b/src/xmppbot/xmppbotlua.h index fa23901..18bbb6d 100644 --- a/src/xmppbot/xmppbotlua.h +++ b/src/xmppbot/xmppbotlua.h @@ -70,10 +70,20 @@ public: static int getArgumentCount(lua_State *L_p); private: + // XMPP static int jid(lua_State *L_p); static int jin(lua_State *L_p); static int sendMessage(lua_State *L_p); - static int setPresence(lua_State *L_p); + static int setClientPresence(lua_State *L_p); + + // JSON + static int jsonToTable(lua_State *L_p); + static int tableToJson(lua_State *L_p); + + // Process + static int executeProcess(lua_State *L_p); + + // Lua lua_State *L; }; diff --git a/src/xmppbot/xmppbotluathread.cpp b/src/xmppbot/xmppbotluathread.cpp index 5109a48..21b0b99 100644 --- a/src/xmppbot/xmppbotluathread.cpp +++ b/src/xmppbot/xmppbotluathread.cpp @@ -16,13 +16,15 @@ * responsible for anything with use of the software, you are self responsible. *****************************************************************************/ +#include +#include #include #include "xmppbotlua.h" #include "xmppbotluathread.h" -XmppBotLuaThread::XmppBotLuaThread(const QString &filePath, const QString &lua_function, const QVariantList &lua_args) : - filePath(filePath), lua_function(lua_function), lua_args(lua_args) +XmppBotLuaThread::XmppBotLuaThread(const QString &filePath, const QString &lua_function, const QVariantList &lua_args, const bool &lua_globalthread) : + filePath(filePath), lua_function(lua_function), lua_args(lua_args), lua_globalthread(lua_globalthread) { } @@ -36,9 +38,20 @@ void XmppBotLuaThread::run() scriptFile.close(); } } - if (!script.isEmpty()) { - XmppBotLua xmppBotLua; - xmppBotLua.executeLuaScript(script); - xmppBotLua.executeLuaFunction(lua_function.toUtf8().constData(), lua_args); + + if (script.isEmpty()) + return; + + XmppBotLua xmppBotLua; + xmppBotLua.executeLuaScript(script); + xmppBotLua.executeLuaFunction(lua_function.toUtf8().constData(), lua_args); + + if (lua_globalthread) { + QObject::connect(this, &XmppBotLuaThread::executeLuaFunction, this, [&](const QString &lua_function, const QVariantList &lua_args) { + xmppBotLua.executeLuaFunction(lua_function.toUtf8().constData(), lua_args); + }); + QEventLoop threadLoop; + QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, &threadLoop, &QEventLoop::quit); + threadLoop.exec(); } } diff --git a/src/xmppbot/xmppbotluathread.h b/src/xmppbot/xmppbotluathread.h index c82a0bb..bdc2ff5 100644 --- a/src/xmppbot/xmppbotluathread.h +++ b/src/xmppbot/xmppbotluathread.h @@ -26,7 +26,7 @@ class XmppBotLuaThread : public QThread { Q_OBJECT public: - XmppBotLuaThread(const QString &filePath, const QString &lua_function, const QVariantList &lua_args); + XmppBotLuaThread(const QString &filePath, const QString &lua_function, const QVariantList &lua_args, const bool &lua_globalthread = false); protected: void run(); @@ -35,6 +35,10 @@ private: QString filePath; QString lua_function; QVariantList lua_args; + bool lua_globalthread; + +signals: + void executeLuaFunction(const QString &lua_function, const QVariantList &lua_args); }; #endif // XMPPBOTLUATHREAD_H