[Version] Version 1.3.7 Release

Signed-off-by: Leroy.H.Y <lhy20010403@hotmail.com>
This commit is contained in:
Leroy.H.Y 2019-09-21 21:17:57 +08:00
commit ce6be82497
No known key found for this signature in database
GPG Key ID: 6AC1673B587DC37D
26 changed files with 707 additions and 669 deletions

View File

@ -14,7 +14,7 @@ CONFIG += c++11 openssl openssl-linked lrelease embed_translations
win32: QMAKE_TARGET_DESCRIPTION = "Qv2ray, a cross-platform v2ray GUI client." win32: QMAKE_TARGET_DESCRIPTION = "Qv2ray, a cross-platform v2ray GUI client."
win32: QMAKE_TARGET_PRODUCT = "Qv2ray" win32: QMAKE_TARGET_PRODUCT = "Qv2ray"
VERSION = 1.3.6.1 VERSION = 1.3.7.0
DEFINES += QV_MAJOR_VERSION=\"\\\"$${VERSION}\\\"\" DEFINES += QV_MAJOR_VERSION=\"\\\"$${VERSION}\\\"\"
SOURCES += \ SOURCES += \

View File

@ -7,10 +7,22 @@
#define QV2RAY_VERSION_STRING "v" QV_MAJOR_VERSION #define QV2RAY_VERSION_STRING "v" QV_MAJOR_VERSION
#define QV2RAY_CONFIG_VERSION 2 #define QV2RAY_CONFIG_VERSION 3
// Base folder.
#define QV2RAY_CONFIG_DIR_PATH (Qv2ray::Utils::GetConfigDirPath() + "/") #define QV2RAY_CONFIG_DIR_PATH (Qv2ray::Utils::GetConfigDirPath() + "/")
#define QV2RAY_CONFIG_FILE_PATH (QV2RAY_CONFIG_DIR_PATH + "Qv2ray.conf") #define QV2RAY_CONFIG_FILE_PATH (QV2RAY_CONFIG_DIR_PATH + "Qv2ray.conf")
// We need v2ray.exe/v2ray executables here!
#define QV2RAY_V2RAY_CORE_DIR_PATH (QV2RAY_CONFIG_DIR_PATH + "vcore/")
#ifdef __WIN32
// Win32 has .exe
#define QV2RAY_V2RAY_CORE_PATH (QV2RAY_V2RAY_CORE_DIR_PATH + "v2ray.exe")
#else
// MacOS and Linux....
#define QV2RAY_V2RAY_CORE_PATH (QV2RAY_V2RAY_CORE_DIR_PATH + "v2ray")
#endif
#define QV2RAY_CONNECTION_FILE_EXTENSION ".qv2ray.json" #define QV2RAY_CONNECTION_FILE_EXTENSION ".qv2ray.json"
#define QV2RAY_GENERATED_FILE_PATH (QV2RAY_CONFIG_DIR_PATH + "generated/config.gen.json") #define QV2RAY_GENERATED_FILE_PATH (QV2RAY_CONFIG_DIR_PATH + "generated/config.gen.json")
@ -18,15 +30,6 @@
#define QV2RAY_VCORE_ACCESS_LOG_FILENAME "access.log" #define QV2RAY_VCORE_ACCESS_LOG_FILENAME "access.log"
#define QV2RAY_VCORE_ERROR_LOG_FILENAME "error.log" #define QV2RAY_VCORE_ERROR_LOG_FILENAME "error.log"
// These is for early-2.0 version, final 2.0 will move these content into global config.
#define QV2RAY_CONFIG_TYPE_FILE "File"
#define QV2RAY_CONFIG_TYPE_MANUAL "Manual"
#define QV2RAY_CONFIG_TYPE_CONNECTIONSTRING "ConnectionString"
#define QV2RAY_CONFIG_TYPE_SUBSCRIPTION "Subscription"
#define QV2RAY_CONFIG_TYPE_JSON_KEY "_qv2ray.configSource"
// GUI TOOLS // GUI TOOLS
#define RED(obj) \ #define RED(obj) \
auto _temp = ui->obj->palette(); \ auto _temp = ui->obj->palette(); \
@ -77,7 +80,6 @@ namespace Qv2ray
int logLevel; int logLevel;
// //
string language; string language;
string v2CorePath;
string v2AssetsPath; string v2AssetsPath;
string autoStartConfig; string autoStartConfig;
// //
@ -97,13 +99,12 @@ namespace Qv2ray
map<string, string> subscribes; map<string, string> subscribes;
MuxObject mux; MuxObject mux;
Qv2rayConfig(): config_version(QV2RAY_CONFIG_VERSION), runAsRoot(false), logLevel(), proxyDefault(), proxyCN(), withLocalDNS(), inBoundSettings(), configs(), subscribes(), mux() { } Qv2rayConfig(): config_version(QV2RAY_CONFIG_VERSION), runAsRoot(false), logLevel(), proxyDefault(), proxyCN(), withLocalDNS(), inBoundSettings(), configs(), subscribes(), mux() { }
Qv2rayConfig(string lang, string exePath, string assetsPath, int log, Qv2rayBasicInboundsConfig _inBoundSettings): Qv2rayConfig() Qv2rayConfig(string lang, string assetsPath, int log, Qv2rayBasicInboundsConfig _inBoundSettings): Qv2rayConfig()
{ {
// These settings below are defaults. // These settings below are defaults.
ignoredVersion = ""; ignoredVersion = "";
autoStartConfig = ""; autoStartConfig = "";
language = lang; language = lang;
v2CorePath = exePath;
v2AssetsPath = assetsPath; v2AssetsPath = assetsPath;
logLevel = log; logLevel = log;
inBoundSettings = _inBoundSettings; inBoundSettings = _inBoundSettings;
@ -116,7 +117,7 @@ namespace Qv2ray
proxyDefault = true; proxyDefault = true;
withLocalDNS = true; withLocalDNS = true;
} }
XTOSTRUCT(O(config_version, runAsRoot, logLevel, language, autoStartConfig, ignoredVersion, v2CorePath, v2AssetsPath, proxyDefault, proxyCN, withLocalDNS, dnsList, inBoundSettings, mux, configs, subscribes)) XTOSTRUCT(O(config_version, runAsRoot, logLevel, language, autoStartConfig, ignoredVersion, v2AssetsPath, proxyDefault, proxyCN, withLocalDNS, dnsList, inBoundSettings, mux, configs, subscribes))
}; };
QJsonObject UpgradeConfig(int fromVersion, int toVersion, QJsonObject root); QJsonObject UpgradeConfig(int fromVersion, int toVersion, QJsonObject root);

View File

@ -3,7 +3,7 @@
// from old to newer versions of Qv2ray. // from old to newer versions of Qv2ray.
// //
#include "Qv2rayBase.h" #include "QvUtils.h"
#define UPGRADELOG(item, old, _new) LOG(MODULE_CONFIG, "Upgrading " item " from old value " + old + " to " + _new); #define UPGRADELOG(item, old, _new) LOG(MODULE_CONFIG, "Upgrading " item " from old value " + old + " to " + _new);
#define XConfLog(oldVersion, newVersion) LOG(MODULE_CONFIG, "Migrating config from version " + oldVersion + " to " + newVersion); #define XConfLog(oldVersion, newVersion) LOG(MODULE_CONFIG, "Migrating config from version " + oldVersion + " to " + newVersion);
@ -18,7 +18,7 @@ namespace Qv2ray
XConfLog(to_string(fromVersion), to_string(fromVersion + 1)) XConfLog(to_string(fromVersion), to_string(fromVersion + 1))
switch (fromVersion) { switch (fromVersion) {
case 1: case 1: {
// From 1 to 2, we changed the config_version from 'string' to 'int' // From 1 to 2, we changed the config_version from 'string' to 'int'
auto old_config_version = root["config_version"].toString(); auto old_config_version = root["config_version"].toString();
root.remove("config_version"); root.remove("config_version");
@ -27,6 +27,22 @@ namespace Qv2ray
break; break;
} }
case 2 : {
auto vCoreFilePath = root["v2CorePath"].toString();
auto vCoreDestPath = QV2RAY_V2RAY_CORE_PATH;
// We also need v2ctl
auto v2CtlFilePath = QFileInfo(vCoreFilePath).dir().path() + "/v2ctl";
auto v2CtlDestPath = QFileInfo(vCoreDestPath).dir().path() + "/v2ctl";
QFile::copy(vCoreFilePath, vCoreDestPath);
QFile::copy(v2CtlFilePath, v2CtlDestPath);
root.remove("v2CorePath");
UPGRADELOG("v2CorePath", vCoreFilePath.toStdString(), vCoreDestPath.toStdString())
UPGRADELOG("v2CtlFilePath", v2CtlFilePath.toStdString(), v2CtlDestPath.toStdString())
break;
}
}
root["config_version"] = root["config_version"].toInt() + 1;
return root; return root;
} }

View File

