From 0f435d32afee81535d49edffaa1da2ad6484a687 Mon Sep 17 00:00:00 2001 From: Christophe Deschamps Date: Wed, 9 Apr 2025 14:32:00 +0100 Subject: [PATCH] Command line to run upon incoming call --- Linphone/core/setting/SettingsCore.cpp | 8 +++ Linphone/core/setting/SettingsCore.hpp | 2 + Linphone/data/languages/en.ts | 12 +++++ Linphone/data/languages/fr_FR.ts | 12 +++++ Linphone/model/core/CoreModel.cpp | 10 ++++ Linphone/model/setting/SettingsModel.cpp | 15 ++++++ Linphone/model/setting/SettingsModel.hpp | 2 + Linphone/tool/Utils.cpp | 51 ++++++++++++++++++- Linphone/tool/Utils.hpp | 4 ++ .../Layout/Settings/CallSettingsLayout.qml | 11 ++++ 10 files changed, 126 insertions(+), 1 deletion(-) diff --git a/Linphone/core/setting/SettingsCore.cpp b/Linphone/core/setting/SettingsCore.cpp index 88e4b45e8..af50e2698 100644 --- a/Linphone/core/setting/SettingsCore.cpp +++ b/Linphone/core/setting/SettingsCore.cpp @@ -122,6 +122,8 @@ SettingsCore::SettingsCore(QObject *parent) : QObject(parent) { INIT_CORE_MEMBER(ShortcutCount, settingsModel) INIT_CORE_MEMBER(Shortcuts, settingsModel) INIT_CORE_MEMBER(CallToneIndicationsEnabled, settingsModel) + INIT_CORE_MEMBER(CommandLine, settingsModel) + INIT_CORE_MEMBER(DisableCommandLine, settingsModel) } SettingsCore::SettingsCore(const SettingsCore &settingsCore) { @@ -194,6 +196,8 @@ SettingsCore::SettingsCore(const SettingsCore &settingsCore) { mShortcutCount = settingsCore.mShortcutCount; mShortcuts = settingsCore.mShortcuts; mCallToneIndicationsEnabled = settingsCore.mCallToneIndicationsEnabled; + mCommandLine = settingsCore.mCommandLine; + mDisableCommandLine = settingsCore.mDisableCommandLine; mDefaultDomain = settingsCore.mDefaultDomain; mShowAccountDevices = settingsCore.mShowAccountDevices; @@ -409,6 +413,10 @@ void SettingsCore::setSelf(QSharedPointer me) { shortcuts, Shortcuts) DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool, callToneIndicationsEnabled, CallToneIndicationsEnabled) + DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, QString, + commandLine, CommandLine) + DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool, + disableCommandLine, DisableCommandLine) auto coreModelConnection = SafeConnection::create(me, CoreModel::getInstance()); diff --git a/Linphone/core/setting/SettingsCore.hpp b/Linphone/core/setting/SettingsCore.hpp index 6a425d3ff..94324e9f9 100644 --- a/Linphone/core/setting/SettingsCore.hpp +++ b/Linphone/core/setting/SettingsCore.hpp @@ -229,6 +229,8 @@ public: DECLARE_CORE_MEMBER(int, shortcutCount, ShortcutCount) DECLARE_CORE_MEMBER(QVariantList, shortcuts, Shortcuts) DECLARE_CORE_GETSET_MEMBER(bool, callToneIndicationsEnabled, CallToneIndicationsEnabled) + DECLARE_CORE_GETSET_MEMBER(bool, disableCommandLine, DisableCommandLine) + DECLARE_CORE_GETSET_MEMBER(QString, commandLine, CommandLine) signals: diff --git a/Linphone/data/languages/en.ts b/Linphone/data/languages/en.ts index 3ffc98f5a..5ab0b5513 100644 --- a/Linphone/data/languages/en.ts +++ b/Linphone/data/languages/en.ts @@ -1101,6 +1101,18 @@ "Autoriser la vidéo" Enable video + + + settings_calls_command_line_title + "Redirection vers outil externe lors d'un appel entrant" + Command Line to run upon incoming call + + + + settings_calls_command_line_title_place_holder + "commande "https://exemple.com/?numero=$1&nom=$2"" + command "https://example.com/?phone=$1&displayName=$2" + CallStatistics diff --git a/Linphone/data/languages/fr_FR.ts b/Linphone/data/languages/fr_FR.ts index 816f0617d..caaeed709 100644 --- a/Linphone/data/languages/fr_FR.ts +++ b/Linphone/data/languages/fr_FR.ts @@ -1101,6 +1101,18 @@ "Autoriser la vidéo" Autoriser la vidéo + + + settings_calls_command_line_title + "Redirection vers outil externe lors d'un appel entrant" + Redirection vers outil externe lors d'un appel entrant. + + + + settings_calls_command_line_title_place_holder + "commande "https://exemple.com/?numero=$1&nom=$2"" + commande "https://exemple.com/?numero=$1&nom=$2" + CallStatistics diff --git a/Linphone/model/core/CoreModel.cpp b/Linphone/model/core/CoreModel.cpp index 357ae1f8b..451455197 100644 --- a/Linphone/model/core/CoreModel.cpp +++ b/Linphone/model/core/CoreModel.cpp @@ -410,6 +410,16 @@ void CoreModel::onCallStateChanged(const std::shared_ptr &core, const std::string &message) { if (state == linphone::Call::State::IncomingReceived) { App::getInstance()->getNotifier()->notifyReceivedCall(call); + if (!core->getConfig()->getBool(SettingsModel::UiSection, "disable_command_line", false) && + !core->getConfig()->getString(SettingsModel::UiSection, "command_line", "").empty()) { + QString command = Utils::coreStringToAppString( + core->getConfig()->getString(SettingsModel::UiSection, "command_line", "")); + QString userName = Utils::coreStringToAppString(call->getRemoteAddress()->getUsername()); + QString displayName = Utils::coreStringToAppString(call->getRemoteAddress()->getDisplayName()); + command = command.replace("$1", userName); + command = command.replace("$2", displayName); + Utils::runCommandLine(command); + } } if (state == linphone::Call::State::End && SettingsModel::dndEnabled(core->getConfig()) && core->getCallsNb() == 0) { // Disable tones in DND mode if no more calls are running. diff --git a/Linphone/model/setting/SettingsModel.cpp b/Linphone/model/setting/SettingsModel.cpp index b6d74a53f..8d19ad926 100644 --- a/Linphone/model/setting/SettingsModel.cpp +++ b/Linphone/model/setting/SettingsModel.cpp @@ -732,6 +732,8 @@ void SettingsModel::notifyConfigReady(){ DEFINE_NOTIFY_CONFIG_READY(shortcuts, Shortcuts) DEFINE_NOTIFY_CONFIG_READY(usernameOnlyForLdapLookupsInCalls, UsernameOnlyForLdapLookupsInCalls) DEFINE_NOTIFY_CONFIG_READY(usernameOnlyForCardDAVLookupsInCalls, UsernameOnlyForCardDAVLookupsInCalls) + DEFINE_NOTIFY_CONFIG_READY(commandLine, CommandLine) + DEFINE_NOTIFY_CONFIG_READY(disableCommandLine, DisableCommandLine) } DEFINE_GETSET_CONFIG(SettingsModel, bool, Bool, disableChatFeature, DisableChatFeature, "disable_chat_feature", true) @@ -860,4 +862,17 @@ DEFINE_GETSET_CONFIG(SettingsModel, UsernameOnlyForCardDAVLookupsInCalls, "username_only_for_carddav_lookups_in_calls", false) +DEFINE_GETSET_CONFIG_STRING(SettingsModel, + commandLine, + CommandLine, + "command_line", + "") +DEFINE_GETSET_CONFIG(SettingsModel, + bool, + Bool, + disableCommandLine, + DisableCommandLine, + "disable_command_line", + false) + // clang-format on diff --git a/Linphone/model/setting/SettingsModel.hpp b/Linphone/model/setting/SettingsModel.hpp index d833b36dc..dcab5025e 100644 --- a/Linphone/model/setting/SettingsModel.hpp +++ b/Linphone/model/setting/SettingsModel.hpp @@ -184,6 +184,8 @@ public: DECLARE_GETSET(QVariantList, shortcuts, Shortcuts) DECLARE_GETSET(bool, usernameOnlyForLdapLookupsInCalls, UsernameOnlyForLdapLookupsInCalls) DECLARE_GETSET(bool, usernameOnlyForCardDAVLookupsInCalls, UsernameOnlyForCardDAVLookupsInCalls) + DECLARE_GETSET(QString, commandLine, CommandLine) + DECLARE_GETSET(bool, disableCommandLine, DisableCommandLine) signals: void logsUploadUrlChanged(); diff --git a/Linphone/tool/Utils.cpp b/Linphone/tool/Utils.cpp index c58024baa..be4ac176f 100644 --- a/Linphone/tool/Utils.cpp +++ b/Linphone/tool/Utils.cpp @@ -40,10 +40,18 @@ #include #include #include +#include #include #include #include +#ifdef Q_OS_WIN +#ifndef NOMINMAX +#define NOMINMAX 1 +#endif +#include +#endif + DEFINE_ABSTRACT_OBJECT(Utils) // ============================================================================= @@ -1440,7 +1448,7 @@ QList Utils::append(const QList a, const QList b) QString Utils::getAddressToDisplay(QVariantList addressList, QString filter, QString defaultAddress) { if (filter.isEmpty()) return defaultAddress; - for (auto& item: addressList) { + for (auto &item : addressList) { QString address = item.toMap()["address"].toString(); if (address.contains(filter)) return address; } @@ -1497,3 +1505,44 @@ Utils::createFriendDeviceVariant(const QString &name, const QString &address, Li map.insert("securityLevel", QVariant::fromValue(level)); return map; } + +// CLI + +void Utils::runCommandLine(const QString command) { + QStringList arguments; + QString program; + +#ifdef Q_OS_WIN + std::wstring fullCommand = std::wstring(L"cmd.exe /C ") + command.toStdWString(); + STARTUPINFOW si; + PROCESS_INFORMATION pi; + ZeroMemory(&si, sizeof(si)); + ZeroMemory(&pi, sizeof(pi)); + si.cb = sizeof(si); + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; + + BOOL success = CreateProcessW(nullptr, // Application name + fullCommand.data(), // Command line (mutable) + nullptr, // Process security attributes + nullptr, // Primary thread security attributes + FALSE, // Inherit handles + CREATE_NO_WINDOW, // Creation flags (hide window) + nullptr, // Environment + nullptr, // Current directory + &si, // STARTUPINFO + &pi // PROCESS_INFORMATION + ); + + if (success) { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } else { + lWarning() << "Failed to start process. GetLastError() =" << (int)GetLastError(); + } +#elif defined(Q_OS_MACOS) || defined(Q_OS_LINUX) + QProcess::startDetached("/bin/sh", {"-c", command}); +#else + lWarning() << "Unsupported OS!"; +#endif +} diff --git a/Linphone/tool/Utils.hpp b/Linphone/tool/Utils.hpp index 9f81a823b..c8b60b5fe 100644 --- a/Linphone/tool/Utils.hpp +++ b/Linphone/tool/Utils.hpp @@ -186,6 +186,10 @@ public: static QVariantMap createFriendDeviceVariant(const QString &name, const QString &address, LinphoneEnums::SecurityLevel level); + // CLI + + static void runCommandLine(QString command); + private: DECLARE_ABSTRACT_OBJECT }; diff --git a/Linphone/view/Page/Layout/Settings/CallSettingsLayout.qml b/Linphone/view/Page/Layout/Settings/CallSettingsLayout.qml index 64bc428b4..fa0d676af 100644 --- a/Linphone/view/Page/Layout/Settings/CallSettingsLayout.qml +++ b/Linphone/view/Page/Layout/Settings/CallSettingsLayout.qml @@ -68,6 +68,17 @@ AbstractSettingsLayout { propertyName: "videoEnabled" propertyOwner: SettingsCpp } + DecoratedTextField { + visible: !SettingsCpp.disableCommandLine + Layout.fillWidth: true + propertyName: "commandLine" + propertyOwner: SettingsCpp + //: Command line + title: qsTr("settings_calls_command_line_title") + placeHolder: qsTr("settings_calls_command_line_title_place_holder") + useTitleAsPlaceHolder: false + toValidate: true + } } }