mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-17 11:28:07 +00:00
598 lines
22 KiB
C++
598 lines
22 KiB
C++
/*
|
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
|
*
|
|
* This file is part of linphone-desktop
|
|
* (see https://www.linphone.org).
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <iostream>
|
|
|
|
#include <QQuickWindow>
|
|
|
|
#include "config.h"
|
|
|
|
#include "app/App.hpp"
|
|
#include "components/calls/CallsListModel.hpp"
|
|
#include "components/core/CoreHandlers.hpp"
|
|
#include "components/core/CoreManager.hpp"
|
|
#include "components/settings/SettingsModel.hpp"
|
|
#include "utils/Utils.hpp"
|
|
|
|
#include "Cli.hpp"
|
|
|
|
// =============================================================================
|
|
|
|
using namespace std;
|
|
|
|
// =============================================================================
|
|
// API.
|
|
// =============================================================================
|
|
|
|
static void cliShow(QHash<QString, QString> &args) {
|
|
App *app = App::getInstance();
|
|
if (args.size() > 0) {
|
|
app->processArguments(args);
|
|
app->initContentApp();
|
|
}
|
|
app->smartShowWindow(app->getMainWindow());
|
|
}
|
|
|
|
static void cliCall(QHash<QString, QString> &args) {
|
|
QString addressToCall = args["sip-address"];
|
|
if (args.size() > 1) { // Call with options
|
|
App *app = App::getInstance();
|
|
args["call"] = args["sip-address"]; // Swap cli def to parser
|
|
args.remove("sip-address");
|
|
app->processArguments(args);
|
|
app->initContentApp();
|
|
} else CoreManager::getInstance()->getCallsListModel()->launchAudioCall(args["sip-address"], "");
|
|
}
|
|
|
|
static void cliAccept(QHash<QString, QString> &args) {
|
|
auto currentCall = CoreManager::getInstance()->getCore()->getCurrentCall();
|
|
App *app = App::getInstance();
|
|
if (args.size() > 0) {
|
|
app->processArguments(args);
|
|
app->initContentApp();
|
|
}
|
|
if (currentCall) {
|
|
currentCall->accept();
|
|
}
|
|
}
|
|
|
|
static void cliDecline(QHash<QString, QString> &args) {
|
|
auto currentCall = CoreManager::getInstance()->getCore()->getCurrentCall();
|
|
App *app = App::getInstance();
|
|
if (args.size() > 0) {
|
|
app->processArguments(args);
|
|
app->initContentApp();
|
|
}
|
|
if (currentCall) {
|
|
currentCall->decline(linphone::Reason::Declined);
|
|
}
|
|
}
|
|
|
|
static void cliBye(QHash<QString, QString> &args) {
|
|
auto currentCall = CoreManager::getInstance()->getCore()->getCurrentCall();
|
|
if (args.size() > 0) {
|
|
if (args["sip-address"] == "*") // Call with options
|
|
CoreManager::getInstance()->getCallsListModel()->terminateAllCalls();
|
|
else if (args["sip-address"] == "") {
|
|
if (currentCall) currentCall->terminate();
|
|
} else CoreManager::getInstance()->getCallsListModel()->terminateCall(args["sip-address"]);
|
|
} else if (currentCall) {
|
|
currentCall->terminate();
|
|
}
|
|
}
|
|
|
|
static void cliJoinConference(QHash<QString, QString> &args) {
|
|
const QString sipAddress = args.take("sip-address");
|
|
|
|
CoreManager *coreManager = CoreManager::getInstance();
|
|
const shared_ptr<linphone::Core> core = coreManager->getCore();
|
|
|
|
{
|
|
shared_ptr<linphone::Address> address = core->createPrimaryContactParsed();
|
|
address->setDisplayName(Utils::appStringToCoreString(args.take("display-name")));
|
|
core->setPrimaryContact(address->asString());
|
|
}
|
|
|
|
args["method"] = QStringLiteral("join-conference");
|
|
coreManager->getCallsListModel()->launchAudioCall(sipAddress, "", args);
|
|
}
|
|
|
|
static void cliJoinConferenceAs(QHash<QString, QString> &args) {
|
|
const QString fromSipAddress = args.take("guest-sip-address");
|
|
const QString toSipAddress = args.take("sip-address");
|
|
CoreManager *coreManager = CoreManager::getInstance();
|
|
/*shared_ptr<linphone::ProxyConfig> proxyConfig = coreManager->getCore()->getDefaultProxyConfig();
|
|
if (!proxyConfig) {
|
|
qWarning() << QStringLiteral("You have no proxy config.");
|
|
return;
|
|
}
|
|
|
|
const shared_ptr<const linphone::Address> currentSipAddress = proxyConfig->getIdentityAddress();
|
|
*/
|
|
shared_ptr<linphone::Account> account = coreManager->getCore()->getDefaultAccount();
|
|
if (!account) {
|
|
qWarning() << QStringLiteral("You have no account.");
|
|
return;
|
|
}
|
|
|
|
const shared_ptr<const linphone::Address> currentSipAddress = account->getParams()->getIdentityAddress();
|
|
const shared_ptr<const linphone::Address> askedSipAddress =
|
|
linphone::Factory::get()->createAddress(Utils::appStringToCoreString(fromSipAddress));
|
|
if (!currentSipAddress->weakEqual(askedSipAddress)) {
|
|
qWarning() << QStringLiteral("Guest sip address `%1` doesn't match with default account.").arg(fromSipAddress);
|
|
return;
|
|
}
|
|
|
|
args["method"] = QStringLiteral("join-conference");
|
|
coreManager->getCallsListModel()->launchAudioCall(toSipAddress, "", 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"]));
|
|
if (!address || address->getUsername().empty()) {
|
|
qWarning() << QStringLiteral("Unable to parse invalid sip address.");
|
|
return;
|
|
}
|
|
|
|
address->clean();
|
|
|
|
shared_ptr<linphone::Account> account = core->getDefaultAccount();
|
|
if (!account) {
|
|
qWarning() << QStringLiteral("Not connected to an account");
|
|
return;
|
|
}
|
|
if (!account->getParams()->getIdentityAddress()->weakEqual(address)) {
|
|
qWarning() << QStringLiteral("Received different sip address from identity : `%1 != %2`.")
|
|
.arg(Utils::coreStringToAppString(account->getParams()->getIdentityAddress()->asString()))
|
|
.arg(Utils::coreStringToAppString(address->asString()));
|
|
return;
|
|
}
|
|
|
|
shared_ptr<linphone::Conference> conference = core->searchConference(address);
|
|
const QString id = args["conference-id"];
|
|
|
|
auto updateCallsWindow = []() {
|
|
QQuickWindow *callsWindow = App::getInstance()->getCallsWindow();
|
|
if (!callsWindow) return;
|
|
|
|
// TODO: Set the view to the "waiting call view".
|
|
if (CoreManager::getInstance()->getSettingsModel()->getKeepCallsWindowInBackground()) {
|
|
if (!callsWindow->isVisible()) callsWindow->showMinimized();
|
|
} else App::smartShowWindow(callsWindow);
|
|
};
|
|
|
|
if (conference) {
|
|
qInfo() << QStringLiteral("Conference `%1` already exists.")
|
|
.arg(Utils::coreStringToAppString(conference->getConferenceAddress()->asString()));
|
|
updateCallsWindow();
|
|
return;
|
|
}
|
|
|
|
qInfo() << QStringLiteral("Create conference with id: `%1`.").arg(id);
|
|
auto confParameters = core->createConferenceParams(conference);
|
|
confParameters->enableVideo(false); // Video is not yet fully supported by the application in conference
|
|
conference = core->createConferenceWithParams(confParameters);
|
|
|
|
if (conference->enter() == -1) {
|
|
qWarning() << QStringLiteral("Unable to join created conference: `%1`.").arg(id);
|
|
return;
|
|
}
|
|
|
|
updateCallsWindow();
|
|
}
|
|
|
|
// =============================================================================
|
|
// Helpers.
|
|
// =============================================================================
|
|
|
|
static QString splitWord(QString word, int &curPos, const int lineLength, const QString &padding) {
|
|
QString out;
|
|
out += word.mid(0, lineLength - curPos) + "\n" + padding;
|
|
curPos = padding.length();
|
|
word = word.mid(lineLength - curPos);
|
|
while (word.length() > lineLength - curPos) {
|
|
out += word.mid(0, lineLength - curPos);
|
|
word = word.mid(lineLength - curPos);
|
|
out += "\n" + padding;
|
|
}
|
|
out += word;
|
|
curPos = word.length() + padding.length();
|
|
return out;
|
|
}
|
|
|
|
static QString indentedWord(QString word, int &curPos, const int lineLength, const QString &padding) {
|
|
QString out;
|
|
if (curPos + word.length() > lineLength) {
|
|
if (padding.length() + word.length() > lineLength) {
|
|
out += splitWord(word, curPos, lineLength, padding);
|
|
} else {
|
|
out += QStringLiteral("\n");
|
|
out += padding + word;
|
|
curPos = padding.length();
|
|
}
|
|
} else {
|
|
out += word;
|
|
curPos += word.length();
|
|
}
|
|
return out;
|
|
}
|
|
|
|
static string multilineIndent(const QString &str, int indentationNumber = 0) {
|
|
constexpr int lineLength(80);
|
|
|
|
static const QRegExp spaceRegexp("(\\s)");
|
|
const QString padding(indentationNumber * 2, ' ');
|
|
|
|
QString out = padding;
|
|
|
|
int indentedTextCurPos = padding.length();
|
|
|
|
int spacePos = 0;
|
|
int wordPos = spacePos;
|
|
QString word;
|
|
|
|
while ((spacePos = spaceRegexp.indexIn(str, spacePos)) != -1) {
|
|
word = str.mid(wordPos, spacePos - wordPos);
|
|
out += indentedWord(word, indentedTextCurPos, lineLength, padding);
|
|
switch (str[spacePos].unicode()) {
|
|
case '\n':
|
|
out += "\n" + padding;
|
|
indentedTextCurPos = padding.length();
|
|
break;
|
|
case '\t': // TAB as space.
|
|
case ' ':
|
|
if (indentedTextCurPos == lineLength) {
|
|
out += "\n" + padding;
|
|
indentedTextCurPos = padding.length();
|
|
} else {
|
|
out += " ";
|
|
indentedTextCurPos += 1;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
spacePos += 1;
|
|
wordPos = spacePos;
|
|
}
|
|
word = str.mid(wordPos);
|
|
out += indentedWord(word, indentedTextCurPos, lineLength, padding);
|
|
out += "\n";
|
|
|
|
return Utils::appStringToCoreString(out);
|
|
}
|
|
|
|
// =============================================================================
|
|
|
|
Cli::Command::Command(const QString &functionName,
|
|
const char *functionDescription,
|
|
Cli::Function function,
|
|
const QHash<QString, Cli::Argument> &argsScheme,
|
|
const bool &genericArguments)
|
|
: mFunctionName(functionName), mFunctionDescription(functionDescription), mFunction(function),
|
|
mArgsScheme(argsScheme), mGenericArguments(genericArguments) {
|
|
}
|
|
|
|
void Cli::Command::execute(QHash<QString, QString> &args) const {
|
|
if (!mGenericArguments) { // 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 (!mArgsScheme[argName].isOptional && (!args.contains(argName) || args[argName].isEmpty())) {
|
|
qWarning() << QStringLiteral("Missing argument for command: `%1 (%2)`.").arg(mFunctionName).arg(argName);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Execute!
|
|
App *app = App::getInstance();
|
|
if (app->isOpened()) {
|
|
qInfo() << QStringLiteral("Execute command:") << args;
|
|
(*mFunction)(args);
|
|
} else {
|
|
Function f = mFunction;
|
|
QObject *context = new QObject();
|
|
QObject::connect(app, &App::opened, [f, args, context]() mutable {
|
|
if (context) {
|
|
delete context;
|
|
context = nullptr;
|
|
qInfo() << QStringLiteral("Execute deferred command:") << args;
|
|
QHash<QString, QString> fuckConst = args;
|
|
(*f)(fuckConst);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
void Cli::Command::executeUri(QString address, QHash<QString, QString> args) const {
|
|
QUrl url(address);
|
|
QString query = url.query();
|
|
|
|
QStringList parameters = query.split('&');
|
|
for (int i = 0; i < parameters.size(); ++i) {
|
|
QStringList parameter = parameters[i].split('=');
|
|
if (parameter[0] != "" && parameter[0] != "method") {
|
|
if (parameter.size() > 1) args[parameter[0]] = QByteArray::fromBase64(parameter[1].toUtf8());
|
|
else args[parameter[0]] = "";
|
|
}
|
|
}
|
|
|
|
args["sip-address"] = address;
|
|
execute(args);
|
|
}
|
|
|
|
// pUrl can be `anytoken?p1=x&p2=y` or `p1=x&p2=y`. It will only use p1 and p2
|
|
void Cli::Command::executeUrl(const QString &pUrl) const {
|
|
QHash<QString, QString> args;
|
|
QStringList urlParts = pUrl.split('?');
|
|
QString query = (urlParts.size() > 1 ? urlParts[1] : urlParts[0]);
|
|
QString authority = (urlParts.size() > 1 && urlParts[0].contains(':') ? urlParts[0].split(':')[1] : "");
|
|
|
|
QStringList parameters = query.split('&');
|
|
for (int i = 0; i < parameters.size(); ++i) {
|
|
QStringList parameter = parameters[i].split('=');
|
|
if (parameter[0] != "method") {
|
|
if (parameter.size() > 1) args[parameter[0]] = QByteArray::fromBase64(parameter[1].toUtf8());
|
|
else args[parameter[0]] = "";
|
|
}
|
|
}
|
|
if (!authority.isEmpty()) args["sip-address"] = authority;
|
|
execute(args);
|
|
}
|
|
|
|
QString Cli::Command::getFunctionSyntax() const {
|
|
QString functionSyntax;
|
|
functionSyntax += QStringLiteral("\"");
|
|
functionSyntax += mFunctionName;
|
|
for (auto &argName : mArgsScheme.keys()) {
|
|
functionSyntax += QStringLiteral(" ");
|
|
functionSyntax += mArgsScheme[argName].isOptional ? QStringLiteral("[") : QStringLiteral("");
|
|
functionSyntax += argName;
|
|
functionSyntax += QStringLiteral("=<");
|
|
switch (mArgsScheme[argName].type) {
|
|
case String:
|
|
functionSyntax += QStringLiteral("str");
|
|
break;
|
|
default:
|
|
functionSyntax += QStringLiteral("value");
|
|
break;
|
|
}
|
|
functionSyntax += QString(">");
|
|
functionSyntax += mArgsScheme[argName].isOptional ? QStringLiteral("]") : QStringLiteral("");
|
|
}
|
|
functionSyntax += QStringLiteral("\"");
|
|
return functionSyntax;
|
|
}
|
|
|
|
// =============================================================================
|
|
|
|
// 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::mRegExpFunctionName("^\\s*([a-z-]+)\\s*");
|
|
|
|
QMap<QString, Cli::Command> Cli::mCommands = {
|
|
createCommand("show", QT_TR_NOOP("showFunctionDescription"), cliShow, QHash<QString, Argument>(), true),
|
|
createCommand("call", QT_TR_NOOP("callFunctionDescription"), cliCall, {{"sip-address", {}}}, true),
|
|
createCommand("initiate-conference",
|
|
QT_TR_NOOP("initiateConferenceFunctionDescription"),
|
|
cliInitiateConference,
|
|
{{"sip-address", {}}, {"conference-id", {}}}),
|
|
createCommand("join-conference",
|
|
QT_TR_NOOP("joinConferenceFunctionDescription"),
|
|
cliJoinConference,
|
|
{{"sip-address", {}}, {"conference-id", {}}, {"display-name", {}}}),
|
|
createCommand("join-conference-as",
|
|
QT_TR_NOOP("joinConferenceAsFunctionDescription"),
|
|
cliJoinConferenceAs,
|
|
{{"sip-address", {}}, {"conference-id", {}}, {"guest-sip-address", {}}}),
|
|
createCommand("bye", QT_TR_NOOP("byeFunctionDescription"), cliBye, QHash<QString, Argument>(), true),
|
|
createCommand("accept", QT_TR_NOOP("acceptFunctionDescription"), cliAccept, QHash<QString, Argument>(), true),
|
|
createCommand("decline", QT_TR_NOOP("declineFunctionDescription"), cliDecline, QHash<QString, Argument>(), true),
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------
|
|
/*
|
|
string Cli::getScheme(const QString& address){
|
|
QStringList tempSipAddress = address->split(':');
|
|
if( tempSipAddress.size() > 0)
|
|
return tempSipAddress[0].toStdString();
|
|
else
|
|
return "";
|
|
}
|
|
bool Cli::changeScheme(QString * address){
|
|
QStringList tempSipAddress = address->split(':');
|
|
string scheme;
|
|
bool ok = false;
|
|
if(tempSipAddress.size() > 1) {
|
|
scheme = tempSipAddress[0].toStdString();
|
|
for (const string &validScheme : { string("sip"), "sip-"+string(EXECUTABLE_NAME), string("sips"),
|
|
"sips-"+string(EXECUTABLE_NAME), string("tel"), string("callto"), string(EXECUTABLE_NAME)+ "-config" }) if (scheme ==
|
|
validScheme) ok = true; if( !ok){ qWarning() << QStringLiteral("Not a valid uri: `%1` Unsupported scheme:
|
|
`%2`.").arg(*address).arg(Utils::coreStringToAppString(scheme)); }else{ tempSipAddress[0] = "sip";// In order to pass
|
|
bellesip parsing. *address = tempSipAddress.join(':');
|
|
}
|
|
}
|
|
return ok;
|
|
}
|
|
*/
|
|
void Cli::executeCommand(const QString &command, CommandFormat *format) {
|
|
|
|
// Detect if command is a CLI by testing commands
|
|
const QString &functionName = parseFunctionName(command);
|
|
const std::string configURI = string(EXECUTABLE_NAME) + "-config";
|
|
if (!functionName.isEmpty()) { // It is a CLI
|
|
qInfo() << QStringLiteral("Detecting cli command: `%1`...").arg(command);
|
|
QHash<QString, QString> args = parseArgs(command);
|
|
mCommands[functionName].execute(args);
|
|
if (format) *format = CliFormat;
|
|
return;
|
|
} else { // It is a URI
|
|
QStringList tempSipAddress = command.split(':');
|
|
string scheme = "sip";
|
|
QString transformedCommand; // In order to pass bellesip parsing, set scheme to 'sip:'.
|
|
if (tempSipAddress.size() == 1) {
|
|
transformedCommand = "sip:" + command;
|
|
} else {
|
|
scheme = tempSipAddress[0].toStdString();
|
|
bool ok = false;
|
|
for (const string &validScheme :
|
|
{string("sip"), "sip-" + string(EXECUTABLE_NAME), string("sips"), "sips-" + string(EXECUTABLE_NAME),
|
|
string("tel"), string("callto"), configURI})
|
|
if (scheme == validScheme) ok = true;
|
|
if (!ok) {
|
|
qWarning() << QStringLiteral("Not a valid URI: `%1` Unsupported scheme: `%2`.")
|
|
.arg(command)
|
|
.arg(Utils::coreStringToAppString(scheme));
|
|
return;
|
|
}
|
|
tempSipAddress[0] = "sip";
|
|
transformedCommand = tempSipAddress.join(':');
|
|
}
|
|
if (scheme == configURI) {
|
|
QHash<QString, QString> args = parseArgs(command);
|
|
QString fetchUrl;
|
|
if (args.contains("fetch-config")) fetchUrl = QByteArray::fromBase64(args["fetch-config"].toUtf8());
|
|
else {
|
|
QUrl url(command.mid(configURI.size() + 1)); // Remove 'exec-config:'
|
|
if (url.scheme().isEmpty()) url.setScheme("https");
|
|
fetchUrl = url.toString();
|
|
}
|
|
if (format) *format = CliFormat;
|
|
QHash<QString, QString> dummy;
|
|
mCommands["show"].execute(dummy); // Just open the app.
|
|
App::getInstance()->useFetchConfig(fetchUrl);
|
|
} else {
|
|
shared_ptr<linphone::Address> address;
|
|
QString qAddress = transformedCommand;
|
|
if (Utils::isUsername(transformedCommand)) {
|
|
address = linphone::Factory::get()->createAddress(
|
|
Utils::appStringToCoreString(transformedCommand + "@to.remove"));
|
|
address->setDomain("");
|
|
qAddress = Utils::coreStringToAppString(address->asString());
|
|
if (address && qAddress.isEmpty()) qAddress = transformedCommand;
|
|
} else
|
|
address = linphone::Factory::get()->createAddress(
|
|
Utils::appStringToCoreString(transformedCommand)); // Test if command is an address
|
|
if (format) *format = UriFormat;
|
|
qInfo() << QStringLiteral("Detecting URI command: `%1`...").arg(command);
|
|
QString functionName;
|
|
if (address) {
|
|
functionName = Utils::coreStringToAppString(address->getHeader("method")).isEmpty()
|
|
? QStringLiteral("call")
|
|
: Utils::coreStringToAppString(address->getHeader("method"));
|
|
} else {
|
|
QStringList fields = command.split('?');
|
|
if (fields.size() > 1) {
|
|
fields = fields[1].split('&');
|
|
for (int i = 0; i < fields.size() && functionName.isEmpty(); ++i) {
|
|
QStringList data = fields[i].split('=');
|
|
if (data[0] == "method" && data.size() > 1) functionName = data[1];
|
|
}
|
|
if (functionName.isEmpty()) functionName = "call";
|
|
}
|
|
}
|
|
functionName = functionName.toLower();
|
|
if (functionName.isEmpty()) {
|
|
qWarning() << QStringLiteral("There is no method set in `%1`.").arg(command);
|
|
return;
|
|
} else if (!mCommands.contains(functionName)) {
|
|
qWarning() << QStringLiteral("This command doesn't exist: `%1`.").arg(functionName);
|
|
return;
|
|
}
|
|
if (address) {
|
|
// TODO: check if there is too much headers.
|
|
QHash<QString, QString> headers;
|
|
for (const auto &argName : mCommands[functionName].mArgsScheme.keys()) {
|
|
const string header = address->getHeader(Utils::appStringToCoreString(argName));
|
|
headers[argName] = QByteArray::fromBase64(QByteArray(header.c_str(), int(header.length())));
|
|
}
|
|
mCommands[functionName].executeUri(qAddress, headers);
|
|
} else mCommands[functionName].executeUrl(command);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Cli::showHelp() {
|
|
cout << multilineIndent(tr("appCliDescription").arg(APPLICATION_NAME), 0) << endl
|
|
<< "Usage: " << endl
|
|
<< multilineIndent(tr("uriCommandLineSyntax").arg(EXECUTABLE_NAME), 0)
|
|
<< multilineIndent(tr("cliCommandLineSyntax").arg(EXECUTABLE_NAME), 0) << endl
|
|
<< multilineIndent(tr("commandsName")) << endl;
|
|
|
|
for (const auto &method : mCommands.keys())
|
|
cout << multilineIndent(mCommands[method].getFunctionSyntax(), 1)
|
|
<< multilineIndent(tr(mCommands[method].getFunctionDescription()), 2) << endl;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
pair<QString, Cli::Command> Cli::createCommand(const QString &functionName,
|
|
const char *functionDescription,
|
|
Function function,
|
|
const QHash<QString, Argument> &argsScheme,
|
|
const bool &genericArguments) {
|
|
return {functionName.toLower(),
|
|
Cli::Command(functionName.toLower(), functionDescription, function, argsScheme, genericArguments)};
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
QString Cli::parseFunctionName(const QString &command) {
|
|
mRegExpFunctionName.indexIn(command.toLower());
|
|
if (mRegExpFunctionName.pos(1) == -1) {
|
|
qWarning() << QStringLiteral("Unable to parse function name of command: `%1`.").arg(command);
|
|
return QString("");
|
|
}
|
|
|
|
const QStringList texts = mRegExpFunctionName.capturedTexts();
|
|
|
|
const QString functionName = texts[1];
|
|
if (!mCommands.contains(functionName)) {
|
|
qWarning() << QStringLiteral("This command doesn't exist: `%1`.").arg(functionName);
|
|
return QString("");
|
|
}
|
|
|
|
return functionName;
|
|
}
|
|
|
|
QHash<QString, QString> Cli::parseArgs(const QString &command) {
|
|
QHash<QString, QString> args;
|
|
int pos = 0;
|
|
|
|
while ((pos = mRegExpArgs.indexIn(command.toLower(), pos)) != -1) {
|
|
pos += mRegExpArgs.matchedLength();
|
|
args[mRegExpArgs.cap(1)] = (mRegExpArgs.cap(2).isEmpty() ? mRegExpArgs.cap(3) : mRegExpArgs.cap(2));
|
|
}
|
|
|
|
return args;
|
|
}
|