@ -16,10 +16,6 @@ namespace Qv2ray
{ {
namespace V2ConfigModels namespace V2ConfigModels
{ {
struct VMessProtocolConfigObject {
string v, ps, add, port, id, aid, net, type, host, path, tls;
XTOSTRUCT(O(v, ps, add, port, id, aid, net, type, host, path, tls))
};
// //
// Used in config generation // Used in config generation
struct AccountObject { struct AccountObject {

View File

@ -57,7 +57,7 @@ namespace Qv2ray
bool SaveConnectionConfig(QJsonObject obj, const QString *alias); bool SaveConnectionConfig(QJsonObject obj, const QString *alias);
bool RenameConnection(QString originalName, QString newName); bool RenameConnection(QString originalName, QString newName);
// VMess Protocol // VMess Protocol
QJsonObject ConvertConfigFromVMessString(QString vmess, QString source = QV2RAY_CONFIG_TYPE_CONNECTIONSTRING); QJsonObject ConvertConfigFromVMessString(QString vmess);
QJsonObject ConvertConfigFromFile(QString sourceFilePath, bool overrideInbounds); QJsonObject ConvertConfigFromFile(QString sourceFilePath, bool overrideInbounds);
// Load Configs // Load Configs
QMap<QString, QJsonObject> GetConnections(list<string> connections); QMap<QString, QJsonObject> GetConnections(list<string> connections);

View File

@ -7,25 +7,39 @@ namespace Qv2ray
bool SaveConnectionConfig(QJsonObject obj, const QString *alias) bool SaveConnectionConfig(QJsonObject obj, const QString *alias)
{ {
QFile config(QV2RAY_CONFIG_DIR_PATH + *alias + QV2RAY_CONNECTION_FILE_EXTENSION); QFile config(QV2RAY_CONFIG_DIR_PATH + *alias + QV2RAY_CONNECTION_FILE_EXTENSION);
return StringToFile(JSONToString(obj), &config); auto str = JSONToString(obj);
return StringToFile(&str, &config);
} }
// This generates global config containing only one outbound.... // This generates global config containing only one outbound....
QJsonObject ConvertConfigFromVMessString(QString str, QString source) QJsonObject ConvertConfigFromVMessString(QString str)
{ {
DROOT DROOT
QStringRef vmessJsonB64(&str, 8, str.length() - 8); QStringRef vmessJsonB64(&str, 8, str.length() - 8);
auto vmessConf = StructFromJSONString<VMessProtocolConfigObject>(Base64Decode(vmessJsonB64.toString())); auto vmessConf = JSONFromString(Base64Decode(vmessJsonB64.toString()));
string ps, add, id, net, type, host, path, tls;
int port, aid;
ps = vmessConf["ps"].toVariant().toString().toStdString();
add = vmessConf["add"].toVariant().toString().toStdString();
id = vmessConf["id"].toVariant().toString().toStdString();
net = vmessConf["net"].toVariant().toString().toStdString();
type = vmessConf["type"].toVariant().toString().toStdString();
host = vmessConf["host"].toVariant().toString().toStdString();
path = vmessConf["path"].toVariant().toString().toStdString();
tls = vmessConf["tls"].toVariant().toString().toStdString();
//
port = vmessConf["port"].toVariant().toInt();
aid = vmessConf["aid"].toVariant().toInt();
// //
// User // User
VMessServerObject::UserObject user; VMessServerObject::UserObject user;
user.id = vmessConf.id; user.id = id;
user.alterId = stoi(vmessConf.aid); user.alterId = aid;
// //
// Server // Server
VMessServerObject serv; VMessServerObject serv;
serv.port = stoi(vmessConf.port); serv.port = port;
serv.address = vmessConf.add; serv.address = add;
serv.users.push_back(user); serv.users.push_back(user);
// //
// VMess root config // VMess root config
@ -38,35 +52,34 @@ namespace Qv2ray
StreamSettingsObject streaming; StreamSettingsObject streaming;
// Fill hosts for HTTP // Fill hosts for HTTP
foreach (auto host, QString::fromStdString(vmessConf.host).split(',')) { foreach (auto _host, QString::fromStdString(host).split(',')) {
streaming.httpSettings.host.push_back(host.toStdString()); streaming.httpSettings.host.push_back(_host.toStdString());
} }
// hosts for ws, h2 and security for QUIC // hosts for ws, h2 and security for QUIC
streaming.wsSettings.headers.insert(make_pair("Host", vmessConf.host)); streaming.wsSettings.headers.insert(make_pair("Host", host));
streaming.quicSettings.security = vmessConf.host; streaming.quicSettings.security = host;
// //
// Fake type for tcp, kcp and QUIC // Fake type for tcp, kcp and QUIC
streaming.tcpSettings.header.type = vmessConf.type; streaming.tcpSettings.header.type = type;
streaming.kcpSettings.header.type = vmessConf.type; streaming.kcpSettings.header.type = type;
streaming.quicSettings.header.type = vmessConf.type; streaming.quicSettings.header.type = type;
// //
// Path for ws, h2, Quic // Path for ws, h2, Quic
streaming.wsSettings.path = vmessConf.path; streaming.wsSettings.path = path;
streaming.httpSettings.path = vmessConf.path; streaming.httpSettings.path = path;
streaming.quicSettings.key = vmessConf.path; streaming.quicSettings.key = path;
streaming.security = vmessConf.tls; streaming.security = tls;
// //
// Network type // Network type
streaming.network = vmessConf.net; streaming.network = net;
// //
auto outbound = GenerateOutboundEntry("vmess", vConf, GetRootObject(streaming), GetRootObject(GetGlobalConfig().mux), "0.0.0.0", OUTBOUND_TAG_PROXY); auto outbound = GenerateOutboundEntry("vmess", vConf, GetRootObject(streaming), GetRootObject(GetGlobalConfig().mux), "0.0.0.0", OUTBOUND_TAG_PROXY);
// //
QJsonArray outbounds; QJsonArray outbounds;
outbounds.append(outbound); outbounds.append(outbound);
root.insert("outbounds", outbounds); root.insert("outbounds", outbounds);
root.insert("QV2RAY_ALIAS", QString::fromStdString(vmessConf.ps)); root.insert("QV2RAY_ALIAS", QString::fromStdString(ps));
root.insert(QV2RAY_CONFIG_TYPE_JSON_KEY, source);
RROOT RROOT
} }
@ -82,7 +95,6 @@ namespace Qv2ray
JSON_ROOT_TRY_REMOVE("api") JSON_ROOT_TRY_REMOVE("api")
JSON_ROOT_TRY_REMOVE("stats") JSON_ROOT_TRY_REMOVE("stats")
JSON_ROOT_TRY_REMOVE("dns") JSON_ROOT_TRY_REMOVE("dns")
root.insert(QV2RAY_CONFIG_TYPE_JSON_KEY, QV2RAY_CONFIG_TYPE_FILE);
return root; return root;
} }
@ -107,7 +119,7 @@ namespace Qv2ray
int StartPreparation(QJsonObject fullConfig) int StartPreparation(QJsonObject fullConfig)
{ {
QString json = JSONToString(fullConfig); QString json = JSONToString(fullConfig);
StringToFile(json, new QFile(QV2RAY_GENERATED_FILE_PATH)); StringToFile(&json, new QFile(QV2RAY_GENERATED_FILE_PATH));
return 0; return 0;
} }
} }

View File

@ -4,6 +4,7 @@ namespace Qv2ray
{ {
namespace ConfigOperations namespace ConfigOperations
{ {
static const QStringList vLogLevels = {"none", "debug", "info", "warning", "error"};
// -------------------------- BEGIN CONFIG GENERATIONS ---------------------------------------------------------------------------- // -------------------------- BEGIN CONFIG GENERATIONS ----------------------------------------------------------------------------
QJsonObject GenerateRoutes(bool globalProxy, bool cnProxy) QJsonObject GenerateRoutes(bool globalProxy, bool cnProxy)
{ {
@ -129,33 +130,11 @@ namespace Qv2ray
{ {
auto gConf = GetGlobalConfig(); auto gConf = GetGlobalConfig();
QJsonObject logObject; QJsonObject logObject;
//
//logObject.insert("access", QV2RAY_CONFIG_PATH + QV2RAY_VCORE_LOG_DIRNAME + QV2RAY_VCORE_ACCESS_LOG_FILENAME); //logObject.insert("access", QV2RAY_CONFIG_PATH + QV2RAY_VCORE_LOG_DIRNAME + QV2RAY_VCORE_ACCESS_LOG_FILENAME);
//logObject.insert("error", QV2RAY_CONFIG_PATH + QV2RAY_VCORE_LOG_DIRNAME + QV2RAY_VCORE_ERROR_LOG_FILENAME); //logObject.insert("error", QV2RAY_CONFIG_PATH + QV2RAY_VCORE_LOG_DIRNAME + QV2RAY_VCORE_ERROR_LOG_FILENAME);
QString logLevel_s; //
logObject.insert("loglevel", vLogLevels[gConf.logLevel]);
switch (gConf.logLevel) {
case 0:
logLevel_s = "none";
break;
case 1:
logLevel_s = "debug";
break;
case 2:
logLevel_s = "info";
break;
case 3:
logLevel_s = "warning";
break;
case 4:
logLevel_s = "error";
break;
}
logObject.insert("loglevel", logLevel_s);
root.insert("log", logObject); root.insert("log", logObject);
// //
QStringList dnsList; QStringList dnsList;
@ -166,16 +145,6 @@ namespace Qv2ray
auto dnsObject = GenerateDNS(gConf.withLocalDNS, dnsList); auto dnsObject = GenerateDNS(gConf.withLocalDNS, dnsList);
root.insert("dns", dnsObject); root.insert("dns", dnsObject);
//
// This is for imported config files as there are routing entries already.
// We don't add extra routings.
// We don't use QV2RAY_CONFIG_TYPE_FILE checking scheme because not all connections have this part.
if (!root.contains("routing")) {
auto routeObject = GenerateRoutes(gConf.proxyDefault, gConf.proxyCN);
root.insert("routing", routeObject);
}
// //
// //
root.insert("stats", QJsonObject()); root.insert("stats", QJsonObject());
@ -210,23 +179,43 @@ namespace Qv2ray
inboundsList.append(socksInBoundObject); inboundsList.append(socksInBoundObject);
} }
if (!root.contains("inbounds") || root["inbounds"].toArray().count() == 0) { if (!root.contains("inbounds") || root["inbounds"].toArray().empty()) {
root.insert("inbounds", inboundsList); root.insert("inbounds", inboundsList);
} }
// TODO: MultiOutbound Settings // Note: The part below always makes the whole functionality in trouble......
if (root.contains(QV2RAY_CONFIG_TYPE_JSON_KEY) && root[QV2RAY_CONFIG_TYPE_JSON_KEY] == QV2RAY_CONFIG_TYPE_FILE) { // BE EXTREME CAREFUL when changing these code below...
LOG(MODULE_CONFIG, "Found an imported config file, skipping adding 'freedom' outbound.") //
// Do nothing because it's an imported connection.
} else { // For SOME configs, there is no "route" entries, so, we add some...
// We don't use QV2RAY_CONFIG_TYPE_FILE to check because not all IMPORTED connections have routings.
if (!root.contains("routing")) {
if (root["outbounds"].toArray().count() != 1) {
// There are no ROUTING but 2 or more outbounds.... This is rare, but possible.
LOG(MODULE_CONNECTION, "WARN: This message usually indicates the config file has some logic errors:")
LOG(MODULE_CONNECTION, "WARN: --> The config file has NO routing section, however more than 1 outbounds are detected.")
}
LOG(MODULE_CONNECTION, "Current connection has NO ROUTING section, we insert default values.")
auto routeObject = GenerateRoutes(gConf.proxyDefault, gConf.proxyCN);
root.insert("routing", routeObject);
QJsonArray outbounds = root["outbounds"].toArray(); QJsonArray outbounds = root["outbounds"].toArray();
// It's not imported so we add new stuff.
// For DIRECT
outbounds.append(GenerateOutboundEntry("freedom", GenerateFreedomOUT("AsIs", ":0", 0), QJsonObject(), QJsonObject(), "0.0.0.0", OUTBOUND_TAG_DIRECT)); outbounds.append(GenerateOutboundEntry("freedom", GenerateFreedomOUT("AsIs", ":0", 0), QJsonObject(), QJsonObject(), "0.0.0.0", OUTBOUND_TAG_DIRECT));
QJsonObject first = outbounds.first().toObject(); // TODO
first.insert("mux", GetRootObject(gConf.mux)); //
outbounds[0] = first; // We don't want to add MUX into the first one in the list.....
// However, this can be added to the Connection Edit Window...
//QJsonObject first = outbounds.first().toObject();
//first.insert("mux", GetRootObject(gConf.mux));
//outbounds[0] = first;
//
root["outbounds"] = outbounds; root["outbounds"] = outbounds;
} else {
// For some config files that has routing entries already.
// We don't add extra routings.
// this part has been left blanking
LOG(MODULE_CONNECTION, "Skip adding 'freedom' entry.")
} }
return root; return root;

View File

@ -16,10 +16,15 @@ namespace Qv2ray
try { try {
QStringRef vmessJsonB64(&vmess, 8, vmess.length() - 8); QStringRef vmessJsonB64(&vmess, 8, vmess.length() - 8);
auto vmessString = Base64Decode(vmessJsonB64.toString()); auto vmessString = Base64Decode(vmessJsonB64.toString());
auto vmessConf = StructFromJSONString<VMessProtocolConfigObject>(vmessString); auto vmessConf = JSONFromString(vmessString);
return 0; // C is a quick hack...
#define C(k) vmessConf.contains(k)
//string v, ps, add, port, id, aid, net, type, host, path, tls;
bool flag = C("v") && C("ps") && C("add") && C("port") && C("id") && C("aid") && C("net") && C("type") && C("host") && C("path") && C("tls");
#undef C
return flag ? 0 : 1;
} catch (exception *e) { } catch (exception *e) {
LOG(MODULE_CONNECTION, QObject::tr("#VMessDecodeError").toStdString() << e->what()) LOG(MODULE_CONNECTION, "Failed to decode vmess string: " << e->what())
return -2; return -2;
} }
} }

View File

@ -1,56 +1,58 @@
#include <QObject> #include <QObject>
#include <QWidget> #include <QWidget>
#include <QDesktopServices>
#include "QvCoreInteractions.h" #include "QvCoreInteractions.h"
#include "QvCoreConfigOperations.h" #include "QvCoreConfigOperations.h"
#include "QvTinyLog.h"
#include "w_MainWindow.h" #include "w_MainWindow.h"
namespace Qv2ray namespace Qv2ray
{ {
bool Qv2Instance::VerifyVConfigFile(const QString path) bool Qv2Instance::VerifyVConfigFile(const QString *path)
{ {
if (ValidateV2rayCoreExe()) { if (ValidateV2rayCoreExe()) {
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("V2RAY_LOCATION_ASSET", QString::fromStdString(GetGlobalConfig().v2AssetsPath)); env.insert("V2RAY_LOCATION_ASSET", QString::fromStdString(GetGlobalConfig().v2AssetsPath));
QProcess process; QProcess process;
process.setProcessEnvironment(env); process.setProcessEnvironment(env);
process.start(QString::fromStdString(Utils::GetGlobalConfig().v2CorePath), QStringList() << "-test" process.start(QV2RAY_V2RAY_CORE_PATH, QStringList() << "-test" << "-config" << *path, QIODevice::ReadWrite | QIODevice::Text);
<< "-config" << path,
QIODevice::ReadWrite | QIODevice::Text);
if (!process.waitForFinished()) { if (!process.waitForFinished()) {
qDebug() << "v2ray core failed with exit code " << process.exitCode(); LOG(MODULE_VCORE, "v2ray core failed with exitcode: " << process.exitCode())
return false; return false;
} }
QString output = QString(process.readAllStandardOutput()); QString output = QString(process.readAllStandardOutput());
if (!output.contains("Configuration OK")) { if (process.exitCode() != 0) {
Utils::QvMessageBox(nullptr, QObject::tr("ConfigurationError"), output.mid(output.indexOf("anti-censorship.") + 17)); Utils::QvMessageBox(nullptr, QObject::tr("Configuration Error"), output.mid(output.indexOf("anti-censorship.") + 17));
return false; return false;
} else }
return true; return true;
} else }
return false; return false;
} }
Qv2Instance::Qv2Instance(QWidget *parent) Qv2Instance::Qv2Instance(QWidget *parent)
{ {
QProcess *proc = new QProcess(); auto proc = new QProcess();
vProcess = proc; vProcess = proc;
QObject::connect(vProcess, &QProcess::readyReadStandardOutput, static_cast<MainWindow *>(parent), &MainWindow::UpdateLog); QObject::connect(vProcess, &QProcess::readyReadStandardOutput, static_cast<MainWindow *>(parent), &MainWindow::UpdateLog);
Status = STOPPED; Status = STOPPED;
} }
QString Qv2Instance::ReadProcessOutput() QString Qv2Instance::ReadProcessOutput()
{ {
return vProcess->readAllStandardOutput(); return vProcess->readAllStandardOutput();
} }
bool Qv2Instance::ValidateV2rayCoreExe() bool Qv2Instance::ValidateV2rayCoreExe()
{ {
auto path = QString::fromStdString(Utils::GetGlobalConfig().v2CorePath); if (!QFile::exists(QV2RAY_V2RAY_CORE_PATH)) {
Utils::QvMessageBox(nullptr, QObject::tr("Cannot start v2ray"), QObject::tr("v2ray core file cannot be found at:") + QV2RAY_V2RAY_CORE_PATH);
if (!QFile::exists(path)) {
Utils::QvMessageBox(nullptr, QObject::tr("CoreNotFound"), QObject::tr("CoreFileNotFoundExplainationAt:") + path);
return false; return false;
} else return true; } else return true;
} }
@ -64,13 +66,13 @@ namespace Qv2ray
Status = STARTING; Status = STARTING;
if (ValidateV2rayCoreExe()) { if (ValidateV2rayCoreExe()) {
if (VerifyVConfigFile(QV2RAY_GENERATED_FILE_PATH)) { auto filePath = QV2RAY_GENERATED_FILE_PATH;
if (VerifyVConfigFile(&filePath)) {
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("V2RAY_LOCATION_ASSET", QString::fromStdString(GetGlobalConfig().v2AssetsPath)); env.insert("V2RAY_LOCATION_ASSET", QString::fromStdString(GetGlobalConfig().v2AssetsPath));
vProcess->setProcessEnvironment(env); vProcess->setProcessEnvironment(env);
vProcess->start(QString::fromStdString(GetGlobalConfig().v2CorePath), QStringList() << "-config" vProcess->start(QV2RAY_V2RAY_CORE_PATH, QStringList() << "-config" << filePath, QIODevice::ReadWrite | QIODevice::Text);
<< QV2RAY_GENERATED_FILE_PATH,
QIODevice::ReadWrite | QIODevice::Text);
vProcess->waitForStarted(); vProcess->waitForStarted();
Status = STARTED; Status = STARTED;
return true; return true;

View File

@ -20,7 +20,7 @@ namespace Qv2ray
bool Start(); bool Start();
void Stop(); void Stop();
V2RAY_INSTANCE_STARTUP_STATUS Status; V2RAY_INSTANCE_STARTUP_STATUS Status;
static bool VerifyVConfigFile(QString path); static bool VerifyVConfigFile(const QString *path);
static bool ValidateV2rayCoreExe(); static bool ValidateV2rayCoreExe();
QString ReadProcessOutput(); QString ReadProcessOutput();

View File

@ -19,4 +19,8 @@ using namespace std;
#define MODULE_FILE "FILE" #define MODULE_FILE "FILE"
#define MODULE_SUBSCRIPTION "SUBSCRIPTION" #define MODULE_SUBSCRIPTION "SUBSCRIPTION"
#define WARN "WARN"
#define INFO "INFO"
#define ERROR "ERROR"
#endif // QVTINYLOG_H #endif // QVTINYLOG_H

View File

@ -22,24 +22,24 @@ namespace Qv2ray
return ConfigDirPath; return ConfigDirPath;
} }
void SetConfigDirPath(QString path) void SetConfigDirPath(const QString *path)
{ {
ConfigDirPath = path; ConfigDirPath = *path;
} }
void SaveGlobalConfig() void SaveGlobalConfig()
{ {
QFile config(QV2RAY_CONFIG_FILE_PATH); QFile config(QV2RAY_CONFIG_FILE_PATH);
QString str = StructToJSONString(GetGlobalConfig()); QString str = StructToJSONString(GetGlobalConfig());
StringToFile(str, &config); StringToFile(&str, &config);
} }
bool StringToFile(QString text, QFile *targetFile) bool StringToFile(const QString *text, QFile *targetFile)
{ {
bool override = targetFile->exists(); bool override = targetFile->exists();
targetFile->open(QFile::WriteOnly); targetFile->open(QFile::WriteOnly);
QTextStream stream(targetFile); QTextStream stream(targetFile);
stream << text << endl; stream << *text << endl;
stream.flush(); stream.flush();
targetFile->close(); targetFile->close();
return override; return override;

View File

@ -18,7 +18,7 @@ namespace Qv2ray
bool CheckFile(QDir *dir, QString fileName); bool CheckFile(QDir *dir, QString fileName);
void SetConfigDirPath(QString path); void SetConfigDirPath(const QString *path);
QString GetConfigDirPath(); QString GetConfigDirPath();
void SetGlobalConfig(Qv2rayConfig conf); void SetGlobalConfig(Qv2rayConfig conf);
@ -30,7 +30,7 @@ namespace Qv2ray
void QvMessageBox(QWidget *parent, QString title, QString text); void QvMessageBox(QWidget *parent, QString title, QString text);
int QvMessageBoxAsk(QWidget *parent, QString title, QString text, QMessageBox::StandardButton extraButtons = QMessageBox::NoButton); int QvMessageBoxAsk(QWidget *parent, QString title, QString text, QMessageBox::StandardButton extraButtons = QMessageBox::NoButton);
// //
bool StringToFile(QString text, QFile *target); bool StringToFile(const QString *text, QFile *target);
QString StringFromFile(QFile *sourceFile); QString StringFromFile(QFile *sourceFile);
// //
QJsonObject JSONFromString(QString string); QJsonObject JSONFromString(QString string);

View File

@ -7,68 +7,36 @@
#include "QvRunguard.h" #include "QvRunguard.h"
#include "w_MainWindow.h" #include "w_MainWindow.h"
using namespace Qv2ray;
using namespace Qv2ray::Utils;
using namespace Qv2ray::QvConfigModels;
bool initQv() bool initQv()
{ {
#ifdef QT_DEBUG if (!QDir(QV2RAY_CONFIG_DIR_PATH).exists()) {
QString configPath = QDir::homePath() + "/.qv2ray_debug"; QDir().mkdir(QV2RAY_CONFIG_DIR_PATH);
#else
QString configPath = QDir::homePath() + "/.qv2ray";
#endif
/// Qv2ray Config Path and ends with "/"
QString exeDefaultPath = configPath + "/vcore/v2ray";
QString v2AssetsPath = configPath + "/vcore";
//
#if defined(__WIN32)
exeDefaultPath = exeDefaultPath + ".exe";
#elif defined(__linux__)
// Special case for GNU/Linux
//
// Unused these values
Q_UNUSED(v2AssetsPath)
Q_UNUSED(exeDefaultPath)
v2AssetsPath = "/etc/v2ray";
exeDefaultPath = "/bin/v2ray";
#endif
//
SetConfigDirPath(configPath);
auto ConfigDir = new QDir(configPath);
if (!ConfigDir->exists()) {
auto result = QDir().mkdir(QV2RAY_CONFIG_DIR_PATH);
if (result) {
LOG(MODULE_INIT, "Created Qv2ray config dir at: " + QV2RAY_CONFIG_DIR_PATH.toStdString()) LOG(MODULE_INIT, "Created Qv2ray config dir at: " + QV2RAY_CONFIG_DIR_PATH.toStdString())
} else {
LOG(MODULE_INIT, "Failed to create config dir at: " + QV2RAY_CONFIG_DIR_PATH.toStdString())
return false;
}
} }
auto genPath = QV2RAY_CONFIG_DIR_PATH + "generated/"; if (!QDir(QV2RAY_CONFIG_DIR_PATH + "generated/").exists()) {
QDir().mkdir(QV2RAY_CONFIG_DIR_PATH + "generated/");
if (!QDir(genPath).exists()) { LOG(MODULE_INIT, "Created config generation dir.")
auto result2 = QDir().mkdir(genPath);
if (result2) {
LOG(MODULE_INIT, "Created config generation dir at: " + genPath.toStdString())
} else {
LOG(MODULE_INIT, "Failed to create config generation dir at: " + genPath.toStdString())
return false;
}
} }
QFile configFile(QV2RAY_CONFIG_FILE_PATH); if (!QDir(QV2RAY_V2RAY_CORE_DIR_PATH).exists()) {
QDir().mkdir(QV2RAY_V2RAY_CORE_DIR_PATH);
LOG(MODULE_INIT, "Created dir for v2ray core and assets.")
QFile _readmeFile(QV2RAY_V2RAY_CORE_DIR_PATH + "Put your v2ray.exe here.txt");
_readmeFile.open(QIODevice::WriteOnly);
_readmeFile.write("Please put your v2ray.exe and assets here!");
_readmeFile.close();
LOG(MODULE_INIT, "Done generating readme.")
}
if (!configFile.exists()) { QFile qvConfigFile(QV2RAY_CONFIG_FILE_PATH);
// This is first run!
if (!qvConfigFile.exists()) {
// This is first run, even the config file does not exist...
// //
// These below genenrated very basic global config. // These below genenrated very basic global config.
Qv2rayBasicInboundsConfig inboundSetting = Qv2rayBasicInboundsConfig("127.0.0.1", 1080, 8000); Qv2rayBasicInboundsConfig inboundSetting = Qv2rayBasicInboundsConfig("127.0.0.1", 1080, 8000);
Qv2rayConfig conf = Qv2rayConfig("zh-CN", exeDefaultPath.toStdString(), v2AssetsPath.toStdString(), 2, inboundSetting); Qv2rayConfig conf = Qv2rayConfig("zh-CN", QV2RAY_V2RAY_CORE_DIR_PATH.toStdString(), 4, inboundSetting);
// //
// Save initial config. // Save initial config.
SetGlobalConfig(conf); SetGlobalConfig(conf);
@ -77,12 +45,19 @@ bool initQv()
LOG(MODULE_INIT, "Created initial config file.") LOG(MODULE_INIT, "Created initial config file.")
} else { } else {
// Some config file upgrades. // Some config file upgrades.
auto conf = JSONFromString(StringFromFile(&configFile)); auto conf = JSONFromString(StringFromFile(&qvConfigFile));
auto confVersion = conf["config_version"].toVariant().toString(); auto confVersion = conf["config_version"].toVariant().toString();
auto newVersion = QSTRING(to_string(QV2RAY_CONFIG_VERSION)); auto newVersion = QSTRING(to_string(QV2RAY_CONFIG_VERSION));
if (QString::compare(confVersion, newVersion) != 0) { // Config version is larger than the current version...
conf = UpgradeConfig(stoi(conf["config_version"].toString().toStdString()), QV2RAY_CONFIG_VERSION, conf); if (stoi(confVersion.toStdString()) > QV2RAY_CONFIG_VERSION) {
QvMessageBox(nullptr, QObject::tr("Qv2ray Cannot Continue"), QObject::tr("You are running a lower version of Qv2ray compared to the current config file.") +
"\r\n" +
QObject::tr("Please report if you think this is an error.") + "\r\n" +
QObject::tr("Qv2ray will now exit."));
return false;
} else if (QString::compare(confVersion, newVersion) != 0) {
conf = UpgradeConfig(stoi(confVersion.toStdString()), QV2RAY_CONFIG_VERSION, conf);
} }
auto confObject = StructFromJSONString<Qv2rayConfig>(JSONToString(conf)); auto confObject = StructFromJSONString<Qv2rayConfig>(JSONToString(conf));
@ -110,7 +85,11 @@ int main(int argc, char *argv[])
// //
#ifdef QT_DEBUG #ifdef QT_DEBUG
LOG("DEBUG", "============================== This is a debug build, many features are not stable enough. ==============================") LOG("DEBUG", "============================== This is a debug build, many features are not stable enough. ==============================")
QString configPath = QDir::homePath() + "/.qv2ray_debug";
#else
QString configPath = QDir::homePath() + "/.qv2ray";
#endif #endif
SetConfigDirPath(&configPath);
QDirIterator it(":/translations"); QDirIterator it(":/translations");
if (!it.hasNext()) { if (!it.hasNext()) {
@ -155,7 +134,6 @@ int main(int argc, char *argv[])
"DEBUG_VERSION" "DEBUG_VERSION"
#endif #endif
); );
auto osslReqVersion = QSslSocket::sslLibraryBuildVersionString().toStdString(); auto osslReqVersion = QSslSocket::sslLibraryBuildVersionString().toStdString();
auto osslCurVersion = QSslSocket::sslLibraryVersionString().toStdString(); auto osslCurVersion = QSslSocket::sslLibraryVersionString().toStdString();
LOG(MODULE_NETWORK, "Current OpenSSL version: " + osslCurVersion) LOG(MODULE_NETWORK, "Current OpenSSL version: " + osslCurVersion)

View File

@ -30,10 +30,10 @@ ConnectionEditWindow::ConnectionEditWindow(QWidget *parent)
GEN_JSON GEN_JSON
} }
ConnectionEditWindow::ConnectionEditWindow(QJsonObject editRootObject, QString alias, QWidget *parent) ConnectionEditWindow::ConnectionEditWindow(QJsonObject editRootObject, const QString *alias, QWidget *parent)
: ConnectionEditWindow(parent) : ConnectionEditWindow(parent)
{ {
_alias = alias; _alias = *alias;
originalRoot = editRootObject; originalRoot = editRootObject;
auto outBoundRoot = originalRoot["outbounds"].toArray().first().toObject(); auto outBoundRoot = originalRoot["outbounds"].toArray().first().toObject();
OutboundType = outBoundRoot["protocol"].toString(); OutboundType = outBoundRoot["protocol"].toString();
@ -156,7 +156,6 @@ void ConnectionEditWindow::on_buttonBox_accepted()
} }
originalRoot.insert("outbounds", outbounds); originalRoot.insert("outbounds", outbounds);
originalRoot.insert(QV2RAY_CONFIG_TYPE_JSON_KEY, QV2RAY_CONFIG_TYPE_MANUAL);
SaveConnectionConfig(originalRoot, &alias); SaveConnectionConfig(originalRoot, &alias);
auto globalConf = GetGlobalConfig(); auto globalConf = GetGlobalConfig();

View File

@ -17,7 +17,7 @@ class ConnectionEditWindow : public QDialog
public: public:
explicit ConnectionEditWindow(QWidget *parent = nullptr); explicit ConnectionEditWindow(QWidget *parent = nullptr);
explicit ConnectionEditWindow(QJsonObject editRootObject, QString alias, QWidget *parent = nullptr); explicit ConnectionEditWindow(QJsonObject editRootObject, const QString *alias, QWidget *parent = nullptr);
~ConnectionEditWindow(); ~ConnectionEditWindow();
signals: signals:
void s_reload_config(bool need_restart); void s_reload_config(bool need_restart);

View File

@ -33,7 +33,7 @@ void ImportConfigWindow::on_importSourceCombo_currentIndexChanged(int index)
void ImportConfigWindow::on_selectFileBtn_clicked() void ImportConfigWindow::on_selectFileBtn_clicked()
{ {
QString dir = QFileDialog::getOpenFileName(this, tr("OpenConfigFile"), "~/"); QString dir = QFileDialog::getOpenFileName(this, tr("Select file to import"), QDir::currentPath());
ui->fileLineTxt->setText(dir); ui->fileLineTxt->setText(dir);
} }
@ -45,9 +45,10 @@ void ImportConfigWindow::on_buttonBox_accepted()
if (ui->importSourceCombo->currentIndex() == 0) { if (ui->importSourceCombo->currentIndex() == 0) {
// From File... // From File...
bool overrideInBound = !ui->keepImportedInboundCheckBox->isChecked(); bool overrideInBound = !ui->keepImportedInboundCheckBox->isChecked();
auto fileName = ui->fileLineTxt->text();
if (!Qv2Instance::VerifyVConfigFile(ui->fileLineTxt->text())) { if (!Qv2Instance::VerifyVConfigFile(&fileName)) {
QvMessageBox(this, tr("#InvalidConfigFile"), tr("ConfigFileCheckFailed")); QvMessageBox(this, tr("Import config file"), tr("Failed to check the validity of the config file."));
return; return;
} }
@ -58,28 +59,33 @@ void ImportConfigWindow::on_buttonBox_accepted()
QString vmess = ui->vmessConnectionStringTxt->toPlainText(); QString vmess = ui->vmessConnectionStringTxt->toPlainText();
int result = VerifyVMessProtocolString(vmess); int result = VerifyVMessProtocolString(vmess);
if (result == 0) { switch (result) {
case 0:
// This result code passes the validation check. // This result code passes the validation check.
//QvMessageBox(this, tr("#VMessCheck"), tr("#AbleToImportConfig")); //QvMessageBox(this, tr("#VMessCheck"), tr("#AbleToImportConfig"));
} else if (result == -1) { break;
QvMessageBox(this, tr("#VMessCheck"), tr("#NotValidVMessProtocolString"));
case -1:
QvMessageBox(this, tr("VMess String Check"), tr("VMess string is not valid"));
done(0); done(0);
return; return;
} else {
QvMessageBox(this, tr("#VMessCheck"), tr("#INTERNAL_ERROR")); default:
QvMessageBox(this, tr("VMess String Check"), tr("Some internal error occured"));
return; return;
} }
config = ConvertConfigFromVMessString(ui->vmessConnectionStringTxt->toPlainText()); config = ConvertConfigFromVMessString(ui->vmessConnectionStringTxt->toPlainText());
// //
alias = alias != "" ? alias : config["QV2RAY_ALIAS"].toString(); alias = alias.isEmpty() ? alias : config["QV2RAY_ALIAS"].toString();
config.remove("QV2RAY_ALIAS"); config.remove("QV2RAY_ALIAS");
} }
Qv2rayConfig conf = GetGlobalConfig(); Qv2rayConfig conf = GetGlobalConfig();
//
conf.configs.push_back(alias.toStdString()); conf.configs.push_back(alias.toStdString());
//
SetGlobalConfig(conf); SetGlobalConfig(conf);
auto needReload = SaveConnectionConfig(config, &alias); auto needReload = SaveConnectionConfig(config, &alias);
LOG(MODULE_CONNECTION_VMESS, "WARNING: POSSIBLE LOSS OF DATA")
emit s_reload_config(needReload); emit s_reload_config(needReload);
} }

View File

@ -15,10 +15,10 @@
#include <windows.h> #include <windows.h>
#endif #endif
#include "w_PrefrencesWindow.h"
#include "w_ImportConfig.h"
#include "w_ConnectionEditWindow.h" #include "w_ConnectionEditWindow.h"
#include "w_ImportConfig.h"
#include "w_MainWindow.h" #include "w_MainWindow.h"
#include "w_PrefrencesWindow.h"
#include "w_SubscribeEditor.h" #include "w_SubscribeEditor.h"
#define TRAY_TOOLTIP_PREFIX "Qv2ray " QV2RAY_VERSION_STRING "\r\n" #define TRAY_TOOLTIP_PREFIX "Qv2ray " QV2RAY_VERSION_STRING "\r\n"
@ -75,9 +75,8 @@ MainWindow::MainWindow(QWidget *parent)
// //
if (!vinstance->ValidateV2rayCoreExe()) { if (!vinstance->ValidateV2rayCoreExe()) {
on_prefrencesBtn_clicked(); QDesktopServices::openUrl(QUrl::fromLocalFile(QV2RAY_V2RAY_CORE_DIR_PATH));
} } else {
auto conf = GetGlobalConfig(); auto conf = GetGlobalConfig();
if (conf.autoStartConfig != "" && QList<string>::fromStdList(conf.configs).contains(conf.autoStartConfig)) { if (conf.autoStartConfig != "" && QList<string>::fromStdList(conf.configs).contains(conf.autoStartConfig)) {
@ -92,6 +91,13 @@ MainWindow::MainWindow(QWidget *parent)
trayMenu->actions()[0]->setText(tr("Show")); trayMenu->actions()[0]->setText(tr("Show"));
} else { } else {
this->show(); this->show();
if (ui->connectionListWidget->count() != 0) {
// The first one is default.
ui->connectionListWidget->setCurrentRow(0);
ShowAndSetConnection(ui->connectionListWidget->item(0)->text(), true, false);
}
}
} }
} }
@ -196,8 +202,8 @@ void MainWindow::on_startButton_clicked()
bool startFlag = this->vinstance->Start(); bool startFlag = this->vinstance->Start();
if (startFlag) { if (startFlag) {
this->hTray->showMessage("Qv2ray", tr("Connected To Server: ") + " " + CurrentConnectionName); this->hTray->showMessage("Qv2ray", tr("Connected To Server: ") + CurrentConnectionName);
hTray->setToolTip(TRAY_TOOLTIP_PREFIX + tr("Connected To Server: ") + ": " + CurrentConnectionName); hTray->setToolTip(TRAY_TOOLTIP_PREFIX + tr("Connected To Server: ") + CurrentConnectionName);
ui->statusLabel->setText(tr("Connected") + ": " + CurrentConnectionName); ui->statusLabel->setText(tr("Connected") + ": " + CurrentConnectionName);
} }
@ -305,11 +311,8 @@ void MainWindow::QTextScrollToBottom()
if (bar->value() >= bar->maximum() - 10) bar->setValue(bar->maximum()); if (bar->value() >= bar->maximum() - 10) bar->setValue(bar->maximum());
} }
void MainWindow::ShowAndSetConnection(int index, bool SetConnection, bool ApplyConnection) void MainWindow::ShowAndSetConnection(QString guiConnectionName, bool SetConnection, bool ApplyConnection)
{ {
if (index < 0) return;
auto guiConnectionName = ui->connectionListWidget->item(index)->text();
// --------- BRGIN Show Connection // --------- BRGIN Show Connection
auto outBoundRoot = (connections[guiConnectionName])["outbounds"].toArray().first().toObject(); auto outBoundRoot = (connections[guiConnectionName])["outbounds"].toArray().first().toObject();
// //
@ -362,7 +365,12 @@ void MainWindow::on_connectionListWidget_itemClicked(QListWidgetItem *item)
{ {
Q_UNUSED(item) Q_UNUSED(item)
int currentRow = ui->connectionListWidget->currentRow(); int currentRow = ui->connectionListWidget->currentRow();
ShowAndSetConnection(currentRow, !isRenamingInProgress && (vinstance->Status != STARTED), false);
if (currentRow < 0) return;
QString currentText = ui->connectionListWidget->currentItem()->text();
bool canSetConnection = !isRenamingInProgress && vinstance->Status != STARTED ;
ShowAndSetConnection(currentText, canSetConnection, false);
} }
void MainWindow::on_prefrencesBtn_clicked() void MainWindow::on_prefrencesBtn_clicked()
@ -374,7 +382,13 @@ void MainWindow::on_prefrencesBtn_clicked()
void MainWindow::on_connectionListWidget_doubleClicked(const QModelIndex &index) void MainWindow::on_connectionListWidget_doubleClicked(const QModelIndex &index)
{ {
ShowAndSetConnection(index.row(), true, true); Q_UNUSED(index)
int currentRow = ui->connectionListWidget->currentRow();
if (currentRow < 0) return;
QString currentText = ui->connectionListWidget->currentItem()->text();
ShowAndSetConnection(currentText, true, true);
} }
void MainWindow::on_clearlogButton_clicked() void MainWindow::on_clearlogButton_clicked()
@ -385,7 +399,7 @@ void MainWindow::on_clearlogButton_clicked()
void MainWindow::on_connectionListWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) void MainWindow::on_connectionListWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{ {
Q_UNUSED(previous) Q_UNUSED(previous)
isRenamingInProgress = true; isRenamingInProgress = false;
on_connectionListWidget_itemClicked(current); on_connectionListWidget_itemClicked(current);
} }
@ -401,14 +415,14 @@ void MainWindow::on_action_RenameConnection_triggered()
item->setFlags(item->flags() | Qt::ItemIsEditable); item->setFlags(item->flags() | Qt::ItemIsEditable);
ui->connectionListWidget->editItem(item); ui->connectionListWidget->editItem(item);
originalName = item->text(); originalName = item->text();
isRenamingInProgress = false; isRenamingInProgress = true;
} }
void MainWindow::on_connectionListWidget_itemChanged(QListWidgetItem *item) void MainWindow::on_connectionListWidget_itemChanged(QListWidgetItem *item)
{ {
LOG(MODULE_UI, "A connection ListViewItem is changed.") LOG(MODULE_UI, "A connection ListViewItem is changed.")
if (!isRenamingInProgress) { if (isRenamingInProgress) {
// In this case it's after we entered the name. // In this case it's after we entered the name.
LOG(MODULE_CONNECTION, "RENAME: " + originalName.toStdString() + " -> " + item->text().toStdString()) LOG(MODULE_CONNECTION, "RENAME: " + originalName.toStdString() + " -> " + item->text().toStdString())
auto newName = item->text(); auto newName = item->text();
@ -416,16 +430,16 @@ void MainWindow::on_connectionListWidget_itemChanged(QListWidgetItem *item)
auto configList = QList<string>::fromStdList(config.configs); auto configList = QList<string>::fromStdList(config.configs);
if (newName.trimmed().isEmpty()) { if (newName.trimmed().isEmpty()) {
QvMessageBox(this, tr("Rename A Connection"), tr("A name cannot be empty")); QvMessageBox(this, tr("Rename a Connection"), tr("The name cannot be empty"));
return; return;
} }
// If I really did some changes.
LOG("RENAME", "ORIGINAL: " + originalName.toStdString() + ", NEW: " + newName.toStdString()) LOG("RENAME", "ORIGINAL: " + originalName.toStdString() + ", NEW: " + newName.toStdString())
// If I really did some changes.
if (originalName != newName) { if (originalName != newName) {
if (configList.contains(newName.toStdString())) { if (configList.contains(newName.toStdString())) {
QvMessageBox(this, tr("Rename A Connection"), tr("The name has been used already, Please choose another.")); QvMessageBox(this, tr("Rename a Connection"), tr("The name has been used already, Please choose another."));
return; return;
} }
@ -452,7 +466,7 @@ void MainWindow::on_connectionListWidget_itemChanged(QListWidgetItem *item)
void MainWindow::on_removeConfigButton_clicked() void MainWindow::on_removeConfigButton_clicked()
{ {
if (QvMessageBoxAsk(this, tr("Removing A Connection"), tr("Are you sure to remove this connection?")) == QMessageBox::Yes) { if (QvMessageBoxAsk(this, tr("Removing this Connection"), tr("Are you sure to remove this connection?")) == QMessageBox::Yes) {
auto conf = GetGlobalConfig(); auto conf = GetGlobalConfig();
QList<string> list = QList<string>::fromStdList(conf.configs); QList<string> list = QList<string>::fromStdList(conf.configs);
auto currentSelected = ui->connectionListWidget->currentIndex().row(); auto currentSelected = ui->connectionListWidget->currentIndex().row();
@ -489,16 +503,14 @@ void MainWindow::on_addConfigButton_clicked()
void MainWindow::on_editConfigButton_clicked() void MainWindow::on_editConfigButton_clicked()
{ {
// Check if we have a connection selected... // Check if we have a connection selected...
auto index = ui->connectionListWidget->currentIndex().row(); if (ui->connectionListWidget->currentIndex().row() < 0) {
if (index < 0) {
QvMessageBox(this, tr("NoConfigSelected"), tr("PleaseSelectAConfig")); QvMessageBox(this, tr("NoConfigSelected"), tr("PleaseSelectAConfig"));
return; return;
} }
auto alias = ui->connectionListWidget->currentItem()->text(); auto alias = ui->connectionListWidget->currentItem()->text();
auto outBoundRoot = connections[alias]; auto outBoundRoot = connections[alias];
ConnectionEditWindow *w = new ConnectionEditWindow(outBoundRoot, alias, this); ConnectionEditWindow *w = new ConnectionEditWindow(outBoundRoot, &alias, this);
connect(w, &ConnectionEditWindow::s_reload_config, this, &MainWindow::save_reload_globalconfig); connect(w, &ConnectionEditWindow::s_reload_config, this, &MainWindow::save_reload_globalconfig);
w->show(); w->show();
} }
@ -508,3 +520,8 @@ void MainWindow::on_pushButton_clicked()
SubscribeEditor *w = new SubscribeEditor(this); SubscribeEditor *w = new SubscribeEditor(this);
w->show(); w->show();
} }
void MainWindow::on_reconnectButton_clicked()
{
on_restartButton_clicked();
}

View File

@ -59,6 +59,8 @@ class MainWindow : public QMainWindow
void on_pushButton_clicked(); void on_pushButton_clicked();
void on_reconnectButton_clicked();
private: private:
void on_action_StartThis_triggered(); void on_action_StartThis_triggered();
void on_action_RenameConnection_triggered(); void on_action_RenameConnection_triggered();
@ -75,7 +77,7 @@ class MainWindow : public QMainWindow
QString originalName; QString originalName;
bool isRenamingInProgress; bool isRenamingInProgress;
// //
void ShowAndSetConnection(int index, bool SetConnection, bool Apply); void ShowAndSetConnection(QString currentText, bool SetConnection, bool Apply);
void LoadConnections(); void LoadConnections();
void closeEvent(QCloseEvent *); void closeEvent(QCloseEvent *);
}; };

View File

@ -37,7 +37,7 @@
</property> </property>
<layout class="QGridLayout" name="gridLayout" columnstretch="2,3"> <layout class="QGridLayout" name="gridLayout" columnstretch="2,3">
<item row="0" column="0" colspan="2"> <item row="0" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1,1,0,0,0"> <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1,0,1,0,0,0">
<property name="spacing"> <property name="spacing">
<number>5</number> <number>5</number>
</property> </property>
@ -58,6 +58,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="reconnectButton">
<property name="text">
<string>Reconnect</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QPushButton" name="clearlogButton"> <widget class="QPushButton" name="clearlogButton">
<property name="text"> <property name="text">

View File

@ -5,10 +5,6 @@
#include <iostream> #include <iostream>
#ifdef __linux
#include <unistd.h>
#endif
#define NEEDRESTART if(finishedLoading) IsConnectionPropertyChanged = true; #define NEEDRESTART if(finishedLoading) IsConnectionPropertyChanged = true;
PrefrencesWindow::PrefrencesWindow(QWidget *parent) : QDialog(parent), PrefrencesWindow::PrefrencesWindow(QWidget *parent) : QDialog(parent),
@ -30,7 +26,7 @@ PrefrencesWindow::PrefrencesWindow(QWidget *parent) : QDialog(parent),
// //
ui->languageComboBox->setCurrentText(QSTRING(CurrentConfig.language)); ui->languageComboBox->setCurrentText(QSTRING(CurrentConfig.language));
ui->logLevelComboBox->setCurrentIndex(CurrentConfig.logLevel); ui->logLevelComboBox->setCurrentIndex(CurrentConfig.logLevel);
ui->runAsRootCheckBox->setChecked(CurrentConfig.runAsRoot); ui->tProxyCheckBox->setChecked(CurrentConfig.runAsRoot);
// //
// //
ui->listenIPTxt->setText(QSTRING(CurrentConfig.inBoundSettings.listenip)); ui->listenIPTxt->setText(QSTRING(CurrentConfig.inBoundSettings.listenip));
@ -63,7 +59,6 @@ PrefrencesWindow::PrefrencesWindow(QWidget *parent) : QDialog(parent),
ui->socksPortLE->setValidator(new QIntValidator()); ui->socksPortLE->setValidator(new QIntValidator());
// //
// //
ui->vCoreExePathTxt->setText(QSTRING(CurrentConfig.v2CorePath));
ui->vCoreAssetsPathTxt->setText(QSTRING(CurrentConfig.v2AssetsPath)); ui->vCoreAssetsPathTxt->setText(QSTRING(CurrentConfig.v2AssetsPath));
// //
// //
@ -105,7 +100,7 @@ void PrefrencesWindow::on_buttonBox_accepted()
int hp = ui->httpPortLE->text().toInt() ; int hp = ui->httpPortLE->text().toInt() ;
if (!(sp == 0 || hp == 0) && sp == hp) { if (!(sp == 0 || hp == 0) && sp == hp) {
QvMessageBox(this, tr("Prefrences"), tr("PortNumbersCannotBeSame")); QvMessageBox(this, tr("Prefrences"), tr("Port numbers cannot be the same"));
return; return;
} }
@ -149,38 +144,6 @@ void PrefrencesWindow::on_httpAuthCB_stateChanged(int checked)
CurrentConfig.inBoundSettings.http_useAuth = checked == Qt::Checked; CurrentConfig.inBoundSettings.http_useAuth = checked == Qt::Checked;
} }
void PrefrencesWindow::on_runAsRootCheckBox_stateChanged(int arg1)
{
#ifdef __linux
// Set UID and GID for linux
QString vCorePath = QString::fromStdString(CurrentConfig.v2CorePath);
QFileInfo v2rayCoreExeFile(vCorePath);
if (arg1 == Qt::Checked && v2rayCoreExeFile.ownerId() != 0) {
QProcess::execute("pkexec", QStringList() << "bash"
<< "-c"
<< "chown root:root " + vCorePath + " && "
<< "chmod +s " + vCorePath);
CurrentConfig.runAsRoot = true;
NEEDRESTART
} else if (arg1 != Qt::Checked && v2rayCoreExeFile.ownerId() == 0) {
uid_t uid = getuid();
gid_t gid = getgid();
QProcess::execute("pkexec", QStringList()
<< "chown" << QString::number(uid) + ":" + QString::number(gid)
<< vCorePath);
CurrentConfig.runAsRoot = false;
NEEDRESTART
}
#else
Q_UNUSED(arg1)
ui->runAsRootCheckBox->setChecked(false);
// No such uid gid thing on Windows and MacOS is in TODO ....
QvMessageBox(this, tr("Prefrences"), tr("RunAsRootNotOnWindows"));
#endif
}
void PrefrencesWindow::on_socksAuthCB_stateChanged(int checked) void PrefrencesWindow::on_socksAuthCB_stateChanged(int checked)
{ {
NEEDRESTART NEEDRESTART
@ -193,7 +156,7 @@ void PrefrencesWindow::on_languageComboBox_currentTextChanged(const QString &arg
{ {
CurrentConfig.language = arg1.toStdString(); CurrentConfig.language = arg1.toStdString();
// //
// A strange bug prevents us to change the UI language `live`ly // A strange bug prevents us to change the UI language online
// https://github.com/lhy0403/Qv2ray/issues/34 // https://github.com/lhy0403/Qv2ray/issues/34
// //
//if (QApplication::installTranslator(getTranslator(&arg1))) { //if (QApplication::installTranslator(getTranslator(&arg1))) {
@ -210,12 +173,6 @@ void PrefrencesWindow::on_logLevelComboBox_currentIndexChanged(int index)
CurrentConfig.logLevel = index; CurrentConfig.logLevel = index;
} }
void PrefrencesWindow::on_vCoreExePathTxt_textEdited(const QString &arg1)
{
NEEDRESTART
CurrentConfig.v2CorePath = arg1.toStdString();
}
void PrefrencesWindow::on_vCoreAssetsPathTxt_textEdited(const QString &arg1) void PrefrencesWindow::on_vCoreAssetsPathTxt_textEdited(const QString &arg1)
{ {
NEEDRESTART NEEDRESTART
@ -294,21 +251,10 @@ void PrefrencesWindow::on_localDNSCb_stateChanged(int arg1)
CurrentConfig.withLocalDNS = arg1 == Qt::Checked; CurrentConfig.withLocalDNS = arg1 == Qt::Checked;
} }
void PrefrencesWindow::on_selectVCoreBtn_clicked()
{
NEEDRESTART
QString path = QFileDialog::getOpenFileName(this, tr("#OpenVCoreFile"), QDir::homePath());
ui->vCoreExePathTxt->setText(path);
on_vCoreExePathTxt_textEdited(path);
auto dir = QFileInfo(path).dir().path();
ui->vCoreAssetsPathTxt->setText(dir);
on_vCoreAssetsPathTxt_textEdited(dir);
}
void PrefrencesWindow::on_selectVAssetBtn_clicked() void PrefrencesWindow::on_selectVAssetBtn_clicked()
{ {
NEEDRESTART NEEDRESTART
QString dir = QFileDialog::getExistingDirectory(this, tr("OpenVAssetsDir"), QDir::homePath()); QString dir = QFileDialog::getExistingDirectory(this, tr("Open v2ray assets folder"), QDir::currentPath());
ui->vCoreAssetsPathTxt->setText(dir); ui->vCoreAssetsPathTxt->setText(dir);
on_vCoreAssetsPathTxt_textEdited(dir); on_vCoreAssetsPathTxt_textEdited(dir);
} }
@ -350,3 +296,55 @@ void PrefrencesWindow::on_cancelIgnoreVersionBtn_clicked()
CurrentConfig.ignoredVersion.clear(); CurrentConfig.ignoredVersion.clear();
ui->cancelIgnoreVersionBtn->setEnabled(false); ui->cancelIgnoreVersionBtn->setEnabled(false);
} }
void PrefrencesWindow::on_tProxyCheckBox_stateChanged(int arg1)
{
#ifdef __linux
if (finishedLoading) {
//LOG(MODULE_UI, "Running getcap....")
//QProcess::execute("getcap " + QV2RAY_V2RAY_CORE_PATH);
// Set UID and GID for linux
// Steps:
// --> 1. Copy v2ray core files to the #CONFIG_DIR#/vcore/ dir.
// --> 2. Change GlobalConfig.v2CorePath.
// --> 3. Call `pkexec setcap CAP_NET_ADMIN,CAP_NET_RAW,CAP_NET_BIND_SERVICE=eip` on the v2ray core.
if (arg1 == Qt::Checked) {
// We enable it!
if (QvMessageBoxAsk(this, tr("Enable tProxy Support"), tr("This will append capabilities to the v2ray executable.") + "\r\n"
+ tr("If anything goes wrong after enabling this, please refer to issue #57 or the link below:") + "\r\n" +
" https://github.com/lhy0403/Qv2ray/blob/master/docs/FAQ.md ") != QMessageBox::Yes) {
ui->tProxyCheckBox->setChecked(false);
LOG(MODULE_UI, "Canceled enabling tProxy feature.")
}
int ret = QProcess::execute("pkexec setcap CAP_NET_ADMIN,CAP_NET_RAW,CAP_NET_BIND_SERVICE=eip " + QV2RAY_V2RAY_CORE_PATH);
if (ret != 0) {
LOG(MODULE_UI, "WARN: setcap exits with code: " + to_string(ret))
QvMessageBox(this, tr("Prefrences"), tr("Failed to setcap onto v2ray executable. You may need to run `setcap` manually."));
}
CurrentConfig.runAsRoot = true;
NEEDRESTART
} else {
int ret = QProcess::execute("pkexec setcap -r " + QV2RAY_V2RAY_CORE_PATH);
if (ret != 0) {
LOG(MODULE_UI, "WARN: setcap exits with code: " + to_string(ret))
QvMessageBox(this, tr("Prefrences"), tr("Failed to setcap onto v2ray executable. You may need to run `setcap` manually."));
}
CurrentConfig.runAsRoot = false;
NEEDRESTART
}
}
#else
Q_UNUSED(arg1)
ui->tProxyCheckBox->setChecked(false);
// No such uid gid thing on Windows and MacOS
QvMessageBox(this, tr("Prefrences"), tr("tProxy is not supported on MacOS and Windows"));
#endif
}

View File

@ -19,23 +19,22 @@ class PrefrencesWindow : public QDialog
~PrefrencesWindow(); ~PrefrencesWindow();
signals: signals:
void s_reload_config(bool need_restart); void s_reload_config(bool need_restart);
private slots: private slots:
void on_buttonBox_accepted(); void on_buttonBox_accepted();
void on_httpCB_stateChanged(int arg1); void on_httpCB_stateChanged(int arg1);
void on_socksCB_stateChanged(int arg1); void on_socksCB_stateChanged(int arg1);
void on_httpAuthCB_stateChanged(int arg1); void on_httpAuthCB_stateChanged(int arg1);
void on_runAsRootCheckBox_stateChanged(int arg1);
void on_socksAuthCB_stateChanged(int arg1); void on_socksAuthCB_stateChanged(int arg1);
void on_languageComboBox_currentTextChanged(const QString &arg1); void on_languageComboBox_currentTextChanged(const QString &arg1);
void on_logLevelComboBox_currentIndexChanged(int index); void on_logLevelComboBox_currentIndexChanged(int index);
void on_vCoreExePathTxt_textEdited(const QString &arg1);
void on_vCoreAssetsPathTxt_textEdited(const QString &arg1); void on_vCoreAssetsPathTxt_textEdited(const QString &arg1);
void on_muxEnabledCB_stateChanged(int arg1); void on_muxEnabledCB_stateChanged(int arg1);
@ -62,8 +61,6 @@ class PrefrencesWindow : public QDialog
void on_localDNSCb_stateChanged(int arg1); void on_localDNSCb_stateChanged(int arg1);
void on_selectVCoreBtn_clicked();
void on_selectVAssetBtn_clicked(); void on_selectVAssetBtn_clicked();
void on_DNSListTxt_textChanged(); void on_DNSListTxt_textChanged();
@ -74,6 +71,8 @@ class PrefrencesWindow : public QDialog
void on_cancelIgnoreVersionBtn_clicked(); void on_cancelIgnoreVersionBtn_clicked();
void on_tProxyCheckBox_stateChanged(int arg1);
private: private:
bool IsConnectionPropertyChanged = false; bool IsConnectionPropertyChanged = false;
bool finishedLoading = false; bool finishedLoading = false;

View File

@ -64,27 +64,13 @@
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Run As Root</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="runAsRootCheckBox">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
<string>Log Level</string> <string>Log Level</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="1" column="1">
<widget class="QComboBox" name="logLevelComboBox"> <widget class="QComboBox" name="logLevelComboBox">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed"> <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
@ -125,14 +111,14 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="2" column="0">
<widget class="QLabel" name="label_19"> <widget class="QLabel" name="label_19">
<property name="text"> <property name="text">
<string>Automatically Connect To</string> <string>Automatically Connect To</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="2" column="1">
<widget class="QComboBox" name="autoStartCombo"> <widget class="QComboBox" name="autoStartCombo">
<item> <item>
<property name="text"> <property name="text">
@ -141,35 +127,28 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Transparent Proxy Support</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="tProxyCheckBox">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item row="4" column="0"> <item row="4" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>v2ray Core Path</string>
</property>
</widget>
</item>
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLineEdit" name="vCoreExePathTxt"/>
</item>
<item>
<widget class="QPushButton" name="selectVCoreBtn">
<property name="text">
<string>#Select</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_15"> <widget class="QLabel" name="label_15">
<property name="text"> <property name="text">
<string>v2ray Assets Path</string> <string>v2ray Assets Path</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_5"> <layout class="QHBoxLayout" name="horizontalLayout_5">
<item> <item>
<widget class="QLineEdit" name="vCoreAssetsPathTxt"/> <widget class="QLineEdit" name="vCoreAssetsPathTxt"/>

View File

@ -69,7 +69,7 @@ void SubscribeEditor::ProcessSubscriptionEntry(QByteArray result, QString subsci
auto vmessList = content.split("\n"); auto vmessList = content.split("\n");
for (auto vmess : vmessList) { for (auto vmess : vmessList) {
auto config = ConvertConfigFromVMessString(vmess, QV2RAY_CONFIG_TYPE_SUBSCRIPTION); auto config = ConvertConfigFromVMessString(vmess);
if (subscriptions.contains(subsciptionName)) { if (subscriptions.contains(subsciptionName)) {
} }

View File

@ -211,14 +211,14 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_ConnectionEditWindow.cpp" line="398"/> <location filename="../src/w_ConnectionEditWindow.cpp" line="397"/>
<location filename="../src/w_ConnectionEditWindow.cpp" line="409"/> <location filename="../src/w_ConnectionEditWindow.cpp" line="408"/>
<source>#JsonPrettify</source> <source>#JsonPrettify</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_ConnectionEditWindow.cpp" line="398"/> <location filename="../src/w_ConnectionEditWindow.cpp" line="397"/>
<location filename="../src/w_ConnectionEditWindow.cpp" line="409"/> <location filename="../src/w_ConnectionEditWindow.cpp" line="408"/>
<source>#JsonContainsError</source> <source>#JsonContainsError</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -293,33 +293,33 @@
</message> </message>
<message> <message>
<location filename="../src/w_ImportConfig.cpp" line="36"/> <location filename="../src/w_ImportConfig.cpp" line="36"/>
<source>OpenConfigFile</source> <source>Select file to import</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_ImportConfig.cpp" line="50"/> <location filename="../src/w_ImportConfig.cpp" line="51"/>
<source>#InvalidConfigFile</source> <source>Import config file</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_ImportConfig.cpp" line="50"/> <location filename="../src/w_ImportConfig.cpp" line="51"/>
<source>ConfigFileCheckFailed</source> <source>Failed to check the validity of the config file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_ImportConfig.cpp" line="65"/>
<location filename="../src/w_ImportConfig.cpp" line="69"/>
<source>#VMessCheck</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_ImportConfig.cpp" line="65"/>
<source>#NotValidVMessProtocolString</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_ImportConfig.cpp" line="69"/> <location filename="../src/w_ImportConfig.cpp" line="69"/>
<source>#INTERNAL_ERROR</source> <location filename="../src/w_ImportConfig.cpp" line="74"/>
<source>VMess String Check</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_ImportConfig.cpp" line="69"/>
<source>VMess string is not valid</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_ImportConfig.cpp" line="74"/>
<source>Some internal error occured</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -343,129 +343,129 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="64"/> <location filename="../src/w_MainWindow.ui" line="71"/>
<source>Clear Log</source> <source>Clear Log</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="71"/> <location filename="../src/w_MainWindow.ui" line="78"/>
<source>Prefrences</source> <source>Prefrences</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="94"/> <location filename="../src/w_MainWindow.ui" line="101"/>
<source>Stopped</source> <source>Stopped</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="103"/> <location filename="../src/w_MainWindow.ui" line="110"/>
<source>Host List</source> <source>Host List</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="110"/> <location filename="../src/w_MainWindow.ui" line="117"/>
<source>Config Details</source> <source>Config Details</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="116"/> <location filename="../src/w_MainWindow.ui" line="123"/>
<source>Type</source> <source>Type</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="130"/> <location filename="../src/w_MainWindow.ui" line="137"/>
<source>Host</source> <source>Host</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="144"/> <location filename="../src/w_MainWindow.ui" line="151"/>
<source>Port</source> <source>Port</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="158"/> <location filename="../src/w_MainWindow.ui" line="165"/>
<source>Detail</source> <source>Detail</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="236"/> <location filename="../src/w_MainWindow.ui" line="243"/>
<source>#AddConnection</source> <source>#AddConnection</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="239"/> <location filename="../src/w_MainWindow.ui" line="246"/>
<source>A</source> <source>A</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="256"/> <location filename="../src/w_MainWindow.ui" line="263"/>
<location filename="../src/w_MainWindow.ui" line="346"/> <location filename="../src/w_MainWindow.ui" line="353"/>
<source>#ImportConnection</source> <source>#ImportConnection</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="259"/> <location filename="../src/w_MainWindow.ui" line="266"/>
<source>I</source> <source>I</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="290"/> <location filename="../src/w_MainWindow.ui" line="297"/>
<source>#RemoveConnection</source> <source>#RemoveConnection</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="293"/> <location filename="../src/w_MainWindow.ui" line="300"/>
<source>R</source> <source>R</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="270"/> <location filename="../src/w_MainWindow.ui" line="277"/>
<source>#EditConnection</source> <source>#EditConnection</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="273"/> <location filename="../src/w_MainWindow.ui" line="280"/>
<source>...</source> <source>...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="319"/> <location filename="../src/w_MainWindow.ui" line="326"/>
<source>Log</source> <source>Log</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="341"/> <location filename="../src/w_MainWindow.ui" line="348"/>
<source>#ManuallyCreateConnection</source> <source>#ManuallyCreateConnection</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="351"/> <location filename="../src/w_MainWindow.ui" line="358"/>
<source>#Exit</source> <source>#Exit</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="356"/> <location filename="../src/w_MainWindow.ui" line="363"/>
<source>#Preferences</source> <source>#Preferences</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="361"/> <location filename="../src/w_MainWindow.ui" line="368"/>
<source>#Start</source> <source>#Start</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="366"/> <location filename="../src/w_MainWindow.ui" line="373"/>
<source>#Stop</source> <source>#Stop</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="371"/> <location filename="../src/w_MainWindow.ui" line="378"/>
<source>#Restart</source> <source>#Restart</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="38"/> <location filename="../src/w_MainWindow.cpp" line="38"/>
<location filename="../src/w_MainWindow.cpp" line="283"/> <location filename="../src/w_MainWindow.cpp" line="289"/>
<source>Hide</source> <source>Hide</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -475,6 +475,7 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.ui" line="64"/>
<location filename="../src/w_MainWindow.cpp" line="41"/> <location filename="../src/w_MainWindow.cpp" line="41"/>
<source>Reconnect</source> <source>Reconnect</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -485,19 +486,35 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="92"/> <location filename="../src/w_MainWindow.cpp" line="91"/>
<location filename="../src/w_MainWindow.cpp" line="238"/> <location filename="../src/w_MainWindow.cpp" line="244"/>
<location filename="../src/w_MainWindow.cpp" line="286"/> <location filename="../src/w_MainWindow.cpp" line="292"/>
<source>Show</source> <source>Show</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="495"/> <location filename="../src/w_MainWindow.cpp" line="433"/>
<location filename="../src/w_MainWindow.cpp" line="442"/>
<source>Rename a Connection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="433"/>
<source>The name cannot be empty</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="469"/>
<source>Removing this Connection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="507"/>
<source>NoConfigSelected</source> <source>NoConfigSelected</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="495"/> <location filename="../src/w_MainWindow.cpp" line="507"/>
<source>PleaseSelectAConfig</source> <source>PleaseSelectAConfig</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -507,99 +524,83 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="120"/> <location filename="../src/w_MainWindow.cpp" line="126"/>
<source>Update</source> <source>Update</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="121"/> <location filename="../src/w_MainWindow.cpp" line="127"/>
<source>Found a new version: </source> <source>Found a new version: </source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="127"/> <location filename="../src/w_MainWindow.cpp" line="133"/>
<source>Download Link: </source> <source>Download Link: </source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="188"/> <location filename="../src/w_MainWindow.cpp" line="194"/>
<source>No connection selected!</source> <source>No connection selected!</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="188"/> <location filename="../src/w_MainWindow.cpp" line="194"/>
<source>Please select a config from the list.</source> <source>Please select a config from the list.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="199"/> <location filename="../src/w_MainWindow.cpp" line="205"/>
<location filename="../src/w_MainWindow.cpp" line="200"/> <location filename="../src/w_MainWindow.cpp" line="206"/>
<source>Connected To Server: </source> <source>Connected To Server: </source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="201"/> <location filename="../src/w_MainWindow.cpp" line="207"/>
<source>Connected</source> <source>Connected</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="218"/> <location filename="../src/w_MainWindow.cpp" line="224"/>
<source>Disconnected</source> <source>Disconnected</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="324"/> <location filename="../src/w_MainWindow.cpp" line="327"/>
<source>UUID</source> <source>UUID</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="326"/> <location filename="../src/w_MainWindow.cpp" line="329"/>
<source>AlterID</source> <source>AlterID</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="328"/> <location filename="../src/w_MainWindow.cpp" line="331"/>
<source>Transport</source> <source>Transport</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="335"/> <location filename="../src/w_MainWindow.cpp" line="338"/>
<source>Email</source> <source>Email</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="337"/> <location filename="../src/w_MainWindow.cpp" line="340"/>
<source>Encryption</source> <source>Encryption</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="344"/> <location filename="../src/w_MainWindow.cpp" line="347"/>
<source>Username</source> <source>Username</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="419"/> <location filename="../src/w_MainWindow.cpp" line="442"/>
<location filename="../src/w_MainWindow.cpp" line="428"/>
<source>Rename A Connection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="419"/>
<source>A name cannot be empty</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="428"/>
<source>The name has been used already, Please choose another.</source> <source>The name has been used already, Please choose another.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_MainWindow.cpp" line="455"/> <location filename="../src/w_MainWindow.cpp" line="469"/>
<source>Removing A Connection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="455"/>
<source>Are you sure to remove this connection?</source> <source>Are you sure to remove this connection?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -608,8 +609,10 @@
<name>PrefrencesWindow</name> <name>PrefrencesWindow</name>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="20"/> <location filename="../src/w_PrefrencesWindow.ui" line="20"/>
<location filename="../src/w_PrefrencesWindow.cpp" line="108"/> <location filename="../src/w_PrefrencesWindow.cpp" line="103"/>
<location filename="../src/w_PrefrencesWindow.cpp" line="180"/> <location filename="../src/w_PrefrencesWindow.cpp" line="326"/>
<location filename="../src/w_PrefrencesWindow.cpp" line="336"/>
<location filename="../src/w_PrefrencesWindow.cpp" line="348"/>
<source>Prefrences</source> <source>Prefrences</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -635,271 +638,296 @@
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="69"/> <location filename="../src/w_PrefrencesWindow.ui" line="69"/>
<source>Run As Root</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="83"/>
<source>Log Level</source> <source>Log Level</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="103"/> <location filename="../src/w_PrefrencesWindow.ui" line="89"/>
<source>none</source> <source>none</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="108"/> <location filename="../src/w_PrefrencesWindow.ui" line="94"/>
<source>debug</source> <source>debug</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="113"/> <location filename="../src/w_PrefrencesWindow.ui" line="99"/>
<source>info</source> <source>info</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="118"/> <location filename="../src/w_PrefrencesWindow.ui" line="104"/>
<source>warning</source> <source>warning</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="123"/> <location filename="../src/w_PrefrencesWindow.ui" line="109"/>
<source>error</source> <source>error</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="131"/> <location filename="../src/w_PrefrencesWindow.ui" line="117"/>
<source>Automatically Connect To</source> <source>Automatically Connect To</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="147"/>
<source>v2ray Core Path</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="159"/> <location filename="../src/w_PrefrencesWindow.ui" line="159"/>
<location filename="../src/w_PrefrencesWindow.ui" line="180"/>
<source>#Select</source> <source>#Select</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="168"/> <location filename="../src/w_PrefrencesWindow.ui" line="147"/>
<source>v2ray Assets Path</source> <source>v2ray Assets Path</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="190"/> <location filename="../src/w_PrefrencesWindow.ui" line="169"/>
<source>Mux Settings</source> <source>Mux Settings</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="76"/> <location filename="../src/w_PrefrencesWindow.ui" line="140"/>
<location filename="../src/w_PrefrencesWindow.ui" line="196"/> <location filename="../src/w_PrefrencesWindow.ui" line="175"/>
<location filename="../src/w_PrefrencesWindow.ui" line="203"/> <location filename="../src/w_PrefrencesWindow.ui" line="182"/>
<location filename="../src/w_PrefrencesWindow.ui" line="259"/> <location filename="../src/w_PrefrencesWindow.ui" line="238"/>
<location filename="../src/w_PrefrencesWindow.ui" line="287"/> <location filename="../src/w_PrefrencesWindow.ui" line="266"/>
<location filename="../src/w_PrefrencesWindow.ui" line="326"/> <location filename="../src/w_PrefrencesWindow.ui" line="305"/>
<location filename="../src/w_PrefrencesWindow.ui" line="360"/> <location filename="../src/w_PrefrencesWindow.ui" line="339"/>
<location filename="../src/w_PrefrencesWindow.ui" line="400"/>
<location filename="../src/w_PrefrencesWindow.ui" line="421"/> <location filename="../src/w_PrefrencesWindow.ui" line="421"/>
<location filename="../src/w_PrefrencesWindow.ui" line="442"/> <location filename="../src/w_PrefrencesWindow.ui" line="428"/>
<location filename="../src/w_PrefrencesWindow.ui" line="449"/>
<source>Enabled</source> <source>Enabled</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="210"/> <location filename="../src/w_PrefrencesWindow.ui" line="133"/>
<source>Transparent Proxy Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="189"/>
<source>Concurrency</source> <source>Concurrency</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="231"/> <location filename="../src/w_PrefrencesWindow.ui" line="210"/>
<source>InBound Settings</source> <source>InBound Settings</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="239"/> <location filename="../src/w_PrefrencesWindow.ui" line="218"/>
<source>Listen IP</source> <source>Listen IP</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="253"/> <location filename="../src/w_PrefrencesWindow.ui" line="232"/>
<source>SOCKS InBound Settings</source> <source>SOCKS InBound Settings</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="266"/> <location filename="../src/w_PrefrencesWindow.ui" line="245"/>
<location filename="../src/w_PrefrencesWindow.ui" line="333"/> <location filename="../src/w_PrefrencesWindow.ui" line="312"/>
<source>Port</source> <source>Port</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="280"/> <location filename="../src/w_PrefrencesWindow.ui" line="259"/>
<location filename="../src/w_PrefrencesWindow.ui" line="353"/> <location filename="../src/w_PrefrencesWindow.ui" line="332"/>
<source>Authentication</source> <source>Authentication</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="294"/> <location filename="../src/w_PrefrencesWindow.ui" line="273"/>
<location filename="../src/w_PrefrencesWindow.ui" line="367"/> <location filename="../src/w_PrefrencesWindow.ui" line="346"/>
<source>Username</source> <source>Username</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="304"/> <location filename="../src/w_PrefrencesWindow.ui" line="283"/>
<location filename="../src/w_PrefrencesWindow.ui" line="377"/> <location filename="../src/w_PrefrencesWindow.ui" line="356"/>
<source>Password</source> <source>Password</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="317"/> <location filename="../src/w_PrefrencesWindow.ui" line="296"/>
<source>HTTP InBound Settings</source> <source>HTTP InBound Settings</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="406"/> <location filename="../src/w_PrefrencesWindow.ui" line="385"/>
<source>Route Settings</source> <source>Route Settings</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="414"/> <location filename="../src/w_PrefrencesWindow.ui" line="393"/>
<source>Enable Proxy</source> <source>Enable Proxy</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="428"/> <location filename="../src/w_PrefrencesWindow.ui" line="407"/>
<source>Chinese Addresses</source> <source>Chinese Addresses</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="435"/> <location filename="../src/w_PrefrencesWindow.ui" line="414"/>
<source>Use Local DNS</source> <source>Use Local DNS</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="461"/> <location filename="../src/w_PrefrencesWindow.ui" line="440"/>
<source>DNS List</source> <source>DNS List</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="475"/> <location filename="../src/w_PrefrencesWindow.ui" line="454"/>
<source>About</source> <source>About</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="523"/> <location filename="../src/w_PrefrencesWindow.ui" line="502"/>
<source>Qv2ray</source> <source>Qv2ray</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="545"/> <location filename="../src/w_PrefrencesWindow.ui" line="524"/>
<source>Version:</source> <source>Version:</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="578"/> <location filename="../src/w_PrefrencesWindow.ui" line="557"/>
<source>Official Repo:</source> <source>Official Repo:</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="596"/> <location filename="../src/w_PrefrencesWindow.ui" line="575"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/lhy0403/Qv2ray&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#2980b9;&quot;&gt;https://github.com/lhy0403/Qv2ray&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/lhy0403/Qv2ray&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#2980b9;&quot;&gt;https://github.com/lhy0403/Qv2ray&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="629"/> <location filename="../src/w_PrefrencesWindow.ui" line="608"/>
<source>License:</source> <source>License:</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="647"/> <location filename="../src/w_PrefrencesWindow.ui" line="626"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://www.gnu.org/licenses/gpl-3.0.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#2980b9;&quot;&gt;GPLv3 (https://www.gnu.org/licenses/gpl-3.0.txt)&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://www.gnu.org/licenses/gpl-3.0.txt&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#2980b9;&quot;&gt;GPLv3 (https://www.gnu.org/licenses/gpl-3.0.txt)&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="684"/> <location filename="../src/w_PrefrencesWindow.ui" line="663"/>
<source>About Qt</source> <source>About Qt</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="719"/> <location filename="../src/w_PrefrencesWindow.ui" line="698"/>
<source>Ingore Next Version</source> <source>Ingore Next Version</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.ui" line="726"/> <location filename="../src/w_PrefrencesWindow.ui" line="705"/>
<source>Cancel</source> <source>Cancel</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.cpp" line="108"/> <location filename="../src/w_PrefrencesWindow.cpp" line="103"/>
<source>PortNumbersCannotBeSame</source> <source>Port numbers cannot be the same</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.cpp" line="180"/> <location filename="../src/w_PrefrencesWindow.cpp" line="257"/>
<source>RunAsRootNotOnWindows</source> <source>Open v2ray assets folder</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.cpp" line="300"/> <location filename="../src/w_PrefrencesWindow.cpp" line="315"/>
<source>#OpenVCoreFile</source> <source>Enable tProxy Support</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/w_PrefrencesWindow.cpp" line="311"/> <location filename="../src/w_PrefrencesWindow.cpp" line="315"/>
<source>OpenVAssetsDir</source> <source>This will append capabilities to the v2ray executable.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.cpp" line="316"/>
<source>If anything goes wrong after enabling this, please refer to issue #57 or the link below:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.cpp" line="326"/>
<location filename="../src/w_PrefrencesWindow.cpp" line="336"/>
<source>Failed to setcap onto v2ray executable. You may need to run `setcap` manually.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.cpp" line="348"/>
<source>tProxy is not supported on MacOS and Windows</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context> <context>
<name>QObject</name> <name>QObject</name>
<message> <message>
<location filename="../src/QvCoreConfigOperations_Verification.cpp" line="22"/> <location filename="../src/main.cpp" line="54"/>
<source>#VMessDecodeError</source> <source>Qv2ray Cannot Continue</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/QvCoreInteractions.cpp" line="29"/> <location filename="../src/main.cpp" line="54"/>
<source>ConfigurationError</source> <source>You are running a lower version of Qv2ray compared to the current config file.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/QvCoreInteractions.cpp" line="53"/> <location filename="../src/main.cpp" line="56"/>
<source>CoreNotFound</source> <source>Please report if you think this is an error.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/QvCoreInteractions.cpp" line="53"/> <location filename="../src/main.cpp" line="57"/>
<source>CoreFileNotFoundExplainationAt:</source> <source>Qv2ray will now exit.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/main.cpp" line="166"/> <location filename="../src/main.cpp" line="144"/>
<source>DependencyMissing</source> <source>DependencyMissing</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/main.cpp" line="167"/> <location filename="../src/main.cpp" line="145"/>
<source>Cannot find openssl libs</source> <source>Cannot find openssl libs</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/main.cpp" line="168"/> <location filename="../src/main.cpp" line="146"/>
<source>This could be caused by a missing of `openssl` package in your system. Or an AppImage issue.</source> <source>This could be caused by a missing of `openssl` package in your system. Or an AppImage issue.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/main.cpp" line="169"/> <location filename="../src/main.cpp" line="147"/>
<source>If you are using AppImage, please report a bug.</source> <source>If you are using AppImage, please report a bug.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../src/main.cpp" line="177"/> <location filename="../src/main.cpp" line="153"/>
<source>Another instance of Qv2ray is already running.</source> <source>Another instance of Qv2ray is already running.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location filename="../src/QvCoreInteractions.cpp" line="29"/>
<source>Configuration Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/QvCoreInteractions.cpp" line="55"/>
<source>Cannot start v2ray</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/QvCoreInteractions.cpp" line="55"/>
<source>v2ray core file cannot be found at:</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>RouteEditor</name> <name>RouteEditor</name>

File diff suppressed because it is too large Load Diff