From 646f0fe3b94cd3bfc576dee13f4a09ebbfd27222 Mon Sep 17 00:00:00 2001 From: Nicolas Follet Date: Wed, 14 Jun 2017 14:34:45 +0200 Subject: [PATCH] feat(App): supports commands and conferences with id --- assets/languages/en.ts | 8 + assets/languages/fr.ts | 8 + assets/linphone.desktop | 1 + cmake_builder/linphone_package/CMakeLists.txt | 3 +- cmake_builder/linphone_package/Info.plist.in | 75 ++++---- cmake_builder/linphone_package/uninstall.nsi | 2 + .../uri-handler-install.nsi.in | 13 ++ src/app/App.cpp | 54 ++++-- src/app/App.hpp | 9 +- src/app/AppController.cpp | 5 + src/app/cli/Cli.cpp | 163 ++++++++++++++---- src/app/cli/Cli.hpp | 35 ++-- src/components/calls/CallsListModel.cpp | 54 +++++- src/components/calls/CallsListModel.hpp | 2 +- .../conference/ConferenceHelperModel.cpp | 1 - .../conference/ConferenceHelperModel.hpp | 14 +- src/utils/Utils.hpp | 41 +++++ submodules/bcmatroska2 | 2 +- submodules/belcard | 2 +- submodules/belle-sip | 2 +- submodules/belr | 2 +- submodules/linphone | 2 +- 22 files changed, 387 insertions(+), 111 deletions(-) create mode 100644 cmake_builder/linphone_package/uri-handler-install.nsi.in diff --git a/assets/languages/en.ts b/assets/languages/en.ts index f3715d375..387755f89 100644 --- a/assets/languages/en.ts +++ b/assets/languages/en.ts @@ -421,6 +421,14 @@ Server url not configured. showFunctionCall + + joinConferenceFunctionDescription + + + + initiateConferenceFunctionDescription + + CodecsViewer diff --git a/assets/languages/fr.ts b/assets/languages/fr.ts index 3ec1c7674..7b0442fba 100644 --- a/assets/languages/fr.ts +++ b/assets/languages/fr.ts @@ -421,6 +421,14 @@ Url du serveur non configurée. showFunctionCall + + joinConferenceFunctionDescription + + + + initiateConferenceFunctionDescription + + CodecsViewer diff --git a/assets/linphone.desktop b/assets/linphone.desktop index 8235d9514..98e74659d 100644 --- a/assets/linphone.desktop +++ b/assets/linphone.desktop @@ -7,6 +7,7 @@ Exec=linphone %u Icon=linphone Terminal=false Categories=Network;Telephony; +MimeType=x-scheme-handler/sip-linphone;x-scheme-handler/sip; # Translations diff --git a/cmake_builder/linphone_package/CMakeLists.txt b/cmake_builder/linphone_package/CMakeLists.txt index 8882375e3..d4abf17da 100644 --- a/cmake_builder/linphone_package/CMakeLists.txt +++ b/cmake_builder/linphone_package/CMakeLists.txt @@ -310,7 +310,8 @@ if(WIN32) string(REPLACE "\\" "\\\\" ESCAPED_DOS_STYLE_SOURCE_DIR "${DOS_STYLE_SOURCE_DIR}") file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}" DOS_STYLE_BINARY_DIR) string(REPLACE "\\" "\\\\" ESCAPED_DOS_STYLE_BINARY_DIR "${DOS_STYLE_BINARY_DIR}") - + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/uri-handler-install.nsi.in" "${CMAKE_CURRENT_BINARY_DIR}/uri-handler-install.nsi" @ONLY) + set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "!include \\\"${ESCAPED_DOS_STYLE_BINARY_DIR}\\\\uri-handler-install.nsi\\\"") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/uninstall.nsi" "${CMAKE_CURRENT_BINARY_DIR}/uninstall.nsi" COPYONLY) set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "!include \\\"${ESCAPED_DOS_STYLE_BINARY_DIR}\\\\uninstall.nsi\\\"") if(ENABLE_OPENH264) diff --git a/cmake_builder/linphone_package/Info.plist.in b/cmake_builder/linphone_package/Info.plist.in index 18ac851cc..956a842eb 100644 --- a/cmake_builder/linphone_package/Info.plist.in +++ b/cmake_builder/linphone_package/Info.plist.in @@ -1,37 +1,48 @@ - + - CFBundleDevelopmentRegion - English - CFBundleName - Linphone - CFBundleDisplayName - Linphone - CFBundleExecutable - linphone - CFBundleGetInfoString - @PACKAGE_VERSION@, (C) 2011-2017 The linphone team http://www.linphone.org - CFBundleIconFile - linphone.icns - CFBundleIdentifier - org.linphone.linphone - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - APPL - CFBundleShortVersionString - @PACKAGE_VERSION@ - CFBundleSignature - ???? - CFBundleVersion - @PACKAGE_VERSION@ - NSHumanReadableCopyright - Copyright 2011-2017 Belledonne Communications - LSMinimumSystemVersion - @CMAKE_OSX_DEPLOYMENT_TARGET@ - NSAppSleepDisabled - YES + CFBundleDevelopmentRegion + English + CFBundleName + Linphone + CFBundleDisplayName + Linphone + CFBundleExecutable + linphone + CFBundleGetInfoString + @PACKAGE_VERSION@, (C) 2011-2017 The linphone team http://www.linphone.org + CFBundleIconFile + linphone.icns + CFBundleIdentifier + org.linphone.linphone + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleShortVersionString + @PACKAGE_VERSION@ + CFBundleSignature + ???? + CFBundleVersion + @PACKAGE_VERSION@ + NSHumanReadableCopyright + Copyright 2011-2017 Belledonne Communications + LSMinimumSystemVersion + @CMAKE_OSX_DEPLOYMENT_TARGET@ + NSAppSleepDisabled + YES + CFBundleURLTypes + + + CFBundleURLName + com.belldonnecommunications.linphone + CFBundleURLSchemes + + sip + sip-linphone + + + - diff --git a/cmake_builder/linphone_package/uninstall.nsi b/cmake_builder/linphone_package/uninstall.nsi index 0645bb0d8..84a21ede6 100644 --- a/cmake_builder/linphone_package/uninstall.nsi +++ b/cmake_builder/linphone_package/uninstall.nsi @@ -5,3 +5,5 @@ Abort notRunningInUninstall: +DeleteRegKey HKCR "sip" +DeleteRegKey HKCR "sip-linphone" diff --git a/cmake_builder/linphone_package/uri-handler-install.nsi.in b/cmake_builder/linphone_package/uri-handler-install.nsi.in new file mode 100644 index 000000000..871a8de96 --- /dev/null +++ b/cmake_builder/linphone_package/uri-handler-install.nsi.in @@ -0,0 +1,13 @@ +WriteRegStr HKCR "sip" "" "URL:sip Protocol" +WriteRegStr HKCR "sip" "URL Protocol" "" +WriteRegExpandStr HKCR "sip\DefaultIcon" "" "@LINPHONE_DESKTOP_DIR@/assets/linphone.ico,1" +WriteRegStr HKCR "sip\shell" "" "open" +WriteRegStr HKCR "sip\shell\open" "" "command" +WriteRegStr HKCR "sip\shell\open\command" "" "$INSTDIR\bin\linphone.exe $\"%1$\"" + +WriteRegStr HKCR "sip-linphone" "" "URL:sip-linphone Protocol" +WriteRegStr HKCR "sip-linphone" "URL Protocol" "" +WriteRegExpandStr HKCR "sip-linphone\DefaultIcon" "" "@LINPHONE_DESKTOP_DIR@/assets/linphone.ico,1" +WriteRegStr HKCR "sip-linphone\shell" "" "open" +WriteRegStr HKCR "sip-linphone\shell\open" "" "command" +WriteRegStr HKCR "sip-linphone\shell\open\command" "" "$INSTDIR\bin\linphone.exe $\"%1$\"" \ No newline at end of file diff --git a/src/app/App.cpp b/src/app/App.cpp index aa029324b..09e43ba7a 100644 --- a/src/app/App.cpp +++ b/src/app/App.cpp @@ -215,6 +215,13 @@ void App::initContentApp () { if (mEngine->rootObjects().isEmpty()) qFatal("Unable to open main window."); + // Execute command argument if needed. + { + const QString commandArgument = getCommandArgument(); + if (!commandArgument.isEmpty()) + mCli->executeCommand(commandArgument); + } + QObject::connect( CoreManager::getInstance()->getHandlers().get(), &CoreHandlers::coreStarted, @@ -225,13 +232,39 @@ void App::initContentApp () { // ----------------------------------------------------------------------------- QString App::getCommandArgument () { - // TODO: Remove me when cmd option will be available. - return QString(""); - // return mParser->value("cmd"); + const QStringList &arguments = mParser->positionalArguments(); + return arguments.empty() ? QString("") : arguments[0]; } // ----------------------------------------------------------------------------- +void App::executeCommand (const QString &command) { + Q_CHECK_PTR(mCli); + mCli->executeCommand(command); +} + +// ----------------------------------------------------------------------------- + +#ifdef Q_OS_MACOS + + bool App::event (QEvent *event) { + if (event->type() == QEvent::FileOpen) { + const QString url = static_cast(event)->url().toString(); + if (isSecondary()) { + sendMessage(url.toLocal8Bit(), -1); + ::exit(EXIT_SUCCESS); + } + + executeCommand(url); + } + + return SingleApplication::event(event); + } + +#endif // ifdef Q_OS_MACOS + +// ----------------------------------------------------------------------------- + QQuickWindow *App::getCallsWindow () { if (!mCallsWindow) mCallsWindow = ::createSubWindow(mEngine, QML_VIEW_CALLS_WINDOW); @@ -281,30 +314,19 @@ bool App::hasFocus () const { // ----------------------------------------------------------------------------- void App::createParser () { - // TODO: Remove me in the future. - static const char *disabledOptions[] = { - QT_TR_NOOP("commandLineOptionCmd"), - QT_TR_NOOP("commandLineOptionCmdArg") - }; - (void)disabledOptions; - - if (mParser) - delete mParser; + delete mParser; mParser = new QCommandLineParser(); - mParser->setApplicationDescription(tr("applicationDescription")); mParser->addOptions({ { { "h", "help" }, tr("commandLineOptionHelp") }, { { "v", "version" }, tr("commandLineOptionVersion") }, { "config", tr("commandLineOptionConfig"), tr("commandLineOptionConfigArg") }, + { { "c", "cmd" }, tr("commandLineOptionCmd"), tr("commandLineOptionCmdArg") }, #ifndef Q_OS_MACOS { "iconified", tr("commandLineOptionIconified") }, #endif // ifndef Q_OS_MACOS { { "V", "verbose" }, tr("commandLineOptionVerbose") } - // TODO: Enable me in future version! - // , - // { { "c", "cmd" }, tr("commandLineOptionCmd"), tr("commandLineOptionCmdArg") } }); } diff --git a/src/app/App.hpp b/src/app/App.hpp index 06d825e40..3ef9fce75 100644 --- a/src/app/App.hpp +++ b/src/app/App.hpp @@ -54,6 +54,11 @@ public: void initContentApp (); QString getCommandArgument (); + void executeCommand (const QString &command); + + #ifdef Q_OS_MACOS + bool event (QEvent *event) override; + #endif // ifdef Q_OS_MACOS QQmlEngine *getEngine () { return mEngine; @@ -117,11 +122,11 @@ private: return qVersion(); } - QCommandLineParser *mParser = nullptr; - QVariantList mAvailableLocales; QString mLocale; + QCommandLineParser *mParser = nullptr; + QQmlApplicationEngine *mEngine = nullptr; DefaultTranslator *mTranslator = nullptr; diff --git a/src/app/AppController.cpp b/src/app/AppController.cpp index 7453b3e6f..f63c7478e 100644 --- a/src/app/AppController.cpp +++ b/src/app/AppController.cpp @@ -84,8 +84,13 @@ AppController::AppController (int &argc, char *argv[]) { mApp = new App(argc, argv); if (mApp->isSecondary()) { + #ifdef Q_OS_MACOS + mApp->processEvents(); + #endif // ifdef Q_OS_MACOS + QString command = mApp->getCommandArgument(); mApp->sendMessage(command.isEmpty() ? "show" : command.toLocal8Bit(), -1); + return; } diff --git a/src/app/cli/Cli.cpp b/src/app/cli/Cli.cpp index d3115be12..deeb73ab8 100644 --- a/src/app/cli/Cli.cpp +++ b/src/app/cli/Cli.cpp @@ -20,9 +20,8 @@ * Author: Nicolas Follet */ -#include - #include "../../components/core/CoreManager.hpp" +#include "../../utils/Utils.hpp" #include "../App.hpp" #include "Cli.hpp" @@ -33,13 +32,64 @@ using namespace std; // API. // ============================================================================= -static void cliShow (const QHash &) { +static void cliShow (QHash &) { App *app = App::getInstance(); app->smartShowWindow(app->getMainWindow()); } -static void cliCall (const QHash &args) { - CoreManager::getInstance()->getCallsListModel()->launchAudioCall(args["sipAddress"]); +static void cliCall (QHash &args) { + CoreManager::getInstance()->getCallsListModel()->launchAudioCall(args["sip-address"]); +} + +static void cliJoinConference (QHash &args) { + const QString sipAddress = args.take("sip-address"); + args["method"] = QStringLiteral("join-conference"); + CoreManager::getInstance()->getCallsListModel()->launchAudioCall(sipAddress, args); +} + +static void cliInitiateConference (QHash &args) { + shared_ptr core = CoreManager::getInstance()->getCore(); + + // Check identity. + { + shared_ptr address = core->interpretUrl(::Utils::appStringToCoreString(args["sip-address"])); + address->clean(); + + const string sipAddress = address->asString(); + const string identity = core->getIdentity(); + if (sipAddress != identity) { + qWarning() << QStringLiteral("Received different sip address from identity : `%1 != %2`.") + .arg(::Utils::coreStringToAppString(identity)) + .arg(::Utils::coreStringToAppString(sipAddress)); + return; + } + } + + shared_ptr conference = core->getConference(); + const QString id = args["conference-id"]; + + if (conference) { + if (conference->getId() == ::Utils::appStringToCoreString(id)) { + qInfo() << QStringLiteral("Conference `%1` already exists.").arg(id); + // TODO: Set the view to the "waiting call view". + return; + } + + qInfo() << QStringLiteral("Remove existing conference with id: `%1`.") + .arg(::Utils::coreStringToAppString(conference->getId())); + core->terminateConference(); + } + + qInfo() << QStringLiteral("Create conference with id: `%1`.").arg(id); + conference = core->createConferenceWithParams(core->createConferenceParams()); + conference->setId(::Utils::appStringToCoreString(id)); + + if (core->enterConference() == -1) { + qWarning() << QStringLiteral("Unable to join created conference: `%1`.").arg(id); + return; + } + + // TODO: Set the view to the "waiting call view". } // ============================================================================= @@ -55,7 +105,18 @@ Cli::Command::Command ( mFunction(function), mArgsScheme(argsScheme) {} -void Cli::Command::execute (const QHash &args) { +void Cli::Command::execute (QHash &args) const { + // Check arguments validity. + for (const auto &argName : args.keys()) { + if (!mArgsScheme.contains(argName)) { + qWarning() << QStringLiteral("Command with invalid argument: `%1 (%2)`.") + .arg(mFunctionName).arg(argName); + + return; + } + } + + // Check missing arguments. for (const auto &argName : mArgsScheme.keys()) { if (!args.contains(argName) && !mArgsScheme[argName].isOptional) { qWarning() << QStringLiteral("Missing argument for command: `%1 (%2)`.") @@ -64,14 +125,34 @@ void Cli::Command::execute (const QHash &args) { } } - (*mFunction)(args); + // Execute! + CoreManager *coreManager = CoreManager::getInstance(); + + if (coreManager->started()) + (*mFunction)(args); + else { + Function f = mFunction; + ::Utils::connectOnce(coreManager->getHandlers().get(), &CoreHandlers::coreStarted, coreManager, [f, args] { + QHash fuckConst = args; + (*f)(fuckConst); + }); + } +} + +void Cli::Command::executeUri (const shared_ptr &address) const { + QHash args; + for (const auto &argName : mArgsScheme.keys()) + args[argName] = ::Utils::coreStringToAppString(address->getHeader(::Utils::appStringToCoreString(argName))); + args["sip-address"] = ::Utils::coreStringToAppString(address->asString()); + + execute(args); } // ============================================================================= // FIXME: Do not accept args without value like: cmd toto. // In the future `toto` could be a boolean argument. -QRegExp Cli::mRegExpArgs("(?:(?:(\\w+)\\s*)=\\s*(?:\"([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"|([^\\s]+)\\s*))"); +QRegExp Cli::mRegExpArgs("(?:(?:([\\w-]+)\\s*)=\\s*(?:\"([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"|([^\\s]+)\\s*))"); QRegExp Cli::mRegExpFunctionName("^\\s*([a-z-]+)\\s*"); Cli::Cli (QObject *parent) : QObject(parent) { @@ -79,6 +160,12 @@ Cli::Cli (QObject *parent) : QObject(parent) { addCommand("call", tr("showFunctionCall"), ::cliCall, { { "sip-address", {} } }); + addCommand("initiate-conference", tr("initiateConferenceFunctionDescription"), ::cliInitiateConference, { + { "sip-address", {} }, { "conference-id", {} } + }); + addCommand("join-conference", tr("joinConferenceFunctionDescription"), ::cliJoinConference, { + { "sip-address", {} }, { "conference-id", {} } + }); } // ----------------------------------------------------------------------------- @@ -88,7 +175,7 @@ void Cli::addCommand ( const QString &description, Function function, const QHash &argsScheme -) noexcept { +) { if (mCommands.contains(functionName)) qWarning() << QStringLiteral("Command already exists: `%1`.").arg(functionName); else @@ -97,22 +184,44 @@ void Cli::addCommand ( // ----------------------------------------------------------------------------- -void Cli::executeCommand (const QString &command) noexcept { - const QString functionName = parseFunctionName(command); - if (functionName.isEmpty()) - return; +void Cli::executeCommand (const QString &command) const { + shared_ptr address = linphone::Factory::get()->createAddress( + ::Utils::appStringToCoreString(command) + ); - bool soFarSoGood; - const QHash &args = parseArgs(command, functionName, soFarSoGood); - if (!soFarSoGood) - return; + // Execute cli command. + if (!address) { + const QString &functionName = parseFunctionName(command); + if (!functionName.isEmpty()) { + QHash args = parseArgs(command); + mCommands[functionName].execute(args); + } - mCommands[functionName].execute(args); + return; + } + + // Execute uri command. + string scheme = address->getScheme(); + if (address->getUsername().empty() || (scheme != "sip" && scheme != "sip-linphone")) { + qWarning() << QStringLiteral("Not a valid uri: `%1`.").arg(command); + return; + } + + const QString functionName = ::Utils::coreStringToAppString(address->getHeader("method")).isEmpty() + ? QStringLiteral("call") + : ::Utils::coreStringToAppString(address->getHeader("method")); + + if (!functionName.isEmpty() && !mCommands.contains(functionName)) { + qWarning() << QStringLiteral("This command doesn't exist: `%1`.").arg(functionName); + return; + } + + mCommands[functionName].executeUri(address); } // ----------------------------------------------------------------------------- -const QString Cli::parseFunctionName (const QString &command) noexcept { +QString Cli::parseFunctionName (const QString &command) const { mRegExpFunctionName.indexIn(command); if (mRegExpFunctionName.pos(1) == -1) { qWarning() << QStringLiteral("Unable to parse function name of command: `%1`.").arg(command); @@ -130,26 +239,12 @@ const QString Cli::parseFunctionName (const QString &command) noexcept { return functionName; } -const QHash Cli::parseArgs ( - const QString &command, - const QString functionName, - bool &soFarSoGood -) noexcept { +QHash Cli::parseArgs (const QString &command) const { QHash args; int pos = 0; - soFarSoGood = true; - while ((pos = mRegExpArgs.indexIn(command, pos)) != -1) { pos += mRegExpArgs.matchedLength(); - if (!mCommands[functionName].argNameExists(mRegExpArgs.cap(1))) { - qWarning() << QStringLiteral("Command with invalid argument(s): `%1 (%2)`.") - .arg(functionName).arg(mRegExpArgs.cap(1)); - - soFarSoGood = false; - return args; - } - args[mRegExpArgs.cap(1)] = (mRegExpArgs.cap(2).isEmpty() ? mRegExpArgs.cap(3) : mRegExpArgs.cap(2)); } diff --git a/src/app/cli/Cli.hpp b/src/app/cli/Cli.hpp index 7d8444968..299b8fcb6 100644 --- a/src/app/cli/Cli.hpp +++ b/src/app/cli/Cli.hpp @@ -23,15 +23,21 @@ #ifndef CLI_H_ #define CLI_H_ +#include + #include #include // ============================================================================= +namespace linphone { +class Address; +} + class Cli : public QObject { Q_OBJECT; - typedef void (*Function)(const QHash &); + typedef void (*Function)(QHash &); enum ArgumentType { STRING @@ -50,13 +56,15 @@ class Cli : public QObject { class Command { public: Command () = default; - Command (const QString &functionName, const QString &description, Function function, const QHash &argsScheme); + Command ( + const QString &functionName, + const QString &description, + Function function, + const QHash &argsScheme + ); - void execute (const QHash &args); - - bool argNameExists (const QString &argName) { - return mArgsScheme.contains(argName); - } + void execute (QHash &args) const; + void executeUri (const std::shared_ptr &address) const; private: QString mFunctionName; @@ -69,13 +77,18 @@ public: Cli (QObject *parent = Q_NULLPTR); ~Cli () = default; - void executeCommand (const QString &command) noexcept; + void executeCommand (const QString &command) const; private: - void addCommand (const QString &functionName, const QString &description, Function function, const QHash &argsScheme = {}) noexcept; + void addCommand ( + const QString &functionName, + const QString &description, + Function function, + const QHash &argsScheme = QHash() + ); - const QString parseFunctionName (const QString &command) noexcept; - const QHash parseArgs (const QString &command, const QString functionName, bool &soFarSoGood) noexcept; + QString parseFunctionName (const QString &command) const; + QHash parseArgs (const QString &command) const; QHash mCommands; diff --git a/src/components/calls/CallsListModel.cpp b/src/components/calls/CallsListModel.cpp index 41897885d..aa4dadd2b 100644 --- a/src/components/calls/CallsListModel.cpp +++ b/src/components/calls/CallsListModel.cpp @@ -24,6 +24,8 @@ #include "../../app/App.hpp" #include "../../utils/Utils.hpp" +#include "../conference/ConferenceAddModel.hpp" +#include "../conference/ConferenceHelperModel.hpp" #include "../core/CoreManager.hpp" #include "CallsListModel.hpp" @@ -89,7 +91,7 @@ void CallsListModel::askForTransfer (CallModel *callModel) { // ----------------------------------------------------------------------------- -void CallsListModel::launchAudioCall (const QString &sipUri) const { +void CallsListModel::launchAudioCall (const QString &sipUri, const QHash &headers) const { shared_ptr core = CoreManager::getInstance()->getCore(); shared_ptr address = core->interpretUrl(::Utils::appStringToCoreString(sipUri)); @@ -100,6 +102,12 @@ void CallsListModel::launchAudioCall (const QString &sipUri) const { params->enableVideo(false); CallModel::setRecordFile(params); + QHashIterator iterator(headers); + while (iterator.hasNext()) { + iterator.next(); + params->addCustomHeader(::Utils::appStringToCoreString(iterator.key()), ::Utils::appStringToCoreString(iterator.value())); + } + core->inviteAddressWithParams(address, params); } @@ -137,8 +145,50 @@ void CallsListModel::terminateAllCalls () const { void CallsListModel::handleCallStateChanged (const shared_ptr &call, linphone::CallState state) { switch (state) { - case linphone::CallStateIncomingReceived: + case linphone::CallStateIncomingReceived: { + // _______________________________________________________________________________________________________________________________________ + // _______________________________________________________________________________________________________________________________________ + addCall(call); + if (!call->getToHeader("method").empty()) { + shared_ptr core = CoreManager::getInstance()->getCore(); + qInfo() << QStringLiteral("----Header method----") << Utils::coreStringToAppString(call->getToHeader("method")); + if (call->getToHeader("method") == "join-conference") { + if (core->getConference() == NULL) { // TODO change this condition, use isInConference() (need to be initiate) + qWarning() << QStringLiteral("Not in a conference,responding to join-conference as a call."); + break; + } + shared_ptr currentConference = core->getConference(); + + QString conferenceIdHeader = Utils::coreStringToAppString(call->getToHeader("conference-id")); + + qInfo() << QStringLiteral("conference id asked: '%1'").arg(conferenceIdHeader); + qWarning() << QStringLiteral("current conference id: '%1'").arg(Utils::coreStringToAppString(currentConference->getId())); + if (currentConference->getId().empty() || currentConference->getId() != Utils::appStringToCoreString(conferenceIdHeader)) { + qWarning() << QStringLiteral("trying to join conference with invalid conference-id, `%1`").arg(conferenceIdHeader); + qWarning() << QStringLiteral("join-conference managed as a call "); + break; + } + qInfo() << QStringLiteral("join conference: `%1`").arg(Utils::coreStringToAppString(currentConference->getId())); + + ConferenceHelperModel helperModel; + ConferenceHelperModel::ConferenceAddModel *addModel = helperModel.getAddModel(); + + CallModel *callModel = &call->getData("call-model"); + callModel->accept(); + addModel->addToConference(call->getRemoteAddress()); + addModel->update(); + + break; + } + } + break; + } + // _______________________________________________________________________________________________________________________________________ + // _______________________________________________________________________________________________________________________________________ case linphone::CallStateOutgoingInit: + if (!call->getToAddress()->getHeader("method").empty()) + qInfo() << QStringLiteral("----Header method----") << Utils::coreStringToAppString(call->getToAddress()->getHeader("method")); + addCall(call); break; diff --git a/src/components/calls/CallsListModel.hpp b/src/components/calls/CallsListModel.hpp index ae9c92e09..571765133 100644 --- a/src/components/calls/CallsListModel.hpp +++ b/src/components/calls/CallsListModel.hpp @@ -45,7 +45,7 @@ public: void askForTransfer (CallModel *callModel); - Q_INVOKABLE void launchAudioCall (const QString &sipUri) const; + Q_INVOKABLE void launchAudioCall (const QString &sipUri, const QHash &headers = {}) const; Q_INVOKABLE void launchVideoCall (const QString &sipUri) const; Q_INVOKABLE int getRunningCallsNumber () const; diff --git a/src/components/conference/ConferenceHelperModel.cpp b/src/components/conference/ConferenceHelperModel.cpp index f672aea32..8b4bc4722 100644 --- a/src/components/conference/ConferenceHelperModel.cpp +++ b/src/components/conference/ConferenceHelperModel.cpp @@ -24,7 +24,6 @@ #include "../../utils/Utils.hpp" #include "../core/CoreManager.hpp" #include "../sip-addresses/SipAddressesProxyModel.hpp" -#include "ConferenceAddModel.hpp" #include "ConferenceHelperModel.hpp" diff --git a/src/components/conference/ConferenceHelperModel.hpp b/src/components/conference/ConferenceHelperModel.hpp index afde60c30..3b0a51b47 100644 --- a/src/components/conference/ConferenceHelperModel.hpp +++ b/src/components/conference/ConferenceHelperModel.hpp @@ -27,17 +27,18 @@ #include +#include "ConferenceHelperModel.hpp" + // ============================================================================= // Sip addresses not in conference. // Can filter the sip addresses with a pattern. // ============================================================================= class CallModel; -class ConferenceAddModel; namespace linphone { - class Conference; - class Core; +class Conference; +class Core; } class ConferenceHelperModel : public QSortFilterProxyModel { @@ -53,6 +54,10 @@ public: QHash roleNames () const override; + ConferenceAddModel *getConferenceAddModel () const { + return mConferenceAddModel; + } + Q_INVOKABLE void setFilter (const QString &pattern); protected: @@ -60,9 +65,6 @@ protected: bool lessThan (const QModelIndex &left, const QModelIndex &right) const override; private: - ConferenceAddModel *getConferenceAddModel () const { - return mConferenceAddModel; - } ConferenceAddModel *mConferenceAddModel = nullptr; diff --git a/src/utils/Utils.hpp b/src/utils/Utils.hpp index 186c92be6..be8a71793 100644 --- a/src/utils/Utils.hpp +++ b/src/utils/Utils.hpp @@ -23,6 +23,7 @@ #ifndef UTILS_H_ #define UTILS_H_ +#include #include // ============================================================================= @@ -54,6 +55,46 @@ namespace Utils { // Returns the same path given in parameter if `filePath` exists. // Otherwise returns a safe path with a unique number before the extension. QString getSafeFilePath (const QString &filePath, bool *soFarSoGood = nullptr); + + // Connect once to a member function. + template + static inline QMetaObject::Connection connectOnce ( + typename QtPrivate::FunctionPointer::Object *sender, + Func1 signal, + typename QtPrivate::FunctionPointer::Object *receiver, + Func2 slot + ) { + QMetaObject::Connection connection = QObject::connect(sender, signal, receiver, slot); + QMetaObject::Connection *deleter = new QMetaObject::Connection(); + + *deleter = QObject::connect(sender, signal, [connection, deleter] { + QObject::disconnect(connection); + QObject::disconnect(*deleter); + delete deleter; + }); + + return connection; + } + + // Connect once to a function. + template + static inline QMetaObject::Connection connectOnce ( + typename QtPrivate::FunctionPointer::Object *sender, + Func1 signal, + const QObject *receiver, + Func2 slot + ) { + QMetaObject::Connection connection = QObject::connect(sender, signal, receiver, slot); + QMetaObject::Connection *deleter = new QMetaObject::Connection(); + + *deleter = QObject::connect(sender, signal, [connection, deleter] { + QObject::disconnect(connection); + QObject::disconnect(*deleter); + delete deleter; + }); + + return connection; + } } #endif // UTILS_H_ diff --git a/submodules/bcmatroska2 b/submodules/bcmatroska2 index 4c7acea97..ac155e025 160000 --- a/submodules/bcmatroska2 +++ b/submodules/bcmatroska2 @@ -1 +1 @@ -Subproject commit 4c7acea973ac94e559d52e45312e90cf4d0f6247 +Subproject commit ac155e025efbcb13778cb436babb80e0f4fd6e72 diff --git a/submodules/belcard b/submodules/belcard index 38eba4c26..a2e36ce33 160000 --- a/submodules/belcard +++ b/submodules/belcard @@ -1 +1 @@ -Subproject commit 38eba4c264b5e45c8650c8ccf05f359541d8c4ae +Subproject commit a2e36ce337b7cba0bd6fddec5912b7134dc627ba diff --git a/submodules/belle-sip b/submodules/belle-sip index 647393a5e..a19b7e3e8 160000 --- a/submodules/belle-sip +++ b/submodules/belle-sip @@ -1 +1 @@ -Subproject commit 647393a5e4b49551f34e213c91d80b675c60a7f6 +Subproject commit a19b7e3e833dc121f91452e40658dd80f8f0c145 diff --git a/submodules/belr b/submodules/belr index df0f66406..a6380eccb 160000 --- a/submodules/belr +++ b/submodules/belr @@ -1 +1 @@ -Subproject commit df0f6640647925b1225eba011a40ce988ede5c57 +Subproject commit a6380eccb56bb070712971189912f41eb7f047a3 diff --git a/submodules/linphone b/submodules/linphone index b9b283dcd..d88e17cd3 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit b9b283dcdb0b19a976df8d5cccba43c373727ee8 +Subproject commit d88e17cd3ab831f2a9ce5ae04f796caff2a93cc2