mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Merge pull request #5789
jenli669 (2): feat(proxy): provide commandline tools for proxy settings docs(usermanual): Add information about commandline options
This commit is contained in:
commit
2dea6d2c1f
|
@ -10,6 +10,7 @@
|
|||
* [Quotes](#quotes)
|
||||
* [Multi Window Mode](#multi-window-mode)
|
||||
* [Keyboard Shortcuts](#keyboard-shortcuts)
|
||||
* [Commandline Options](#commandline-options)
|
||||
* [Emoji Packs](#emoji-packs)
|
||||
|
||||
|
||||
|
@ -429,6 +430,25 @@ The following shortcuts are currently supported:
|
|||
In audio group chat microphone mute state will be changed while `Ctrl` +
|
||||
`p` pressed and reverted on release.
|
||||
|
||||
## Commandline Options
|
||||
|
||||
| Option | Action |
|
||||
|------------------------------------|----------------------------------------------------|
|
||||
| `-p` `<profile>` | Use specified unencrypted profile |
|
||||
| `-l` | Start with loginscreen |
|
||||
| `-I` `<on/off>` | Sets IPv6 toggle [Default: ON] |
|
||||
| `-U` `<on/off>` | Sets UDP toggle [Default: ON] |
|
||||
| `-L` `<on/off>` | Sets LAN toggle [Default: ON] |
|
||||
| `-P` `<protocol>:<address>:<port>` | Applies [proxy options](#commandline-proxy-options) [Default: NONE]|
|
||||
|
||||
### Commandline Proxy Options
|
||||
Protocol: NONE, HTTP or SOCKS5 <br>
|
||||
Address: Proxy address <br>
|
||||
Port: Proxy port number (0-65535) <br>
|
||||
Example input: <br>
|
||||
`qtox -P SOCKS5:192.168.0.1:2121` <br>
|
||||
`qtox -P none`
|
||||
|
||||
## Emoji Packs
|
||||
|
||||
qTox provides support for custom emoji packs. To install a new emoji pack
|
||||
|
|
26
src/main.cpp
26
src/main.cpp
|
@ -215,6 +215,24 @@ int main(int argc, char* argv[])
|
|||
QCommandLineOption(QStringList() << "l"
|
||||
<< "login",
|
||||
QObject::tr("Starts new instance and opens the login screen.")));
|
||||
parser.addOption(QCommandLineOption(QStringList() << "I"
|
||||
<< "IPv6",
|
||||
QObject::tr("Sets IPv6 <on>/<off>. Default is ON."),
|
||||
QObject::tr("on/off")));
|
||||
parser.addOption(QCommandLineOption(QStringList() << "U"
|
||||
<< "UDP",
|
||||
QObject::tr("Sets UDP <on>/<off>. Default is ON."),
|
||||
QObject::tr("on/off")));
|
||||
parser.addOption(
|
||||
QCommandLineOption(QStringList() << "L"
|
||||
<< "LAN",
|
||||
QObject::tr(
|
||||
"Sets LAN discovery <on>/<off>. UDP off overrides. Default is ON."),
|
||||
QObject::tr("on/off")));
|
||||
parser.addOption(QCommandLineOption(QStringList() << "P"
|
||||
<< "proxy",
|
||||
QObject::tr("Sets proxy settings. Default is NONE."),
|
||||
QObject::tr("(SOCKS5/HTTP/NONE):(ADDRESS):(PORT)")));
|
||||
parser.process(*a);
|
||||
|
||||
uint32_t profileId = settings.getCurrentProfileId();
|
||||
|
@ -331,6 +349,10 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
}
|
||||
|
||||
if (!Settings::verifyProxySettings(parser)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO(sudden6): remove once we get rid of Nexus
|
||||
Nexus& nexus = Nexus::getInstance();
|
||||
// TODO(kriby): Consider moving application initializing variables into a globalSettings object
|
||||
|
@ -343,16 +365,16 @@ int main(int argc, char* argv[])
|
|||
// Further: generate view instances separately (loginScreen, mainGUI, audio)
|
||||
Profile* profile = nullptr;
|
||||
if (autoLogin && Profile::exists(profileName) && !Profile::isEncrypted(profileName)) {
|
||||
profile = Profile::loadProfile(profileName, QString(), settings);
|
||||
profile = Profile::loadProfile(profileName, QString(), settings, &parser);
|
||||
if (!profile) {
|
||||
QMessageBox::information(nullptr, QObject::tr("Error"),
|
||||
QObject::tr("Failed to load profile automatically."));
|
||||
}
|
||||
}
|
||||
if (profile) {
|
||||
settings.updateProfileData(profile);
|
||||
nexus.bootstrapWithProfile(profile);
|
||||
} else {
|
||||
nexus.setParser(&parser);
|
||||
int returnval = nexus.showLogin(profileName);
|
||||
if (returnval != 0) {
|
||||
return returnval;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "widget/gui.h"
|
||||
#include "widget/loginscreen.h"
|
||||
#include <QApplication>
|
||||
#include <QCommandLineParser>
|
||||
#include <QDebug>
|
||||
#include <QDesktopWidget>
|
||||
#include <QThread>
|
||||
|
@ -183,14 +184,10 @@ void Nexus::bootstrapWithProfile(Profile* p)
|
|||
void Nexus::setSettings(Settings* settings)
|
||||
{
|
||||
if (this->settings) {
|
||||
QObject::disconnect(this, &Nexus::currentProfileChanged, this->settings,
|
||||
&Settings::updateProfileData);
|
||||
QObject::disconnect(this, &Nexus::saveGlobal, this->settings, &Settings::saveGlobal);
|
||||
}
|
||||
this->settings = settings;
|
||||
if (this->settings) {
|
||||
QObject::connect(this, &Nexus::currentProfileChanged, this->settings,
|
||||
&Settings::updateProfileData);
|
||||
QObject::connect(this, &Nexus::saveGlobal, this->settings, &Settings::saveGlobal);
|
||||
}
|
||||
}
|
||||
|
@ -292,7 +289,8 @@ Profile* Nexus::getProfile()
|
|||
*/
|
||||
void Nexus::onCreateNewProfile(const QString& name, const QString& pass)
|
||||
{
|
||||
setProfile(Profile::createProfile(name, pass, *settings));
|
||||
setProfile(Profile::createProfile(name, pass, *settings, parser));
|
||||
parser = nullptr; // only apply cmdline proxy settings once
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -300,7 +298,8 @@ void Nexus::onCreateNewProfile(const QString& name, const QString& pass)
|
|||
*/
|
||||
void Nexus::onLoadProfile(const QString& name, const QString& pass)
|
||||
{
|
||||
setProfile(Profile::loadProfile(name, pass, *settings));
|
||||
setProfile(Profile::loadProfile(name, pass, *settings, parser));
|
||||
parser = nullptr; // only apply cmdline proxy settings once
|
||||
}
|
||||
/**
|
||||
* Changes the loaded profile and notifies listeners.
|
||||
|
@ -319,6 +318,11 @@ void Nexus::setProfile(Profile* p)
|
|||
emit currentProfileChanged(p);
|
||||
}
|
||||
|
||||
void Nexus::setParser(QCommandLineParser* parser)
|
||||
{
|
||||
this->parser = parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get desktop GUI widget.
|
||||
* @return nullptr if not started, desktop widget otherwise.
|
||||
|
@ -389,7 +393,7 @@ void Nexus::updateWindowsArg(QWindow* closedWindow)
|
|||
QAction* action = windowActions->addAction(windowList[i]->title());
|
||||
action->setCheckable(true);
|
||||
action->setChecked(windowList[i] == activeWindow);
|
||||
connect(action, &QAction::triggered, [=] { onOpenWindow(windowList[i]);});
|
||||
connect(action, &QAction::triggered, [=] { onOpenWindow(windowList[i]); });
|
||||
windowMenu->addAction(action);
|
||||
dockMenu->insertAction(dockLast, action);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ class Profile;
|
|||
class Settings;
|
||||
class LoginScreen;
|
||||
class Core;
|
||||
class QCommandLineParser;
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
class QMenuBar;
|
||||
|
@ -47,6 +48,7 @@ public:
|
|||
void start();
|
||||
void showMainGUI();
|
||||
void setSettings(Settings* settings);
|
||||
void setParser(QCommandLineParser* parser);
|
||||
static Nexus& getInstance();
|
||||
static void destroyInstance();
|
||||
static Core* getCore();
|
||||
|
@ -89,7 +91,7 @@ public slots:
|
|||
void onCreateNewProfile(const QString& name, const QString& pass);
|
||||
void onLoadProfile(const QString& name, const QString& pass);
|
||||
int showLogin(const QString& profileName = QString());
|
||||
void bootstrapWithProfile(Profile *p);
|
||||
void bootstrapWithProfile(Profile* p);
|
||||
|
||||
private:
|
||||
explicit Nexus(QObject* parent = nullptr);
|
||||
|
@ -102,6 +104,7 @@ private:
|
|||
Settings* settings;
|
||||
Widget* widget;
|
||||
std::unique_ptr<IAudioControl> audioControl;
|
||||
QCommandLineParser* parser = nullptr;
|
||||
};
|
||||
|
||||
#endif // NEXUS_H
|
||||
|
|
|
@ -291,7 +291,8 @@ Profile::Profile(const QString& name, const QString& password, std::unique_ptr<T
|
|||
*
|
||||
* @note If the profile is already in use return nullptr.
|
||||
*/
|
||||
Profile* Profile::loadProfile(const QString& name, const QString& password, Settings& settings)
|
||||
Profile* Profile::loadProfile(const QString& name, const QString& password, Settings& settings,
|
||||
const QCommandLineParser* parser)
|
||||
{
|
||||
if (ProfileLocker::hasLock()) {
|
||||
qCritical() << "Tried to load profile " << name << ", but another profile is already locked!";
|
||||
|
@ -315,7 +316,7 @@ Profile* Profile::loadProfile(const QString& name, const QString& password, Sett
|
|||
Profile* p = new Profile(name, password, std::move(tmpKey));
|
||||
|
||||
// Core settings are saved per profile, need to load them before starting Core
|
||||
settings.loadPersonal(name, tmpKey.get());
|
||||
settings.updateProfileData(p, parser);
|
||||
|
||||
p->initCore(toxsave, settings, /*isNewProfile*/ false);
|
||||
p->loadDatabase(password);
|
||||
|
@ -331,19 +332,21 @@ Profile* Profile::loadProfile(const QString& name, const QString& password, Sett
|
|||
*
|
||||
* @note If the profile is already in use return nullptr.
|
||||
*/
|
||||
Profile* Profile::createProfile(const QString& userName, const QString& password,
|
||||
const Settings& settings)
|
||||
Profile* Profile::createProfile(const QString& name, const QString& password, Settings& settings,
|
||||
const QCommandLineParser* parser)
|
||||
{
|
||||
CreateToxDataError error;
|
||||
QString path = Settings::getInstance().getSettingsDirPath() + userName + ".tox";
|
||||
std::unique_ptr<ToxEncrypt> tmpKey = createToxData(userName, password, path, error);
|
||||
QString path = Settings::getInstance().getSettingsDirPath() + name + ".tox";
|
||||
std::unique_ptr<ToxEncrypt> tmpKey = createToxData(name, password, path, error);
|
||||
|
||||
if (logCreateToxDataError(error, userName)) {
|
||||
if (logCreateToxDataError(error, name)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
settings.createPersonal(userName);
|
||||
Profile* p = new Profile(userName, password, std::move(tmpKey));
|
||||
settings.createPersonal(name);
|
||||
Profile* p = new Profile(name, password, std::move(tmpKey));
|
||||
settings.updateProfileData(p, parser);
|
||||
|
||||
p->initCore(QByteArray(), settings, /*isNewProfile*/ true);
|
||||
p->loadDatabase(password);
|
||||
return p;
|
||||
|
|
|
@ -35,15 +35,17 @@
|
|||
#include <memory>
|
||||
|
||||
class Settings;
|
||||
class QCommandLineParser;
|
||||
|
||||
class Profile : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static Profile* loadProfile(const QString& name, const QString& password, Settings& settings);
|
||||
static Profile* createProfile(const QString& name, const QString& password,
|
||||
const Settings& settings);
|
||||
static Profile* loadProfile(const QString& name, const QString& password, Settings& settings,
|
||||
const QCommandLineParser* parser);
|
||||
static Profile* createProfile(const QString& name, const QString& password, Settings& settings,
|
||||
const QCommandLineParser* parser);
|
||||
~Profile();
|
||||
|
||||
Core* getCore();
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include <QStandardPaths>
|
||||
#include <QStyleFactory>
|
||||
#include <QThread>
|
||||
#include <QtCore/QCommandLineParser>
|
||||
|
||||
/**
|
||||
* @var QHash<QString, QByteArray> Settings::widgetSettings
|
||||
|
@ -279,7 +280,7 @@ bool Settings::isToxPortable()
|
|||
return result;
|
||||
}
|
||||
|
||||
void Settings::updateProfileData(Profile* profile)
|
||||
void Settings::updateProfileData(Profile* profile, const QCommandLineParser* parser)
|
||||
{
|
||||
QMutexLocker locker{&bigLock};
|
||||
|
||||
|
@ -290,6 +291,192 @@ void Settings::updateProfileData(Profile* profile)
|
|||
setCurrentProfile(profile->getName());
|
||||
saveGlobal();
|
||||
loadPersonal(profile->getName(), profile->getPasskey());
|
||||
if (parser) {
|
||||
applyCommandLineOptions(*parser);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that commandline proxy settings are at least reasonable. Does not verify provided IP
|
||||
* or hostname addresses are valid. Code duplication with Settings::applyCommandLineOptions, which
|
||||
* also verifies arguments, should be removed in a future refactor.
|
||||
* @param parser QCommandLineParser instance
|
||||
*/
|
||||
bool Settings::verifyProxySettings(const QCommandLineParser& parser)
|
||||
{
|
||||
QString IPv6SettingString = parser.value("I").toLower();
|
||||
QString LANSettingString = parser.value("L").toLower();
|
||||
QString UDPSettingString = parser.value("U").toLower();
|
||||
QString proxySettingString = parser.value("proxy").toLower();
|
||||
QStringList proxySettingStrings = proxySettingString.split(":");
|
||||
|
||||
const QString SOCKS5 = QStringLiteral("socks5");
|
||||
const QString HTTP = QStringLiteral("http");
|
||||
const QString NONE = QStringLiteral("none");
|
||||
const QString ON = QStringLiteral("on");
|
||||
const QString OFF = QStringLiteral("off");
|
||||
|
||||
// Check for incompatible settings
|
||||
bool activeProxyType = false;
|
||||
|
||||
if (parser.isSet("P")) {
|
||||
activeProxyType = proxySettingStrings[0] == SOCKS5 || proxySettingStrings[0] == HTTP;
|
||||
}
|
||||
|
||||
if (parser.isSet("I")) {
|
||||
if (!(IPv6SettingString == ON || IPv6SettingString == OFF)) {
|
||||
qCritical() << "Unable to parse IPv6 setting.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (parser.isSet("U")) {
|
||||
if (!(UDPSettingString == ON || UDPSettingString == OFF)) {
|
||||
qCritical() << "Unable to parse UDP setting.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (parser.isSet("L")) {
|
||||
if (!(LANSettingString == ON || LANSettingString == OFF)) {
|
||||
qCritical() << "Unable to parse LAN setting.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (activeProxyType && UDPSettingString == ON) {
|
||||
qCritical() << "Cannot set UDP on with proxy.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (activeProxyType && LANSettingString == ON) {
|
||||
qCritical() << "Cannot set LAN discovery on with proxy.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (LANSettingString == ON && UDPSettingString == OFF) {
|
||||
qCritical() << "Incompatible UDP/LAN settings.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parser.isSet("P")) {
|
||||
if (proxySettingStrings[0] == NONE) {
|
||||
// slightly lazy check here, accepting 'NONE[:.*]' is fine since no other
|
||||
// arguments will be investigated when proxy settings are applied.
|
||||
return true;
|
||||
}
|
||||
// Since the first argument isn't 'none', verify format of remaining arguments
|
||||
if (proxySettingStrings.size() != 3) {
|
||||
qCritical() << "Invalid number of proxy arguments.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(proxySettingStrings[0] == SOCKS5 || proxySettingStrings[0] == HTTP)) {
|
||||
qCritical() << "Unable to parse proxy type.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(Kriby): Sanity check IPv4/IPv6 addresses/hostnames?
|
||||
|
||||
int portNumber = proxySettingStrings[2].toInt();
|
||||
if (!(portNumber > 0 && portNumber < 65536)) {
|
||||
qCritical() << "Invalid port number range.";
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies command line options on top of loaded settings. Fails without changes if attempting to
|
||||
* apply contradicting settings.
|
||||
* @param parser QCommandLineParser instance
|
||||
* @return Success indicator (success = true)
|
||||
*/
|
||||
bool Settings::applyCommandLineOptions(const QCommandLineParser& parser)
|
||||
{
|
||||
if (!verifyProxySettings(parser)) {
|
||||
return false;
|
||||
};
|
||||
|
||||
QString IPv6Setting = parser.value("I").toUpper();
|
||||
QString LANSetting = parser.value("L").toUpper();
|
||||
QString UDPSetting = parser.value("U").toUpper();
|
||||
QString proxySettingString = parser.value("proxy").toUpper();
|
||||
QStringList proxySettings = proxySettingString.split(":");
|
||||
|
||||
const QString SOCKS5 = QStringLiteral("SOCKS5");
|
||||
const QString HTTP = QStringLiteral("HTTP");
|
||||
const QString NONE = QStringLiteral("NONE");
|
||||
const QString ON = QStringLiteral("ON");
|
||||
const QString OFF = QStringLiteral("OFF");
|
||||
|
||||
|
||||
if (parser.isSet("I")) {
|
||||
enableIPv6 = IPv6Setting == ON;
|
||||
qDebug() << QString("Setting IPv6 %1.").arg(IPv6Setting);
|
||||
}
|
||||
|
||||
if (parser.isSet("P")) {
|
||||
qDebug() << QString("Setting proxy type to %1.").arg(proxySettings[0]);
|
||||
|
||||
quint16 portNumber = 0;
|
||||
QString address = "";
|
||||
|
||||
if (proxySettings[0] == NONE) {
|
||||
proxyType = ICoreSettings::ProxyType::ptNone;
|
||||
} else {
|
||||
if (proxySettings[0] == SOCKS5) {
|
||||
proxyType = ICoreSettings::ProxyType::ptSOCKS5;
|
||||
} else if (proxySettings[0] == HTTP) {
|
||||
proxyType = ICoreSettings::ProxyType::ptHTTP;
|
||||
} else {
|
||||
qCritical() << "Failed to set valid proxy type";
|
||||
assert(false); // verifyProxySettings should've made this impossible
|
||||
}
|
||||
|
||||
forceTCP = true;
|
||||
enableLanDiscovery = false;
|
||||
|
||||
address = proxySettings[1];
|
||||
portNumber = static_cast<quint16>(proxySettings[2].toInt());
|
||||
}
|
||||
|
||||
|
||||
proxyAddr = address;
|
||||
qDebug() << QString("Setting proxy address to %1.").arg(address);
|
||||
proxyPort = portNumber;
|
||||
qDebug() << QString("Setting port number to %1.").arg(portNumber);
|
||||
}
|
||||
|
||||
if (parser.isSet("U")) {
|
||||
bool shouldForceTCP = UDPSetting == OFF;
|
||||
if (!shouldForceTCP && proxyType != ICoreSettings::ProxyType::ptNone) {
|
||||
qDebug() << "Cannot use UDP with proxy; disable proxy explicitly with '-P none'.";
|
||||
} else {
|
||||
forceTCP = shouldForceTCP;
|
||||
qDebug() << QString("Setting UDP %1.").arg(UDPSetting);
|
||||
}
|
||||
|
||||
// LANSetting == ON is caught by verifyProxySettings, the OFF check removes needless debug
|
||||
if (shouldForceTCP && !(LANSetting == OFF) && enableLanDiscovery) {
|
||||
qDebug() << "Cannot perform LAN discovery without UDP; disabling LAN discovery.";
|
||||
enableLanDiscovery = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (parser.isSet("L")) {
|
||||
bool shouldEnableLAN = LANSetting == ON;
|
||||
|
||||
if (shouldEnableLAN && proxyType != ICoreSettings::ProxyType::ptNone) {
|
||||
qDebug()
|
||||
<< "Cannot use LAN discovery with proxy; disable proxy explicitly with '-P none'.";
|
||||
} else if (shouldEnableLAN && forceTCP) {
|
||||
qDebug() << "Cannot use LAN discovery without UDP; enable UDP explicitly with '-U on'.";
|
||||
} else {
|
||||
enableLanDiscovery = shouldEnableLAN;
|
||||
qDebug() << QString("Setting LAN Discovery %1.").arg(LANSetting);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Settings::loadPersonal(QString profileName, const ToxEncrypt* passKey)
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <QPixmap>
|
||||
|
||||
class Profile;
|
||||
class QCommandLineParser;
|
||||
|
||||
namespace Db {
|
||||
enum class syncType;
|
||||
|
@ -170,7 +171,7 @@ public slots:
|
|||
void saveGlobal();
|
||||
void sync();
|
||||
void setAutoLogin(bool state);
|
||||
void updateProfileData(Profile* profile);
|
||||
void updateProfileData(Profile* profile, const QCommandLineParser* parser);
|
||||
|
||||
signals:
|
||||
// General
|
||||
|
@ -238,6 +239,9 @@ signals:
|
|||
void blackListChanged(QStringList& blist);
|
||||
|
||||
public:
|
||||
bool applyCommandLineOptions(const QCommandLineParser& parser);
|
||||
static bool verifyProxySettings(const QCommandLineParser& parser);
|
||||
|
||||
bool getMakeToxPortable() const;
|
||||
void setMakeToxPortable(bool newValue);
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user