diff --git a/AdaptixClient/Headers/Client/AxScript/AxScriptEngine.h b/AdaptixClient/Headers/Client/AxScript/AxScriptEngine.h index 7eba45b5..bff47b59 100644 --- a/AdaptixClient/Headers/Client/AxScript/AxScriptEngine.h +++ b/AdaptixClient/Headers/Client/AxScript/AxScriptEngine.h @@ -20,7 +20,7 @@ struct AxEvent { QTimer* timer; QString event_id; QSet agents; - QSet listenerts; + QSet listeners; QSet os; QJSEngine* jsEngine; }; @@ -28,7 +28,7 @@ struct AxEvent { struct AxMenuItem { AbstractAxMenuItem* menu; QSet agents; - QSet listenerts; + QSet listeners; QSet os; }; @@ -38,29 +38,8 @@ struct ScriptContext { QList objects; QList actions; - QList eventFileBroserDisks; - QList eventFileBroserList; - QList eventFileBrowserUpload; - QList eventProcessBrowserList; - QList eventNewAgent; - QList eventReady; - QList eventDisconnect; - QList eventTimer; - - QList menuSessionMain; - QList menuSessionAgent; - QList menuSessionBrowser; - QList menuSessionAccess; - QList menuFileBrowser; - QList menuProcessBrowser; - QList menuDownloadRunning; - QList menuDownloadFinished; - QList menuTasks; - QList menuTasksJob; - QList menuTargetsTop; - QList menuTargetsBottom; - QList menuTargetsCenter; - QList menuCreds; + QHash events; + QHash> menus; }; class AxScriptEngine : public QObject { diff --git a/AdaptixClient/Headers/Client/AxScript/AxScriptManager.h b/AdaptixClient/Headers/Client/AxScript/AxScriptManager.h index 465fb1ed..0c8e7d2d 100644 --- a/AdaptixClient/Headers/Client/AxScript/AxScriptManager.h +++ b/AdaptixClient/Headers/Client/AxScript/AxScriptManager.h @@ -86,6 +86,10 @@ public: QList FilterMenuItems(const QStringList &agentIds, const QString &menuType); QList FilterEvents(const QString &agentId, const QString &eventType); + QList getAllEngines() const; + void safeCallHandler(const AxEvent& event, const QJSValueList& args = QJSValueList()); + int addMenuItemsToMenu(QMenu* menu, const QList& items, const QVariantList& context); + void AppAgentHide(const QStringList &agents); void AppAgentRemove(const QStringList &agents); void AppAgentSetColor(const QStringList &agents, const QString &background, const QString &foreground, const bool reset); diff --git a/AdaptixClient/Headers/Client/AxScript/AxScriptUtils.h b/AdaptixClient/Headers/Client/AxScript/AxScriptUtils.h new file mode 100644 index 00000000..7c71cd54 --- /dev/null +++ b/AdaptixClient/Headers/Client/AxScript/AxScriptUtils.h @@ -0,0 +1,102 @@ +#ifndef AXSCRIPTUTILS_H +#define AXSCRIPTUTILS_H + +#include +#include +#include +#include + +class AxScriptUtils { +public: + static QStringList jsArrayToStringList(const QJSValue& array) + { + QStringList result; + if (!array.isArray()) + return result; + + const int length = array.property("length").toInt(); + result.reserve(length); + for (int i = 0; i < length; ++i) + result << array.property(i).toString(); + + return result; + } + + static QSet jsArrayToStringSet(const QJSValue& array) + { + QSet result; + if (!array.isArray()) + return result; + + const int length = array.property("length").toInt(); + result.reserve(length); + for (int i = 0; i < length; ++i) + result.insert(array.property(i).toString()); + + return result; + } + + static QSet parseOsSet(const QJSValue& os) + { + QSet result; + if (!os.isArray()) + return result; + + const int length = os.property("length").toInt(); + for (int i = 0; i < length; ++i) { + QString val = os.property(i).toString(); + if (val == "windows") result.insert(1); + else if (val == "linux") result.insert(2); + else if (val == "macos") result.insert(3); + } + return result; + } + + static QList parseOsList(const QJSValue& os) + { + QList result; + if (!os.isArray()) + return result; + + const int length = os.property("length").toInt(); + for (int i = 0; i < length; ++i) { + QString val = os.property(i).toString(); + if (val == "windows") result.append(1); + else if (val == "linux") result.append(2); + else if (val == "macos") result.append(3); + } + return result; + } + + static bool isValidArray(const QJSValue& value) + { + return !value.isUndefined() && !value.isNull() && value.isArray(); + } + + static bool isValidNonEmptyArray(const QJSValue& value) + { + return isValidArray(value) && value.property("length").toInt() > 0; + } + + static bool isOptionalValidArray(const QJSValue& value) + { + if (value.isUndefined() || value.isNull()) + return true; + return value.isArray(); + } + + static QJSValue stringListToJsArray(QJSEngine* engine, const QStringList& list) + { + QJSValue array = engine->newArray(list.size()); + for (int i = 0; i < list.size(); ++i) + array.setProperty(i, list[i]); + return array; + } + + static QJSValue variantListToJsArray(QJSEngine* engine, const QVariantList& list) + { + return engine->toScriptValue(list); + } +}; + +#endif diff --git a/AdaptixClient/Headers/Client/AxScript/BridgeApp.h b/AdaptixClient/Headers/Client/AxScript/BridgeApp.h index ee01e248..ba0800ea 100644 --- a/AdaptixClient/Headers/Client/AxScript/BridgeApp.h +++ b/AdaptixClient/Headers/Client/AxScript/BridgeApp.h @@ -11,7 +11,6 @@ class Command; class BridgeApp : public QObject { Q_OBJECT AxScriptEngine* scriptEngine; - QWidget* widget; public: explicit BridgeApp(AxScriptEngine* scriptEngine, QObject* parent = nullptr); diff --git a/AdaptixClient/Headers/Client/AxScript/BridgeMenu.h b/AdaptixClient/Headers/Client/AxScript/BridgeMenu.h index 6ab42122..c2ead30d 100644 --- a/AdaptixClient/Headers/Client/AxScript/BridgeMenu.h +++ b/AdaptixClient/Headers/Client/AxScript/BridgeMenu.h @@ -13,7 +13,6 @@ class AxSeparatorWrapper; class BridgeMenu : public QObject { Q_OBJECT AxScriptEngine* scriptEngine; - QWidget* widget; QList menuItems; QList items() const; diff --git a/AdaptixClient/Source/Client/AxScript/AxElementWrappers.cpp b/AdaptixClient/Source/Client/AxScript/AxElementWrappers.cpp index 24e1f64a..f3b9926d 100644 --- a/AdaptixClient/Source/Client/AxScript/AxElementWrappers.cpp +++ b/AdaptixClient/Source/Client/AxScript/AxElementWrappers.cpp @@ -458,12 +458,14 @@ void AxTableWidgetWrapper::setText(const int row, const int column, const QStrin void AxTableWidgetWrapper::setReadOnly(const bool read) { for(int rowIndex = 0; rowIndex < table->rowCount(); rowIndex++) { - for(int columnIndex = 0; columnIndex < table->rowCount(); columnIndex++) { + for(int columnIndex = 0; columnIndex < table->columnCount(); columnIndex++) { auto item = table->item(rowIndex, columnIndex); - if (read) - item->setFlags(item->flags() & ~Qt::ItemIsEditable); - else - item->setFlags(item->flags() | Qt::ItemIsEditable); + if (item) { + if (read) + item->setFlags(item->flags() & ~Qt::ItemIsEditable); + else + item->setFlags(item->flags() | Qt::ItemIsEditable); + } } } } diff --git a/AdaptixClient/Source/Client/AxScript/AxScriptEngine.cpp b/AdaptixClient/Source/Client/AxScript/AxScriptEngine.cpp index 47718233..358ae4b4 100644 --- a/AdaptixClient/Source/Client/AxScript/AxScriptEngine.cpp +++ b/AdaptixClient/Source/Client/AxScript/AxScriptEngine.cpp @@ -4,6 +4,7 @@ #include #include #include +#include AxScriptEngine::AxScriptEngine(AxScriptManager* script_manager, const QString &name, QObject *parent) : QObject(parent), scriptManager(script_manager) { @@ -37,12 +38,13 @@ AxScriptEngine::~AxScriptEngine() context.actions.clear(); context.objects.clear(); - for (auto event : context.eventTimer) { - if (event.timer) { - event.timer->stop(); - event.timer->deleteLater(); + for (auto it = context.events.begin(); it != context.events.end(); ++it) { + if (it.value().timer) { + it.value().timer->stop(); + it.value().timer->deleteLater(); } } + context.events.clear(); bridgeApp.reset(); bridgeForm.reset(); @@ -76,84 +78,33 @@ void AxScriptEngine::registerEvent(const QString &type, const QJSValue &handler, if (list_os.contains("linux")) os.insert(2); if (list_os.contains("macos")) os.insert(3); - AxEvent event = {handler, timer, id, list_agents, list_listeners, os, jsEngine.get()}; + QString eventKey = id.isEmpty() ? type + "_" + GenerateRandomString(8, "hex") : id; + AxEvent event = {handler, timer, eventKey, list_agents, list_listeners, os, jsEngine.get()}; + event.event_id = eventKey; - if ( type == "FileBroserDisks") context.eventFileBroserDisks.append(event); - else if (type == "FileBroserList") context.eventFileBroserList.append(event); - else if (type == "FileBrowserUpload") context.eventFileBrowserUpload.append(event); - else if (type == "ProcessBrowserList") context.eventProcessBrowserList.append(event); - else if (type == "new_agent") context.eventNewAgent.append(event); - else if (type == "ready") context.eventReady.append(event); - else if (type == "disconnect") context.eventDisconnect.append(event); - else if (type == "timer") context.eventTimer.append(event); + context.events.insert(eventKey, event); } QList AxScriptEngine::getEvents(const QString &type) { - if ( type == "FileBroserDisks") return context.eventFileBroserDisks; - else if (type == "FileBroserList") return context.eventFileBroserList; - else if (type == "FileBrowserUpload") return context.eventFileBrowserUpload; - else if (type == "ProcessBrowserList") return context.eventProcessBrowserList; - else if (type == "new_agent") return context.eventNewAgent; - else if (type == "ready") return context.eventReady; - else if (type == "disconnect") return context.eventDisconnect; - else if (type == "timer") return context.eventTimer; - - return QList(); + QList result; + for (auto it = context.events.constBegin(); it != context.events.constEnd(); ++it) { + const QString& key = it.key(); + if (key.startsWith(type + "_") || key == type || + (type == "timer" && (key.startsWith("interval_") || key.startsWith("timeout_")))) { + result.append(it.value()); + } + } + return result; } - - void AxScriptEngine::removeEvent(const QString &id) { - for (int i=0; i< context.eventFileBroserDisks.size(); i++) { - if (id == context.eventFileBroserDisks[i].event_id) { - context.eventFileBroserDisks.removeAt(i); - i--; - } - } - for (int i=0; i< context.eventFileBroserList.size(); i++) { - if (id == context.eventFileBroserList[i].event_id) { - context.eventFileBroserList.removeAt(i); - i--; - } - } - for (int i=0; i< context.eventFileBrowserUpload.size(); i++) { - if (id == context.eventFileBrowserUpload[i].event_id) { - context.eventFileBrowserUpload.removeAt(i); - i--; - } - } - for (int i=0; i< context.eventProcessBrowserList.size(); i++) { - if (id == context.eventProcessBrowserList[i].event_id) { - context.eventProcessBrowserList.removeAt(i); - i--; - } - } - for (int i=0; i< context.eventNewAgent.size(); i++) { - if (id == context.eventNewAgent[i].event_id) { - context.eventNewAgent.removeAt(i); - i--; - } - } - for (int i=0; i< context.eventReady.size(); i++) { - if (id == context.eventReady[i].event_id) { - context.eventReady.removeAt(i); - i--; - } - } - for (int i=0; i< context.eventDisconnect.size(); i++) { - if (id == context.eventDisconnect[i].event_id) { - context.eventDisconnect.removeAt(i); - i--; - } - } - for (int i=0; i< context.eventTimer.size(); i++) { - if (id == context.eventTimer[i].event_id) { - auto event = context.eventTimer.takeAt(i); + if (context.events.contains(id)) { + AxEvent event = context.events.take(id); + if (event.timer) { event.timer->stop(); event.timer->deleteLater(); - i--; } } } @@ -161,42 +112,13 @@ void AxScriptEngine::removeEvent(const QString &id) QStringList AxScriptEngine::listEvent() { QStringList list; - for (int i=0; i< context.eventFileBroserDisks.size(); i++) { - if (context.eventFileBroserDisks[i].event_id != "") - list.append(context.eventFileBroserDisks[i].event_id); - } - for (int i=0; i< context.eventFileBroserList.size(); i++) { - if (context.eventFileBroserList[i].event_id != "") - list.append(context.eventFileBroserList[i].event_id); - } - for (int i=0; i< context.eventFileBrowserUpload.size(); i++) { - if (context.eventFileBrowserUpload[i].event_id != "") - list.append(context.eventFileBrowserUpload[i].event_id); - } - for (int i=0; i< context.eventProcessBrowserList.size(); i++) { - if (context.eventProcessBrowserList[i].event_id != "") - list.append(context.eventProcessBrowserList[i].event_id); - } - for (int i=0; i< context.eventNewAgent.size(); i++) { - if (context.eventNewAgent[i].event_id != "") - list.append(context.eventNewAgent[i].event_id); - } - for (int i=0; i< context.eventReady.size(); i++) { - if (context.eventReady[i].event_id != "") - list.append(context.eventReady[i].event_id); - } - for (int i=0; i< context.eventDisconnect.size(); i++) { - if (context.eventDisconnect[i].event_id != "") - list.append(context.eventDisconnect[i].event_id); - } - for (int i=0; i< context.eventTimer.size(); i++) { - if (context.eventTimer[i].event_id != "") - list.append(context.eventTimer[i].event_id); + for (auto it = context.events.constBegin(); it != context.events.constEnd(); ++it) { + if (!it.key().isEmpty()) + list.append(it.key()); } return list; } - ///// void AxScriptEngine::registerMenu(const QString &type, AbstractAxMenuItem *menu, const QSet &list_agents, const QSet &list_os, const QSet &list_listeners) @@ -206,42 +128,13 @@ void AxScriptEngine::registerMenu(const QString &type, AbstractAxMenuItem *menu, if (list_os.contains("linux")) os.insert(2); if (list_os.contains("macos")) os.insert(3); - AxMenuItem item = {menu, list_agents, list_listeners, os}; - - if ( type == "SessionMain") context.menuSessionMain.append(item); - else if (type == "SessionAgent") context.menuSessionAgent.append(item); - else if (type == "SessionBrowser") context.menuSessionBrowser.append(item); - else if (type == "SessionAccess") context.menuSessionAccess.append(item); - else if (type == "FileBrowser") context.menuFileBrowser.append(item); - else if (type == "ProcessBrowser") context.menuProcessBrowser.append(item); - else if (type == "DownloadRunning") context.menuDownloadRunning.append(item); - else if (type == "DownloadFinished") context.menuDownloadFinished.append(item); - else if (type == "Tasks") context.menuTasks.append(item); - else if (type == "TasksJob") context.menuTasksJob.append(item); - else if (type == "TargetsTop") context.menuTargetsTop.append(item); - else if (type == "TargetsBottom") context.menuTargetsBottom.append(item); - else if (type == "TargetsCenter") context.menuTargetsCenter.append(item); - else if (type == "Creds") context.menuCreds.append(item); + AxMenuItem item = {menu, list_agents, list_listeners, os}; + context.menus[type].append(item); } QList AxScriptEngine::getMenuItems(const QString &type) { - if ( type == "SessionMain") return context.menuSessionMain; - else if (type == "SessionAgent") return context.menuSessionAgent; - else if (type == "SessionBrowser") return context.menuSessionBrowser; - else if (type == "SessionAccess") return context.menuSessionAccess; - else if (type == "FileBrowser") return context.menuFileBrowser; - else if (type == "ProcessBrowser") return context.menuProcessBrowser; - else if (type == "DownloadRunning") return context.menuDownloadRunning; - else if (type == "DownloadFinished") return context.menuDownloadFinished; - else if (type == "Tasks") return context.menuTasks; - else if (type == "TasksJob") return context.menuTasksJob; - else if (type == "TargetsTop") return context.menuTargetsTop; - else if (type == "TargetsBottom") return context.menuTargetsBottom; - else if (type == "TargetsCenter") return context.menuTargetsCenter; - else if (type == "Creds") return context.menuCreds; - - return QList(); + return context.menus.value(type); } void AxScriptEngine::engineError(const QString &message) { engine()->throwError(QJSValue::TypeError, message); } diff --git a/AdaptixClient/Source/Client/AxScript/AxScriptManager.cpp b/AdaptixClient/Source/Client/AxScript/AxScriptManager.cpp index ac728f3d..2b7abf42 100644 --- a/AdaptixClient/Source/Client/AxScript/AxScriptManager.cpp +++ b/AdaptixClient/Source/Client/AxScript/AxScriptManager.cpp @@ -167,6 +167,49 @@ void AxScriptManager::GlobalScriptLoad(const QString &path) { Q_EMIT adaptixWidg void AxScriptManager::GlobalScriptUnload(const QString &path) { Q_EMIT adaptixWidget->UnloadGlobalScriptSignal(path); } +QList AxScriptManager::getAllEngines() const +{ + QList list; + list.reserve(agents_scripts.size() + scripts.size() + 1); + list << agents_scripts.values() << scripts.values(); + if (mainScript) + list << mainScript; + return list; +} + +void AxScriptManager::safeCallHandler(const AxEvent& event, const QJSValueList& args) +{ + if (!event.jsEngine || !event.handler.isCallable()) + return; + + QJSValue result = event.handler.call(args); + if (result.isError()) { + QString error = QString("Script error in event handler: %1\n at line %2\n stack: %3") + .arg(result.toString()) + .arg(result.property("lineNumber").toInt()) + .arg(result.property("stack").toString()); + consolePrintError(error); + } +} + +int AxScriptManager::addMenuItemsToMenu(QMenu* menu, const QList& items, const QVariantList& context) +{ + int count = 0; + for (const auto& item : items) { + item.menu->setContext(context); + if (auto* sep = dynamic_cast(item.menu)) + menu->addAction(sep->action()); + else if (auto* act = dynamic_cast(item.menu)) + menu->addAction(act->action()); + else if (auto* sub = dynamic_cast(item.menu)) + menu->addMenu(sub->menu()); + else + continue; + count++; + } + return count; +} + void AxScriptManager::RegisterCommandsGroup(const CommandsGroup &group, const QStringList &listeners, const QStringList &agents, const QList &os) { auto commanderList = adaptixWidget->GetCommanders(listeners, agents, os); @@ -177,11 +220,8 @@ void AxScriptManager::RegisterCommandsGroup(const CommandsGroup &group, const QS QStringList AxScriptManager::EventList() { QStringList slist; - QList list = this->agents_scripts.values() + this->scripts.values(); - list.append(this->mainScript); - - for (const auto script : list) { - if (script != nullptr) + for (const auto script : getAllEngines()) { + if (script) slist += script->listEvent(); } return slist; @@ -189,11 +229,10 @@ QStringList AxScriptManager::EventList() void AxScriptManager::EventRemove(const QString &event_id) { - QList list = this->agents_scripts.values() + this->scripts.values(); - list.append(this->mainScript); - - for (const auto script : list) - script->removeEvent(event_id); + for (const auto script : getAllEngines()) { + if (script) + script->removeEvent(event_id); + } } QList AxScriptManager::FilterMenuItems(const QStringList &agentIds, const QString &menuType) @@ -201,7 +240,7 @@ QList AxScriptManager::FilterMenuItems(const QStringList &agentIds, QSet agentTypes; QSet listenerTypes; QSet osTypes; - for (auto agent_id: agentIds) { + for (const auto& agent_id: agentIds) { if (adaptixWidget->AgentsMap.contains(agent_id)) { agentTypes.insert(adaptixWidget->AgentsMap[agent_id]->data.Name); osTypes.insert(adaptixWidget->AgentsMap[agent_id]->data.Os); @@ -209,22 +248,19 @@ QList AxScriptManager::FilterMenuItems(const QStringList &agentIds, } } - QList list = this->agents_scripts.values() + this->scripts.values(); - list.append(this->mainScript); - QList items; - for (const auto script : list) - items += script->getMenuItems(menuType); + for (const auto script : getAllEngines()) { + if (script) + items += script->getMenuItems(menuType); + } QList ret; - for (int i = 0; i < items.size(); ++i) { - AxMenuItem item = items[i]; - - if ( !item.agents.contains(agentTypes) ) + for (const auto& item : items) { + if (!item.agents.contains(agentTypes)) continue; if (item.os.size() > 0 && !item.os.contains(osTypes)) continue; - if (item.listenerts.size() > 0 && !item.listenerts.contains(listenerTypes)) + if (item.listeners.size() > 0 && !item.listeners.contains(listenerTypes)) continue; ret.append(item); @@ -236,29 +272,25 @@ QList AxScriptManager::FilterEvents(const QString &agentId, const QStri { QList ret; - if( !adaptixWidget->AgentsMap.contains(agentId) ) + if (!adaptixWidget->AgentsMap.contains(agentId)) return ret; QString agentType = adaptixWidget->AgentsMap[agentId]->data.Name; QString listenerType = adaptixWidget->AgentsMap[agentId]->listenerType; - int osType = adaptixWidget->AgentsMap[agentId]->data.Os; - - QList list = this->agents_scripts.values() + this->scripts.values(); - list.append(this->mainScript); + int osType = adaptixWidget->AgentsMap[agentId]->data.Os; QList items; - for (const auto script : list) { - items += script->getEvents(eventType); + for (const auto script : getAllEngines()) { + if (script) + items += script->getEvents(eventType); } - for (int i = 0; i < items.size(); ++i) { - AxEvent event = items[i]; - - if ( !event.agents.contains(agentType) ) + for (const auto& event : items) { + if (!event.agents.contains(agentType)) continue; if (event.os.size() > 0 && !event.os.contains(osType)) continue; - if (event.listenerts.size() > 0 && !event.listenerts.contains(listenerType)) + if (event.listeners.size() > 0 && !event.listeners.contains(listenerType)) continue; ret.append(event); @@ -322,36 +354,19 @@ void AxScriptManager::AppAgentSetTag(const QStringList &agents, const QString &t int AxScriptManager::AddMenuSession(QMenu *menu, const QString &menuType, QStringList agentIds) { QVariantList context; - for (auto agent_id: agentIds) { - if (adaptixWidget->AgentsMap.contains(agent_id)) { + for (const auto& agent_id: agentIds) { + if (adaptixWidget->AgentsMap.contains(agent_id)) context << agent_id; - } } - int count = 0; - QList items = this->FilterMenuItems(agentIds, menuType); - for (int i = 0; i < items.size(); ++i) { - AxMenuItem item = items[i]; - - item.menu->setContext(context); - if (auto* item1 = dynamic_cast(item.menu)) - menu->addAction(item1->action()); - else if (auto* item2 = dynamic_cast(item.menu)) - menu->addAction(item2->action()); - else if (auto* item3 = dynamic_cast(item.menu)) - menu->addMenu(item3->menu()); - else - continue; - count++; - } - return count; + return addMenuItemsToMenu(menu, FilterMenuItems(agentIds, menuType), context); } int AxScriptManager::AddMenuFileBrowser(QMenu *menu, QVector files) { if (files.empty()) return 0; - QVariantList context; - for (auto file : files) { + QVariantList context; + for (const auto& file : files) { if (adaptixWidget->AgentsMap.contains(file.agentId)) { QVariantMap map; map["agent_id"] = file.agentId; @@ -361,32 +376,15 @@ int AxScriptManager::AddMenuFileBrowser(QMenu *menu, QVector items = this->FilterMenuItems(QStringList() << files[0].agentId, "FileBrowser"); - for (int i = 0; i < items.size(); ++i) { - AxMenuItem item = items[i]; - - item.menu->setContext(context); - if (auto* item1 = dynamic_cast(item.menu)) - menu->addAction(item1->action()); - else if (auto* item2 = dynamic_cast(item.menu)) - menu->addAction(item2->action()); - else if (auto* item3 = dynamic_cast(item.menu)) - menu->addMenu(item3->menu()); - else - continue; - count++; - } - return count; + return addMenuItemsToMenu(menu, FilterMenuItems(QStringList() << files[0].agentId, "FileBrowser"), context); } int AxScriptManager::AddMenuProcessBrowser(QMenu *menu, QVector processes) { if (processes.empty()) return 0; - QVariantList context; - for (auto proc : processes) { + QVariantList context; + for (const auto& proc : processes) { if (adaptixWidget->AgentsMap.contains(proc.agentId)) { QVariantMap map; map["agent_id"] = proc.agentId; @@ -399,24 +397,7 @@ int AxScriptManager::AddMenuProcessBrowser(QMenu *menu, QVector items = this->FilterMenuItems(QStringList() << processes[0].agentId, "ProcessBrowser"); - for (int i = 0; i < items.size(); ++i) { - AxMenuItem item = items[i]; - - item.menu->setContext(context); - if (auto* item1 = dynamic_cast(item.menu)) - menu->addAction(item1->action()); - else if (auto* item2 = dynamic_cast(item.menu)) - menu->addAction(item2->action()); - else if (auto* item3 = dynamic_cast(item.menu)) - menu->addMenu(item3->menu()); - else - continue; - count++; - } - return count; + return addMenuItemsToMenu(menu, FilterMenuItems(QStringList() << processes[0].agentId, "ProcessBrowser"), context); } int AxScriptManager::AddMenuDownload(QMenu *menu, const QString &menuType, QVector files) @@ -424,7 +405,7 @@ int AxScriptManager::AddMenuDownload(QMenu *menu, const QString &menuType, QVect if (files.empty()) return 0; QVariantList context; - for (auto file : files) { + for (const auto& file : files) { if (adaptixWidget->AgentsMap.contains(file.agentId)) { QVariantMap map; map["agent_id"] = file.agentId; @@ -434,24 +415,7 @@ int AxScriptManager::AddMenuDownload(QMenu *menu, const QString &menuType, QVect context << map; } } - - int count = 0; - QList items = this->FilterMenuItems(QStringList() << files[0].agentId, menuType); - for (int i = 0; i < items.size(); ++i) { - AxMenuItem item = items[i]; - - item.menu->setContext(context); - if (auto* item1 = dynamic_cast(item.menu)) - menu->addAction(item1->action()); - else if (auto* item2 = dynamic_cast(item.menu)) - menu->addAction(item2->action()); - else if (auto* item3 = dynamic_cast(item.menu)) - menu->addMenu(item3->menu()); - else - continue; - count++; - } - return count; + return addMenuItemsToMenu(menu, FilterMenuItems(QStringList() << files[0].agentId, menuType), context); } int AxScriptManager::AddMenuTask(QMenu *menu, const QString &menuType, const QStringList &tasks) @@ -459,20 +423,19 @@ int AxScriptManager::AddMenuTask(QMenu *menu, const QString &menuType, const QSt if (tasks.empty()) return 0; QSet agents; - QVariantList context; - for (auto taskId : tasks) { + for (const auto& taskId : tasks) { if (adaptixWidget->TasksMap.contains(taskId)) { TaskData taskData = adaptixWidget->TasksMap[taskId]; QVariantMap map; map["agent_id"] = taskData.AgentId; map["task_id"] = taskData.TaskId; map["state"] = taskData.Status; - if ( taskData.TaskType == 1 ) + if (taskData.TaskType == 1) map["type"] = "TASK"; - else if ( taskData.TaskType == 3 ) + else if (taskData.TaskType == 3) map["type"] = "JOB"; - else if ( taskData.TaskType == 4 ) + else if (taskData.TaskType == 4) map["type"] = "TUNNEL"; else map["type"] = "unknown"; @@ -481,86 +444,35 @@ int AxScriptManager::AddMenuTask(QMenu *menu, const QString &menuType, const QSt agents.insert(taskData.AgentId); } } - - int count = 0; - QList items = this->FilterMenuItems(QList(agents.begin(), agents.end()), menuType); - for (int i = 0; i < items.size(); ++i) { - AxMenuItem item = items[i]; - - item.menu->setContext(context); - if (auto* item1 = dynamic_cast(item.menu)) - menu->addAction(item1->action()); - else if (auto* item2 = dynamic_cast(item.menu)) - menu->addAction(item2->action()); - else if (auto* item3 = dynamic_cast(item.menu)) - menu->addMenu(item3->menu()); - else - continue; - count++; - } - return count; + return addMenuItemsToMenu(menu, FilterMenuItems(QList(agents.begin(), agents.end()), menuType), context); } int AxScriptManager::AddMenuTargets(QMenu *menu, const QString &menuType, const QStringList &targets) { QVariantList context; - for (auto targetId: targets) + for (const auto& targetId: targets) context << targetId; - QList list = this->agents_scripts.values() + this->scripts.values(); - list.append(this->mainScript); - QList items; - for (const auto script : list) - items += script->getMenuItems(menuType); - - int count = 0; - for (int i = 0; i < items.size(); ++i) { - AxMenuItem item = items[i]; - - item.menu->setContext(context); - if (auto* item1 = dynamic_cast(item.menu)) - menu->addAction(item1->action()); - else if (auto* item2 = dynamic_cast(item.menu)) - menu->addAction(item2->action()); - else if (auto* item3 = dynamic_cast(item.menu)) - menu->addMenu(item3->menu()); - else - continue; - count++; + for (const auto script : getAllEngines()) { + if (script) + items += script->getMenuItems(menuType); } - return count; + return addMenuItemsToMenu(menu, items, context); } int AxScriptManager::AddMenuCreds(QMenu *menu, const QString &menuType, const QStringList &creds) { QVariantList context; - for (auto credId: creds) + for (const auto& credId: creds) context << credId; - QList list = this->agents_scripts.values() + this->scripts.values(); - list.append(this->mainScript); - QList items; - for (const auto script : list) - items += script->getMenuItems(menuType); - - int count = 0; - for (int i = 0; i < items.size(); ++i) { - AxMenuItem item = items[i]; - - item.menu->setContext(context); - if (auto* item1 = dynamic_cast(item.menu)) - menu->addAction(item1->action()); - else if (auto* item2 = dynamic_cast(item.menu)) - menu->addAction(item2->action()); - else if (auto* item3 = dynamic_cast(item.menu)) - menu->addMenu(item3->menu()); - else - continue; - count++; + for (const auto script : getAllEngines()) { + if (script) + items += script->getMenuItems(menuType); } - return count; + return addMenuItemsToMenu(menu, items, context); } @@ -568,99 +480,79 @@ int AxScriptManager::AddMenuCreds(QMenu *menu, const QString &menuType, const QS void AxScriptManager::emitNewAgent(const QString &agentId) { - QList items = this->FilterEvents(agentId, "new_agent"); - for (int i = 0; i < items.size(); ++i) { - AxEvent event = items[i]; + for (const auto& event : FilterEvents(agentId, "new_agent")) { if (event.jsEngine) { QJSValue argId = event.jsEngine->toScriptValue(agentId); - event.handler.call(QJSValueList() << argId); + safeCallHandler(event, QJSValueList() << argId); } } } void AxScriptManager::emitFileBrowserDisks(const QString &agentId) { - QList items = this->FilterEvents(agentId, "FileBroserDisks"); - for (int i = 0; i < items.size(); ++i) { - AxEvent event = items[i]; + for (const auto& event : FilterEvents(agentId, "FileBrowserDisks")) { if (event.jsEngine) { QJSValue argId = event.jsEngine->toScriptValue(agentId); - event.handler.call(QJSValueList() << argId); + safeCallHandler(event, QJSValueList() << argId); } } } void AxScriptManager::emitFileBrowserList(const QString &agentId, const QString &path) { - QList items = this->FilterEvents(agentId, "FileBroserList"); - for (int i = 0; i < items.size(); ++i) { - AxEvent event = items[i]; + for (const auto& event : FilterEvents(agentId, "FileBrowserList")) { if (event.jsEngine) { QJSValue argId = event.jsEngine->toScriptValue(agentId); QJSValue argPath = event.jsEngine->toScriptValue(path); - event.handler.call(QJSValueList() << argId << argPath); + safeCallHandler(event, QJSValueList() << argId << argPath); } } } void AxScriptManager::emitFileBrowserUpload(const QString &agentId, const QString &path, const QString &localFilename) { - QList items = this->FilterEvents(agentId, "FileBrowserUpload"); - for (int i = 0; i < items.size(); ++i) { - AxEvent event = items[i]; + for (const auto& event : FilterEvents(agentId, "FileBrowserUpload")) { if (event.jsEngine) { QJSValue argId = event.jsEngine->toScriptValue(agentId); QJSValue argPath = event.jsEngine->toScriptValue(path); QJSValue argFile = event.jsEngine->toScriptValue(localFilename); - event.handler.call(QJSValueList() << argId << argPath << argFile); + safeCallHandler(event, QJSValueList() << argId << argPath << argFile); } } } void AxScriptManager::emitProcessBrowserList(const QString &agentId) { - QList items = this->FilterEvents(agentId, "ProcessBrowserList"); - for (int i = 0; i < items.size(); ++i) { - AxEvent event = items[i]; + for (const auto& event : FilterEvents(agentId, "ProcessBrowserList")) { if (event.jsEngine) { QJSValue argId = event.jsEngine->toScriptValue(agentId); - event.handler.call(QJSValueList() << argId); + safeCallHandler(event, QJSValueList() << argId); } } } void AxScriptManager::emitReadyClient() { - QList list = this->agents_scripts.values() + this->scripts.values(); - list.append(this->mainScript); - QList items; - for (const auto script : list) { - items += script->getEvents("ready"); + for (const auto script : getAllEngines()) { + if (script) + items += script->getEvents("ready"); } - for (int i = 0; i < items.size(); ++i) { - AxEvent event = items[i]; - if (event.jsEngine) - event.handler.call(); - } + for (const auto& event : items) + safeCallHandler(event); } void AxScriptManager::emitDisconnectClient() { - QList list = this->agents_scripts.values() + this->scripts.values(); - list.append(this->mainScript); - QList items; - for (const auto script : list) { - items += script->getEvents("disconnect"); + for (const auto script : getAllEngines()) { + if (script) + items += script->getEvents("disconnect"); } - for (int i = 0; i < items.size(); ++i) { - AxEvent event = items[i]; - if (event.jsEngine) - event.handler.call(); - } + for (const auto& event : items) + safeCallHandler(event); } /// SLOTS diff --git a/AdaptixClient/Source/Client/AxScript/BridgeApp.cpp b/AdaptixClient/Source/Client/AxScript/BridgeApp.cpp index 3d2e27b8..2fb83980 100644 --- a/AdaptixClient/Source/Client/AxScript/BridgeApp.cpp +++ b/AdaptixClient/Source/Client/AxScript/BridgeApp.cpp @@ -5,14 +5,15 @@ #include #include #include +#include #include #include #include #include -BridgeApp::BridgeApp(AxScriptEngine* scriptEngine, QObject* parent) : QObject(parent), scriptEngine(scriptEngine), widget(new QWidget()){} +BridgeApp::BridgeApp(AxScriptEngine* scriptEngine, QObject* parent) : QObject(parent), scriptEngine(scriptEngine) {} -BridgeApp::~BridgeApp() { delete widget; } +BridgeApp::~BridgeApp() = default; AxScriptEngine* BridgeApp::GetScriptEngine() const { return this->scriptEngine; } @@ -115,84 +116,54 @@ QJSValue BridgeApp::agent_info(const QString &id, const QString &property) const void BridgeApp::agent_hide(const QJSValue &agents) { - if (agents.isUndefined() || agents.isNull() || !agents.isArray()) { + if (!AxScriptUtils::isValidArray(agents)) { Q_EMIT engineError("agent_hide expected array of strings in agents parameter!"); return; } - QStringList list_agents; - for (int i = 0; i < agents.property("length").toInt(); ++i) { - QJSValue val = agents.property(i); - list_agents << val.toString(); - } - - scriptEngine->manager()->AppAgentHide(list_agents); + scriptEngine->manager()->AppAgentHide(AxScriptUtils::jsArrayToStringList(agents)); } void BridgeApp::agent_remove(const QJSValue &agents) { - if (agents.isUndefined() || agents.isNull() || !agents.isArray()) { + if (!AxScriptUtils::isValidArray(agents)) { Q_EMIT engineError("agent_remove expected array of strings in agents parameter!"); return; } - QStringList list_agents; - for (int i = 0; i < agents.property("length").toInt(); ++i) { - QJSValue val = agents.property(i); - list_agents << val.toString(); - } - - scriptEngine->manager()->AppAgentRemove(list_agents); + scriptEngine->manager()->AppAgentRemove(AxScriptUtils::jsArrayToStringList(agents)); } void BridgeApp::agent_set_color(const QJSValue &agents, const QString &background, const QString &foreground, const bool reset) { - if (agents.isUndefined() || agents.isNull() || !agents.isArray()) { + if (!AxScriptUtils::isValidArray(agents)) { Q_EMIT engineError("agent_set_color expected array of strings in agents parameter!"); return; } - QStringList list_agents; - for (int i = 0; i < agents.property("length").toInt(); ++i) { - QJSValue val = agents.property(i); - list_agents << val.toString(); - } - - scriptEngine->manager()->AppAgentSetColor(list_agents, background, foreground, reset); + scriptEngine->manager()->AppAgentSetColor(AxScriptUtils::jsArrayToStringList(agents), background, foreground, reset); } void BridgeApp::agent_set_impersonate(const QString &id, const QString &impersonate, const bool elevated) { scriptEngine->manager()->AppAgentSetImpersonate(id, impersonate, elevated); } void BridgeApp::agent_set_mark(const QJSValue &agents, const QString &mark) { - if (agents.isUndefined() || agents.isNull() || !agents.isArray()) { - Q_EMIT engineError("agent_set_color expected array of strings in agents parameter!"); + if (!AxScriptUtils::isValidArray(agents)) { + Q_EMIT engineError("agent_set_mark expected array of strings in agents parameter!"); return; } - QStringList list_agents; - for (int i = 0; i < agents.property("length").toInt(); ++i) { - QJSValue val = agents.property(i); - list_agents << val.toString(); - } - - scriptEngine->manager()->AppAgentSetMark(list_agents, mark); + scriptEngine->manager()->AppAgentSetMark(AxScriptUtils::jsArrayToStringList(agents), mark); } void BridgeApp::agent_set_tag(const QJSValue &agents, const QString &tag) { - if (agents.isUndefined() || agents.isNull() || !agents.isArray()) { - Q_EMIT engineError("agent_set_color expected array of strings in agents parameter!"); + if (!AxScriptUtils::isValidArray(agents)) { + Q_EMIT engineError("agent_set_tag expected array of strings in agents parameter!"); return; } - QStringList list_agents; - for (int i = 0; i < agents.property("length").toInt(); ++i) { - QJSValue val = agents.property(i); - list_agents << val.toString(); - } - - scriptEngine->manager()->AppAgentSetTag(list_agents, tag); + scriptEngine->manager()->AppAgentSetTag(AxScriptUtils::jsArrayToStringList(agents), tag); } QString BridgeApp::arch(const QString &id) const @@ -375,7 +346,7 @@ void BridgeApp::credentials_add_list(const QVariantList &array) if (map.contains("username")) cd.Username = map["username"].toString(); if (map.contains("password")) cd.Password = map["password"].toString(); if (map.contains("realm")) cd.Realm = map["realm"].toString(); - if (map.contains("type")) cd.Tag = map["type"].toString(); + if (map.contains("type")) cd.Type = map["type"].toString(); if (map.contains("tag")) cd.Tag = map["tag"].toString(); if (map.contains("storage")) cd.Storage = map["storage"].toString(); if (map.contains("host")) cd.Host = map["host"].toString(); @@ -636,42 +607,21 @@ int BridgeApp::random_int(const int min, const int max) { return GenerateRandomI void BridgeApp::register_commands_group(QObject *obj, const QJSValue &agents, const QJSValue &os, const QJSValue &listeners) { - QList list_os; - QStringList list_agents; - QStringList list_listeners; - - if (agents.isUndefined() || agents.isNull() || !agents.isArray()) { + if (!AxScriptUtils::isValidArray(agents)) { Q_EMIT engineError("register_commands_group expected array of strings in agents parameter!"); return; } - if (os.isUndefined() && (os.isNull() || !os.isArray()) ) { + if (!AxScriptUtils::isOptionalValidArray(os)) { Q_EMIT engineError("register_commands_group expected array of strings in os parameter!"); return; } - if (listeners.isUndefined() && (listeners.isNull() || !listeners.isArray())) { + if (!AxScriptUtils::isOptionalValidArray(listeners)) { Q_EMIT engineError("register_commands_group expected array of strings in listeners parameter!"); return; } - for (int i = 0; i < os.property("length").toInt(); ++i) { - QJSValue val = os.property(i); - if (val.toString() == "windows") list_os.append(1); - else if (val.toString() == "linux") list_os.append(2); - else if (val.toString() == "macos") list_os.append(3); - } - - for (int i = 0; i < agents.property("length").toInt(); ++i) { - QJSValue val = agents.property(i); - list_agents << val.toString(); - } - - for (int i = 0; i < listeners.property("length").toInt(); ++i) { - QJSValue val = listeners.property(i); - list_listeners << val.toString(); - } - auto wrapper = qobject_cast(obj); if (!wrapper) { Q_EMIT engineError("register_commands_group no support object type!"); @@ -684,7 +634,12 @@ void BridgeApp::register_commands_group(QObject *obj, const QJSValue &agents, co commandsGroup.engine = wrapper->getEngine(); commandsGroup.filepath = scriptEngine->context.name; - scriptEngine->manager()->RegisterCommandsGroup(commandsGroup, list_listeners, list_agents, list_os); + scriptEngine->manager()->RegisterCommandsGroup( + commandsGroup, + AxScriptUtils::jsArrayToStringList(listeners), + AxScriptUtils::jsArrayToStringList(agents), + AxScriptUtils::parseOsList(os) + ); } void BridgeApp::script_import(const QString &path) diff --git a/AdaptixClient/Source/Client/AxScript/BridgeEvent.cpp b/AdaptixClient/Source/Client/AxScript/BridgeEvent.cpp index 8e31a832..7273ed36 100644 --- a/AdaptixClient/Source/Client/AxScript/BridgeEvent.cpp +++ b/AdaptixClient/Source/Client/AxScript/BridgeEvent.cpp @@ -1,6 +1,7 @@ #include #include #include +#include BridgeEvent::BridgeEvent(AxScriptEngine* scriptEngine, QObject* parent) : QObject(parent), scriptEngine(scriptEngine) {} @@ -9,37 +10,18 @@ BridgeEvent::~BridgeEvent() {} void BridgeEvent::reg(const QString &event, const QString &type, const QJSValue &handler, const QJSValue &agents, const QJSValue &os, const QJSValue &listeners, const QString &event_id) { if (!handler.isCallable()) { - Q_EMIT scriptError( type + " -> handler in not Callable"); + Q_EMIT scriptError(type + " -> handler is not Callable"); return; } - QSet list_agents; - QSet list_os; - QSet list_listeners; - - if (agents.isUndefined() || agents.isNull() || !agents.isArray() || agents.property("length").toInt() == 0) { - Q_EMIT scriptError(type + " -> agents in undefined"); + if (!AxScriptUtils::isValidNonEmptyArray(agents)) { + Q_EMIT scriptError(type + " -> agents is undefined or empty"); return; } - for (int i = 0; i < agents.property("length").toInt(); ++i) { - QJSValue val = agents.property(i); - list_agents.insert(val.toString()); - } - - if (!os.isUndefined() && !os.isNull() && os.isArray()) { - for (int i = 0; i < os.property("length").toInt(); ++i) { - QJSValue val = os.property(i); - list_os << val.toString(); - } - } - - if (!listeners.isUndefined() && !listeners.isNull() && listeners.isArray()) { - for (int i = 0; i < listeners.property("length").toInt(); ++i) { - QJSValue val = listeners.property(i); - list_listeners << val.toString(); - } - } + QSet list_agents = AxScriptUtils::jsArrayToStringSet(agents); + QSet list_os = AxScriptUtils::jsArrayToStringSet(os); + QSet list_listeners = AxScriptUtils::jsArrayToStringSet(listeners); this->scriptEngine->registerEvent(event, handler, nullptr, list_agents, list_os, list_listeners, event_id); } @@ -47,11 +29,11 @@ void BridgeEvent::reg(const QString &event, const QString &type, const QJSValue void BridgeEvent::on_filebrowser_disks(const QJSValue &handler, const QJSValue &agents, const QJSValue &os, const QJSValue &listeners, const QString &event_id) { - this->reg("FileBroserDisks", "on_filebrowser_disks", handler, agents, os, listeners, event_id); + this->reg("FileBrowserDisks", "on_filebrowser_disks", handler, agents, os, listeners, event_id); } void BridgeEvent::on_filebrowser_list(const QJSValue &handler, const QJSValue &agents, const QJSValue &os, const QJSValue &listeners, const QString &event_id) { - this->reg("FileBroserList", "on_filebrowser_list", handler, agents, os, listeners, event_id); + this->reg("FileBrowserList", "on_filebrowser_list", handler, agents, os, listeners, event_id); } void BridgeEvent::on_filebrowser_upload(const QJSValue &handler, const QJSValue &agents, const QJSValue &os, const QJSValue &listeners, const QString &event_id) { @@ -68,24 +50,30 @@ void BridgeEvent::on_new_agent(const QJSValue &handler, const QJSValue &agents, void BridgeEvent::on_ready(const QJSValue &handler, const QString &event_id) { - if (!handler.isCallable()) - Q_EMIT scriptError("on_ready -> handler in not Callable"); + if (!handler.isCallable()) { + Q_EMIT scriptError("on_ready -> handler is not Callable"); + return; + } this->scriptEngine->registerEvent("ready", handler, nullptr, QSet(), QSet(), QSet(), event_id); } void BridgeEvent::on_disconnect(const QJSValue &handler, const QString &event_id) { - if (!handler.isCallable()) - Q_EMIT scriptError("on_disconnect -> handler in not Callable"); + if (!handler.isCallable()) { + Q_EMIT scriptError("on_disconnect -> handler is not Callable"); + return; + } this->scriptEngine->registerEvent("disconnect", handler, nullptr, QSet(), QSet(), QSet(), event_id); } QString BridgeEvent::on_interval(const QJSValue &handler, int delay, QString event_id) { - if (!handler.isCallable()) - Q_EMIT scriptError("on_timer -> handler in not Callable"); + if (!handler.isCallable()) { + Q_EMIT scriptError("on_interval -> handler is not Callable"); + return ""; + } if (delay < 0) delay = 0; if (event_id == "") event_id = "interval_" + GenerateRandomString(8, "hex"); @@ -104,8 +92,10 @@ QString BridgeEvent::on_interval(const QJSValue &handler, int delay, QString eve QString BridgeEvent::on_timeout(const QJSValue &handler, int delay, QString event_id) { - if (!handler.isCallable()) - Q_EMIT scriptError("on_timeout -> handler in not Callable"); + if (!handler.isCallable()) { + Q_EMIT scriptError("on_timeout -> handler is not Callable"); + return ""; + } if (delay < 0) delay = 0; if (event_id == "") event_id = "timeout_" + GenerateRandomString(8, "hex"); diff --git a/AdaptixClient/Source/Client/AxScript/BridgeMenu.cpp b/AdaptixClient/Source/Client/AxScript/BridgeMenu.cpp index 58d38e78..141ac3e4 100644 --- a/AdaptixClient/Source/Client/AxScript/BridgeMenu.cpp +++ b/AdaptixClient/Source/Client/AxScript/BridgeMenu.cpp @@ -1,38 +1,20 @@ #include #include #include +#include -BridgeMenu::BridgeMenu(AxScriptEngine* scriptEngine, QObject* parent) : QObject(parent), scriptEngine(scriptEngine), widget(new QWidget()) {} +BridgeMenu::BridgeMenu(AxScriptEngine* scriptEngine, QObject* parent) : QObject(parent), scriptEngine(scriptEngine) {} -BridgeMenu::~BridgeMenu() { delete widget; } +BridgeMenu::~BridgeMenu() = default; void BridgeMenu::reg(const QString &type, AbstractAxMenuItem *item, const QJSValue &agents, const QJSValue &os, const QJSValue &listeners) { - QSet list_agents; - QSet list_os; - QSet list_listeners; - - if (agents.isUndefined() || agents.isNull() || !agents.isArray() || agents.property("length").toInt() == 0) + if (!AxScriptUtils::isValidNonEmptyArray(agents)) return; - for (int i = 0; i < agents.property("length").toInt(); ++i) { - QJSValue val = agents.property(i); - list_agents.insert(val.toString()); - } - - if (!os.isUndefined() && !os.isNull() && os.isArray()) { - for (int i = 0; i < os.property("length").toInt(); ++i) { - QJSValue val = os.property(i); - list_os << val.toString(); - } - } - - if (!listeners.isUndefined() && !listeners.isNull() && listeners.isArray()) { - for (int i = 0; i < listeners.property("length").toInt(); ++i) { - QJSValue val = listeners.property(i); - list_listeners << val.toString(); - } - } + QSet list_agents = AxScriptUtils::jsArrayToStringSet(agents); + QSet list_os = AxScriptUtils::jsArrayToStringSet(os); + QSet list_listeners = AxScriptUtils::jsArrayToStringSet(listeners); this->scriptEngine->registerMenu(type, item, list_agents, list_os, list_listeners); }