From 900d1ddb36da9464d747b7c1999b2273bde3b52f Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 27 Apr 2018 21:26:45 +0400 Subject: [PATCH] Support multiple proxies in local storage. --- Telegram/SourceFiles/application.cpp | 6 +- Telegram/SourceFiles/boxes/connection_box.cpp | 106 +++++++--------- Telegram/SourceFiles/boxes/connection_box.h | 13 +- Telegram/SourceFiles/core/utils.cpp | 28 +++++ Telegram/SourceFiles/core/utils.h | 12 +- Telegram/SourceFiles/facades.cpp | 10 +- Telegram/SourceFiles/facades.h | 5 +- Telegram/SourceFiles/mainwindow.cpp | 5 +- .../SourceFiles/mtproto/config_loader.cpp | 4 +- Telegram/SourceFiles/mtproto/session.cpp | 17 ++- .../settings/settings_advanced_widget.cpp | 26 ++-- Telegram/SourceFiles/storage/localstorage.cpp | 119 +++++++++++++----- 12 files changed, 205 insertions(+), 146 deletions(-) diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index 438911a8f..0b70496b8 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -313,9 +313,9 @@ void Application::refreshGlobalProxy() { #ifndef TDESKTOP_DISABLE_NETWORK_PROXY const auto proxy = [&] { if (Global::started()) { - return Global::ConnectionType() == dbictAuto - ? ProxyData() - : Global::ConnectionProxy(); + return Global::UseProxy() + ? Global::SelectedProxy() + : ProxyData(); } return Sandbox::PreLaunchProxy(); }(); diff --git a/Telegram/SourceFiles/boxes/connection_box.cpp b/Telegram/SourceFiles/boxes/connection_box.cpp index 360e0b455..d8e1dd061 100644 --- a/Telegram/SourceFiles/boxes/connection_box.cpp +++ b/Telegram/SourceFiles/boxes/connection_box.cpp @@ -28,14 +28,17 @@ void ConnectionBox::ShowApplyProxyConfirmation( const QMap &fields) { const auto server = fields.value(qsl("server")); const auto port = fields.value(qsl("port")).toUInt(); - const auto secret = fields.value(qsl("secret")); - const auto valid = !server.isEmpty() - && (port != 0) - && (type != ProxyData::Type::Mtproto - || ProxyData::ValidSecret(secret)) - && (type == ProxyData::Type::Socks5 - || type == ProxyData::Type::Mtproto); - if (valid) { + auto proxy = ProxyData(); + proxy.type = type; + proxy.host = server; + proxy.port = port; + if (type == ProxyData::Type::Socks5) { + proxy.user = fields.value(qsl("user")); + proxy.password = fields.value(qsl("pass")); + } else if (type == ProxyData::Type::Mtproto) { + proxy.password = fields.value(qsl("secret")); + } + if (proxy) { const auto box = std::make_shared>(); const auto text = lng_sure_enable_socks( lt_server, @@ -43,18 +46,12 @@ void ConnectionBox::ShowApplyProxyConfirmation( lt_port, QString::number(port)); *box = Ui::show(Box(text, lang(lng_sure_enable), [=] { - auto proxy = ProxyData(); - proxy.type = type; - proxy.host = server; - proxy.port = port; - if (type == ProxyData::Type::Socks5) { - proxy.user = fields.value(qsl("user")); - proxy.password = fields.value(qsl("pass")); - } else if (type == ProxyData::Type::Mtproto) { - proxy.password = secret; + auto &proxies = Global::RefProxiesList(); + if (ranges::find(proxies, proxy) == end(proxies)) { + proxies.insert(begin(proxies), proxy); } - Global::SetConnectionType(dbictTcpProxy); - Global::SetConnectionProxy(proxy); + Global::SetSelectedProxy(proxy); + Global::SetUseProxy(true); Local::writeSettings(); Sandbox::refreshGlobalProxy(); Global::RefConnectionTypeChanged().notify(); @@ -67,15 +64,14 @@ void ConnectionBox::ShowApplyProxyConfirmation( } ConnectionBox::ConnectionBox(QWidget *parent) -: _hostInput(this, st::connectionHostInputField, langFactory(lng_connection_host_ph), Global::ConnectionProxy().host) -, _portInput(this, st::connectionPortInputField, langFactory(lng_connection_port_ph), QString::number(Global::ConnectionProxy().port)) -, _userInput(this, st::connectionUserInputField, langFactory(lng_connection_user_ph), Global::ConnectionProxy().user) -, _passwordInput(this, st::connectionPasswordInputField, langFactory(lng_connection_password_ph), Global::ConnectionProxy().password) -, _currentProxyType(Global::ConnectionProxy().type) -, _typeGroup(std::make_shared>(Global::ConnectionType())) -, _autoRadio(this, _typeGroup, dbictAuto, lang(lng_connection_auto_rb), st::defaultBoxCheckbox) -, _httpProxyRadio(this, _typeGroup, dbictHttpProxy, lang(lng_connection_http_proxy_rb), st::defaultBoxCheckbox) -, _tcpProxyRadio(this, _typeGroup, dbictTcpProxy, lang(lng_connection_tcp_proxy_rb), st::defaultBoxCheckbox) +: _hostInput(this, st::connectionHostInputField, langFactory(lng_connection_host_ph), Global::SelectedProxy().host) +, _portInput(this, st::connectionPortInputField, langFactory(lng_connection_port_ph), QString::number(Global::SelectedProxy().port)) +, _userInput(this, st::connectionUserInputField, langFactory(lng_connection_user_ph), Global::SelectedProxy().user) +, _passwordInput(this, st::connectionPasswordInputField, langFactory(lng_connection_password_ph), Global::SelectedProxy().password) +, _typeGroup(std::make_shared>(Global::SelectedProxy().type)) +, _autoRadio(this, _typeGroup, Type::None, lang(lng_connection_auto_rb), st::defaultBoxCheckbox) +, _httpProxyRadio(this, _typeGroup, Type::Http, lang(lng_connection_http_proxy_rb), st::defaultBoxCheckbox) +, _tcpProxyRadio(this, _typeGroup, Type::Socks5, lang(lng_connection_tcp_proxy_rb), st::defaultBoxCheckbox) , _tryIPv6(this, lang(lng_connection_try_ipv6), Global::TryIPv6(), st::defaultBoxCheckbox) { } @@ -85,7 +81,7 @@ void ConnectionBox::prepare() { addButton(langFactory(lng_connection_save), [this] { onSave(); }); addButton(langFactory(lng_cancel), [this] { closeBox(); }); - _typeGroup->setChangedCallback([this](DBIConnectionType value) { typeChanged(value); }); + _typeGroup->setChangedCallback([this](Type value) { typeChanged(value); }); connect(_hostInput, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); connect(_portInput, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); @@ -123,17 +119,15 @@ void ConnectionBox::updateControlsVisibility() { } bool ConnectionBox::proxyFieldsVisible() const { - return (_typeGroup->value() != dbictAuto) - || (!badProxyValue() - && (_currentProxyType == ProxyData::Type::Http - || _currentProxyType == ProxyData::Type::Socks5)); + return (_typeGroup->value() == ProxyData::Type::Http + || _typeGroup->value() == ProxyData::Type::Socks5); } void ConnectionBox::setInnerFocus() { - if (_typeGroup->value() == dbictAuto) { - setFocus(); - } else { + if (proxyFieldsVisible()) { _hostInput->setFocusFast(); + } else { + setFocus(); } } @@ -150,8 +144,8 @@ void ConnectionBox::updateControlsPosition() { auto inputy = 0; auto fieldsVisible = proxyFieldsVisible(); - auto fieldsBelowHttp = fieldsVisible && (type == dbictHttpProxy || (type == dbictAuto && _currentProxyType == ProxyData::Type::Http)); - auto fieldsBelowTcp = fieldsVisible && (type == dbictTcpProxy || (type == dbictAuto && _currentProxyType == ProxyData::Type::Socks5)); + auto fieldsBelowHttp = fieldsVisible && (type == ProxyData::Type::Http); + auto fieldsBelowTcp = fieldsVisible && (type == ProxyData::Type::Socks5); if (fieldsBelowHttp) { inputy = _httpProxyRadio->bottomNoMargins() + st::boxOptionInputSkip; _tcpProxyRadio->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), inputy + st::boxOptionInputSkip + 2 * _hostInput->height() + st::boxOptionListSkip); @@ -173,21 +167,16 @@ void ConnectionBox::updateControlsPosition() { _tryIPv6->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), tryipv6y); } -void ConnectionBox::typeChanged(DBIConnectionType type) { - if (type == dbictAuto) { +void ConnectionBox::typeChanged(Type type) { + if (!proxyFieldsVisible()) { setFocus(); } updateControlsVisibility(); - if (type != dbictAuto) { - _currentProxyType = (type == dbictTcpProxy) - ? ProxyData::Type::Socks5 - : (type == dbictHttpProxy) - ? ProxyData::Type::Http - : ProxyData::Type::None; + if (proxyFieldsVisible()) { if (!_hostInput->hasFocus() && !_portInput->hasFocus() && !_userInput->hasFocus() && !_passwordInput->hasFocus()) { _hostInput->setFocusFast(); } - if ((type == dbictHttpProxy) && !_portInput->getLastText().toInt()) { + if ((type == Type::Http) && !_portInput->getLastText().toInt()) { _portInput->setText(qsl("80")); _portInput->finishAnimating(); } @@ -196,11 +185,6 @@ void ConnectionBox::typeChanged(DBIConnectionType type) { } void ConnectionBox::onFieldFocus() { - if (_currentProxyType == ProxyData::Type::Http) { - _typeGroup->setValue(dbictHttpProxy); - } else if (_currentProxyType == ProxyData::Type::Socks5) { - _typeGroup->setValue(dbictTcpProxy); - } } void ConnectionBox::onSubmit() { @@ -240,12 +224,10 @@ void ConnectionBox::onSave() { proxy.port = _portInput->getLastText().toUInt(); auto type = _typeGroup->value(); - if (type == dbictAuto) { - if (proxy.host.isEmpty() || !proxy.port) { - proxy = ProxyData(); - } else { - proxy.type = _currentProxyType; - } + if (type == Type::None) { + proxy = ProxyData(); + } else if (type == Type::Mtproto) { + proxy = Global::SelectedProxy(); } else { if (proxy.host.isEmpty()) { _hostInput->showError(); @@ -254,12 +236,10 @@ void ConnectionBox::onSave() { _portInput->showError(); return; } - proxy.type = (type == dbictTcpProxy) - ? ProxyData::Type::Socks5 - : ProxyData::Type::Http; + proxy.type = type; } - Global::SetConnectionType(type); - Global::SetConnectionProxy(proxy); + Global::SetSelectedProxy(proxy ? proxy : ProxyData()); + Global::SetUseProxy(proxy ? true : false); if (cPlatform() == dbipWindows && Global::TryIPv6() != _tryIPv6->checked()) { Global::SetTryIPv6(_tryIPv6->checked()); Local::writeSettings(); diff --git a/Telegram/SourceFiles/boxes/connection_box.h b/Telegram/SourceFiles/boxes/connection_box.h index 9c638d5e3..7e08955ad 100644 --- a/Telegram/SourceFiles/boxes/connection_box.h +++ b/Telegram/SourceFiles/boxes/connection_box.h @@ -42,7 +42,9 @@ private slots: void onSave(); private: - void typeChanged(DBIConnectionType type); + using Type = ProxyData::Type; + + void typeChanged(Type type); void updateControlsVisibility(); void updateControlsPosition(); bool badProxyValue() const; @@ -52,11 +54,10 @@ private: object_ptr _portInput; object_ptr _userInput; object_ptr _passwordInput; - ProxyData::Type _currentProxyType; - std::shared_ptr> _typeGroup; - object_ptr> _autoRadio; - object_ptr> _httpProxyRadio; - object_ptr> _tcpProxyRadio; + std::shared_ptr> _typeGroup; + object_ptr> _autoRadio; + object_ptr> _httpProxyRadio; + object_ptr> _tcpProxyRadio; object_ptr _tryIPv6; }; diff --git a/Telegram/SourceFiles/core/utils.cpp b/Telegram/SourceFiles/core/utils.cpp index e40da4724..5dc40b3e5 100644 --- a/Telegram/SourceFiles/core/utils.cpp +++ b/Telegram/SourceFiles/core/utils.cpp @@ -236,6 +236,34 @@ namespace { _MsStarter _msStarter; } +bool ProxyData::valid() const { + if (type == Type::None || host.isEmpty() || !port) { + return false; + } else if (type == Type::Mtproto && !ValidSecret(password)) { + return false; + } + return true; +} + +ProxyData::operator bool() const { + return valid(); +} + +bool ProxyData::operator==(const ProxyData &other) const { + if (!valid()) { + return !other.valid(); + } + return (type == other.type) + && (host == other.host) + && (port == other.port) + && (user == other.user) + && (password == other.password); +} + +bool ProxyData::operator!=(const ProxyData &other) const { + return !(*this == other); +} + bool ProxyData::ValidSecret(const QString &secret) { return QRegularExpression("^[a-fA-F0-9]{32}$").match(secret).hasMatch(); } diff --git a/Telegram/SourceFiles/core/utils.h b/Telegram/SourceFiles/core/utils.h index 0f25b24ac..fdc9959c8 100644 --- a/Telegram/SourceFiles/core/utils.h +++ b/Telegram/SourceFiles/core/utils.h @@ -420,13 +420,6 @@ enum DBIWorkMode { dbiwmWindowOnly = 2, }; -enum DBIConnectionType { - dbictAuto = 0, - dbictHttpAuto = 1, // not used - dbictHttpProxy = 2, - dbictTcpProxy = 3, -}; - struct ProxyData { enum class Type { None, @@ -440,6 +433,11 @@ struct ProxyData { uint32 port = 0; QString user, password; + bool valid() const; + explicit operator bool() const; + bool operator==(const ProxyData &other) const; + bool operator!=(const ProxyData &other) const; + static bool ValidSecret(const QString &secret); }; diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 1f9413b92..acde25cd9 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -563,9 +563,10 @@ struct Data { Notify::ScreenCorner NotificationsCorner = Notify::ScreenCorner::BottomRight; bool NotificationsDemoIsShown = false; - DBIConnectionType ConnectionType = dbictAuto; bool TryIPv6 = (cPlatform() == dbipWindows) ? false : true; - ProxyData ConnectionProxy; + std::vector ProxiesList; + ProxyData SelectedProxy; + bool UseProxy = false; base::Observable ConnectionTypeChanged; int AutoLock = 3600; @@ -685,9 +686,10 @@ DefineVar(Global, int, NotificationsCount); DefineVar(Global, Notify::ScreenCorner, NotificationsCorner); DefineVar(Global, bool, NotificationsDemoIsShown); -DefineVar(Global, DBIConnectionType, ConnectionType); DefineVar(Global, bool, TryIPv6); -DefineVar(Global, ProxyData, ConnectionProxy); +DefineVar(Global, std::vector, ProxiesList); +DefineVar(Global, ProxyData, SelectedProxy); +DefineVar(Global, bool, UseProxy); DefineRefVar(Global, base::Observable, ConnectionTypeChanged); DefineVar(Global, int, AutoLock); diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index 743f61856..697c47d8b 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -371,9 +371,10 @@ DeclareVar(int, NotificationsCount); DeclareVar(Notify::ScreenCorner, NotificationsCorner); DeclareVar(bool, NotificationsDemoIsShown); -DeclareVar(DBIConnectionType, ConnectionType); +DeclareVar(std::vector, ProxiesList); +DeclareVar(ProxyData, SelectedProxy); +DeclareVar(bool, UseProxy); DeclareVar(bool, TryIPv6); -DeclareVar(ProxyData, ConnectionProxy); DeclareRefVar(base::Observable, ConnectionTypeChanged); DeclareVar(int, AutoLock); diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 69934b193..775d292c4 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -99,8 +99,7 @@ void ConnectingWidget::paintEvent(QPaintEvent *e) { } void ConnectingWidget::onReconnect() { - auto throughProxy = (Global::ConnectionType() != dbictAuto); - if (throughProxy) { + if (Global::UseProxy()) { Ui::show(Box()); } else { MTP::restart(); @@ -409,7 +408,7 @@ void MainWindow::mtpStateChanged(int32 dc, int32 state) { void MainWindow::updateConnectingStatus() { auto state = MTP::dcstate(); - auto throughProxy = (Global::ConnectionType() != dbictAuto); + const auto throughProxy = Global::UseProxy(); if (state == MTP::ConnectingState || state == MTP::DisconnectedState || (state < 0 && state > -600)) { if (_main || getms() > 5000 || _connecting) { showConnecting(lang(throughProxy ? lng_connecting_to_proxy : lng_connecting), throughProxy ? lang(lng_connecting_settings) : QString()); diff --git a/Telegram/SourceFiles/mtproto/config_loader.cpp b/Telegram/SourceFiles/mtproto/config_loader.cpp index 4305ccd99..0eb3742ed 100644 --- a/Telegram/SourceFiles/mtproto/config_loader.cpp +++ b/Telegram/SourceFiles/mtproto/config_loader.cpp @@ -100,7 +100,7 @@ void ConfigLoader::enumerate() { } void ConfigLoader::createSpecialLoader() { - if (Global::ConnectionProxy().type != ProxyData::Type::None) { + if (Global::UseProxy()) { _specialLoader.reset(); return; } @@ -128,7 +128,7 @@ void ConfigLoader::addSpecialEndpoint(DcId dcId, const std::string &ip, int port void ConfigLoader::sendSpecialRequest() { terminateSpecialRequest(); - if (Global::ConnectionType() != dbictAuto) { + if (Global::UseProxy()) { _specialLoader.reset(); return; } diff --git a/Telegram/SourceFiles/mtproto/session.cpp b/Telegram/SourceFiles/mtproto/session.cpp index 4bf9cf25d..1513eca53 100644 --- a/Telegram/SourceFiles/mtproto/session.cpp +++ b/Telegram/SourceFiles/mtproto/session.cpp @@ -168,21 +168,18 @@ void Session::restart() { } void Session::refreshDataFields() { - const auto connectionType = Global::ConnectionType(); - const auto proxyType = Global::ConnectionProxy().type; - const auto useTcp = (proxyType != ProxyData::Type::Http) && - (connectionType == dbictAuto - || connectionType == dbictTcpProxy - || proxyType == ProxyData::Type::Mtproto); - const auto useHttp = (proxyType != ProxyData::Type::Mtproto) && - (connectionType == dbictAuto - || connectionType == dbictHttpProxy); + const auto &proxy = Global::SelectedProxy(); + const auto proxyType = Global::UseProxy() + ? proxy.type + : ProxyData::Type::None; + const auto useTcp = (proxyType != ProxyData::Type::Http); + const auto useHttp = (proxyType != ProxyData::Type::Mtproto); const auto useIPv4 = true; const auto useIPv6 = Global::TryIPv6(); data.setConnectionOptions(ConnectionOptions( _instance->systemLangCode(), _instance->cloudLangCode(), - Global::ConnectionProxy(), + Global::UseProxy() ? proxy : ProxyData(), useIPv4, useIPv6, useHttp, diff --git a/Telegram/SourceFiles/settings/settings_advanced_widget.cpp b/Telegram/SourceFiles/settings/settings_advanced_widget.cpp index 057590269..abd53942e 100644 --- a/Telegram/SourceFiles/settings/settings_advanced_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_advanced_widget.cpp @@ -94,21 +94,19 @@ void AdvancedWidget::onManageLocalStorage() { #ifndef TDESKTOP_DISABLE_NETWORK_PROXY void AdvancedWidget::connectionTypeUpdated() { - auto connection = [] { - switch (Global::ConnectionType()) { - case dbictHttpProxy: - case dbictTcpProxy: { - auto transport = MTP::dctransport(); - return transport.isEmpty() ? lang(lng_connection_proxy_connecting) : lng_connection_proxy(lt_transport, transport); - } break; - case dbictAuto: - default: { - auto transport = MTP::dctransport(); - return transport.isEmpty() ? lang(lng_connection_auto_connecting) : lng_connection_auto(lt_transport, transport); - } break; + const auto connection = [] { + const auto transport = MTP::dctransport(); + if (!Global::UseProxy()) { + return transport.isEmpty() + ? lang(lng_connection_auto_connecting) + : lng_connection_auto(lt_transport, transport); + } else { + return transport.isEmpty() + ? lang(lng_connection_proxy_connecting) + : lng_connection_proxy(lt_transport, transport); } - }; - _connectionType->link()->setText(connection()); + }(); + _connectionType->link()->setText(connection); resizeToWidth(width()); } diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index decb5bcc1..3ad18ff44 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -584,6 +584,13 @@ enum { dbiVersion = 666, }; +enum { + dbictAuto = 0, + dbictHttpAuto = 1, // not used + dbictHttpProxy = 2, + dbictTcpProxy = 3, + dbictProxiesList = 4, +}; typedef QMap DraftsMap; DraftsMap _draftsMap, _draftCursorsMap; @@ -1171,44 +1178,77 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting proxy.type = (v == dbictTcpProxy) ? ProxyData::Type::Socks5 : ProxyData::Type::Http; - Global::SetConnectionType(DBIConnectionType(v)); } break; - case dbictHttpAuto: - default: Global::SetConnectionType(dbictAuto); break; }; - Global::SetConnectionProxy(proxy); + Global::SetSelectedProxy(proxy ? proxy : ProxyData()); + Global::SetUseProxy(proxy ? true : false); + if (proxy) { + Global::SetProxiesList({ 1, proxy }); + } Sandbox::refreshGlobalProxy(); } break; case dbiConnectionType: { - ProxyData proxy; - qint32 connectionType, proxyType, port; - stream >> connectionType >> proxyType >> proxy.host >> port >> proxy.user >> proxy.password; + qint32 connectionType; + stream >> connectionType; if (!_checkStreamStatus(stream)) { return false; } - proxy.port = port; - proxy.type = (proxyType == dbictTcpProxy) - ? ProxyData::Type::Socks5 - : (proxyType == dbictHttpProxy) - ? ProxyData::Type::Http - : (proxyType == kProxyTypeShift + int(ProxyData::Type::Socks5)) - ? ProxyData::Type::Socks5 - : (proxyType == kProxyTypeShift + int(ProxyData::Type::Http)) - ? ProxyData::Type::Http - : (proxyType == kProxyTypeShift + int(ProxyData::Type::Mtproto)) - ? ProxyData::Type::Mtproto - : ProxyData::Type::None; - switch (connectionType) { - case dbictHttpProxy: - case dbictTcpProxy: { - Global::SetConnectionType(DBIConnectionType(connectionType)); - } break; - case dbictHttpAuto: - default: Global::SetConnectionType(dbictAuto); break; + const auto readProxy = [&] { + qint32 proxyType, port; + ProxyData proxy; + stream >> proxyType >> proxy.host >> port >> proxy.user >> proxy.password; + proxy.port = port; + proxy.type = (proxyType == dbictTcpProxy) + ? ProxyData::Type::Socks5 + : (proxyType == dbictHttpProxy) + ? ProxyData::Type::Http + : (proxyType == kProxyTypeShift + int(ProxyData::Type::Socks5)) + ? ProxyData::Type::Socks5 + : (proxyType == kProxyTypeShift + int(ProxyData::Type::Http)) + ? ProxyData::Type::Http + : (proxyType == kProxyTypeShift + int(ProxyData::Type::Mtproto)) + ? ProxyData::Type::Mtproto + : ProxyData::Type::None; + return proxy; }; - Global::SetConnectionProxy(proxy); + if (connectionType == dbictProxiesList) { + qint32 count = 0, index = 0; + stream >> count >> index; + auto list = std::vector(); + for (auto i = 0; i < count; ++i) { + const auto proxy = readProxy(); + if (proxy) { + list.push_back(proxy); + } + } + if (!_checkStreamStatus(stream)) { + return false; + } + Global::SetProxiesList(list); + Global::SetUseProxy(index >= 0 && index < count); + index = std::abs(index); + if (index >= 0 && index < count) { + Global::SetSelectedProxy(list[index]); + } else { + Global::SetSelectedProxy(ProxyData()); + } + } else { + const auto proxy = readProxy(); + if (!_checkStreamStatus(stream)) { + return false; + } + Global::SetProxiesList({ 1, proxy }); + if (connectionType == dbictTcpProxy + || connectionType == dbictHttpProxy) { + Global::SetSelectedProxy(proxy); + Global::SetUseProxy(true); + } else { + Global::SetSelectedProxy(ProxyData()); + Global::SetUseProxy(false); + } + } Sandbox::refreshGlobalProxy(); } break; @@ -2393,9 +2433,18 @@ void writeSettings() { quint32 size = 12 * (sizeof(quint32) + sizeof(qint32)); size += sizeof(quint32) + Serialize::bytearraySize(dcOptionsSerialized); - auto &proxy = Global::ConnectionProxy(); - size += sizeof(quint32) + sizeof(qint32) + sizeof(qint32); - size += Serialize::stringSize(proxy.host) + sizeof(qint32) + Serialize::stringSize(proxy.user) + Serialize::stringSize(proxy.password); + auto &proxies = Global::RefProxiesList(); + const auto &proxy = Global::SelectedProxy(); + auto proxyIt = ranges::find(proxies, proxy); + if (proxy.type != ProxyData::Type::None + && proxyIt == end(proxies)) { + proxies.insert(begin(proxies), proxy); + proxyIt = begin(proxies); + } + size += sizeof(quint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32); + for (const auto &proxy : proxies) { + size += sizeof(qint32) + Serialize::stringSize(proxy.host) + sizeof(qint32) + Serialize::stringSize(proxy.user) + Serialize::stringSize(proxy.password); + } if (_themeKey) { size += sizeof(quint32) + sizeof(quint64); @@ -2421,8 +2470,14 @@ void writeSettings() { data.stream << quint32(dbiScale) << qint32(cConfigScale()); data.stream << quint32(dbiDcOptions) << dcOptionsSerialized; - data.stream << quint32(dbiConnectionType) << qint32(Global::ConnectionType()) << qint32(kProxyTypeShift + int(proxy.type)); - data.stream << proxy.host << qint32(proxy.port) << proxy.user << proxy.password; + data.stream << quint32(dbiConnectionType) << qint32(dbictProxiesList); + data.stream << qint32(proxies.size()); + const auto index = qint32(proxyIt - begin(proxies)); + data.stream << (Global::UseProxy() ? index : -index); + for (const auto &proxy : proxies) { + data.stream << qint32(kProxyTypeShift + int(proxy.type)); + data.stream << proxy.host << qint32(proxy.port) << proxy.user << proxy.password; + } data.stream << quint32(dbiTryIPv6) << qint32(Global::TryIPv6()); if (_themeKey) {