mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-20 10:50:23 +08:00
Merge branch 'dev' into dev-group-routing
This commit is contained in:
commit
f10b35f34f
@ -10,7 +10,7 @@ env:
|
||||
addons:
|
||||
snaps:
|
||||
- name: snapcraft
|
||||
channel: stable
|
||||
channel: edge
|
||||
confinement: classic
|
||||
- name: lxd
|
||||
channel: stable
|
||||
|
@ -29,10 +29,12 @@ add_definitions(-DQV2RAY_VERSION_BUGFIX=${CPACK_PACKAGE_VERSION_PATCH})
|
||||
add_definitions(-DQV2RAY_VERSION_BUILD=${QV2RAY_BUILD_VERSION})
|
||||
|
||||
add_definitions(-DQV2RAY_VERSION_STRING="${QV2RAY_VERSION_STRING}")
|
||||
add_definitions(-DXTOSTRUCT_QT)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
endif()
|
||||
|
||||
find_package(Qt5 5.11 COMPONENTS Core Gui Widgets Network REQUIRED)
|
||||
|
||||
@ -145,6 +147,10 @@ if(QV2RAY_DISABLE_AUTO_UPDATE)
|
||||
add_definitions(-DDISABLE_AUTO_UPDATE)
|
||||
endif()
|
||||
|
||||
if(FALL_BACK_TO_XDG_OPEN)
|
||||
add_definitions(-DFALL_BACK_TO_XDG_OPEN)
|
||||
endif()
|
||||
|
||||
set(QVPLUGIN_INTERFACE_INCLUDE_DIR "src/components/plugins/interface")
|
||||
include(src/components/plugins/interface/QvPluginInterface.cmake)
|
||||
|
||||
@ -168,11 +174,13 @@ set(QV2RAY_SOURCES
|
||||
src/components/plugins/toolbar/QvToolbar_linux.cpp
|
||||
src/components/plugins/toolbar/QvToolbar_win.cpp
|
||||
src/components/plugins/QvPluginHost.cpp
|
||||
src/components/port/QvPortDetector.cpp
|
||||
src/components/proxy/QvProxyConfigurator.cpp
|
||||
src/components/route/RouteSchemeIO.cpp
|
||||
src/components/speedchart/speedplotview.cpp
|
||||
src/components/speedchart/speedwidget.cpp
|
||||
src/components/darkmode/DarkmodeDetector.cpp
|
||||
src/components/ntp/QvNTPClient.cpp
|
||||
src/components/update/UpdateChecker.cpp
|
||||
src/core/connection/ConnectionIO.cpp
|
||||
src/core/connection/Generation.cpp
|
||||
@ -257,7 +265,9 @@ set(QV2RAY_SOURCES
|
||||
src/components/latency/QvTCPing.hpp
|
||||
src/components/plugins/toolbar/QvToolbar.hpp
|
||||
src/components/plugins/QvPluginHost.hpp
|
||||
src/components/port/QvPortDetector.hpp
|
||||
src/components/proxy/QvProxyConfigurator.hpp
|
||||
src/components/ntp/QvNTPClient.hpp
|
||||
src/components/route/RouteSchemeIO.hpp
|
||||
src/components/route/presets/RouteScheme_V2rayN.hpp
|
||||
src/components/speedchart/speedplotview.hpp
|
||||
|
@ -1 +1 @@
|
||||
5391
|
||||
5400
|
||||
|
@ -1,5 +1,5 @@
|
||||
name: qv2ray
|
||||
base: core18
|
||||
base: core20
|
||||
adopt-info: qv2ray
|
||||
icon: assets/icons/qv2ray.png
|
||||
|
||||
@ -57,7 +57,6 @@ parts:
|
||||
- libgrpc++-dev
|
||||
- libprotobuf-dev
|
||||
- protobuf-compiler-grpc
|
||||
- ninja-build
|
||||
- pkg-config
|
||||
stage-packages:
|
||||
- libgcc1
|
||||
@ -70,11 +69,11 @@ parts:
|
||||
- libqt5network5
|
||||
- libqt5widgets5
|
||||
- libglib2.0-bin
|
||||
configflags:
|
||||
cmake-parameters:
|
||||
- -DCMAKE_INSTALL_PREFIX=/usr
|
||||
- -DCMAKE_BUILD_TYPE=Release
|
||||
- -GNinja
|
||||
- -DEMBED_TRANSLATIONS=ON
|
||||
- -DFALL_BACK_TO_XDG_OPEN=ON
|
||||
override-pull: |
|
||||
snapcraftctl pull
|
||||
build_number=$(cat makespec/BUILDVERSION)
|
||||
@ -84,7 +83,6 @@ parts:
|
||||
sed -i 's|^Icon=.*|Icon=/usr/share/icons/hicolor/256x256/apps/qv2ray.png|g' assets/qv2ray.desktop
|
||||
after:
|
||||
- desktop-qt5
|
||||
- ppa
|
||||
|
||||
desktop-qt5:
|
||||
source: https://github.com/ubuntu/snapcraft-desktop-helpers.git
|
||||
@ -110,21 +108,8 @@ parts:
|
||||
- locales-all
|
||||
- xdg-user-dirs
|
||||
- fcitx-frontend-qt5
|
||||
after:
|
||||
- ppa
|
||||
|
||||
qt5-gtk-platform:
|
||||
plugin: nil
|
||||
stage-packages:
|
||||
- qt5-gtk-platformtheme
|
||||
after:
|
||||
- ppa
|
||||
|
||||
ppa:
|
||||
plugin: nil
|
||||
build-packages:
|
||||
- software-properties-common
|
||||
- dirmngr
|
||||
override-build: |
|
||||
sudo add-apt-repository -y ppa:ymshenyu/qv2ray-deps
|
||||
sudo apt-get dist-upgrade -y
|
||||
- qt5-gtk-platformtheme
|
@ -8,6 +8,7 @@ namespace Qv2ray::base
|
||||
struct Qv2rayRuntimeConfig
|
||||
{
|
||||
bool screenShotHideQv2ray = false;
|
||||
bool deepinHorribleProxyHint = false;
|
||||
};
|
||||
inline base::Qv2rayRuntimeConfig RuntimeConfig = base::Qv2rayRuntimeConfig();
|
||||
} // namespace Qv2ray::base
|
||||
|
@ -127,7 +127,7 @@ namespace Qv2ray::base::config
|
||||
Qv2rayRouteConfig_Impl(){};
|
||||
friend bool operator==(const Qv2rayRouteConfig_Impl &left, const Qv2rayRouteConfig_Impl &right)
|
||||
{
|
||||
return left.direct == right.direct && left.block == right.block && left.proxy == left.proxy;
|
||||
return left.direct == right.direct && left.block == right.block && left.proxy == right.proxy;
|
||||
}
|
||||
Qv2rayRouteConfig_Impl(const QList<QString> &_direct, const QList<QString> &_block, const QList<QString> &_proxy)
|
||||
: direct(_direct), block(_block), proxy(_proxy){};
|
||||
|
@ -111,6 +111,31 @@ namespace Qv2ray::common
|
||||
return doc.object();
|
||||
}
|
||||
|
||||
// backported from QvPlugin-SSR.
|
||||
QString SafeBase64Decode(QString string) {
|
||||
QByteArray ba = string.replace(QChar('-'), QChar('+')).replace(QChar('_'), QChar('/')).toUtf8();
|
||||
return QByteArray::fromBase64(ba, QByteArray::Base64Option::OmitTrailingEquals);
|
||||
}
|
||||
|
||||
// backported from QvPlugin-SSR.
|
||||
QString SafeBase64Encode(const QString &string, bool trim)
|
||||
{
|
||||
QString base64 = string.toUtf8().toBase64();
|
||||
if (trim)
|
||||
{
|
||||
auto tmp = base64.replace(QChar('+'), QChar('-')).replace(QChar('/'), QChar('_'));
|
||||
auto crbedin = tmp.crbegin();
|
||||
auto idx = tmp.length();
|
||||
while (crbedin != tmp.crend() && (*crbedin) == '=') idx -= 1, crbedin++;
|
||||
return idx != tmp.length() ? tmp.remove(idx, tmp.length() - idx) : tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
return base64.replace(QChar('+'), QChar('-')).replace(QChar('/'), QChar('_'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QString Base64Encode(const QString &string)
|
||||
{
|
||||
QByteArray ba = string.toUtf8();
|
||||
|
@ -18,6 +18,10 @@
|
||||
namespace Qv2ray::common
|
||||
{
|
||||
QStringList GetFileList(const QDir &dir);
|
||||
|
||||
QString SafeBase64Decode(QString string);
|
||||
QString SafeBase64Encode(const QString &string, bool trim);
|
||||
|
||||
QString Base64Encode(const QString &string);
|
||||
QString Base64Decode(const QString &string);
|
||||
QStringList SplitLines(const QString &str);
|
||||
|
@ -2,7 +2,9 @@
|
||||
#include <WS2tcpip.h>
|
||||
#include <WinSock2.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
@ -11,6 +13,110 @@
|
||||
#include "QvTCPing.hpp"
|
||||
#include "core/handler/ConfigHandler.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
using qv_socket_t = SOCKET;
|
||||
#else
|
||||
using qv_socket_t = int;
|
||||
#endif
|
||||
namespace
|
||||
{
|
||||
inline int setnonblocking(qv_socket_t sockno, int &opt)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ULONG block = 1;
|
||||
if (ioctlsocket(sockno, FIONBIO, &block) == SOCKET_ERROR)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
if ((opt = fcntl(sockno, F_GETFL, NULL)) < 0)
|
||||
{
|
||||
// get socket flags
|
||||
return -1;
|
||||
}
|
||||
if (fcntl(sockno, F_SETFL, opt | O_NONBLOCK) < 0)
|
||||
{
|
||||
// set socket non-blocking
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int setblocking(qv_socket_t sockno, int &opt)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ULONG block = 0;
|
||||
if (ioctlsocket(sockno, FIONBIO, &block) == SOCKET_ERROR)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
if (fcntl(sockno, F_SETFL, opt) < 0)
|
||||
{
|
||||
// reset socket flags
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connect_wait(qv_socket_t sockno, struct sockaddr *addr, size_t addrlen, int timeout_sec = 5)
|
||||
{
|
||||
int res;
|
||||
int opt;
|
||||
timeval tv = { 0 };
|
||||
tv.tv_sec = timeout_sec;
|
||||
tv.tv_usec = 0;
|
||||
if ((res = setnonblocking(sockno, opt)) != 0)
|
||||
return -1;
|
||||
if ((res = ::connect(sockno, addr, addrlen)) < 0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (WSAGetLastError() != WSAEWOULDBLOCK)
|
||||
{
|
||||
#else
|
||||
if (errno == EINPROGRESS)
|
||||
{
|
||||
#endif
|
||||
// connecting
|
||||
fd_set wait_set;
|
||||
FD_ZERO(&wait_set);
|
||||
FD_SET(sockno, &wait_set);
|
||||
res = select(sockno + 1, NULL, &wait_set, NULL, &tv);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// connect immediately
|
||||
res = 1;
|
||||
}
|
||||
if (setblocking(sockno, opt) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (res < 0)
|
||||
{
|
||||
// an error occured
|
||||
return -1;
|
||||
}
|
||||
else if (res == 0)
|
||||
{
|
||||
// timeout
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
socklen_t len = sizeof(opt);
|
||||
if (getsockopt(sockno, SOL_SOCKET, SO_ERROR, reinterpret_cast<char *>(&opt), &len) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace Qv2ray::components::tcping
|
||||
{
|
||||
static int resolveHost(const std::string &host, int portnr, struct addrinfo **res);
|
||||
@ -159,11 +265,8 @@ namespace Qv2ray::components::tcping
|
||||
|
||||
int testLatency(struct addrinfo *addr, std::chrono::system_clock::time_point *start, std::chrono::system_clock::time_point *end)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SOCKET fd;
|
||||
#else
|
||||
int fd;
|
||||
#endif
|
||||
qv_socket_t fd;
|
||||
|
||||
const int on = 1;
|
||||
/* int flags; */
|
||||
int rv = 0;
|
||||
@ -198,7 +301,7 @@ namespace Qv2ray::components::tcping
|
||||
/* connect to peer */
|
||||
// Qt has its own connect() function in QObject....
|
||||
// So we add "::" here
|
||||
if (::connect(fd, addr->ai_addr, addr->ai_addrlen) == 0)
|
||||
if (connect_wait(fd, addr->ai_addr, addr->ai_addrlen) == 0)
|
||||
{
|
||||
*end = system_clock::now();
|
||||
#ifdef Q_OS_WIN
|
||||
|
216
src/components/ntp/QvNTPClient.cpp
Normal file
216
src/components/ntp/QvNTPClient.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
/* This file from part of QNtp, a library that implements NTP protocol.
|
||||
*
|
||||
* Copyright (C) 2011 Alexander Fokin <apfokin@gmail.com>
|
||||
*
|
||||
* QNtp is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* QNtp is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with QNtp. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "QvNTPClient.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace Qv2ray::components::ntp
|
||||
{
|
||||
|
||||
NtpTimestamp NtpTimestamp::fromDateTime(const QDateTime &dateTime)
|
||||
{
|
||||
qint64 ntpMSecs = dateTime.toMSecsSinceEpoch() - january_1_1900;
|
||||
|
||||
quint32 seconds = ntpMSecs / 1000;
|
||||
quint32 fraction = 0x100000000ll * (ntpMSecs % 1000) / 1000;
|
||||
|
||||
NtpTimestamp result;
|
||||
result.seconds = qToBigEndian(seconds);
|
||||
result.fraction = qToBigEndian(fraction);
|
||||
return result;
|
||||
}
|
||||
|
||||
QDateTime NtpTimestamp::toDateTime(const NtpTimestamp &ntpTime)
|
||||
{
|
||||
/* Convert to local-endian. */
|
||||
quint32 seconds = qFromBigEndian(ntpTime.seconds);
|
||||
quint32 fraction = qFromBigEndian(ntpTime.fraction);
|
||||
|
||||
/* Convert NTP timestamp to number of milliseconds passed since Jan 1 1900. */
|
||||
qint64 ntpMSecs = seconds * 1000ll + fraction * 1000ll / 0x100000000ll;
|
||||
|
||||
/* Construct Qt date time. */
|
||||
return QDateTime::fromMSecsSinceEpoch(ntpMSecs + january_1_1900);
|
||||
}
|
||||
|
||||
NtpReply::NtpReply() : d(new NtpReplyPrivate())
|
||||
{
|
||||
/* We don't use shared null because NtpReplyPrivate isn't a POD type and
|
||||
* allocation overhead is negligible here. */
|
||||
memset(&d->packet, 0, sizeof(d->packet));
|
||||
}
|
||||
|
||||
NtpReply::NtpReply(NtpReplyPrivate *dd) : d(dd)
|
||||
{
|
||||
Q_ASSERT(dd != NULL);
|
||||
}
|
||||
|
||||
NtpReply::NtpReply(const NtpReply &other) : d(other.d)
|
||||
{
|
||||
}
|
||||
|
||||
NtpReply::~NtpReply()
|
||||
{
|
||||
}
|
||||
|
||||
NtpReply &NtpReply::operator=(const NtpReply &other)
|
||||
{
|
||||
d = other.d;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NtpLeapIndicator NtpReply::leapIndicator() const
|
||||
{
|
||||
return static_cast<NtpLeapIndicator>(d->packet.basic.flags.leapIndicator);
|
||||
}
|
||||
|
||||
quint8 NtpReply::versionNumber() const
|
||||
{
|
||||
return d->packet.basic.flags.versionNumber;
|
||||
}
|
||||
|
||||
NtpMode NtpReply::mode() const
|
||||
{
|
||||
return static_cast<NtpMode>(d->packet.basic.flags.mode);
|
||||
}
|
||||
|
||||
quint8 NtpReply::stratum() const
|
||||
{
|
||||
return d->packet.basic.stratum;
|
||||
}
|
||||
|
||||
qreal NtpReply::pollInterval() const
|
||||
{
|
||||
return std::pow(static_cast<qreal>(2), static_cast<qreal>(d->packet.basic.poll));
|
||||
}
|
||||
|
||||
qreal NtpReply::precision() const
|
||||
{
|
||||
return std::pow(static_cast<qreal>(2), static_cast<qreal>(d->packet.basic.precision));
|
||||
}
|
||||
|
||||
QDateTime NtpReply::referenceTime() const
|
||||
{
|
||||
return NtpTimestamp::toDateTime(d->packet.basic.referenceTimestamp);
|
||||
}
|
||||
|
||||
QDateTime NtpReply::originTime() const
|
||||
{
|
||||
return NtpTimestamp::toDateTime(d->packet.basic.originateTimestamp);
|
||||
}
|
||||
|
||||
QDateTime NtpReply::receiveTime() const
|
||||
{
|
||||
return NtpTimestamp::toDateTime(d->packet.basic.receiveTimestamp);
|
||||
}
|
||||
|
||||
QDateTime NtpReply::transmitTime() const
|
||||
{
|
||||
return NtpTimestamp::toDateTime(d->packet.basic.transmitTimestamp);
|
||||
}
|
||||
|
||||
QDateTime NtpReply::destinationTime() const
|
||||
{
|
||||
return d->destinationTime;
|
||||
}
|
||||
|
||||
qint64 NtpReply::roundTripDelay() const
|
||||
{
|
||||
return originTime().msecsTo(destinationTime()) - receiveTime().msecsTo(transmitTime());
|
||||
}
|
||||
|
||||
qint64 NtpReply::localClockOffset() const
|
||||
{
|
||||
return (originTime().msecsTo(receiveTime()) + destinationTime().msecsTo(transmitTime())) / 2;
|
||||
}
|
||||
|
||||
bool NtpReply::isNull() const
|
||||
{
|
||||
return d->destinationTime.isNull();
|
||||
}
|
||||
|
||||
NtpClient::NtpClient(QObject *parent) : QObject(parent)
|
||||
{
|
||||
init(QHostAddress::Any, 0);
|
||||
}
|
||||
|
||||
NtpClient::NtpClient(const QHostAddress &bindAddress, quint16 bindPort, QObject *parent) : QObject(parent)
|
||||
{
|
||||
init(bindAddress, bindPort);
|
||||
}
|
||||
|
||||
void NtpClient::init(const QHostAddress &bindAddress, quint16 bindPort)
|
||||
{
|
||||
mSocket = new QUdpSocket(this);
|
||||
mSocket->bind(bindAddress, bindPort);
|
||||
|
||||
connect(mSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
|
||||
}
|
||||
|
||||
NtpClient::~NtpClient()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool NtpClient::sendRequest(const QHostAddress &address, quint16 port)
|
||||
{
|
||||
if (mSocket->state() != QAbstractSocket::BoundState)
|
||||
return false;
|
||||
|
||||
/* Initialize the NTP packet. */
|
||||
NtpPacket packet;
|
||||
memset(&packet, 0, sizeof(packet));
|
||||
packet.flags.mode = ClientMode;
|
||||
packet.flags.versionNumber = 4;
|
||||
packet.transmitTimestamp = NtpTimestamp::fromDateTime(QDateTime::currentDateTimeUtc());
|
||||
|
||||
/* Send it. */
|
||||
if (mSocket->writeDatagram(reinterpret_cast<const char *>(&packet), sizeof(packet), address, port) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NtpClient::readPendingDatagrams()
|
||||
{
|
||||
while (mSocket->hasPendingDatagrams())
|
||||
{
|
||||
NtpFullPacket packet;
|
||||
memset(&packet, 0, sizeof(packet));
|
||||
|
||||
QHostAddress address;
|
||||
quint16 port;
|
||||
|
||||
if (mSocket->readDatagram(reinterpret_cast<char *>(&packet), sizeof(packet), &address, &port) < (qint64) sizeof(NtpPacket))
|
||||
continue;
|
||||
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
|
||||
/* Prepare reply. */
|
||||
NtpReplyPrivate *replyPrivate = new NtpReplyPrivate();
|
||||
replyPrivate->packet = packet;
|
||||
replyPrivate->destinationTime = now;
|
||||
NtpReply reply(replyPrivate);
|
||||
|
||||
/* Notify. */
|
||||
Q_EMIT replyReceived(address, port, reply);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Qv2ray::components::ntp
|
165
src/components/ntp/QvNTPClient.hpp
Normal file
165
src/components/ntp/QvNTPClient.hpp
Normal file
@ -0,0 +1,165 @@
|
||||
/* This file from part of QNtp, a library that implements NTP protocol.
|
||||
*
|
||||
* Copyright (C) 2011 Alexander Fokin <apfokin@gmail.com>
|
||||
*
|
||||
* QNtp is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* QNtp is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with QNtp. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QHostAddress>
|
||||
#include <QObject>
|
||||
#include <QUdpSocket>
|
||||
#include <QtEndian>
|
||||
#include <QtGlobal>
|
||||
|
||||
namespace Qv2ray::components::ntp
|
||||
{
|
||||
const qint64 january_1_1900 = -2208988800000ll;
|
||||
|
||||
enum NtpLeapIndicator
|
||||
{
|
||||
NoWarning = 0, /**< No warning. */
|
||||
LastMinute61Warning = 1, /**< Last minute has 61 seconds. */
|
||||
LastMinute59Warning = 2, /**< Last minute has 59 seconds. */
|
||||
UnsynchronizedWarning = 3, /**< Alarm condition (clock not synchronized). */
|
||||
};
|
||||
|
||||
enum NtpMode
|
||||
{
|
||||
ReservedMode = 0, /**< Reserved. */
|
||||
SymmetricActiveMode = 1, /**< Symmetric active. */
|
||||
SymmetricPassiveMode = 2, /**< Symmetric passive. */
|
||||
ClientMode = 3, /**< Client. */
|
||||
ServerMode = 4, /**< Server. */
|
||||
BroadcastMode = 5, /**< Broadcast. */
|
||||
ControlMode = 6, /**< NTP control message. */
|
||||
PrivateMode = 7, /**< Reserved for private use. */
|
||||
};
|
||||
|
||||
enum NtpStratum
|
||||
{
|
||||
UnspecifiedStratum = 0, /**< Unspecified or unavailable. */
|
||||
PrimaryStratum = 1, /**< Primary reference (e.g. radio-clock). */
|
||||
SecondaryStratumFirst = 2, /**< Secondary reference (via NTP or SNTP). */
|
||||
SecondaryStratumLast = 15,
|
||||
UnsynchronizedStratum = 16, /**< Unsynchronized. */
|
||||
/* 17-255 are reserved. */
|
||||
};
|
||||
|
||||
struct NtpPacketFlags
|
||||
{
|
||||
unsigned char mode : 3;
|
||||
unsigned char versionNumber : 3;
|
||||
unsigned char leapIndicator : 2;
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct NtpTimestamp
|
||||
{
|
||||
quint32 seconds;
|
||||
quint32 fraction;
|
||||
static inline NtpTimestamp fromDateTime(const QDateTime &dateTime);
|
||||
static inline QDateTime toDateTime(const NtpTimestamp &ntpTime);
|
||||
};
|
||||
|
||||
struct NtpPacket
|
||||
{
|
||||
NtpPacketFlags flags;
|
||||
quint8 stratum;
|
||||
qint8 poll;
|
||||
qint8 precision;
|
||||
qint32 rootDelay;
|
||||
qint32 rootDispersion;
|
||||
qint8 referenceID[4];
|
||||
NtpTimestamp referenceTimestamp;
|
||||
NtpTimestamp originateTimestamp;
|
||||
NtpTimestamp receiveTimestamp;
|
||||
NtpTimestamp transmitTimestamp;
|
||||
};
|
||||
|
||||
struct NtpAuthenticationInfo
|
||||
{
|
||||
quint32 keyId;
|
||||
quint8 messageDigest[16];
|
||||
};
|
||||
|
||||
struct NtpFullPacket
|
||||
{
|
||||
NtpPacket basic;
|
||||
NtpAuthenticationInfo auth;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
class NtpReplyPrivate : public QSharedData
|
||||
{
|
||||
public:
|
||||
NtpFullPacket packet;
|
||||
QDateTime destinationTime;
|
||||
};
|
||||
|
||||
class NtpReply
|
||||
{
|
||||
public:
|
||||
NtpReply();
|
||||
NtpReply(const NtpReply &other);
|
||||
~NtpReply();
|
||||
NtpReply &operator=(const NtpReply &other);
|
||||
NtpLeapIndicator leapIndicator() const;
|
||||
quint8 versionNumber() const;
|
||||
NtpMode mode() const;
|
||||
quint8 stratum() const;
|
||||
qreal pollInterval() const;
|
||||
qreal precision() const;
|
||||
QDateTime referenceTime() const;
|
||||
QDateTime originTime() const;
|
||||
QDateTime receiveTime() const;
|
||||
QDateTime transmitTime() const;
|
||||
QDateTime destinationTime() const;
|
||||
qint64 roundTripDelay() const;
|
||||
qint64 localClockOffset() const;
|
||||
bool isNull() const;
|
||||
|
||||
protected:
|
||||
friend class NtpClient;
|
||||
NtpReply(NtpReplyPrivate *dd);
|
||||
|
||||
private:
|
||||
QSharedDataPointer<NtpReplyPrivate> d;
|
||||
};
|
||||
|
||||
class NtpClient : public QObject
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
NtpClient(QObject *parent = NULL);
|
||||
NtpClient(const QHostAddress &bindAddress, quint16 bindPort, QObject *parent = NULL);
|
||||
virtual ~NtpClient();
|
||||
bool sendRequest(const QHostAddress &address, quint16 port);
|
||||
|
||||
Q_SIGNALS:
|
||||
void replyReceived(const QHostAddress &address, quint16 port, const NtpReply &reply);
|
||||
|
||||
private Q_SLOTS:
|
||||
void readPendingDatagrams();
|
||||
|
||||
private:
|
||||
void init(const QHostAddress &bindAddress, quint16 bindPort);
|
||||
|
||||
QUdpSocket *mSocket;
|
||||
};
|
||||
} // namespace Qv2ray::components::ntp
|
13
src/components/port/QvPortDetector.cpp
Normal file
13
src/components/port/QvPortDetector.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "QvPortDetector.hpp"
|
||||
|
||||
#include <QTcpServer>
|
||||
|
||||
namespace Qv2ray::components::port
|
||||
{
|
||||
bool detectPortTCP(quint16 port)
|
||||
{
|
||||
QTcpServer server;
|
||||
return server.listen(QHostAddress::LocalHost, port);
|
||||
}
|
||||
|
||||
} // namespace Qv2ray::components::port
|
7
src/components/port/QvPortDetector.hpp
Normal file
7
src/components/port/QvPortDetector.hpp
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include <QtGlobal>
|
||||
|
||||
namespace Qv2ray::components::port
|
||||
{
|
||||
bool detectPortTCP(quint16 port);
|
||||
}
|
@ -232,61 +232,101 @@ namespace Qv2ray::components::proxy
|
||||
QStringList actions;
|
||||
actions << QString("gsettings set org.gnome.system.proxy mode '%1'").arg("manual");
|
||||
bool isKDE = qEnvironmentVariable("XDG_SESSION_DESKTOP") == "KDE";
|
||||
bool isDDE = isKDE ? false : qEnvironmentVariable("XDG_CURRENT_DESKTOP").toLower() == "deepin";
|
||||
const auto configPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
|
||||
if (isKDE)
|
||||
{
|
||||
LOG(MODULE_PROXY, "KDE detected")
|
||||
actions << QString("kwriteconfig5 --file " + configPath + "/kioslaverc --group \"Proxy Settings\" --key ProxyType 1");
|
||||
}
|
||||
|
||||
// Configure HTTP Proxies for HTTP, FTP and HTTPS
|
||||
if (hasHTTP)
|
||||
{
|
||||
actions << QString("gsettings set org.gnome.system.proxy.http host '%1'").arg(address);
|
||||
actions << QString("gsettings set org.gnome.system.proxy.http port %1").arg(httpPort);
|
||||
//
|
||||
actions << QString("gsettings set org.gnome.system.proxy.https host '%1'").arg(address);
|
||||
actions << QString("gsettings set org.gnome.system.proxy.https port %1").arg(httpPort);
|
||||
if (isKDE)
|
||||
// iterate over protocols...
|
||||
for (const auto protocol : { "http", "ftp", "https" })
|
||||
{
|
||||
// FTP here should be scheme: ftp://
|
||||
for (auto protocol : { "http", "ftp", "https" })
|
||||
// for GNOME:
|
||||
{
|
||||
auto str =
|
||||
QString("kwriteconfig5 --file " + configPath + "/kioslaverc --group \"Proxy Settings\" --key %1Proxy \"http://%2 %3\"")
|
||||
.arg(protocol)
|
||||
.arg(address)
|
||||
.arg(QSTRN(httpPort));
|
||||
actions << str;
|
||||
actions << QString("gsettings set org.gnome.system.proxy.%1 host '%2'").arg(protocol, address);
|
||||
actions << QString("gsettings set org.gnome.system.proxy.%1 port %2").arg(protocol, QSTRN(httpPort));
|
||||
}
|
||||
|
||||
// for KDE:
|
||||
if (isKDE)
|
||||
{
|
||||
actions << QString(R"(kwriteconfig5 --file "%1/kioslaverc" --group "Proxy Settings" --key %2Proxy "http://%3 %4")")
|
||||
.arg(configPath, protocol, address, QSTRN(httpPort));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Configure SOCKS5 Proxies
|
||||
if (hasSOCKS)
|
||||
{
|
||||
actions << QString("gsettings set org.gnome.system.proxy.socks host '%1'").arg(address);
|
||||
actions << QString("gsettings set org.gnome.system.proxy.socks port %1").arg(socksPort);
|
||||
// for GNOME:
|
||||
{
|
||||
actions << QString("gsettings set org.gnome.system.proxy.socks host '%1'").arg(address);
|
||||
actions << QString("gsettings set org.gnome.system.proxy.socks port %1").arg(socksPort);
|
||||
}
|
||||
|
||||
// for KDE:
|
||||
if (isKDE)
|
||||
{
|
||||
actions << QString("kwriteconfig5 --file " + configPath +
|
||||
"/kioslaverc --group \"Proxy Settings\" --key socksProxy \"socks://%1 %2\"")
|
||||
.arg(address)
|
||||
.arg(QSTRN(socksPort));
|
||||
actions << QString(R"(kwriteconfig5 --file "%1/kioslaverc" --group "Proxy Settings" --key socksProxy "socks://%2 %3")")
|
||||
.arg(configPath, address, QSTRN(socksPort));
|
||||
}
|
||||
}
|
||||
|
||||
// Setting Proxy Mode to Manual
|
||||
{
|
||||
// for GNOME:
|
||||
{
|
||||
actions << "gsettings set org.gnome.system.proxy mode 'manual'";
|
||||
}
|
||||
|
||||
// for KDE:
|
||||
if (isKDE)
|
||||
{
|
||||
LOG(MODULE_PROXY, "KDE detected")
|
||||
actions << QString(R"(kwriteconfig5 --file "%1/kioslaverc" --group "Proxy Settings" --key ProxyType 1)").arg(configPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute them all!
|
||||
//
|
||||
// note: do not use std::all_of / any_of / none_of,
|
||||
// because those are short-circuit and cannot guarantee atomicity.
|
||||
auto result = std::count_if(actions.cbegin(), actions.cend(), [](const QString &action) {
|
||||
DEBUG(MODULE_PROXY, action)
|
||||
return QProcess::execute(action) == QProcess::NormalExit;
|
||||
// execute and get the code
|
||||
const auto returnCode = QProcess::execute(action);
|
||||
// print out the commands and result codes
|
||||
DEBUG(MODULE_PROXY, QString("[%1] %2").arg(QSTRN(returnCode), action))
|
||||
// give the code back
|
||||
return returnCode == QProcess::NormalExit;
|
||||
}) == actions.size();
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG(MODULE_PROXY, "There was something wrong when setting proxies.")
|
||||
LOG(MODULE_PROXY, "It may happen if you are using KDE with no gsettings support.")
|
||||
LOG(MODULE_PROXY, "Something wrong when setting proxies.")
|
||||
}
|
||||
|
||||
// Post-Actions for HTTP on Deepin Desktop Environment.
|
||||
if (isDDE && hasHTTP)
|
||||
{
|
||||
if (!RuntimeConfig.deepinHorribleProxyHint)
|
||||
{
|
||||
RuntimeConfig.deepinHorribleProxyHint = true;
|
||||
|
||||
const auto deepinWarnTitle = QObject::tr("Deepin Detected");
|
||||
const auto deepinWarnMessage =
|
||||
QObject::tr("Deepin plays smart and sets you the wrong HTTPS_PROXY, FTP_PROXY environment variable.") + NEWLINE + //
|
||||
QObject::tr("The origin scheme http is wrongly replaced by https and ftp, causing the problem.") + NEWLINE + //
|
||||
QObject::tr("Qv2ray cannot help you change them back. Please don't blame us if things go wrong."); //
|
||||
QvMessageBoxWarn(nullptr, deepinWarnTitle, deepinWarnMessage);
|
||||
}
|
||||
|
||||
// set them back! - NOPE. setenv only works within your little program.
|
||||
// const auto httpProxyURL = QString("http://%1:%2").arg(address, QSTRN(httpPort)).toStdString();
|
||||
// setenv("https_proxy", httpProxyURL.c_str(), true);
|
||||
// setenv("ftp_proxy", httpProxyURL.c_str(), true);
|
||||
}
|
||||
|
||||
Q_UNUSED(result);
|
||||
#else
|
||||
|
||||
for (auto service : macOSgetNetworkServices())
|
||||
@ -323,6 +363,7 @@ namespace Qv2ray::components::proxy
|
||||
void ClearSystemProxy()
|
||||
{
|
||||
LOG(MODULE_PROXY, "Clearing System Proxy")
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
LOG(MODULE_PROXY, "Cleaning system proxy settings.")
|
||||
INTERNET_PER_CONN_OPTION_LIST list;
|
||||
@ -353,21 +394,33 @@ namespace Qv2ray::components::proxy
|
||||
InternetSetOption(nullptr, INTERNET_OPTION_SETTINGS_CHANGED, nullptr, 0);
|
||||
InternetSetOption(nullptr, INTERNET_OPTION_REFRESH, nullptr, 0);
|
||||
#elif defined(Q_OS_LINUX)
|
||||
if (qEnvironmentVariable("XDG_SESSION_DESKTOP") == "KDE")
|
||||
QStringList actions;
|
||||
const bool isKDE = qEnvironmentVariable("XDG_SESSION_DESKTOP") == "KDE";
|
||||
const auto configRoot = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
|
||||
|
||||
// Setting System Proxy Mode to: None
|
||||
{
|
||||
QProcess::execute("kwriteconfig5 --file " + QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) +
|
||||
"/kioslaverc --group \"Proxy Settings\" --key ProxyType 0");
|
||||
for (auto protocol : { "http", "ftp", "https" })
|
||||
// for GNOME:
|
||||
{
|
||||
auto str = QString("kwriteconfig5 --file " + QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) +
|
||||
"/kioslaverc --group \"Proxy Settings\" --key %1Proxy ''")
|
||||
.arg(protocol);
|
||||
QProcess::execute(str);
|
||||
actions << QString("gsettings set org.gnome.system.proxy mode 'none'");
|
||||
}
|
||||
|
||||
// for KDE:
|
||||
if (isKDE)
|
||||
{
|
||||
actions << QString(R"(kwriteconfig5 --file "%1/kioslaverc" --group "Proxy Settings" --key ProxyType 0)").arg(configRoot);
|
||||
}
|
||||
QProcess::execute("kwriteconfig5 --file " + QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) +
|
||||
"/kioslaverc --group \"Proxy Settings\" --key socksProxy ''");
|
||||
}
|
||||
QProcess::execute("gsettings set org.gnome.system.proxy mode 'none'");
|
||||
|
||||
// Execute the Actions
|
||||
for (const auto &action : actions)
|
||||
{
|
||||
// execute and get the code
|
||||
const auto returnCode = QProcess::execute(action);
|
||||
// print out the commands and result codes
|
||||
DEBUG(MODULE_PROXY, QString("[%1] %2").arg(QSTRN(returnCode), action))
|
||||
}
|
||||
|
||||
#else
|
||||
for (auto service : macOSgetNetworkServices())
|
||||
{
|
||||
|
@ -122,7 +122,7 @@ namespace Qv2ray::core::connection
|
||||
// Some subscription providers may use plain vmess:// saperated by
|
||||
// lines But others may use base64 of above.
|
||||
auto result = QString::fromUtf8(arr).trimmed();
|
||||
return result.contains("://") ? result : Base64Decode(result);
|
||||
return result.contains("://") ? result : SafeBase64Decode(result);
|
||||
}
|
||||
} // namespace Serialization
|
||||
} // namespace Qv2ray::core::connection
|
||||
|
@ -81,7 +81,7 @@ namespace Qv2ray::core::connection
|
||||
auto x = QUrl::fromUserInput(uri);
|
||||
server.address = x.host();
|
||||
server.port = x.port();
|
||||
QString userInfo = Base64Decode(x.userName());
|
||||
QString userInfo = SafeBase64Decode(x.userName());
|
||||
auto userInfoSp = userInfo.indexOf(':');
|
||||
//
|
||||
DEBUG(MODULE_CONNECTION, "Userinfo splitter position: " + QSTRN(userInfoSp))
|
||||
|
@ -84,7 +84,7 @@ namespace Qv2ray::core::connection::Serialization
|
||||
|
||||
// decode base64
|
||||
const auto ssdURIBody = QStringRef(&uri, 6, uri.length() - 6);
|
||||
const auto decodedJSON = QByteArray::fromBase64(ssdURIBody.toUtf8());
|
||||
const auto decodedJSON = SafeBase64Decode(ssdURIBody.toString()).toUtf8();
|
||||
|
||||
if (decodedJSON.length() == 0)
|
||||
{
|
||||
|
@ -52,6 +52,11 @@ namespace Qv2ray::core::connection
|
||||
vmessUriRoot["host"] = transfer.httpSettings.host.join(",");
|
||||
vmessUriRoot["path"] = transfer.httpSettings.path;
|
||||
}
|
||||
|
||||
if(!vmessUriRoot.contains("type") || vmessUriRoot["type"].toString().isEmpty())
|
||||
{
|
||||
vmessUriRoot["type"] = "none";
|
||||
}
|
||||
|
||||
//
|
||||
auto vmessPart = Base64Encode(JsonToString(vmessUriRoot, QJsonDocument::JsonFormat::Compact));
|
||||
@ -88,7 +93,7 @@ namespace Qv2ray::core::connection
|
||||
return default;
|
||||
}
|
||||
|
||||
auto vmessString = Base64Decode(b64Str);
|
||||
auto vmessString = SafeBase64Decode(b64Str);
|
||||
auto jsonErr = VerifyJsonString(vmessString);
|
||||
|
||||
if (!jsonErr.isEmpty())
|
||||
@ -111,28 +116,10 @@ namespace Qv2ray::core::connection
|
||||
*errMessage = QObject::tr("seems like a v1 vmess, we don't support it");
|
||||
return default;
|
||||
}
|
||||
bool flag = true;
|
||||
// C is a quick hack...
|
||||
#define C(k) (flag = (vmessConf.contains(k) ? (errMessage->clear(), true) : (*errMessage += (k " does not exist"), false)))
|
||||
// id, aid, port and add are mandatory fields of a vmess://
|
||||
// link.
|
||||
flag = flag && C("id") && (C("aid") || C("alterId")) && C("port") && C("add");
|
||||
// Stream Settings
|
||||
auto net = vmessConf["net"].toString();
|
||||
|
||||
if (net == "http" || net == "ws")
|
||||
flag = flag && C("host") && C("path");
|
||||
else if (net == "domainsocket")
|
||||
flag = flag && C("path");
|
||||
else if (net == "quic")
|
||||
flag = flag && C("host") && C("type") && C("path");
|
||||
|
||||
#undef C
|
||||
// return flag ? 0 : 1;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
CONFIGROOT root;
|
||||
QString ps, add, id, /*net,*/ type, host, path, tls;
|
||||
QString ps, add, id, net, type, host, path, tls;
|
||||
int port, aid;
|
||||
//
|
||||
// __vmess_checker__func(key, values)
|
||||
@ -194,9 +181,10 @@ namespace Qv2ray::core::connection
|
||||
<< "domainsocket" //
|
||||
<< "quic"); //
|
||||
//
|
||||
__vmess_checker__func(path, << ""); //
|
||||
__vmess_checker__func(host, << ""); //
|
||||
__vmess_checker__func(tls, << ""); //
|
||||
__vmess_checker__func(tls, << "none" //
|
||||
<< "tls"); //
|
||||
path = vmessConf.contains("path") ? vmessConf["path"].toVariant().toString() : (net == "quic" ? "" : "/");
|
||||
host = vmessConf.contains("host") ? vmessConf["host"].toVariant().toString() : (net == "quic" ? "none" : "");
|
||||
}
|
||||
// Repect connection type rather than obfs type //
|
||||
if (QStringList{ "srtp", "utp", "wechat-video" }.contains(type)) //
|
||||
@ -250,7 +238,8 @@ namespace Qv2ray::core::connection
|
||||
}
|
||||
else if (net == "ws")
|
||||
{
|
||||
streaming.wsSettings.headers["Host"] = host;
|
||||
if (!host.isEmpty())
|
||||
streaming.wsSettings.headers["Host"] = host;
|
||||
streaming.wsSettings.path = path;
|
||||
}
|
||||
else if (net == "kcp")
|
||||
|
@ -9,7 +9,7 @@
|
||||
#endif
|
||||
|
||||
// Check 10 times before telling user that API has failed.
|
||||
constexpr auto QV2RAY_API_CALL_FAILEDCHECK_THRESHOLD = 10;
|
||||
constexpr auto QV2RAY_API_CALL_FAILEDCHECK_THRESHOLD = 30;
|
||||
|
||||
namespace Qv2ray::core::kernel
|
||||
{
|
||||
|
@ -6,6 +6,7 @@ namespace Qv2ray::core::kernel::abi
|
||||
{
|
||||
QvKernelABICompatibility checkCompatibility(QvKernelABIType hostType, QvKernelABIType targetType)
|
||||
{
|
||||
#ifndef QV2RAY_TRUSTED_ABI
|
||||
switch (hostType)
|
||||
{
|
||||
case ABI_WIN32:
|
||||
@ -15,12 +16,19 @@ namespace Qv2ray::core::kernel::abi
|
||||
case ABI_ELF_X86: return targetType == hostType ? ABI_PERFECT : ABI_NOPE;
|
||||
case ABI_ELF_X86_64: return targetType == hostType ? ABI_PERFECT : targetType == ABI_ELF_X86 ? ABI_MAYBE : ABI_NOPE;
|
||||
case ABI_ELF_OTHER: return targetType == hostType ? ABI_PERFECT : ABI_MAYBE;
|
||||
case ABI_TRUSTED: return ABI_PERFECT;
|
||||
default: return ABI_MAYBE;
|
||||
}
|
||||
#else
|
||||
return ABI_PERFECT;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::pair<std::optional<QvKernelABIType>, std::optional<QString>> deduceKernelABI(const QString &pathCoreExecutable)
|
||||
{
|
||||
#ifdef QV2RAY_TRUSTED_ABI
|
||||
return { QvKernelABIType::ABI_TRUSTED, std::nullopt };
|
||||
#else
|
||||
QFile file(pathCoreExecutable);
|
||||
if (!file.exists())
|
||||
return { std::nullopt, QObject::tr("core executable file %1 does not exist").arg(pathCoreExecutable) };
|
||||
@ -55,6 +63,7 @@ namespace Qv2ray::core::kernel::abi
|
||||
return { QvKernelABIType::ABI_MACH_O, std::nullopt };
|
||||
else
|
||||
return { std::nullopt, QObject::tr("cannot deduce the type of core executable file %1").arg(pathCoreExecutable) };
|
||||
#endif
|
||||
}
|
||||
|
||||
QString abiToString(QvKernelABIType abi)
|
||||
@ -68,6 +77,7 @@ namespace Qv2ray::core::kernel::abi
|
||||
case ABI_ELF_AARCH64: return QObject::tr("ELF arm64 executable");
|
||||
case ABI_ELF_ARM: return QObject::tr("ELF arm executable");
|
||||
case ABI_ELF_OTHER: return QObject::tr("other ELF executable");
|
||||
case ABI_TRUSTED: return QObject::tr("trusted abi");
|
||||
default: return QObject::tr("unknown abi");
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ namespace Qv2ray::core::kernel
|
||||
ABI_ELF_AARCH64,
|
||||
ABI_ELF_ARM,
|
||||
ABI_ELF_OTHER,
|
||||
ABI_TRUSTED,
|
||||
};
|
||||
|
||||
enum QvKernelABICompatibility
|
||||
@ -42,7 +43,8 @@ namespace Qv2ray::core::kernel
|
||||
#elif defined(Q_OS_LINUX) && defined(Q_PROCESSOR_ARM_V7)
|
||||
QvKernelABIType::ABI_ELF_ARM;
|
||||
#else
|
||||
#error "unknown architecture"
|
||||
QvKernelABIType::ABI_TRUSTED;
|
||||
#define QV2RAY_TRUSTED_ABI
|
||||
#endif
|
||||
|
||||
std::pair<std::optional<QvKernelABIType>, std::optional<QString>> deduceKernelABI(const QString &pathCoreExecutable);
|
||||
|
@ -196,6 +196,7 @@ int main(int argc, char *argv[])
|
||||
case CommandLineHelpRequested: std::cout << parser.Parser()->helpText().toStdString() << std::endl; return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
|
||||
// Unix OS root user check.
|
||||
@ -419,6 +420,7 @@ int main(int argc, char *argv[])
|
||||
// Initialise Connection Handler
|
||||
PluginHost = new QvPluginHost();
|
||||
ConnectionManager = new QvConfigHandler();
|
||||
|
||||
// Show MainWindow
|
||||
MainWindow w;
|
||||
QObject::connect(&_qApp, &SingleApplication::instanceStarted, [&]() {
|
||||
|
@ -122,8 +122,8 @@ void PluginManageWindow::on_openPluginFolder_clicked()
|
||||
{
|
||||
pluginPath.mkpath(QV2RAY_CONFIG_DIR + "plugins/");
|
||||
}
|
||||
#ifdef Q_OS_LINUX
|
||||
QProcess::execute("xdg-open", { "\"" + pluginPath.absolutePath() + "\"" });
|
||||
#ifdef FALL_BACK_TO_XDG_OPEN
|
||||
QProcess::execute("xdg-open", { pluginPath.absolutePath() });
|
||||
#else
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(pluginPath.absolutePath()));
|
||||
#endif
|
||||
|
@ -1153,7 +1153,15 @@ void PreferencesWindow::on_enableAPI_stateChanged(int arg1)
|
||||
{
|
||||
LOADINGCHECK
|
||||
NEEDRESTART
|
||||
CurrentConfig.kernelConfig.enableAPI = arg1 == Qt::Checked;
|
||||
|
||||
CurrentConfig.apiConfig.enableAPI = arg1 == Qt::Checked;
|
||||
if (arg1 == Qt::Unchecked)
|
||||
{
|
||||
const auto msgAPIDisableTitle = tr("Disabling API Subsystem");
|
||||
const auto msgAPIDisableMsg = tr("Disabling API subsystem will also disable the statistics function of Qv2ray.") + NEWLINE + //
|
||||
tr("Speed chart and traffic statistics will be disabled.");
|
||||
QvMessageBoxWarn(this, msgAPIDisableTitle, msgAPIDisableMsg);
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesWindow::on_updateChannelCombo_currentIndexChanged(int index)
|
||||
|
@ -33,7 +33,7 @@
|
||||
<item row="0" column="0">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>3</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tabWidgetPage1">
|
||||
<attribute name="title">
|
||||
@ -274,28 +274,28 @@
|
||||
<string>Network Settings</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_13">
|
||||
<item row="0" column="0">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_67">
|
||||
<property name="text">
|
||||
<string>User-Agent</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="qvNetworkUATxt">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_71">
|
||||
<property name="text">
|
||||
<string>Qv2ray Proxy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="2" column="1">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="qvProxyNoProxy">
|
||||
@ -320,14 +320,14 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_64">
|
||||
<property name="text">
|
||||
<string>Curtom Proxy</string>
|
||||
<string>Custom Proxy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="qvProxyTypeCombo">
|
||||
<item>
|
||||
<property name="text">
|
||||
@ -341,14 +341,7 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_66">
|
||||
<property name="text">
|
||||
<string>Curtom Proxy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="4" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="qvProxyAddressTxt"/>
|
||||
@ -375,6 +368,22 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_89">
|
||||
<property name="font">
|
||||
<font>
|
||||
<italic>true</italic>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>These settings are for Qv2ray itself.
|
||||
For example, for updating subscriptions.</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::PlainText</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@ -725,8 +734,8 @@ Custom DNS Settings</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>818</width>
|
||||
<height>558</height>
|
||||
<width>824</width>
|
||||
<height>516</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
|
@ -115,6 +115,13 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConnectionSettingsWidget</name>
|
||||
<message>
|
||||
<source>Form</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConnectionWidget</name>
|
||||
<message>
|
||||
@ -142,6 +149,45 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>GroupManager</name>
|
||||
<message>
|
||||
<source>Connection Management</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reload Subscription</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Would you like to reload the subscription?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deleting a subscription</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>All connections will be moved to default group, do you want to continue?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Export Connection(s)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Connection(s)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy to...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Move to...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImportConfigWindow</name>
|
||||
<message>
|
||||
@ -516,6 +562,13 @@
|
||||
<translation></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>InboundSettingsWidget</name>
|
||||
<message>
|
||||
<source>Form</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>JsonEditor</name>
|
||||
<message>
|
||||
@ -569,10 +622,6 @@
|
||||
<source>Qv2ray</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Add</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Preferences</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@ -851,6 +900,10 @@
|
||||
<source>Groups</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Add Connection</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OutboundEditor</name>
|
||||
@ -1628,10 +1681,6 @@ But could damage your server if improperly used.</source>
|
||||
<source>Custom Proxy</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Curtom Proxy</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network Options</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@ -1680,6 +1729,23 @@ But could damage your server if improperly used.</source>
|
||||
<source>tproxy inbound's sniffing is enabled by default.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>These settings are for Qv2ray itself.
|
||||
For example, for updating subscriptions.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disabling API Subsystem</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disabling API subsystem will also disable the statistics function of Qv2ray.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed chart and traffic statistics will be disabled.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QObject</name>
|
||||
@ -1903,14 +1969,6 @@ But could damage your server if improperly used.</source>
|
||||
<source>Invalid ssd link: rc4-md5 encryption is not supported by v2ray-core</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Not connected</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connected</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Text</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@ -2063,6 +2121,26 @@ But could damage your server if improperly used.</source>
|
||||
<source>Unknown</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deepin Detected</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deepin plays smart and sets you the wrong HTTPS_PROXY, FTP_PROXY environment variable.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The origin scheme http is wrongly replaced by https and ftp, causing the problem.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Qv2ray cannot help you change them back. Please don't blame us if things go wrong.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>trusted abi</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Qv2ray::common::QvCommandArgParser</name>
|
||||
@ -2871,25 +2949,6 @@ Maybe you have downloaded the wrong core?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SubscriptionEditor</name>
|
||||
<message>
|
||||
<source>Reload Subscription</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Would you like to reload the subscription?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deleting a subscription</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>All connections will be moved to default group, do you want to continue?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>misc</name>
|
||||
<message>
|
||||
@ -2951,10 +3010,6 @@ Maybe you have downloaded the wrong core?</source>
|
||||
<source>Remove Subscription</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group Details</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group Name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@ -2976,11 +3031,43 @@ Maybe you have downloaded the wrong core?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connection List</source>
|
||||
<source>Update Subscription Data</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update Subscription Data</source>
|
||||
<source>Group Info</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Created At</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connections</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Selection</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Export Selection</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Subscription Settings</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This group is a subscription</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connection Settings</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Route Settings</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
|
@ -150,6 +150,13 @@
|
||||
<translation>つ</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConnectionSettingsWidget</name>
|
||||
<message>
|
||||
<source>Form</source>
|
||||
<translation>Form</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConnectionWidget</name>
|
||||
<message>
|
||||
@ -219,6 +226,45 @@
|
||||
<translation type="vanished">フローシーンファイル (*.flow)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>GroupManager</name>
|
||||
<message>
|
||||
<source>Connection Management</source>
|
||||
<translation>項目管理</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reload Subscription</source>
|
||||
<translation>サブスクリプションを更新</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Would you like to reload the subscription?</source>
|
||||
<translation>サブスクリプションを更新しますか?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deleting a subscription</source>
|
||||
<translation>サブスクリプションを削除する</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>All connections will be moved to default group, do you want to continue?</source>
|
||||
<translation>すべての項目がデフォルトグループに移動します。続行しますか?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Export Connection(s)</source>
|
||||
<translation>項目をエクスポート</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Connection(s)</source>
|
||||
<translation>項目を削除</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy to...</source>
|
||||
<translation>コピーして...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Move to...</source>
|
||||
<translation>移動して...</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImportConfigWindow</name>
|
||||
<message>
|
||||
@ -645,6 +691,13 @@
|
||||
<translation>このユーザーは既に存在します.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>InboundSettingsWidget</name>
|
||||
<message>
|
||||
<source>Form</source>
|
||||
<translation>Form</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>JsonEditor</name>
|
||||
<message>
|
||||
@ -792,7 +845,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Add</source>
|
||||
<translation>追加</translation>
|
||||
<translation type="vanished">追加</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Preferences</source>
|
||||
@ -1314,6 +1367,10 @@
|
||||
<source>Groups</source>
|
||||
<translation>グループ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Add Connection</source>
|
||||
<translation>項目を作成</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OutboundEditor</name>
|
||||
@ -2337,7 +2394,7 @@ But could damage your server if improperly used.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Curtom Proxy</source>
|
||||
<translation>カスタムプロキシ</translation>
|
||||
<translation type="vanished">カスタムプロキシ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network Options</source>
|
||||
@ -2387,6 +2444,24 @@ But could damage your server if improperly used.</source>
|
||||
<source>tproxy inbound's sniffing is enabled by default.</source>
|
||||
<translation>tProxyインバウンドのスニッフィングはデフォルトで有効になっています。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>These settings are for Qv2ray itself.
|
||||
For example, for updating subscriptions.</source>
|
||||
<translation>これらの設定はQv2ray自体のためのものです。
|
||||
例えば、サブスクリプションの更新などです。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disabling API Subsystem</source>
|
||||
<translation>APIサブシステムを無効</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disabling API subsystem will also disable the statistics function of Qv2ray.</source>
|
||||
<translation>APIサブシステムを無効にすると、Qv2rayの統計機能も無効になります。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed chart and traffic statistics will be disabled.</source>
|
||||
<translation>スピードチャートや交通統計は無効になります。</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QObject</name>
|
||||
@ -2536,11 +2611,11 @@ But could damage your server if improperly used.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Not connected</source>
|
||||
<translation>接続されていません</translation>
|
||||
<translation type="vanished">接続されていません</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connected</source>
|
||||
<translation>接続済み</translation>
|
||||
<translation type="vanished">接続済み</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disconnected</source>
|
||||
@ -2850,6 +2925,38 @@ But could damage your server if improperly used.</source>
|
||||
<source>Unknown</source>
|
||||
<translation>不明</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deepin Detected</source>
|
||||
<translation>Deepin検出</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deepin plays smart and sets you the wrong HTTPS_PROXY environment variable. </source>
|
||||
<translation type="vanished">Deepinのバカ、間違ったHTTPS_PROXY環境変数を設定します。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The original scheme should be http://, but he will replace with https://, causing the problem. </source>
|
||||
<translation type="vanished">本来のスキームは http:// であるべきなのですが、彼は https:// に置き換えて問題を引き起こします。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Qv2ray will help you change it back and make things work again. </source>
|
||||
<translation type="vanished">Qv2rayはそれを元に戻して、またうまくいくようにしてくれます。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deepin plays smart and sets you the wrong HTTPS_PROXY, FTP_PROXY environment variable.</source>
|
||||
<translation>Deepinのバカ、間違ったHTTPS_PROXYとFTP_PROXYの環境変数を設定します。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The origin scheme http is wrongly replaced by https and ftp, causing the problem.</source>
|
||||
<translation>元のスキームのhttpがhttpsとftpに間違って置き換えられてしまい、問題が発生しています。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Qv2ray cannot help you change them back. Please don't blame us if things go wrong.</source>
|
||||
<translation>Qv2rayでは元に戻すことはできません。何かあっても私たちのせいにしないでください。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>trusted abi</source>
|
||||
<translation>信頼できるABI</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Qv2ray::common::QvCommandArgParser</name>
|
||||
@ -3775,19 +3882,19 @@ Maybe you have downloaded the wrong core?</source>
|
||||
<name>SubscriptionEditor</name>
|
||||
<message>
|
||||
<source>Reload Subscription</source>
|
||||
<translation>サブスクリプションを更新</translation>
|
||||
<translation type="vanished">サブスクリプションを更新</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Would you like to reload the subscription?</source>
|
||||
<translation>サブスクリプションを更新しますか?</translation>
|
||||
<translation type="vanished">サブスクリプションを更新しますか?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deleting a subscription</source>
|
||||
<translation>サブスクリプションを削除する</translation>
|
||||
<translation type="vanished">サブスクリプションを削除する</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>All connections will be moved to default group, do you want to continue?</source>
|
||||
<translation>すべての項目がデフォルトグループに移動します。続行しますか?</translation>
|
||||
<translation type="vanished">すべての項目がデフォルトグループに移動します。続行しますか?</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -3853,7 +3960,7 @@ Maybe you have downloaded the wrong core?</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group Details</source>
|
||||
<translation>詳細</translation>
|
||||
<translation type="vanished">詳細</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group Name</source>
|
||||
@ -3877,12 +3984,48 @@ Maybe you have downloaded the wrong core?</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connection List</source>
|
||||
<translation>項目リスト</translation>
|
||||
<translation type="vanished">項目リスト</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update Subscription Data</source>
|
||||
<translation>サブスクリプションデータの更新</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group Info</source>
|
||||
<translation>グループ情報</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Created At</source>
|
||||
<translation>作成日</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connections</source>
|
||||
<translation>項目</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Selection</source>
|
||||
<translation>選択したものを削除</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Export Selection</source>
|
||||
<translation>選択したものをエクスポート</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Subscription Settings</source>
|
||||
<translation>サブスクリプション設定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This group is a subscription</source>
|
||||
<translation>このグループはサブスクリプションです</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connection Settings</source>
|
||||
<translation>接続設定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Route Settings</source>
|
||||
<translation>ルート設定</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>w_PluginManager</name>
|
||||
|
@ -134,6 +134,13 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConnectionSettingsWidget</name>
|
||||
<message>
|
||||
<source>Form</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConnectionWidget</name>
|
||||
<message>
|
||||
@ -203,6 +210,45 @@
|
||||
<translation type="vanished">Файл сцены потока (*.flow)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>GroupManager</name>
|
||||
<message>
|
||||
<source>Connection Management</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reload Subscription</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Would you like to reload the subscription?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deleting a subscription</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>All connections will be moved to default group, do you want to continue?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Export Connection(s)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Connection(s)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy to...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Move to...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImportConfigWindow</name>
|
||||
<message>
|
||||
@ -629,6 +675,13 @@
|
||||
<translation>Этот пользователь уже существует.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>InboundSettingsWidget</name>
|
||||
<message>
|
||||
<source>Form</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>JsonEditor</name>
|
||||
<message>
|
||||
@ -776,7 +829,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Add</source>
|
||||
<translation>Добавить</translation>
|
||||
<translation type="vanished">Добавить</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Preferences</source>
|
||||
@ -1294,6 +1347,10 @@
|
||||
<source>Groups</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Add Connection</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OutboundEditor</name>
|
||||
@ -2239,10 +2296,6 @@ But could damage your server if improperly used.</source>
|
||||
<source>Custom Proxy</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Curtom Proxy</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network Options</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@ -2291,6 +2344,23 @@ But could damage your server if improperly used.</source>
|
||||
<source>tproxy inbound's sniffing is enabled by default.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>These settings are for Qv2ray itself.
|
||||
For example, for updating subscriptions.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disabling API Subsystem</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disabling API subsystem will also disable the statistics function of Qv2ray.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed chart and traffic statistics will be disabled.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QObject</name>
|
||||
@ -2438,13 +2508,9 @@ But could damage your server if improperly used.</source>
|
||||
<source>Technical Details</source>
|
||||
<translation>Технические детали</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Not connected</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connected</source>
|
||||
<translation>Подключено</translation>
|
||||
<translation type="vanished">Подключено</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disconnected</source>
|
||||
@ -2742,6 +2808,26 @@ But could damage your server if improperly used.</source>
|
||||
<source>Unknown</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deepin Detected</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deepin plays smart and sets you the wrong HTTPS_PROXY, FTP_PROXY environment variable.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The origin scheme http is wrongly replaced by https and ftp, causing the problem.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Qv2ray cannot help you change them back. Please don't blame us if things go wrong.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>trusted abi</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Qv2ray::common::QvCommandArgParser</name>
|
||||
@ -3612,25 +3698,6 @@ Maybe you have downloaded the wrong core?</source>
|
||||
<translation type="vanished">Не удалось обработать результат из апстрима, проверьте ваш URL.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SubscriptionEditor</name>
|
||||
<message>
|
||||
<source>Reload Subscription</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Would you like to reload the subscription?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deleting a subscription</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>All connections will be moved to default group, do you want to continue?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>misc</name>
|
||||
<message>
|
||||
@ -3692,10 +3759,6 @@ Maybe you have downloaded the wrong core?</source>
|
||||
<source>Remove Subscription</source>
|
||||
<translation type="unfinished">Удалить подписку</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group Details</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group Name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@ -3718,12 +3781,48 @@ Maybe you have downloaded the wrong core?</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connection List</source>
|
||||
<translation type="unfinished">Список подключений</translation>
|
||||
<translation type="obsolete">Список подключений</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update Subscription Data</source>
|
||||
<translation type="unfinished">Обновить данные подписки</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group Info</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Created At</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connections</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Selection</source>
|
||||
<translation type="unfinished">Удалить выделение</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Export Selection</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Subscription Settings</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This group is a subscription</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connection Settings</source>
|
||||
<translation type="unfinished">Настройки соединения</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Route Settings</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>w_PluginManager</name>
|
||||
|
@ -122,6 +122,13 @@
|
||||
<translation>个</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConnectionSettingsWidget</name>
|
||||
<message>
|
||||
<source>Form</source>
|
||||
<translation>窗体</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ConnectionWidget</name>
|
||||
<message>
|
||||
@ -149,6 +156,45 @@
|
||||
<translation>好</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>GroupManager</name>
|
||||
<message>
|
||||
<source>Connection Management</source>
|
||||
<translation>连接管理</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reload Subscription</source>
|
||||
<translation>更新订阅</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Would you like to reload the subscription?</source>
|
||||
<translation>您要更新此订阅吗?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deleting a subscription</source>
|
||||
<translation>删除订阅</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>All connections will be moved to default group, do you want to continue?</source>
|
||||
<translation>本订阅中的所有连接都将移动到默认分组,您确定要继续吗?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Export Connection(s)</source>
|
||||
<translation>导出连接</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Connection(s)</source>
|
||||
<translation>删除连接</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy to...</source>
|
||||
<translation>复制到...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Move to...</source>
|
||||
<translation>移动到...</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImportConfigWindow</name>
|
||||
<message>
|
||||
@ -555,6 +601,13 @@
|
||||
<translation>此用户已存在。</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>InboundSettingsWidget</name>
|
||||
<message>
|
||||
<source>Form</source>
|
||||
<translation>窗体</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>JsonEditor</name>
|
||||
<message>
|
||||
@ -618,7 +671,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Add</source>
|
||||
<translation>添加</translation>
|
||||
<translation type="vanished">添加</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Preferences</source>
|
||||
@ -952,6 +1005,10 @@
|
||||
<source>Groups</source>
|
||||
<translation>分组</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Add Connection</source>
|
||||
<translation>添加连接</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OutboundEditor</name>
|
||||
@ -1967,7 +2024,7 @@ But could damage your server if improperly used.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Curtom Proxy</source>
|
||||
<translation>自定义代理</translation>
|
||||
<translation type="vanished">自定义代理</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network Options</source>
|
||||
@ -2017,6 +2074,24 @@ But could damage your server if improperly used.</source>
|
||||
<source>tproxy inbound's sniffing is enabled by default.</source>
|
||||
<translation>tProxy 入站的嗅探选项默认开启。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>These settings are for Qv2ray itself.
|
||||
For example, for updating subscriptions.</source>
|
||||
<translation>这些设定是针对 Qv2ray 本身的。
|
||||
例如,用在更新订阅时。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disabling API Subsystem</source>
|
||||
<translation>禁用 API 子系统</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disabling API subsystem will also disable the statistics function of Qv2ray.</source>
|
||||
<translation>如果禁用 API 子系统,Qv2ray 的统计功能也会被一同禁用。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed chart and traffic statistics will be disabled.</source>
|
||||
<translation>速度图表和流量统计功能将不再可用。</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QObject</name>
|
||||
@ -2270,11 +2345,11 @@ But could damage your server if improperly used.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Not connected</source>
|
||||
<translation>未连接</translation>
|
||||
<translation type="vanished">未连接</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connected</source>
|
||||
<translation>已连接</translation>
|
||||
<translation type="vanished">已连接</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Text</source>
|
||||
@ -2428,6 +2503,38 @@ But could damage your server if improperly used.</source>
|
||||
<source>Unknown</source>
|
||||
<translation>未知</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deepin Detected</source>
|
||||
<translation>检测到 Deepin</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deepin plays smart and sets you the wrong HTTPS_PROXY environment variable. </source>
|
||||
<translation type="vanished">默认情况下,Deepin 自作聪明,会给你设置错误的 HTTPS_PROXY 环境变量。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The original scheme should be http://, but he will replace with https://, causing the problem. </source>
|
||||
<translation type="vanished">原 scheme 应为 http://,但 Deepin 将其替换成了 https://,导致 HTTPS 代理无法正常使用。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Qv2ray will help you change it back and make things work again. </source>
|
||||
<translation type="vanished">Qv2ray 会尝试帮你改回去,以期解决此问题。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deepin plays smart and sets you the wrong HTTPS_PROXY, FTP_PROXY environment variable.</source>
|
||||
<translation>Deepin可能自作聪明,为你设置了错误的 HTTPS_PROXY 和 FTP_PROXY 环境变量。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The origin scheme http is wrongly replaced by https and ftp, causing the problem.</source>
|
||||
<translation>原来正确的 http:// 可能被错误地替换为 https:// 和 ftp://,导致这个问题。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Qv2ray cannot help you change them back. Please don't blame us if things go wrong.</source>
|
||||
<translation>Qv2ray 很遗憾无法帮你改回来。若因此遇到问题,请勿指责吾等。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>trusted abi</source>
|
||||
<translation>受信 ABI</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Qv2ray::common::QvCommandArgParser</name>
|
||||
@ -3317,19 +3424,19 @@ Maybe you have downloaded the wrong core?</source>
|
||||
<name>SubscriptionEditor</name>
|
||||
<message>
|
||||
<source>Reload Subscription</source>
|
||||
<translation>更新订阅</translation>
|
||||
<translation type="vanished">更新订阅</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Would you like to reload the subscription?</source>
|
||||
<translation>您要更新此订阅吗?</translation>
|
||||
<translation type="vanished">您要更新此订阅吗?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Deleting a subscription</source>
|
||||
<translation>删除订阅</translation>
|
||||
<translation type="vanished">删除订阅</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>All connections will be moved to default group, do you want to continue?</source>
|
||||
<translation>本订阅中的所有连接都将移动到默认分组,您确定要继续吗?</translation>
|
||||
<translation type="vanished">本订阅中的所有连接都将移动到默认分组,您确定要继续吗?</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -3395,7 +3502,7 @@ Maybe you have downloaded the wrong core?</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group Details</source>
|
||||
<translation>分组细节</translation>
|
||||
<translation type="vanished">分组细节</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group Name</source>
|
||||
@ -3419,12 +3526,48 @@ Maybe you have downloaded the wrong core?</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connection List</source>
|
||||
<translation>连接列表</translation>
|
||||
<translation type="vanished">连接列表</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update Subscription Data</source>
|
||||
<translation>更新订阅数据</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group Info</source>
|
||||
<translation>分组信息</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Created At</source>
|
||||
<translation>创建于</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connections</source>
|
||||
<translation>连接</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Selection</source>
|
||||
<translation>删除所选项</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Export Selection</source>
|
||||
<translation>导出所选项</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Subscription Settings</source>
|
||||
<translation>订阅设置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This group is a subscription</source>
|
||||
<translation>此分组是是一个订阅</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connection Settings</source>
|
||||
<translation>连接设置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Route Settings</source>
|
||||
<translation>路由设定</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>w_PluginManager</name>
|
||||
|
Loading…
Reference in New Issue
Block a user