mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-17 11:28:07 +00:00
feat(App): supports commands and conferences with id
This commit is contained in:
parent
628665c6b1
commit
646f0fe3b9
22 changed files with 387 additions and 111 deletions
|
|
@ -421,6 +421,14 @@ Server url not configured.</translation>
|
|||
<source>showFunctionCall</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>joinConferenceFunctionDescription</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>initiateConferenceFunctionDescription</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CodecsViewer</name>
|
||||
|
|
|
|||
|
|
@ -421,6 +421,14 @@ Url du serveur non configurée.</translation>
|
|||
<source>showFunctionCall</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>joinConferenceFunctionDescription</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>initiateConferenceFunctionDescription</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CodecsViewer</name>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1,37 +1,48 @@
|
|||
<?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">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Linphone</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Linphone</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>linphone</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>@PACKAGE_VERSION@, (C) 2011-2017 The linphone team http://www.linphone.org</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>linphone.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.linphone.linphone</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>@PACKAGE_VERSION@</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>@PACKAGE_VERSION@</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright 2011-2017 Belledonne Communications</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>@CMAKE_OSX_DEPLOYMENT_TARGET@</string>
|
||||
<key>NSAppSleepDisabled</key>
|
||||
<string>YES</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Linphone</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Linphone</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>linphone</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>@PACKAGE_VERSION@, (C) 2011-2017 The linphone team http://www.linphone.org</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>linphone.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.linphone.linphone</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>@PACKAGE_VERSION@</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>@PACKAGE_VERSION@</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright 2011-2017 Belledonne Communications</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>@CMAKE_OSX_DEPLOYMENT_TARGET@</string>
|
||||
<key>NSAppSleepDisabled</key>
|
||||
<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>
|
||||
</plist>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,3 +5,5 @@ Abort
|
|||
|
||||
notRunningInUninstall:
|
||||
|
||||
DeleteRegKey HKCR "sip"
|
||||
DeleteRegKey HKCR "sip-linphone"
|
||||
|
|
|
|||
13
cmake_builder/linphone_package/uri-handler-install.nsi.in
Normal file
13
cmake_builder/linphone_package/uri-handler-install.nsi.in
Normal file
|
|
@ -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$\""
|
||||
|
|
@ -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<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 () {
|
||||
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") }
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,9 +20,8 @@
|
|||
* Author: Nicolas Follet
|
||||
*/
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#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<QString, QString> &) {
|
||||
static void cliShow (QHash<QString, QString> &) {
|
||||
App *app = App::getInstance();
|
||||
app->smartShowWindow(app->getMainWindow());
|
||||
}
|
||||
|
||||
static void cliCall (const QHash<QString, QString> &args) {
|
||||
CoreManager::getInstance()->getCallsListModel()->launchAudioCall(args["sipAddress"]);
|
||||
static void cliCall (QHash<QString, QString> &args) {
|
||||
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 (
|
|||
mFunction(function),
|
||||
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()) {
|
||||
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<QString, QString> &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<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.
|
||||
// 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<QString, Argument> &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<linphone::Address> address = linphone::Factory::get()->createAddress(
|
||||
::Utils::appStringToCoreString(command)
|
||||
);
|
||||
|
||||
bool soFarSoGood;
|
||||
const QHash<QString, QString> &args = parseArgs(command, functionName, soFarSoGood);
|
||||
if (!soFarSoGood)
|
||||
return;
|
||||
// Execute cli command.
|
||||
if (!address) {
|
||||
const QString &functionName = parseFunctionName(command);
|
||||
if (!functionName.isEmpty()) {
|
||||
QHash<QString, QString> 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<QString, QString> Cli::parseArgs (
|
||||
const QString &command,
|
||||
const QString functionName,
|
||||
bool &soFarSoGood
|
||||
) noexcept {
|
||||
QHash<QString, QString> Cli::parseArgs (const QString &command) const {
|
||||
QHash<QString, QString> 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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,15 +23,21 @@
|
|||
#ifndef CLI_H_
|
||||
#define CLI_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
namespace linphone {
|
||||
class Address;
|
||||
}
|
||||
|
||||
class Cli : public QObject {
|
||||
Q_OBJECT;
|
||||
|
||||
typedef void (*Function)(const QHash<QString, QString> &);
|
||||
typedef void (*Function)(QHash<QString, QString> &);
|
||||
|
||||
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<QString, Argument> &argsScheme);
|
||||
Command (
|
||||
const QString &functionName,
|
||||
const QString &description,
|
||||
Function function,
|
||||
const QHash<QString, Argument> &argsScheme
|
||||
);
|
||||
|
||||
void execute (const QHash<QString, QString> &args);
|
||||
|
||||
bool argNameExists (const QString &argName) {
|
||||
return mArgsScheme.contains(argName);
|
||||
}
|
||||
void execute (QHash<QString, QString> &args) const;
|
||||
void executeUri (const std::shared_ptr<linphone::Address> &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<QString, Argument> &argsScheme = {}) noexcept;
|
||||
void addCommand (
|
||||
const QString &functionName,
|
||||
const QString &description,
|
||||
Function function,
|
||||
const QHash<QString, Argument> &argsScheme = QHash<QString, Argument>()
|
||||
);
|
||||
|
||||
const QString parseFunctionName (const QString &command) noexcept;
|
||||
const QHash<QString, QString> parseArgs (const QString &command, const QString functionName, bool &soFarSoGood) noexcept;
|
||||
QString parseFunctionName (const QString &command) const;
|
||||
QHash<QString, QString> parseArgs (const QString &command) const;
|
||||
|
||||
QHash<QString, Command> mCommands;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<QString, QString> &headers) const {
|
||||
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
|
||||
|
||||
shared_ptr<linphone::Address> address = core->interpretUrl(::Utils::appStringToCoreString(sipUri));
|
||||
|
|
@ -100,6 +102,12 @@ void CallsListModel::launchAudioCall (const QString &sipUri) const {
|
|||
params->enableVideo(false);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -137,8 +145,50 @@ void CallsListModel::terminateAllCalls () const {
|
|||
|
||||
void CallsListModel::handleCallStateChanged (const shared_ptr<linphone::Call> &call, linphone::CallState 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:
|
||||
if (!call->getToAddress()->getHeader("method").empty())
|
||||
qInfo() << QStringLiteral("----Header method----") << Utils::coreStringToAppString(call->getToAddress()->getHeader("method"));
|
||||
|
||||
addCall(call);
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<QString, QString> &headers = {}) const;
|
||||
Q_INVOKABLE void launchVideoCall (const QString &sipUri) const;
|
||||
|
||||
Q_INVOKABLE int getRunningCallsNumber () const;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
#include "../../utils/Utils.hpp"
|
||||
#include "../core/CoreManager.hpp"
|
||||
#include "../sip-addresses/SipAddressesProxyModel.hpp"
|
||||
#include "ConferenceAddModel.hpp"
|
||||
|
||||
#include "ConferenceHelperModel.hpp"
|
||||
|
||||
|
|
|
|||
|
|
@ -27,17 +27,18 @@
|
|||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#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<int, QByteArray> 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#ifndef UTILS_H_
|
||||
#define UTILS_H_
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
// =============================================================================
|
||||
|
|
@ -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<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_
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 4c7acea973ac94e559d52e45312e90cf4d0f6247
|
||||
Subproject commit ac155e025efbcb13778cb436babb80e0f4fd6e72
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 38eba4c264b5e45c8650c8ccf05f359541d8c4ae
|
||||
Subproject commit a2e36ce337b7cba0bd6fddec5912b7134dc627ba
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 647393a5e4b49551f34e213c91d80b675c60a7f6
|
||||
Subproject commit a19b7e3e833dc121f91452e40658dd80f8f0c145
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit df0f6640647925b1225eba011a40ce988ede5c57
|
||||
Subproject commit a6380eccb56bb070712971189912f41eb7f047a3
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit b9b283dcdb0b19a976df8d5cccba43c373727ee8
|
||||
Subproject commit d88e17cd3ab831f2a9ce5ae04f796caff2a93cc2
|
||||
Loading…
Add table
Reference in a new issue