[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_PRODUCT = "Qv2ray"
VERSION = 1.3.6.1
VERSION = 1.3.7.0
DEFINES += QV_MAJOR_VERSION=\"\\\"$${VERSION}\\\"\"
SOURCES += \

View File

@ -7,10 +7,22 @@
#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_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_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_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
#define RED(obj) \
auto _temp = ui->obj->palette(); \
@ -77,7 +80,6 @@ namespace Qv2ray
int logLevel;
//
string language;
string v2CorePath;
string v2AssetsPath;
string autoStartConfig;
//
@ -97,13 +99,12 @@ namespace Qv2ray
map<string, string> subscribes;
MuxObject 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.
ignoredVersion = "";
autoStartConfig = "";
language = lang;
v2CorePath = exePath;
v2AssetsPath = assetsPath;
logLevel = log;
inBoundSettings = _inBoundSettings;
@ -116,7 +117,7 @@ namespace Qv2ray
proxyDefault = 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);

View File

@ -3,7 +3,7 @@
// 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 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))
switch (fromVersion) {
case 1:
case 1: {
// From 1 to 2, we changed the config_version from 'string' to 'int'
auto old_config_version = root["config_version"].toString();
root.remove("config_version");
@ -27,6 +27,22 @@ namespace Qv2ray
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;
}

View File

@ -16,10 +16,6 @@ namespace Qv2ray
{
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
struct AccountObject {

View File

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

View File

@ -7,25 +7,39 @@ namespace Qv2ray
bool SaveConnectionConfig(QJsonObject obj, const QString *alias)
{
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....
QJsonObject ConvertConfigFromVMessString(QString str, QString source)
QJsonObject ConvertConfigFromVMessString(QString str)
{
DROOT
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
VMessServerObject::UserObject user;
user.id = vmessConf.id;
user.alterId = stoi(vmessConf.aid);
user.id = id;
user.alterId = aid;
//
// Server
VMessServerObject serv;
serv.port = stoi(vmessConf.port);
serv.address = vmessConf.add;
serv.port = port;
serv.address = add;
serv.users.push_back(user);
//
// VMess root config
@ -38,35 +52,34 @@ namespace Qv2ray
StreamSettingsObject streaming;
// Fill hosts for HTTP
foreach (auto host, QString::fromStdString(vmessConf.host).split(',')) {
streaming.httpSettings.host.push_back(host.toStdString());
foreach (auto _host, QString::fromStdString(host).split(',')) {
streaming.httpSettings.host.push_back(_host.toStdString());
}
// hosts for ws, h2 and security for QUIC
streaming.wsSettings.headers.insert(make_pair("Host", vmessConf.host));
streaming.quicSettings.security = vmessConf.host;
streaming.wsSettings.headers.insert(make_pair("Host", host));
streaming.quicSettings.security = host;
//
// Fake type for tcp, kcp and QUIC
streaming.tcpSettings.header.type = vmessConf.type;
streaming.kcpSettings.header.type = vmessConf.type;
streaming.quicSettings.header.type = vmessConf.type;
streaming.tcpSettings.header.type = type;
streaming.kcpSettings.header.type = type;
streaming.quicSettings.header.type = type;
//
// Path for ws, h2, Quic
streaming.wsSettings.path = vmessConf.path;
streaming.httpSettings.path = vmessConf.path;
streaming.quicSettings.key = vmessConf.path;
streaming.security = vmessConf.tls;
streaming.wsSettings.path = path;
streaming.httpSettings.path = path;
streaming.quicSettings.key = path;
streaming.security = tls;
//
// 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);
//
QJsonArray outbounds;
outbounds.append(outbound);
root.insert("outbounds", outbounds);
root.insert("QV2RAY_ALIAS", QString::fromStdString(vmessConf.ps));
root.insert(QV2RAY_CONFIG_TYPE_JSON_KEY, source);
root.insert("QV2RAY_ALIAS", QString::fromStdString(ps));
RROOT
}
@ -82,7 +95,6 @@ namespace Qv2ray
JSON_ROOT_TRY_REMOVE("api")
JSON_ROOT_TRY_REMOVE("stats")
JSON_ROOT_TRY_REMOVE("dns")
root.insert(QV2RAY_CONFIG_TYPE_JSON_KEY, QV2RAY_CONFIG_TYPE_FILE);
return root;
}
@ -107,7 +119,7 @@ namespace Qv2ray
int StartPreparation(QJsonObject fullConfig)
{
QString json = JSONToString(fullConfig);
StringToFile(json, new QFile(QV2RAY_GENERATED_FILE_PATH));
StringToFile(&json, new QFile(QV2RAY_GENERATED_FILE_PATH));
return 0;
}
}

View File

@ -4,6 +4,7 @@ namespace Qv2ray
{
namespace ConfigOperations
{
static const QStringList vLogLevels = {"none", "debug", "info", "warning", "error"};
// -------------------------- BEGIN CONFIG GENERATIONS ----------------------------------------------------------------------------
QJsonObject GenerateRoutes(bool globalProxy, bool cnProxy)
{
@ -129,33 +130,11 @@ namespace Qv2ray
{
auto gConf = GetGlobalConfig();
QJsonObject logObject;
//
//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);
QString logLevel_s;
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);
//
logObject.insert("loglevel", vLogLevels[gConf.logLevel]);
root.insert("log", logObject);
//
QStringList dnsList;
@ -166,16 +145,6 @@ namespace Qv2ray
auto dnsObject = GenerateDNS(gConf.withLocalDNS, dnsList);
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());
@ -210,23 +179,43 @@ namespace Qv2ray
inboundsList.append(socksInBoundObject);
}
if (!root.contains("inbounds") || root["inbounds"].toArray().count() == 0) {
if (!root.contains("inbounds") || root["inbounds"].toArray().empty()) {
root.insert("inbounds", inboundsList);
}
// TODO: MultiOutbound Settings
if (root.contains(QV2RAY_CONFIG_TYPE_JSON_KEY) && root[QV2RAY_CONFIG_TYPE_JSON_KEY] == QV2RAY_CONFIG_TYPE_FILE) {
LOG(MODULE_CONFIG, "Found an imported config file, skipping adding 'freedom' outbound.")
// Do nothing because it's an imported connection.
} else {
// Note: The part below always makes the whole functionality in trouble......
// BE EXTREME CAREFUL when changing these code below...
//
// 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();
// 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));
QJsonObject first = outbounds.first().toObject();
first.insert("mux", GetRootObject(gConf.mux));
outbounds[0] = first;
// TODO
//
// 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;
} 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;

View File

@ -16,10 +16,15 @@ namespace Qv2ray
try {
QStringRef vmessJsonB64(&vmess, 8, vmess.length() - 8);
auto vmessString = Base64Decode(vmessJsonB64.toString());
auto vmessConf = StructFromJSONString<VMessProtocolConfigObject>(vmessString);
return 0;
auto vmessConf = JSONFromString(vmessString);
// 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) {
LOG(MODULE_CONNECTION, QObject::tr("#VMessDecodeError").toStdString() << e->what())
LOG(MODULE_CONNECTION, "Failed to decode vmess string: " << e->what())
return -2;
}
}

View File

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

View File

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

View File

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

View File

@ -22,24 +22,24 @@ namespace Qv2ray
return ConfigDirPath;
}
void SetConfigDirPath(QString path)
void SetConfigDirPath(const QString *path)
{
ConfigDirPath = path;
ConfigDirPath = *path;
}
void SaveGlobalConfig()
{
QFile config(QV2RAY_CONFIG_FILE_PATH);
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();
targetFile->open(QFile::WriteOnly);
QTextStream stream(targetFile);
stream << text << endl;
stream << *text << endl;
stream.flush();
targetFile->close();
return override;

View File

@ -18,7 +18,7 @@ namespace Qv2ray
bool CheckFile(QDir *dir, QString fileName);
void SetConfigDirPath(QString path);
void SetConfigDirPath(const QString *path);
QString GetConfigDirPath();
void SetGlobalConfig(Qv2rayConfig conf);
@ -30,7 +30,7 @@ namespace Qv2ray
void QvMessageBox(QWidget *parent, QString title, QString text);
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);
//
QJsonObject JSONFromString(QString string);

View File

@ -7,68 +7,36 @@
#include "QvRunguard.h"
#include "w_MainWindow.h"
using namespace Qv2ray;
using namespace Qv2ray::Utils;
using namespace Qv2ray::QvConfigModels;
bool initQv()
{
#ifdef QT_DEBUG
QString configPath = QDir::homePath() + "/.qv2ray_debug";
#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) {
if (!QDir(QV2RAY_CONFIG_DIR_PATH).exists()) {
QDir().mkdir(QV2RAY_CONFIG_DIR_PATH);
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(genPath).exists()) {
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;
}
if (!QDir(QV2RAY_CONFIG_DIR_PATH + "generated/").exists()) {
QDir().mkdir(QV2RAY_CONFIG_DIR_PATH + "generated/");
LOG(MODULE_INIT, "Created config generation dir.")
}
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()) {
// This is first run!
QFile qvConfigFile(QV2RAY_CONFIG_FILE_PATH);
if (!qvConfigFile.exists()) {
// This is first run, even the config file does not exist...
//
// These below genenrated very basic global config.
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.
SetGlobalConfig(conf);
@ -77,12 +45,19 @@ bool initQv()
LOG(MODULE_INIT, "Created initial config file.")
} else {
// Some config file upgrades.
auto conf = JSONFromString(StringFromFile(&configFile));
auto conf = JSONFromString(StringFromFile(&qvConfigFile));
auto confVersion = conf["config_version"].toVariant().toString();
auto newVersion = QSTRING(to_string(QV2RAY_CONFIG_VERSION));
if (QString::compare(confVersion, newVersion) != 0) {
conf = UpgradeConfig(stoi(conf["config_version"].toString().toStdString()), QV2RAY_CONFIG_VERSION, conf);
// Config version is larger than the current version...
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));
@ -110,7 +85,11 @@ int main(int argc, char *argv[])
//
#ifdef QT_DEBUG
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
SetConfigDirPath(&configPath);
QDirIterator it(":/translations");
if (!it.hasNext()) {
@ -155,7 +134,6 @@ int main(int argc, char *argv[])
"DEBUG_VERSION"
#endif
);
auto osslReqVersion = QSslSocket::sslLibraryBuildVersionString().toStdString();
auto osslCurVersion = QSslSocket::sslLibraryVersionString().toStdString();
LOG(MODULE_NETWORK, "Current OpenSSL version: " + osslCurVersion)

View File

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

View File

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

View File

@ -15,10 +15,10 @@
#include <windows.h>
#endif
#include "w_PrefrencesWindow.h"
#include "w_ImportConfig.h"
#include "w_ConnectionEditWindow.h"
#include "w_ImportConfig.h"
#include "w_MainWindow.h"
#include "w_PrefrencesWindow.h"
#include "w_SubscribeEditor.h"
#define TRAY_TOOLTIP_PREFIX "Qv2ray " QV2RAY_VERSION_STRING "\r\n"
@ -75,9 +75,8 @@ MainWindow::MainWindow(QWidget *parent)
//
if (!vinstance->ValidateV2rayCoreExe()) {
on_prefrencesBtn_clicked();
}
QDesktopServices::openUrl(QUrl::fromLocalFile(QV2RAY_V2RAY_CORE_DIR_PATH));
} else {
auto conf = GetGlobalConfig();
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"));
} else {
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();
if (startFlag) {
this->hTray->showMessage("Qv2ray", tr("Connected To Server: ") + " " + CurrentConnectionName);
hTray->setToolTip(TRAY_TOOLTIP_PREFIX + tr("Connected To Server: ") + ": " + CurrentConnectionName);
this->hTray->showMessage("Qv2ray", tr("Connected To Server: ") + CurrentConnectionName);
hTray->setToolTip(TRAY_TOOLTIP_PREFIX + tr("Connected To Server: ") + CurrentConnectionName);
ui->statusLabel->setText(tr("Connected") + ": " + CurrentConnectionName);
}
@ -305,11 +311,8 @@ void MainWindow::QTextScrollToBottom()
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
auto outBoundRoot = (connections[guiConnectionName])["outbounds"].toArray().first().toObject();
//
@ -362,7 +365,12 @@ void MainWindow::on_connectionListWidget_itemClicked(QListWidgetItem *item)
{
Q_UNUSED(item)
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()
@ -374,7 +382,13 @@ void MainWindow::on_prefrencesBtn_clicked()
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()
@ -385,7 +399,7 @@ void MainWindow::on_clearlogButton_clicked()
void MainWindow::on_connectionListWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
Q_UNUSED(previous)
isRenamingInProgress = true;
isRenamingInProgress = false;
on_connectionListWidget_itemClicked(current);
}
@ -401,14 +415,14 @@ void MainWindow::on_action_RenameConnection_triggered()
item->setFlags(item->flags() | Qt::ItemIsEditable);
ui->connectionListWidget->editItem(item);
originalName = item->text();
isRenamingInProgress = false;
isRenamingInProgress = true;
}
void MainWindow::on_connectionListWidget_itemChanged(QListWidgetItem *item)
{
LOG(MODULE_UI, "A connection ListViewItem is changed.")
if (!isRenamingInProgress) {
if (isRenamingInProgress) {
// In this case it's after we entered the name.
LOG(MODULE_CONNECTION, "RENAME: " + originalName.toStdString() + " -> " + item->text().toStdString())
auto newName = item->text();
@ -416,16 +430,16 @@ void MainWindow::on_connectionListWidget_itemChanged(QListWidgetItem *item)
auto configList = QList<string>::fromStdList(config.configs);
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;
}
// If I really did some changes.
LOG("RENAME", "ORIGINAL: " + originalName.toStdString() + ", NEW: " + newName.toStdString())
// If I really did some changes.
if (originalName != newName) {
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;
}
@ -452,7 +466,7 @@ void MainWindow::on_connectionListWidget_itemChanged(QListWidgetItem *item)
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();
QList<string> list = QList<string>::fromStdList(conf.configs);
auto currentSelected = ui->connectionListWidget->currentIndex().row();
@ -489,16 +503,14 @@ void MainWindow::on_addConfigButton_clicked()
void MainWindow::on_editConfigButton_clicked()
{
// Check if we have a connection selected...
auto index = ui->connectionListWidget->currentIndex().row();
if (index < 0) {
if (ui->connectionListWidget->currentIndex().row() < 0) {
QvMessageBox(this, tr("NoConfigSelected"), tr("PleaseSelectAConfig"));
return;
}
auto alias = ui->connectionListWidget->currentItem()->text();
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);
w->show();
}
@ -508,3 +520,8 @@ void MainWindow::on_pushButton_clicked()
SubscribeEditor *w = new SubscribeEditor(this);
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_reconnectButton_clicked();
private:
void on_action_StartThis_triggered();
void on_action_RenameConnection_triggered();
@ -75,7 +77,7 @@ class MainWindow : public QMainWindow
QString originalName;
bool isRenamingInProgress;
//
void ShowAndSetConnection(int index, bool SetConnection, bool Apply);
void ShowAndSetConnection(QString currentText, bool SetConnection, bool Apply);
void LoadConnections();
void closeEvent(QCloseEvent *);
};

View File

@ -37,7 +37,7 @@
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="2,3">
<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">
<number>5</number>
</property>
@ -58,6 +58,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="reconnectButton">
<property name="text">
<string>Reconnect</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearlogButton">
<property name="text">

View File

@ -5,10 +5,6 @@
#include <iostream>
#ifdef __linux
#include <unistd.h>
#endif
#define NEEDRESTART if(finishedLoading) IsConnectionPropertyChanged = true;
PrefrencesWindow::PrefrencesWindow(QWidget *parent) : QDialog(parent),
@ -30,7 +26,7 @@ PrefrencesWindow::PrefrencesWindow(QWidget *parent) : QDialog(parent),
//
ui->languageComboBox->setCurrentText(QSTRING(CurrentConfig.language));
ui->logLevelComboBox->setCurrentIndex(CurrentConfig.logLevel);
ui->runAsRootCheckBox->setChecked(CurrentConfig.runAsRoot);
ui->tProxyCheckBox->setChecked(CurrentConfig.runAsRoot);
//
//
ui->listenIPTxt->setText(QSTRING(CurrentConfig.inBoundSettings.listenip));
@ -63,7 +59,6 @@ PrefrencesWindow::PrefrencesWindow(QWidget *parent) : QDialog(parent),
ui->socksPortLE->setValidator(new QIntValidator());
//
//
ui->vCoreExePathTxt->setText(QSTRING(CurrentConfig.v2CorePath));
ui->vCoreAssetsPathTxt->setText(QSTRING(CurrentConfig.v2AssetsPath));
//
//
@ -105,7 +100,7 @@ void PrefrencesWindow::on_buttonBox_accepted()
int hp = ui->httpPortLE->text().toInt() ;
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;
}
@ -149,38 +144,6 @@ void PrefrencesWindow::on_httpAuthCB_stateChanged(int 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)
{
NEEDRESTART
@ -193,7 +156,7 @@ void PrefrencesWindow::on_languageComboBox_currentTextChanged(const QString &arg
{
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
//
//if (QApplication::installTranslator(getTranslator(&arg1))) {
@ -210,12 +173,6 @@ void PrefrencesWindow::on_logLevelComboBox_currentIndexChanged(int 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)
{
NEEDRESTART
@ -294,21 +251,10 @@ void PrefrencesWindow::on_localDNSCb_stateChanged(int arg1)
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()
{
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);
on_vCoreAssetsPathTxt_textEdited(dir);
}
@ -350,3 +296,55 @@ void PrefrencesWindow::on_cancelIgnoreVersionBtn_clicked()
CurrentConfig.ignoredVersion.clear();
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();
signals:
void s_reload_config(bool need_restart);
private slots:
void on_buttonBox_accepted();
void on_httpCB_stateChanged(int arg1);
void on_socksCB_stateChanged(int arg1);
void on_httpAuthCB_stateChanged(int arg1);
void on_runAsRootCheckBox_stateChanged(int arg1);
void on_socksAuthCB_stateChanged(int arg1);
void on_languageComboBox_currentTextChanged(const QString &arg1);
void on_logLevelComboBox_currentIndexChanged(int index);
void on_vCoreExePathTxt_textEdited(const QString &arg1);
void on_vCoreAssetsPathTxt_textEdited(const QString &arg1);
void on_muxEnabledCB_stateChanged(int arg1);
@ -62,8 +61,6 @@ class PrefrencesWindow : public QDialog
void on_localDNSCb_stateChanged(int arg1);
void on_selectVCoreBtn_clicked();
void on_selectVAssetBtn_clicked();
void on_DNSListTxt_textChanged();
@ -74,6 +71,8 @@ class PrefrencesWindow : public QDialog
void on_cancelIgnoreVersionBtn_clicked();
void on_tProxyCheckBox_stateChanged(int arg1);
private:
bool IsConnectionPropertyChanged = false;
bool finishedLoading = false;

View File

@ -64,27 +64,13 @@
</widget>
</item>
<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">
<property name="text">
<string>Log Level</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="1" column="1">
<widget class="QComboBox" name="logLevelComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
@ -125,14 +111,14 @@
</item>
</widget>
</item>
<item row="3" column="0">
<item row="2" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Automatically Connect To</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="2" column="1">
<widget class="QComboBox" name="autoStartCombo">
<item>
<property name="text">
@ -141,35 +127,28 @@
</item>
</widget>
</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">
<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">
<property name="text">
<string>v2ray Assets Path</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLineEdit" name="vCoreAssetsPathTxt"/>

View File

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

View File

@ -211,14 +211,14 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_ConnectionEditWindow.cpp" line="398"/>
<location filename="../src/w_ConnectionEditWindow.cpp" line="409"/>
<location filename="../src/w_ConnectionEditWindow.cpp" line="397"/>
<location filename="../src/w_ConnectionEditWindow.cpp" line="408"/>
<source>#JsonPrettify</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_ConnectionEditWindow.cpp" line="398"/>
<location filename="../src/w_ConnectionEditWindow.cpp" line="409"/>
<location filename="../src/w_ConnectionEditWindow.cpp" line="397"/>
<location filename="../src/w_ConnectionEditWindow.cpp" line="408"/>
<source>#JsonContainsError</source>
<translation type="unfinished"></translation>
</message>
@ -293,33 +293,33 @@
</message>
<message>
<location filename="../src/w_ImportConfig.cpp" line="36"/>
<source>OpenConfigFile</source>
<source>Select file to import</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_ImportConfig.cpp" line="50"/>
<source>#InvalidConfigFile</source>
<location filename="../src/w_ImportConfig.cpp" line="51"/>
<source>Import config file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_ImportConfig.cpp" line="50"/>
<source>ConfigFileCheckFailed</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>
<location filename="../src/w_ImportConfig.cpp" line="51"/>
<source>Failed to check the validity of the config file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<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>
</message>
</context>
@ -343,129 +343,129 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="64"/>
<location filename="../src/w_MainWindow.ui" line="71"/>
<source>Clear Log</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="71"/>
<location filename="../src/w_MainWindow.ui" line="78"/>
<source>Prefrences</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="94"/>
<location filename="../src/w_MainWindow.ui" line="101"/>
<source>Stopped</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="103"/>
<location filename="../src/w_MainWindow.ui" line="110"/>
<source>Host List</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="110"/>
<location filename="../src/w_MainWindow.ui" line="117"/>
<source>Config Details</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="116"/>
<location filename="../src/w_MainWindow.ui" line="123"/>
<source>Type</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="130"/>
<location filename="../src/w_MainWindow.ui" line="137"/>
<source>Host</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="144"/>
<location filename="../src/w_MainWindow.ui" line="151"/>
<source>Port</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="158"/>
<location filename="../src/w_MainWindow.ui" line="165"/>
<source>Detail</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="236"/>
<location filename="../src/w_MainWindow.ui" line="243"/>
<source>#AddConnection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="239"/>
<location filename="../src/w_MainWindow.ui" line="246"/>
<source>A</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="256"/>
<location filename="../src/w_MainWindow.ui" line="346"/>
<location filename="../src/w_MainWindow.ui" line="263"/>
<location filename="../src/w_MainWindow.ui" line="353"/>
<source>#ImportConnection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="259"/>
<location filename="../src/w_MainWindow.ui" line="266"/>
<source>I</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="290"/>
<location filename="../src/w_MainWindow.ui" line="297"/>
<source>#RemoveConnection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="293"/>
<location filename="../src/w_MainWindow.ui" line="300"/>
<source>R</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="270"/>
<location filename="../src/w_MainWindow.ui" line="277"/>
<source>#EditConnection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="273"/>
<location filename="../src/w_MainWindow.ui" line="280"/>
<source>...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="319"/>
<location filename="../src/w_MainWindow.ui" line="326"/>
<source>Log</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="341"/>
<location filename="../src/w_MainWindow.ui" line="348"/>
<source>#ManuallyCreateConnection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="351"/>
<location filename="../src/w_MainWindow.ui" line="358"/>
<source>#Exit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="356"/>
<location filename="../src/w_MainWindow.ui" line="363"/>
<source>#Preferences</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="361"/>
<location filename="../src/w_MainWindow.ui" line="368"/>
<source>#Start</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="366"/>
<location filename="../src/w_MainWindow.ui" line="373"/>
<source>#Stop</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="371"/>
<location filename="../src/w_MainWindow.ui" line="378"/>
<source>#Restart</source>
<translation type="unfinished"></translation>
</message>
<message>
<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>
<translation type="unfinished"></translation>
</message>
@ -475,6 +475,7 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.ui" line="64"/>
<location filename="../src/w_MainWindow.cpp" line="41"/>
<source>Reconnect</source>
<translation type="unfinished"></translation>
@ -485,19 +486,35 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="92"/>
<location filename="../src/w_MainWindow.cpp" line="238"/>
<location filename="../src/w_MainWindow.cpp" line="286"/>
<location filename="../src/w_MainWindow.cpp" line="91"/>
<location filename="../src/w_MainWindow.cpp" line="244"/>
<location filename="../src/w_MainWindow.cpp" line="292"/>
<source>Show</source>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="495"/>
<location filename="../src/w_MainWindow.cpp" line="507"/>
<source>PleaseSelectAConfig</source>
<translation type="unfinished"></translation>
</message>
@ -507,99 +524,83 @@
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="120"/>
<location filename="../src/w_MainWindow.cpp" line="126"/>
<source>Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="121"/>
<location filename="../src/w_MainWindow.cpp" line="127"/>
<source>Found a new version: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="127"/>
<location filename="../src/w_MainWindow.cpp" line="133"/>
<source>Download Link: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="188"/>
<location filename="../src/w_MainWindow.cpp" line="194"/>
<source>No connection selected!</source>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="199"/>
<location filename="../src/w_MainWindow.cpp" line="200"/>
<location filename="../src/w_MainWindow.cpp" line="205"/>
<location filename="../src/w_MainWindow.cpp" line="206"/>
<source>Connected To Server: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="201"/>
<location filename="../src/w_MainWindow.cpp" line="207"/>
<source>Connected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="218"/>
<location filename="../src/w_MainWindow.cpp" line="224"/>
<source>Disconnected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="324"/>
<location filename="../src/w_MainWindow.cpp" line="327"/>
<source>UUID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="326"/>
<location filename="../src/w_MainWindow.cpp" line="329"/>
<source>AlterID</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="328"/>
<location filename="../src/w_MainWindow.cpp" line="331"/>
<source>Transport</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="335"/>
<location filename="../src/w_MainWindow.cpp" line="338"/>
<source>Email</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="337"/>
<location filename="../src/w_MainWindow.cpp" line="340"/>
<source>Encryption</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="344"/>
<location filename="../src/w_MainWindow.cpp" line="347"/>
<source>Username</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="419"/>
<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"/>
<location filename="../src/w_MainWindow.cpp" line="442"/>
<source>The name has been used already, Please choose another.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="455"/>
<source>Removing A Connection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_MainWindow.cpp" line="455"/>
<location filename="../src/w_MainWindow.cpp" line="469"/>
<source>Are you sure to remove this connection?</source>
<translation type="unfinished"></translation>
</message>
@ -608,8 +609,10 @@
<name>PrefrencesWindow</name>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="20"/>
<location filename="../src/w_PrefrencesWindow.cpp" line="108"/>
<location filename="../src/w_PrefrencesWindow.cpp" line="180"/>
<location filename="../src/w_PrefrencesWindow.cpp" line="103"/>
<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>
<translation type="unfinished"></translation>
</message>
@ -635,271 +638,296 @@
</message>
<message>
<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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="103"/>
<location filename="../src/w_PrefrencesWindow.ui" line="89"/>
<source>none</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="108"/>
<location filename="../src/w_PrefrencesWindow.ui" line="94"/>
<source>debug</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="113"/>
<location filename="../src/w_PrefrencesWindow.ui" line="99"/>
<source>info</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="118"/>
<location filename="../src/w_PrefrencesWindow.ui" line="104"/>
<source>warning</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="123"/>
<location filename="../src/w_PrefrencesWindow.ui" line="109"/>
<source>error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="131"/>
<location filename="../src/w_PrefrencesWindow.ui" line="117"/>
<source>Automatically Connect To</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="147"/>
<source>v2ray Core Path</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="159"/>
<location filename="../src/w_PrefrencesWindow.ui" line="180"/>
<source>#Select</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="168"/>
<location filename="../src/w_PrefrencesWindow.ui" line="147"/>
<source>v2ray Assets Path</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="190"/>
<location filename="../src/w_PrefrencesWindow.ui" line="169"/>
<source>Mux Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="76"/>
<location filename="../src/w_PrefrencesWindow.ui" line="196"/>
<location filename="../src/w_PrefrencesWindow.ui" line="203"/>
<location filename="../src/w_PrefrencesWindow.ui" line="259"/>
<location filename="../src/w_PrefrencesWindow.ui" line="287"/>
<location filename="../src/w_PrefrencesWindow.ui" line="326"/>
<location filename="../src/w_PrefrencesWindow.ui" line="360"/>
<location filename="../src/w_PrefrencesWindow.ui" line="140"/>
<location filename="../src/w_PrefrencesWindow.ui" line="175"/>
<location filename="../src/w_PrefrencesWindow.ui" line="182"/>
<location filename="../src/w_PrefrencesWindow.ui" line="238"/>
<location filename="../src/w_PrefrencesWindow.ui" line="266"/>
<location filename="../src/w_PrefrencesWindow.ui" line="305"/>
<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="442"/>
<location filename="../src/w_PrefrencesWindow.ui" line="449"/>
<location filename="../src/w_PrefrencesWindow.ui" line="428"/>
<source>Enabled</source>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="231"/>
<location filename="../src/w_PrefrencesWindow.ui" line="210"/>
<source>InBound Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="239"/>
<location filename="../src/w_PrefrencesWindow.ui" line="218"/>
<source>Listen IP</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="253"/>
<location filename="../src/w_PrefrencesWindow.ui" line="232"/>
<source>SOCKS InBound Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="266"/>
<location filename="../src/w_PrefrencesWindow.ui" line="333"/>
<location filename="../src/w_PrefrencesWindow.ui" line="245"/>
<location filename="../src/w_PrefrencesWindow.ui" line="312"/>
<source>Port</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="280"/>
<location filename="../src/w_PrefrencesWindow.ui" line="353"/>
<location filename="../src/w_PrefrencesWindow.ui" line="259"/>
<location filename="../src/w_PrefrencesWindow.ui" line="332"/>
<source>Authentication</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="294"/>
<location filename="../src/w_PrefrencesWindow.ui" line="367"/>
<location filename="../src/w_PrefrencesWindow.ui" line="273"/>
<location filename="../src/w_PrefrencesWindow.ui" line="346"/>
<source>Username</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="304"/>
<location filename="../src/w_PrefrencesWindow.ui" line="377"/>
<location filename="../src/w_PrefrencesWindow.ui" line="283"/>
<location filename="../src/w_PrefrencesWindow.ui" line="356"/>
<source>Password</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="317"/>
<location filename="../src/w_PrefrencesWindow.ui" line="296"/>
<source>HTTP InBound Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="406"/>
<location filename="../src/w_PrefrencesWindow.ui" line="385"/>
<source>Route Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="414"/>
<location filename="../src/w_PrefrencesWindow.ui" line="393"/>
<source>Enable Proxy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="428"/>
<location filename="../src/w_PrefrencesWindow.ui" line="407"/>
<source>Chinese Addresses</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="435"/>
<location filename="../src/w_PrefrencesWindow.ui" line="414"/>
<source>Use Local DNS</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="461"/>
<location filename="../src/w_PrefrencesWindow.ui" line="440"/>
<source>DNS List</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="475"/>
<location filename="../src/w_PrefrencesWindow.ui" line="454"/>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="523"/>
<location filename="../src/w_PrefrencesWindow.ui" line="502"/>
<source>Qv2ray</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="545"/>
<location filename="../src/w_PrefrencesWindow.ui" line="524"/>
<source>Version:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="578"/>
<location filename="../src/w_PrefrencesWindow.ui" line="557"/>
<source>Official Repo:</source>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="629"/>
<location filename="../src/w_PrefrencesWindow.ui" line="608"/>
<source>License:</source>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="684"/>
<location filename="../src/w_PrefrencesWindow.ui" line="663"/>
<source>About Qt</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="719"/>
<location filename="../src/w_PrefrencesWindow.ui" line="698"/>
<source>Ingore Next Version</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.ui" line="726"/>
<location filename="../src/w_PrefrencesWindow.ui" line="705"/>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.cpp" line="108"/>
<source>PortNumbersCannotBeSame</source>
<location filename="../src/w_PrefrencesWindow.cpp" line="103"/>
<source>Port numbers cannot be the same</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.cpp" line="180"/>
<source>RunAsRootNotOnWindows</source>
<location filename="../src/w_PrefrencesWindow.cpp" line="257"/>
<source>Open v2ray assets folder</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.cpp" line="300"/>
<source>#OpenVCoreFile</source>
<location filename="../src/w_PrefrencesWindow.cpp" line="315"/>
<source>Enable tProxy Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/w_PrefrencesWindow.cpp" line="311"/>
<source>OpenVAssetsDir</source>
<location filename="../src/w_PrefrencesWindow.cpp" line="315"/>
<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>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../src/QvCoreConfigOperations_Verification.cpp" line="22"/>
<source>#VMessDecodeError</source>
<location filename="../src/main.cpp" line="54"/>
<source>Qv2ray Cannot Continue</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/QvCoreInteractions.cpp" line="29"/>
<source>ConfigurationError</source>
<location filename="../src/main.cpp" line="54"/>
<source>You are running a lower version of Qv2ray compared to the current config file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/QvCoreInteractions.cpp" line="53"/>
<source>CoreNotFound</source>
<location filename="../src/main.cpp" line="56"/>
<source>Please report if you think this is an error.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/QvCoreInteractions.cpp" line="53"/>
<source>CoreFileNotFoundExplainationAt:</source>
<location filename="../src/main.cpp" line="57"/>
<source>Qv2ray will now exit.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/main.cpp" line="166"/>
<location filename="../src/main.cpp" line="144"/>
<source>DependencyMissing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/main.cpp" line="167"/>
<location filename="../src/main.cpp" line="145"/>
<source>Cannot find openssl libs</source>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<translation type="unfinished"></translation>
</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>
<name>RouteEditor</name>

File diff suppressed because it is too large Load Diff