Commit 646f0fe3 authored by Nicolas Follet's avatar Nicolas Follet Committed by Wescoeur

feat(App): supports commands and conferences with id

parent 628665c6
...@@ -421,6 +421,14 @@ Server url not configured.</translation> ...@@ -421,6 +421,14 @@ Server url not configured.</translation>
<source>showFunctionCall</source> <source>showFunctionCall</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>joinConferenceFunctionDescription</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>initiateConferenceFunctionDescription</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>CodecsViewer</name> <name>CodecsViewer</name>
......
...@@ -421,6 +421,14 @@ Url du serveur non configurée.</translation> ...@@ -421,6 +421,14 @@ Url du serveur non configurée.</translation>
<source>showFunctionCall</source> <source>showFunctionCall</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>joinConferenceFunctionDescription</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>initiateConferenceFunctionDescription</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>CodecsViewer</name> <name>CodecsViewer</name>
......
...@@ -7,6 +7,7 @@ Exec=linphone %u ...@@ -7,6 +7,7 @@ Exec=linphone %u
Icon=linphone Icon=linphone
Terminal=false Terminal=false
Categories=Network;Telephony; Categories=Network;Telephony;
MimeType=x-scheme-handler/sip-linphone;x-scheme-handler/sip;
# Translations # Translations
......
...@@ -310,7 +310,8 @@ if(WIN32) ...@@ -310,7 +310,8 @@ if(WIN32)
string(REPLACE "\\" "\\\\" ESCAPED_DOS_STYLE_SOURCE_DIR "${DOS_STYLE_SOURCE_DIR}") string(REPLACE "\\" "\\\\" ESCAPED_DOS_STYLE_SOURCE_DIR "${DOS_STYLE_SOURCE_DIR}")
file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}" DOS_STYLE_BINARY_DIR) file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}" DOS_STYLE_BINARY_DIR)
string(REPLACE "\\" "\\\\" ESCAPED_DOS_STYLE_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) 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\\\"") set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "!include \\\"${ESCAPED_DOS_STYLE_BINARY_DIR}\\\\uninstall.nsi\\\"")
if(ENABLE_OPENH264) if(ENABLE_OPENH264)
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
...@@ -32,6 +32,17 @@ ...@@ -32,6 +32,17 @@
<string>@CMAKE_OSX_DEPLOYMENT_TARGET@</string> <string>@CMAKE_OSX_DEPLOYMENT_TARGET@</string>
<key>NSAppSleepDisabled</key> <key>NSAppSleepDisabled</key>
<string>YES</string> <string>YES</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.belldonnecommunications.linphone</string>
<key>CFBundleURLSchemes</key>
<array>
<string>sip</string>
<string>sip-linphone</string>
</array>
</dict>
</array>
</dict> </dict>
</plist> </plist>
...@@ -5,3 +5,5 @@ Abort ...@@ -5,3 +5,5 @@ Abort
notRunningInUninstall: notRunningInUninstall:
DeleteRegKey HKCR "sip"
DeleteRegKey HKCR "sip-linphone"
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
...@@ -215,6 +215,13 @@ void App::initContentApp () { ...@@ -215,6 +215,13 @@ void App::initContentApp () {
if (mEngine->rootObjects().isEmpty()) if (mEngine->rootObjects().isEmpty())
qFatal("Unable to open main window."); qFatal("Unable to open main window.");
// Execute command argument if needed.
{
const QString commandArgument = getCommandArgument();
if (!commandArgument.isEmpty())
mCli->executeCommand(commandArgument);
}
QObject::connect( QObject::connect(
CoreManager::getInstance()->getHandlers().get(), CoreManager::getInstance()->getHandlers().get(),
&CoreHandlers::coreStarted, &CoreHandlers::coreStarted,
...@@ -225,13 +232,39 @@ void App::initContentApp () { ...@@ -225,13 +232,39 @@ void App::initContentApp () {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
QString App::getCommandArgument () { QString App::getCommandArgument () {
// TODO: Remove me when cmd option will be available. const QStringList &arguments = mParser->positionalArguments();
return QString(""); return arguments.empty() ? QString("") : arguments[0];
// return mParser->value("cmd"); }
// -----------------------------------------------------------------------------
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<QFileOpenEvent *>(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 () { QQuickWindow *App::getCallsWindow () {
if (!mCallsWindow) if (!mCallsWindow)
mCallsWindow = ::createSubWindow(mEngine, QML_VIEW_CALLS_WINDOW); mCallsWindow = ::createSubWindow(mEngine, QML_VIEW_CALLS_WINDOW);
...@@ -281,30 +314,19 @@ bool App::hasFocus () const { ...@@ -281,30 +314,19 @@ bool App::hasFocus () const {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void App::createParser () { 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 = new QCommandLineParser();
mParser->setApplicationDescription(tr("applicationDescription")); mParser->setApplicationDescription(tr("applicationDescription"));
mParser->addOptions({ mParser->addOptions({
{ { "h", "help" }, tr("commandLineOptionHelp") }, { { "h", "help" }, tr("commandLineOptionHelp") },
{ { "v", "version" }, tr("commandLineOptionVersion") }, { { "v", "version" }, tr("commandLineOptionVersion") },
{ "config", tr("commandLineOptionConfig"), tr("commandLineOptionConfigArg") }, { "config", tr("commandLineOptionConfig"), tr("commandLineOptionConfigArg") },
{ { "c", "cmd" }, tr("commandLineOptionCmd"), tr("commandLineOptionCmdArg") },
#ifndef Q_OS_MACOS #ifndef Q_OS_MACOS
{ "iconified", tr("commandLineOptionIconified") }, { "iconified", tr("commandLineOptionIconified") },
#endif // ifndef Q_OS_MACOS #endif // ifndef Q_OS_MACOS
{ { "V", "verbose" }, tr("commandLineOptionVerbose") } { { "V", "verbose" }, tr("commandLineOptionVerbose") }
// TODO: Enable me in future version!
// ,
// { { "c", "cmd" }, tr("commandLineOptionCmd"), tr("commandLineOptionCmdArg") }
}); });
} }
......
...@@ -54,6 +54,11 @@ public: ...@@ -54,6 +54,11 @@ public:
void initContentApp (); void initContentApp ();
QString getCommandArgument (); QString getCommandArgument ();
void executeCommand (const QString &command);
#ifdef Q_OS_MACOS
bool event (QEvent *event) override;
#endif // ifdef Q_OS_MACOS
QQmlEngine *getEngine () { QQmlEngine *getEngine () {
return mEngine; return mEngine;
...@@ -117,11 +122,11 @@ private: ...@@ -117,11 +122,11 @@ private:
return qVersion(); return qVersion();
} }
QCommandLineParser *mParser = nullptr;
QVariantList mAvailableLocales; QVariantList mAvailableLocales;
QString mLocale; QString mLocale;
QCommandLineParser *mParser = nullptr;
QQmlApplicationEngine *mEngine = nullptr; QQmlApplicationEngine *mEngine = nullptr;
DefaultTranslator *mTranslator = nullptr; DefaultTranslator *mTranslator = nullptr;
......
...@@ -84,8 +84,13 @@ AppController::AppController (int &argc, char *argv[]) { ...@@ -84,8 +84,13 @@ AppController::AppController (int &argc, char *argv[]) {
mApp = new App(argc, argv); mApp = new App(argc, argv);
if (mApp->isSecondary()) { if (mApp->isSecondary()) {
#ifdef Q_OS_MACOS
mApp->processEvents();
#endif // ifdef Q_OS_MACOS
QString command = mApp->getCommandArgument(); QString command = mApp->getCommandArgument();
mApp->sendMessage(command.isEmpty() ? "show" : command.toLocal8Bit(), -1); mApp->sendMessage(command.isEmpty() ? "show" : command.toLocal8Bit(), -1);
return; return;
} }
......
...@@ -20,9 +20,8 @@ ...@@ -20,9 +20,8 @@
* Author: Nicolas Follet * Author: Nicolas Follet
*/ */
#include <stdexcept>
#include "../../components/core/CoreManager.hpp" #include "../../components/core/CoreManager.hpp"
#include "../../utils/Utils.hpp"
#include "../App.hpp" #include "../App.hpp"
#include "Cli.hpp" #include "Cli.hpp"
...@@ -33,13 +32,64 @@ using namespace std; ...@@ -33,13 +32,64 @@ using namespace std;
// API. // API.
// ============================================================================= // =============================================================================
static void cliShow (const QHash<QString, QString> &) { static void cliShow (QHash<QString, QString> &) {
App *app = App::getInstance(); App *app = App::getInstance();
app->smartShowWindow(app->getMainWindow()); app->smartShowWindow(app->getMainWindow());
} }
static void cliCall (const QHash<QString, QString> &args) { static void cliCall (QHash<QString, QString> &args) {
CoreManager::getInstance()->getCallsListModel()->launchAudioCall(args["sipAddress"]); CoreManager::getInstance()->getCallsListModel()->launchAudioCall(args["sip-address"]);
}
static void cliJoinConference (QHash<QString, QString> &args) {
const QString sipAddress = args.take("sip-address");
args["method"] = QStringLiteral("join-conference");
CoreManager::getInstance()->getCallsListModel()->launchAudioCall(sipAddress, args);
}
static void cliInitiateConference (QHash<QString, QString> &args) {
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
// Check identity.
{
shared_ptr<linphone::Address> 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<linphone::Conference> 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 ( ...@@ -55,7 +105,18 @@ Cli::Command::Command (
mFunction(function), mFunction(function),
mArgsScheme(argsScheme) {} mArgsScheme(argsScheme) {}
void Cli::Command::execute (const QHash<QString, QString> &args) { void Cli::Command::execute (QHash<QString, QString> &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()) { for (const auto &argName : mArgsScheme.keys()) {
if (!args.contains(argName) && !mArgsScheme[argName].isOptional) { if (!args.contains(argName) && !mArgsScheme[argName].isOptional) {
qWarning() << QStringLiteral("Missing argument for command: `%1 (%2)`.") qWarning() << QStringLiteral("Missing argument for command: `%1 (%2)`.")
...@@ -64,14 +125,34 @@ void Cli::Command::execute (const QHash<QString, QString> &args) { ...@@ -64,14 +125,34 @@ void Cli::Command::execute (const QHash<QString, QString> &args) {
} }
} }
// Execute!
CoreManager *coreManager = CoreManager::getInstance();
if (coreManager->started())
(*mFunction)(args); (*mFunction)(args);
else {
Function f = mFunction;
::Utils::connectOnce(coreManager->getHandlers().get(), &CoreHandlers::coreStarted, coreManager, [f, args] {
QHash<QString, QString> fuckConst = args;
(*f)(fuckConst);
});
}
}
void Cli::Command::executeUri (const shared_ptr<linphone::Address> &address) const {
QHash<QString, QString> 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. // FIXME: Do not accept args without value like: cmd toto.
// In the future `toto` could be a boolean argument. // 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*"); QRegExp Cli::mRegExpFunctionName("^\\s*([a-z-]+)\\s*");
Cli::Cli (QObject *parent) : QObject(parent) { Cli::Cli (QObject *parent) : QObject(parent) {
...@@ -79,6 +160,12 @@ Cli::Cli (QObject *parent) : QObject(parent) { ...@@ -79,6 +160,12 @@ Cli::Cli (QObject *parent) : QObject(parent) {
addCommand("call", tr("showFunctionCall"), ::cliCall, { addCommand("call", tr("showFunctionCall"), ::cliCall, {
{ "sip-address", {} } { "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 ( ...@@ -88,7 +175,7 @@ void Cli::addCommand (
const QString &description, const QString &description,
Function function, Function function,
const QHash<QString, Argument> &argsScheme const QHash<QString, Argument> &argsScheme
) noexcept { ) {
if (mCommands.contains(functionName)) if (mCommands.contains(functionName))
qWarning() << QStringLiteral("Command already exists: `%1`.").arg(functionName); qWarning() << QStringLiteral("Command already exists: `%1`.").arg(functionName);
else else
...@@ -97,22 +184,44 @@ void Cli::addCommand ( ...@@ -97,22 +184,44 @@ void Cli::addCommand (
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void Cli::executeCommand (const QString &command) noexcept { void Cli::executeCommand (const QString &command) const {
const QString functionName = parseFunctionName(command); shared_ptr<linphone::Address> address = linphone::Factory::get()->createAddress(
if (functionName.isEmpty()) ::Utils::appStringToCoreString(command)
);
// Execute cli command.
if (!address) {
const QString &functionName = parseFunctionName(command);
if (!functionName.isEmpty()) {
QHash<QString, QString> args = parseArgs(command);
mCommands[functionName].execute(args);
}
return; return;
}
bool soFarSoGood; // Execute uri command.
const QHash<QString, QString> &args = parseArgs(command, functionName, soFarSoGood); string scheme = address->getScheme();
if (!soFarSoGood) if (address->getUsername().empty() || (scheme != "sip" && scheme != "sip-linphone")) {
qWarning() << QStringLiteral("Not a valid uri: `%1`.").arg(command);
return; return;
}
mCommands[functionName].execute(args); 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); mRegExpFunctionName.indexIn(command);
if (mRegExpFunctionName.pos(1) == -1) { if (mRegExpFunctionName.pos(1) == -1) {
qWarning() << QStringLiteral("Unable to parse function name of command: `%1`.").arg(command); qWarning() << QStringLiteral("Unable to parse function name of command: `%1`.").arg(command);
...@@ -130,26 +239,12 @@ const QString Cli::parseFunctionName (const QString &command) noexcept { ...@@ -130,26 +239,12 @@ const QString Cli::parseFunctionName (const QString &command) noexcept {
return functionName; return functionName;
} }
const QHash<QString, QString> Cli::parseArgs ( QHash<QString, QString> Cli::parseArgs (const QString &command) const {
const QString &command,
const QString functionName,
bool &soFarSoGood
) noexcept {
QHash<QString, QString> args; QHash<QString, QString> args;
int pos = 0; int pos = 0;
soFarSoGood = true;
while ((pos = mRegExpArgs.indexIn(command, pos)) != -1) { while ((pos = mRegExpArgs.indexIn(command, pos)) != -1) {
pos += mRegExpArgs.matchedLength(); 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)); args[mRegExpArgs.cap(1)] = (mRegExpArgs.cap(2).isEmpty() ? mRegExpArgs.cap(3) : mRegExpArgs.cap(2));
} }
......
...@@ -23,15 +23,21 @@ ...@@ -23,15 +23,21 @@
#ifndef CLI_H_ #ifndef CLI_H_
#define CLI_H_ #define CLI_H_
#include <memory>
#include <QHash> #include <QHash>
#include <QObject> #include <QObject>
// ============================================================================= // =============================================================================
namespace linphone {
class Address;
}
class Cli : public QObject { class Cli : public QObject {
Q_OBJECT; Q_OBJECT;
typedef void (*Function)(const QHash<QString, QString> &); typedef void (*Function)(QHash<QString, QString> &);
enum ArgumentType { enum ArgumentType {
STRING STRING
...@@ -50,13 +56,15 @@ class Cli : public QObject { ...@@ -50,13 +56,15 @@ class Cli : public QObject {
class Command { class Command {
public: public:
Command () = default; Command () = default;
Command (const QString &functionName, const QString &description, Function function, const QHash<QString, Argument> &argsScheme); Command (
const QString &functionName,
const QString &description,
Function function,
const QHash<QString, Argument> &argsScheme
);
void execute (const QHash<QString, QString> &args); void execute (QHash<QString, QString> &args) const;
void executeUri (const std::shared_ptr<linphone::Address> &address) const;
bool argNameExists (const QString &argName) {
return mArgsScheme.contains(argName);
}
private: private:
QString mFunctionName; QString mFunctionName;
...@@ -69,13 +77,18 @@ public: ...@@ -69,13 +77,18 @@ public:
Cli (QObject *parent = Q_NULLPTR); Cli (QObject *parent = Q_NULLPTR);
~Cli () = default; ~Cli () = default;
void executeCommand (const QString &command) noexcept; void executeCommand (const QString &command) const;
private: private:
void addCommand (const QString &functionName, const QString &description, Function function, const QHash<QString, Argument> &argsScheme = {}) noexcept; void addCommand (
const QString &functionName,
const QString parseFunctionName (const QString &command) noexcept; const QString &description,
const QHash<QString, QString> parseArgs (const QString &command, const QString functionName, bool &soFarSoGood) noexcept; Function function,
const QHash<QString, Argument> &argsScheme = QHash<QString, Argument>()
);
QString parseFunctionName (const QString &command) const;
QHash<QString, QString> parseArgs (const QString &command) const;
QHash<QString, Command> mCommands; QHash<QString, Command> mCommands;
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include "../../app/App.hpp" #include "../../app/App.hpp"
#include "../../utils/Utils.hpp" #include "../../utils/Utils.hpp"
#include "../conference/ConferenceAddModel.hpp"
#include "../conference/ConferenceHelperModel.hpp"
#include "../core/CoreManager.hpp" #include "../core/CoreManager.hpp"
#include "CallsListModel.hpp" #include "CallsListModel.hpp"
...@@ -89,7 +91,7 @@ void CallsListModel::askForTransfer (CallModel *callModel) { ...@@ -89,7 +91,7 @@ void CallsListModel::askForTransfer (CallModel *callModel) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void CallsListModel::launchAudioCall (const QString &sipUri) const { void CallsListModel::launchAudioCall (const QString &sipUri, const QHash<QString, QString> &headers) const {
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore(); shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
shared_ptr<linphone::Address> address = core->interpretUrl(::Utils::appStringToCoreString(sipUri)); shared_ptr<linphone::Address> address = core->interpretUrl(::Utils::appStringToCoreString(sipUri));
...@@ -100,6 +102,12 @@ void CallsListModel::launchAudioCall (const QString &sipUri) const { ...@@ -100,6 +102,12 @@ void CallsListModel::launchAudioCall (const QString &sipUri) const {
params->enableVideo(false); params->enableVideo(false);
CallModel::setRecordFile(params); CallModel::setRecordFile(params);
QHashIterator<QString, QString> iterator(headers);
while (iterator.hasNext()) {
iterator.next();
params->addCustomHeader(::Utils::appStringToCoreString(iterator.key()), ::Utils::appStringToCoreString(iterator.value()));
}
core->inviteAddressWithParams(address, params); core->inviteAddressWithParams(address, params);
} }
...@@ -137,8 +145,50 @@ void CallsListModel::terminateAllCalls () const { ...@@ -137,8 +145,50 @@ void CallsListModel::terminateAllCalls () const {
void CallsListModel::handleCallStateChanged (const shared_ptr<linphone::Call> &call, linphone::CallState state) { void CallsListModel::handleCallStateChanged (const shared_ptr<linphone::Call> &call, linphone::CallState state) {
switch (state) { switch (state) {
case linphone::CallStateIncomingReceived: case linphone::CallStateIncomingReceived: {
// _______________________________________________________________________________________________________________________________________
// _______________________________________________________________________________________________________________________________________
addCall(call);
if (!call->getToHeader("method").empty()) {
shared_ptr<linphone::Core> 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<linphone::Conference> 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<CallModel>("call-model");
callModel->accept();
addModel->addToConference(call->getRemoteAddress());
addModel->update();
break;
}
}
break;
}
// _______________________________________________________________________________________________________________________________________
// _______________________________________________________________________________________________________________________________________
case linphone::CallStateOutgoingInit: case linphone::CallStateOutgoingInit:
if (!call->getToAddress()->getHeader("method").empty())
qInfo() << QStringLiteral("----Header method----") << Utils::coreStringToAppString(call->getToAddress()->getHeader("method"));
addCall(call); addCall(call);
break; break;
......
...@@ -45,7 +45,7 @@ public: ...@@ -45,7 +45,7 @@ public:
void askForTransfer (CallModel *callModel); void askForTransfer (CallModel *callModel);
Q_INVOKABLE void launchAudioCall (const QString &sipUri) const; Q_INVOKABLE void launchAudioCall (const QString &sipUri, const QHash<QString, QString> &headers = {}) const;
Q_INVOKABLE void launchVideoCall (const QString &sipUri) const; Q_INVOKABLE void launchVideoCall (const QString &sipUri) const;
Q_INVOKABLE int getRunningCallsNumber () const; Q_INVOKABLE int getRunningCallsNumber () const;
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include "../../utils/Utils.hpp" #include "../../utils/Utils.hpp"
#include "../core/CoreManager.hpp" #include "../core/CoreManager.hpp"
#include "../sip-addresses/SipAddressesProxyModel.hpp" #include "../sip-addresses/SipAddressesProxyModel.hpp"
#include "ConferenceAddModel.hpp"
#include "ConferenceHelperModel.hpp" #include "ConferenceHelperModel.hpp"
......
...@@ -27,17 +27,18 @@ ...@@ -27,17 +27,18 @@
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include "ConferenceHelperModel.hpp"
// ============================================================================= // =============================================================================
// Sip addresses not in conference. // Sip addresses not in conference.
// Can filter the sip addresses with a pattern. // Can filter the sip addresses with a pattern.
// ============================================================================= // =============================================================================
class CallModel; class CallModel;
class ConferenceAddModel;
namespace linphone { namespace linphone {
class Conference; class Conference;
class Core; class Core;
} }
class ConferenceHelperModel : public QSortFilterProxyModel { class ConferenceHelperModel : public QSortFilterProxyModel {
...@@ -53,6 +54,10 @@ public: ...@@ -53,6 +54,10 @@ public:
QHash<int, QByteArray> roleNames () const override; QHash<int, QByteArray> roleNames () const override;
ConferenceAddModel *getConferenceAddModel () const {
return mConferenceAddModel;
}
Q_INVOKABLE void setFilter (const QString &pattern); Q_INVOKABLE void setFilter (const QString &pattern);
protected: protected:
...@@ -60,9 +65,6 @@ protected: ...@@ -60,9 +65,6 @@ protected:
bool lessThan (const QModelIndex &left, const QModelIndex &right) const override; bool lessThan (const QModelIndex &left, const QModelIndex &right) const override;
private: private:
ConferenceAddModel *getConferenceAddModel () const {
return mConferenceAddModel;
}
ConferenceAddModel *mConferenceAddModel = nullptr; ConferenceAddModel *mConferenceAddModel = nullptr;
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#ifndef UTILS_H_ #ifndef UTILS_H_
#define UTILS_H_ #define UTILS_H_
#include <QObject>
#include <QString> #include <QString>
// ============================================================================= // =============================================================================
...@@ -54,6 +55,46 @@ namespace Utils { ...@@ -54,6 +55,46 @@ namespace Utils {
// Returns the same path given in parameter if `filePath` exists. // Returns the same path given in parameter if `filePath` exists.
// Otherwise returns a safe path with a unique number before the extension. // Otherwise returns a safe path with a unique number before the extension.
QString getSafeFilePath (const QString &filePath, bool *soFarSoGood = nullptr); QString getSafeFilePath (const QString &filePath, bool *soFarSoGood = nullptr);
// Connect once to a member function.
template<typename Func1, typename Func2>
static inline QMetaObject::Connection connectOnce (
typename QtPrivate::FunctionPointer<Func1>::Object *sender,
Func1 signal,
typename QtPrivate::FunctionPointer<Func2>::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<typename Func1, typename Func2>
static inline QMetaObject::Connection connectOnce (
typename QtPrivate::FunctionPointer<Func1>::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_ #endif // UTILS_H_
bcmatroska2 @ ac155e02
Subproject commit 4c7acea973ac94e559d52e45312e90cf4d0f6247 Subproject commit ac155e025efbcb13778cb436babb80e0f4fd6e72
belcard @ a2e36ce3
Subproject commit 38eba4c264b5e45c8650c8ccf05f359541d8c4ae Subproject commit a2e36ce337b7cba0bd6fddec5912b7134dc627ba
belle-sip @ a19b7e3e
Subproject commit 647393a5e4b49551f34e213c91d80b675c60a7f6 Subproject commit a19b7e3e833dc121f91452e40658dd80f8f0c145
belr @ a6380ecc
Subproject commit df0f6640647925b1225eba011a40ce988ede5c57 Subproject commit a6380eccb56bb070712971189912f41eb7f047a3
linphone @ d88e17cd
Subproject commit b9b283dcdb0b19a976df8d5cccba43c373727ee8 Subproject commit d88e17cd3ab831f2a9ce5ae04f796caff2a93cc2
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment