diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ec1184 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# Delphi +*.dcu +*.rsm +*.local +*.identcache +*.~* +__history/ +__Temp/ + +# Windows +*.lnk +Thumbs.db +[Dd]esktop.ini + +# Tcp +Skins/ +Data/ +Tor/ + +# Other +*.zip +TorControlPanel.res +TorControlPanel.exe \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..78c178e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020, abysshint + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..0ce6fac --- /dev/null +++ b/README.md @@ -0,0 +1,119 @@ + +
+ +[![Contributors](https://img.shields.io/github/contributors/abysshint/tor-control-panel.svg?style=for-the-badge)](https://github.com/abysshint/tor-control-panel/graphs/contributors) +[![Forks](https://img.shields.io/github/forks/abysshint/tor-control-panel.svg?style=for-the-badge)](https://github.com/abysshint/tor-control-panel/network/members) +[![MIT License](https://img.shields.io/github/license/abysshint/tor-control-panel.svg?style=for-the-badge)](https://github.com/abysshint/tor-control-panel/blob/main/LICENSE) +[![Stargazers](https://img.shields.io/github/stars/abysshint/tor-control-panel.svg?style=for-the-badge)](https://github.com/abysshint/tor-control-panel/stargazers) +[![Downloads](https://img.shields.io/github/downloads/abysshint/tor-control-panel/total.svg?style=for-the-badge)](https://github.com/abysshint/tor-control-panel/releases) + +
+ +
+ Logo +

Tor Control Panel

+

+ Windows GUI Client for Tor Expert Bundle +
+
+ Language: + English · + Русский +

+
+ +## Table of contents + +* [Overview](#overview) +* [System Requirements](#system-requirements) +* [Program Features](#program-features) +* [Screenshots](#screenshots) +* [Project Build](#Project-build) +* [Privacy](#privacy) +* [License](#license) +* [Links](#links) + +## Overview +Tor Control Panel is a free and simple GUI tool for configuring, managing and monitoring the operation of the [Tor Expert Bundle](https://www.torproject.org/download/tor/) on the operating system Windows. The program's operation is based solely on editing configuration files, parsing local descriptor caches, and sending requests/receiving responses through the control port. The program has a nice and intuitive interface that will help you get more out of the Tor network with a minimum of effort. + +## System Requirements +* Operating system: Windows 7 and above +* Tor version: 0.4.0.5 and above + + > Note: The program can run on Windows XP and Vista, but the latest supported version of Tor for these operating systems is 0.4.4.6, and pluggable transports need to be rebuilt in Golang version 1.10 and below. +

[↑ Up]

+ +## Program Features +* Ability to connect to the Tor network via bridges and a proxy server +* Ability to choose as nodes not only countries, but also hashes, IP addresses and CIDR masks +* Ability to reset Guard nodes +* Ability to scan relays for reachability of ports and ping measuring +* Ability to manage hidden services +* Ability to use selected Entry nodes as Vanguards +* Ability to add and configure the launch of pluggable transports +* Saving/Loading your lists of Entry, Middle, Exit and Exlude nodes +* Automatic nodes selection based on user settings +* Running multiple copies of the program with different profiles +* Showing the Tor message log and saving it to a file +* Configuring Tor to Work in Server Mode (Exit Node, Relay, and Bridge) +* View information on all nodes of the current consensus (Nickname, IP address, Country, Version, Consensus weight, Ping, etc.) +* A convenient filtering, searching and sorting system that helps you choose the most suitable nodes +* Viewing and closing circuits/active connections +* Displaying traffic statistics in the form of a graph and digital data +* The program is portable, installation is not required, where it was launched, it works there +* Support for visual themes +* Multilingual interface with the ability to add new localizations +

[↑ Up]

+ +## Screenshots + + + + + + + + + + + + + + + + + + +
tcp-options-generaltcp-options-networktcp-options-filtertcp-options-server
tcp-circuitstcp-statustcp-relays
tcp-options-hstcp-options-liststcp-options-othertcp-log
+

[↑ Up]

+ +## Project Build +1. Install the IDE [Delphi 10.4.2 CE](https://www.embarcadero.com/ru/products/delphi/starter/free-download) + > Warning! Building the project in other versions of Delphi has not been tested and may lead to the most unexpected results. +2. Download and install the Delphi library [Ararat Synapse](https://sourceforge.net/p/synalist/code/HEAD/tree/trunk/) + + * Create a folder **Synapse** and extract the files from the archive **synalist-code-r000-trunk.zip** into it + + `C:\Program Files (x86)\Embarcadero\Studio\21.0\source\Synapse` + + * Open the Delphi Options and add the path **$(BDS)\source\Synapse** to the lists **Library path** and **Browsing path** + + `[Tools] → [Options] → [Language] → [Delphi] → [Library] → [Windows 32-bit]/[Windows 64-bit]` + +3. Open the file **TorControlPanel.dproj**, select platform and compile the project by pressing the **[Run]** button +4. Run the file **TCP-RSP-31045-PATCHER.exe** to fix the Delphi 10.4 bug which causes the buttons to be displayed incorrectly in Windows 7 when Aero is enabled. + > Warning! The [AT4RE-Patcher-v0.7.6](https://github.com/anomous/AT4RE-Patcher-Windows) program was used to create the patch. The patches created in it are defined by some antiviruses as potentially dangerous applications, since "hacker" methods of modifying executable files are used. +

[↑ Up]

+ +## Privacy +The program does not have direct access to the transmitted user data, does not require administrator rights, does not change any operating system system settings, including the system proxy server, does not collect any usage statistics + +## License +This program is free software and distributed under the [MIT license](https://github.com/abysshint/tor-control-panel/blob/main/LICENSE) + +## Links +* [Tor Manual](https://man.archlinux.org/man/tor.1) +* [Tor Specifications and Proposals](https://gitlab.torproject.org/tpo/core/torspec) +* [Tor Project Distribution Server](https://dist.torproject.org/) +* [Tor Project File Archive](https://archive.torproject.org/tor-package-archive/) +

[↑ Up]

\ No newline at end of file diff --git a/README.ru.md b/README.ru.md new file mode 100644 index 0000000..9cc4985 --- /dev/null +++ b/README.ru.md @@ -0,0 +1,120 @@ + +
+ +[![Contributors](https://img.shields.io/github/contributors/abysshint/tor-control-panel.svg?style=for-the-badge)](https://github.com/abysshint/tor-control-panel/graphs/contributors) +[![Forks](https://img.shields.io/github/forks/abysshint/tor-control-panel.svg?style=for-the-badge)](https://github.com/abysshint/tor-control-panel/network/members) +[![MIT License](https://img.shields.io/github/license/abysshint/tor-control-panel.svg?style=for-the-badge)](https://github.com/abysshint/tor-control-panel/blob/main/LICENSE) +[![Stargazers](https://img.shields.io/github/stars/abysshint/tor-control-panel.svg?style=for-the-badge)](https://github.com/abysshint/tor-control-panel/stargazers) +[![Downloads](https://img.shields.io/github/downloads/abysshint/tor-control-panel/total.svg?style=for-the-badge)](https://github.com/abysshint/tor-control-panel/releases) + +
+ +
+ Logo +

Панель управления Tor

+

+ Windows GUI-клиент для Tor Expert Bundle +
+
+ Язык: + English · + Русский +

+
+ +## Оглавление + +* [Обзор](#обзор) +* [Системные требования](#системные-требования) +* [Особенности программы](#особенности-программы) +* [Скриншоты](#скриншоты) +* [Сборка проекта](#сборка-проекта) +* [Конфиденциальность](#конфиденциальность) +* [Лицензия](#лицензия) +* [Ссылки](#ссылки) + +## Обзор +Панель управления Tor - это бесплатный и простой инструмент с графическим интерфейсом для настройки, управления и мониторинга работы [Tor Expert Bundle](https://www.torproject.org/download/tor/) в операционной системе Windows. Работа программы основана исключительно на редактировании конфигурационных файлов, разборе локальных кэшей дескрипторов и отправке запросов/получении ответов через управляющий порт. Программа имеет приятный и интуитивно-понятный интерфейс, который поможет вам использовать больше возможностей сети Tor, прилагая при этом минимум усилий. + +## Системные требования +* Операционная система: Windows 7 и выше +* Версия Tor: 0.4.0.5 и выше + + > Примечание: программа может работать на Windows XP и Vista, но последняя поддерживаемая версия Tor для этих операционных систем - 0.4.4.6, а подключаемые транспорты нужно пересобрать в Gоlang версии 1.10 и ниже. +

[↑ Вверх]

+ +## Особенности программы +* Возможность подключения к сети Tor через мосты и прокси-сервер +* Возможность выбирать в качестве узлов не только страны, но и хэши, IP-адреса и CIDR-маски +* Возможность сброса сторожевых узлов +* Возможность сканировать узлы на доступность портов и измерять пинг +* Возможность управлять скрытыми сервисами +* Возможность использовать избранные сторожевые узлы в качестве Vanguards +* Возможность добавлять и настраивать запуск подключаемых транспортов +* Сохранение/загрузка своих списков входных, промежуточных, выходных и запрещённых узлов +* Автоматический подбор узлов на основе пользовательских настроек +* Запуск нескольких копий программы с разными профилями +* Отображение журнала сообщений Tor и сохранение его в файл +* Настройка работы Tor в режиме сервера (Выходной узел, Ретранслятор и мост) +* Просмотр информации по всем узлам текущего консенсуса (Ник, IP-адрес, Страна, Версия, Вес в консенсусе, Пинг и тд.) +* Удобная система фильтрации, поиска и сортировки, помогающая выбрать наиболее подходящие вам узлы +* Просмотр и закрытие цепочек/активных соединений +* Отображение статистики по трафику в виде графика и цифровых данных +* Программа портативная, установка не требуется, где её запустили там она и работает +* Поддержка визуальных тем оформления +* Мультиязычный интерфейс с возможностю добавлять новые локализации +

[↑ Вверх]

+ +## Скриншоты + + + + + + + + + + + + + + + + + + +
tcp-options-generaltcp-options-networktcp-options-filtertcp-options-server
tcp-circuitstcp-statustcp-relays
tcp-options-hs
tcp-options-liststcp-options-othertcp-log
+

[↑ Вверх]

+ +## Сборка проекта +1. Установите интегрированную среду разработки [Delphi 10.4.2 CE](https://www.embarcadero.com/ru/products/delphi/starter/free-download) + > Внимание! Сборка проекта в других версиях Delphi не тестировалась и может привести к самым неожиданным результатам +2. Загрузите и установите в Delphi библиотеку [Ararat Synapse](https://sourceforge.net/p/synalist/code/HEAD/tree/trunk/) + + * Создайте папку **Synapse** и извлеките в неё файлы из архива **synalist-code-r000-trunk.zip** + + `C:\Program Files (x86)\Embarcadero\Studio\21.0\source\Synapse` + + * Откройте настройки Delphi и добавьте путь **$(BDS)\source\Synapse** в списки **Library path** и **Browsing path** + + `[Tools] → [Options] → [Language] → [Delphi] → [Library] → [Windows 32-bit]/[Windows 64-bit]` + +3. Откройте файл **TorControlPanel.dproj**, выберите платформу и скомпилируйте проект нажатием кнопки **[Run]** +4. Запустите файл **TCP-RSP-31045-PATCHER.exe** для исправления ошибки Delphi 10.4 из-за которой неправильно ображаются кнопки в Windows 7 при включённом Aero. + > Внимание! Для создания патча использовалась программа [AT4RE-Patcher-v0.7.6](https://github.com/anomous/AT4RE-Patcher-Windows). Созданные в ней патчи определяются некоторыми антивирусами как потенциально-опасные приложения, так как используются "хакерские" методы модификации исполняемых файлов. +

[↑ Вверх]

+ +## Конфиденциальность +Программа не имеет прямого доступа к передаваемым данным пользователя, не требует прав администратора, не изменяет никакие системные настройки операционной системы, включая системный прокси-сервер, не собирает никаких статистических данных об использовании + +## Лицензия +Эта программа является свободным программным обеспечением и распространяется по [лицензии MIT](https://github.com/abysshint/tor-control-panel/blob/main/LICENSE) + +## Ссылки +* [Мануал по Tor](https://man.archlinux.org/man/tor.1) +* [Спецификации и предложения Tor](https://gitlab.torproject.org/tpo/core/torspec) +* [Сервер дистрибутивов проекта Tor Project](https://dist.torproject.org/) +* [Файловый архив проекта Tor Project](https://archive.torproject.org/tor-package-archive/) +

[↑ Вверх]

+ diff --git a/images/common/tcp-logo.png b/images/common/tcp-logo.png new file mode 100644 index 0000000..b468dbc Binary files /dev/null and b/images/common/tcp-logo.png differ diff --git a/images/english/tcp-circuits.png b/images/english/tcp-circuits.png new file mode 100644 index 0000000..52c1939 Binary files /dev/null and b/images/english/tcp-circuits.png differ diff --git a/images/english/tcp-log.png b/images/english/tcp-log.png new file mode 100644 index 0000000..40e7988 Binary files /dev/null and b/images/english/tcp-log.png differ diff --git a/images/english/tcp-options-filter.png b/images/english/tcp-options-filter.png new file mode 100644 index 0000000..380a817 Binary files /dev/null and b/images/english/tcp-options-filter.png differ diff --git a/images/english/tcp-options-general.png b/images/english/tcp-options-general.png new file mode 100644 index 0000000..fd59ea2 Binary files /dev/null and b/images/english/tcp-options-general.png differ diff --git a/images/english/tcp-options-hs.png b/images/english/tcp-options-hs.png new file mode 100644 index 0000000..a5cf42d Binary files /dev/null and b/images/english/tcp-options-hs.png differ diff --git a/images/english/tcp-options-lists.png b/images/english/tcp-options-lists.png new file mode 100644 index 0000000..4c6391a Binary files /dev/null and b/images/english/tcp-options-lists.png differ diff --git a/images/english/tcp-options-network.png b/images/english/tcp-options-network.png new file mode 100644 index 0000000..d6a1a29 Binary files /dev/null and b/images/english/tcp-options-network.png differ diff --git a/images/english/tcp-options-other.png b/images/english/tcp-options-other.png new file mode 100644 index 0000000..07db416 Binary files /dev/null and b/images/english/tcp-options-other.png differ diff --git a/images/english/tcp-options-server.png b/images/english/tcp-options-server.png new file mode 100644 index 0000000..f174822 Binary files /dev/null and b/images/english/tcp-options-server.png differ diff --git a/images/english/tcp-relays.png b/images/english/tcp-relays.png new file mode 100644 index 0000000..2f4d2d5 Binary files /dev/null and b/images/english/tcp-relays.png differ diff --git a/images/english/tcp-status.png b/images/english/tcp-status.png new file mode 100644 index 0000000..4780326 Binary files /dev/null and b/images/english/tcp-status.png differ diff --git a/images/russian/tcp-circuits.png b/images/russian/tcp-circuits.png new file mode 100644 index 0000000..24af746 Binary files /dev/null and b/images/russian/tcp-circuits.png differ diff --git a/images/russian/tcp-log.png b/images/russian/tcp-log.png new file mode 100644 index 0000000..c556a72 Binary files /dev/null and b/images/russian/tcp-log.png differ diff --git a/images/russian/tcp-options-filter.png b/images/russian/tcp-options-filter.png new file mode 100644 index 0000000..f1cee17 Binary files /dev/null and b/images/russian/tcp-options-filter.png differ diff --git a/images/russian/tcp-options-general.png b/images/russian/tcp-options-general.png new file mode 100644 index 0000000..d23c9b0 Binary files /dev/null and b/images/russian/tcp-options-general.png differ diff --git a/images/russian/tcp-options-hs.png b/images/russian/tcp-options-hs.png new file mode 100644 index 0000000..05319bc Binary files /dev/null and b/images/russian/tcp-options-hs.png differ diff --git a/images/russian/tcp-options-lists.png b/images/russian/tcp-options-lists.png new file mode 100644 index 0000000..8ef9be0 Binary files /dev/null and b/images/russian/tcp-options-lists.png differ diff --git a/images/russian/tcp-options-network.png b/images/russian/tcp-options-network.png new file mode 100644 index 0000000..7fe5686 Binary files /dev/null and b/images/russian/tcp-options-network.png differ diff --git a/images/russian/tcp-options-other.png b/images/russian/tcp-options-other.png new file mode 100644 index 0000000..10b648f Binary files /dev/null and b/images/russian/tcp-options-other.png differ diff --git a/images/russian/tcp-options-server.png b/images/russian/tcp-options-server.png new file mode 100644 index 0000000..91d8885 Binary files /dev/null and b/images/russian/tcp-options-server.png differ diff --git a/images/russian/tcp-relays.png b/images/russian/tcp-relays.png new file mode 100644 index 0000000..ed190b1 Binary files /dev/null and b/images/russian/tcp-relays.png differ diff --git a/images/russian/tcp-status.png b/images/russian/tcp-status.png new file mode 100644 index 0000000..5ae9bc8 Binary files /dev/null and b/images/russian/tcp-status.png differ diff --git a/source/Addons.pas b/source/Addons.pas new file mode 100644 index 0000000..9ea9699 --- /dev/null +++ b/source/Addons.pas @@ -0,0 +1,387 @@ +unit Addons; + +interface + +uses + Winapi.Windows, Vcl.Graphics, Winapi.Messages, System.Classes, System.SysUtils, + Vcl.Controls, Vcl.Forms, Vcl.Grids, Vcl.StdCtrls, Vcl.Themes, Vcl.ComCtrls, Vcl.Menus; + +type + TColsDataType = (dtInteger, dtText, dtSize, dtParams); + + TUpDown = class (Vcl.ComCtrls.TUpDown) + public + ResetValue: Integer; + end; + + TComboBox = class (Vcl.StdCtrls.TComboBox) + public + ResetValue: Integer; + protected + procedure MouseDown(Button: TMouseButton; Shift: TShiftState;X, Y: Integer); override; + end; + + TEdit = class (Vcl.StdCtrls.TEdit) + public + ResetValue: string; + protected + procedure MouseDown(Button: TMouseButton; Shift: TShiftState;X, Y: Integer); override; + procedure DoExit; override; + end; + + TCheckBox = class (Vcl.StdCtrls.TCheckBox) + public + ResetValue: Boolean; + protected + procedure MouseDown(Button: TMouseButton; Shift: TShiftState;X, Y: Integer); override; + end; + + TMemo = class (Vcl.StdCtrls.TMemo) + private + FTextHint: TStrings; + FTextHintFont: TFont; + protected + FCanvas: TCanvas; + procedure WMPaint(var Message: TWMPaint); message WM_PAINT; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + published + property OnExit; + property TextHint: TStrings read FTextHint write FTextHint; + property TextHintFont: TFont read FTextHintFont write FTextHintFont; + procedure SetTextHintFont(const Value: TFont); inline; + end; + + TButton = class (Vcl.StdCtrls.TButton) + strict private + class constructor Create; + class destructor Destroy; + end; + + TSplitButtonStyleHook = class(TButtonStyleHook) + protected + procedure Paint(Canvas: TCanvas); override; + end; + + TStringGrid = class(Vcl.Grids.TStringGrid) + private + FCellsAlignment: TStringList; + FColsDefaultAlignment: TStringList; + FColsDataType: TStringList; + function GetCellsAlignment(ACol, ARow: Integer): TAlignment; + function GetColsDefaultAlignment(ACol: Integer): TAlignment; + function GetColsDataType(ACol: Integer): TColsDataType; + procedure SetCellsAlignment(ACol, ARow: Integer; const Alignment: TAlignment); + procedure SetColsDefaultAlignment(ACol: Integer; const Alignment: TAlignment); + procedure SetColsDataType(ACol: Integer; const ColsDataType: TColsDataType); + protected + procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override; + function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; override; + function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; override; + public + SelCol, SelRow, MovCol, MovRow: Integer; + SortType, SortCol: Byte; + ScrollKeyDown: Boolean; + RowID: string; + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + property CellsAlignment[ACol, ARow: Integer]: TAlignment read GetCellsAlignment write SetCellsAlignment; + property ColsDefaultAlignment[ACol: Integer]: TAlignment read GetColsDefaultAlignment write SetColsDefaultAlignment; + property ColsDataType[ACol: Integer]: TColsDataType read GetColsDataType write SetColsDataType; + end; + + TStyleManagerHelper = class helper for TStyleManager + public + class procedure RemoveStyle(StyleName: string); + end; + +implementation + +Uses Main, Functions; + +class constructor TButton.Create; +begin + TCustomStyleEngine.RegisterStyleHook(TButton, TSplitButtonStyleHook); +end; + +class destructor TButton.Destroy; +begin + TCustomStyleEngine.UnRegisterStyleHook(TButton, TSplitButtonStyleHook); +end; + +function TStringGrid.DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; +begin + Perform(WM_VSCROLL, SB_LINEDOWN, 0); + Result := True; +end; + +function TStringGrid.DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; +begin + Perform(WM_VSCROLL, SB_LINEUP, 0); + Result := True; +end; + +procedure TComboBox.MouseDown(Button: TMouseButton; Shift: TShiftState;X, Y: Integer); +begin + if Button = mbMiddle then + begin + if (ItemIndex <> ResetValue) and CanFocus then + begin + SetFocus; + ItemIndex := ResetValue; + Change; + end; + end; + Inherited; +end; + +procedure TCheckBox.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +begin + if Button = mbMiddle then + begin + if (Checked <> ResetValue) and CanFocus then + begin + SetFocus; + Checked := ResetValue; + end; + end; + inherited; +end; + +procedure TEdit.DoExit; +var + UpDown: TUpDown; +begin + UpDown := GetAssocUpDown(Name); + if UpDown <> nil then + Text := IntToStr(UpDown.Position); + inherited; +end; + +procedure TEdit.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +var + UpDown: TUpDown; +begin + if Button = mbMiddle then + begin + UpDown := GetAssocUpDown(Name); + if CanFocus then + begin + SetFocus; + if UpDown <> nil then + begin + if (UpDown.Position <> UpDown.ResetValue) then + UpDown.Position := UpDown.ResetValue; + end + else + begin + if Text <> ResetValue then + Text := ResetValue; + end; + SelStart := Length(Text); + end; + end; + inherited; +end; + +procedure TSplitButtonStyleHook.Paint(Canvas: TCanvas); +var + Icon: TIcon; +begin + Inherited; + if (Win32MajorVersion = 5) and (TButton(Control).Style = bsSplitButton) then + begin + Icon := TIcon.Create; + try + Tcp.lsMain.GetIcon(14, Icon); + Canvas.MoveTo(Control.Width - 15, 2); + Canvas.LineTo(Control.Width - 15, Control.Height - 2); + Canvas.Draw(Control.Width - 16, (Control.Height - 16) div 2, Icon); + ReleaseDC(Handle, Canvas.Handle); + finally + Icon.Free; + end; + end; +end; + +class procedure TStyleManagerHelper.RemoveStyle(StyleName: string); +var + Style: TCustomStyleServices; +begin + if TStyleManager.Style[StyleName] <> nil then + begin + if TStyleManager.FRegisteredStyles.ContainsKey(StyleName) then + begin + Style := TStyleManager.Style[StyleName]; + TStyleManager.FStyles.Remove(Style); + TStyleManager.FRegisteredStyles.Remove(StyleName); + FreeAndNil(Style); + end; + end; +end; + +constructor TMemo.Create(AOwner: TComponent); +begin + inherited; + FTextHint := TStringList.Create; + FCanvas := TControlCanvas.Create; + FTextHintFont := TFont.Create; + FTextHintFont.Color := StyleServices.GetStyleFontColor(sfEditBoxTextDisabled); + FTextHintFont.Name := 'Lucida Console'; + TControlCanvas(FCanvas).Control := Self; +end; + +destructor TMemo.Destroy; +begin + FreeAndNil(FTextHintFont); + FreeAndNil(FCanvas); + FTextHint.Clear; + FreeAndNil(FTextHint); + inherited; +end; + +procedure TMemo.WMPaint(var Message: TWMPaint); +var + i, TextHeight: Integer; +begin + inherited; + if (Text = '') and (not Focused) then + begin + FCanvas.Font := FTextHintFont; + FCanvas.Brush.Color := StyleServices.GetStyleColor(scEdit); + TextHeight := FCanvas.TextHeight('yY'); + for i := 0 to FTextHint.Count - 1 do + FCanvas.TextOut(1, 1 + (i * TextHeight), FTextHint[i]); + end; +end; + +procedure TMemo.SetTextHintFont(const Value: TFont); +begin + FTextHintFont.Assign(Value); +end; + +constructor TStringGrid.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FCellsAlignment := TStringList.Create; + FCellsAlignment.CaseSensitive := True; + FCellsAlignment.Sorted := True; + FCellsAlignment.Duplicates := dupIgnore; + FColsDefaultAlignment := TStringList.Create; + FColsDefaultAlignment.CaseSensitive := True; + FColsDefaultAlignment.Sorted := True; + FColsDefaultAlignment.Duplicates := dupIgnore; + FColsDataType := TStringList.Create; + FColsDataType.CaseSensitive := True; + FColsDataType.Sorted := True; + FColsDataType.Duplicates := dupIgnore; +end; + +destructor TStringGrid.Destroy; +begin + FCellsAlignment.Free; + FColsDefaultAlignment.Free; + FColsDataType.Free; + inherited Destroy; +end; + +procedure TStringGrid.SetCellsAlignment(ACol, ARow: Integer; const Alignment: TAlignment); +var + Index: Integer; +begin + Index := 0; + if (Index > -1) then + FCellsAlignment.Objects[Index] := TObject(Alignment) + else + FCellsAlignment.AddObject(IntToStr(ACol) + '-' + IntToStr(ARow), TObject(Alignment)); +end; + +function TStringGrid.GetCellsAlignment(ACol, ARow: Integer): TAlignment; +var + Index: Integer; +begin + Index := FCellsAlignment.IndexOf(IntToStr(ACol) + '-' + IntToStr(ARow)); + if (Index > -1) then + GetCellsAlignment := TAlignment(FCellsAlignment.Objects[Index]) + else + GetCellsAlignment := ColsDefaultAlignment[ACol]; +end; + +procedure TStringGrid.SetColsDefaultAlignment(ACol: Integer; const Alignment: TAlignment); +var + Index: Integer; +begin + Index := FColsDefaultAlignment.IndexOf(IntToStr(ACol)); + if (Index > -1) then + FColsDefaultAlignment.Objects[Index] := TObject(Alignment) + else + FColsDefaultAlignment.AddObject(IntToStr(ACol), TObject(Alignment)); +end; + +function TStringGrid.GetColsDefaultAlignment(ACol: Integer): TAlignment; +var + Index: Integer; +begin + Index := FColsDefaultAlignment.IndexOf(IntToStr(ACol)); + if (Index > -1) then + GetColsDefaultAlignment := TAlignment(FColsDefaultAlignment.Objects[Index]) + else + GetColsDefaultAlignment := taLeftJustify; +end; + +procedure TStringGrid.SetColsDataType(ACol: Integer; const ColsDataType: TColsDataType); +var + Index: Integer; +begin + Index := FColsDataType.IndexOf(IntToStr(ACol)); + if (Index > -1) then + FColsDataType.Objects[Index] := TObject(ColsDataType) + else + FColsDataType.AddObject(IntToStr(ACol), TObject(ColsDataType)); +end; + +function TStringGrid.GetColsDataType(ACol: Integer): TColsDataType; +var + Index: Integer; +begin + Index := FColsDataType.IndexOf(IntToStr(ACol)); + if (Index > -1) then + GetColsDataType := TColsDataType(FColsDataType.Objects[Index]) + else + GetColsDataType := dtText; +end; + +procedure TStringGrid.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); +var + Temp: Boolean; + NewText: String; +begin + if DefaultDrawing then + begin + NewText := Cells[ACol, ARow]; + case CellsAlignment[ACol, ARow] of + taLeftJustify: + begin + ARect.Left := ARect.Left + 2; + Canvas.TextRect(ARect, NewText, [tfLeft, tfEndEllipsis, tfSingleLine, tfVerticalCenter]); + end; + taRightJustify: + begin + ARect.Right := ARect.Right - 2; + Canvas.TextRect(ARect, NewText, [tfRight, tfEndEllipsis, tfSingleLine, tfVerticalCenter]); + end; + taCenter: + begin + ARect.Left := ARect.Left + 2; + Canvas.TextRect(ARect, NewText, [tfCenter, tfEndEllipsis, tfSingleLine, tfVerticalCenter]); + end; + end; + end; + Temp := DefaultDrawing; + DefaultDrawing := False; + inherited DrawCell(ACol, ARow, ARect, AState); + DefaultDrawing := Temp; +end; + +end. diff --git a/source/Changelog.txt b/source/Changelog.txt new file mode 100644 index 0000000..44785e2 --- /dev/null +++ b/source/Changelog.txt @@ -0,0 +1,172 @@ + : + +2.2.11.4: + + - , . + - , , "". + - "IP-" "" Tor + - , + - " " " " + - 2 3 HiddenServiceVersion torrc-. , 2 . + - Cookie- Tor (-: ) + - + - Ctrl+A , "" "" + - - IP- + - . + - + - , Defaults.ini + - " ", + - + - . + - + - Windows 8.1 10 100% + - : , . + - / . + - : , , + - . . + - , + - torrc-, , Tor + - "", Tor, + - "" / + - ( ) + - , + - , + - Ctrl+C + - (Ctrl+F) + - " ", , , "" + - , , , "" + - . + - + - " " . + - IP- "", Ctrl - "" + - IP- "" "" . + - ", ". ExcludeExitNodes . + - " " " ", - . , . + - " " . , + - . + - geoip geoip6 . + - "", "" "" Tor, + - "" . + - "" . + - . + - , , / . / + - " " " ", , , . + - , " " + - torrc-, settings.ini (-: , , , ) + - torrc / + - + - Ipv6- torrc + - "" "", MyFamily, + - "" " ", StrictNodes + - "" ". ", MaxClientCircuitsPending + - "" "" , MaxAdvertisedBandwidth + - "" " ", DirCache + - "" " IPv6-", IPv4Only ORPort DirPort + - "" " ", AssumeReachable + - "" " ", Address + - "" "" "", BridgeDistribution + - "" " ", HSLayer2Nodes HSLayer3Nodes. . + - : , , . + - OpenDNS, Tor + - Ip-cc- network-cache. + - ClientOnionAuthDir, + - " " Tor. " ", " ", " " + - , + - + - + - "eu" , , + - : 32-bit 64-bit + - GitHub MIT-. " " + +2.0.4.30: + + - + +2.0.4.26: + + - , masterlola + - , + +2.0.4.24: + + - UTF-8 + - : , , + - + - , + - Ctrl+C , + - Windows " " + - , Translations.ini + - , , Google Yandex + +2.0.4.14: + + - 100% + - , + - , / + - , + - torrc- + - torcc + - + - Tor , + - + - , torrc + - , + - Tor (, ) + - , + - " ", Tor , . + - (, ip, , ) + - (/ ) + - IP- , " " + - + - (, , ) + - , + - c , %AppData%\Tcp\* + - , + - Tor , , + - Tor + - "", metrics.torproject.org + - (-: Tor ) + +2.0.3.6: + + - + - 127.0.0.1 + - , Tor . + - + - torrc + - torrc, , + - Tor + - Tor + - Tor + - Tor + - + - ns/id, + - " " , " DNS-" + - , Indy Synapse, + - + - " " + +2.0.2.15: + + - , + - Tor + - (. ) + - + - + - signal newnym, + - , Tor + +2.0.1.3: + + - , + - + - IP + - Tor + - + - Tor + - Tor + - + - stdout + - ( , .) + - (, , ) + - diff --git a/source/ConstData.pas b/source/ConstData.pas new file mode 100644 index 0000000..a456a33 --- /dev/null +++ b/source/ConstData.pas @@ -0,0 +1,407 @@ +unit ConstData; + +interface + +uses + System.Types; + +const + BR = #13#10; + SELECT_CHAR = '★'; + FAVERR_CHAR = '☆'; + BOTH_CHAR = '✿'; + EXCLUDE_CHAR = '✖'; + NONE_CHAR = '-'; + INFINITY_CHAR = '∞'; + + BRIDGES_BOT = 'GetBridgesBot'; + BRIDGES_EMAIL = 'bridges@torproject.org'; + BRIDGES_SITE = 'https://bridges.torproject.org/bridges'; + CHECK_URL = 'https://check.torproject.org'; + DOWNLOAD_URL = 'https://www.torproject.org/download/languages'; + METRICS_URL = 'https://metrics.torproject.org/rs.html'; + GITHUB_URL = 'https://github.com/abysshint/tor-control-panel'; + + DEFAULT_ENTRY_NODES = '{cz},{fi},{fr},{gb},{se},{nl},{de},{no},{at},{ch}'; + DEFAULT_MIDDLE_NODES = '{cz},{fi},{fr},{gb},{se},{nl},{de},{no},{at},{dk},{pl},{ch}'; + DEFAULT_EXIT_NODES = '{gb},{se},{nl},{de},{no},{hr},{at},{pl},{ro},{ch}'; + DEFAULT_ROUTERS_FILTER_DATA = '15;-1;739;-1;10;0;0;0;'; + DEFAULT_CUSTOM_EXIT_POLICY = 'accept *:80,accept *:443,reject *:*'; + DEFAULT_ALLOWED_PORTS = '80,443'; + DEFAULT_COUNTRY_ID = 249; + + CURRENT_CONFIG_VERSION = 2; + MAX_SPEED_DATA_LENGTH = 24 * 60 * 60; + BUFSIZE = 1024 * 1024; + + MAX_COUNTRIES = 251; + MAX_TOTALS = 6; + + CIRCUIT_FILTER_DEFAULT = 32767; + CIRCUIT_FILTER_MAX = 32767; + ROUTER_FILTER_DEFAULT = 15; + ROUTER_FILTER_MAX = 15; + SHOW_NODES_FILTER_DEFAULT = 739; + SHOW_NODES_FILTER_MAX = 8176; + TPL_MENU_DEFAULT = 7; + TPL_MENU_MAX = 7; + + L1_NUM_GUARDS = 2; + L2_NUM_GUARDS = 4; + L3_NUM_GUARDS = 8; + + STOP_NORMAL = 0; + STOP_CONFIG_ERROR = 1; + STOP_AUTH_ERROR = 2; + + LP_OPTIONS = 0; + LP_LOG = 1; + LP_STATUS = 2; + LP_CIRCUITS = 3; + LP_ROUTERS = 4; + + TOTAL_RELAYS = 0; + TOTAL_GUARDS = 1; + TOTAL_EXITS = 2; + TOTAL_PING_SUM = 3; + TOTAL_PING_COUNTS = 4; + TOTAL_ALIVES = 5; + + SORT_ASC = 1; + SORT_DESC = 2; + + PRIORITY_BALANCED = 0; + PRIORITY_WEIGHT = 1; + PRIORITY_PING = 2; + PRIORITY_RANDOM = 3; + + BRIDGE_RELAY = 0; + BRIDGE_NATIVE = 1; + + BRIDGES_TYPE_BUILTIN = 0; + BRIDGES_TYPE_USER = 1; + + TRANSPORT_CLIENT = 0; + TRANSPORT_SERVER = 1; + TRANSPORT_BOTH = 2; + + PROXY_TYPE_SOCKS4 = 0; + PROXY_TYPE_SOCKS5 = 1; + PROXY_TYPE_HTTPS = 2; + + FILTER_TYPE_NONE = 0; + FILTER_TYPE_COUNTRIES = 1; + FILTER_TYPE_FAVORITES = 2; + + NL_TYPE_ENTRY = 0; + NL_TYPE_MIDDLE = 1; + NL_TYPE_EXIT = 2; + NL_TYPE_EXLUDE = 3; + + HS_VERSION_2 = 0; + HS_VERSION_3 = 1; + + HS_STATE_ENABLED = 0; + HS_STATE_DISABLED = 1; + + GRID_FILTER = 1; + GRID_ROUTERS = 2; + GRID_CIRCUITS = 3; + GRID_STREAMS = 4; + GRID_HS = 5; + GRID_HSP = 6; + GRID_CIRC_INFO = 7; + GRID_STREAM_INFO = 8; + GRID_TRANSPORTS = 9; + + FILTER_ID = 0; + FILTER_FLAG = 1; + FILTER_NAME = 2; + FILTER_TOTAL = 3; + FILTER_GUARD = 4; + FILTER_EXIT = 5; + FILTER_ALIVE = 6; + FILTER_PING = 7; + FILTER_ENTRY_NODES = 8; + FILTER_MIDDLE_NODES = 9; + FILTER_EXIT_NODES = 10; + FILTER_EXCLUDE_NODES = 11; + + ROUTER_ID = 0; + ROUTER_NAME = 1; + ROUTER_IP = 2; + ROUTER_FLAG = 3; + ROUTER_COUNTRY = 4; + ROUTER_WEIGHT = 5; + ROUTER_PORT = 6; + ROUTER_VERSION = 7; + ROUTER_PING = 8; + ROUTER_FLAGS = 9; + ROUTER_ENTRY_NODES = 10; + ROUTER_MIDDLE_NODES = 11; + ROUTER_EXIT_NODES = 12; + ROUTER_EXCLUDE_NODES = 13; + + CIRC_ID = 0; + CIRC_PURPOSE = 1; + CIRC_STREAMS = 2; + CIRC_BYTES_READ = 3; + CIRC_BYTES_WRITTEN = 4; + + STREAMS_ID = 0; + STREAMS_TARGET = 1; + STREAMS_TRACK = 2; + STREAMS_COUNT = 3; + STREAMS_BYTES_READ = 4; + STREAMS_BYTES_WRITTEN = 5; + + HS_NAME = 0; + HS_VERSION = 1; + HS_INTRO_POINTS = 2; + HS_MAX_STREAMS = 3; + HS_STATE = 4; + HS_PORTS_DATA = 5; + HS_PREVIOUS_NAME = 6; + + HSP_INTERFACE = 0; + HSP_REAL_PORT = 1; + HSP_VIRTUAL_PORT = 2; + + CIRC_INFO_ID = 0; + CIRC_INFO_NAME = 1; + CIRC_INFO_IP = 2; + CIRC_INFO_FLAG = 3; + CIRC_INFO_COUNTRY = 4; + CIRC_INFO_WEIGHT = 5; + CIRC_INFO_PING = 6; + + STREAMS_INFO_ID = 0; + STREAMS_INFO_SOURCE_ADDR = 1; + STREAMS_INFO_DEST_ADDR = 2; + STREAMS_INFO_PURPOSE = 3; + STREAMS_INFO_BYTES_READ = 4; + STREAMS_INFO_BYTES_WRITTEN = 5; + + PT_TRANSPORTS = 0; + PT_HANDLER = 1; + PT_TYPE = 2; + PT_PARAMS = 3; + + ROUTER_BAD_EXIT = 1; + ROUTER_NOT_RECOMMENDED = 2; + ROUTER_DIR_MIRROR = 4; + ROUTER_HS_DIR = 8; + ROUTER_REACHABLE_IPV6 = 16; + ROUTER_ALIVE = 32; + ROUTER_AUTHORITY = 64; + ROUTER_BRIDGE = 128; + + GENERAL = 0; + HS_CLIENT_HSDIR = 1; + HS_CLIENT_INTRO = 2; + HS_CLIENT_REND = 3; + HS_SERVICE_HSDIR = 4; + HS_SERVICE_INTRO = 5; + HS_SERVICE_REND = 6; + HS_VANGUARDS = 7; + PATH_BIAS_TESTING = 8; + TESTING = 9; + CIRCUIT_PADDING = 10; + MEASURE_TIMEOUT = 11; + + LAUNCHED = 12; + BUILT = 13; + GUARD_WAIT = 14; + EXTENDED = 15; + FAILED = 16; + CLOSED = 17; + + NEW = 18; + NEWRESOLVE = 19; + REMAP = 20; + SENTCONNECT = 21; + SENTRESOLVE = 22; + SUCCEEDED = 23; + DETACHED = 24; + CONTROLLER_WAIT = 25; + + DIR_FETCH = 26; + DIR_UPLOAD = 27; + DIRPORT_TEST = 28; + DNS_REQUEST = 29; + USER = 30; + + FILTER_BY_ALIVE = 5; + FILTER_BY_TOTAL = 6; + FILTER_BY_GUARD = 7; + FILTER_BY_EXIT = 8; + FILTER_BY_QUERY = 9; + + NONE_ID = 0; + ENTRY_ID = ROUTER_ENTRY_NODES; + MIDDLE_ID = ROUTER_MIDDLE_NODES; + EXIT_ID = ROUTER_EXIT_NODES; + EXCLUDE_ID = ROUTER_EXCLUDE_NODES; + FAVORITES_ID = 14; + +type + ArrOfStr = array of string; + ArrOfPoint = array of TPoint; + + TNodeType = ( + ntNone = NONE_ID, + ntEntry = ENTRY_ID, + ntMiddle = MIDDLE_ID, + ntExit = EXIT_ID, + ntExclude = EXCLUDE_ID, + ntFavorites = FAVORITES_ID + ); + TNodeTypes = set of TNodeType; + + TEditMenuType = (emCopy, emCut, emPaste, emSelectAll, emClear, emDelete, emFind); + TListType = (ltNoCheck, ltHost, ltHash, ltPolicy, ltBridge, ltNode, ltSocket, ltTransport, ltIp, ltCidr, ltCode); + TGuardType = (gtNone, gtBridges, gtRestricted, gtDefault, gtAll); + TMsgType = (mtInfo, mtWarning, mtError, mtQuestion); + TParamType = (ptString, ptInteger, ptBoolean, ptSocket, ptHost, ptSize, ptBridge); + TTaskBarPos = (tbTop, tbBottom, tbLeft, tbRight, tbNone); + TScanType = (stNone, stPing, stAlive, stBoth); + TScanPurpose = (spNone, spNew, spFailed, spUserBridges, spAll, spNewAndFailed, spBridges, spAuto); + + TConfigFlag = (cfAutoAppend, cfAutoSave, cfFindComments, cfExistCheck, cfMultiLine, cfBoolInvert); + TConfigFlags = set of TConfigFlag; + + TBridgeType = (btNone, btList, btPrefer); + TBridgeTypes = set of TBridgeType; + + TProcessFlag = (pfHideWindow, pfReadStdOut); + TProcessFlags = set of TProcessFlag; + TProcessInfo = record + hProcess: THandle; + hStdOutput: THandle; + end; + + TStaticPair = record + Key: string; + Value: Integer; + end; + + TIPv4Range = record + IpStart: Cardinal; + IpEnd: Cardinal; + end; + + TSocket = record + Ip: string; + Port: Word; + end; + + TNodeData = record + NodeStr: string; + NodeID: TListType; + RangeData: TIPv4Range; + end; + ArrOfNodes = array of TNodeData; +var + CountryCodes: array [0..MAX_COUNTRIES - 1] of string = ( + 'au','at','az','ax','al','dz','as','ai','ao','ad','aq','ag','ar','am','aw', + 'af','bs','bd','bb','bh','bz','by','be','bj','bm','bg','bo','bq','ba','bw', + 'br','io','bn','bf','bi','bt','vu','va','gb','hu','ve','vg','vi','um','tl', + 'vn','ga','gy','ht','gm','gh','gp','gt','gf','gn','gw','de','gg','gi','hn', + 'hk','ps','gd','gl','gr','ge','gu','dk','cd','je','dj','dm','do','eg','zm', + 'zw','ye','il','in','id','jo','iq','ir','ie','is','es','it','cv','kz','kh', + 'cm','ca','qa','ke','cy','kg','ki','cn','kp','cc','co','km','cr','ci','cu', + 'kw','cw','la','lv','ls','lr','lb','ly','lt','li','lu','mu','mr','mg','yt', + 'mo','mk','mw','my','ml','mv','mt','ma','mq','mh','mx','fm','mz','md','mc', + 'mn','ms','mm','na','nr','np','ne','ng','nl','ni','nu','nz','nc','no','ae', + 'om','bv','im','nf','cx','ky','ck','pn','sh','pk','pw','pa','pg','py','pe', + 'pl','pt','pr','cg','kr','re','ru','rw','ro','eh','sv','ws','sm','st','sa', + 'sz','mp','sc','bl','sn','mf','pm','vc','kn','lc','rs','sg','sx','sy','sk', + 'si','sb','so','sd','sr','us','sl','tj','tw','th','tz','tc','tg','tk','to', + 'tt','tv','tn','tm','tr','ug','uz','ua','wf','uy','fo','fj','ph','fi','fk', + 'fr','pf','tf','hm','hr','cf','td','me','cz','cl','ch','se','sj','lk','ec', + 'gq','er','ee','et','za','gs','ss','jm','jp','??','eu'); + + PlotIntervals: array [0..8] of Integer = ( + 60, 300, 900, 1800, 3600, 10800, 21600, 43200, 86400 + ); + BridgeDistributions: array [0..4] of string = ( + 'any', 'https', 'email', 'moat', 'none' + ); + LogLevels: array [0..4] of string = ( + 'debug', 'info', 'notice', 'warn', 'err' + ); + PolicyTypes: array [0..3] of string = ( + 'accept', 'reject', 'accept6', 'reject6' + ); + MaskTypes: array [0..3] of string = ( + '*', '*4', '*6', 'private' + ); + DataSizes: array [0..4] of string = ( + 'b', 'byte', 'bytes', 'bit', 'bits' + ); + PrefixSizes: array [0..4] of string = ( + '', 'kilo', 'mega', 'giga', 'tera' + ); + PrefixShortSizes: array [0..4] of string = ( + '', 'k', 'm', 'g', 't' + ); + PrivateRanges: array [0..3] of string = ( + '192.168.0.0/16', + '172.16.0.0/12', + '169.254.0.0/16', + '10.0.0.0/8' + ); + DocRanges: array [0..2] of string = ( + '192.0.2.0/24', + '198.51.100.0/24', + '203.0.113.0/24' + ); + + CircuitPurposes: array[0..11] of TStaticPair = ( + (Key: 'GENERAL'; Value: GENERAL), + (Key: 'HS_CLIENT_HSDIR'; Value: HS_CLIENT_HSDIR), + (Key: 'HS_CLIENT_INTRO'; Value: HS_CLIENT_INTRO), + (Key: 'HS_CLIENT_REND'; Value: HS_CLIENT_REND), + (Key: 'HS_SERVICE_HSDIR'; Value: HS_SERVICE_HSDIR), + (Key: 'HS_SERVICE_INTRO'; Value: HS_SERVICE_INTRO), + (Key: 'HS_SERVICE_REND'; Value: HS_SERVICE_REND), + (Key: 'HS_VANGUARDS'; Value: HS_VANGUARDS), + (Key: 'PATH_BIAS_TESTING'; Value: PATH_BIAS_TESTING), + (Key: 'TESTING'; Value: TESTING), + (Key: 'CIRCUIT_PADDING'; Value: CIRCUIT_PADDING), + (Key: 'MEASURE_TIMEOUT'; Value: MEASURE_TIMEOUT) + ); + + CircuitStatuses: array[0..5] of TStaticPair = ( + (Key: 'LAUNCHED'; Value: LAUNCHED), + (Key: 'BUILT'; Value: BUILT), + (Key: 'GUARD_WAIT'; Value: GUARD_WAIT), + (Key: 'EXTENDED'; Value: EXTENDED), + (Key: 'FAILED'; Value: FAILED), + (Key: 'CLOSED'; Value: CLOSED) + ); + + StreamPurposes: array[0..4] of TStaticPair = ( + (Key: 'DIR_FETCH'; Value: DIR_FETCH), + (Key: 'DIR_UPLOAD'; Value: DIR_UPLOAD), + (Key: 'DIRPORT_TEST'; Value: DIRPORT_TEST), + (Key: 'DNS_REQUEST'; Value: DNS_REQUEST), + (Key: 'USER'; Value: USER) + ); + + StreamStatuses: array[0..9] of TStaticPair = ( + (Key: 'NEW'; Value: NEW), + (Key: 'NEWRESOLVE'; Value: NEWRESOLVE), + (Key: 'REMAP'; Value: REMAP), + (Key: 'SENTCONNECT'; Value: SENTCONNECT), + (Key: 'SENTRESOLVE'; Value: SENTRESOLVE), + (Key: 'SUCCEEDED'; Value: SUCCEEDED), + (Key: 'FAILED'; Value: FAILED), + (Key: 'CLOSED'; Value: CLOSED), + (Key: 'DETACHED'; Value: DETACHED), + (Key: 'CONTROLLER_WAIT'; Value: CONTROLLER_WAIT) + ); + +implementation + +end. diff --git a/source/Defaults.ini b/source/Defaults.ini new file mode 100644 index 0000000..369ff04 --- /dev/null +++ b/source/Defaults.ini @@ -0,0 +1,29 @@ +[Bridges] +obfs4.1=obfs4 192.68.11.218:80 D7AE9A9FDCA05666A7BFDD5650063658DE781F8F cert=B525/2egv4zTCq83lhsvm182R3qx/915gGiYX1+hCxvkYYtvbPXa9oB7a2eToww4T2StAQ iat-mode=0 +obfs4.2=obfs4 168.119.187.62:2352 A88F76AA71AA06692BD45A5548A4BC26E9332186 cert=SSOsJZ1mceeGp1D9JimzKoOrjINekaaCQBdEYb78OxzR7ah9Hf19id4irytCod5JPEbeOg iat-mode=0 +obfs4.3=obfs4 116.203.147.82:443 C36F6A3A74864124457257FA8662B2D5EF4F6D29 cert=qNFUCn+6Qj/RLQmgJa1WDbbEy2cGjPBnE9rC47UhWXoTmYkXy1BegVidM0Kt9z7JjHcUJw iat-mode=0 +obfs4.4=obfs4 103.214.6.254:443 9BA5E686B1FEB28C1A62AFE790FDBC8FBE06ECE6 cert=5AVdusnEQKYZ05LDoBtpYLitdqGt9JsQhJmO+ISV1RC+E21P5sSmcXE3xgL+fzIJHZB5Zw iat-mode=0 +obfs4.5=obfs4 104.244.75.82:443 E85E1DAF2819EF4BDA82EB67BA66799F2E171452 cert=dtIY9MpT0O1QEd4VBDjKN9e6QVxdA9xW+2x5GnPn/FrS2sfcYlxTXPmYFc3qRYt8XudWdA iat-mode=0 +obfs4.6=obfs4 5.189.170.3:10338 6412721889430C518D5B8D30BCAE026D96571953 cert=hrWOPQaUr6X+UehLBIMK2Qsh177jh1BeQLViwsFkMNWe0sr7QyHsUf2uLFGW8RlDeNQWeA iat-mode=0 +obfs4.7=obfs4 165.227.225.46:8060 E08E08BDD944C52080CBA44851F8D703BA8EC7DF cert=d9/EHfKcMdRYGcWt4/ktxSDHQxuEo2XR/XpTUKyUheizOhjLv8oL5aOnQP3dcWjtFQWBHA iat-mode=0 +obfs4.8=obfs4 95.217.45.150:8364 17D88EC9D3196D3C5CA126E85C41B2B28B58783C cert=ggBNji0pxQFTlZ4ShZufg597tPOG5w32XUeLx3tPmxch9AQ8hF50703oZWhJVBwNRGc0Xw iat-mode=0 +obfs4.9=obfs4 195.201.202.125:80 D44C0BC5AF900547704BCE5062E4B169672120E8 cert=frdxjWqogIf0Sl85YCOs4wJ6BG5F4RTbTsr5EveRB2FdyoWF8aXyy7ZzCil+E9dXaXO0UQ iat-mode=0 +obfs4.10=obfs4 68.183.36.57:23411 11A47B73E44EC752E77B9864D8A26D250613B642 cert=Jc9MHFAfavb/MmJYz5exrKC7es3lnFq+BOaOv6RgrQ3ALxD/bBmwyDQOi/njk115QK0YGw iat-mode=0 +obfs4.11=obfs4 85.209.48.139:42020 1E1011E5A7BBAA0FE974454228A682295B77F1C1 cert=mh9kD7LJ6BSef95P17J7SRz7qsTJXTPp8WPdTInuAoTLRBguYQ7UL77/dJEpI7ELVC1nSA iat-mode=0 +obfs4.12=obfs4 185.177.207.144:8443 A0A4E85A13F568B6D5BC6C8FFCCF53822DC0950E cert=ZQnVMVv33zlWv6YRYoNDDx8PhKn7yVn6zxJHZOV74saNwE1YQqcU/RlAhbYp+C0QDwtXDQ iat-mode=0 +obfs4.13=obfs4 146.59.95.211:8080 CE03E1E96035DE3BCC2491BF206B0DC0A9011B22 cert=dAwUHhP9BfJ3nmTeSDYaOWFBaBTf1iBJYxcmAHycMfIBKjERLGGnjaT1ZtzmOqAu8880bw iat-mode=0 +snowflake.1=snowflake 192.0.2.3:80 2B280B23E1107BB62ABFC40DDCC8824814F80A72 fingerprint=2B280B23E1107BB62ABFC40DDCC8824814F80A72 url=https://snowflake-broker.torproject.net.global.prod.fastly.net/ front=cdn.sstatic.net ice=stun:stun.l.google.com:19302,stun:stun.stunprotocol.org:3478,stun:stun.ipfire.org:3478,stun:stun.voipgate.com:3478 utls-imitate=hellorandomizedalpn +meek-azure.1=meek_lite 192.0.2.18:80 BE776A53492E1E044A26F17306E1BC46A55A1625 url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com + +[Transports] +0=snowflake|snowflake-client.exe|0 +1=meek_lite,scramblesuit|obfs4proxy.exe|0 +2=obfs4,obfs3,obfs2|obfs4proxy.exe|2 + +[UserOverrides] +BridgesBot=GetBridgesBot +BridgesEmail=bridges@torproject.org +BridgesSite=https://bridges.torproject.org/bridges +DownloadUrl=https://www.torproject.org/download/languages +MetricsUrl=https://metrics.torproject.org/rs.html +CheckUrl=https://check.torproject.org \ No newline at end of file diff --git a/source/Functions.pas b/source/Functions.pas new file mode 100644 index 0000000..4e1d0be --- /dev/null +++ b/source/Functions.pas @@ -0,0 +1,3368 @@ +unit Functions; + +interface + +uses + Winapi.Windows, Winapi.Messages, Winapi.ActiveX, Winapi.ShlObj, System.Classes, + Winapi.ShellApi, Winapi.WinSock, System.StrUtils, System.SysUtils, System.IniFiles, + System.Variants, System.Masks, System.DateUtils, System.Generics.Collections, System.Math, + System.Win.ComObj, System.Win.Registry, Vcl.Graphics, Vcl.Forms, Vcl.Controls, Vcl.Grids, + Vcl.Menus, Vcl.Imaging.pngimage, Vcl.ComCtrls, Vcl.StdCtrls, Vcl.Clipbrd, Vcl.Dialogs, + Vcl.Themes, synacode, blcksock, pingsend, synautil, ConstData, Addons; + +const + JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = $00002000; + CREATE_BREAKAWAY_FROM_JOB = $01000000; + +type + TBridge = record + Ip: string; + Port: Word; + Hash: string; + Transport: string; + Params: string; + end; + + TCharUpCaseTable = array [Char] of Char; + TPing = class(TPINGSend) + public + constructor Create(Timeout: Integer); + end; + TUserGrid = class(TCustomGrid); + +var + CharUpCaseTable: TCharUpCaseTable; + + function CreateJob(lpJobAttributes: PSecurityAttributes; lpName: LPCSTR): THandle; stdcall; + external 'kernel32.dll' name 'CreateJobObjectA'; + + function CompareNaturalText(psz1, psz2: PWideChar): Integer; stdcall; + external 'shlwapi.dll' name 'StrCmpLogicalW'; + + function BoolToStrDef(Value: Boolean): string; + function GetCommandLineFileName(const CommandLine: string): string; + function CheckSplitButton(Button: TButton): Boolean; + function GetAssocUpDown(AName: string): TUpdown; + function GetCountryValue(IpStr: string): Byte; + function GetIntDef(const Value, Default, Min, Max: Integer): Integer; + function GetPortProtocol(PortID: Word): string; + function GetFileVersionStr(const FileName: string): string; + function FindStr(Mask, Str: string): Boolean; + function CtrlKeyPressed(Key: Char): Boolean; + function GetArrayIndex(Data: array of string; Value: string): Integer; + function GetConstantIndex(Key: string): Integer; + function GetDefaultsValue(Key: string; Default: string = ''): string; + function GetSystemDir(CSIDL: Integer): string; + function RegistryFileExists(Root: HKEY; Key, Param: string): Boolean; + function RegistryGetValue(Root: HKEY; Key, Param: string): string; + function CreateShortcut(const CmdLine, Args, WorkDir, LinkFile, IconFile: string): IPersistFile; + function GetFullFileName(FileName: string): string; + function GetHost(SocksHost: TCombobox): string; + function GetAddressFromSocket(SocketStr: string): string; + function GetPortFromSocket(SocketStr: string): Word; + function FormatHost(HostStr: string): string; + function ExtractDomain(Url: string; HasPort: Boolean = False): string; + function GetAvailPhysMemory: Cardinal; + function GetCPUCount: Integer; + function AnsiStrToHex(const Value: AnsiString): string; + function StrToHex(Value: string): string; + function HexToStr(hex: string): string; + function AuthStageReady(AuthMethod: Integer): Boolean; + function Crypt(str, Key: string): string; + function Decrypt(str, Key: string): string; + function FileGetString(Filename: string; Hex: Boolean = False): string; + function ExecuteProcess(CmdLine: string; Flags: TProcessFlags = []; JobHandle: THandle = 0): TProcessInfo; + function RandomString(StrLen: Integer): string; + function GetPasswordHash(const password: string): string; + function CheckFileVersion(FileVersion, StaticVersion: string): Boolean; + function Explode(sPart, sInput: string): ArrOfStr; + function GetLogFileName(SeparateType: Integer): string; + function GetRoutersParamsCount(Mask: Integer): Integer; + function GetTorConfig(const Param, Default: string; Flags: TConfigFlags = []; ParamType: TParamType = ptString; MinValue: Integer = 0; MaxValue: Integer = 0; Prefix: string = ''): string; + function BytesFormat(Bytes: Double): string; + function FormatSizeToBytes(SizeStr: string): Int64; + function UTCToLocalTime(AValue: TDateTime): TDateTime; + function TorDateFormat(Date: string): string; + function CheckEditSymbols(Key: Char; UserSymbols: AnsiString = ''; EditMsg: string = ''): string; + function CheckEditString(Str: string; UserSymbols: AnsiString = ''; AllowNumbersFirst: Boolean = True; EditMsg: string = ''; edComponent: TEdit = nil): string; + function IsEmptyRow(aSg: TStringGrid; ARow: Integer): Boolean; + function IsEmptyGrid(aSg: TStringGrid): Boolean; + function IsDirectoryWritable(const Dir: string): Boolean; + function PortTCPIsOpen(Port: Word; IpStr: string; Timeout: Integer): Boolean; + function GetBridgeCert: string; + function InsensPosEx(const SubStr, S: string; Offset: Integer = 1): Integer; + function GetPrefixSize(Prefix: string; Localize: Boolean = False): Int64; + function ConvertSize(SizeStr: string; Prefix: string = ''): Int64; + function HasBrackets(Str: string): Boolean; + function IsIPv4(IpStr: string): Boolean; + function IsIPv6(IpStr: string): Boolean; + function GetNodeType(NodeStr: string): TListType; + function ValidData(Str: string; ListType: TListType): Boolean; + function ValidSize(SizeStr: string; Min, Max: Int64; Prefix: string): Boolean; + function ValidInt(IntStr: string; Min, Max: Integer): Boolean; overload; + function ValidInt(IntStr: string; Min, Max: Int64): Boolean; overload; + function ValidHash(HashStr: string): Boolean; + function ValidAddress(AddrStr: string; AllowCidr: Boolean = False; ReqBrackets: Boolean = False): Byte; + function ValidHost(HostStr: string; AllowRootDomain: Boolean = False; AllowIp: Boolean = True; ReqBrackets: Boolean = False): Boolean; + function ValidBridge(BridgeStr: string; BridgeType: TBridgeType): Boolean; + function ValidTransport(TransportStr: string): Boolean; + function ValidSocket(SocketStr: string; AllowHostNames: Boolean = False): Boolean; + function ValidPolicy(PolicyStr: string): Boolean; + function GetMsgCaption(Caption: string; MsgType: TMsgType): string; + function TryParseBridge(BridgeStr: string; out Bridge: TBridge): Boolean; + function IpToInt(IpStr: string): Cardinal; + function IntToIp(Ip: Cardinal): string; + function CidrToRange(CidrStr: string): TIPv4Range; + function IpInRanges(const IpStr: string; RangesData: array of string): Boolean; + function CompIntObjectAsc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; + function CompIntObjectDesc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; + function CompIntDesc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; + function CompIntAsc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; + function CompTextAsc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; + function CompTextDesc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; + function CompSizeAsc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; + function CompSizeDesc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; + function CompParamsAsc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; + function CompParamsDesc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; + function GetTaskBarPos: TTaskBarPos; + function SendPing(const Host: string; Timeout: Integer): Integer; + function RemoveBrackets(Str: string; Square: Boolean = False): string; + function SearchEdit(EditControl: TCustomEdit; const SearchString: String; Options: TFindOptions; FindFirst: Boolean = False): Boolean; + function ShowMsg(Msg: string; Caption: string = ''; MsgType: TMsgType = mtInfo; Question: Boolean = False): Boolean; + function MemoToLine(Memo: TMemo; ListType: TListType; Sorted: Boolean = False; Separator: string = ','): string; + function MenuToInt(Menu: TMenuItem): Integer; + function GetTransportID(TypeStr: string): Byte; + function GetTransportChar(TransportID: Byte): string; + function TryUpdateMask(var Mask: Byte; Param: Byte; Condition: Boolean): Boolean; + function TryGetDataFromStr(Str: string; DataType: TListType; out DatatStr: string): Boolean; + function SampleDown(Data: ArrOfPoint; Threshold: Integer): ArrOfPoint; + procedure DeleteDir(const DirName: string); + procedure LineToMemo(Line: string; Memo: TMemo; ListType: TListType; Sorted: Boolean = False; Separator: string = ','); + procedure IntToMenu(Menu: TMenuItem; Mask: Integer; DisableUnchecked: Boolean = False); + procedure GetNodes(var Nodeslist: string; NodeType: TNodeType; Favorites: Boolean; ini: TMemIniFile = nil); + procedure SetTorConfig(const Param, Value: string; Flags: TConfigFlags = []; Separator: string = '|'); + procedure DeleteTorConfig(const Param: string; Flags: TConfigFlags = []); + procedure SetConfigBoolean(Section, Ident: string; Value: Boolean); + procedure SetConfigInteger(Section, Ident: string; Value: Integer); overload; + procedure SetConfigInteger(Section, Ident: string; Value: Int64); overload; + procedure SetConfigString(Section, Ident: string; Value: string); + procedure SaveToLog(str: string; LogFile: string); + procedure AddUPnPEntry(Port: Integer; Desc, LanIp: string; Test: Boolean; var Msg: string); + procedure RemoveUPnPEntry(First: Integer; Second: Integer = 0; Third: Integer = 0); + procedure SetGridLastCell(aSg: TStringGrid; Show: Boolean = True; ScrollTop: Boolean = False; ManualSort: Boolean = False; ARow: Integer = -1; ACol: Integer = -1; FindCol: Integer = 0); + procedure ClearCol(aSg: TStringGrid; ACol: Integer); + procedure ClearRow(aSg: TStringGrid; ARow: Integer); + procedure ClearGrid(aSg: TStringGrid; DeleteBlankRows: Boolean = True); + procedure FindInGridColumn(aSg: TStringGrid; ACol: Integer; Key: Char); + procedure InitCharUpCaseTable(var Table: TCharUpCaseTable); + procedure DeleteARow(aSg: TStringGrid; ARow: Integer); + procedure CheckFileEncoding(FileName: string); + procedure CheckLabelEndEllipsis(lbComponent: TLabel; MaxWidth: Integer; EllipsisType: TEllipsisPosition; UseHint: Boolean; IgnoreFormSize: Boolean); + procedure BeginUpdateTable(aSg: TStringGrid); + procedure EndUpdateTable(aSg: TStringGrid); + procedure sgSort(aSg: TStringGrid; aCol: Integer; aCompare: TStringListSortCompare); + procedure SetDesktopPosition(Left, Top: Integer; CheckBorders: Boolean = True; SaveToVar: Boolean = False); + procedure GetLocalInterfaces(ComboBox: TComboBox; RecentHost: string = ''; IsSocksPort: Boolean = False); + procedure ComboBoxAutoWidth(const AComboBox: TCombobox); + procedure GridDrawIcon(aSg: TStringGrid; Rect: TRect; ls: TImageList; Index: Integer; W: Integer = 16; H: Integer = 16); + procedure GridDrawSortArrows(aSg: TStringGrid; Rect: TRect); + procedure GridSetKeyboardLayout(aSg: TStringGrid; ACol: Integer); + procedure GridSetFocus(aSg: TStringGrid); + procedure GridShowHints(aSg: TStringGrid); + procedure GridScrollCheck(aSg: TStringGrid; ACol, ColWidth: Integer); + procedure GridSelectCell(aSg: TStringGrid; ACol, ARow: Integer); + procedure GridKeyDown(aSg: TStringGrid; Shift: TShiftState; var Key: Word); + procedure GridCheckAutoPopup(aSg: TStringGrid; ARow: Integer; AllowEmptyRows: Boolean = False); + procedure GoToInvalidOption(PageID: TTabSheet; Msg: string = ''; edComponent: TCustomEdit = nil); + procedure DeleteDuplicatesFromList(List: TStringList); + procedure SortNodesList(ls: TStringList; DescSort: Boolean = False); + procedure ControlsDisable(Control: TWinControl); + procedure ControlsEnable(Control: TWinControl); + procedure LoadTorConfig; + procedure SaveTorConfig; + procedure LoadIconsFromResource(ImageList: TImageList; ResourceName: string); + procedure LoadThemesList(ThemesList: TComboBox; LastStyle: string); + procedure LoadStyle(ThemesList: TCombobox); + procedure EditMenuHandle(MenuType: TEditMenuType); + procedure EditMenuEnableCheck(MenuItem: TMenuItem; MenuType: TEditMenuType); + procedure MenuSelectPrepare(SelMenu: TMenuItem = nil; UnSelMenu: TMenuItem = nil; HandleDisabled: Boolean = False); + procedure ShellOpen(Url: string); + procedure LoadSettings(Section: string; UpDownControl: TUpDown; ini: TMemIniFile); overload; + procedure LoadSettings(Section: string; CheckBoxControl: TCheckBox; ini: TMemIniFile); overload; + procedure LoadSettings(Section: string; MenuControl: TMenuItem; ini: TMemIniFile; Default: Boolean = True); overload; + procedure LoadSettings(Section: string; ComboBoxControl: TComboBox; ini: TMemIniFile; Default: Integer = 0); overload; + procedure LoadSettings(Section: string; EditControl: TEdit; ini: TMemIniFile; UseSquareBrackets: Boolean = False); overload; + procedure LoadSettings(UpDownControl: TUpDown; Flags: TConfigFlags = []); overload; + procedure LoadSettings(CheckBoxControl: TCheckBox; Flags: TConfigFlags = []); overload; + procedure LoadSettings(MenuControl: TMenuItem; Flags: TConfigFlags = []; Default: Boolean = True); overload; + procedure EnableComposited(WinControl: TWinControl); + +implementation + +uses Main, Languages; + +constructor TPing.Create(Timeout: Integer); +begin + inherited Create; + FTimeout := Timeout; +end; + +function BoolToStrDef(Value: Boolean): string; +begin + if Value then + Result := '1' + else + Result := '0' +end; + +function SendPing(const Host: string; Timeout: Integer): Integer; +begin + with TPing.Create(Timeout) do + try + Result := -1; + if Ping(Host) then + if ReplyError = IE_NoError then + Result := PingTime; + finally + Free; + end; +end; + +function GetAssocUpDown(AName: string): TUpdown; +begin + Result := TUpdown(Tcp.FindComponent('ud' + copy(AName, 3))); +end; + +function GetCountryValue(IpStr: string): Byte; +var + GeoIpInfo: TGeoIpInfo; +begin + if GeoIpDic.TryGetValue(IpStr, GeoIpInfo) then + Result := GeoIpInfo.cc + else + Result := DEFAULT_COUNTRY_ID; +end; + +function GetArrayIndex(Data: array of string; Value: string): Integer; +var + i: Integer; +begin + for i := 0 to Length(Data) - 1 do + begin + if Data[i] = Value then + begin + Result := i; + Exit; + end; + end; + Result := -1; +end; + +function GetConstantIndex(Key: string): Integer; +var + Index: Integer; +begin + if ConstDic.TryGetValue(Key, Index) then + Result := Index + else + Result := -1; +end; + +function GetDefaultsValue(Key: string; Default: string = ''): string; +var + Value: string; +begin + if DefaultsDic.TryGetValue(Key, Value) then + begin + if Trim(Value) <> '' then + begin + Result := Value; + Exit; + end; + end; + Result := Default; +end; + +function FindStr(Mask, Str: string): Boolean; +begin + if not MatchesMask(Mask, '*[*?-!]*') then + Result := InsensPosEx(Mask, Str) <> 0 + else + Result := MatchesMask(Str, Mask); +end; + +procedure ShellOpen(Url: string); +var + Port: Word; + Address: string; +begin + if Url = '' then + Exit; + if (Pos('://', Url) <> 0) or (Pos(':\', Url) <> 0) or (Pos('mailto:', Url) = 1) then + ShellExecute(Application.Handle, 'open', PChar(Url), nil, nil, SW_NORMAL) + else + begin + Port := GetPortFromSocket(Url); + if Port = 0 then + Port := 80; + Address := ExtractDomain(Url, True); + ShellExecute(Application.Handle, 'open', PChar(GetPortProtocol(Port) + '://' + FormatHost(Address) + ':' + IntToStr(Port)), nil, nil, SW_NORMAL); + end; +end; + +procedure GridDrawIcon(aSg: TStringGrid; Rect: TRect; ls: TImageList; Index: Integer; W: Integer = 16; H: Integer = 16); +begin + ls.Draw(aSg.Canvas, Rect.Left + (Rect.Width - W) div 2, Rect.Top + (Rect.Height - H) div 2, Index, True); +end; + +procedure GridDrawSortArrows(aSg: TStringGrid; Rect: TRect); +begin + case aSg.SortType of + SORT_ASC: Tcp.lsMain.Draw(aSg.Canvas, Rect.Right - 14, Rect.Top + (Rect.Height - 16) div 2, 13, True); + SORT_DESC: Tcp.lsMain.Draw(aSg.Canvas, Rect.Right - 14, Rect.Top + (Rect.Height - 16) div 2, 14, True); + end; +end; + +procedure GridSetKeyboardLayout(aSg: TStringGrid; ACol: Integer); +var + EN_COLS, LOCALE_COLS: set of Byte; +begin + case aSg.Tag of + GRID_FILTER: + begin + EN_COLS := [0]; + LOCALE_COLS := [2]; + end; + GRID_ROUTERS: + begin + EN_COLS := [1]; + LOCALE_COLS := [4]; + end; + end; + if ACol in EN_COLS then + ActivateKeyboardLayout(1033, 0) + else + if ACol in LOCALE_COLS then + ActivateKeyboardLayout(CurrentLanguage, 0); +end; + +procedure GridSelectCell(aSg: TStringGrid; ACol, ARow: Integer); +begin + if not aSg.ScrollKeyDown then + begin + aSg.SelCol := ACol; + if aSg.Focused then + GridSetKeyboardLayout(aSg, ACol) + end + else + aSg.ScrollKeyDown := False; + aSg.SelRow := ARow; +end; + +procedure GridKeyDown(aSg: TStringGrid; Shift: TShiftState; var Key: Word); +var + i: Integer; +begin + if (ssCtrl in Shift) and (Key = 67) then + Clipboard.AsText := aSg.Cells[aSg.SelCol, aSg.SelRow]; + + if Key in [VK_PRIOR, VK_NEXT, VK_END, VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN] then + aSg.ScrollKeyDown := True + else + aSg.ScrollKeyDown := False; + + case Key of + VK_APPS: + begin + case aSg.Tag of + GRID_HS, GRID_HSP: GridCheckAutoPopup(aSg, aSg.Row, True); + else + GridCheckAutoPopup(aSg, aSg.Row); + end; + end; + VK_LEFT: + begin + Key := 0; + if (aSg.SelCol > 0) then + begin + if (aSg.ColWidths[aSg.SelCol - 1] > 0) then + dec(aSg.SelCol) + else + begin + for i := aSg.SelCol - 1 downto 0 do + begin + if (aSg.ColWidths[i] > 0) then + begin + aSg.SelCol := i; + Break; + end; + end; + end; + end; + aSg.Col := aSg.SelCol; + GridSetKeyboardLayout(aSg, aSg.SelCol) + end; + VK_RIGHT: + begin + Key := 0; + if (aSg.SelCol < aSg.ColCount - 1) then + begin + if aSg.ColWidths[aSg.SelCol + 1] > 0 then + inc(aSg.SelCol) + else + begin + for i := aSg.SelCol + 1 to aSg.ColCount - 1 do + begin + if (aSg.ColWidths[i] > 0) then + begin + aSg.SelCol := i; + Break; + end; + end; + end; + end; + aSg.Col := aSg.SelCol; + GridSetKeyboardLayout(aSg, aSg.SelCol) + end; + end; +end; + +procedure CheckLabelEndEllipsis(lbComponent: TLabel; MaxWidth: Integer; EllipsisType: TEllipsisPosition; UseHint: Boolean; IgnoreFormSize: Boolean); +begin + if ((FormSize = 0) or IgnoreFormSize) and (lbComponent.Canvas.TextWidth(lbComponent.Caption) > Round(MaxWidth * Scale)) then + begin + lbComponent.EllipsisPosition := EllipsisType; + lbComponent.Width := Round(MaxWidth * Scale); + if UseHint then + lbComponent.Hint := lbComponent.Caption; + end + else + begin + lbComponent.EllipsisPosition := epNone; + lbComponent.AutoSize := True; + if UseHint then + lbComponent.Hint := ''; + end; +end; + +procedure GridSetFocus(aSg: TStringGrid); +begin + if aSg.Focused then + Exit + else + begin + if aSg.CanFocus and (Tcp.FindDialog.Handle = 0) then + aSg.SetFocus; + end; +end; + +procedure GridShowHints(aSg: TStringGrid); +begin + if (aSg.MovCol > -1) and (aSg.Canvas.TextWidth(aSg.Cells[aSg.MovCol, aSg.MovRow]) + 2 > aSg.ColWidths[aSg.MovCol]) then + begin + aSg.Hint := aSg.Cells[aSg.MovCol, aSg.MovRow]; + Application.ActivateHint(Mouse.CursorPos); + end + else + begin + Application.CancelHint; + aSg.Hint := ''; + end; +end; + +procedure GridCheckAutoPopup(aSg: TStringGrid; ARow: Integer; AllowEmptyRows: Boolean = False); +begin + if not Assigned(aSg.PopupMenu) then + Exit; + if (ARow > 0) and (not IsEmptyRow(aSg, ARow) or AllowEmptyRows) then + aSg.PopupMenu.AutoPopup := True + else + aSg.PopupMenu.AutoPopup := False; +end; + +procedure InitCharUpCaseTable(var Table: TCharUpCaseTable); +var + n: cardinal; +begin + for n := 0 to Length(Table) - 1 do + Table[Char(n)] := Char(n); + CharUpperBuff(@Table, Length(Table)); +end; + +function InsensPosEx(const SubStr, S: string; Offset: Integer = 1): Integer; +var + n: Integer; + SubStrLength: Integer; + SLength: Integer; +label + Fail; +begin + Result := 0; + if S = '' then Exit; + if Offset <= 0 then Exit; + + SubStrLength := Length(SubStr); + SLength := Length(s); + + if SubStrLength > SLength then Exit; + + Result := Offset; + while SubStrLength <= (SLength - Result + 1) do + begin + for n := 1 to SubStrLength do + if CharUpCaseTable[SubStr[n]] <> CharUpCaseTable[s[Result+n-1]] then + goto Fail; + Exit; +Fail: + Inc(Result); + end; + Result := 0; +end; + +procedure ClearRow(aSg: TStringGrid; ARow: Integer); +var + i: Integer; +begin + for i := aSg.FixedCols to aSg.ColCount - 1 do + aSg.Cells[i, ARow] := ''; +end; + +procedure ClearCol(aSg: TStringGrid; ACol: Integer); +var + i: Integer; +begin + for i := aSg.FixedRows to aSg.RowCount - 1 do + aSg.Cells[ACol, i] := ''; +end; + +procedure ClearGrid(aSg: TStringGrid; DeleteBlankRows: Boolean = True); +var + i, j: Integer; +begin + for i := 1 to aSg.RowCount - 1 do + for j := 0 to aSg.ColCount - 1 do + aSg.Cells[j, i] := ''; + if DeleteBlankRows then + aSg.RowCount := 2; +end; + +function IsEmptyRow(aSg: TStringGrid; ARow: Integer): Boolean; +var + i: Integer; +begin + Result := True; + for i := 0 to aSg.ColCount - 1 do + if aSg.Cells[i, ARow] <> '' then + begin + Result := False; + Break; + end; +end; + +function IsEmptyGrid(aSg: TStringGrid): Boolean; +begin + if (aSg.RowCount = 2) and (IsEmptyRow(aSg, 1)) then + Result := True + else + Result := False; +end; + +procedure FindInGridColumn(aSg: TStringGrid; ACol: Integer; Key: Char); +var + i: Integer; +begin + if GetTickCount > SearchTimer + 1000 then + SearchStr := ''; + SearchStr := SearchStr + Key; + for i := 1 to aSg.RowCount - 1 do + if AnsiLowerCase(copy(aSg.Cells[ACol, i], 1, Length(SearchStr))) = SearchStr then + begin + aSg.Row := i; + aSg.Col := ACol; + SearchTimer := GetTickCount; + break; + end; +end; + +procedure GoToInvalidOption(PageID: TTabSheet; Msg: string = ''; edComponent: TCustomEdit = nil); +begin + if LastPlace <> 0 then + Tcp.sbShowOptions.Click; + Tcp.pcOptions.ActivePage := PageID; + if Msg <> '' then + begin + ShowMsg(Msg, TransStr('324'), mtWarning); + if Assigned(edComponent) and (edComponent.CanFocus) then + begin + edComponent.SetFocus; + edComponent.SelectAll; + end; + end; + SetConfigInteger('Main', 'LastPlace', LastPlace); + SetConfigInteger('Main', 'OptionsPage', PageID.TabIndex); +end; + +function CheckEditString(Str: string; UserSymbols: AnsiString = ''; AllowNumbersFirst: Boolean = True; EditMsg: string = ''; edComponent: TEdit = nil): string; +var + i: Integer; + Temp: string; + ParentBox: TGroupBox; +begin + Result := ''; + ParentBox := nil; + if Assigned(edComponent) then + begin + if edComponent.GetParentComponent is TGroupBox then + begin + ParentBox := TGroupBox(edComponent.GetParentComponent); + EditMsg := TTabSheet(ParentBox.GetParentComponent).Caption + ' - ' + ParentBox.Caption + ' - ' + EditMsg + BR + BR + end + else + EditMsg := TTabSheet(edComponent.GetParentComponent).Caption + ' - ' + EditMsg + BR + BR; + end; + if Length(Str) > 0 then + begin + if not AllowNumbersFirst and ValidInt(Str[1], 0, MAXINT) then + begin + Result := TransStr('398'); + end; + + if Result = '' then + begin + for i := 1 to Length(Str) do + begin + Temp := CheckEditSymbols(Str[i], UserSymbols, EditMsg); + if Temp <> '' then + begin + Result := Temp; + Break; + end; + end; + end; + + end; + if Assigned(edComponent) and (Result <> '') then + begin + if Assigned(ParentBox) then + GoToInvalidOption(TTabSheet(ParentBox.GetParentComponent), Result, edComponent) + else + GoToInvalidOption(TTabSheet(edComponent.GetParentComponent), Result, edComponent); + end; +end; + +function CheckEditSymbols(Key: Char; UserSymbols: AnsiString = ''; EditMsg: string = ''): string; +var + i: Integer; + UserCharSet: TSysCharSet; + UserMsg: string; +begin + UserMsg := EditMsg + TransStr('269'); + UserCharSet := []; + if UserSymbols <> '' then + begin + UserMsg := StringReplace(UserMsg, ' ' + TransStr('270') + ' ', ', ', []) + ' ' + TransStr('270') + ' '; + for i := 1 to Length(UserSymbols) do + begin + Include(UserCharSet, UserSymbols[i]); + UserMsg := UserMsg + Char(UserSymbols[i]); + end; + end; + if not CharInSet(Key, ['0'..'9', 'A'..'Z', 'a'..'z', #8]) and + not CharInSet(Key, UserCharSet) then + Result := UserMsg + else + Result := ''; +end; + +function MenuToInt(Menu: TMenuItem): Integer; +var + i: Integer; +begin + Result := 0; + for i := 0 to Menu.Count - 1 do + if Menu.Items[i].AutoCheck and Menu.Items[i].Checked then + Inc(Result, Menu.Items[i].Tag); +end; + +procedure IntToMenu(Menu: TMenuItem; Mask: Integer; DisableUnchecked: Boolean = False); +var + i: Integer; + Max, Default: Integer; +begin + Default := 0; + Max := 0; + case Menu.Tag of + 1: begin Default := SHOW_NODES_FILTER_DEFAULT; Max := SHOW_NODES_FILTER_MAX; end; + 2: begin Default := ROUTER_FILTER_DEFAULT; Max := ROUTER_FILTER_MAX; end; + 3: begin Default := CIRCUIT_FILTER_DEFAULT; Max := CIRCUIT_FILTER_MAX;end; + 4,5: begin Default := TPL_MENU_DEFAULT; Max := TPL_MENU_MAX; end; + end; + if (Mask < 0) or (Mask > Max) then + Mask := Default; + for i := Menu.Count - 1 downto 0 do + begin + if Menu.Items[i].AutoCheck then + begin + if Mask and Menu.Items[i].Tag <> 0 then + begin + Menu.Items[i].Checked := True; + Menu.Items[i].Enabled := True; + Dec(Mask, Menu.Items[i].Tag); + end + else + begin + Menu.Items[i].Checked := False; + Menu.Items[i].Enabled := not DisableUnchecked; + end; + end; + + end; +end; + +procedure MenuSelectPrepare(SelMenu: TMenuItem = nil; UnSelMenu: TMenuItem = nil; HandleDisabled: Boolean = False); +var + i: Integer; + SelCount, UnSelCount, EnableCount: Integer; + Parent: TMenuItem; +begin + + if Assigned(SelMenu) then + Parent := SelMenu.Parent + else + if Assigned(UnSelMenu) then + Parent := UnSelMenu.Parent + else + Exit; + + SelCount := 0; + UnSelCount := 0; + EnableCount := 0; + + for i := 0 to Parent.Count - 1 do + begin + if Parent.Items[i].AutoCheck and (Parent.Items[i].Enabled or HandleDisabled) then + begin + Inc(EnableCount); + if Parent.Items[i].Checked then + Inc(SelCount) + else + Inc(UnSelCount); + end; + end; + if Assigned(SelMenu) then + begin + SelMenu.Enabled := (EnableCount > 0) and (UnSelCount > 0); + SelMenu.Tag := 1; + SelMenu.HelpContext := Integer(HandleDisabled); + end; + if Assigned(UnSelMenu) then + begin + UnSelMenu.Enabled := (EnableCount > 0) and (SelCount > 0); + UnSelMenu.Tag := 0; + UnSelMenu.HelpContext := Integer(HandleDisabled); + end; + +end; + +function TorDateFormat(Date: string): string; +var + fs: TFormatSettings; +begin + fs.DateSeparator := '-'; + fs.ShortDateFormat := 'yyyy-MM-dd'; + fs.TimeSeparator := ':'; + fs.ShortTimeFormat := 'hh:mm'; + fs.LongTimeFormat := 'hh:mm:ss'; + Result := DateTimeToStr(UTCToLocalTime(StrToDateTime(Date, fs))); +end; + +function UTCToLocalTime(AValue: TDateTime): TDateTime; +var + ST1, ST2: TSystemTime; + TZ: TTimeZoneInformation; +begin + GetTimeZoneInformation(TZ); + DateTimeToSystemTime(AValue, ST1); + SystemTimeToTzSpecificLocalTime(@TZ, ST1, ST2); + Result := SystemTimeToDateTime(ST2); +end; + +function LocalTimeToUTC(AValue: TDateTime): TDateTime; +var + ST1, ST2: TSystemTime; + TZ: TTimeZoneInformation; +begin + GetTimeZoneInformation(TZ); + TZ.Bias := -TZ.Bias; + TZ.StandardBias := -TZ.StandardBias; + TZ.DaylightBias := -TZ.DaylightBias; + DateTimeToSystemTime(AValue, ST1); + SystemTimeToTzSpecificLocalTime(@TZ, ST1, ST2); + Result := SystemTimeToDateTime(ST2); +end; + +function HasBrackets(Str: string): Boolean; +begin + Result := (Str[1] = '[') and (Str[Length(Str)] = ']'); +end; + +function RemoveBrackets(Str: string; Square: Boolean = False): string; +begin + if Square then + begin + Result := StringReplace(Str, '[', '', [rfReplaceAll]); + Result := StringReplace(Result, ']', '', [rfReplaceAll]); + end + else + begin + Result := StringReplace(Str, '{', '', [rfReplaceAll]); + Result := StringReplace(Result, '}', '', [rfReplaceAll]); + end; +end; + +procedure GetNodes(var Nodeslist: string; NodeType: TNodeType; Favorites: Boolean; ini: TMemIniFile = nil); +var + Count, i: Integer; + Nodes: ArrOfStr; + FilterInfo: TFilterInfo; + FNodeType: TNodeTypes; + NodeStr: string; + lbComponent: TLabel; +begin + Count := 0; + if Nodeslist <> '' then + begin + if Favorites then + begin + Nodes := Explode(',', AnsiUpperCase(StringReplace(RemoveBrackets(Nodeslist), '$', '', [rfReplaceAll]))); + for i := 0 to Length(Nodes) - 1 do + begin + if ValidData(Nodes[i], ltNode) then + begin + if Length(Nodes[i]) = 2 then + Nodes[i] := AnsiLowerCase(Nodes[i]); + if Pos('/', Nodes[i]) <> 0 then + RangesDic.AddOrSetValue(Nodes[i], CidrToRange(Nodes[i])); + NodesDic.TryGetValue(Nodes[i], FNodeType); + Include(FNodeType, NodeType); + NodesDic.AddOrSetValue(Nodes[i], FNodeType); + Inc(Count); + end + else + Nodes[i] := ''; + end; + lbComponent := Tcp.GetFavoritesLabel(Byte(NodeType)); + if (lbComponent.Tag = 0) and (lbComponent.HelpContext = 0) and (Count > 0) then + lbComponent.HelpContext := 1; + lbComponent.Tag := Count; + end + else + begin + Nodes := Explode(',', AnsiLowerCase(RemoveBrackets(Nodeslist))); + for i := 0 to Length(Nodes) - 1 do + begin + if FilterDic.TryGetValue(Nodes[i], FilterInfo) then + begin + Include(FilterInfo.Data, NodeType); + FilterDic.AddOrSetValue(Nodes[i], FilterInfo); + Inc(Count); + end + else + Nodes[i] := ''; + end; + end; + if (ini <> nil) and (Length(Nodes) <> Count) then + begin + Nodeslist := ''; + NodeStr := ''; + for i := 0 to Length(Nodes) - 1 do + if Nodes[i] <> '' then + begin + if Length(Nodes[i]) = 2 then + Nodes[i] := '{' + Nodes[i] + '}'; + Nodeslist := Nodeslist + ',' + Nodes[i]; + end; + Delete(Nodeslist, 1, 1); + case NodeType of + ntEntry: NodeStr := 'EntryNodes'; + ntMiddle: NodeStr := 'MiddleNodes'; + ntExit: NodeStr := 'ExitNodes'; + ntExclude: NodeStr := 'ExcludeNodes'; + end; + if Favorites then + ini.WriteString('Routers', NodeStr, Nodeslist) + else + ini.WriteString('Filter', NodeStr, Nodeslist); + end; + end; +end; + +function BytesFormat(Bytes: Double): string; +var + i: Integer; +begin + i := 0; + while Bytes > 1024 do + begin + Bytes := Bytes / 1024; + inc(i); + end; + Result := FloatToStrF(Bytes, ffFixed, 4, 1) + ' ' + Prefixes[i]; +end; + +function FormatSizeToBytes(SizeStr: string): Int64; +begin + Result := Round(GetPrefixSize(SeparateRight(SeparateLeft(SizeStr, '/'), ' '), True) * StrToFloatDef(SeparateLeft(SizeStr, ' '), 0.0)); +end; + +function GetHost(SocksHost: TCombobox): string; +begin + if SocksHost.Text = '0.0.0.0' then + Result := '127.0.0.1' + else + Result := SocksHost.Text; +end; + +function GetAvailPhysMemory: Cardinal; +var + MS: TMemoryStatusEx; +begin + MS.dwLength := SizeOf(MS); + GlobalMemoryStatusEx(MS); + Result := Round(MS.ullAvailPhys / 1024 / 1024); +end; + +function GetCPUCount: Integer; +var + s: TSystemInfo; +begin + GetSystemInfo(s); + Result := s.dwNumberOfProcessors; +end; + +function AnsiStrToHex(const Value: AnsiString): string; +var + i: Integer; +begin + Result := ''; + for i := 1 to Length(Value) do + Result := Result + IntToHex(Byte(Value[i]), 2); +end; + +function StrToHex(Value: string): string; +var + i: Integer; + c: Char; +begin + Result := ''; + for i := 1 to Length(Value) do + begin + c := Value[i]; + Result := Result + IntToHex(Integer(c), 2); ; + end; +end; + +function HexToStr(hex: string): string; +var + i: Integer; +begin + for i := 1 to Length(hex) div 2 do + Result := Result + Char(StrToInt('$' + copy(hex, (i - 1) * 2 + 1, 2))); +end; + +function Crypt(str, Key: string): string; +var + i, T: Integer; +begin + if (str = '') or (Key = '') then + Exit; + for i := 1 to Length(str) do + begin + T := (ord(str[i]) + (ord(Key[(pred(i) mod Length(Key)) + 1]) - ord('0'))); + str[i] := Char(T); + end; + Result := StrToHex(str); +end; + +function Decrypt(str, Key: string): string; +var + i, T: Integer; +begin + if (str = '') or (Key = '') then + Exit; + str := HexToStr(str); + for i := 1 to Length(str) do + begin + T := (ord(str[i]) - (ord(Key[(pred(i) mod Length(Key)) + 1]) - ord('0'))); + str[i] := Chr(T); + end; + Result := str; +end; + +function FileGetString(Filename: string; Hex: Boolean = False): string; +var + Buf: array of Byte; + F: File of Byte; + FSize, i: Integer; + Str: string; +begin + if FileExists(Filename) then + begin + AssignFile(F, Filename); + try + Reset(F); + FSize := FileSize(F); + SetLength(Buf, FSize); + BlockRead(F, Buf[0], FSize); + finally + Closefile(F); + end; + for i := 0 to FSize - 1 do + Str := Str + Chr(Buf[i]); + end; + if Hex then + Result := StrToHex(Str) + else + Result := Str; +end; + +function AuthStageReady(AuthMethod: Integer): Boolean; +var + Time: TDateTime; +begin + Result := False; + if AuthMethod = 1 then + Result := True + else + begin + if FileAge(UserDir + 'control_auth_cookie', Time) = True then + begin + if LastAuthCookieDate <> Time then + Result := True; + end; + end; +end; + +function ExecuteProcess(CmdLine: string; Flags: TProcessFlags = []; JobHandle: THandle = 0): TProcessInfo; +var + hStdOutRead, hStdOutWrite: THandle; + SA: SECURITY_ATTRIBUTES; + SI: STARTUPINFO; + PI: PROCESS_INFORMATION; + CreationFlags: Cardinal; +begin + Result.hProcess := 0; + Result.hStdOutput := 0; + UniqueString(CmdLine); + SA.nLength := SizeOf(SECURITY_ATTRIBUTES); + SA.bInheritHandle := True; + SA.lpSecurityDescriptor := nil; + if pfReadStdOut in Flags then + if not CreatePipe(hStdOutRead, hStdOutWrite, @SA, BUFSIZE) then + Exit; + FillChar(SI, SizeOf(SI), 0); + SI.cb := SizeOf(SI); + if pfReadStdOut in Flags then + SI.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES + else + SI.dwFlags := STARTF_USESHOWWINDOW; + if pfReadStdOut in Flags then + SI.hStdOutput := hStdOutWrite; + if pfHideWindow in Flags then + SI.wShowWindow := SW_HIDE + else + SI.wShowWindow := SW_SHOWDEFAULT; + if JobHandle <> 0 then + CreationFlags := CREATE_BREAKAWAY_FROM_JOB + else + CreationFlags := 0; + if CreateProcess(nil, PWideChar(CmdLine), nil, nil, True, CreationFlags, nil, nil, SI, PI) then + begin + if JobHandle <> 0 then + AssignProcessToJobObject(JobHandle, PI.hProcess); + if pfReadStdOut in Flags then + Result.hStdOutput := hStdOutRead; + Result.hProcess := PI.hProcess; + end; + if pfReadStdOut in Flags then + CloseHandle(hStdOutWrite); + CloseHandle(PI.hThread); +end; + +function RandomString(StrLen: Integer): string; +var + Str: string; +begin + Result := ''; + str := 'abcdefghijklmnopqrstuvwxyz' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + '0123456789'; + Randomize; + repeat + Result := Result + str[Random(Length(str)) + 1]; + until (Length(Result) = StrLen) +end; + +function GetPasswordHash(const password: string): string; +var + tmp, hash, salt: string; + count: Integer; +begin + if password = '' then + Exit; + salt := RandomString(8); + count := (16 + (96 and 15)) shl ((96 shr 4) + 6); + tmp := salt + password; + while count > 0 do + begin + if count > Length(tmp) then + begin + insert(tmp, hash, Length(hash) + 1); + count := count - Length(tmp); + end + else + begin + insert(copy(tmp, 0, count), hash, Length(hash) + 1); + count := 0; + end; + end; + salt := salt + Chr(96); + Result := '16:' + StrToHex(salt) + AnsiStrToHex(SHA1(AnsiString(hash))); +end; + +function Explode(sPart, sInput: string): ArrOfStr; +begin + Result := nil; + while Pos(sPart, sInput) <> 0 do + begin + SetLength(Result, Length(Result) + 1); + Result[Length(Result) - 1] := copy(sInput, 0, Pos(sPart, sInput) - 1); + Delete(sInput, 1, Pos(sPart, sInput)); + end; + SetLength(Result, Length(Result) + 1); + Result[Length(Result) - 1] := sInput; +end; + +function GetLogFileName(SeparateType: Integer): string; +var + FileName: string; +begin + case SeparateType of + 1: FileName := FormatDateTime('yyyy-mm', Now); + 2: FileName := FormatDateTime('yyyy-mm-dd', Now); + else + FileName := 'console'; + end; + Result := LogsDir + FileName + '.log'; +end; + +procedure SaveToLog(str: string; LogFile: string); +var + log: TextFile; +begin + AssignFile(log, LogFile); +{$i-} + if FileExists(LogFile) then + Append(log) + else + Rewrite(log); +{$i+} + WriteLn(log, str); + Closefile(log); +end; + +procedure DeleteDir(const DirName: string); +var + Path: string; + F: TSearchRec; +begin + Path:= DirName + '\*.*'; + if FindFirst(Path, faAnyFile, F) = 0 then + begin + try + repeat + if (F.Attr and faDirectory <> 0) then + begin + if (F.Name <> '.') and (F.Name <> '..') then + DeleteDir(DirName + '\' + F.Name); + end + else + DeleteFile(DirName + '\' + F.Name); + until FindNext(F) <> 0; + finally + FindClose(F); + end; + end; + RemoveDir(DirName); +end; + +function GetIntDef(const Value, Default, Min, Max: Integer): Integer; +begin + if InRange(Value, Min, Max) then + Result := Value + else + Result := Default; +end; + +procedure LoadSettings(Section: string; EditControl: TEdit; ini: TMemIniFile; UseSquareBrackets: Boolean = False); +var + Str: string; +begin + if FirstLoad then + EditControl.ResetValue := EditControl.Text; + Str := ini.ReadString(Section, StringReplace(EditControl.Name, 'ed', '', [rfIgnoreCase]), EditControl.ResetValue); + + if UseSquareBrackets then + EditControl.Text := RemoveBrackets(Str, True) + else + EditControl.Text := Str; +end; + +procedure LoadSettings(Section: string; ComboBoxControl: TComboBox; ini: TMemIniFile; Default: Integer = 0); +var + Value: Integer; +begin + if FirstLoad then + ComboBoxControl.ResetValue := Default; + + Value := ini.ReadInteger(Section, StringReplace(ComboBoxControl.Name, 'cbx', '', [rfIgnoreCase]), Default); + if InRange(Value, 0, ComboBoxControl.Items.Count - 1) then + ComboBoxControl.ItemIndex := Value + else + ComboBoxControl.ItemIndex := Default; +end; + +procedure LoadSettings(Section: string; UpDownControl: TUpDown; ini: TMemIniFile); +var + Value: Integer; + Ident: string; +begin + if FirstLoad then + UpDownControl.ResetValue := UpDownControl.Position; + Ident := StringReplace(UpDownControl.Name, 'ud', '', [rfIgnoreCase]); + + Value := ini.ReadInteger(Section, Ident, UpDownControl.ResetValue); + if InRange(Value, UpDownControl.Min, UpDownControl.Max) then + UpDownControl.Position := Value + else + UpDownControl.Position := UpDownControl.ResetValue; +end; + +procedure LoadSettings(UpDownControl: TUpDown; Flags: TConfigFlags = []); +begin + if FirstLoad then + UpDownControl.ResetValue := UpDownControl.Position; + UpDownControl.Position := StrToInt(GetTorConfig(StringReplace(UpDownControl.Name, 'ud', '', [rfIgnoreCase]), IntToStr(UpDownControl.ResetValue), Flags, ptInteger, UpDownControl.Min, UpDownControl.Max)); +end; + +procedure LoadSettings(Section: string; CheckBoxControl: TCheckBox; ini: TMemIniFile); +begin + if FirstLoad then + CheckBoxControl.ResetValue := CheckBoxControl.Checked; + CheckBoxControl.Checked := ini.ReadBool(Section, StringReplace(CheckBoxControl.Name, 'cb', '', [rfIgnoreCase]), CheckBoxControl.ResetValue) +end; + +procedure LoadSettings(CheckBoxControl: TCheckBox; Flags: TConfigFlags = []); +begin + if FirstLoad then + CheckBoxControl.ResetValue := CheckBoxControl.Checked; + CheckBoxControl.Checked := StrToBool(GetTorConfig(StringReplace(CheckBoxControl.Name, 'cb', '', [rfIgnoreCase]), BoolToStrDef(CheckBoxControl.ResetValue), Flags, ptBoolean)); +end; + +procedure LoadSettings(Section: string; MenuControl: TMenuItem; ini: TMemIniFile; Default: Boolean = True); +begin + MenuControl.Checked := ini.ReadBool(Section, StringReplace(MenuControl.Name, 'mi', '', [rfIgnoreCase]), Default) +end; + +procedure LoadSettings(MenuControl: TMenuItem; Flags: TConfigFlags = []; Default: Boolean = True); +begin + MenuControl.Checked := StrToBool(GetTorConfig(StringReplace(MenuControl.Name, 'mi', '', [rfIgnoreCase]), BoolToStrDef(Default), Flags, ptBoolean)); +end; + +procedure LoadTorConfig; +var + i: Integer; +begin + if Assigned(TorConfig) then + Exit + else + begin + TorConfig := TStringList.Create; + if FileExists(TorConfigFile) then + TorConfig.LoadFromFile(TorConfigFile, EncodingNoBom); + for i := 0 to TorConfig.Count - 1 do + TorConfig[i] := Trim(TorConfig[i]); + end; +end; + +procedure SaveTorConfig; +var + i: Integer; +begin + LoadTorConfig; + for i := TorConfig.Count - 1 downto 0 do + if (i <> 1) and (TorConfig[i] = '') then + TorConfig.Delete(i); + TorConfig.SaveToFile(TorConfigFile, EncodingNoBom); + FreeAndNil(TorConfig); + FileAge(TorConfigFile, LastTorrcDate); +end; + +function GetTorConfig(const Param, Default: string; Flags: TConfigFlags = []; ParamType: TParamType = ptString; MinValue: Integer = 0; MaxValue: Integer = 0; Prefix: string = ''): string; +var + i, p, ParamSize, CommentPos: Integer; + ls: TStringList; + Values: set of Byte; + Search: Boolean; + + procedure Reset; + begin + if (Default <> '') and (GetDefaultsValue(Param) <> Default) then + TorConfig[i] := Param + ' ' + Default + else + TorConfig[i] := ''; + Result := Default; + end; + +begin + LoadTorConfig; + + if cfFindComments in Flags then + Values := [1,2,3] + else + Values := [1]; + Search := False; + + if cfMultiLine in Flags then + ls := TStringList.Create + else + ls := nil; + + for i := 0 to TorConfig.Count - 1 do + begin + p := InsensPosEx(Param + ' ', TorConfig[i]); + Search := p in Values; + if Search then + begin + if cfExistCheck in Flags then + begin + Result := '1'; + Exit; + end; + ParamSize := Length(Param); + CommentPos := Pos('#', TorConfig[i]); + if CommentPos > p + ParamSize then + Result := Trim(copy(TorConfig[i], p + ParamSize + 1, CommentPos - ParamSize - 2)) + else + Result := Trim(copy(TorConfig[i], p + ParamSize + 1, Length(TorConfig[i]) - ParamSize - 1)); + case ParamType of + ptString: + if (MinValue > 0) or (MaxValue > 0) then + begin + ParamSize := Length(Result); + if (ParamSize < MinValue) or (ParamSize > MaxValue) then + Reset; + end; + ptInteger: + if not ValidInt(Result, MinValue, MaxValue) then + Reset; + ptBoolean: + begin + if not ValidInt(Result, 0, 1) then + Reset + else + begin + if cfBoolInvert in Flags then + Result := BoolToStrDef(not StrToBool(Result)); + end; + end; + ptSocket: + if not ValidSocket(Result, Boolean(MinValue)) then + Reset; + ptHost: + if not ValidHost(Result, False, True, Boolean(MinValue)) then + Reset; + ptSize: + if not ValidSize(Result, MinValue, MaxValue, Prefix) then + Reset; + ptBridge: + if not ValidBridge(Result, btList) then + begin + TorConfig[i] := ''; + Continue; + end; + end; + if cfMultiLine in Flags then + begin + if Result <> '' then + ls.Append(Result) + end + else + Break; + end; + end; + + if cfMultiLine in Flags then + begin + if ls.Count = 0 then + Result := Default + else + begin + Result := ''; + DeleteDuplicatesFromList(ls); + for i := 0 to ls.Count - 1 do + Result := Result + '|' + ls[i]; + Delete(Result, 1, 1); + end; + ls.Free; + end + else + begin + if not Search then + begin + Result := Default; + if cfAutoAppend in Flags then + TorConfig.Append(Param + ' ' + Default); + end; + end; + + if cfAutoSave in Flags then + SaveTorConfig; +end; + +procedure SetTorConfig(const Param, Value: string; Flags: TConfigFlags = []; Separator: string = '|'); +var + i, p: Integer; + Values: set of Byte; + ParseStr: ArrOfStr; +begin + LoadTorConfig; + if cfMultiLine in Flags then + begin + if Value <> '' then + begin + ParseStr := Explode(Separator, Value); + for i := 0 to Length(ParseStr) - 1 do + if ParseStr[i] <> '' then + TorConfig.Append(Param + ' ' + ParseStr[i]); + end + else + DeleteTorConfig(Param, [cfMultiLine]); + end + else + begin + p := 0; + if cfFindComments in Flags then + Values := [1,2,3] + else + Values := [1]; + for i := TorConfig.Count - 1 downto 0 do + begin + p := InsensPosEx(Param + ' ', TorConfig[i]); + if p in Values then + Break; + end; + if p in Values then + begin + if (Value <> '') and (GetDefaultsValue(Param) <> Value) then + TorConfig[i] := Param + ' ' + Value + else + TorConfig.Delete(i); + end + else + begin + if (Value <> '') and (GetDefaultsValue(Param) <> Value) then + TorConfig.Append(Param + ' ' + Value); + end; + end; + if cfAutoSave in Flags then + SaveTorConfig; +end; + +procedure DeleteTorConfig(const Param: string; Flags: TConfigFlags = []); +var + i,j: Integer; + Values: set of Byte; + ParseStr: ArrOfStr; +begin + LoadTorConfig; + if cfFindComments in Flags then + Values := [1,2,3] + else + Values := [1]; + ParseStr := Explode(',', Param); + for i := TorConfig.Count - 1 downto 0 do + begin + for j := 0 to Length(ParseStr) - 1 do + begin + if InsensPosEx(ParseStr[j] + ' ', TorConfig[i]) in Values then + begin + TorConfig.Delete(i); + if not (cfMultiLine in Flags) then + Break; + end; + end; + end; + if cfAutoSave in Flags then + SaveTorConfig; +end; + +procedure SetConfigBoolean(Section, Ident: string; Value: Boolean); +var + ini: TMemIniFile; +begin + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + ini.WriteBool(Section, Ident, Value); + finally + ini.UpdateFile; + ini.Free; + end; +end; + +procedure SetConfigInteger(Section, Ident: string; Value: Int64); overload; +var + ini: TMemIniFile; +begin + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + ini.WriteInteger(Section, Ident, Value); + finally + ini.UpdateFile; + ini.Free; + end; +end; + +procedure SetConfigInteger(Section, Ident: string; Value: Integer); overload; +var + ini: TMemIniFile; +begin + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + ini.WriteInt64(Section, Ident, Value); + finally + ini.UpdateFile; + ini.Free; + end; +end; + +procedure SetConfigString(Section, Ident: string; Value: string); +var + ini: TMemIniFile; +begin + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + ini.WriteString(Section, Ident, Value); + finally + ini.UpdateFile; + ini.Free; + end; +end; + +procedure DeleteDuplicatesFromList(List: TStringList); +var + ls: TDictionary; + i: Integer; +begin + ls := TDictionary.Create; + try + for i := List.Count - 1 downto 0 do + begin + if ls.ContainsKey(List[i]) then + List.Delete(i) + else + ls.AddOrSetValue(List[i], 0); + end; + finally + ls.Free; + end; +end; + +procedure SortNodesList(ls: TStringList; DescSort: Boolean = False); +var + i: Integer; + Hashes, Addresses, CountryCodes: TStringList; +begin + Addresses := TStringList.Create; + CountryCodes := TStringList.Create; + Hashes := TStringList.Create; + try + for i := 0 to ls.Count - 1 do + begin + if ValidHash(ls[i]) then + Hashes.Append(ls[i]) + else + begin + if FilterDic.ContainsKey(AnsiLowerCase(ls[i])) then + CountryCodes.Append(ls[i]) + else + Addresses.Append(ls[i]) + end; + end; + Addresses.CustomSort(CompTextAsc); + CountryCodes.Sort; + Hashes.Sort; + ls.Clear; + if DescSort then + begin + ls.AddStrings(Hashes); + ls.BeginUpdate; + try + for i := Addresses.Count - 1 downto 0 do + ls.AddObject(Addresses[i], Addresses.Objects[i]); + for i := CountryCodes.Count - 1 downto 0 do + ls.AddObject(CountryCodes[i], CountryCodes.Objects[i]); + finally + ls.EndUpdate; + end; + end + else + begin + ls.AddStrings(CountryCodes); + ls.AddStrings(Addresses); + ls.AddStrings(Hashes); + end; + finally + Hashes.Free; + Addresses.Free; + CountryCodes.Free; + end; +end; + +function GetNodeType(NodeStr: string): TListType; +begin + Result := ltNoCheck; + if Length(NodeStr) < 2 then + Exit; + if ValidHash(NodeStr) then + Result := ltHash + else + begin + if ValidAddress(NodeStr, True) = 1 then + begin + if Pos('/', NodeStr) <> 0 then + Result := ltCidr + else + Result := ltIp; + end + else + begin + if FilterDic.ContainsKey(AnsiLowerCase(NodeStr)) then + Result := ltCode + end; + end; +end; + +function ValidData(Str: string; ListType: TListType): Boolean; +begin + case ListType of + ltHost: Result := ValidHost(Str, True, True); + ltHash: Result := ValidHash(Str); + ltPolicy: Result := ValidPolicy(Str); + ltBridge: Result := ValidBridge(Str, btList); + ltNode: Result := ValidHash(Str) or (ValidAddress(Str, True, True) = 1) or FilterDic.ContainsKey(AnsiLowerCase(Str)); + ltSocket: Result := ValidSocket(Str); + ltTransport: Result := ValidTransport(Str); + else + Result := True; + end; +end; + +procedure LineToMemo(Line: string; Memo: TMemo; ListType: TListType; Sorted: Boolean = False; Separator: string = ','); +var + ParseStr: ArrOfStr; + i: Integer; + ls: TStringList; + Str: string; +begin + ParseStr := Explode(Separator, Line); + Memo.Tag := Length(ParseStr); + if (Memo.Tag = 1) and (Trim(ParseStr[0]) = '') then + Memo.Tag := 0; + ls := TStringList.Create; + try + if ListType = ltNoCheck then + begin + if Memo.Tag <> 0 then + for i := 0 to Length(ParseStr) - 1 do + ls.Append(ParseStr[i]); + end + else + begin + for i := 0 to Length(ParseStr) - 1 do + begin + Str := Trim(ParseStr[i]); + if Str <> '' then + begin + if ValidData(Str, ListType) then + begin + if ListType = ltNode then + begin + if Length(Str) = 2 then + Str := AnsiUpperCase(Str); + end; + ls.Append(Str); + end; + end; + end; + DeleteDuplicatesFromList(ls); + if Sorted then + begin + if ListType = ltNode then + SortNodesList(ls) + else + ls.CustomSort(CompTextAsc); + end; + end; + Memo.Text := ls.Text; + finally + ls.Free; + end; +end; + +function MemoToLine(Memo: TMemo; ListType: TListType; Sorted: Boolean = False; Separator: string = ','): string; +var + ls: TStringList; + i: Integer; + Str: string; +begin + ls := TStringList.Create; + try + if ListType = ltNoCheck then + ls.Text := Memo.Text + else + begin + ls.Text := StringReplace(Memo.Text, ',', BR, [rfReplaceAll]); + if ListType = ltNode then + ls.Text := RemoveBrackets(ls.Text); + for i := ls.Count - 1 downto 0 do + begin + Str := Trim(ls[i]); + if Str = '' then + ls.Delete(i) + else + begin + case ListType of + ltHost: Str := ExtractDomain(Str); + ltHash: Str := AnsiUpperCase(Str); + ltPolicy: Str := AnsiLowerCase(Str); + ltNode: Str := AnsiUpperCase(Str); + end; + if not ValidData(Str, ListType) then + ls.Delete(i) + else + ls[i] := Str; + end; + end; + DeleteDuplicatesFromList(ls); + if Sorted then + begin + if ListType = ltNode then + SortNodesList(ls) + else + ls.CustomSort(CompTextAsc); + end; + Memo.Text := ls.Text; + end; + Result := ''; + for i := 0 to ls.Count - 1 do + Result := Result + Separator + ls[i]; + Delete(Result, 1, Length(Separator)); + finally + ls.Free; + end; +end; + +procedure AddUPnPEntry(Port: Integer; Desc, LanIp: string; Test: Boolean; var Msg: string); +var + Nat: OleVariant; + Ports: OleVariant; +begin + try + Nat := CreateOleObject('HNetCfg.NATUPnP'); + Ports := Nat.StaticPortMappingCollection; + if not VarIsClear(Ports) then + begin + Ports.Add(Port, 'TCP', Port, LanIp, True, Desc); + if Test then + begin + Msg := Msg + LanIp + ' : ' + inttostr(Port) + ' - ' + TransStr('245') + BR; + if ConnectState = 0 then + Ports.Remove(Port, 'TCP'); + end; + end; + except + on E:Exception do + Exit + end; +end; + +procedure RemoveUPnPEntry(First: Integer; Second: Integer = 0; Third: Integer = 0); +var + Nat: Variant; + Ports: Variant; +begin + if (First = 0) and (Second = 0) and (Third = 0) then + Exit; + try + Nat := CreateOleObject('HNetCfg.NATUPnP'); + Ports := Nat.StaticPortMappingCollection; + if not VarIsClear(Ports) then + begin + if First > 0 then + Ports.Remove(First, 'TCP'); + if Second > 0 then + Ports.Remove(Second, 'TCP'); + if Third > 0 then + Ports.Remove(Third, 'TCP'); + end; + except + on E:Exception do + Exit; + end; +end; + +function IsDirectoryWritable(const Dir: string): Boolean; +var + TempFile: array[0..MAX_PATH] of Char; +begin + if GetTempFileName(PChar(Dir), 'Tmp', 0, TempFile) <> 0 then + Result := DeleteFile(TempFile) + else + Result := False; +end; + +function GetFullFileName(FileName: string): string; +var + ppshf: IShellFolder; + lpItemID: PItemIDList; + NumChars: Cardinal; + Flags: Cardinal; + s: array[0..MAX_PATH] of Char; + P: PWideChar; +begin + NumChars := Length(FileName); + Flags := SFGAO_FILESYSTEM; + SHGetDesktopFolder(ppshf); + P := StringToOleStr(FileName); + ppshf.ParseDisplayName(Application.Handle, nil, P, NumChars, lpItemID, Flags); + ShGetPathFromIDList(lpItemID, s); + SetString(Result, s, StrLen(s)); +end; + +function CreateShortcut(const CmdLine, Args, WorkDir, LinkFile, IconFile: string): IPersistFile; +var + MyObject: IUnknown; + MySLink: IShellLink; + MyPFile: IPersistFile; + WideFile: WideString; +begin + MyObject := CreateComObject(CLSID_ShellLink); + MySLink := MyObject as IShellLink; + MyPFile := MyObject as IPersistFile; + with MySLink do + begin + SetPath(PChar(CmdLine)); + SetIconLocation(PChar(IconFile), 0 ); + SetArguments(PChar(Args)); + SetWorkingDirectory(PChar(WorkDir)); + end; + WideFile := LinkFile; + MyPFile.Save(PWideChar(WideFile), false); + Result := MyPFile; +end; + +function GetSystemDir(CSIDL: Integer): string; +var + Dir: array[0..MAX_PATH] of WideChar; +begin + if SHGetFolderPath(0, CSIDL, 0, SHGFP_TYPE_CURRENT, @Dir) = S_OK then + Result := Dir; +end; + +function GetCommandLineFileName(const CommandLine: string): string; +var + Count: Integer; + Args: PPWideChar; + DataStr: array[0..MAX_PATH] of WideChar; +begin + Args := CommandLineToArgvW(PWideChar(CommandLine), Count); + if Assigned(Args) and (Count > 0) then + begin + if ExpandEnvironmentStrings(Args^, DataStr, MAX_PATH) > 0 then + Result := DataStr + else + Result := Args^; + Exit; + end; + Result := ''; +end; + +function RegistryFileExists(Root: HKEY; Key, Param: string): Boolean; +begin + Result := FileExists(GetCommandLineFileName(RegistryGetValue(Root, Key, Param))); +end; + +function RegistryGetValue(Root: HKEY; Key, Param: string): string; +var + Reg: TRegistry; +begin + Result := ''; + Reg := TRegistry.Create; + try + Reg.RootKey := Root; + Reg.OpenKey(Key, False); + case Reg.GetDataType(Param) of + rdInteger: Result := IntToStr(Reg.ReadInteger(Param)); + rdString, rdExpandString: Result := Reg.ReadString(Param); + end; + Reg.CloseKey; + finally + Reg.Free; + end; +end; + +function TryGetDataFromStr(Str: string; DataType: TListType; out DatatStr: string): Boolean; +var + i: Integer; + ParseStr: ArrOfStr; +begin + if Str <> '' then + begin + ParseStr := Explode(' ', Str); + for i := 0 to Length(ParseStr) - 1 do + begin + if ValidData(ParseStr[i], DataType) then + begin + Result := True; + DatatStr := ParseStr[i]; + Exit; + end; + end; + end; + Result := False; + DatatStr := ''; +end; + +function PortTCPIsOpen(Port: Word; IpStr: string; Timeout: Integer): Boolean; +var + Socket: TTCPBlockSocket; +begin + Socket := TTCPBlockSocket.Create; + Socket.ConnectionTimeout := Timeout; + Socket.SetLinger(True, 0); + try + Socket.Connect(IpStr, IntToStr(Port)); + Result := Socket.LastError = 0; + CloseSocket(Socket.Socket); + finally + Socket.Free; + end; +end; + +function GetBridgeCert: string; +var + ls: TStringList; + i, p: Integer; + Bridgeline: string; +begin + Result := ''; + ls := TStringList.Create; + try + Bridgeline := UserDir + 'pt_state\obfs4_bridgeline.txt'; + if FileExists(Bridgeline) then + begin + ls.LoadFromFile(Bridgeline, EncodingNoBom); + for i := ls.Count - 1 downto 0 do + begin + p := Pos('cert=', ls[i]); + if (p <> 0) then + begin + Result := Trim(copy(ls[i], p)); + break; + end; + end; + end; + finally + ls.Free; + end; +end; + +function GetMsgCaption(Caption: string; MsgType: TMsgType): string; +begin + if Caption = '' then + begin + case MsgType of + mtInfo: + Result := TransStr('235'); + mtWarning: + Result := TransStr('246'); + mtError: + Result := TransStr('247'); + mtQuestion: + Result := TransStr('262'); + end; + end + else + Result := Caption; +end; + +function ShowMsg(Msg: string; Caption: string = ''; MsgType: TMsgType = mtInfo; Question: Boolean = False): Boolean; +var + MsgCode, MsgButtons, MsgResult: Integer; +begin + MsgCode := 0; + case MsgType of + mtInfo: + MsgCode := MB_ICONINFORMATION; + mtWarning: + MsgCode := MB_ICONWARNING; + mtError: + MsgCode := MB_ICONERROR; + mtQuestion: + MsgCode := MB_ICONQUESTION; + end; + if Question then + begin + MsgButtons := MB_YESNO; + MsgResult := IDYES; + end + else + begin + MsgButtons := MB_OK; + MsgResult := ID_OK; + end; + + if MessageBox(Application.Handle, PChar(Msg), PChar(GetMsgCaption(Caption, MsgType)), MsgButtons + MsgCode) = MsgResult then + Result := True + else + Result := False; +end; + +procedure DeleteARow(aSg: TStringGrid; ARow: Integer); +begin; + if aSg.RowCount = 2 then + ClearGrid(aSg) + else + begin + ClearRow(aSg, ARow); + TUserGrid(aSg).DeleteRow(ARow); + end; +end; + +procedure CheckFileEncoding(FileName: string); +var + AStream: TFileStream; + Options: TStringList; + Hdr: string; +begin + if not FileExists(FileName) then + Exit; + Hdr := ''; + AStream := TFileStream.Create(FileName, fmOpenRead); + try + AStream.Seek(0,soFromBeginning); + SetLength(Hdr, 2); + AStream.ReadBuffer(Hdr[1], 3); + if StrToHex(Hdr) = 'BBEFBF' then + Exit; + finally + AStream.Free; + end; + Options := TStringList.Create; + try + Options.LoadFromFile(FileName); + Options.SaveToFile(FileName, TEncoding.UTF8); + finally + Options.Free; + end; +end; + +function CompIntObjectAsc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; +begin + Result := CompareValue(Integer(aSl.Objects[aIndex1]), Integer(aSl.Objects[aIndex2])); +end; + +function CompIntObjectDesc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; +begin + Result := CompareValue(Integer(aSl.Objects[aIndex2]), Integer(aSl.Objects[aIndex1])); +end; + +function CompIntAsc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; +begin + Result := CompareValue(StrToIntDef(aSl[aIndex1], 0), StrToIntDef(aSl[aIndex2], 0)); +end; + +function CompIntDesc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; +begin + Result := CompareValue(StrToIntDef(aSl[aIndex2], 0), StrToIntDef(aSl[aIndex1], 0)); +end; + +function CompTextAsc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; +begin + Result := CompareNaturalText(PWideChar(aSl[aIndex1]), PWideChar(aSl[aIndex2])); +end; + +function CompTextDesc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; +begin + Result := CompareNaturalText(PWideChar(aSl[aIndex2]), PWideChar(aSl[aIndex1])); +end; + +function CompSizeAsc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; +begin + Result := CompareValue(FormatSizeToBytes(aSl[aIndex1]), FormatSizeToBytes(aSl[aIndex2])); +end; + +function CompSizeDesc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; +begin + Result := CompareValue(FormatSizeToBytes(aSl[aIndex2]), FormatSizeToBytes(aSl[aIndex1])); +end; + +function CompParamsAsc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; +begin + Result := CompareValue(RoutersDic.Items[aSl[aIndex1]].Params, RoutersDic.Items[aSl[aIndex2]].Params); +end; + +function CompParamsDesc(aSl: TStringList; aIndex1, aIndex2: Integer) : Integer; +begin + Result := CompareValue(RoutersDic.Items[aSl[aIndex2]].Params, RoutersDic.Items[aSl[aIndex1]].Params); +end; + +procedure SgSort(aSg: TStringGrid; aCol: Integer; aCompare: TStringListSortCompare); +var + SlSort, SlRow: TStringList; + i, j: Integer; +begin + SlSort := TStringList.Create; + for i := aSg.FixedRows to aSg.RowCount - 1 do + begin + SlRow := TStringList.Create; + SlRow.Assign(aSg.Rows[i]); + SlSort.AddObject(aSg.Cells[aCol, i], SlRow); + end; + SlSort.CustomSort(aCompare); + j := 0; + for i := aSg.FixedRows to aSg.RowCount - 1 do + begin + SlRow := Pointer(SlSort.Objects[j]); + aSg.Rows[i].Assign(SlRow); + SlRow.Free; + Inc(j); + end; + FreeAndNil(SlSort); +end; + +procedure SetGridLastCell(aSg: TStringGrid; Show: Boolean = True; ScrollTop: Boolean = False; ManualSort: Boolean = False; ARow: Integer = -1; ACol: Integer = -1; FindCol: Integer = 0); +var + RowIndex, ColIndex: Integer; +begin + if ARow = -1 then + begin + if ScrollTop and ManualSort then + RowIndex := 1 + else + RowIndex := aSg.Cols[FindCol].IndexOf(aSg.RowID); + end + else + RowIndex := ARow; + + if not (goRowSelect in aSg.Options) then + begin + if aSg.Row = RowIndex then + begin + if (RowIndex = 1) and (aSg.RowCount > 2) then + aSg.Row := RowIndex + 1 + else + if aSg.RowCount > 2 then + aSg.Row := RowIndex - 1; + end; + end; + + if (RowIndex > 0) then + begin + if ACol > -1 then + ColIndex := ACol + else + ColIndex := aSg.SelCol; + TUserGrid(aSg).MoveColRow(ColIndex, RowIndex, True, Show); + end; +end; + +procedure BeginUpdateTable(aSg: TStringGrid); +var + i: Integer; +begin + for i := 0 to aSg.ColCount - 1 do + aSg.Cols[i].BeginUpdate; +end; + +procedure EndUpdateTable(aSg: TStringGrid); +var + i: Integer; +begin + for i := 0 to aSg.ColCount - 1 do + aSg.Cols[i].EndUpdate; +end; + +function GetTaskBarPos: TTaskBarPos; +var + hTaskbar: HWND; + T: TRect; + ScrW, ScrH: Integer; +begin + Result := tbNone; + hTaskbar := FindWindow('Shell_TrayWnd', nil); + if hTaskbar <> 0 then + begin + GetWindowRect(hTaskbar, T); + ScrW := Screen.Width; + ScrH := Screen.Height; + if (T.Top > ScrH div 2) and (T.Right >= ScrW) then + Result := tbBottom + else if (T.Top < ScrH div 2) and (T.Bottom <= ScrW div 2) then + Result := tbTop + else if (T.Left < ScrW div 2) and (T.Top <= 0) then + Result := tbLeft + else if T.Left >= ScrW div 2 then + Result := tbRight; + end; +end; + +procedure SetDesktopPosition(Left, Top: Integer; CheckBorders: Boolean = True; SaveToVar: Boolean = False); +var + TP: TTaskBarPos; +begin + if (Left = -1) and (Top = -1) then + begin + Left := Round((Screen.Width - Tcp.Width) / 2); + Top := Round((Screen.Height - Tcp.Height) / 2); + end + else + begin + if CheckBorders or FirstLoad then + begin + TP := GetTaskBarPos; + if Left < Screen.WorkAreaLeft then + Left := Screen.WorkAreaLeft + 5 + else + if Left > Screen.WorkAreaWidth - Tcp.Width then + begin + if TP = tbLeft then + Left := Screen.Width - Tcp.Width - 5 + else + Left := Screen.WorkAreaWidth - Tcp.Width - 5; + end; + + if Top < Screen.WorkAreaTop then + Top := Screen.WorkAreaTop + 5 + else + if Top > Screen.WorkAreaHeight - Tcp.Height then + begin + if TP = tbTop then + Top := Screen.Height - Tcp.Height - 5 + else + Top := Screen.WorkAreaHeight - Tcp.Height - 5; + end; + end; + end; + if not (FirstLoad and (FormSize = 1)) then + begin + Tcp.Left := Left; + Tcp.Top := Top; + end; + + if SaveToVar then + begin + if FormSize = 0 then + begin + DecFormPos.X := Left; + DecFormPos.Y := Top; + end + else + begin + IncFormPos.X := Left; + IncFormPos.Y := Top; + end; + end; +end; + +procedure LoadThemesList(ThemesList: TComboBox; LastStyle: string); +var + Search: TSearchRec; + ls: TStringList; + Index: Integer; +begin + if LastStyle = 'Windows' then + LastStyle := TransStr('104') + else + if LastStyle = '' then + LastStyle := ThemesList.Text; + ls := TStringList.Create; + try + ls.Append(TransStr('104')); + if FindFirst(ThemesDir + '*.vsf', faAnyFile, Search) = 0 then + begin + try + repeat + if (Search.Attr and faDirectory = 0)then + ls.Append(Copy(Search.Name, 1, RPos('.', Search.Name) - 1)); + until FindNext(Search) <> 0; + finally + FindClose(Search); + end; + end; + ThemesList.Items := ls; + Index := ThemesList.Items.IndexOf(LastStyle); + if Index = -1 then + ThemesList.ItemIndex := 0 + else + ThemesList.ItemIndex := Index; + finally + ls.Free; + end; + ComboBoxAutoWidth(ThemesList); +end; + +procedure LoadStyle(ThemesList: TCombobox); +var + SI: TStyleInfo; + i: Integer; + FileName, StyleName: string; +begin + if ThemesList.ItemIndex = 0 then + TStyleManager.SetStyle(TStyleManager.SystemStyle) + else + begin + FileName := ThemesDir + ThemesList.Text + '.vsf'; + if not FileExists(FileName) then + Exit; + if TStyleManager.IsValidStyle(FileName, SI) then + begin + if TStyleManager.ActiveStyle.Name <> SI.Name then + begin + if TStyleManager.Style[SI.Name] = nil then + TStyleManager.LoadFromFile(FileName); + TStyleManager.SetStyle(TStyleManager.Style[SI.Name]); + end; + end; + end; + for i := Length(TStyleManager.StyleNames) - 1 downto 0 do + begin + StyleName := TStyleManager.StyleNames[i]; + if (StyleName <> 'Windows') and (StyleName <> TStyleManager.ActiveStyle.Name) then + TStyleManager.RemoveStyle(StyleName); + end; +end; + +procedure GetLocalInterfaces(ComboBox: TComboBox; RecentHost: string = ''; IsSocksPort: Boolean = False); +var + i, Index: Integer; + ls: TStringList; + TcpSock: TTCPBlockSocket; +begin + Index := 0; + if RecentHost = '' then + RecentHost := Combobox.Text + else + RecentHost := RemoveBrackets(RecentHost, True); + ls := TStringList.Create; + try + TcpSock := TTCPBlockSocket.create; + try + TcpSock.ResolveNameToIP(TcpSock.LocalName, ls); + finally + TcpSock.Free; + end; + for i := ls.Count - 1 downto 0 do + if (Tcp.cbHideIPv6Addreses.Checked and (not IsIPv4(ls[i])) or (Pos('%', ls[i]) <> 0)) then + ls.Delete(i); + if IsSocksPort then + begin + ComboBox.ResetValue := 1; + ls.Insert(0, '0.0.0.0'); + Index := 1; + end; + if ls.IndexOf('127.0.0.1') = -1 then + ls.Insert(Index, '127.0.0.1'); + if not Tcp.cbHideIPv6Addreses.Checked then + begin + if ls.IndexOf('::1') = -1 then + ls.Insert(Index + 1, '::1'); + end; + ComboBox.items := ls; + ComboBox.ItemIndex := ComboBox.Items.IndexOf(RecentHost); + if ComboBox.ItemIndex = -1 then + begin + if IsSocksPort then + begin + ComboBox.ItemIndex := 1; + SetTorConfig('SOCKSPort', '127.0.0.1:' + IntToStr(Tcp.udSOCKSPort.Position) + ComboBox.Hint); + end + else + ComboBox.ItemIndex := 0; + end; + ComboBoxAutoWidth(ComboBox); + finally + ls.Free; + end; +end; + +function ExtractDomain(Url: string; HasPort: Boolean = False): string; +var + Search: Integer; +begin + Result := AnsiLowerCase(Url); + Search := Pos('@', Result); + if Search > 0 then + Delete(Result, 1, Search) + else + begin + Search := Pos('://', Result); + if Search > 0 then + Delete(Result, 1, Search + 2); + end; + Search := Pos('/', Result); + if Search > 0 then + SetLength(Result, Pred(Search)); + Search := RPos(':', Result); + if (Search > 0) then + begin + if (Result[1] = '[') and (Result[Search - 1] = ']') then + SetLength(Result, Pred(Search)) + else + if (Search = Pos(':', Result)) or HasPort then + SetLength(Result, Pred(Search)); + Result := RemoveBrackets(Result, True); + end; + Search := Pos('.$', Result); + if Search > 0 then + SetLength(Result, Pred(Search)); +end; + +function GetAddressFromSocket(SocketStr: string): string; +var + Search: Integer; +begin + Search := RPos(':', SocketStr); + if Search > 0 then + Result := RemoveBrackets(Copy(SocketStr, 1, Search - 1), True) + else + Result := SocketStr; +end; + +function GetPortFromSocket(SocketStr: string): Word; +begin + Result := StrToIntDef(Copy(SocketStr, RPos(':', SocketStr) + 1), 0); +end; + +function FormatHost(HostStr: string): string; +begin + if IsIPv6(HostStr) then + Result := '[' + HostStr + ']' + else + Result := HostStr; +end; + +function GetPrefixSize(Prefix: string; Localize: Boolean = False): Int64; +var + Index: Integer; +begin + if Localize then + ConstDic.TryGetValue(Prefix, Index) + else + begin + if Length(Prefix) > 1 then + Index := GetArrayIndex(PrefixSizes, Prefix) + else + Index := GetArrayIndex(PrefixShortSizes, Prefix) + end; + case Index of + 0: Result := Int64(1); + 1: Result := Int64(1) shl 10; + 2: Result := Int64(1) shl 20; + 3: Result := Int64(1) shl 30; + 4: Result := Int64(1) shl 40; + else + Result := -1; + end; +end; + +function ConvertSize(SizeStr: string; Prefix: string = ''): Int64; +var + Search: Integer; + ParseStr: ArrOfStr; + Value: Int64; + XPrefix, XPostfix: string; +begin + Result := -1; + ParseStr := Explode(' ', AnsiLowerCase(SizeStr)); + if TryStrToInt64(ParseStr[0], Value) then + begin + case Length(ParseStr) of + 1: + Result := Value; + 2: + begin + Search := Pos('b', ParseStr[1]); + if Search > 0 then + begin + XPrefix := Copy(ParseStr[1], 1, Search - 1); + XPostfix := Copy(ParseStr[1], Search); + case GetArrayIndex(DataSizes, XPostfix) of + 0,1,2: Result := Value * GetPrefixSize(XPrefix); + 3,4: Result := Trunc(Value/8) * GetPrefixSize(XPrefix); + else + Exit; + end; + end; + end; + else + Exit; + end; + if Prefix <> '' then + Result := Trunc(Result/GetPrefixSize(Prefix)); + end; +end; + +function ValidSize(SizeStr: string; Min, Max: int64; Prefix: string): Boolean; +begin + Result := ValidInt(IntToStr(ConvertSize(SizeStr, Prefix)), Min, Max); +end; + +function ValidInt(IntStr: string; Min, Max: Integer): Boolean; overload; +var + n: Integer; +begin + if TryStrToInt(IntStr, n) then + begin + if (n >= Min) and (n <= Max) then + begin + Result := True; + Exit; + end; + end; + Result := False; +end; + +function ValidInt(IntStr: string; Min, Max: Int64): Boolean; overload; +var + n: Int64; +begin + if TryStrToInt64(IntStr, n) then + if (n >= Min) and (n <= Max) then + begin + Result := True; + Exit; + end; + Result := False; +end; + +function ValidHash(HashStr: string): Boolean; +var + i: Integer; +begin + Result := False; + if Length(HashStr) = 40 then + begin + for i := 1 to Length(HashStr) do + if not CharInSet(HashStr[i], ['0'..'9', 'A'..'F']) then + Exit; + Result := True; + end; +end; + +function IsIPv4(IpStr: string): Boolean; +var + ParseStr: ArrOfStr; + n, i: Integer; +begin + Result := False; + ParseStr := Explode('.', IpStr); + if Length(ParseStr) <> 4 then + Exit; + for i := 0 to 3 do + begin + if TryStrToInt(ParseStr[i], n) then + begin + if (n < 0) or (n > 255) then + Exit; + if ParseStr[i][1] = '$' then + Exit; + if ParseStr[i][1] = '-' then + Exit; + if ParseStr[i][1] = '0' then + begin + if n <> 0 then + Exit + else + if ParseStr[i][2] = '0' then + Exit; + end; + end + else + Exit; + end; + Result := True; +end; + +function IsIPv6(IpStr: string): Boolean; +var + Parts, Words: ArrOfStr; + Flag: Boolean; + i, j, n, WordCount, PartsCount, Totals: Integer; +begin + Result := False; + Flag := False; + IpStr := StringReplace(IpStr, '::', '|', [rfReplaceAll]); + Parts := Explode('|', IpStr); + PartsCount := Length(Parts); + if PartsCount > 2 then + Exit; + Totals := 0; + for i := 0 to PartsCount - 1 do + begin + if Parts[i] = '' then + Continue; + Words := Explode(':', Parts[i]); + WordCount := Length(Words); + for j := 0 to WordCount - 1 do + begin + if TryStrToInt('$' + Words[j], n) then + begin + if (n < 0) or (n > 65535) then + Exit; + end + else + begin + if (j = WordCount - 1) and (i = PartsCount - 1) and IsIPv4(Words[j]) then + Flag := True + else + Exit; + end; + end; + Inc(Totals, WordCount); + end; + if not Assigned(Words) then + Exit; + if Flag then + Inc(Totals); + case PartsCount of + 1: if Totals <> 8 then Exit; + 2: if (Totals + 1) > 8 then Exit; + end; + Result := True; +end; + +function ValidAddress(AddrStr: string; AllowCidr: Boolean = False; ReqBrackets: Boolean = False): Byte; +var + Search: Integer; + Mask: Byte; + IpStr: string; +begin + Result := 0; + Search := Pos('/', AddrStr); + if Search = 0 then + begin + if IsIPv4(AddrStr) then + Result := 1 + else + begin + if ReqBrackets then + begin + if not HasBrackets(AddrStr) then + Exit; + if IsIPv6(Copy(AddrStr, 2, Length(AddrStr) - 2)) then + Result := 2; + end + else + if IsIPv6(AddrStr) then + Result := 2; + end; + end + else + begin + if AllowCidr then + begin + IpStr := Copy(AddrStr, 1, Search - 1); + if IsIPv4(IpStr) then + Mask := 32 + else + begin + if ReqBrackets then + begin + if not HasBrackets(IpStr) then + Exit; + IpStr := Copy(IpStr, 2, Length(IpStr) - 2); + end; + if IsIPv6(IpStr) then + Mask := 128 + else + Exit; + end; + if ValidInt(Copy(AddrStr, Search + 1), 1, Mask) then + begin + case Mask of + 32: Result := 1; + 128: Result := 2; + end; + end; + end; + end; +end; + +function ValidHost(HostStr: string; AllowRootDomain: Boolean = False; AllowIp: Boolean = True; ReqBrackets: Boolean = False): Boolean; +var + i, j, SubLen, Count: Integer; + SubDomains: ArrOfStr; +begin + Result := False; + if AllowRootDomain and (HostStr = '.') then + begin + Result := True; + Exit; + end; + if ValidAddress(HostStr, False, ReqBrackets) <> 0 then + begin + if AllowIp then + begin + Result := True; + Exit; + end + else + Exit; + end; + if Length(HostStr) > 255 then + Exit; + SubDomains := Explode('.', HostStr); + Count := Length(SubDomains); + if Count < 2 then + Exit; + for i := 0 to Count - 1 do + begin + if (i = 0) and (SubDomains[i] = '') then + begin + if AllowRootDomain then + continue + else + Exit; + end; + SubLen := Length(SubDomains[i]); + if ((SubLen < 2) and (i >= Count - 2)) or (SubLen > 63) then + Exit; + for j := 1 to SubLen do + begin + if ((j = 1) or (j = SubLen)) and not CharInSet(SubDomains[i][j], ['0'..'9', 'a'..'z']) then + Exit + else + if not CharInSet(SubDomains[i][j], ['0'..'9', 'a'..'z', '-']) then + Exit; + end; + end; + if SubDomains[Count - 1] = 'exit' then + Exit; + if SubDomains[Count - 1] = 'onion' then + Exit; + Result := True; +end; + +function ValidSocket(SocketStr: string; AllowHostNames: Boolean = False): Boolean; +var + Search: Integer; +begin + Result := False; + Search := RPos(':', SocketStr); + if Search = 0 then + Exit; + if AllowHostNames then + Result := ValidHost(Copy(SocketStr, 1, Search - 1), False, True, True) + else + Result := ValidAddress(Copy(SocketStr, 1, Search - 1), False, True) <> 0; + if Result then + if not ValidInt(Copy(SocketStr, Search + 1), 1, 65535) then + Result := False +end; + +function ValidPolicy(PolicyStr: string): Boolean; +var + ParseStr, Ports: ArrOfStr; + Search, i: Integer; + Address, Port: string; + PolicyType, AddressType, MaskType: Integer; +begin + Result := False; + ParseStr := Explode(' ', PolicyStr); + if Length(ParseStr) <> 2 then + Exit; + PolicyType := GetArrayIndex(PolicyTypes, ParseStr[0]); + if PolicyType = -1 then + Exit; + if ParseStr[1] <> '*' then + begin + Search := RPos(':', ParseStr[1]); + if Search = 0 then + Exit; + Port := Copy(ParseStr[1], Search + 1); + if Port <> '*' then + begin + Ports := Explode('-', Port); + if Length(Ports) > 2 then + Exit; + for i := 0 to Length(Ports) - 1 do + if not ValidInt(Ports[i], 1, 65535) then + Exit; + end; + Address := Copy(ParseStr[1], 1, Search - 1); + MaskType := GetArrayIndex(MaskTypes, Address); + case MaskType of + -1: + begin + AddressType := ValidAddress(Address, True, True); + case AddressType of + 0: Exit; + 1: if PolicyType > 1 then Exit; + end; + end; + 1,3: if PolicyType > 1 then Exit; + end; + end; + Result := True; +end; + +function GetTransportID(TypeStr: string): Byte; +begin + Result := TRANSPORT_CLIENT; + if Length(TypeStr) > 0 then + begin + case AnsiChar(TypeStr[1]) of + SELECT_CHAR: Result := TRANSPORT_SERVER; + BOTH_CHAR: Result := TRANSPORT_BOTH; + end; + end; +end; + +function GetTransportChar(TransportID: Byte): string; +begin + case TransportID of + TRANSPORT_SERVER: Result := SELECT_CHAR; + TRANSPORT_BOTH: Result := BOTH_CHAR; + else + Result := FAVERR_CHAR; + end; +end; + +function TryParseBridge(BridgeStr: string; out Bridge: TBridge): Boolean; +var + ParseStr: ArrOfStr; + ParamsFlag: Boolean; + ParamsStr: string; + i: Integer; +begin + Bridge.Ip := ''; + Bridge.Port := 0; + Bridge.Hash := ''; + Bridge.Transport := ''; + Bridge.Params := ''; + Result := ValidBridge(BridgeStr, btNone); + if Result then + begin + ParamsFlag := False; + ParamsStr := ''; + ParseStr := Explode(' ', BridgeStr); + for i := 0 to Length(ParseStr) - 1 do + begin + if ParamsFlag then + begin + ParamsStr := ParamsStr + ' ' + ParseStr[i]; + Continue; + end; + if ValidTransport(ParseStr[i]) then + begin + Bridge.Transport := ParseStr[i]; + Continue; + end; + if ValidSocket(ParseStr[i]) then + begin + Bridge.Ip := GetAddressFromSocket(ParseStr[i]); + Bridge.Port := GetPortFromSocket(ParseStr[i]); + Continue; + end; + if ValidHash(ParseStr[i]) then + begin + Bridge.Hash := ParseStr[i]; + ParamsFlag := True; + end; + end; + Bridge.Params := Trim(ParamsStr); + end; +end; + +function ValidTransport(TransportStr: string): Boolean; +var + T: TTransportInfo; +begin + if TransportsDic.TryGetValue(TransportStr, T) then + begin + Result := T.TransportID <> TRANSPORT_SERVER; + Exit; + end; + Result := False; +end; + +function ValidBridge(BridgeStr: string; BridgeType: TBridgeType): Boolean; +var + ParseStr: ArrOfStr; + ParamCount: Integer; + T: TTransportInfo; +begin + Result := False; + BridgeStr := Trim(BridgeStr); + if (BridgeStr = '') or (Pos('|', BridgeStr) <> 0) then + Exit; + ParseStr := Explode(' ', BridgeStr); + ParamCount := Length(ParseStr); + case ParamCount of + 1: if ValidSocket(ParseStr[0]) then Result := True; + 2: if ValidSocket(ParseStr[0]) and ValidHash(ParseStr[1]) then Result := True; + else + begin + if TransportsDic.TryGetValue(ParseStr[0], T) then + begin + if (T.TransportID <> TRANSPORT_SERVER) and ValidSocket(ParseStr[1]) and ValidHash(ParseStr[2]) then + begin + if BridgeType <> btNone then + begin + Include(T.BridgeType, BridgeType); + TransportsDic.AddOrSetValue(ParseStr[0], T); + end; + Result := True; + end; + end; + end; + end; +end; + +function CidrToRange(CidrStr: string): TIPv4Range; +var + Search: Integer; + Prefix: Byte; + Ip, Mask: Cardinal; + ParseStr: ArrOfStr; +begin + Search := Pos('/', CidrStr); + Prefix := StrToInt(Copy(CidrStr, Search + 1)); + ParseStr := Explode('.', Copy(CidrStr, 1, Search - 1)); + + Ip := StrToInt(ParseStr[0]) shl 24 or StrToInt(ParseStr[1]) shl 16 or + StrToInt(ParseStr[2]) shl 8 or StrToInt(ParseStr[3]); + Mask := $FFFFFFFF shl (32 - Prefix); + Result.IpStart := Ip and Mask; + Result.IpEnd := Ip or (Mask xor $FFFFFFFF); +end; + +function IpInRanges(const IpStr: string; RangesData: array of string): Boolean; +var + i: Integer; + Range: TIPv4Range; + Ip: Cardinal; +begin + Ip := IpToInt(IpStr); + for i := 0 to Length(RangesData) - 1 do + begin + Range := CidrToRange(RangesData[i]); + if InRange(Ip, Range.IpStart, Range.IpEnd) then + begin + Result := True; + Exit; + end; + end; + Result := False; +end; + +function IpToInt(IpStr: string): Cardinal; +var + i, x, Index: Byte; +begin + Result := 0; + for i := 0 to 3 do + begin + Index := Pos('.', IpStr); + x := StrToIntDef(copy(IpStr, 0, Index - 1), 0); + Result := (256 * Result) + x; + Delete(IpStr, 1, Index); + end; + Result := Result + Cardinal(StrToIntDef(IpStr, 0)); +end; + +function IntToIp(Ip: Cardinal): string; +begin + Result := Format('%d.%d.%d.%d', [Ip shr 24, (Ip shr 16) and 255, (Ip shr 8) and 255, Ip and 255]); +end; + +procedure ComboBoxAutoWidth(const AComboBox: TCombobox); +var + i: Integer; + FullWidth: Integer; + ItemWidth: Integer; + ScrollSize: Integer; +begin + ScrollSize := 0; + FullWidth := 0; + if AComboBox.DropDownCount < AComboBox.Items.Count then + ScrollSize := GetSystemMetrics(SM_CXVSCROLL); + for i := 0 to AComboBox.Items.Count - 1 do + begin + ItemWidth := ScrollSize + AComboBox.Canvas.TextWidth(AComboBox.Items[i]) + 8; + if ItemWidth > FullWidth then + FullWidth := ItemWidth; + end; + if FullWidth > AComboBox.Width then + SendMessage(AComboBox.Handle, CB_SETDROPPEDWIDTH, FullWidth, 0); +end; + +procedure GridScrollCheck(aSg: TStringGrid; ACol, ColWidth: Integer); +begin + if (aSg.RowCount - aSg.FixedRows) > aSg.VisibleRowCount then + aSg.ColWidths[ACol] := Round(ColWidth * Scale) - GetSystemMetrics(SM_CXVSCROLL) + else + aSg.ColWidths[ACol] := Round(ColWidth * Scale); +end; + +procedure ControlsDisable(Control: TWinControl); +var + i: Integer; +begin + for i := 0 to Control.ControlCount - 1 do + begin + if Control.Controls[i] is TControl and Control.Controls[i].Enabled then + begin + Control.Controls[i].HelpContext := 1; + Control.Controls[i].Enabled := False; + end; + end; +end; + +procedure ControlsEnable(Control: TWinControl); +var + i: Integer; +begin + for i := 0 to Control.ControlCount - 1 do + begin + if Control.Controls[i] is TControl and (Control.Controls[i].HelpContext = 1) then + begin + Control.Controls[i].HelpContext := 0; + Control.Controls[i].Enabled := True; + end; + end; +end; + +function CtrlKeyPressed(Key: Char): Boolean; +var + State: Boolean; +begin + if Key = #0 then + State := True + else + State := GetKeyState(Ord(Key)) < 0; + Result := (GetKeyState(VK_CONTROL) < 0) and State; +end; + +function GetPortProtocol(PortID: Word): string; +begin + case PortID of + 443: Result := 'https'; + else + Result := 'http'; + end; +end; + +procedure LoadIconsFromResource(ImageList: TImageList; ResourceName: string); +var + Bmp: TBitmap; + Png: TPngImage; +begin + Png := TPngImage.Create; + Bmp := TBitmap.Create; + try + Png.LoadFromResourceName(HInstance, ResourceName); + Bmp.Assign(Png); + ImageList.Clear; + ImageList.Add(Bmp, nil); + finally + Png.Free; + Bmp.Free; + end; +end; + +procedure EditMenuEnableCheck(MenuItem: TMenuItem; MenuType: TEditMenuType); +var + Control: TCustomEdit; +begin + if Screen.ActiveControl is TCustomEdit then + begin + Control := TCustomEdit(Screen.ActiveControl); + case MenuType of + emCopy: MenuItem.Enabled := Control.SelLength > 0; + emCut: MenuItem.Enabled := (Control.SelLength > 0) and not Control.ReadOnly; + emPaste: MenuItem.Enabled := (IsClipboardFormatAvailable(CF_TEXT) or IsClipboardFormatAvailable(CF_UNICODETEXT)) and not Control.ReadOnly; + emSelectAll: MenuItem.Enabled := Length(Control.Text) > 0; + emClear: MenuItem.Enabled := (Length(Control.Text) > 0) and (not Control.ReadOnly or (Control = Tcp.meLog)); + emDelete: MenuItem.Enabled := (Control.SelLength > 0) and not Control.ReadOnly; + emFind: + begin + MenuItem.Visible := Control is TMemo; + if MenuItem.Visible then + MenuItem.Enabled := Length(Control.Text) > 0; + end; + end; + end; +end; + +function SearchEdit(EditControl: TCustomEdit; const SearchString: String; Options: TFindOptions; FindFirst: Boolean = False): Boolean; +var + Size: Integer; + SearchOptions: TStringSearchOptions; + Buffer, P: PChar; +begin + Result := False; + if (Length(SearchString) = 0) then Exit; + Size := EditControl.GetTextLen; + if (Size = 0) then Exit; + + SearchOptions := []; + if frDown in Options then + Include(SearchOptions, soDown); + if frMatchCase in Options then + Include(SearchOptions, soMatchCase); + if frWholeWord in Options then + Include(SearchOptions, soWholeWord); + + Buffer := StrAlloc(Size + 1); + try + EditControl.GetTextBuf(Buffer, Size + 1); + if FindFirst then + P := SearchBuf(Buffer, Size, 0, EditControl.SelLength, SearchString, SearchOptions) + else + P := SearchBuf(Buffer, Size, EditControl.SelStart, EditControl.SelLength, SearchString, SearchOptions); + if P <> nil then + begin + EditControl.SelStart := P - Buffer; + EditControl.SelLength := Length(SearchString); + Result := True; + end; + finally + StrDispose(Buffer); + end; +end; + +procedure EditMenuHandle(MenuType: TEditMenuType); +var + Control: TCustomEdit; +begin + if Screen.ActiveControl is TCustomEdit then + begin + Control := TCustomEdit(Screen.ActiveControl); + if Control.Enabled then + begin + case MenuType of + emCopy: Control.CopyToClipboard; + emCut: Control.CutToClipboard; + emPaste: Control.PasteFromClipboard; + emSelectAll: Control.SelectAll; + emClear: Control.Text := ''; + emDelete: Control.ClearSelection; + emFind: + begin + if Control is TMemo then + begin + SearchFirst := False; + FindObject := TMemo(Control); + if Tcp.cbClearPreviousSearchQuery.Checked then + Tcp.FindDialog.FindText := FindObject.SelText + else + begin + if FindObject.SelText <> '' then + Tcp.FindDialog.FindText := FindObject.SelText + end; + Tcp.FindDialog.Execute; + end; + end; + end; + end; + end; +end; + +function GetFileVersionStr(const FileName: string): string; +var + InfoSize, Wnd: DWORD; + VerBuf: Pointer; + FI: PVSFixedFileInfo; + VerSize: DWORD; +begin + Result := '0.0.0.0'; + InfoSize := GetFileVersionInfoSize(PChar(FileName), Wnd); + if InfoSize <> 0 then + begin + GetMem(VerBuf, InfoSize); + try + if GetFileVersionInfo(PChar(FileName), Wnd, InfoSize, VerBuf) then + if VerQueryValue(VerBuf, '\', Pointer(FI), VerSize) then + Result := Format('%d.%d.%d.%d', [ + HiWord(FI.dwFileVersionMS), LoWord(FI.dwFileVersionMS), + HiWord(FI.dwFileVersionLS), LoWord(FI.dwFileVersionLS) + ]); + finally + FreeMem(VerBuf); + end; + end; +end; + +function CheckFileVersion(FileVersion, StaticVersion: string): Boolean; +begin + FileVersion := SeparateLeft(FileVersion, '-'); + StaticVersion := SeparateLeft(StaticVersion, '-'); + Result := CompareNaturalText(PWideChar(FileVersion), PWideChar(StaticVersion)) <> -1; +end; + +function TryUpdateMask(var Mask: Byte; Param: Byte; Condition: Boolean): Boolean; +begin + if Condition then + begin + Result := Mask and Param = 0; + if Result then + Inc(Mask, Param); + end + else + begin + Result := Mask and Param <> 0; + if Result then + Dec(Mask, Param); + end; +end; + +function GetRoutersParamsCount(Mask: Integer): Integer; + procedure CheckMask(Param: Integer); + begin + if Mask and Param <> 0 then + Inc(Result); + end; +begin + Result := 0; + CheckMask(ROUTER_BRIDGE); + CheckMask(ROUTER_AUTHORITY); + CheckMask(ROUTER_ALIVE); + CheckMask(ROUTER_REACHABLE_IPV6); + CheckMask(ROUTER_HS_DIR); + CheckMask(ROUTER_DIR_MIRROR); + CheckMask(ROUTER_NOT_RECOMMENDED); + CheckMask(ROUTER_BAD_EXIT); +end; + +function CheckSplitButton(Button: TButton): Boolean; +var + MousePoint, MenuPoint: TPoint; +begin + Result := False; + if (Win32MajorVersion = 5) and (Button.Style = bsSplitButton) then + begin + MousePoint := Button.ScreenToClient(Mouse.CursorPos); + if not InRange(MousePoint.X, 0, Button.Width - 16) then + begin + if Assigned(Button.DropDownMenu) then + begin + MenuPoint := Button.ClientOrigin; + Button.DropDownMenu.Popup(MenuPoint.X, MenuPoint.Y + Button.Height); + end; + Result := True; + end; + end; +end; + +function SampleDown(Data: ArrOfPoint; Threshold: Integer): ArrOfPoint; +var + i, DataLength, SampledIndex: Integer; + a, NextA: Integer; + AvgRangeStart, AvgRangeEnd, AvgRangeLength: Integer; + RangeOffs, RangeTo: Integer; + PointAX, PointAY: Integer; + MaxAreaPoint: TPoint; + Every, Area, MaxArea: Real; + AvgX, AvgY: Real; +begin + DataLength := Length(Data); + if (Threshold >= DataLength) or (Threshold < 3) then + begin + Result := Data; + Exit; + end; + + Result := nil; + SetLength(Result, Threshold); + + i := 0; + a := 0; + NextA := 0; + MaxAreaPoint.X := 0; + MaxAreaPoint.Y := 0; + SampledIndex := 0; + Result[SampledIndex] := Data[a]; + Inc(SampledIndex); + + Every := (DataLength - 2) / (Threshold - 2); + + while i < Threshold - 2 do + begin + AvgX := 0; + AvgY := 0; + AvgRangeStart := Floor((i + 1) * Every) + 1; + AvgRangeEnd := Floor((i + 2) * Every) + 1; + if AvgRangeEnd < DataLength then + AvgRangeEnd := AvgRangeEnd + else + AvgRangeEnd := DataLength; + AvgRangeLength := AvgRangeEnd - AvgRangeStart; + while AvgRangeStart < AvgRangeEnd do + begin + AvgX := AvgX + Data[AvgRangeStart].X * 1; + AvgY := AvgY + Data[AvgRangeStart].Y * 1; + Inc(AvgRangeStart); + end; + + AvgX := AvgX / AvgRangeLength; + AvgY := AvgY / AvgRangeLength; + + RangeOffs := Floor((i + 0) * Every) + 1; + RangeTo := Floor((i + 1) * Every) + 1; + + PointAX := Data[a].X * 1; + PointAY := Data[a].Y * 1; + + MaxArea := -1; + + while RangeOffs < RangeTo do + begin + Area := Abs((PointAX - AvgX) * (Data[RangeOffs].Y - PointAY) - (PointAX - Data[RangeOffs].X) * (AvgY - PointAY)) * 0.5; + if Area > MaxArea then + begin + MaxArea := Area; + MaxAreaPoint := Data[RangeOffs]; + NextA := RangeOffs; + end; + Inc(RangeOffs); + end; + + Result[SampledIndex] := MaxAreaPoint; + Inc(SampledIndex); + a := NextA; + Inc(i); + end; + Result[SampledIndex] := Data[DataLength - 1]; +end; + +procedure EnableComposited(WinControl: TWinControl); +begin + SetWindowLong(WinControl.Handle, GWL_EXSTYLE, + GetWindowLong(WinControl.Handle, GWL_EXSTYLE) or WS_EX_COMPOSITED); +end; + +initialization + InitCharUpCaseTable(CharUpCaseTable); + +end. diff --git a/source/Languages.pas b/source/Languages.pas new file mode 100644 index 0000000..8f440ba --- /dev/null +++ b/source/Languages.pas @@ -0,0 +1,1211 @@ +unit Languages; + +interface + +uses + Winapi.Windows, System.Classes, System.SysUtils, System.IniFiles, System.DateUtils, + System.Generics.Collections, Vcl.Forms, Vcl.Graphics, Vcl.StdCtrls, + synautil, ConstData, Functions; + + function GetLangList: Integer; + function Load(Key, Default: string): string; + function TransStr(const StrID: string): string; + procedure LoadLns(Key, Default: string); + procedure LoadStr(Key, Default: string); + procedure Translate(Section: string); + procedure TranslateArray(var HeaderArray: array of string; Header: string); + +var + DetailsHeader: array [0..5] of string; + FilterHeader: array [0..7] of string; + HsHeader: array [0..3] of string; + HsPortsHeader: array [0..2] of string; + RoutersHeader: array [0..8] of string; + CircuitsHeader: array [0..0] of string; + StreamsHeader: array [0..0] of string; + StreamsInfoHeader: array [0..2] of string; + TransportsHeader: array [0..2] of string; + Prefixes: array[0..6] of string; + LangStr: TDictionary; + LangIniFile: TMemIniFile; + CurrentTranslate: string; + CurrentLanguage: Word; + +implementation + +uses + Main; + +procedure TranslateArray(var HeaderArray: array of string; Header: string); +var + i: Integer; + ls: TStringList; +begin + ls := TStringList.Create; + try + ParseParametersEx(Header, ',', ls); + for i := 0 to Length(HeaderArray) - 1 do + if i < ls.Count then + HeaderArray[i] := ls[i]; + finally + ls.Free; + end; +end; + +function GetLangList: Integer; +var + ini: TMemIniFile; + ls, rs: TStringList; + i, LangID, English: Integer; + SystemLanguage: Word; +begin + Result := 0; + English := 0; + SystemLanguage := GetSystemDefaultLangID; + ls := TStringList.Create; + try + if FileExists(LangFile) then + begin + ini := TMemIniFile.Create(LangFile, TEncoding.UTF8); + rs := TStringList.Create; + try + ini.ReadSections(rs); + for i := 0 to rs.Count - 1 do + begin + if rs[i] = 'DefaultCountries' then + continue; + LangID := ini.ReadInteger(rs[i], 'Locale', 0); + ls.AddObject(rs[i], TObject(Integer(LangID))); + if LangID = SystemLanguage then + Result := LangID; + if LangID = 1033 then + English := 1033; + end; + finally + ini.Free; + rs.Free; + end; + + if Result = 0 then + begin + case SystemLanguage of + 1049: Result := 1049; + 1058: Result := 1049; + 1059: Result := 1049; + else + begin + if English > 0 then + Result := English; + end; + end; + end; + + end; + ls.AddObject('Русский', TObject(Integer(1049))); + Tcp.cbxLanguage.Items := ls; + finally + ls.Free; + end; +end; + +function TransStr(const StrID: string): string; +begin + LangStr.TryGetValue(StrID, Result); +end; + +function Load(Key, Default: string): string; +begin + Result := LangIniFile.ReadString(CurrentTranslate, Key, Default) +end; + +procedure LoadList(ls: TCombobox; Key, Default: string); +var + Index: Integer; +begin + Index := ls.ItemIndex; + ls.Items.DelimitedText := LangIniFile.ReadString(CurrentTranslate, Key, Default); + ls.ItemIndex := Index; +end; + +procedure LoadStr(Key, Default: string); +begin + LangStr.AddOrSetValue(Key, LangIniFile.ReadString(CurrentTranslate, Key, Default)); +end; + +procedure LoadLns(Key, Default: string); +begin + LangStr.AddOrSetValue(Key, StringReplace(LangIniFile.ReadString(CurrentTranslate, Key, Default), '\n', BR, [rfReplaceAll])); +end; + +procedure Translate(Section: string); +var + i: Integer; +begin + CurrentTranslate := Section; + if Assigned(LangStr) then + LangStr.Clear + else + LangStr := TDictionary.Create; + + LangIniFile := TMemIniFile.Create(LangFile, TEncoding.UTF8); + try + LoadStr('Locale', '1049'); + LoadStr('100', 'Старт'); + LoadStr('101', 'Запуск...'); + LoadStr('102', 'Стоп'); + LoadLns('103', 'Сменить\nцепочку'); + LoadStr('104', 'По умолчанию'); + LoadStr('105', 'Панель управления Tor'); + LoadLns('106', '%s\nПрофиль: %s'); + LoadStr('107', 'Настройки'); + LoadStr('108', 'Журнал'); + LoadStr('109', 'Не получен'); + LoadStr('110', 'Не определена'); + LoadStr('111', 'Получение...'); + LoadStr('112', 'Определение...'); + LoadStr('113', 'IP адрес'); + LoadStr('114', 'Страна'); + LoadStr('122', 'Скрытый сервис'); + LoadStr('130', 'Пароль'); + LoadStr('135', 'сек.'); + LoadStr('146', 'Преобразование в хэши включено'); + LoadStr('151', 'Тип'); + LoadStr('153', 'Порт'); + LoadStr('159', 'Необязательно'); + LoadStr('160', 'Прокручивать вверх при сортировке'); + LoadLns('161', 'Текущая конфигурация авангардов для скрытых сервисов требует как минимум %d избранных входных узлов (Найдено: %d). \n\nИсправить проблему и продолжить сохранение настроек?'); + LoadStr('164', 'Эта операция требует перезапуска Tor'); + LoadStr('175', 'Максимум'); + LoadStr('180', 'c'); + LoadStr('181', 'Проверка переадресации портов'); + LoadStr('197', 'мин.'); + LoadStr('203', 'Всего'); + LoadStr('204', 'Внимание! Отключение кэша каталога ускорит работу сервера, но ваш сервер никогда не станет сторожевым узлом. Хотите продолжить?'); + LoadStr('206', 'Обычный'); + LoadLns('208', '\n Щёлкните здесь для добавления адресов\n\n Примеры:\n\n Ip: 8.8.8.8\n Сайт: metrics.torproject.org\n Домен:.torproject.org\n Все:.'); + LoadLns('209', '\n Щёлкните здесь для добавления узлов\n\n Примеры:\n\n Ip: 8.8.8.8\n CIDR: 8.8.8.8/24\n Страна: RU,DE,US,..\n Хэш: ABCD1234CDEF567..'); + LoadLns('210', '\n Щёлкните здесь для добавления мостов\n\n Примеры:\n\n 8.8.8.8:443\n 8.8.8.8:443 ABCD1234CDEF567..\n obfs4 8.8.8.8:443 ABCD1234CDEF567.. cert=.. iat-mode=..\n\n Примечание: мосты переопределяют настройки входных узлов'); + LoadStr('212', 'Загрузка'); + LoadStr('213', 'Отправка'); + LoadStr('214', 'Получено'); + LoadStr('215', 'Отправлено'); + LoadStr('221', 'Дата создания'); + LoadStr('226', 'Выключен'); + LoadStr('230', 'Название,Версия,Точек входа,Соединений'); + LoadStr('231', 'Интерфейс,Порт,Виртуальный'); + LoadStr('232', 'Ник,IP адрес,,Страна,Вес,Пинг'); + LoadStr('233', 'ID,,Страна,Всего,Вход,Выход,Живые,∑ пинг'); + LoadStr('234', 'Б,КБ,МБ,ГБ,ТБ,ПБ,ЭБ'); + LoadStr('235', 'Информация'); + LoadStr('236', 'Ошибка при разборе конфигурационного файла torrc, подробности смотрите в журнале'); + LoadStr('237', 'Подключение к сети Tor остановлено, неверно указан пароль для управляющего порта!'); + LoadLns('238', 'Исполняемый файл Tor не запускается. Возможно он:\n\n - повреждён или не является приложением Windows\n - является 64-битным приложением, в то время как у вас 32-битная операционная система.'); + LoadStr('239', 'Исполняемый файл Tor не найден. Скачайте Tor Windows Expert Bundle и распакуйте в каталог с программой. Перейти на страницу загрузки прямо сейчас?'); + LoadStr('240', 'Подключение к сети Tor...'); + LoadStr('241', 'Вы отключились от сети Tor'); + LoadStr('242', 'Устройств с поддержкой переадресации портов не найдено!'); + LoadStr('243', 'Результат'); + LoadStr('244', 'Источник,Назначение,Цель'); + LoadStr('245', 'Успешно'); + LoadStr('246', 'Предупреждение'); + LoadStr('247', 'Ошибка'); + LoadStr('248', 'Название не может быть пустым!'); + LoadStr('249', 'Это название уже используется другим сервисом!'); + LoadStr('250', 'Список портов'); + LoadStr('251', 'Вы должны добавить хотя бы один порт!'); + LoadStr('252', 'Такая комбинация интерфейса и портов уже существует!'); + LoadStr('253', 'Пароль для управляющего порта изменён'); + LoadStr('254', 'Ошибка при загрузке шаблона: параметры заданы неверно!'); + LoadStr('255', 'Нельзя использовать разделительный символ " %s "'); + LoadStr('256', 'Сохранение шаблона'); + LoadStr('257', 'Введите название шаблона'); + LoadStr('258', 'Цепочка изменена'); + LoadLns('259', 'Запуск приостановлен, порты указанные в настройках программы уже используются!\n\nЗанятые порты: %s \n\nИзменить порты на случайные и продолжить запуск?'); + LoadStr('260', 'Не определён'); + LoadLns('261', 'Использовать мосты, прокси и разрешённые порты в режиме сервера нельзя!\n\nВыключить эти опции и продолжить сохранение настроек?'); + LoadStr('262', 'Подтверждение'); + LoadStr('263', 'Вы действительно хотите удалить %s"%s"?'); + LoadStr('264', 'Все шаблоны'); + LoadStr('265', 'Создание ярлыка'); + LoadStr('266', 'Введите название профиля'); + LoadStr('267', 'Все сервисы'); + LoadLns('268', 'Вы действительно хотите добавить:\n\n%s\n\nв список "%s узлы"?%s'); + LoadLns('269', 'Используйте только буквы латинского алфавита и цифры'); + LoadStr('270', 'и'); + LoadStr('271', 'Конфигурационный файл Tor'); + LoadStr('274', 'Копировать'); + LoadStr('275', 'Вставить'); + LoadStr('276', 'Вырезать'); + LoadStr('277', 'Выделить всё'); + LoadStr('278', 'Очистить'); + LoadStr('279', 'Добавить'); + LoadStr('280', 'Удалить'); + LoadStr('281', 'Информация по ретранслятору'); + LoadStr('282', 'Статус'); + LoadStr('284', 'Обновить'); + LoadStr('285', 'Изменить список узлов'); + LoadStr('287', 'Запрещённые'); + LoadStr('288', 'Входныe'); + LoadStr('289', 'Средние'); + LoadStr('290', 'Выходные'); + LoadStr('320', 'Ник,IP адрес,,Страна,Вес,Порт,Версия,Пинг,Флаги'); + LoadStr('321', 'Показано: %d из %d'); + LoadLns('322', '\n Список хэшей, определяющих ваше семейство\n\n Пример:\n\n ABCD1234CDEF567..'); + LoadStr('323', 'Роутеры'); + LoadStr('324', 'Неправильные настройки'); + LoadStr('326', 'Протокол скрытых сервисов второй версии устарел, его поддержка была прекращена в версии 0.4.6.1 и выше. Вы действительно хотите использовать эту версию протокола?'); + LoadStr('327', 'Цепочки'); + LoadStr('328', 'Уменьшить окно'); + LoadStr('329', 'Назначение'); + LoadStr('330', 'Целевой адрес'); + LoadStr('331', 'Запрос каталога'); + LoadStr('332', 'Внутренний трафик'); + LoadStr('333', 'Выходной трафик'); + LoadStr('334', 'Клиент: Запрос каталога'); + LoadStr('335', 'Клиент: Точка входа'); + LoadStr('336', 'Клиент: Место встречи'); + LoadStr('337', 'Сервис: Запрос каталога'); + LoadStr('338', 'Сервис: Точка входа'); + LoadStr('339', 'Сервис: Место встречи'); + LoadStr('340', 'Авангард скрытого сервиса'); + LoadStr('341', 'Проверка закрытия цепочки'); + LoadStr('342', 'Проверка доступности'); + LoadStr('343', 'Маскировка времени'); + LoadStr('344', 'Измерение ожидания'); + LoadStr('345', 'Другое назначение'); + LoadStr('346', 'Внимание! Частая смена сторожевых узлов может помочь злоумышленникам обнаружить вас. Используйте только в случае крайней необходимости. %sХотите продолжить?'); + LoadStr('347', '(Все страны)'); + LoadStr('348', '(Выбранные в фильтре)'); + LoadStr('349', 'Цепочек: %d из %d'); + LoadStr('350', 'Соединений'); + LoadStr('351', 'Привязать к выходному узлу'); + LoadStr('352', 'Отвязать от выходного узла'); + LoadStr('353', 'Глобальный домен'); + LoadStr('354', 'Настройки программы были изменены! Хотите применить изменения?'); + LoadStr('355', 'О программе'); + LoadLns('356', '%s, версия: %s\n\n%s\n\n(Windows GUI-клиент для Tor Expert Bundle)\n\n%s\n\nХотите посетить страницу программы на GitHub?'); + LoadStr('357', 'Эта программа является свободным программным обеспечением и распространяется по лицензии MIT'); + LoadLns('358', 'Узлы, отсутствующие в консенсусе, будут удалены из пользовательских списков.\n\nИгнорировать список исключенных узлов при сканировании?'); + LoadStr('359', 'Удалить из списков'); + LoadStr('360', 'Автоподбор роутеров'); + LoadLns('361', 'Вы действительно хотите удалить:\n\n%s\n\nиз всех списков узлов?%s'); + LoadLns('362', 'Вы действительно хотите удалить:\n\n%s\n\nиз списка "%s узлы"?%s'); + LoadStr('363', 'Шаблон "%s" успешно сохранён'); + LoadStr('364', 'Шаблон "%s" успешно загружен'); + LoadStr('365', 'Шаблон "%s" успешно удалён'); + LoadStr('366', 'шаблон'); + LoadStr('367', 'сервис'); + LoadStr('368', 'Выбрать все'); + LoadStr('369', 'Снять все'); + LoadStr('370', 'Запрос каталога'); + LoadStr('371', 'Загрузка каталога'); + LoadStr('372', 'Тест порта каталога'); + LoadStr('373', 'DNS-запрос'); + LoadStr('374', 'Обычный трафик'); + LoadStr('375', 'Другая цель'); + LoadStr('376', 'Внутренний сокет'); + LoadStr('377', 'Для нормальной работы программы требуется Tor Windows Expert Bundle версии 0.4.0.5 и выше.'); + LoadStr('378', 'Не удается найти "%s"'); + LoadStr('379', 'мс'); + LoadStr('380', 'Автоматический режим'); + LoadStr('381', 'Ручной режим'); + LoadStr('382', 'Измерение пинга'); + LoadStr('383', 'Определение живых узлов'); + LoadStr('384', 'Мост (Входной узел)'); + LoadStr('385', 'Корневой каталог'); + LoadStr('386', 'Живой (отвечает на соединения)'); + LoadStr('387', 'Принимает IPv6-соединения'); + LoadStr('388', 'Каталог скрытых сервисов'); + LoadStr('389', 'Зеркало каталога (порт: %d)'); + LoadStr('390', 'Не рекомендуемая версия'); + LoadStr('391', 'Плохой выходной узел'); + LoadStr('392', 'Неизвестный флаг'); + LoadStr('393', 'Транспорты,Обработчик,Тип'); + LoadStr('394', 'Список транспортов не может содержать пустые данные'); + LoadStr('395', 'Не найден файл обработчика, скопируйте его в каталог транспортов и повторите'); + LoadStr('396', 'Определение живых мостов'); + LoadStr('397', 'Последняя поддерживаемая версия для вашей операционной системы: 0.4.4.6'); + LoadStr('398', 'Цифры в начале слова запрещены'); + LoadStr('399', 'Транспорт с таким названием и типом уже существует'); + LoadLns('400', 'Идёт сканирование мостов...\n\nДождитесь окончания и повторите попытку.'); + LoadStr('401', 'Нет соединения'); + LoadStr('402', 'Начало учёта: %s'); + LoadStr('404', 'Остановка сканирования..'); + LoadLns('405', 'Вы действительно хотите: "%s"\n\nВыбранное действие нельзя будет отменить!'); + LoadStr('406', 'Удалить все'); + LoadStr('423', 'Найти...'); + LoadStr('444', 'Сетевой сканер'); + LoadStr('459', 'мсек.'); + LoadStr('470', 'шт.'); + LoadStr('477', 'ч.'); + LoadStr('515', 'Выделять все ячейки в строке'); + LoadStr('521', 'Выбранные страны'); + LoadStr('522', 'Избранные узлы'); + LoadStr('523', 'Запрещённые узлы'); + LoadStr('524', 'Уничтожить'); + LoadStr('525', 'Сортировка'); + LoadStr('526', 'Фильтры'); + LoadStr('528', 'Соединения'); + LoadStr('530', 'Назначение'); + LoadStr('547', 'Тип узла'); + + TranslateArray(HsHeader, TransStr('230')); + TranslateArray(HsPortsHeader, TransStr('231')); + TranslateArray(DetailsHeader, TransStr('232')); + TranslateArray(FilterHeader, TransStr('233')); + TranslateArray(RoutersHeader, TransStr('320')); + TranslateArray(CircuitsHeader, TransStr('329')); + TranslateArray(StreamsHeader, TransStr('330')); + TranslateArray(StreamsInfoHeader, TransStr('244')); + TranslateArray(TransportsHeader, TransStr('393')); + + for i := 0 to Length(Prefixes) - 1 do + ConstDic.Remove(Prefixes[i]); + TranslateArray(Prefixes, TransStr('234')); + for i := 0 to Length(Prefixes) - 1 do + ConstDic.AddOrSetValue(Prefixes[i], i); + + if UserProfile = 'User' then + Tcp.lbUserDir.Caption := TransStr('104') + else + Tcp.lbUserDir.Caption := UserProfile; + Tcp.tiTray.Hint := Format(TransStr('106'), [TransStr('105'), Tcp.lbUserDir.Caption]); + Tcp.Caption := TransStr('105'); + Application.Title := TransStr('105'); + if ConnectState = 0 then + begin + Tcp.btnSwitchTor.Caption := TransStr('100'); + Tcp.miSwitchTor.Caption := TransStr('100'); + Tcp.lbExitIp.Caption := TransStr('109'); + Tcp.lbExitCountry.Caption := TransStr('110'); + end; + if ConnectState = 2 then + begin + Tcp.btnSwitchTor.Caption := TransStr('102'); + Tcp.miSwitchTor.Caption := TransStr('102'); + end; + Tcp.btnChangeCircuit.Caption := TransStr('103'); + Tcp.sbShowOptions.Caption := TransStr('107'); + Tcp.sbShowLog.Caption := TransStr('108'); + Tcp.sbShowStatus.Caption := TransStr('282'); + Tcp.sbShowCircuits.Caption := TransStr('327'); + Tcp.sbShowRouters.Caption := TransStr('323'); + Tcp.sbDecreaseForm.Hint := TransStr('328'); + + Tcp.lbExitIpCaption.Caption := TransStr('113') + ':'; + Tcp.lbExitCountryCaption.Caption := TransStr('114') + ':'; + Tcp.btnApplyOptions.Caption := Load('115', 'Применить'); + Tcp.btnCancelOptions.Caption := Load('116', 'Отмена'); + + Tcp.tsMain.Caption := Load('118', 'Общие'); + Tcp.tsNetwork.Caption := Load('119', 'Сеть'); + Tcp.tsFilter.Caption := Load('120', 'Фильтр'); + Tcp.tsServer.Caption := Load('121', 'Сервер'); + Tcp.tsHs.Caption := TransStr('122'); + Tcp.tsOther.Caption := Load('123', 'Разное'); + Tcp.tsLists.Caption := Load('546', 'Списки'); + + Tcp.gbOptions.Caption := Load('410', 'Основные'); + Tcp.lbMaxCircuitDirtiness.Caption := Load('124', 'Менять цепочку существующую более чем'); + Tcp.lbNewCircuitPeriod.Caption := Load('125', 'Интервал между попытками построить цепочку'); + Tcp.lbCircuitBuildTimeout.Caption := Load('126', 'Макс. время на построение цепочки'); + Tcp.lbMaxClientCircuitsPending.Caption := Load('317', 'Количество ожидающих цепочек клиента'); + Tcp.cbLearnCircuitBuildTimeout.Caption := Load('136', 'Автоматически выбирать время на построение цепочки'); + Tcp.cbEnforceDistinctSubnets.Caption := Load('137', 'Не строить цепочки из узлов одной подсети'); + Tcp.cbAvoidDiskWrites.Caption := Load('138', 'Выполнять меньше операций с диском'); + Tcp.cbStrictNodes.Caption := Load('318', 'Разрешить запрещённые узлы для внутренних цепочек'); + Tcp.cbUseOpenDNS.Caption := Load('407', 'Определять внешний адрес сервера через OpenDNS'); + Tcp.cbUseOpenDNSOnlyWhenUnknown.Caption := Load('408', 'Только если TOR не может определить его сам'); + Tcp.cbUseNetworkCache.Caption := Load('409', 'Кэшировать IP-cc-запросы и результаты сетевого сканера'); + Tcp.lbTheme.Caption := Load('413', 'Тема'); + Tcp.lbLanguage.Caption := Load('132', 'Язык'); + Tcp.lbSeconds1.Caption := TransStr('135'); + Tcp.lbSeconds2.Caption := TransStr('135'); + Tcp.lbSeconds3.Caption := TransStr('135'); + + Tcp.gbControlAuth.Caption := Load('412', 'Управление'); + Tcp.lbControlPort.Caption := Load('127', 'Порт'); + Tcp.lbAuthMetod.Caption := Load('128', 'Аутентификация'); + LoadList(Tcp.cbxAuthMetod, '129', '"Cookie-файл","Пароль"'); + Tcp.lbControlPassword.Caption := TransStr('130'); + Tcp.imGeneratePassword.Hint := Load('131', 'Сгенерировать случайный пароль'); + + Tcp.gbInterface.Caption := Load('411', 'Интерфейс'); + Tcp.cbConnectOnStartup.Caption := Load('139', 'Подключаться при запуске программы'); + Tcp.cbRestartOnControlFail.Caption := Load('140', 'Перезапуск при обрыве связи с клиентом'); + Tcp.cbMinimizeOnStartup.Caption := Load('141', 'Сворачивать в трей при запуске'); + Tcp.cbMinimizeOnClose.Caption := Load('142', 'Сворачивать в трей при закрытии'); + Tcp.cbShowBalloonHint.Caption := Load('143', 'Показывать всплывающие сообщения'); + Tcp.cbShowBalloonOnlyWhenHide.Caption := Load('144', 'Только когда программа свёрнута'); + Tcp.cbStayOnTop.Caption := Load('145', 'Оставаться поверх всех окон'); + Tcp.cbNoDesktopBorders.Caption := Load('414', 'Разрешить окну выходить за границы экрана'); + Tcp.cbNoDesktopBordersOnlyEnlarged.Caption := Load('415', 'Только при увеличенном окне программы'); + Tcp.cbRememberEnlargedPosition.Caption := Load('416', 'Запоминать позицию увеличенного окна'); + Tcp.cbHideIPv6Addreses.Caption := Load('417', 'Скрывать IPv6-адреса в списках интерфейсов'); + Tcp.cbClearPreviousSearchQuery.Caption := Load('418', 'Очищать предыдущий поисковый запрос в списках'); + + Tcp.gbProfile.Caption := Load('134', 'Профиль'); + Tcp.btnCreateProfile.Caption := Load('117', 'Создать..'); + Tcp.lbCreateProfile.Caption := Load('133', 'Ярлык программы с новым профилем на рабочем столе'); + + Tcp.cbUseReachableAddresses.Caption := Load('147', 'Мой сетевой экран разрешает подключаться только к этим портам'); + Tcp.lbReachableAddresses.Caption := Load('148', 'Список портов'); + Tcp.cbEnableSocks.Caption := Load('149', 'Включить встроенный прокси'); + Tcp.cbUseProxy.Caption := Load('150', 'Я использую прокси для подключения к Интернету'); + Tcp.lbProxyType.Caption := TransStr('151'); + Tcp.lbProxyAddress.Caption := Load('152', 'Адрес'); + Tcp.lbProxyPort.Caption := TransStr('153'); + Tcp.lbProxyUser.Caption := Load('154', 'Логин'); + Tcp.lbProxyPassword.Caption := TransStr('130'); + Tcp.cbUseBridges.Caption := Load('155', 'Использовать мосты'); + Tcp.edControlPassword.TextHint := Load('156', 'Введите пароль'); + Tcp.edReachableAddresses.TextHint := Load('157', 'Значения, разделённые запятыми'); + Tcp.edProxyAddress.TextHint := Load('158', 'IP-адрес или имя узла'); + Tcp.edProxyUser.TextHint := TransStr('159'); + Tcp.edProxyPassword.TextHint := TransStr('159'); + Tcp.meBridges.TextHint.Text := TransStr('210'); + Tcp.lbBridgesType.Caption := TransStr('151'); + Tcp.lbBridgesList.Caption := Load('419', 'Список мостов'); + Tcp.cbUsePreferredBridge.Caption := Load('420', 'Задать предпочитаемый мост вручную'); + Tcp.lbPreferredBridge.Caption := Load('421', 'Мост'); + Tcp.edPreferredBridge.TextHint := Load('422', 'Эта настройка переопределяет выбранный список мостов'); + Tcp.btnFindPreferredBridge.Caption := TransStr('423'); + LoadList(Tcp.cbxBridgesType, '424', '"Встроенные","Пользовательские"'); + + Tcp.lbFilterMode.Caption := Load('162', 'Режим'); + Tcp.lbFilterEntry.Caption := TransStr('288') + ': ' + IntToStr(Tcp.lbFilterEntry.Tag); + Tcp.lbFilterMiddle.Caption := TransStr('289') + ': ' + IntToStr(Tcp.lbFilterMiddle.Tag); + Tcp.lbFilterExit.Caption := TransStr('290') + ': ' + IntToStr(Tcp.lbFilterExit.Tag); + Tcp.lbFilterExclude.Caption := TransStr('287') + ': ' + IntToStr(Tcp.lbFilterExclude.Tag); + LoadList(Tcp.cbxFilterMode, '165', '"Отключено", "Выбранные страны", "Избранные узлы"'); + + Tcp.lbServerMode.Caption := Load('166', 'Режим работы'); + Tcp.lbNickname.Caption := Load('167', 'Ник'); + Tcp.lbContactInfo.Caption := Load('168', 'Контакты'); + Tcp.lbBridgeType.Caption := Load('169', 'Тип моста'); + Tcp.lbExitPolicy.Caption := Load('170', 'Политика выхода'); + Tcp.lbORPort.Caption := Load('171', 'Сервер'); + Tcp.lbDirPort.Caption := Load('172', 'Каталог'); + Tcp.lbTransportPort.Caption := Load('173', 'Транспорт'); + Tcp.cbUseMaxMemInQueues.Caption := Load('174', 'Ограничить память'); + Tcp.lbSizeMb.Caption := Prefixes[2]; + Tcp.cbUseRelayBandwidth.Caption := Load('176', 'Ограничить скорость'); + Tcp.cbUseNumCPUs.Caption := Load('177', 'Ограничить процессор'); + Tcp.lbNumCPUs.Caption := Load('178', 'Макс. ядер'); + Tcp.lbRelayBandwidthRate.Caption := Load('179', 'Средняя'); + Tcp.lbSpeed1.Caption := Prefixes[1] + '/' + TransStr('180'); + Tcp.lbSpeed2.Caption := Prefixes[1] + '/' + TransStr('180'); + Tcp.lbMaxMemInQueues.Caption := TransStr('175'); + Tcp.lbRelayBandwidthBurst.Caption := TransStr('175'); + Tcp.imUPnPTest.Hint := TransStr('181'); + Tcp.cbUseUPnP.Caption := Load('182', 'Пытаться автоматически настроить переадресацию портов'); + Tcp.cbPublishServerDescriptor.Caption := Load('183', 'Публиковать сервер в каталоге ретрансляторов'); + Tcp.cbUseDirPort.Caption := Load('184', 'Включить зеркало каталога ретрансляторов'); + Tcp.cbDirReqStatistics.Caption := Load('185', 'Собирать статистику запросов каталога'); + Tcp.cbHiddenServiceStatistics.Caption := Load('186', 'Собирать статистику о своей роли в качестве узла скрытого сервиса'); + Tcp.cbIPv6Exit.Caption := Load('187', 'Разрешить выход IPv6 трафика'); + Tcp.edNickname.TextHint := Load('188', 'Имя вашего узла'); + Tcp.edContactInfo.TextHint := Load('189', 'Электронный адрес'); + LoadList(Tcp.cbxServerMode, '205', '"Отключено","Ретранслятор","Выходной узел","Мост"'); + LoadList(Tcp.cbxExitPolicyType, '207', '"По умолчанию","Ограниченная","Настраиваемая"'); + Tcp.meMyFamily.TextHint.Text := TransStr('322'); + Tcp.lbBridgeDistribution.Caption := Load('425', 'Распространение'); + LoadList(Tcp.cbxBridgeDistribution, '426', '"Любое","Https","E-mail","Moat","Не распространять"'); + Tcp.cbUseAddress.Caption := Load('427', 'Задать внешний адрес вручную'); + Tcp.lbAddress.Caption := Load('428', 'Адрес'); + Tcp.edAddress.TextHint := Load('429', 'IP-адрес или имя узла'); + Tcp.lbPorts.Caption := Load('430', 'Настройка портов'); + Tcp.lbMaxAdvertisedBandwidth.Caption := Load('431', 'Рекламируемая'); + Tcp.lbSpeed4.Caption := Prefixes[1] + '/' + TransStr('180'); + Tcp.cbDirCache.Caption := Load('432', 'Использовать кэш каталога'); + Tcp.cbAssumeReachable.Caption := Load('433', 'Отключить проверку доступности сервера'); + Tcp.cbListenIPv6.Caption := Load('434', 'Прослушивать IPv6-адреса'); + Tcp.cbUseMyFamily.Caption := Load('435', 'Использовать семейство'); + Tcp.lbTotalMyFamily.Caption := TransStr('203') + ': ' + IntToStr(Tcp.meMyFamily.Lines.Count); + + Tcp.lbHsName.Caption := Load('190', 'Название');; + Tcp.edHsName.TextHint := Load('191', 'Имя каталога'); + Tcp.cbHsMaxStreams.Caption := Load('192', 'Ограничить число соединений'); + Tcp.lbHsMaxStreams.Caption := Load('193', 'Соединений на цепочку'); + Tcp.lbHsVersion.Caption := Load('194', 'Версия протокола'); + Tcp.lbHsNumIntroductionPoints.Caption := Load('195', 'Точек входа'); + Tcp.lbRendPostPeriod.Caption := Load('196', 'Интервал публикации'); + Tcp.lbMinutes.Caption := TransStr('197'); + Tcp.lbHsSocket.Caption := Load('198', 'Сервис'); + Tcp.lbHsState.Caption := Load('199', 'Состояние'); + Tcp.lbHsVirtualPort.Caption := Load('200', 'Виртуальный порт'); + Tcp.gbHsEdit.Caption := Load('272', 'Панель редактирования'); + LoadList(Tcp.cbxHsState, '436', '"Включено","Выключено"'); + + Tcp.cbUseTrackHostExits.Caption := Load('201', 'Сохранять выходной узел для указанных адресов'); + Tcp.lbTrackHostExitsExpire.Caption := Load('202', 'Менять по истечении'); + Tcp.lbSeconds4.Caption := TransStr('135'); + Tcp.lbTotalHosts.Caption := TransStr('203') + ': ' + IntToStr(Tcp.meTrackHostExits.Lines.Count); + Tcp.lbTotalNodesList.Caption := TransStr('203') + ': ' + IntToStr(Tcp.meNodesList.Lines.Count); + Tcp.meTrackHostExits.TextHint.Text := TransStr('208'); + Tcp.meNodesList.TextHint.Text := TransStr('209'); + Tcp.cbUseHiddenServiceVanguards.Caption := Load('437', 'Использовать авангарды для скрытых сервисов'); + Tcp.lbVanguardLayerType.Caption := Load('438', 'Изменять узел цепочки'); + LoadList(Tcp.cbxVanguardLayerType, '439', '"Автовыбор","Только второй","Только третий","Второй и третий"'); + Tcp.lbNodesListTypeCaption.Caption := Load('440', 'Выберите список для редактирования'); + Tcp.lbNodesListType.Caption := Load('441', 'Список'); + LoadList(Tcp.cbxNodesListType, '442', '"Входные узлы","Средние узлы","Выходные узлы","Запрещённые узлы"'); + Tcp.cbEnableNodesList.Caption := Load('443', 'Включить'); + + Tcp.gbNetworkScanner.Caption := TransStr('444'); + Tcp.cbEnableDetectAliveNodes.Caption := Load('445', 'Включить определение живых узлов'); + Tcp.cbEnablePingMeasure.Caption := Load('446', 'Включить измерение пинга'); + Tcp.lbScanPortTimeout.Caption := Load('447', 'Таймаут подключения к порту'); + Tcp.lbScanPortAttempts.Caption := Load('448', 'Количество попыток соединения с портом'); + Tcp.lbScanPingTimeout.Caption := Load('449', 'Таймаут пинг-запросов'); + Tcp.lbScanPingAttempts.Caption := Load('450', 'Количество попыток измерить пинг'); + Tcp.lbDelayBetweenAttempts.Caption := Load('451', 'Задержка между попытками'); + Tcp.lbScanMaxThread.Caption := Load('452', 'Количество потоков сканирования'); + Tcp.lbScanPortionTimeout.Caption := Load('453', 'Задержка между порциями'); + Tcp.lbScanPortionSize.Caption := Load('454', 'Количество сканирований на порцию'); + Tcp.cbAutoScanNewNodes.Caption := Load('455', 'Автоматически определять пинг и живые узлы'); + Tcp.lbFullScanInterval.Caption := Load('456', 'Полное сканирование каждые'); + Tcp.lbNonResponsedScanInterval.Caption := Load('457', 'Сканирование узлов без ответа каждые'); + Tcp.lbPartialScansCounts.Caption := Load('458', 'Количество частичных сканирований'); + Tcp.lbMiliseconds1.Caption := TransStr('459'); + Tcp.lbMiliseconds2.Caption := TransStr('459'); + Tcp.lbMiliseconds3.Caption := TransStr('459'); + Tcp.lbMiliseconds4.Caption := TransStr('459'); + Tcp.lbHours1.Caption := TransStr('477'); + Tcp.lbHours2.Caption := TransStr('477'); + + Tcp.gbTransports.Caption := Load('460', 'Подключаемые транспорты'); + Tcp.lbTransports.Caption := Load('461', 'Транспорты'); + Tcp.edTransports.TextHint := Load('462', 'Список поддерживаемых транспортов'); + Tcp.lbTransportsHandler.Caption := Load('463', 'Обработчик'); + Tcp.edTransportsHandler.TextHint := Load('464', 'Введите имя файла'); + Tcp.lbHandlerParams.Caption := Load('465', 'Параметры'); + Tcp.lbTransportType.Caption := TransStr('151'); + LoadList(Tcp.cbxTransportType, '466', '"Клиент","Сервер","Совмещённый"'); + + Tcp.gbAutoSelectRouters.Caption := Load('467', 'Автоподбор роутеров'); + Tcp.lbAutoSelEntry.Caption := TransStr('288'); + Tcp.lbAutoSelMiddle.Caption := TransStr('289'); + Tcp.lbAutoSelExit.Caption := TransStr('290'); + Tcp.lbAutoSelMinWeight.Caption := Load('468', 'Вес'); + Tcp.lbAutoSelMaxPing.Caption := Load('469', 'Пинг'); + Tcp.lbCount1.Caption := TransStr('470'); + Tcp.lbCount2.Caption := TransStr('470'); + Tcp.lbCount3.Caption := TransStr('470'); + Tcp.lbSpeed5.Caption := Prefixes[2] + '/' + TransStr('180'); + Tcp.lbMiliseconds5.Caption := TransStr('459'); + Tcp.lbAutoSelPriority.Caption := Load('471', 'Приоритет'); + LoadList(Tcp.cbxAutoSelPriority, '472', '"Сбалансированный","Вес в консенсусе","Пинг до узла","Случайный"'); + Tcp.cbAutoSelStableOnly.Caption := Load('473', 'Только стабильные'); + Tcp.cbAutoSelFilterCountriesOnly.Caption := Load('474', 'Только страны из фильтра'); + Tcp.cbAutoSelUniqueNodes.Caption := Load('475', 'Только уникальные'); + Tcp.cbAutoSelNodesWithPingOnly.Caption := Load('476', 'Только отвечающие на пинг'); + Tcp.cbAutoSelMiddleNodesWithoutDir.Caption := Load('591', 'Средние узлы без каталогов'); + + Tcp.gbTraffic.Caption := Load('211', 'Скорость'); + Tcp.lbDownloadSpeedCaption.Caption := TransStr('212') + ':'; + Tcp.lbUploadSpeedCaption.Caption := TransStr('213') + ':'; + Tcp.lbDLSpeed.Caption := BytesFormat(DLSpeed) + '/' + TransStr('180'); + Tcp.lbULSpeed.Caption := BytesFormat(ULSpeed) + '/' + TransStr('180'); + + Tcp.gbMaxTraffic.Caption := TransStr('175'); + Tcp.lbMaxDLSpeedCaption.Caption := TransStr('212') + ':'; + Tcp.lbMaxULSpeedCaption.Caption := TransStr('213') + ':'; + Tcp.lbMaxDLSpeed.Caption := BytesFormat(MaxDLSpeed) + '/' + TransStr('180'); + Tcp.lbMaxULSpeed.Caption := BytesFormat(MaxULSpeed) + '/' + TransStr('180'); + + Tcp.gbSession.Caption := Load('229', 'Итого за сеанс'); + Tcp.lbSessionDLCaption.Caption := TransStr('214') + ':'; + Tcp.lbSessionULCaption.Caption := TransStr('215') + ':'; + Tcp.lbSessionDL.Caption := BytesFormat(SessionDL); + Tcp.lbSessionUL.Caption := BytesFormat(SessionUL); + + Tcp.gbTotal.Caption := Load('403', 'Итого за всё время'); + Tcp.gbTotal.Hint := Format(TransStr('402'), [DateTimeToStr(UnixToDateTime(TotalStartDate))]); + Tcp.lbTotalDLCaption.Caption := TransStr('214') + ':'; + Tcp.lbTotalULCaption.Caption := TransStr('215') + ':'; + Tcp.lbTotalDL.Caption := BytesFormat(TotalDL); + Tcp.lbTotalUL.Caption := BytesFormat(TotalUL); + + Tcp.gbInfo.Caption := Load('222', 'Сведения'); + Tcp.lbClientVersionCaption.Caption := Load('223', 'Версия клиента') + ':'; + Tcp.lbUserDirCaption.Caption := Load('224', 'Профиль') + ':'; + Tcp.lbClientVersion.Hint := Load('325', 'Перейти на страницу загрузки Tor'); + Tcp.lbUserDir.Hint := Load('227', 'Открыть папку профиля'); + Tcp.lbStatusProxyAddrCaption.Caption := Load('225', 'Встроенный прокси') + ':'; + Tcp.lbStatusProxyAddr.Hint := Load('228', 'Скопировать в буфер обмена'); + Tcp.lbStatusScannerCaption.Caption := TransStr('444') + ':'; + + Tcp.gbServerInfo.Caption := Load('216', 'Сервер'); + Tcp.lbServerExternalIpCaption.Caption := Load('217', 'Внешний адрес') + ':'; + Tcp.lbFingerprintCaption.Caption := Load('218', 'Идентификатор') + ':'; + Tcp.lbBridgeCaption.Caption := Load('219', 'Адрес моста') + ':'; + if AlreadyStarted then + Tcp.lbDetailsTime.Caption := TransStr('221') + ': ' + SeparateRight(Tcp.lbDetailsTime.Caption, ': ') + else + begin + Tcp.lbDetailsTime.Caption := TransStr('221') + ': ' + TransStr('110'); + Tcp.lbClientVersion.Caption := TransStr('110'); + Tcp.lbServerExternalIp.Caption := TransStr('260'); + Tcp.lbFingerprint.Caption := TransStr('260'); + Tcp.lbBridge.Caption := TransStr('260'); + end; + + Tcp.gbSpeedGraph.Caption := Load('220', 'График скорости'); + + Tcp.lbSpeed3.Caption := Prefixes[2] + '/' + TransStr('180'); + Tcp.btnShowNodes.Caption := TransStr('547'); + LoadList(Tcp.cbxRoutersQuery, '548', '"Хеш","Ник","IPv4","IPv6","OR-порт","DIR-порт","Версия","Пинг"'); + Tcp.edRoutersQuery.TextHint := Load('549', 'Введите запрос'); + Tcp.lbFavoritesEntry.Caption := TransStr('288') + ': ' + IntToStr(Tcp.lbFavoritesEntry.Tag); + Tcp.lbFavoritesMiddle.Caption := TransStr('289') + ': ' + IntToStr(Tcp.lbFavoritesMiddle.Tag); + Tcp.lbFavoritesExit.Caption := TransStr('290') + ': ' + IntToStr(Tcp.lbFavoritesExit.Tag); + Tcp.lbFavoritesTotal.Caption := TransStr('203') + ': ' + IntToStr(Tcp.lbFavoritesTotal.Tag); + Tcp.lbExcludeNodes.Caption := TransStr('287') + ': ' + IntToStr(Tcp.lbExcludeNodes.Tag); + + Tcp.miHsOpenDir.Caption := Load('273', 'Каталог сервиса'); + Tcp.miHsCopy.Caption := TransStr('274'); + Tcp.miHsInsert.Caption := TransStr('279'); + Tcp.miHsDelete.Caption := TransStr('280'); + Tcp.miHsClear.Caption := TransStr('278'); + + Tcp.miServerCopy.Caption := TransStr('274'); + Tcp.miServerInfo.Caption := TransStr('281'); + + Tcp.miCacheOperations.Caption := Load('478', 'Операции с кэшем'); + Tcp.miUpdateIpToCountryCache.Caption := Load('479', 'Обновить страны в сетевом кэше');; + Tcp.miClearDNSCache.Caption := Load('283', 'Очистить DNS-кэш'); + Tcp.miClearServerCache.Caption := Load('480', 'Очистить серверный кэш'); + Tcp.miClearBridgeCacheUnnecessary.Caption := Load('481', 'Очистить кэш от ненужных мостов'); + Tcp.miClearBridgesCacheAll.Caption := Load('482', 'Очистить кэш всех мостов'); + Tcp.miClearPingCache.Caption := Load('483', 'Очистить кэш пинг-запросов'); + Tcp.miClearAliveCache.Caption := Load('484', 'Очистить кэш живых узлов'); + Tcp.miClearUnusedNetworkCache.Caption := Load('485', 'Очистить неиспользуемый сетевой кэш'); + Tcp.miResetScannerSchedule.Caption := Load('486', 'Сбросить расписание сканирования узлов'); + Tcp.miResetTotalsCounter.Caption := Load('487', 'Сбросить счётчик трафика'); + Tcp.miStartScan.Caption := Load('488', 'Запустить сканирование'); + Tcp.miScanNewNodes.Caption := Load('489', 'Новые узлы'); + Tcp.miScanNonResponsed.Caption := Load('490', 'Не отвечающие узлы'); + Tcp.miScanCachedBridges.Caption := Load('491', 'Кэшированные мосты'); + Tcp.miScanAll.Caption := Load('492', 'Все узлы'); + Tcp.miManualPingMeasure.Caption := Load('493', 'Измерять пинг'); + Tcp.miManualDetectAliveNodes.Caption := Load('494', 'Определять живые узлы'); + Tcp.miStopScan.Caption := Load('495', 'Остановить сканирование'); + Tcp.miResetGuards.Caption := Load('496', 'Сбросить сторожевые узлы'); + Tcp.miResetGuardsAll.Caption := Load('497', 'Все сторожевые узлы'); + Tcp.miResetGuardsBridges.Caption := Load('498', 'Мостовые узлы'); + Tcp.miResetGuardsRestricted.Caption := Load('499', 'Выбранные входные узлы'); + Tcp.miResetGuardsDefault.Caption := Load('500', 'Входные узлы по умолчанию'); + + Tcp.miDetailsUpdateIp.Caption := TransStr('284'); + Tcp.miDetailsCopy.Caption := TransStr('274'); + Tcp.miDetailsAddToNodesList.Caption := TransStr('285'); + Tcp.miDetailsRelayInfo.Caption := TransStr('281'); + Tcp.miDetailsSelectTemplate.Caption := Load('286', 'Выбрать шаблон'); + + Tcp.miGetBridges.Caption := Load('291', 'Получить мосты'); + Tcp.miGetBridgesSite.Caption := Load('501', 'Веб-сайт'); + Tcp.miGetBridgesTelegram.Caption := Load('502', 'Телеграм-канал'); + Tcp.miGetBridgesEmail.Caption := Load('503', 'Электронная почта'); + Tcp.miPreferWebTelegram.Caption := Load('504', 'Предпочитать веб-версию Телеграма'); + Tcp.miRequestObfuscatedBridges.Caption := Load('505', 'Запрашивать обфусцированные мосты'); + Tcp.miRequestIPv6Bridges.Caption := Load('506', 'Запрашивать IPv6-мосты'); + Tcp.miCut.Caption := TransStr('276'); + Tcp.miCopy.Caption := TransStr('274'); + Tcp.miPaste.Caption := TransStr('275'); + Tcp.miDelete.Caption := TransStr('280'); + Tcp.miSelectAll.Caption := TransStr('277'); + Tcp.miFind.Caption := TransStr('423'); + Tcp.miClear.Caption := TransStr('278'); + Tcp.miClearBridges.Caption := TransStr('278'); + Tcp.miClearBridgesNotAlive.Caption := Load('507', 'Не отвечающие на соединения'); + Tcp.miClearBridgesNonCached.Caption := Load('508', 'Отсутствующие в кэше'); + Tcp.miClearBridgesCached.Caption := Load('509', 'Найденные в кэше'); + Tcp.miClearBridgesAll.Caption := Load('510', 'Все мосты'); + + Tcp.miLogOptions.Caption := TransStr('107'); + Tcp.miWriteLogFile.Caption := Load('292', 'Записывать в файл'); + Tcp.miAutoClear.Caption := Load('293', 'Очищать при каждом запуске'); + Tcp.miAutoScroll.Caption := Load('294', 'Автоматическая прокрутка'); + Tcp.miScrollBars.Caption := Load('295', 'Полоса прокрутки'); + Tcp.miSbVertical.Caption := Load('296', 'Вертикальная'); + Tcp.miSbHorizontal.Caption := Load('297', 'Горизонтальная'); + Tcp.miSbBoth.Caption := Load('298', 'Все'); + Tcp.miSbNone.Caption := Load('299', 'Нет'); + Tcp.miWordWrap.Caption := Load('300', 'Перенос строк'); + Tcp.miSafeLogging.Caption := Load('301', 'Скрывать сетевые адреса'); + Tcp.miLogLevel.Caption := Load('302', 'Уровень журналирования'); + Tcp.miDebug.Caption := Load('303', 'Отладка'); + Tcp.miInfo.Caption := Load('304', 'Информация'); + Tcp.miNotice.Caption := Load('305', 'Уведомления'); + Tcp.miWarn.Caption := Load('306', 'Предупреждения'); + Tcp.miErr.Caption := Load('307', 'Ошибки'); + Tcp.miOpenFileLog.Caption := Load('308', 'Открыть файл журнала'); + Tcp.miLogCopy.Caption := TransStr('274'); + Tcp.miLogSelectAll.Caption := TransStr('277'); + Tcp.miLogFind.Caption := TransStr('423'); + Tcp.miLogClear.Caption := TransStr('278'); + Tcp.miLogSeparate.Caption := Load('511', 'Разделение файла журнала'); + Tcp.miLogSeparateNone.Caption := Load('512', 'Не разделять'); + Tcp.miLogSeparateMonth.Caption := Load('513', 'По месяцам'); + Tcp.miLogSeparateDay.Caption := Load('514', 'По дням'); + + Tcp.miStat.Caption := Load('309', 'Статистика'); + Tcp.miStatRelays.Caption := Load('310', 'Все'); + Tcp.miStatGuards.Caption := Load('311', 'Сторожевые'); + Tcp.miStatExit.Caption := Load('312', 'Выходные'); + Tcp.miStatAggregate.Caption := Load('313', 'Общая по странам'); + Tcp.miSaveTemplate.Caption := Load('314', 'Сохранить'); + Tcp.miLoadTemplate.Caption := Load('315', 'Загрузить'); + Tcp.miDeleteTemplate.Caption := TransStr('280'); + Tcp.miClearFilter.Caption := TransStr('278'); + Tcp.miClearFilterEntry.Caption := TransStr('288'); + Tcp.miClearFilterMiddle.Caption := TransStr('289'); + Tcp.miClearFilterExit.Caption := TransStr('290'); + Tcp.miClearFilterExclude.Caption := TransStr('287'); + Tcp.miClearFilterAll.Caption := Load('316', 'Все выбранные'); + Tcp.miFilterHideUnused.Caption := Load('163', 'Скрыть неиспользуемые страны'); + Tcp.miFilterScrollTop.Caption := TransStr('160'); + Tcp.miFilterOptions.Caption := TransStr('107'); + Tcp.miFilterSelectRow.Caption := TransStr('515');; + Tcp.miNotLoadEmptyTplData.Caption := Load('516', 'Не загружать пустые данные шаблона'); + Tcp.miIgnoreTplLoadParamsOutsideTheFilter.Caption := Load('517', 'Игнорировать параметры загрузки из шаблона вне фильтра'); + Tcp.miReplaceDisabledFavoritesWithCountries.Caption := Load('518', 'Заменять выключенные списки узлов выбранными странами'); + Tcp.miTplSave.Caption := Load('519', 'Сохранять в шаблоне..'); + Tcp.miTplLoad.Caption := Load('520', 'Загружать из шаблона..'); + Tcp.miTplSaveCountries.Caption := TransStr('521'); + Tcp.miTplSaveRouters.Caption := TransStr('522'); + Tcp.miTplSaveExcludes.Caption := TransStr('523'); + Tcp.miTplSaveSA.Caption := TransStr('368'); + Tcp.miTplSaveUA.Caption := TransStr('369'); + Tcp.miTplLoadCountries.Caption := TransStr('521'); + Tcp.miTplLoadRouters.Caption := TransStr('522'); + Tcp.miTplLoadExcludes.Caption := TransStr('523'); + Tcp.miTplLoadSA.Caption := TransStr('368'); + Tcp.miTplLoadUA.Caption := TransStr('369'); + + Tcp.miChangeCircuit.Caption := TransStr('103'); + Tcp.miShowStatus.Caption := TransStr('282'); + Tcp.miShowOptions.Caption := TransStr('107'); + Tcp.miShowLog.Caption := TransStr('108'); + Tcp.miShowCircuits.Caption := TransStr('327'); + Tcp.miShowRouters.Caption := TransStr('323'); + Tcp.miAbout.Caption := TransStr('355'); + Tcp.miExit.Caption := Load('319', 'Выход'); + + Tcp.miCircuitsDestroy.Caption := TransStr('524'); + Tcp.miDestroyCircuit.Caption := Load('527', 'Цепочку'); + Tcp.miDestroyStreams.Caption := TransStr('528'); + Tcp.miDestroyExitCircuits.Caption := Load('529', 'Все выходные цепочки'); + Tcp.miCircuitsUpdateNow.Caption := TransStr('284'); + Tcp.miCircuitsSort.Caption := TransStr('525'); + Tcp.miCircuitsSortID.Caption := TransStr('221'); + Tcp.miCircuitsSortPurpose.Caption := TransStr('530'); + Tcp.miCircuitsSortStreams.Caption := TransStr('528'); + Tcp.miCircuitsSortDL.Caption := TransStr('214'); + Tcp.miCircuitsSortUL.Caption := TransStr('215'); + Tcp.miCircuitFilter.Caption := TransStr('526'); + Tcp.miCircOneHop.Caption := TransStr('331'); + Tcp.miCircInternal.Caption := TransStr('332'); + Tcp.miCircExit.Caption := TransStr('333'); + Tcp.miCircHsClientDir.Caption := TransStr('334'); + Tcp.miCircHsClientIntro.Caption := TransStr('335'); + Tcp.miCircHsClientRend.Caption := TransStr('336'); + Tcp.miCircHsServiceDir.Caption := TransStr('337'); + Tcp.miCircHsServiceIntro.Caption := TransStr('338'); + Tcp.miCircHsServiceRend.Caption := TransStr('339'); + Tcp.miCircHsVanguards.Caption := TransStr('340'); + Tcp.miCircPathBiasTesting.Caption := TransStr('341'); + Tcp.miCircTesting.Caption := TransStr('342'); + Tcp.miCircCircuitPadding.Caption := TransStr('343'); + Tcp.miCircMeasureTimeout.Caption := TransStr('344'); + Tcp.miCircOther.Caption := TransStr('345'); + Tcp.miCircSA.Caption := TransStr('368'); + Tcp.miCircUA.Caption := TransStr('369'); + Tcp.miCircuitOptions.Caption := TransStr('107'); + + Tcp.miHideCircuitsWithoutStreams.Caption := Load('531', 'Скрывать цепочки без соединений'); + Tcp.miAlwaysShowExitCircuit.Caption := Load('532', 'Всегда показывать выходную цепочку'); + Tcp.miSelectExitCircuitWhetItChanges.Caption := Load('533', 'Выделять выходную цепочку при её изменении'); + Tcp.miShowCircuitsTraffic.Caption := Load('534', 'Показывать трафик цепочек'); + Tcp.miShowStreamsTraffic.Caption := Load('535', 'Показывать трафик соединений'); + Tcp.miShowStreamsInfo.Caption := Load('536', 'Показывать подробности соединений'); + Tcp.miCircuitsUpdateSpeed.Caption := Load('537', 'Скорость обновления'); + Tcp.miCircuitsUpdateHigh.Caption := Load('538', 'Высокая'); + Tcp.miCircuitsUpdateNormal.Caption := Load('539', 'Нормальная'); + Tcp.miCircuitsUpdateLow.Caption := Load('540', 'Низкая'); + Tcp.miCircuitsUpdateManual.Caption := Load('541', 'Обновлять вручную'); + + Tcp.miStreamsDestroyStream.Caption := TransStr('524'); + Tcp.miStreamsOpenInBrowser.Caption := Load('542', 'Открыть в браузере'); + Tcp.miStreamsSort.Caption := TransStr('525'); + Tcp.miStreamsSortID.Caption := TransStr('221'); + Tcp.miStreamsSortTarget.Caption := TransStr('330'); + Tcp.miStreamsSortTrack.Caption := Load('543', 'Привязка к выходному узлу'); + Tcp.miStreamsSortStreams.Caption := TransStr('528'); + Tcp.miStreamsSortDL.Caption := TransStr('214'); + Tcp.miStreamsSortUL.Caption := TransStr('215'); + + Tcp.miStreamsInfoDestroyStream.Caption := TransStr('524'); + Tcp.miStreamsInfoSort.Caption := TransStr('525'); + Tcp.miStreamsInfoSortID.Caption := TransStr('221'); + Tcp.miStreamsInfoSortSource.Caption := Load('544', 'Источник'); + Tcp.miStreamsInfoSortDest.Caption := Load('545', 'Назначение'); + Tcp.miStreamsInfoSortPurpose.Caption := TransStr('530'); + Tcp.miStreamsInfoSortDL.Caption := TransStr('214'); + Tcp.miStreamsInfoSortUL.Caption := TransStr('215'); + + Tcp.miShowExit.Caption := Load('550', 'Выходной'); + Tcp.miShowGuard.Caption := Load('551', 'Сторожевой'); + Tcp.miShowOther.Caption := Load('552', 'Обычный'); + Tcp.miShowAuthority.Caption := Load('553', 'Корневой'); + Tcp.miShowBridge.Caption := Load('554', 'Кэшированный мост'); + Tcp.miShowFast.Caption := Load('555', 'Быстрый'); + Tcp.miShowStable.Caption := Load('556', 'Стабильный'); + Tcp.miShowV2Dir.Caption := Load('557', 'Вторая версия каталога'); + Tcp.miShowHSDir.Caption := Load('558', 'Каталог скрытых сервисов'); + Tcp.miShowDirMirror.Caption := Load('559', 'Зеркало каталога'); + Tcp.miShowRecommend.Caption := Load('560', 'Рекомендуемая версия'); + Tcp.miShowAlive.Caption := Load('561', 'Живой узел'); + Tcp.miReverseConditions.Caption := Load('562', 'Обратить условия фильтра'); + Tcp.miShowNodesUA.Caption := TransStr('369'); + + Tcp.miRtResetFilter.Caption := Load('563', 'Сброс фильтров'); + Tcp.miRtCopy.Caption := TransStr('274'); + Tcp.miRtAddToNodesList.Caption := TransStr('285'); + Tcp.miRtSelectAsBridge.Caption := Load('564', 'Выбрать в качестве моста'); + Tcp.miRtDisableBridges.Caption := Load('565', 'Отменить использование мостов'); + Tcp.miRtRelayInfo.Caption := TransStr('281'); + Tcp.miRtFilters.Caption := TransStr('526'); + Tcp.miRtFiltersType.Caption := TransStr('547'); + Tcp.miRtFiltersCountry.Caption := TransStr('114'); + Tcp.miRtFiltersWeight.Caption := Load('566', 'Вес в консенсусе'); + Tcp.miRtFiltersQuery.Caption := Load('567', 'Запрос пользователя'); + Tcp.miRtFilterSA.Caption := TransStr('368'); + Tcp.miRtFilterUA.Caption := TransStr('369'); + Tcp.miRoutersOptions.Caption := TransStr('107'); + Tcp.miRoutersScrollTop.Caption := TransStr('160'); + Tcp.miRoutersSelectRow.Caption := TransStr('515'); + Tcp.miShowFlagsHint.Caption := Load('568', 'Показывать подсказки флагов при наведении мыши'); + Tcp.miLoadCachedRoutersOnStartup.Caption := Load('569', 'Загружать роутеры из кэша при запуске'); + Tcp.miDisableSelectionUnSuitableAsBridge.Caption := Load('570', 'Запретить выбор в качестве моста неподходящих узлов'); + Tcp.miConvertNodes.Caption := Load('571', 'Преобразовывать IP, CIDR и коды стран в хэши'); + Tcp.miEnableConvertNodesOnIncorrectClear.Caption := Load('572', 'При очистке неправильных узлов'); + Tcp.miEnableConvertNodesOnAddToNodesList.Caption := Load('573', 'При добавлении в список узлов'); + Tcp.miEnableConvertNodesOnRemoveFromNodesList.Caption := Load('574', 'При удалении из списка узлов'); + Tcp.miConvertIpNodes.Caption := Load('575', 'Преобразовывать IP-адреса'); + Tcp.miConvertCidrNodes.Caption := Load('576', 'Преобразовывать CIDR-маски'); + Tcp.miConvertCountryNodes.Caption := Load('577', 'Преобразовывать коды стран'); + Tcp.miIgnoreConvertExcludeNodes.Caption := Load('578', 'Исключить список запрещённых узлов'); + Tcp.miAvoidAddingIncorrectNodes.Caption := Load('579', 'Избегать добавление неправильных узлов'); + Tcp.miDisableFiltersOn.Caption := Load('580', 'Отключать фильтры при событии'); + Tcp.miDisableFiltersOnUserQuery.Caption := Load('581', 'Отправка запроса пользователя'); + Tcp.miDisableFiltersOnAuthorityOrBridge.Caption := Load('582', 'Выбор мостов или корневых узлов'); + Tcp.miRtSaveDefault.Caption := Load('583', 'Сохранить как фильтр по умолчанию'); + Tcp.miClearRouters.Caption := TransStr('278'); + Tcp.miClearRoutersEntry.Caption := TransStr('288'); + Tcp.miClearRoutersMiddle.Caption := TransStr('289'); + Tcp.miClearRoutersExit.Caption := TransStr('290'); + Tcp.miClearRoutersExclude.Caption := TransStr('287'); + Tcp.miClearRoutersFavorites.Caption := Load('584', 'Все избранные'); + Tcp.miClearRoutersIncorrect.Caption := Load('585', 'Неправильные узлы'); + Tcp.miClearRoutersAbsent.Caption := Load('586', 'Отсутствующие в консенсусе'); + + Tcp.miTransportsInsert.Caption := TransStr('279'); + Tcp.miTransportsDelete.Caption := TransStr('280'); + Tcp.miTransportsOpenDir.Caption := Load('587', 'Каталог транспортов'); + Tcp.miTransportsReset.Caption := Load('588', 'Настройки по умолчанию'); + Tcp.miTransportsClear.Caption := TransStr('278'); + + Tcp.miTrafficPeriod.Caption := Load('589', 'Период'); + Tcp.miPeriod1m.Caption := '1 ' + TransStr('197'); + Tcp.miPeriod5m.Caption := '5 ' + TransStr('197'); + Tcp.miPeriod15m.Caption := '15 ' + TransStr('197'); + Tcp.miPeriod30m.Caption := '30 ' + TransStr('197'); + Tcp.miPeriod1h.Caption := '1 ' + TransStr('477'); + Tcp.miPeriod3h.Caption := '3 ' + TransStr('477'); + Tcp.miPeriod6h.Caption := '6 ' + TransStr('477'); + Tcp.miPeriod12h.Caption := '12 ' + TransStr('477'); + Tcp.miPeriod24h.Caption := '24 ' + TransStr('477'); + Tcp.miSelectGraph.Caption := Load('590', 'Показывать графики'); + Tcp.miSelectGraphDL.Caption := TransStr('212'); + Tcp.miSelectGraphUL.Caption := TransStr('213'); + + if ValidInt(TransStr('Locale'), 0, 65535) then + CurrentLanguage := StrToInt(TransStr('Locale')) + else + CurrentLanguage := GetSystemDefaultLangID; + + Tcp.lbExitCountry.Font.Style := [fsUnderline]; + Tcp.lbExitIp.Font.Style := [fsUnderline]; + + if Tcp.cbxThemes.ItemIndex = 0 then + begin + Tcp.cbxThemes.Items[0] := TransStr('104'); + Tcp.cbxThemes.ItemIndex := 0; + end; + + if Load('UseDefaultCountries', '0') = '1' then + CurrentTranslate := 'DefaultCountries'; + + LoadStr('au','Австралия'); + LoadStr('at','Австрия'); + LoadStr('az','Азербайджан'); + LoadStr('ax','Аланды'); + LoadStr('al','Албания'); + LoadStr('dz','Алжир'); + LoadStr('as','Американское Самоа'); + LoadStr('ai','Ангилья'); + LoadStr('ao','Ангола'); + LoadStr('ad','Андорра'); + LoadStr('aq','Антарктида'); + LoadStr('ag','Антигуа и Барбуда'); + LoadStr('ar','Аргентина'); + LoadStr('am','Армения'); + LoadStr('aw','Аруба'); + LoadStr('af','Афганистан'); + LoadStr('bs','Багамы'); + LoadStr('bd','Бангладеш'); + LoadStr('bb','Барбадос'); + LoadStr('bh','Бахрейн'); + LoadStr('bz','Белиз'); + LoadStr('by','Беларусь'); + LoadStr('be','Бельгия'); + LoadStr('bj','Бенин'); + LoadStr('bm','Бермудские острова'); + LoadStr('bg','Болгария'); + LoadStr('bo','Боливия'); + LoadStr('bq','Бонайре, Синт-Эстатиус и Саба'); + LoadStr('ba','Босния и Герцеговина'); + LoadStr('bw','Ботсвана'); + LoadStr('br','Бразилия'); + LoadStr('io','Британская территория в Индийском океане'); + LoadStr('bn','Бруней'); + LoadStr('bf','Буркина Фасо'); + LoadStr('bi','Бурунди'); + LoadStr('bt','Бутан'); + LoadStr('vu','Вануату'); + LoadStr('va','Ватикан'); + LoadStr('gb','Великобритания'); + LoadStr('hu','Венгрия'); + LoadStr('ve','Венесуэла'); + LoadStr('vg','Виргинские острова (Великобритания)'); + LoadStr('vi','Виргинские острова (США)'); + LoadStr('um','Внешние малые острова (США)'); + LoadStr('tl','Восточный Тимор'); + LoadStr('vn','Вьетнам'); + LoadStr('ga','Габон'); + LoadStr('gy','Гайана'); + LoadStr('ht','Гаити'); + LoadStr('gm','Гамбия'); + LoadStr('gh','Гана'); + LoadStr('gp','Гваделупа'); + LoadStr('gt','Гватемала'); + LoadStr('gf','Французская Гвиана'); + LoadStr('gn','Гвинея'); + LoadStr('gw','Гвинея-Биссау'); + LoadStr('de','Германия'); + LoadStr('gg','Гернси'); + LoadStr('gi','Гибралтар'); + LoadStr('hn','Гондурас'); + LoadStr('hk','Гонконг'); + LoadStr('ps','Палестина'); + LoadStr('gd','Гренада'); + LoadStr('gl','Гренландия'); + LoadStr('gr','Греция'); + LoadStr('ge','Грузия'); + LoadStr('gu','Гуам'); + LoadStr('dk','Дания'); + LoadStr('cd','Демократическая Республика Конго'); + LoadStr('je','Джерси'); + LoadStr('dj','Джибути'); + LoadStr('dm','Остров Доминика'); + LoadStr('do','Доминиканская Республика'); + LoadStr('eg','Египет'); + LoadStr('zm','Замбия'); + LoadStr('zw','Зимбабве'); + LoadStr('ye','Йемен'); + LoadStr('il','Израиль'); + LoadStr('in','Индия'); + LoadStr('id','Индонезия'); + LoadStr('jo','Иордания'); + LoadStr('iq','Ирак'); + LoadStr('ir','Иран'); + LoadStr('ie','Ирландия'); + LoadStr('is','Исландия'); + LoadStr('es','Испания'); + LoadStr('it','Италия'); + LoadStr('cv','Кабо-Верде'); + LoadStr('kz','Казахстан'); + LoadStr('kh','Камбоджа'); + LoadStr('cm','Камерун'); + LoadStr('ca','Канада'); + LoadStr('qa','Катар'); + LoadStr('ke','Кения'); + LoadStr('cy','Кипр'); + LoadStr('kg','Кыргызстан'); + LoadStr('ki','Кирибати'); + LoadStr('cn','Китай'); + LoadStr('kp','Северная Корея'); + LoadStr('cc','Кокосовые острова'); + LoadStr('co','Колумбия'); + LoadStr('km','Коморские острова'); + LoadStr('cr','Коста-Рика'); + LoadStr('ci','Кот-д''Ивуар'); + LoadStr('cu','Куба'); + LoadStr('kw','Кувейт'); + LoadStr('cw','Кюрасао'); + LoadStr('la','Лаос'); + LoadStr('lv','Латвия'); + LoadStr('ls','Лесото'); + LoadStr('lr','Либерия'); + LoadStr('lb','Ливан'); + LoadStr('ly','Ливия'); + LoadStr('lt','Литва'); + LoadStr('li','Лихтенштейн'); + LoadStr('lu','Люксембург'); + LoadStr('mu','Маврикий'); + LoadStr('mr','Мавритания'); + LoadStr('mg','Мадагаскар'); + LoadStr('yt','Майотта'); + LoadStr('mo','Макао'); + LoadStr('mk','Северная Македония'); + LoadStr('mw','Малави'); + LoadStr('my','Малайзия'); + LoadStr('ml','Мали'); + LoadStr('mv','Мальдивские острова'); + LoadStr('mt','Мальта'); + LoadStr('ma','Марокко'); + LoadStr('mq','Мартиника'); + LoadStr('mh','Маршалловы острова'); + LoadStr('mx','Мексика'); + LoadStr('fm','Микронезия'); + LoadStr('mz','Мозамбик'); + LoadStr('md','Молдова'); + LoadStr('mc','Монако'); + LoadStr('mn','Монголия'); + LoadStr('ms','Монсеррат'); + LoadStr('mm','Мьянма'); + LoadStr('na','Намибия'); + LoadStr('nr','Науру'); + LoadStr('np','Непал'); + LoadStr('ne','Нигер'); + LoadStr('ng','Нигерия'); + LoadStr('nl','Нидерланды'); + LoadStr('ni','Никарагуа'); + LoadStr('nu','Ниуе'); + LoadStr('nz','Новая Зеландия'); + LoadStr('nc','Новая Каледония'); + LoadStr('no','Норвегия'); + LoadStr('ae','ОАЭ'); + LoadStr('om','Оман'); + LoadStr('bv','Остров Буве'); + LoadStr('im','Остров Мэн'); + LoadStr('nf','Остров Норфолк'); + LoadStr('cx','Остров Рождества'); + LoadStr('ky','Каймановы острова'); + LoadStr('ck','Острова Кука'); + LoadStr('pn','Питкэрн'); + LoadStr('sh','Остров Святой Елены'); + LoadStr('pk','Пакистан'); + LoadStr('pw','Палау'); + LoadStr('pa','Панама'); + LoadStr('pg','Папуа-Новая Гвинея'); + LoadStr('py','Парагвай'); + LoadStr('pe','Перу'); + LoadStr('pl','Польша'); + LoadStr('pt','Португалия'); + LoadStr('pr','Пуэрто-Рико'); + LoadStr('cg','Конго'); + LoadStr('kr','Южная Корея'); + LoadStr('re','Реюньон'); + LoadStr('ru','Россия'); + LoadStr('rw','Руанда'); + LoadStr('ro','Румыния'); + LoadStr('eh','Западная Сахара'); + LoadStr('sv','Сальвадор'); + LoadStr('ws','Самоа'); + LoadStr('sm','Сан-Марино'); + LoadStr('st','Сан-Томе и Принсипе'); + LoadStr('sa','Саудовская Аравия'); + LoadStr('sz','Свазиленд'); + LoadStr('mp','Северные Марианские острова'); + LoadStr('sc','Сейшельские острова'); + LoadStr('bl','Остров Святого Бартоломея'); + LoadStr('sn','Сенегал'); + LoadStr('mf','Остров Святого Мартина'); + LoadStr('pm','Сен-Пьер и Микелон'); + LoadStr('vc','Сент-Винсент и Гренадины'); + LoadStr('kn','Сент-Киттс и Невис'); + LoadStr('lc','Сент-Люсия'); + LoadStr('rs','Сербия'); + LoadStr('sg','Сингапур'); + LoadStr('sx','Синт-Мартен'); + LoadStr('sy','Сирия'); + LoadStr('sk','Словакия'); + LoadStr('si','Словения'); + LoadStr('sb','Соломонские острова'); + LoadStr('so','Сомали'); + LoadStr('sd','Судан'); + LoadStr('sr','Суринам'); + LoadStr('us','США'); + LoadStr('sl','Сьерра-Леоне'); + LoadStr('tj','Таджикистан'); + LoadStr('tw','Тайвань'); + LoadStr('th','Тайланд'); + LoadStr('tz','Танзания'); + LoadStr('tc','Острова Тёркс и Кайкос'); + LoadStr('tg','Того'); + LoadStr('tk','Токелау'); + LoadStr('to','Тонга'); + LoadStr('tt','Тринидад и Тобаго'); + LoadStr('tv','Тувалу'); + LoadStr('tn','Тунис'); + LoadStr('tm','Туркменистан'); + LoadStr('tr','Турция'); + LoadStr('ug','Уганда'); + LoadStr('uz','Узбекистан'); + LoadStr('ua','Украина'); + LoadStr('wf','Уоллис и Футуна'); + LoadStr('uy','Уругвай'); + LoadStr('fo','Фарерские острова'); + LoadStr('fj','Фиджи'); + LoadStr('ph','Филиппины'); + LoadStr('fi','Финляндия'); + LoadStr('fk','Фолклендские острова'); + LoadStr('fr','Франция'); + LoadStr('pf','Французская Полинезия'); + LoadStr('tf','Французские Южные Территории'); + LoadStr('hm','Острова Херд и Макдональд'); + LoadStr('hr','Хорватия'); + LoadStr('cf','ЦАР'); + LoadStr('td','Чад'); + LoadStr('me','Черногория'); + LoadStr('cz','Чешская Республика'); + LoadStr('cl','Чили'); + LoadStr('ch','Швейцария'); + LoadStr('se','Швеция'); + LoadStr('sj','Свальбард и Ян-Майен'); + LoadStr('lk','Шри-Ланка'); + LoadStr('ec','Эквадор'); + LoadStr('gq','Экваториальная Гвинея'); + LoadStr('er','Эритрея'); + LoadStr('ee','Эстония'); + LoadStr('et','Эфиопия'); + LoadStr('za','ЮАР'); + LoadStr('gs','Южная Джорджия и Южные Сандвичевы острова'); + LoadStr('ss','Южный Судан'); + LoadStr('jm','Ямайка'); + LoadStr('jp','Япония'); + LoadStr('??','Неизвестная'); + LoadStr('eu','Европейский союз'); + + finally + LangIniFile.Free; + end; +end; + +end. + + + diff --git a/source/Main.dfm b/source/Main.dfm new file mode 100644 index 0000000..7bf4714 --- /dev/null +++ b/source/Main.dfm @@ -0,0 +1,6201 @@ +object Tcp: TTcp + Left = 299 + Top = 196 + BorderIcons = [biSystemMenu, biMinimize] + BorderStyle = bsSingle + Caption = #1055#1072#1085#1077#1083#1100' '#1091#1087#1088#1072#1074#1083#1077#1085#1080#1103' Tor' + ClientHeight = 531 + ClientWidth = 728 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + OnClose = FormClose + OnCloseQuery = FormCloseQuery + OnCreate = FormCreate + OnDestroy = FormDestroy + OnPaint = FormPaint + OnResize = FormResize + PixelsPerInch = 96 + TextHeight = 13 + object paLog: TPanel + Left = 3 + Top = 92 + Width = 721 + Height = 435 + BevelInner = bvLowered + Color = clWindow + DoubleBuffered = True + ParentBackground = False + ParentDoubleBuffered = False + ShowCaption = False + TabOrder = 2 + Visible = False + object meLog: TMemo + Left = 2 + Top = 2 + Width = 717 + Height = 431 + Align = alClient + BevelInner = bvNone + BevelOuter = bvNone + BorderStyle = bsNone + HideSelection = False + PopupMenu = mnLog + ReadOnly = True + ScrollBars = ssVertical + TabOrder = 0 + WordWrap = False + OnExit = MemoExit + OnKeyPress = MemoKeyPress + OnMouseDown = meLogMouseDown + OnMouseUp = meLogMouseUp + end + end + object paStatus: TPanel + Left = 3 + Top = 92 + Width = 721 + Height = 435 + BevelInner = bvLowered + Color = clWindow + DoubleBuffered = True + ParentBackground = False + ParentDoubleBuffered = False + ShowCaption = False + TabOrder = 3 + Visible = False + object gbSession: TGroupBox + Left = 12 + Top = 126 + Width = 155 + Height = 57 + Caption = #1042#1089#1077#1075#1086' '#1079#1072' '#1089#1077#1089#1089#1080#1102 + ParentBackground = False + TabOrder = 2 + object lbSessionDLCaption: TLabel + Left = 36 + Top = 16 + Width = 53 + Height = 13 + Alignment = taRightJustify + Caption = #1055#1086#1083#1091#1095#1077#1085#1086':' + Transparent = True + end + object lbSessionULCaption: TLabel + Left = 23 + Top = 32 + Width = 66 + Height = 13 + Alignment = taRightJustify + AutoSize = False + Caption = #1054#1090#1087#1088#1072#1074#1083#1077#1085#1086':' + Transparent = True + end + object lbSessionDL: TLabel + Left = 92 + Top = 16 + Width = 25 + Height = 13 + Caption = '0,0 '#1041 + Transparent = True + end + object lbSessionUL: TLabel + Left = 92 + Top = 32 + Width = 25 + Height = 13 + Caption = '0,0 '#1041 + Transparent = True + end + end + object gbServerInfo: TGroupBox + Left = 12 + Top = 307 + Width = 698 + Height = 117 + Caption = #1057#1077#1088#1074#1077#1088 + ParentBackground = False + TabOrder = 6 + Visible = False + object lbServerExternalIpCaption: TLabel + Left = 19 + Top = 16 + Width = 81 + Height = 13 + Alignment = taRightJustify + Caption = #1042#1085#1077#1096#1085#1080#1081' '#1072#1076#1088#1077#1089':' + Transparent = True + end + object lbFingerprintCaption: TLabel + Left = 14 + Top = 33 + Width = 86 + Height = 13 + Alignment = taRightJustify + Caption = #1048#1076#1077#1085#1090#1080#1092#1080#1082#1072#1090#1086#1088':' + Transparent = True + end + object lbServerExternalIp: TLabel + Left = 103 + Top = 17 + Width = 71 + Height = 13 + Caption = #1053#1077' '#1086#1087#1088#1077#1076#1077#1083#1105#1085 + PopupMenu = mnServerInfo + Transparent = True + OnMouseMove = lbServerInfoMouseMove + end + object lbFingerprint: TLabel + Left = 103 + Top = 33 + Width = 71 + Height = 13 + Caption = #1053#1077' '#1086#1087#1088#1077#1076#1077#1083#1105#1085 + PopupMenu = mnServerInfo + Transparent = True + OnMouseMove = lbServerInfoMouseMove + end + object lbBridgeCaption: TLabel + Left = 33 + Top = 49 + Width = 67 + Height = 13 + Alignment = taRightJustify + Caption = #1040#1076#1088#1077#1089' '#1084#1086#1089#1090#1072':' + Transparent = True + end + object lbBridge: TLabel + Left = 103 + Top = 49 + Width = 71 + Height = 13 + Caption = #1053#1077' '#1086#1087#1088#1077#1076#1077#1083#1105#1085 + PopupMenu = mnServerInfo + Transparent = True + OnMouseMove = lbServerInfoMouseMove + end + end + object gbTraffic: TGroupBox + Left = 12 + Top = 6 + Width = 155 + Height = 57 + Caption = #1057#1082#1086#1088#1086#1089#1090#1100 + ParentBackground = False + TabOrder = 0 + object lbDownloadSpeedCaption: TLabel + Left = 39 + Top = 16 + Width = 50 + Height = 13 + Alignment = taRightJustify + Caption = #1047#1072#1075#1088#1091#1079#1082#1072':' + Transparent = True + end + object lbUploadSpeedCaption: TLabel + Left = 35 + Top = 32 + Width = 54 + Height = 13 + Alignment = taRightJustify + Caption = #1054#1090#1087#1088#1072#1074#1082#1072':' + Transparent = True + end + object lbDLSpeed: TLabel + Left = 92 + Top = 16 + Width = 34 + Height = 13 + Caption = '0,0 '#1041'/c' + Transparent = True + end + object lbULSpeed: TLabel + Left = 92 + Top = 32 + Width = 34 + Height = 13 + Caption = '0,0 '#1041'/c' + Transparent = True + end + end + object gbInfo: TGroupBox + Left = 12 + Top = 247 + Width = 698 + Height = 57 + Caption = #1057#1074#1077#1076#1077#1085#1080#1103 + ParentBackground = False + TabOrder = 5 + object lbClientVersionCaption: TLabel + Left = 16 + Top = 16 + Width = 84 + Height = 13 + Alignment = taRightJustify + Caption = #1042#1077#1088#1089#1080#1103' '#1082#1083#1080#1077#1085#1090#1072':' + Transparent = True + end + object lbClientVersion: TLabel + Left = 103 + Top = 16 + Width = 77 + Height = 13 + Cursor = crHandPoint + Hint = #1055#1077#1088#1077#1081#1090#1080' '#1085#1072' '#1089#1090#1088#1072#1085#1080#1094#1091' '#1079#1072#1075#1088#1091#1079#1082#1080' Tor' + Caption = #1053#1077' '#1086#1087#1088#1077#1076#1077#1083#1077#1085#1072 + ParentShowHint = False + ShowHint = True + Transparent = True + OnClick = lbClientVersionClick + end + object lbUserDirCaption: TLabel + Left = 51 + Top = 32 + Width = 49 + Height = 13 + Alignment = taRightJustify + Caption = #1055#1088#1086#1092#1080#1083#1100':' + Transparent = True + end + object lbUserDir: TLabel + Left = 103 + Top = 32 + Width = 73 + Height = 13 + Cursor = crHandPoint + Hint = #1054#1090#1082#1088#1099#1090#1100' '#1087#1072#1087#1082#1091' '#1087#1088#1086#1092#1080#1083#1103 + Caption = #1055#1086' '#1091#1084#1086#1083#1095#1072#1085#1080#1102 + ParentShowHint = False + ShowHint = True + Transparent = True + OnClick = lbUserDirClick + end + object lbStatusProxyAddrCaption: TLabel + Left = 270 + Top = 16 + Width = 103 + Height = 13 + Alignment = taRightJustify + Caption = #1042#1089#1090#1088#1086#1077#1085#1085#1099#1081' '#1087#1088#1086#1082#1089#1080':' + Transparent = True + end + object lbStatusProxyAddr: TLabel + Left = 376 + Top = 16 + Width = 76 + Height = 13 + Cursor = crHandPoint + Hint = #1057#1082#1086#1087#1080#1088#1086#1074#1072#1090#1100' '#1074' '#1073#1091#1092#1077#1088' '#1086#1073#1084#1077#1085#1072 + Caption = '127.0.0.1:9050' + ParentShowHint = False + ShowHint = True + Transparent = True + OnClick = lbStatusProxyAddrClick + end + object lbStatusScannerCaption: TLabel + Left = 288 + Top = 32 + Width = 85 + Height = 13 + Alignment = taRightJustify + Caption = #1057#1077#1090#1077#1074#1086#1081' '#1089#1082#1072#1085#1077#1088':' + Transparent = True + end + object lbStatusScanner: TLabel + Left = 376 + Top = 32 + Width = 53 + Height = 13 + Hint = #1057#1082#1086#1087#1080#1088#1086#1074#1072#1090#1100' '#1074' '#1073#1091#1092#1077#1088' '#1086#1073#1084#1077#1085#1072 + Caption = #1054#1078#1080#1076#1072#1085#1080#1077 + Transparent = True + end + end + object gbSpeedGraph: TGroupBox + Left = 176 + Top = 6 + Width = 534 + Height = 238 + Caption = #1043#1088#1072#1092#1080#1082' '#1089#1082#1086#1088#1086#1089#1090#1080 + ParentBackground = False + TabOrder = 4 + object pbTraffic: TPaintBox + Left = 2 + Top = 15 + Width = 530 + Height = 221 + Align = alClient + PopupMenu = mnTraffic + OnPaint = pbTrafficPaint + end + end + object gbMaxTraffic: TGroupBox + Left = 12 + Top = 66 + Width = 155 + Height = 57 + Caption = #1052#1072#1082#1089#1080#1084#1091#1084 + ParentBackground = False + TabOrder = 1 + object lbMaxDLSpeedCaption: TLabel + Left = 39 + Top = 16 + Width = 50 + Height = 13 + Alignment = taRightJustify + Caption = #1047#1072#1075#1088#1091#1079#1082#1072':' + Transparent = True + end + object lbMaxULSpeedCaption: TLabel + Left = 35 + Top = 32 + Width = 54 + Height = 13 + Alignment = taRightJustify + Caption = #1054#1090#1087#1088#1072#1074#1082#1072':' + Transparent = True + end + object lbMaxDLSpeed: TLabel + Left = 92 + Top = 16 + Width = 34 + Height = 13 + Caption = '0,0 '#1041'/c' + Transparent = True + end + object lbMaxULSpeed: TLabel + Left = 92 + Top = 32 + Width = 34 + Height = 13 + Caption = '0,0 '#1041'/c' + Transparent = True + end + end + object gbTotal: TGroupBox + Left = 12 + Top = 187 + Width = 155 + Height = 57 + Hint = #1053#1072#1095#1072#1083#1086' '#1091#1095#1105#1090#1072': 01.01.1970 00:00' + Caption = #1042#1089#1077#1075#1086' '#1079#1072' '#1074#1089#1105' '#1074#1088#1077#1084#1103 + ParentBackground = False + ParentShowHint = False + ShowHint = True + TabOrder = 3 + object lbTotalDLCaption: TLabel + Left = 36 + Top = 16 + Width = 53 + Height = 13 + Alignment = taRightJustify + Caption = #1055#1086#1083#1091#1095#1077#1085#1086':' + Transparent = True + end + object lbTotalULCaption: TLabel + Left = 23 + Top = 32 + Width = 66 + Height = 13 + Alignment = taRightJustify + AutoSize = False + Caption = #1054#1090#1087#1088#1072#1074#1083#1077#1085#1086':' + Transparent = True + end + object lbTotalDL: TLabel + Left = 92 + Top = 16 + Width = 25 + Height = 13 + Caption = '0,0 '#1041 + Transparent = True + end + object lbTotalUL: TLabel + Left = 92 + Top = 32 + Width = 25 + Height = 13 + Caption = '0,0 '#1041 + Transparent = True + end + end + end + object paCircuits: TPanel + Left = 3 + Top = 92 + Width = 721 + Height = 435 + BevelInner = bvLowered + Color = clWindow + DoubleBuffered = True + ParentBackground = False + ParentDoubleBuffered = False + ShowCaption = False + TabOrder = 4 + Visible = False + object lbDetailsTime: TLabel + Left = 550 + Top = 10 + Width = 160 + Height = 13 + Alignment = taRightJustify + Caption = #1044#1072#1090#1072' '#1089#1086#1079#1076#1072#1085#1080#1103': '#1053#1077' '#1086#1087#1088#1077#1076#1077#1083#1077#1085#1072 + Transparent = True + end + object lbCircuitsCount: TLabel + Left = 12 + Top = 10 + Width = 80 + Height = 13 + Caption = #1062#1077#1087#1086#1095#1077#1082': 0 '#1080#1079' 0' + Transparent = True + end + object lbStreamsCount: TLabel + Left = 143 + Top = 10 + Width = 75 + Height = 13 + Alignment = taRightJustify + Caption = #1057#1086#1077#1076#1080#1085#1077#1085#1080#1081': 0' + Transparent = True + end + object lbULCirc: TLabel + Left = 349 + Top = 10 + Width = 79 + Height = 13 + Caption = #1054#1090#1087#1088#1072#1074#1083#1077#1085#1086': '#8734 + Transparent = True + end + object lbDLCirc: TLabel + Left = 227 + Top = 10 + Width = 66 + Height = 13 + Caption = #1055#1086#1083#1091#1095#1077#1085#1086': '#8734 + Transparent = True + end + object sgStreams: TStringGrid + Tag = 4 + Left = 227 + Top = 149 + Width = 483 + Height = 158 + ColCount = 6 + DefaultRowHeight = 16 + FixedCols = 0 + RowCount = 2 + Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goDrawFocusSelected, goRowSelect, goThumbTracking, goFixedRowClick] + ParentShowHint = False + PopupMenu = mnStreams + ScrollBars = ssVertical + ShowHint = True + TabOrder = 2 + OnDblClick = sgStreamsDblClick + OnDrawCell = sgStreamsDrawCell + OnFixedCellClick = sgStreamsFixedCellClick + OnKeyDown = sgStreamsKeyDown + OnMouseDown = sgStreamsMouseDown + OnMouseMove = sgStreamsMouseMove + OnSelectCell = sgStreamsSelectCell + end + object sgCircuits: TStringGrid + Tag = 3 + Left = 12 + Top = 33 + Width = 205 + Height = 391 + DefaultRowHeight = 16 + FixedCols = 0 + RowCount = 2 + Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goDrawFocusSelected, goRowSelect, goThumbTracking, goFixedRowClick] + ParentShowHint = False + PopupMenu = mnCircuits + ScrollBars = ssVertical + ShowHint = True + TabOrder = 0 + OnDrawCell = sgCircuitsDrawCell + OnFixedCellClick = sgCircuitsFixedCellClick + OnKeyDown = sgCircuitsKeyDown + OnMouseDown = sgCircuitsMouseDown + OnMouseMove = sgCircuitsMouseMove + OnSelectCell = sgCircuitsSelectCell + end + object sgCircuitInfo: TStringGrid + Tag = 7 + Left = 227 + Top = 33 + Width = 483 + Height = 106 + ColCount = 7 + DefaultRowHeight = 16 + FixedCols = 0 + RowCount = 2 + Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goDrawFocusSelected, goRowSelect, goThumbTracking] + ParentShowHint = False + PopupMenu = mnDetails + ScrollBars = ssNone + ShowHint = True + TabOrder = 1 + OnDblClick = sgCircuitInfoDblClick + OnDrawCell = sgCircuitInfoDrawCell + OnKeyDown = sgCircuitInfoKeyDown + OnMouseDown = sgCircuitInfoMouseDown + OnMouseMove = sgCircuitInfoMouseMove + OnSelectCell = sgCircuitInfoSelectCell + end + object sgStreamsInfo: TStringGrid + Tag = 8 + Left = 227 + Top = 318 + Width = 483 + Height = 106 + ColCount = 6 + DefaultRowHeight = 16 + FixedCols = 0 + RowCount = 2 + Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goDrawFocusSelected, goRowSelect, goThumbTracking, goFixedRowClick] + ParentShowHint = False + PopupMenu = mnStreamsInfo + ScrollBars = ssVertical + ShowHint = True + TabOrder = 3 + OnDrawCell = sgStreamsInfoDrawCell + OnFixedCellClick = sgStreamsInfoFixedCellClick + OnKeyDown = sgStreamsInfoKeyDown + OnMouseDown = sgStreamsInfoMouseDown + OnMouseMove = sgStreamsInfoMouseMove + OnSelectCell = sgStreamsInfoSelectCell + end + end + object paButtons: TPanel + Left = 0 + Top = 0 + Width = 728 + Height = 91 + BevelOuter = bvNone + DoubleBuffered = True + ParentBackground = False + ParentDoubleBuffered = False + TabOrder = 0 + OnDblClick = paButtonsDblClick + object sbShowLog: TSpeedButton + Left = 229 + Top = 53 + Width = 111 + Height = 35 + GroupIndex = 1 + Caption = #1046#1091#1088#1085#1072#1083 + Spacing = 8 + OnClick = sbShowLogClick + end + object sbShowOptions: TSpeedButton + Left = 116 + Top = 53 + Width = 111 + Height = 35 + GroupIndex = 1 + Caption = #1053#1072#1089#1090#1088#1086#1081#1082#1080 + Spacing = 6 + OnClick = sbShowOptionsClick + OnMouseDown = sbShowOptionsMouseDown + end + object sbShowStatus: TSpeedButton + Left = 342 + Top = 53 + Width = 111 + Height = 35 + GroupIndex = 1 + Caption = #1057#1090#1072#1090#1091#1089 + Spacing = 8 + OnClick = sbShowStatusClick + end + object imExitFlag: TImage + Left = 175 + Top = 32 + Width = 20 + Height = 13 + ParentShowHint = False + ShowHint = True + Stretch = True + Visible = False + end + object lbExitCountryCaption: TLabel + Left = 131 + Top = 31 + Width = 41 + Height = 13 + Alignment = taRightJustify + Caption = #1057#1090#1088#1072#1085#1072':' + Transparent = True + end + object lbExitIpCaption: TLabel + Left = 125 + Top = 12 + Width = 47 + Height = 13 + Alignment = taRightJustify + Caption = 'IP '#1072#1076#1088#1077#1089':' + Transparent = True + end + object lbExitIp: TLabel + Left = 174 + Top = 12 + Width = 58 + Height = 13 + Caption = #1053#1077' '#1087#1086#1083#1091#1095#1077#1085 + PopupMenu = mnDetails + Transparent = True + OnMouseDown = lbExitIpMouseDown + OnMouseMove = lbExitMouseMove + end + object lbExitCountry: TLabel + Left = 174 + Top = 31 + Width = 77 + Height = 13 + Caption = #1053#1077' '#1086#1087#1088#1077#1076#1077#1083#1077#1085#1072 + ParentShowHint = False + PopupMenu = mnDetails + ShowHint = True + Transparent = True + OnDblClick = lbExitCountryDblClick + OnMouseMove = lbExitMouseMove + end + object sbShowCircuits: TSpeedButton + Left = 455 + Top = 53 + Width = 111 + Height = 35 + GroupIndex = 1 + Caption = #1062#1077#1087#1086#1095#1082#1080 + Spacing = 8 + OnClick = sbShowCircuitsClick + OnMouseDown = sbShowCircuitsMouseDown + end + object sbShowRouters: TSpeedButton + Left = 568 + Top = 53 + Width = 111 + Height = 35 + GroupIndex = 1 + Caption = #1056#1086#1091#1090#1077#1088#1099 + Spacing = 8 + OnClick = sbShowRoutersClick + OnMouseDown = sbShowRoutersMouseDown + end + object sbDecreaseForm: TSpeedButton + Left = 681 + Top = 53 + Width = 43 + Height = 35 + OnClick = sbDecreaseFormClick + end + object btnChangeCircuit: TButton + Left = 3 + Top = 3 + Width = 111 + Height = 48 + Caption = #1057#1084#1077#1085#1080#1090#1100' '#1094#1077#1087#1086#1095#1082#1091 + DropDownMenu = mnChangeCircuit + ImageIndex = 3 + ImageMargins.Left = 5 + Images = lsButtons + Style = bsSplitButton + TabOrder = 1 + WordWrap = True + OnClick = btnChangeCircuitClick + end + object btnSwitchTor: TButton + Left = 3 + Top = 53 + Width = 111 + Height = 35 + Caption = #1057#1090#1072#1088#1090 + DoubleBuffered = False + ImageIndex = 0 + ImageMargins.Left = 8 + ImageMargins.Right = -8 + Images = lsButtons + ParentDoubleBuffered = False + TabOrder = 0 + OnClick = btnSwitchTorClick + end + end + object paRouters: TPanel + Left = 3 + Top = 92 + Width = 721 + Height = 435 + BevelInner = bvLowered + Color = clWindow + DoubleBuffered = True + ParentBackground = False + ParentDoubleBuffered = False + ShowCaption = False + TabOrder = 5 + Visible = False + OnClick = paRoutersClick + object lbRoutersCount: TLabel + Left = 627 + Top = 10 + Width = 84 + Height = 13 + Alignment = taRightJustify + Caption = #1055#1086#1082#1072#1079#1072#1085#1086': 0 '#1080#1079' 0' + Transparent = True + end + object lbSpeed3: TLabel + Left = 283 + Top = 10 + Width = 23 + Height = 13 + Caption = #1052#1041'/c' + Transparent = True + end + object lbFavoritesChar: TLabel + Left = 10 + Top = 412 + Width = 9 + Height = 13 + Caption = #9733 + Transparent = True + end + object lbFavoritesEntry: TLabel + Left = 23 + Top = 412 + Width = 58 + Height = 13 + Cursor = crHandPoint + Hint = '288' + Caption = #1042#1093#1086#1076#1085#1099#1077': 0' + Transparent = True + OnMouseDown = ShowFavoritesRouters + end + object lbFavoritesMiddle: TLabel + Left = 103 + Top = 412 + Width = 57 + Height = 13 + Cursor = crHandPoint + Hint = '289' + Caption = #1057#1088#1077#1076#1085#1080#1077': 0' + Transparent = True + OnMouseDown = ShowFavoritesRouters + end + object lbFavoritesExit: TLabel + Left = 185 + Top = 412 + Width = 66 + Height = 13 + Cursor = crHandPoint + Hint = '290' + Caption = #1042#1099#1093#1086#1076#1085#1099#1077': 0' + Transparent = True + OnMouseDown = ShowFavoritesRouters + end + object lbExcludeNodes: TLabel + Left = 362 + Top = 412 + Width = 84 + Height = 13 + Cursor = crHandPoint + Hint = '287' + Caption = #1047#1072#1087#1088#1077#1097#1105#1085#1085#1099#1077': 0' + Transparent = True + OnMouseDown = ShowFavoritesRouters + end + object lbExcludeChar: TLabel + Left = 348 + Top = 412 + Width = 9 + Height = 13 + Caption = #10006 + Transparent = True + end + object lbFavoritesTotal: TLabel + Left = 273 + Top = 412 + Width = 41 + Height = 13 + Cursor = crHandPoint + Hint = '203' + Caption = #1042#1089#1077#1075#1086': 0' + Transparent = True + OnMouseDown = ShowFavoritesRouters + end + object sgRouters: TStringGrid + Tag = 2 + Left = 1 + Top = 33 + Width = 720 + Height = 374 + ColCount = 14 + DefaultRowHeight = 16 + FixedCols = 0 + RowCount = 2 + Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goDrawFocusSelected, goRowSelect, goThumbTracking, goFixedRowClick] + ParentShowHint = False + PopupMenu = mnRouters + ScrollBars = ssVertical + ShowHint = True + TabOrder = 0 + OnDblClick = sgRoutersDblClick + OnDrawCell = sgRoutersDrawCell + OnFixedCellClick = sgRoutersFixedCellClick + OnKeyDown = sgRoutersKeyDown + OnKeyPress = sgRoutersKeyPress + OnMouseDown = sgRoutersMouseDown + OnMouseMove = sgRoutersMouseMove + OnSelectCell = sgRoutersSelectCell + end + object btnShowNodes: TButton + Left = 6 + Top = 7 + Width = 75 + Height = 21 + Caption = #1058#1080#1087' '#1091#1079#1083#1072 + DropDownMenu = mnShowNodes + Style = bsSplitButton + TabOrder = 1 + OnClick = btnShowNodesClick + end + object cbxRoutersCountry: TComboBox + Tag = -1 + Left = 84 + Top = 7 + Width = 145 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + ParentDoubleBuffered = False + Sorted = True + TabOrder = 2 + OnChange = cbxRoutersCountryChange + OnDropDown = cbxRoutersCountryDropDown + OnEnter = cbxRoutersCountryEnter + end + object edRoutersWeight: TEdit + Left = 233 + Top = 7 + Width = 35 + Height = 21 + Alignment = taCenter + MaxLength = 5 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 3 + Text = '10' + OnKeyDown = edRoutersWeightKeyDown + OnMouseDown = edRoutersWeightMouseDown + end + object udRoutersWeight: TUpDown + Left = 268 + Top = 7 + Width = 13 + Height = 21 + HelpContext = 10 + Associate = edRoutersWeight + ArrowKeys = False + DoubleBuffered = True + Max = 65535 + Increment = 5 + ParentDoubleBuffered = False + Position = 10 + TabOrder = 4 + Thousands = False + OnClick = udRoutersWeightClick + end + object cbxRoutersQuery: TComboBox + Tag = -1 + Left = 310 + Top = 7 + Width = 75 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + ItemIndex = 0 + ParentDoubleBuffered = False + TabOrder = 5 + Text = #1061#1077#1096 + OnChange = cbxRoutersQueryChange + Items.Strings = ( + #1061#1077#1096 + #1053#1080#1082 + 'IPv4' + 'IPv6' + 'OR-'#1087#1086#1088#1090 + 'DIR-'#1087#1086#1088#1090 + #1042#1077#1088#1089#1080#1103 + #1055#1080#1085#1075) + end + object edRoutersQuery: TEdit + Left = 389 + Top = 7 + Width = 178 + Height = 21 + PopupMenu = EditMenu + TabOrder = 6 + TextHint = #1042#1074#1077#1076#1080#1090#1077' '#1079#1072#1087#1088#1086#1089 + OnChange = edRoutersQueryChange + OnKeyDown = edRoutersQueryKeyDown + end + end + object pcOptions: TPageControl + Left = 4 + Top = 94 + Width = 721 + Height = 433 + ActivePage = tsMain + DoubleBuffered = True + Images = lsMain + ParentDoubleBuffered = False + TabHeight = 26 + TabOrder = 1 + TabPosition = tpBottom + OnChange = pcOptionsChange + object tsMain: TTabSheet + Caption = #1054#1073#1097#1080#1077 + object gbProfile: TGroupBox + Left = 390 + Top = 326 + Width = 318 + Height = 65 + Caption = #1055#1088#1086#1092#1080#1083#1100 + TabOrder = 3 + object lbCreateProfile: TLabel + Left = 10 + Top = 20 + Width = 196 + Height = 31 + Alignment = taRightJustify + AutoSize = False + Caption = #1071#1088#1083#1099#1082' '#1087#1088#1086#1075#1088#1072#1084#1084#1099' '#1089' '#1085#1086#1074#1099#1084' '#1087#1088#1086#1092#1080#1083#1077#1084' '#1085#1072' '#1088#1072#1073#1086#1095#1077#1084' '#1089#1090#1086#1083#1077 + Transparent = True + WordWrap = True + end + object btnCreateProfile: TButton + Left = 225 + Top = 25 + Width = 75 + Height = 21 + Caption = #1057#1086#1079#1076#1072#1090#1100'..' + TabOrder = 0 + OnClick = btnCreateProfileClick + end + end + object gbControlAuth: TGroupBox + Left = 10 + Top = 326 + Width = 370 + Height = 65 + Caption = #1059#1087#1088#1072#1074#1083#1077#1085#1080#1077 + TabOrder = 1 + object lbControlPort: TLabel + Left = 8 + Top = 40 + Width = 25 + Height = 13 + Alignment = taRightJustify + Caption = #1055#1086#1088#1090 + Transparent = True + end + object lbAuthMetod: TLabel + Left = 174 + Top = 15 + Width = 87 + Height = 13 + Alignment = taRightJustify + Caption = #1040#1091#1090#1077#1085#1090#1080#1092#1080#1082#1072#1094#1080#1103 + Transparent = True + end + object lbControlPassword: TLabel + Left = 127 + Top = 40 + Width = 37 + Height = 13 + Alignment = taRightJustify + Caption = #1055#1072#1088#1086#1083#1100 + Enabled = False + Transparent = True + end + object imGeneratePassword: TImage + Left = 343 + Top = 37 + Width = 20 + Height = 20 + Cursor = crHandPoint + Hint = #1057#1075#1077#1085#1077#1088#1080#1088#1086#1074#1072#1090#1100' '#1089#1083#1091#1095#1072#1081#1085#1099#1081' '#1087#1072#1088#1086#1083#1100 + Enabled = False + OnClick = imGeneratePasswordClick + end + object edControlPort: TEdit + Left = 36 + Top = 37 + Width = 42 + Height = 21 + MaxLength = 5 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 0 + Text = '9051' + OnChange = EditChange + end + object udControlPort: TUpDown + Left = 78 + Top = 37 + Width = 13 + Height = 21 + Associate = edControlPort + Min = 1 + Max = 65535 + Position = 9051 + TabOrder = 1 + Thousands = False + OnChanging = SpinChanging + end + object cbxAuthMetod: TComboBox + Left = 264 + Top = 12 + Width = 100 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + ItemIndex = 0 + ParentDoubleBuffered = False + TabOrder = 2 + Text = 'Cookie-'#1092#1072#1081#1083 + OnChange = cbxAuthMetodChange + Items.Strings = ( + 'Cookie-'#1092#1072#1081#1083 + #1055#1072#1088#1086#1083#1100) + end + object edControlPassword: TEdit + Left = 166 + Top = 37 + Width = 174 + Height = 21 + Enabled = False + MaxLength = 255 + PasswordChar = '*' + PopupMenu = EditMenu + TabOrder = 3 + TextHint = #1042#1074#1077#1076#1080#1090#1077' '#1087#1072#1088#1086#1083#1100 + OnChange = EditChange + OnDblClick = edControlPasswordDblClick + end + end + object gbInterface: TGroupBox + Left = 390 + Top = 3 + Width = 318 + Height = 319 + Caption = #1048#1085#1090#1077#1088#1092#1077#1081#1089 + TabOrder = 2 + object cbStayOnTop: TCheckBox + Left = 10 + Top = 165 + Width = 300 + Height = 17 + Caption = #1054#1089#1090#1072#1074#1072#1090#1100#1089#1103' '#1087#1086#1074#1077#1088#1093' '#1074#1089#1077#1093' '#1086#1082#1086#1085 + TabOrder = 6 + OnClick = cbStayOnTopClick + end + object cbShowBalloonOnlyWhenHide: TCheckBox + Left = 29 + Top = 141 + Width = 280 + Height = 17 + Caption = #1058#1086#1083#1100#1082#1086' '#1082#1086#1075#1076#1072' '#1087#1088#1086#1075#1088#1072#1084#1084#1072' '#1089#1074#1105#1088#1085#1091#1090#1072 + Checked = True + State = cbChecked + TabOrder = 5 + OnClick = OptionsChange + end + object cbShowBalloonHint: TCheckBox + Left = 10 + Top = 117 + Width = 300 + Height = 17 + Caption = #1055#1086#1082#1072#1079#1099#1074#1072#1090#1100' '#1074#1089#1087#1083#1099#1074#1072#1102#1097#1080#1077' '#1089#1086#1086#1073#1097#1077#1085#1080#1103 + Checked = True + State = cbChecked + TabOrder = 4 + OnClick = cbShowBalloonHintClick + end + object cbMinimizeOnClose: TCheckBox + Left = 10 + Top = 93 + Width = 300 + Height = 17 + Caption = #1057#1074#1086#1088#1072#1095#1080#1074#1072#1090#1100' '#1074' '#1090#1088#1077#1081' '#1087#1088#1080' '#1079#1072#1082#1088#1099#1090#1080#1080 + Checked = True + State = cbChecked + TabOrder = 3 + OnClick = OptionsChange + end + object cbMinimizeOnStartup: TCheckBox + Left = 10 + Top = 69 + Width = 300 + Height = 17 + Caption = #1057#1074#1086#1088#1072#1095#1080#1074#1072#1090#1100' '#1074' '#1090#1088#1077#1081' '#1087#1088#1080' '#1079#1072#1087#1091#1089#1082#1077 + TabOrder = 2 + OnClick = OptionsChange + end + object cbConnectOnStartup: TCheckBox + Left = 10 + Top = 21 + Width = 300 + Height = 17 + Caption = #1055#1086#1076#1082#1083#1102#1095#1072#1090#1100#1089#1103' '#1087#1088#1080' '#1079#1072#1087#1091#1089#1082#1077' '#1087#1088#1086#1075#1088#1072#1084#1084#1099 + TabOrder = 0 + OnClick = OptionsChange + end + object cbRestartOnControlFail: TCheckBox + Left = 10 + Top = 45 + Width = 300 + Height = 17 + Caption = #1055#1077#1088#1077#1079#1072#1087#1091#1089#1082' '#1087#1088#1080' '#1086#1073#1088#1099#1074#1077' '#1089#1074#1103#1079#1080' '#1089' '#1082#1083#1080#1077#1085#1090#1086#1084 + Checked = True + State = cbChecked + TabOrder = 1 + OnClick = OptionsChange + end + object cbNoDesktopBorders: TCheckBox + Left = 10 + Top = 189 + Width = 300 + Height = 17 + Caption = #1056#1072#1079#1088#1077#1096#1080#1090#1100' '#1086#1082#1085#1091' '#1074#1099#1093#1086#1076#1080#1090#1100' '#1079#1072' '#1075#1088#1072#1085#1080#1094#1099' '#1101#1082#1088#1072#1085#1072 + Checked = True + State = cbChecked + TabOrder = 7 + OnClick = cbNoDesktopBordersClick + end + object cbRememberEnlargedPosition: TCheckBox + Left = 10 + Top = 237 + Width = 300 + Height = 17 + Caption = #1047#1072#1087#1086#1084#1080#1085#1072#1090#1100' '#1087#1086#1079#1080#1094#1080#1102' '#1091#1074#1077#1083#1080#1095#1077#1085#1085#1086#1075#1086' '#1086#1082#1085#1072 + TabOrder = 9 + OnClick = OptionsChange + end + object cbHideIPv6Addreses: TCheckBox + Left = 10 + Top = 261 + Width = 300 + Height = 17 + Caption = #1057#1082#1088#1099#1074#1072#1090#1100' IPv6-'#1072#1076#1088#1077#1089#1072' '#1074' '#1089#1087#1080#1089#1082#1072#1093' '#1080#1085#1090#1077#1088#1092#1077#1081#1089#1086#1074 + Checked = True + State = cbChecked + TabOrder = 10 + OnClick = OptionsChange + end + object cbNoDesktopBordersOnlyEnlarged: TCheckBox + Left = 29 + Top = 213 + Width = 280 + Height = 17 + Caption = #1058#1086#1083#1100#1082#1086' '#1087#1088#1080' '#1091#1074#1077#1083#1080#1095#1077#1085#1085#1086#1084' '#1086#1082#1085#1077' '#1087#1088#1086#1075#1088#1072#1084#1084#1099 + Checked = True + State = cbChecked + TabOrder = 8 + OnClick = OptionsChange + end + object cbClearPreviousSearchQuery: TCheckBox + Left = 10 + Top = 284 + Width = 300 + Height = 17 + Caption = #1054#1095#1080#1097#1072#1090#1100' '#1087#1088#1077#1076#1099#1076#1091#1097#1080#1081' '#1087#1086#1080#1089#1082#1086#1074#1099#1081' '#1079#1072#1087#1088#1086#1089' '#1074' '#1089#1087#1080#1089#1082#1072#1093 + TabOrder = 11 + OnClick = OptionsChange + end + end + object gbOptions: TGroupBox + Left = 10 + Top = 3 + Width = 370 + Height = 319 + Caption = #1054#1089#1085#1086#1074#1085#1099#1077 + TabOrder = 0 + object lbMaxCircuitDirtiness: TLabel + Left = 58 + Top = 22 + Width = 222 + Height = 13 + Alignment = taRightJustify + Caption = #1052#1077#1085#1103#1090#1100' '#1094#1077#1087#1086#1095#1082#1091' '#1089#1091#1097#1077#1089#1090#1074#1091#1102#1097#1091#1102' '#1073#1086#1083#1077#1077' '#1095#1077#1084 + Transparent = True + end + object lbSeconds1: TLabel + Left = 344 + Top = 22 + Width = 21 + Height = 13 + Caption = #1089#1077#1082'.' + ParentShowHint = False + ShowHint = True + Transparent = True + end + object lbCircuitBuildTimeout: TLabel + Left = 96 + Top = 70 + Width = 184 + Height = 13 + Alignment = taRightJustify + Caption = #1052#1072#1082#1089'. '#1074#1088#1077#1084#1103' '#1085#1072' '#1087#1086#1089#1090#1088#1086#1077#1085#1080#1077' '#1094#1077#1087#1086#1095#1082#1080 + Enabled = False + Transparent = True + end + object lbSeconds2: TLabel + Left = 344 + Top = 70 + Width = 21 + Height = 13 + Caption = #1089#1077#1082'.' + Enabled = False + Transparent = True + end + object lbSeconds3: TLabel + Left = 344 + Top = 46 + Width = 21 + Height = 13 + Caption = #1089#1077#1082'.' + Transparent = True + end + object lbNewCircuitPeriod: TLabel + Left = 35 + Top = 46 + Width = 245 + Height = 13 + Alignment = taRightJustify + Caption = #1048#1085#1090#1077#1088#1074#1072#1083' '#1084#1077#1078#1076#1091' '#1087#1086#1087#1099#1090#1082#1072#1084#1080' '#1087#1086#1089#1090#1088#1086#1080#1090#1100' '#1094#1077#1087#1086#1095#1082#1091 + Transparent = True + end + object lbTheme: TLabel + Left = 28 + Top = 294 + Width = 24 + Height = 13 + Alignment = taRightJustify + Caption = #1058#1077#1084#1072 + Transparent = True + end + object lbLanguage: TLabel + Left = 236 + Top = 294 + Width = 26 + Height = 13 + Alignment = taRightJustify + Caption = #1071#1079#1099#1082 + Transparent = True + end + object lbMaxClientCircuitsPending: TLabel + Left = 64 + Top = 94 + Width = 216 + Height = 13 + Alignment = taRightJustify + Caption = #1050#1086#1083#1080#1095#1077#1089#1090#1074#1086' '#1086#1078#1080#1076#1072#1102#1097#1080#1093' '#1094#1077#1087#1086#1095#1077#1082' '#1082#1083#1080#1077#1085#1090#1072 + Transparent = True + end + object cbAvoidDiskWrites: TCheckBox + Left = 10 + Top = 189 + Width = 350 + Height = 17 + Caption = #1042#1099#1087#1086#1083#1085#1103#1090#1100' '#1084#1077#1085#1100#1096#1077' '#1086#1087#1077#1088#1072#1094#1080#1081' '#1089' '#1076#1080#1089#1082#1086#1084 + TabOrder = 11 + OnClick = OptionsChange + end + object cbLearnCircuitBuildTimeout: TCheckBox + Left = 10 + Top = 117 + Width = 350 + Height = 17 + Caption = #1040#1074#1090#1086#1084#1072#1090#1080#1095#1077#1089#1082#1080' '#1074#1099#1073#1080#1088#1072#1090#1100' '#1074#1088#1077#1084#1103' '#1085#1072' '#1087#1086#1089#1090#1088#1086#1077#1085#1080#1077' '#1094#1077#1087#1086#1095#1082#1080 + Checked = True + State = cbChecked + TabOrder = 8 + OnClick = cbLearnCircuitBuildTimeoutClick + end + object cbEnforceDistinctSubnets: TCheckBox + Left = 10 + Top = 141 + Width = 350 + Height = 17 + Caption = #1053#1077' '#1089#1090#1088#1086#1080#1090#1100' '#1094#1077#1087#1086#1095#1082#1080' '#1080#1079' '#1091#1079#1083#1086#1074' '#1086#1076#1085#1086#1081' '#1087#1086#1076#1089#1077#1090#1080 + Checked = True + State = cbChecked + TabOrder = 9 + OnClick = OptionsChange + end + object edMaxCircuitDirtiness: TEdit + Left = 283 + Top = 19 + Width = 42 + Height = 21 + MaxLength = 7 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 0 + Text = '600' + OnChange = EditChange + end + object udMaxCircuitDirtiness: TUpDown + Left = 325 + Top = 19 + Width = 16 + Height = 21 + Associate = edMaxCircuitDirtiness + Min = 10 + Max = 2592000 + Increment = 60 + Position = 600 + TabOrder = 1 + Thousands = False + OnChanging = SpinChanging + end + object edNewCircuitPeriod: TEdit + Left = 283 + Top = 43 + Width = 42 + Height = 21 + MaxLength = 7 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 2 + Text = '30' + OnChange = EditChange + end + object udNewCircuitPeriod: TUpDown + Left = 325 + Top = 43 + Width = 16 + Height = 21 + Associate = edNewCircuitPeriod + Min = 1 + Max = 2592000 + Increment = 5 + Position = 30 + TabOrder = 3 + Thousands = False + OnChanging = SpinChanging + end + object edCircuitBuildTimeout: TEdit + Left = 283 + Top = 67 + Width = 42 + Height = 21 + Enabled = False + MaxLength = 7 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 4 + Text = '60' + OnChange = EditChange + end + object udCircuitBuildTimeout: TUpDown + Left = 325 + Top = 67 + Width = 16 + Height = 21 + Associate = edCircuitBuildTimeout + Enabled = False + Min = 10 + Max = 2592000 + Increment = 5 + Position = 60 + TabOrder = 5 + Thousands = False + OnChanging = SpinChanging + end + object cbUseOpenDNS: TCheckBox + Left = 10 + Top = 213 + Width = 350 + Height = 17 + Caption = #1054#1087#1088#1077#1076#1077#1083#1103#1090#1100' '#1074#1085#1077#1096#1085#1080#1081' '#1072#1076#1088#1077#1089' '#1089#1077#1088#1074#1077#1088#1072' '#1095#1077#1088#1077#1079' OpenDNS' + Checked = True + State = cbChecked + TabOrder = 12 + OnClick = cbUseOpenDNSClick + end + object cbUseOpenDNSOnlyWhenUnknown: TCheckBox + Left = 26 + Top = 237 + Width = 334 + Height = 17 + Caption = #1058#1086#1083#1100#1082#1086' '#1077#1089#1083#1080' TOR '#1085#1077' '#1084#1086#1078#1077#1090' '#1086#1087#1088#1077#1076#1077#1083#1080#1090#1100' '#1077#1075#1086' '#1089#1072#1084 + Checked = True + State = cbChecked + TabOrder = 13 + OnClick = cbUseOpenDNSOnlyWhenUnknownClick + end + object cbUseNetworkCache: TCheckBox + Left = 10 + Top = 261 + Width = 350 + Height = 17 + Caption = #1050#1101#1096#1080#1088#1086#1074#1072#1090#1100' IP-cc-'#1079#1072#1087#1088#1086#1089#1099' '#1080' '#1088#1077#1079#1091#1083#1100#1090#1072#1090#1099' '#1089#1077#1090#1077#1074#1086#1075#1086' '#1089#1082#1072#1085#1077#1088#1072 + Checked = True + State = cbChecked + TabOrder = 14 + OnClick = cbUseNetworkCacheClick + end + object cbxThemes: TComboBox + Left = 55 + Top = 291 + Width = 130 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + ItemIndex = 0 + ParentDoubleBuffered = False + TabOrder = 15 + Text = #1055#1086' '#1091#1084#1086#1083#1095#1072#1085#1080#1102 + OnChange = cbxThemesChange + OnDropDown = cbxThemesDropDown + Items.Strings = ( + #1055#1086' '#1091#1084#1086#1083#1095#1072#1085#1080#1102) + end + object cbxLanguage: TComboBox + Left = 264 + Top = 291 + Width = 100 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + ItemIndex = 0 + ParentDoubleBuffered = False + Sorted = True + TabOrder = 16 + Text = #1056#1091#1089#1089#1082#1080#1081 + OnChange = OptionsChange + Items.Strings = ( + #1056#1091#1089#1089#1082#1080#1081) + end + object cbStrictNodes: TCheckBox + Left = 10 + Top = 165 + Width = 350 + Height = 17 + Caption = #1056#1072#1079#1088#1077#1096#1080#1090#1100' '#1079#1072#1087#1088#1077#1097#1105#1085#1085#1099#1077' '#1091#1079#1083#1099' '#1076#1083#1103' '#1074#1085#1091#1090#1088#1077#1085#1085#1080#1093' '#1094#1077#1087#1086#1095#1077#1082 + Checked = True + State = cbChecked + TabOrder = 10 + OnClick = OptionsChange + end + object edMaxClientCircuitsPending: TEdit + Left = 283 + Top = 91 + Width = 42 + Height = 21 + MaxLength = 4 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 6 + Text = '32' + OnChange = EditChange + end + object udMaxClientCircuitsPending: TUpDown + Left = 325 + Top = 91 + Width = 16 + Height = 21 + Associate = edMaxClientCircuitsPending + Min = 1 + Max = 1024 + Increment = 8 + Position = 32 + TabOrder = 7 + Thousands = False + OnChanging = SpinChanging + end + end + end + object tsNetwork: TTabSheet + Caption = #1057#1077#1090#1100 + ImageIndex = 1 + object lbReachableAddresses: TLabel + Left = 28 + Top = 30 + Width = 75 + Height = 13 + Alignment = taRightJustify + Caption = #1057#1087#1080#1089#1086#1082' '#1087#1086#1088#1090#1086#1074 + Enabled = False + Transparent = True + end + object lbProxyAddress: TLabel + Left = 117 + Top = 79 + Width = 31 + Height = 13 + Alignment = taRightJustify + Caption = #1040#1076#1088#1077#1089 + Enabled = False + Transparent = True + end + object lbProxyUser: TLabel + Left = 429 + Top = 80 + Width = 30 + Height = 13 + Alignment = taRightJustify + Caption = #1051#1086#1075#1080#1085 + Enabled = False + Transparent = True + end + object lbProxyPort: TLabel + Left = 333 + Top = 80 + Width = 25 + Height = 13 + Alignment = taRightJustify + Caption = #1055#1086#1088#1090 + Enabled = False + Transparent = True + end + object lbProxyPassword: TLabel + Left = 571 + Top = 80 + Width = 37 + Height = 13 + Alignment = taRightJustify + Caption = #1055#1072#1088#1086#1083#1100 + Enabled = False + Transparent = True + end + object lbProxyType: TLabel + Left = 28 + Top = 80 + Width = 18 + Height = 13 + Alignment = taRightJustify + Caption = #1058#1080#1087 + Enabled = False + Transparent = True + end + object lbTotalBridges: TLabel + Left = 666 + Top = 131 + Width = 41 + Height = 13 + Alignment = taRightJustify + Caption = #1042#1089#1077#1075#1086': 0' + Enabled = False + Transparent = True + end + object lbBridgesType: TLabel + Left = 28 + Top = 131 + Width = 18 + Height = 13 + Alignment = taRightJustify + Caption = #1058#1080#1087 + Enabled = False + Transparent = True + end + object lbBridgesList: TLabel + Left = 178 + Top = 132 + Width = 74 + Height = 13 + Alignment = taRightJustify + Caption = #1057#1087#1080#1089#1086#1082' '#1084#1086#1089#1090#1086#1074 + Transparent = True + end + object lbScanBridgesStatus: TLabel + Left = 384 + Top = 132 + Width = 172 + Height = 13 + Caption = #1054#1087#1088#1077#1076#1077#1083#1077#1085#1080#1077' '#1078#1080#1074#1099#1093' '#1084#1086#1089#1090#1086#1074' (0%)' + Transparent = True + Visible = False + end + object lbPreferredBridge: TLabel + Left = 28 + Top = 373 + Width = 25 + Height = 13 + Alignment = taRightJustify + Caption = #1052#1086#1089#1090 + Enabled = False + Transparent = True + end + object cbUseReachableAddresses: TCheckBox + Left = 10 + Top = 6 + Width = 402 + Height = 17 + Margins.Left = 0 + Caption = #1052#1086#1081' '#1089#1077#1090#1077#1074#1086#1081' '#1101#1082#1088#1072#1085' '#1088#1072#1079#1088#1077#1096#1072#1077#1090' '#1087#1086#1076#1082#1083#1102#1095#1072#1090#1100#1089#1103' '#1090#1086#1083#1100#1082#1086' '#1082' '#1101#1090#1080#1084' '#1087#1086#1088#1090#1072#1084 + TabOrder = 0 + WordWrap = True + OnClick = cbUseReachableAddressesClick + end + object edReachableAddresses: TEdit + Left = 106 + Top = 27 + Width = 307 + Height = 21 + Enabled = False + PopupMenu = EditMenu + TabOrder = 1 + Text = '80,443' + TextHint = #1047#1085#1072#1095#1077#1085#1080#1103', '#1088#1072#1079#1076#1077#1083#1105#1085#1085#1099#1077' '#1079#1072#1087#1103#1090#1099#1084#1080 + OnChange = EditChange + OnKeyPress = edReachableAddressesKeyPress + end + object cbUseProxy: TCheckBox + Left = 10 + Top = 56 + Width = 402 + Height = 17 + Caption = #1071' '#1080#1089#1087#1086#1083#1100#1079#1091#1102' '#1087#1088#1086#1082#1089#1080' '#1076#1083#1103' '#1087#1086#1076#1082#1083#1102#1095#1077#1085#1080#1103' '#1082' '#1048#1085#1090#1077#1088#1085#1077#1090#1091 + TabOrder = 6 + OnClick = cbUseProxyClick + end + object edProxyAddress: TEdit + Left = 153 + Top = 77 + Width = 170 + Height = 21 + Enabled = False + MaxLength = 255 + PopupMenu = EditMenu + TabOrder = 8 + TextHint = 'IP-'#1072#1076#1088#1077#1089' '#1080#1083#1080' '#1080#1084#1103' '#1091#1079#1083#1072 + OnChange = EditChange + end + object edProxyUser: TEdit + Left = 462 + Top = 77 + Width = 97 + Height = 21 + Enabled = False + MaxLength = 255 + PopupMenu = EditMenu + TabOrder = 11 + TextHint = #1053#1077#1086#1073#1103#1079#1072#1090#1077#1083#1100#1085#1086 + OnChange = EditChange + end + object edProxyPassword: TEdit + Left = 611 + Top = 77 + Width = 97 + Height = 21 + Enabled = False + MaxLength = 255 + PasswordChar = '*' + PopupMenu = EditMenu + TabOrder = 12 + TextHint = #1053#1077#1086#1073#1103#1079#1072#1090#1077#1083#1100#1085#1086 + OnChange = EditChange + end + object cbxProxyType: TComboBox + Left = 49 + Top = 77 + Width = 63 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + Enabled = False + ItemIndex = 1 + ParentDoubleBuffered = False + TabOrder = 7 + Text = 'SOCKS5' + OnChange = cbxProxyTypeChange + Items.Strings = ( + 'SOCKS4' + 'SOCKS5' + 'HTTPS') + end + object cbUseBridges: TCheckBox + Left = 10 + Top = 107 + Width = 313 + Height = 16 + Caption = #1048#1089#1087#1086#1083#1100#1079#1086#1074#1072#1090#1100' '#1084#1086#1089#1090#1099 + TabOrder = 13 + OnClick = cbUseBridgesClick + OnExit = cbUseBridgesExit + end + object meBridges: TMemo + Left = 10 + Top = 154 + Width = 697 + Height = 190 + Enabled = False + PopupMenu = EditMenu + ScrollBars = ssVertical + TabOrder = 16 + WordWrap = False + OnChange = meBridgesChange + OnExit = MemoExit + OnKeyPress = MemoKeyPress + end + object cbxSocksHost: TComboBox + Left = 473 + Top = 27 + Width = 177 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + ItemIndex = 1 + ParentDoubleBuffered = False + TabOrder = 3 + Text = '127.0.0.1' + OnChange = OptionsChange + OnDropDown = cbxSocksHostDropDown + Items.Strings = ( + '0.0.0.0' + '127.0.0.1') + end + object edProxyPort: TEdit + Left = 361 + Top = 77 + Width = 42 + Height = 21 + Enabled = False + MaxLength = 5 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 9 + Text = '1080' + OnChange = EditChange + end + object udProxyPort: TUpDown + Left = 403 + Top = 77 + Width = 13 + Height = 21 + Associate = edProxyPort + Enabled = False + Min = 1 + Max = 65535 + Position = 1080 + TabOrder = 10 + Thousands = False + OnChanging = SpinChanging + end + object edSOCKSPort: TEdit + Left = 653 + Top = 27 + Width = 42 + Height = 21 + MaxLength = 5 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 4 + Text = '9050' + OnChange = EditChange + end + object udSOCKSPort: TUpDown + Left = 695 + Top = 27 + Width = 13 + Height = 21 + Associate = edSOCKSPort + Min = 1 + Max = 65535 + Position = 9050 + TabOrder = 5 + Thousands = False + OnChanging = SpinChanging + end + object cbEnableSocks: TCheckBox + Left = 456 + Top = 6 + Width = 251 + Height = 17 + Caption = #1042#1082#1083#1102#1095#1080#1090#1100' '#1074#1089#1090#1088#1086#1077#1085#1085#1099#1081' '#1087#1088#1086#1082#1089#1080 + Checked = True + State = cbChecked + TabOrder = 2 + OnClick = cbEnableSocksClick + end + object cbxBridgesType: TComboBox + Left = 49 + Top = 127 + Width = 120 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + Enabled = False + ItemIndex = 0 + ParentDoubleBuffered = False + TabOrder = 14 + Text = #1042#1089#1090#1088#1086#1077#1085#1085#1099#1077 + OnChange = cbxBridgesTypeChange + OnCloseUp = cbxBridgesTypeCloseUp + OnKeyDown = cbxBridgesTypeKeyDown + Items.Strings = ( + #1042#1089#1090#1088#1086#1077#1085#1085#1099#1077 + #1055#1086#1083#1100#1079#1086#1074#1072#1090#1077#1083#1100#1089#1082#1080#1077) + end + object cbxBridgesList: TComboBox + Left = 255 + Top = 129 + Width = 120 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + ParentDoubleBuffered = False + TabOrder = 15 + OnChange = cbxBridgesListChange + OnCloseUp = cbxBridgesListCloseUp + OnKeyDown = cbxBridgesListKeyDown + end + object cbUsePreferredBridge: TCheckBox + Left = 10 + Top = 351 + Width = 313 + Height = 16 + Caption = #1047#1072#1076#1072#1090#1100' '#1087#1088#1077#1076#1087#1086#1095#1080#1090#1072#1077#1084#1099#1081' '#1084#1086#1089#1090' '#1074#1088#1091#1095#1085#1091#1102 + TabOrder = 17 + OnClick = cbUsePreferredBridgeClick + OnExit = cbUsePreferredBridgeExit + end + object edPreferredBridge: TEdit + Left = 55 + Top = 370 + Width = 588 + Height = 21 + Enabled = False + MaxLength = 255 + PopupMenu = EditMenu + TabOrder = 18 + TextHint = #1069#1090#1072' '#1085#1072#1089#1090#1088#1086#1081#1082#1072' '#1087#1077#1088#1077#1086#1087#1088#1077#1076#1077#1083#1103#1077#1090' '#1074#1099#1073#1088#1072#1085#1085#1099#1081' '#1089#1087#1080#1089#1086#1082' '#1084#1086#1089#1090#1086#1074 + OnChange = edPreferredBridgeChange + OnExit = edPreferredBridgeExit + end + object btnFindPreferredBridge: TButton + Left = 647 + Top = 370 + Width = 62 + Height = 21 + Caption = #1053#1072#1081#1090#1080'..' + DoubleBuffered = True + Enabled = False + ParentDoubleBuffered = False + TabOrder = 19 + OnClick = btnFindPreferredBridgeClick + end + end + object tsFilter: TTabSheet + Caption = #1060#1080#1083#1100#1090#1088 + ImageIndex = 2 + object lbFilterMode: TLabel + Left = 36 + Top = 6 + Width = 32 + Height = 13 + Alignment = taRightJustify + Caption = #1056#1077#1078#1080#1084 + Transparent = True + end + object lbFilterCount: TLabel + Left = 628 + Top = 6 + Width = 84 + Height = 13 + Alignment = taRightJustify + Caption = #1055#1086#1082#1072#1079#1072#1085#1086': 0 '#1080#1079' 0' + Transparent = True + end + object lbFilterEntry: TLabel + Left = 250 + Top = 6 + Width = 58 + Height = 13 + Hint = '288' + Alignment = taRightJustify + Caption = #1042#1093#1086#1076#1085#1099#1077': 0' + Transparent = True + end + object lbFilterMiddle: TLabel + Left = 334 + Top = 6 + Width = 57 + Height = 13 + Hint = '289' + Alignment = taRightJustify + Caption = #1057#1088#1077#1076#1085#1080#1077': 0' + Transparent = True + end + object lbFilterExit: TLabel + Left = 414 + Top = 6 + Width = 66 + Height = 13 + Hint = '290' + Alignment = taRightJustify + Caption = #1042#1099#1093#1086#1076#1085#1099#1077': 0' + Transparent = True + end + object lbFilterExclude: TLabel + Left = 498 + Top = 6 + Width = 84 + Height = 13 + Hint = '287' + Alignment = taRightJustify + Caption = #1047#1072#1087#1088#1077#1097#1105#1085#1085#1099#1077': 0' + Transparent = True + end + object cbxFilterMode: TComboBox + Left = 71 + Top = 3 + Width = 150 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + ItemIndex = 1 + ParentDoubleBuffered = False + TabOrder = 1 + Text = #1042#1099#1073#1088#1072#1085#1085#1099#1077' '#1089#1090#1088#1072#1085#1099 + OnChange = OptionsChange + Items.Strings = ( + #1054#1090#1082#1083#1102#1095#1077#1085#1086 + #1042#1099#1073#1088#1072#1085#1085#1099#1077' '#1089#1090#1088#1072#1085#1099 + #1048#1079#1073#1088#1072#1085#1085#1099#1077' '#1091#1079#1083#1099) + end + object sgFilter: TStringGrid + Tag = 1 + Left = -1 + Top = 29 + Width = 720 + Height = 373 + ColCount = 12 + DefaultRowHeight = 16 + FixedCols = 0 + RowCount = 2 + Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goDrawFocusSelected, goRowSelect, goThumbTracking, goFixedRowClick] + ParentShowHint = False + PopupMenu = mnFilter + ScrollBars = ssVertical + ShowHint = True + TabOrder = 0 + OnDrawCell = sgFilterDrawCell + OnExit = sgFilterExit + OnFixedCellClick = sgFilterFixedCellClick + OnKeyDown = sgFilterKeyDown + OnKeyPress = sgFilterKeyPress + OnMouseDown = sgFilterMouseDown + OnMouseMove = sgFilterMouseMove + OnSelectCell = sgFilterSelectCell + ColWidths = ( + 65 + 66 + 66 + 64 + 64 + 64 + 64 + 64 + 64 + 64 + 64 + 64) + end + end + object tsServer: TTabSheet + Caption = #1057#1077#1088#1074#1077#1088 + ImageIndex = 3 + object lbORPort: TLabel + Left = 614 + Top = 28 + Width = 37 + Height = 13 + Alignment = taRightJustify + Caption = #1057#1077#1088#1074#1077#1088 + Enabled = False + Transparent = True + end + object lbNickname: TLabel + Left = 86 + Top = 29 + Width = 19 + Height = 13 + Alignment = taRightJustify + Caption = #1053#1080#1082 + Enabled = False + Transparent = True + end + object lbServerMode: TLabel + Left = 32 + Top = 7 + Width = 73 + Height = 13 + Alignment = taRightJustify + Caption = #1056#1077#1078#1080#1084' '#1088#1072#1073#1086#1090#1099 + Transparent = True + end + object lbRelayBandwidthRate: TLabel + Left = 449 + Top = 28 + Width = 44 + Height = 13 + Alignment = taRightJustify + Caption = #1057#1088#1077#1076#1085#1103#1103 + Enabled = False + Transparent = True + end + object lbRelayBandwidthBurst: TLabel + Left = 444 + Top = 52 + Width = 49 + Height = 13 + Alignment = taRightJustify + Caption = #1052#1072#1082#1089#1080#1084#1091#1084 + Enabled = False + Transparent = True + end + object lbSpeed1: TLabel + Left = 554 + Top = 28 + Width = 22 + Height = 13 + Caption = #1050#1041'/c' + Enabled = False + Transparent = True + end + object lbSpeed2: TLabel + Left = 554 + Top = 52 + Width = 22 + Height = 13 + Caption = #1050#1041'/c' + Enabled = False + Transparent = True + end + object lbContactInfo: TLabel + Left = 54 + Top = 53 + Width = 51 + Height = 13 + Alignment = taRightJustify + Caption = #1050#1086#1085#1090#1072#1082#1090#1099 + Enabled = False + Transparent = True + end + object lbDirPort: TLabel + Left = 609 + Top = 52 + Width = 42 + Height = 13 + Alignment = taRightJustify + Caption = #1050#1072#1090#1072#1083#1086#1075 + Enabled = False + Transparent = True + end + object lbExitPolicy: TLabel + Left = 14 + Top = 125 + Width = 91 + Height = 13 + Alignment = taRightJustify + Caption = #1055#1086#1083#1080#1090#1080#1082#1072' '#1074#1099#1093#1086#1076#1072 + Enabled = False + Transparent = True + end + object lbMaxMemInQueues: TLabel + Left = 265 + Top = 29 + Width = 49 + Height = 13 + Alignment = taRightJustify + Caption = #1052#1072#1082#1089#1080#1084#1091#1084 + Enabled = False + Transparent = True + end + object lbSizeMb: TLabel + Left = 375 + Top = 29 + Width = 14 + Height = 13 + Caption = #1052#1041 + Enabled = False + Transparent = True + end + object lbBridgeType: TLabel + Left = 55 + Top = 77 + Width = 50 + Height = 13 + Alignment = taRightJustify + Caption = #1058#1080#1087' '#1084#1086#1089#1090#1072 + Enabled = False + Transparent = True + end + object lbNumCPUs: TLabel + Left = 257 + Top = 76 + Width = 57 + Height = 13 + Alignment = taRightJustify + Caption = #1052#1072#1082#1089'. '#1103#1076#1077#1088 + Enabled = False + Transparent = True + end + object lbTransportPort: TLabel + Left = 598 + Top = 76 + Width = 53 + Height = 13 + Alignment = taRightJustify + Caption = #1058#1088#1072#1085#1089#1087#1086#1088#1090 + Enabled = False + Transparent = True + end + object imUPnPTest: TImage + Left = 687 + Top = 114 + Width = 20 + Height = 20 + Cursor = crHandPoint + Hint = #1055#1088#1086#1074#1077#1088#1082#1072' '#1087#1077#1088#1077#1072#1076#1088#1077#1089#1072#1094#1080#1080' '#1087#1086#1088#1090#1086#1074 + ParentShowHint = False + ShowHint = True + OnClick = imUPnPTestClick + end + object lbTotalMyFamily: TLabel + Left = 664 + Top = 285 + Width = 41 + Height = 13 + Alignment = taRightJustify + Caption = #1042#1089#1077#1075#1086': 0' + Enabled = False + Transparent = True + end + object lbPorts: TLabel + Left = 616 + Top = 6 + Width = 93 + Height = 13 + Alignment = taRightJustify + Caption = #1053#1072#1089#1090#1088#1086#1081#1082#1072' '#1087#1086#1088#1090#1086#1074 + Transparent = True + end + object lbAddress: TLabel + Left = 28 + Top = 373 + Width = 31 + Height = 13 + Alignment = taRightJustify + Caption = #1040#1076#1088#1077#1089 + Enabled = False + Transparent = True + end + object lbBridgeDistribution: TLabel + Left = 17 + Top = 101 + Width = 88 + Height = 13 + Alignment = taRightJustify + Caption = #1056#1072#1089#1087#1088#1086#1089#1090#1088#1072#1085#1077#1085#1080#1077 + Enabled = False + Transparent = True + end + object lbMaxAdvertisedBandwidth: TLabel + Left = 415 + Top = 76 + Width = 78 + Height = 13 + Alignment = taRightJustify + Caption = #1056#1077#1082#1083#1072#1084#1080#1088#1091#1077#1084#1072#1103 + Enabled = False + Transparent = True + end + object lbSpeed4: TLabel + Left = 554 + Top = 76 + Width = 22 + Height = 13 + Caption = #1050#1041'/c' + Enabled = False + Transparent = True + end + object edNickname: TEdit + Left = 108 + Top = 26 + Width = 125 + Height = 21 + Enabled = False + MaxLength = 19 + PopupMenu = EditMenu + TabOrder = 1 + Text = 'Unnamed' + TextHint = #1048#1084#1103' '#1074#1072#1096#1077#1075#1086' '#1091#1079#1083#1072 + OnChange = EditChange + end + object cbxServerMode: TComboBox + Left = 108 + Top = 3 + Width = 125 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + ItemIndex = 0 + ParentDoubleBuffered = False + TabOrder = 0 + Text = #1054#1090#1082#1083#1102#1095#1077#1085#1086 + OnChange = cbxServerModeChange + Items.Strings = ( + #1054#1090#1082#1083#1102#1095#1077#1085#1086 + #1056#1077#1090#1088#1072#1085#1089#1083#1103#1090#1086#1088 + #1042#1099#1093#1086#1076#1085#1086#1081' '#1091#1079#1077#1083 + #1052#1086#1089#1090) + end + object cbUseRelayBandwidth: TCheckBox + Left = 413 + Top = 4 + Width = 160 + Height = 17 + Caption = #1054#1075#1088#1072#1085#1080#1095#1080#1090#1100' '#1089#1082#1086#1088#1086#1089#1090#1100 + Enabled = False + TabOrder = 15 + OnClick = cbUseRelayBandwidthClick + end + object edContactInfo: TEdit + Left = 108 + Top = 50 + Width = 125 + Height = 21 + TabStop = False + Enabled = False + MaxLength = 255 + PopupMenu = EditMenu + TabOrder = 2 + TextHint = #1069#1083#1077#1082#1090#1088#1086#1085#1085#1099#1081' '#1072#1076#1088#1077#1089 + OnChange = EditChange + end + object cbxExitPolicyType: TComboBox + Left = 108 + Top = 122 + Width = 125 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + Enabled = False + ItemIndex = 0 + ParentDoubleBuffered = False + TabOrder = 5 + Text = #1055#1086' '#1091#1084#1086#1083#1095#1072#1085#1080#1102 + OnChange = cbxExitPolicyTypeChange + Items.Strings = ( + #1055#1086' '#1091#1084#1086#1083#1095#1072#1085#1080#1102 + #1054#1075#1088#1072#1085#1080#1095#1077#1085#1085#1072#1103 + #1053#1072#1089#1090#1088#1072#1080#1074#1072#1077#1084#1072#1103) + end + object cbUseUPnP: TCheckBox + Left = 244 + Top = 121 + Width = 390 + Height = 17 + Caption = #1055#1099#1090#1072#1090#1100#1089#1103' '#1072#1074#1090#1086#1084#1072#1090#1080#1095#1077#1089#1082#1080' '#1085#1072#1089#1090#1088#1086#1080#1090#1100' '#1087#1077#1088#1077#1072#1076#1088#1077#1089#1072#1094#1080#1102' '#1087#1086#1088#1090#1086#1074 + Checked = True + Enabled = False + State = cbChecked + TabOrder = 29 + OnClick = cbUseUPnPClick + end + object cbUseMaxMemInQueues: TCheckBox + Left = 244 + Top = 5 + Width = 160 + Height = 17 + Caption = #1054#1075#1088#1072#1085#1080#1095#1080#1090#1100' '#1087#1072#1084#1103#1090#1100 + Enabled = False + TabOrder = 9 + OnClick = cbUseMaxMemInQueuesClick + end + object cbxBridgeType: TComboBox + Left = 108 + Top = 74 + Width = 125 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + Enabled = False + ParentDoubleBuffered = False + TabOrder = 3 + OnChange = cbxBridgeTypeChange + end + object meExitPolicy: TMemo + Left = 10 + Top = 146 + Width = 223 + Height = 194 + Enabled = False + Lines.Strings = ( + 'accept *:80' + 'accept *:443' + 'reject *:*') + PopupMenu = EditMenu + ScrollBars = ssVertical + TabOrder = 6 + WordWrap = False + OnChange = OptionsChange + OnExit = MemoExit + OnKeyPress = MemoKeyPress + end + object cbUseNumCPUs: TCheckBox + Left = 244 + Top = 52 + Width = 160 + Height = 17 + Caption = #1054#1075#1088#1072#1085#1080#1095#1080#1090#1100' '#1087#1088#1086#1094#1077#1089#1089#1086#1088 + Enabled = False + TabOrder = 12 + OnClick = cbUseNumCPUsClick + end + object cbPublishServerDescriptor: TCheckBox + Left = 244 + Top = 141 + Width = 415 + Height = 17 + Caption = #1055#1091#1073#1083#1080#1082#1086#1074#1072#1090#1100' '#1089#1077#1088#1074#1077#1088' '#1074' '#1082#1072#1090#1072#1083#1086#1075#1077' '#1088#1077#1090#1088#1072#1085#1089#1083#1103#1090#1086#1088#1086#1074 + Checked = True + Enabled = False + State = cbChecked + TabOrder = 30 + OnClick = OptionsChange + end + object cbUseDirPort: TCheckBox + Left = 244 + Top = 161 + Width = 415 + Height = 17 + TabStop = False + Caption = #1042#1082#1083#1102#1095#1080#1090#1100' '#1079#1077#1088#1082#1072#1083#1086' '#1082#1072#1090#1072#1083#1086#1075#1072' '#1088#1077#1090#1088#1072#1085#1089#1083#1103#1090#1086#1088#1086#1074 + Enabled = False + TabOrder = 31 + OnClick = cbUseDirPortClick + end + object cbDirReqStatistics: TCheckBox + Left = 244 + Top = 201 + Width = 415 + Height = 17 + Caption = #1057#1086#1073#1080#1088#1072#1090#1100' '#1089#1090#1072#1090#1080#1089#1090#1080#1082#1091' '#1079#1072#1087#1088#1086#1089#1086#1074' '#1082#1072#1090#1072#1083#1086#1075#1072 + Checked = True + Enabled = False + State = cbChecked + TabOrder = 33 + OnClick = OptionsChange + end + object cbIPv6Exit: TCheckBox + Left = 259 + Top = 261 + Width = 320 + Height = 17 + Caption = #1056#1072#1079#1088#1077#1096#1080#1090#1100' '#1074#1099#1093#1086#1076' IPv6 '#1090#1088#1072#1092#1080#1082#1072 + Enabled = False + TabOrder = 36 + OnClick = OptionsChange + end + object cbHiddenServiceStatistics: TCheckBox + Left = 244 + Top = 181 + Width = 415 + Height = 17 + Caption = + #1057#1086#1073#1080#1088#1072#1090#1100' '#1089#1090#1072#1090#1080#1089#1090#1080#1082#1091' '#1086' '#1089#1074#1086#1077#1081' '#1088#1086#1083#1080' '#1074' '#1082#1072#1095#1077#1089#1090#1074#1077' '#1091#1079#1083#1072' '#1089#1082#1088#1099#1090#1086#1075#1086' '#1089#1077#1088#1074#1080#1089 + + #1072 + Checked = True + Enabled = False + State = cbChecked + TabOrder = 32 + OnClick = OptionsChange + end + object edORPort: TEdit + Left = 654 + Top = 25 + Width = 42 + Height = 21 + Enabled = False + MaxLength = 5 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 22 + Text = '9001' + OnChange = EditChange + end + object udORPort: TUpDown + Left = 696 + Top = 25 + Width = 13 + Height = 21 + Associate = edORPort + Enabled = False + Min = 1 + Max = 65535 + Position = 9001 + TabOrder = 23 + Thousands = False + OnChanging = SpinChanging + end + object edDirPort: TEdit + Left = 654 + Top = 49 + Width = 42 + Height = 21 + Enabled = False + MaxLength = 5 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 24 + Text = '9030' + OnChange = EditChange + end + object udDirPort: TUpDown + Left = 696 + Top = 49 + Width = 13 + Height = 21 + Associate = edDirPort + Enabled = False + Min = 1 + Max = 65535 + Position = 9030 + TabOrder = 25 + Thousands = False + OnChanging = SpinChanging + end + object edTransportPort: TEdit + Left = 654 + Top = 73 + Width = 42 + Height = 21 + Enabled = False + MaxLength = 5 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 26 + Text = '443' + OnChange = EditChange + end + object udTransportPort: TUpDown + Left = 696 + Top = 73 + Width = 13 + Height = 21 + Associate = edTransportPort + Enabled = False + Min = 1 + Max = 65535 + Position = 443 + TabOrder = 27 + Thousands = False + OnChanging = SpinChanging + end + object edMaxMemInQueues: TEdit + Left = 317 + Top = 26 + Width = 42 + Height = 21 + Enabled = False + MaxLength = 5 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 10 + Text = '1024' + OnChange = EditChange + end + object udMaxMemInQueues: TUpDown + Left = 359 + Top = 26 + Width = 13 + Height = 21 + Associate = edMaxMemInQueues + Enabled = False + Min = 256 + Max = 32768 + Increment = 256 + Position = 1024 + TabOrder = 11 + Thousands = False + OnChanging = SpinChanging + end + object edNumCPUs: TEdit + Left = 317 + Top = 73 + Width = 42 + Height = 21 + Enabled = False + MaxLength = 2 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 13 + Text = '1' + OnChange = EditChange + end + object udNumCPUs: TUpDown + Left = 359 + Top = 73 + Width = 13 + Height = 21 + Associate = edNumCPUs + Enabled = False + Min = 1 + Max = 32 + Position = 1 + TabOrder = 14 + Thousands = False + OnChanging = SpinChanging + end + object edRelayBandwidthRate: TEdit + Left = 496 + Top = 25 + Width = 42 + Height = 21 + Enabled = False + MaxLength = 7 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 16 + Text = '1250' + OnChange = EditChange + end + object udRelayBandwidthRate: TUpDown + Left = 538 + Top = 25 + Width = 13 + Height = 21 + Associate = edRelayBandwidthRate + Enabled = False + Min = 250 + Max = 1048576 + Increment = 250 + Position = 1250 + TabOrder = 17 + Thousands = False + OnChanging = SpinChanging + end + object edRelayBandwidthBurst: TEdit + Left = 496 + Top = 49 + Width = 42 + Height = 21 + Enabled = False + MaxLength = 7 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 18 + Text = '2500' + OnChange = EditChange + end + object udRelayBandwidthBurst: TUpDown + Left = 538 + Top = 49 + Width = 13 + Height = 21 + Associate = edRelayBandwidthBurst + Enabled = False + Min = 250 + Max = 1048576 + Increment = 250 + Position = 2500 + TabOrder = 19 + Thousands = False + OnChanging = SpinChanging + end + object meMyFamily: TMemo + Left = 244 + Top = 306 + Width = 464 + Height = 85 + DoubleBuffered = True + Enabled = False + ParentDoubleBuffered = False + PopupMenu = EditMenu + ScrollBars = ssVertical + TabOrder = 38 + WordWrap = False + OnChange = meMyFamilyChange + OnExit = MemoExit + OnKeyPress = MemoKeyPress + end + object cbDirCache: TCheckBox + Left = 244 + Top = 101 + Width = 162 + Height = 17 + Caption = #1048#1089#1087#1086#1083#1100#1079#1086#1074#1072#1090#1100' '#1082#1101#1096' '#1082#1072#1090#1072#1083#1086#1075#1072 + Checked = True + State = cbChecked + TabOrder = 28 + OnMouseDown = cbDirCacheMouseDown + end + object cbListenIPv6: TCheckBox + Left = 244 + Top = 241 + Width = 415 + Height = 17 + Caption = #1055#1088#1086#1089#1083#1091#1096#1080#1074#1072#1090#1100' IPv6-'#1072#1076#1088#1077#1089#1072 + Enabled = False + TabOrder = 35 + OnClick = cbListenIPv6Click + end + object cbAssumeReachable: TCheckBox + Left = 244 + Top = 221 + Width = 415 + Height = 17 + Caption = #1054#1090#1082#1083#1102#1095#1080#1090#1100' '#1087#1088#1086#1074#1077#1088#1082#1091' '#1076#1086#1089#1090#1091#1087#1085#1086#1089#1090#1080' '#1089#1077#1088#1074#1077#1088#1072 + Enabled = False + TabOrder = 34 + OnClick = cbListenIPv6Click + end + object cbUseAddress: TCheckBox + Left = 10 + Top = 349 + Width = 222 + Height = 17 + Caption = #1047#1072#1076#1072#1090#1100' '#1074#1085#1077#1096#1085#1080#1081' '#1072#1076#1088#1077#1089' '#1074#1088#1091#1095#1085#1091#1102 + Enabled = False + TabOrder = 7 + OnClick = cbUseAddressClick + end + object edAddress: TEdit + Left = 63 + Top = 370 + Width = 170 + Height = 21 + Enabled = False + MaxLength = 255 + PopupMenu = EditMenu + TabOrder = 8 + TextHint = 'IP-'#1072#1076#1088#1077#1089' '#1080#1083#1080' '#1080#1084#1103' '#1091#1079#1083#1072 + OnChange = EditChange + end + object cbUseMyFamily: TCheckBox + Left = 244 + Top = 281 + Width = 288 + Height = 17 + Caption = #1048#1089#1087#1086#1083#1100#1079#1086#1074#1072#1090#1100' '#1089#1077#1084#1077#1081#1089#1090#1074#1086 + Enabled = False + TabOrder = 37 + OnClick = cbUseMyFamilyClick + end + object cbxBridgeDistribution: TComboBox + Left = 108 + Top = 98 + Width = 125 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + Enabled = False + ItemIndex = 0 + ParentDoubleBuffered = False + TabOrder = 4 + Text = #1051#1102#1073#1086#1077 + OnChange = OptionsChange + Items.Strings = ( + #1051#1102#1073#1086#1077 + 'https' + 'e-mail' + 'Moat' + #1053#1077' '#1088#1072#1089#1087#1088#1086#1089#1090#1088#1072#1085#1103#1090#1100) + end + object edMaxAdvertisedBandwidth: TEdit + Left = 496 + Top = 73 + Width = 42 + Height = 21 + Enabled = False + MaxLength = 7 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 20 + Text = '2000' + OnChange = EditChange + end + object udMaxAdvertisedBandwidth: TUpDown + Left = 538 + Top = 73 + Width = 13 + Height = 21 + Associate = edMaxAdvertisedBandwidth + Enabled = False + Min = 250 + Max = 1048576 + Increment = 250 + Position = 2000 + TabOrder = 21 + Thousands = False + OnChanging = SpinChanging + end + end + object tsHs: TTabSheet + Caption = #1057#1082#1088#1099#1090#1099#1081' '#1089#1077#1088#1074#1080#1089 + ImageIndex = 4 + object sgHsPorts: TStringGrid + Tag = 6 + Left = 436 + Top = 9 + Width = 272 + Height = 269 + ColCount = 3 + DefaultRowHeight = 16 + FixedCols = 0 + RowCount = 2 + Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goDrawFocusSelected, goRowSelect, goThumbTracking] + ParentShowHint = False + PopupMenu = mnHs + ScrollBars = ssVertical + ShowHint = True + TabOrder = 1 + OnDrawCell = sgHsPortsDrawCell + OnEnter = sgHsPortsEnter + OnKeyDown = sgHsPortsKeyDown + OnMouseMove = sgHsPortsMouseMove + OnSelectCell = sgHsPortsSelectCell + end + object sgHs: TStringGrid + Tag = 5 + Left = 10 + Top = 9 + Width = 416 + Height = 269 + ColCount = 7 + DefaultRowHeight = 16 + FixedCols = 0 + RowCount = 2 + Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goDrawFocusSelected, goRowSelect, goThumbTracking] + ParentShowHint = False + PopupMenu = mnHs + ScrollBars = ssVertical + ShowHint = True + TabOrder = 0 + OnDrawCell = sgHsDrawCell + OnEnter = sgHsEnter + OnKeyDown = sgHsKeyDown + OnMouseMove = sgHsMouseMove + OnSelectCell = sgHsSelectCell + ColWidths = ( + 64 + 64 + 64 + 64 + 64 + 64 + 64) + end + object gbHsEdit: TGroupBox + Left = 10 + Top = 282 + Width = 698 + Height = 109 + Caption = #1055#1072#1085#1077#1083#1100' '#1088#1077#1076#1072#1082#1090#1080#1088#1086#1074#1072#1085#1080#1103 + TabOrder = 2 + object lbHsSocket: TLabel + Left = 460 + Top = 21 + Width = 36 + Height = 13 + Alignment = taRightJustify + Caption = #1057#1077#1088#1074#1080#1089 + Enabled = False + Transparent = True + end + object lbHsVirtualPort: TLabel + Left = 535 + Top = 49 + Width = 95 + Height = 13 + Alignment = taRightJustify + Caption = #1042#1080#1088#1090#1091#1072#1083#1100#1085#1099#1081' '#1087#1086#1088#1090 + Enabled = False + Transparent = True + end + object lbHsVersion: TLabel + Left = 268 + Top = 21 + Width = 92 + Height = 13 + Alignment = taRightJustify + Caption = #1042#1077#1088#1089#1080#1103' '#1087#1088#1086#1090#1086#1082#1086#1083#1072 + Enabled = False + Transparent = True + end + object lbHsNumIntroductionPoints: TLabel + Left = 296 + Top = 49 + Width = 64 + Height = 13 + Alignment = taRightJustify + Caption = #1058#1086#1095#1077#1082' '#1074#1093#1086#1076#1072 + Enabled = False + Transparent = True + end + object lbRendPostPeriod: TLabel + Left = 248 + Top = 77 + Width = 112 + Height = 13 + Alignment = taRightJustify + Caption = #1048#1085#1090#1077#1088#1074#1072#1083' '#1087#1091#1073#1083#1080#1082#1072#1094#1080#1080 + Enabled = False + Transparent = True + end + object lbMinutes: TLabel + Left = 420 + Top = 77 + Width = 22 + Height = 13 + Caption = #1084#1080#1085'.' + Enabled = False + Transparent = True + end + object lbHsMaxStreams: TLabel + Left = 28 + Top = 76 + Width = 122 + Height = 13 + Alignment = taRightJustify + Caption = #1057#1086#1077#1076#1080#1085#1077#1085#1080#1081' '#1085#1072' '#1094#1077#1087#1086#1095#1082#1091 + Enabled = False + Transparent = True + end + object lbHsName: TLabel + Left = 12 + Top = 21 + Width = 48 + Height = 13 + Alignment = taRightJustify + Caption = #1053#1072#1079#1074#1072#1085#1080#1077 + Enabled = False + Transparent = True + end + object lbHsState: TLabel + Left = 541 + Top = 77 + Width = 54 + Height = 13 + Alignment = taRightJustify + Caption = #1057#1086#1089#1090#1086#1103#1085#1080#1077 + Enabled = False + Transparent = True + end + object cbxHsAddress: TComboBox + Left = 499 + Top = 18 + Width = 130 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + Enabled = False + ItemIndex = 0 + ParentDoubleBuffered = False + TabOrder = 9 + Text = '127.0.0.1' + OnChange = cbxHsAddressChange + OnDropDown = cbxHsAddressDropDown + Items.Strings = ( + '127.0.0.1') + end + object cbxHsVersion: TComboBox + Left = 362 + Top = 18 + Width = 54 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + Enabled = False + ItemIndex = 1 + ParentDoubleBuffered = False + TabOrder = 4 + Text = '3' + OnChange = cbxHsVersionChange + Items.Strings = ( + '2' + '3') + end + object cbHsMaxStreams: TCheckBox + Left = 12 + Top = 47 + Width = 213 + Height = 17 + Caption = #1054#1075#1088#1072#1085#1080#1095#1080#1090#1100' '#1095#1080#1089#1083#1086' '#1089#1086#1077#1076#1080#1085#1077#1085#1080#1081 + Enabled = False + TabOrder = 1 + OnClick = cbHsMaxStreamsClick + end + object edHsName: TEdit + Left = 62 + Top = 18 + Width = 145 + Height = 21 + Enabled = False + MaxLength = 25 + PopupMenu = EditMenu + TabOrder = 0 + TextHint = #1048#1084#1103' '#1082#1072#1090#1072#1083#1086#1075#1072 + OnChange = edHsChange + end + object edHsNumIntroductionPoints: TEdit + Left = 362 + Top = 46 + Width = 42 + Height = 21 + HelpType = htKeyword + HelpContext = 1 + Enabled = False + MaxLength = 2 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 5 + Text = '3' + OnChange = edHsChange + end + object udHsNumIntroductionPoints: TUpDown + Tag = 1 + Left = 404 + Top = 46 + Width = 13 + Height = 21 + Associate = edHsNumIntroductionPoints + Enabled = False + Min = 3 + Max = 20 + Position = 3 + TabOrder = 6 + Thousands = False + OnMouseDown = udHsMouseDown + end + object edHsMaxStreams: TEdit + Left = 153 + Top = 73 + Width = 42 + Height = 21 + HelpType = htKeyword + HelpContext = 2 + Enabled = False + MaxLength = 5 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 2 + Text = '32' + OnChange = edHsChange + end + object udHsMaxStreams: TUpDown + Tag = 2 + Left = 195 + Top = 73 + Width = 13 + Height = 21 + Associate = edHsMaxStreams + Enabled = False + Min = 1 + Max = 65535 + Position = 32 + TabOrder = 3 + Thousands = False + OnMouseDown = udHsMouseDown + end + object udRendPostPeriod: TUpDown + Left = 404 + Top = 74 + Width = 13 + Height = 21 + Associate = edRendPostPeriod + Enabled = False + Min = 10 + Max = 5040 + Increment = 10 + Position = 60 + TabOrder = 8 + Thousands = False + OnChanging = SpinChanging + end + object edRendPostPeriod: TEdit + Left = 362 + Top = 74 + Width = 42 + Height = 21 + Enabled = False + MaxLength = 4 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 7 + Text = '60' + OnChange = EditChange + end + object edHsRealPort: TEdit + Left = 632 + Top = 18 + Width = 42 + Height = 21 + HelpType = htKeyword + HelpContext = 3 + Enabled = False + MaxLength = 5 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 10 + Text = '80' + OnChange = edHsChange + end + object udHsRealPort: TUpDown + Tag = 3 + Left = 674 + Top = 18 + Width = 13 + Height = 21 + Associate = edHsRealPort + Enabled = False + Min = 1 + Max = 65535 + Position = 80 + TabOrder = 11 + Thousands = False + OnMouseDown = udHsMouseDown + end + object edHsVirtualPort: TEdit + Left = 632 + Top = 46 + Width = 42 + Height = 21 + HelpType = htKeyword + HelpContext = 4 + Enabled = False + MaxLength = 5 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 12 + Text = '80' + OnChange = edHsChange + end + object udHsVirtualPort: TUpDown + Tag = 4 + Left = 674 + Top = 46 + Width = 13 + Height = 21 + Associate = edHsVirtualPort + Enabled = False + Min = 1 + Max = 65535 + Position = 80 + TabOrder = 13 + Thousands = False + OnMouseDown = udHsMouseDown + end + object cbxHsState: TComboBox + Left = 598 + Top = 74 + Width = 89 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + Enabled = False + ItemIndex = 0 + ParentDoubleBuffered = False + TabOrder = 14 + Text = #1042#1082#1083#1102#1095#1077#1085#1086 + OnChange = cbxHsStateChange + Items.Strings = ( + #1042#1082#1083#1102#1095#1077#1085#1086 + #1042#1099#1082#1083#1102#1095#1077#1085#1086) + end + end + end + object tsLists: TTabSheet + Caption = #1057#1087#1080#1089#1082#1080 + ImageIndex = 12 + object lbSeconds4: TLabel + Left = 199 + Top = 29 + Width = 21 + Height = 13 + Caption = #1089#1077#1082'.' + Enabled = False + Transparent = True + end + object lbTotalHosts: TLabel + Left = 313 + Top = 29 + Width = 41 + Height = 13 + Alignment = taRightJustify + Caption = #1042#1089#1077#1075#1086': 0' + Enabled = False + Transparent = True + end + object lbTrackHostExitsExpire: TLabel + Left = 26 + Top = 29 + Width = 109 + Height = 13 + Alignment = taRightJustify + Caption = #1052#1077#1085#1103#1090#1100' '#1087#1086' '#1080#1089#1090#1077#1095#1077#1085#1080#1080 + Enabled = False + Transparent = True + end + object lbTotalNodesList: TLabel + Left = 666 + Top = 29 + Width = 41 + Height = 13 + Alignment = taRightJustify + Caption = #1042#1089#1077#1075#1086': 0' + Transparent = True + end + object lbNodesListType: TLabel + Left = 363 + Top = 29 + Width = 36 + Height = 13 + Alignment = taRightJustify + Caption = #1057#1087#1080#1089#1086#1082 + Transparent = True + end + object lbNodesListTypeCaption: TLabel + Left = 364 + Top = 7 + Width = 197 + Height = 13 + Caption = #1042#1099#1073#1077#1088#1080#1090#1077' '#1089#1087#1080#1089#1086#1082' '#1076#1083#1103' '#1088#1077#1076#1072#1082#1090#1080#1088#1086#1074#1072#1085#1080#1103 + Transparent = True + end + object lbVanguardLayerType: TLabel + AlignWithMargins = True + Left = 96 + Top = 373 + Width = 119 + Height = 13 + Alignment = taRightJustify + Caption = #1048#1079#1084#1077#1085#1103#1090#1100' '#1091#1079#1077#1083' '#1094#1077#1087#1086#1095#1082#1080 + Transparent = True + end + object meTrackHostExits: TMemo + Left = 10 + Top = 52 + Width = 344 + Height = 285 + Enabled = False + PopupMenu = EditMenu + ScrollBars = ssVertical + TabOrder = 3 + WordWrap = False + OnChange = meTrackHostExitsChange + OnExit = MemoExit + OnKeyPress = MemoKeyPress + end + object cbUseTrackHostExits: TCheckBox + Left = 10 + Top = 6 + Width = 310 + Height = 17 + Caption = #1057#1086#1093#1088#1072#1085#1103#1090#1100' '#1074#1099#1093#1086#1076#1085#1086#1081' '#1091#1079#1077#1083' '#1076#1083#1103' '#1091#1082#1072#1079#1072#1085#1085#1099#1093' '#1072#1076#1088#1077#1089#1086#1074 + TabOrder = 0 + OnClick = cbUseTrackHostExitsClick + end + object cbEnableNodesList: TCheckBox + Left = 540 + Top = 28 + Width = 75 + Height = 17 + Caption = #1042#1082#1083#1102#1095#1080#1090#1100 + TabOrder = 7 + OnClick = cbEnableNodesListClick + end + object meNodesList: TMemo + Left = 364 + Top = 51 + Width = 344 + Height = 340 + Enabled = False + PopupMenu = EditMenu + ScrollBars = ssVertical + TabOrder = 8 + WordWrap = False + OnChange = meNodesListChange + OnExit = meNodesListExit + OnKeyPress = MemoKeyPress + end + object edTrackHostExitsExpire: TEdit + Left = 139 + Top = 26 + Width = 42 + Height = 21 + Enabled = False + MaxLength = 7 + NumbersOnly = True + PopupMenu = EditMenu + TabOrder = 1 + Text = '1800' + OnChange = EditChange + end + object udTrackHostExitsExpire: TUpDown + Left = 181 + Top = 26 + Width = 13 + Height = 21 + Associate = edTrackHostExitsExpire + Enabled = False + Min = 10 + Max = 2592000 + Increment = 60 + Position = 1800 + TabOrder = 2 + Thousands = False + OnChanging = SpinChanging + end + object cbxNodesListType: TComboBox + Left = 403 + Top = 26 + Width = 130 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + ItemIndex = 3 + ParentDoubleBuffered = False + TabOrder = 6 + Text = #1047#1072#1087#1088#1077#1097#1105#1085#1085#1099#1077' '#1091#1079#1083#1099 + OnChange = cbxNodesListTypeChange + OnKeyDown = cbxNodesListTypeKeyDown + Items.Strings = ( + #1042#1093#1086#1076#1085#1099#1077' '#1091#1079#1083#1099 + #1057#1088#1077#1076#1085#1080#1077' '#1091#1079#1083#1099 + #1042#1099#1093#1086#1076#1085#1099#1077' '#1091#1079#1083#1099 + #1047#1072#1087#1088#1077#1097#1105#1085#1085#1099#1077' '#1091#1079#1083#1099) + end + object cbUseHiddenServiceVanguards: TCheckBox + Left = 10 + Top = 347 + Width = 344 + Height = 17 + Caption = #1048#1089#1087#1086#1083#1100#1079#1086#1074#1072#1090#1100' '#1072#1074#1072#1085#1075#1072#1088#1076#1099' '#1076#1083#1103' '#1089#1082#1088#1099#1090#1099#1093' '#1089#1077#1088#1074#1080#1089#1086#1074 + Checked = True + State = cbChecked + TabOrder = 4 + OnClick = cbUseHiddenServiceVanguardsClick + end + object cbxVanguardLayerType: TComboBox + Left = 218 + Top = 370 + Width = 135 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + ItemIndex = 0 + ParentDoubleBuffered = False + TabOrder = 5 + Text = #1040#1074#1090#1086#1074#1099#1073#1086#1088 + OnChange = OptionsChange + Items.Strings = ( + #1040#1074#1090#1086#1074#1099#1073#1086#1088 + #1058#1086#1083#1100#1082#1086' '#1074#1090#1086#1088#1086#1081 + #1058#1086#1083#1100#1082#1086' '#1090#1088#1077#1090#1080#1081 + #1042#1090#1086#1088#1086#1081' '#1080' '#1090#1088#1077#1090#1080#1081) + end + end + object tsOther: TTabSheet + Caption = #1056#1072#1079#1085#1086#1077 + ImageIndex = 5 + object gbNetworkScanner: TGroupBox + Left = 10 + Top = 3 + Width = 323 + Height = 388 + Caption = #1057#1077#1090#1077#1074#1086#1081' '#1089#1082#1072#1085#1077#1088 + TabOrder = 0 + object lbFullScanInterval: TLabel + Left = 70 + Top = 298 + Width = 155 + Height = 13 + Alignment = taRightJustify + Caption = #1055#1086#1083#1085#1086#1077' '#1089#1082#1072#1085#1080#1088#1086#1074#1072#1085#1080#1077' '#1082#1072#1078#1076#1099#1077 + Transparent = True + end + object lbHours1: TLabel + Left = 290 + Top = 298 + Width = 10 + Height = 13 + Caption = #1095'.' + Transparent = True + end + object lbNonResponsedScanInterval: TLabel + Left = 17 + Top = 322 + Width = 208 + Height = 13 + Alignment = taRightJustify + Caption = #1057#1082#1072#1085#1080#1088#1086#1074#1072#1085#1080#1077' '#1091#1079#1083#1086#1074' '#1073#1077#1079' '#1086#1090#1074#1077#1090#1072' '#1082#1072#1078#1076#1099#1077 + Transparent = True + end + object lbHours2: TLabel + Left = 290 + Top = 322 + Width = 10 + Height = 13 + Caption = #1095'.' + Transparent = True + end + object lbPartialScansCounts: TLabel + Left = 33 + Top = 346 + Width = 192 + Height = 13 + Alignment = taRightJustify + Caption = #1050#1086#1083#1080#1095#1077#1089#1090#1074#1086' '#1095#1072#1089#1090#1080#1095#1085#1099#1093' '#1089#1082#1072#1085#1080#1088#1086#1074#1072#1085#1080#1081 + Transparent = True + end + object lbScanMaxThread: TLabel + Left = 47 + Top = 191 + Width = 179 + Height = 13 + Alignment = taRightJustify + Caption = #1050#1086#1083#1080#1095#1077#1089#1090#1074#1086' '#1087#1086#1090#1086#1082#1086#1074' '#1089#1082#1072#1085#1080#1088#1086#1074#1072#1085#1080#1103 + Transparent = True + end + object lbScanPortAttempts: TLabel + Left = 9 + Top = 95 + Width = 217 + Height = 13 + Alignment = taRightJustify + Caption = #1050#1086#1083#1080#1095#1077#1089#1090#1074#1086' '#1087#1086#1087#1099#1090#1086#1082' '#1089#1086#1077#1076#1080#1085#1077#1085#1080#1103' '#1089' '#1087#1086#1088#1090#1086#1084 + Transparent = True + end + object lbScanPortionSize: TLabel + Left = 35 + Top = 239 + Width = 191 + Height = 13 + Alignment = taRightJustify + Caption = #1050#1086#1083#1080#1095#1077#1089#1090#1074#1086' '#1089#1082#1072#1085#1080#1088#1086#1074#1072#1085#1080#1081' '#1085#1072' '#1087#1086#1088#1094#1080#1102 + Transparent = True + end + object lbScanPingAttempts: TLabel + Left = 43 + Top = 143 + Width = 183 + Height = 13 + Alignment = taRightJustify + Caption = #1050#1086#1083#1080#1095#1077#1089#1090#1074#1086' '#1087#1086#1087#1099#1090#1086#1082' '#1080#1079#1084#1077#1088#1080#1090#1100' '#1087#1080#1085#1075 + Transparent = True + end + object lbScanPortTimeout: TLabel + Left = 69 + Top = 71 + Width = 157 + Height = 13 + Alignment = taRightJustify + Caption = #1058#1072#1081#1084#1072#1091#1090' '#1087#1086#1076#1082#1083#1102#1095#1077#1085#1080#1103' '#1082' '#1087#1086#1088#1090#1091 + Transparent = True + end + object lbMiliseconds2: TLabel + Left = 290 + Top = 69 + Width = 27 + Height = 13 + Caption = #1084#1089#1077#1082'.' + Transparent = True + end + object lbScanPingTimeout: TLabel + Left = 107 + Top = 119 + Width = 118 + Height = 13 + Alignment = taRightJustify + Caption = #1058#1072#1081#1084#1072#1091#1090' '#1087#1080#1085#1075'-'#1079#1072#1087#1088#1086#1089#1086#1074 + Transparent = True + end + object lbMiliseconds1: TLabel + Left = 289 + Top = 117 + Width = 27 + Height = 13 + Caption = #1084#1089#1077#1082'.' + Transparent = True + end + object lbDelayBetweenAttempts: TLabel + Left = 80 + Top = 167 + Width = 146 + Height = 13 + Alignment = taRightJustify + Caption = #1047#1072#1076#1077#1088#1078#1082#1072' '#1084#1077#1078#1076#1091' '#1087#1086#1087#1099#1090#1082#1072#1084#1080 + Transparent = True + end + object lbMiliseconds3: TLabel + Left = 290 + Top = 165 + Width = 27 + Height = 13 + Caption = #1084#1089#1077#1082'.' + Transparent = True + end + object lbScanPortionTimeout: TLabel + Left = 88 + Top = 215 + Width = 138 + Height = 13 + Alignment = taRightJustify + Caption = #1047#1072#1076#1077#1088#1078#1082#1072' '#1084#1077#1078#1076#1091' '#1087#1086#1088#1094#1080#1103#1084#1080 + Transparent = True + end + object lbMiliseconds4: TLabel + Left = 290 + Top = 213 + Width = 27 + Height = 13 + Caption = #1084#1089#1077#1082'.' + Transparent = True + end + object cbAutoScanNewNodes: TCheckBox + Left = 13 + Top = 272 + Width = 290 + Height = 17 + Caption = #1040#1074#1090#1086#1084#1072#1090#1080#1095#1077#1089#1082#1080' '#1086#1087#1088#1077#1076#1077#1083#1103#1090#1100' '#1087#1080#1085#1075' '#1080' '#1078#1080#1074#1099#1077' '#1091#1079#1083#1099 + Checked = True + State = cbChecked + TabOrder = 18 + OnClick = cbAutoScanNewNodesClick + end + object cbEnableDetectAliveNodes: TCheckBox + Left = 14 + Top = 21 + Width = 290 + Height = 17 + Caption = #1042#1082#1083#1102#1095#1080#1090#1100' '#1086#1087#1088#1077#1076#1077#1083#1077#1085#1080#1077' '#1078#1080#1074#1099#1093' '#1091#1079#1083#1086#1074 + Checked = True + State = cbChecked + TabOrder = 0 + OnClick = cbEnableDetectAliveNodesClick + end + object cbEnablePingMeasure: TCheckBox + Left = 14 + Top = 44 + Width = 290 + Height = 17 + Caption = #1042#1082#1083#1102#1095#1080#1090#1100' '#1080#1079#1084#1077#1088#1077#1085#1080#1077' '#1087#1080#1085#1075#1072 + Checked = True + State = cbChecked + TabOrder = 1 + OnClick = cbEnablePingMeasureClick + end + object edFullScanInterval: TEdit + Left = 228 + Top = 295 + Width = 42 + Height = 21 + MaxLength = 4 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 19 + Text = '72' + OnChange = EditChange + end + object udFullScanInterval: TUpDown + Left = 270 + Top = 295 + Width = 16 + Height = 21 + Associate = edFullScanInterval + Min = 3 + Max = 720 + Position = 72 + TabOrder = 20 + Thousands = False + OnChanging = SpinChanging + end + object edNonResponsedScanInterval: TEdit + Left = 228 + Top = 319 + Width = 42 + Height = 21 + MaxLength = 5 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 21 + Text = '12' + OnChange = EditChange + end + object udNonResponsedScanInterval: TUpDown + Left = 270 + Top = 319 + Width = 16 + Height = 21 + Associate = edNonResponsedScanInterval + Min = 1 + Max = 360 + Position = 12 + TabOrder = 22 + Thousands = False + OnChanging = SpinChanging + end + object edPartialScansCounts: TEdit + Left = 228 + Top = 343 + Width = 42 + Height = 21 + MaxLength = 5 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 23 + Text = '6' + OnChange = EditChange + end + object udPartialScansCounts: TUpDown + Left = 270 + Top = 343 + Width = 16 + Height = 21 + Associate = edPartialScansCounts + Min = 1 + Max = 24 + Position = 6 + TabOrder = 24 + Thousands = False + OnChanging = SpinChanging + end + object edScanMaxThread: TEdit + Left = 229 + Top = 188 + Width = 42 + Height = 21 + MaxLength = 5 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 12 + Text = '512' + OnChange = EditChange + end + object udScanMaxThread: TUpDown + Left = 271 + Top = 188 + Width = 16 + Height = 21 + Associate = edScanMaxThread + Min = 32 + Max = 65535 + Increment = 32 + Position = 512 + TabOrder = 13 + Thousands = False + OnChanging = SpinChanging + end + object edScanPortAttempts: TEdit + Left = 229 + Top = 92 + Width = 42 + Height = 21 + MaxLength = 2 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 4 + Text = '3' + OnChange = EditChange + end + object udScanPortAttempts: TUpDown + Left = 271 + Top = 92 + Width = 16 + Height = 21 + Associate = edScanPortAttempts + Min = 1 + Max = 32 + Position = 3 + TabOrder = 5 + Thousands = False + OnChanging = SpinChanging + end + object edScanPortionSize: TEdit + Left = 229 + Top = 236 + Width = 42 + Height = 21 + MaxLength = 5 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 16 + Text = '64' + OnChange = EditChange + end + object udScanPortionSize: TUpDown + Left = 271 + Top = 236 + Width = 16 + Height = 21 + Associate = edScanPortionSize + Min = 8 + Max = 65535 + Increment = 8 + Position = 64 + TabOrder = 17 + Thousands = False + OnChanging = SpinChanging + end + object edScanPingAttempts: TEdit + Left = 229 + Top = 140 + Width = 42 + Height = 21 + MaxLength = 2 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 8 + Text = '4' + OnChange = EditChange + end + object udScanPingAttempts: TUpDown + Left = 271 + Top = 140 + Width = 16 + Height = 21 + Associate = edScanPingAttempts + Min = 1 + Max = 32 + Position = 4 + TabOrder = 9 + Thousands = False + OnChanging = SpinChanging + end + object edScanPortTimeout: TEdit + Left = 229 + Top = 68 + Width = 42 + Height = 21 + MaxLength = 5 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 2 + Text = '3000' + OnChange = EditChange + end + object udScanPortTimeout: TUpDown + Left = 271 + Top = 68 + Width = 16 + Height = 21 + Associate = edScanPortTimeout + Min = 1000 + Max = 60000 + Increment = 1000 + Position = 3000 + TabOrder = 3 + Thousands = False + OnChanging = SpinChanging + end + object edScanPingTimeout: TEdit + Left = 229 + Top = 116 + Width = 42 + Height = 21 + MaxLength = 5 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 6 + Text = '2000' + OnChange = EditChange + end + object udScanPingTimeout: TUpDown + Left = 271 + Top = 116 + Width = 16 + Height = 21 + Associate = edScanPingTimeout + Min = 1000 + Max = 60000 + Increment = 1000 + Position = 2000 + TabOrder = 7 + Thousands = False + OnChanging = SpinChanging + end + object edDelayBetweenAttempts: TEdit + Left = 229 + Top = 164 + Width = 42 + Height = 21 + MaxLength = 5 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 10 + Text = '1000' + OnChange = EditChange + end + object udDelayBetweenAttempts: TUpDown + Left = 271 + Top = 164 + Width = 16 + Height = 21 + Associate = edDelayBetweenAttempts + Min = 250 + Max = 60000 + Increment = 250 + Position = 1000 + TabOrder = 11 + Thousands = False + OnChanging = SpinChanging + end + object edScanPortionTimeout: TEdit + Left = 229 + Top = 212 + Width = 42 + Height = 21 + MaxLength = 4 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 14 + Text = '10' + OnChange = EditChange + end + object udScanPortionTimeout: TUpDown + Left = 271 + Top = 212 + Width = 16 + Height = 21 + Associate = edScanPortionTimeout + Min = 1 + Max = 1000 + Position = 10 + TabOrder = 15 + Thousands = False + OnChanging = SpinChanging + end + end + object gbTransports: TGroupBox + Left = 343 + Top = 3 + Width = 365 + Height = 235 + Caption = #1055#1086#1076#1082#1083#1102#1095#1072#1077#1084#1099#1077' '#1090#1088#1072#1085#1089#1087#1086#1088#1090#1099 + TabOrder = 1 + object lbTransports: TLabel + Left = 16 + Top = 132 + Width = 61 + Height = 13 + Alignment = taRightJustify + Caption = #1058#1088#1072#1085#1089#1087#1086#1088#1090#1099 + Enabled = False + Transparent = True + end + object lbTransportsHandler: TLabel + AlignWithMargins = True + Left = 15 + Top = 156 + Width = 62 + Height = 13 + Alignment = taRightJustify + Caption = #1054#1073#1088#1072#1073#1086#1090#1095#1080#1082 + Enabled = False + Transparent = True + end + object lbHandlerParams: TLabel + Left = 20 + Top = 179 + Width = 57 + Height = 13 + Alignment = taRightJustify + Caption = #1055#1072#1088#1072#1084#1077#1090#1088#1099 + Enabled = False + Transparent = True + end + object lbTransportType: TLabel + Left = 236 + Top = 156 + Width = 18 + Height = 13 + Alignment = taRightJustify + Caption = #1058#1080#1087 + Enabled = False + Transparent = True + end + object sgTransports: TStringGrid + Tag = 6 + Left = 12 + Top = 18 + Width = 341 + Height = 108 + ColCount = 4 + DefaultRowHeight = 16 + FixedCols = 0 + RowCount = 2 + Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goDrawFocusSelected, goRowSelect, goThumbTracking] + ParentShowHint = False + PopupMenu = mnTransports + ScrollBars = ssVertical + ShowHint = True + TabOrder = 0 + OnDrawCell = sgTransportsDrawCell + OnKeyDown = sgTransportsKeyDown + OnMouseMove = sgTransportsMouseMove + OnSelectCell = sgTransportsSelectCell + end + object edTransports: TEdit + Tag = 1 + Left = 80 + Top = 129 + Width = 273 + Height = 21 + Enabled = False + PopupMenu = EditMenu + TabOrder = 1 + TextHint = #1057#1087#1080#1089#1086#1082' '#1087#1086#1076#1076#1077#1088#1078#1080#1074#1072#1077#1084#1099#1093' '#1090#1088#1072#1085#1089#1087#1086#1088#1090#1086#1074 + OnChange = edTransportsChange + end + object edTransportsHandler: TEdit + Tag = 2 + Left = 80 + Top = 153 + Width = 140 + Height = 21 + Enabled = False + PopupMenu = EditMenu + TabOrder = 2 + TextHint = #1042#1074#1077#1076#1080#1090#1077' '#1080#1084#1103' '#1092#1072#1081#1083#1072 + OnChange = edTransportsChange + end + object meHandlerParams: TMemo + Tag = 3 + Left = 80 + Top = 177 + Width = 273 + Height = 46 + Enabled = False + PopupMenu = EditMenu + ScrollBars = ssVertical + TabOrder = 4 + WantReturns = False + OnChange = edTransportsChange + OnExit = MemoExit + OnKeyPress = MemoKeyPress + end + object cbxTransportType: TComboBox + Left = 257 + Top = 153 + Width = 96 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + Enabled = False + ItemIndex = 0 + ParentDoubleBuffered = False + TabOrder = 3 + Text = #1050#1083#1080#1077#1085#1090 + OnChange = cbxTransportTypeChange + Items.Strings = ( + #1050#1083#1080#1077#1085#1090 + #1057#1077#1088#1074#1077#1088 + #1057#1086#1074#1084#1077#1097#1105#1085#1085#1099#1081) + end + end + object gbAutoSelectRouters: TGroupBox + Left = 343 + Top = 242 + Width = 365 + Height = 149 + Caption = #1040#1074#1090#1086#1087#1086#1076#1073#1086#1088' '#1088#1086#1091#1090#1077#1088#1086#1074 + TabOrder = 2 + object lbAutoSelEntry: TLabel + Left = 17 + Top = 22 + Width = 45 + Height = 13 + Alignment = taRightJustify + Caption = #1042#1093#1086#1076#1085#1099#1077 + Transparent = True + end + object lbAutoSelMiddle: TLabel + Left = 18 + Top = 45 + Width = 44 + Height = 13 + Alignment = taRightJustify + Caption = #1057#1088#1077#1076#1085#1080#1077 + Transparent = True + end + object lbAutoSelExit: TLabel + Left = 9 + Top = 70 + Width = 53 + Height = 13 + Alignment = taRightJustify + Caption = #1042#1099#1093#1086#1076#1085#1099#1077 + Transparent = True + end + object lbAutoSelMaxPing: TLabel + Left = 38 + Top = 118 + Width = 24 + Height = 13 + Alignment = taRightJustify + Caption = #1055#1080#1085#1075 + Transparent = True + end + object lbAutoSelMinWeight: TLabel + Left = 45 + Top = 94 + Width = 17 + Height = 13 + Alignment = taRightJustify + Caption = #1042#1077#1089 + Transparent = True + end + object lbSpeed5: TLabel + Left = 126 + Top = 94 + Width = 23 + Height = 13 + Caption = #1052#1041'/c' + Transparent = True + end + object lbMiliseconds5: TLabel + Left = 126 + Top = 118 + Width = 27 + Height = 13 + Caption = #1084#1089#1077#1082'.' + Transparent = True + end + object lbCount1: TLabel + Left = 126 + Top = 22 + Width = 18 + Height = 13 + Caption = #1096#1090'.' + Transparent = True + end + object lbCount2: TLabel + Left = 126 + Top = 46 + Width = 18 + Height = 13 + Caption = #1096#1090'.' + Transparent = True + end + object lbCount3: TLabel + Left = 126 + Top = 70 + Width = 18 + Height = 13 + Caption = #1096#1090'.' + Transparent = True + end + object lbAutoSelPriority: TLabel + Left = 161 + Top = 22 + Width = 55 + Height = 13 + Alignment = taRightJustify + Caption = #1055#1088#1080#1086#1088#1080#1090#1077#1090 + Transparent = True + end + object edAutoSelExitCount: TEdit + Left = 65 + Top = 67 + Width = 42 + Height = 21 + MaxLength = 5 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 4 + Text = '40' + OnChange = EditChange + end + object udAutoSelExitCount: TUpDown + Left = 107 + Top = 67 + Width = 16 + Height = 21 + Associate = edAutoSelExitCount + Min = 1 + Max = 65535 + Increment = 10 + Position = 40 + TabOrder = 5 + Thousands = False + OnChanging = SpinChanging + end + object edAutoSelMiddleCount: TEdit + Left = 65 + Top = 43 + Width = 42 + Height = 21 + MaxLength = 5 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 2 + Text = '60' + OnChange = EditChange + end + object udAutoSelMiddleCount: TUpDown + Left = 107 + Top = 43 + Width = 16 + Height = 21 + Associate = edAutoSelMiddleCount + Min = 1 + Max = 65535 + Increment = 10 + Position = 60 + TabOrder = 3 + Thousands = False + OnChanging = SpinChanging + end + object edAutoSelEntryCount: TEdit + Left = 65 + Top = 19 + Width = 42 + Height = 21 + MaxLength = 5 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 0 + Text = '20' + OnChange = EditChange + end + object udAutoSelEntryCount: TUpDown + Left = 107 + Top = 19 + Width = 16 + Height = 21 + Associate = edAutoSelEntryCount + Min = 1 + Max = 65535 + Increment = 10 + Position = 20 + TabOrder = 1 + Thousands = False + OnChanging = SpinChanging + end + object cbAutoSelNodesWithPingOnly: TCheckBox + Left = 161 + Top = 120 + Width = 195 + Height = 17 + Caption = #1058#1086#1083#1100#1082#1086' '#1086#1090#1074#1077#1095#1072#1102#1097#1080#1077' '#1085#1072' '#1087#1080#1085#1075 + Checked = True + State = cbChecked + TabOrder = 15 + OnClick = OptionsChange + end + object cbAutoSelUniqueNodes: TCheckBox + Left = 161 + Top = 82 + Width = 195 + Height = 17 + Caption = #1058#1086#1083#1100#1082#1086' '#1091#1085#1080#1082#1072#1083#1100#1085#1099#1077 + Checked = True + State = cbChecked + TabOrder = 13 + OnClick = OptionsChange + end + object cbAutoSelStableOnly: TCheckBox + Left = 161 + Top = 101 + Width = 195 + Height = 17 + Caption = #1058#1086#1083#1100#1082#1086' '#1089#1090#1072#1073#1080#1083#1100#1085#1099#1077 + TabOrder = 14 + OnClick = OptionsChange + end + object edAutoSelMaxPing: TEdit + Left = 65 + Top = 115 + Width = 42 + Height = 21 + MaxLength = 5 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 8 + Text = '200' + OnChange = EditChange + end + object udAutoSelMaxPing: TUpDown + Left = 107 + Top = 115 + Width = 16 + Height = 21 + Associate = edAutoSelMaxPing + Min = 1 + Max = 60000 + Increment = 50 + Position = 200 + TabOrder = 9 + Thousands = False + OnChanging = SpinChanging + end + object edAutoSelMinWeight: TEdit + Left = 65 + Top = 91 + Width = 42 + Height = 21 + MaxLength = 5 + NumbersOnly = True + ParentShowHint = False + PopupMenu = EditMenu + ShowHint = True + TabOrder = 6 + Text = '10' + OnChange = EditChange + end + object udAutoSelMinWeight: TUpDown + Left = 107 + Top = 91 + Width = 16 + Height = 21 + Associate = edAutoSelMinWeight + Min = 1 + Max = 10240 + Increment = 5 + Position = 10 + TabOrder = 7 + Thousands = False + OnChanging = SpinChanging + end + object cbAutoSelFilterCountriesOnly: TCheckBox + Left = 161 + Top = 63 + Width = 195 + Height = 17 + Caption = #1058#1086#1083#1100#1082#1086' '#1089#1090#1088#1072#1085#1099' '#1080#1079' '#1092#1080#1083#1100#1090#1088#1072 + Checked = True + State = cbChecked + TabOrder = 12 + OnClick = OptionsChange + end + object cbxAutoSelPriority: TComboBox + Left = 219 + Top = 19 + Width = 134 + Height = 21 + AutoDropDown = True + Style = csDropDownList + DoubleBuffered = False + ItemIndex = 0 + ParentDoubleBuffered = False + TabOrder = 10 + Text = #1057#1073#1072#1083#1072#1085#1089#1080#1088#1086#1074#1072#1085#1085#1099#1081 + OnChange = cbxAutoSelPriorityChange + Items.Strings = ( + #1057#1073#1072#1083#1072#1085#1089#1080#1088#1086#1074#1072#1085#1085#1099#1081 + #1042#1077#1089' '#1074' '#1082#1086#1085#1089#1077#1085#1089#1091#1089#1077 + #1055#1080#1085#1075' '#1076#1086' '#1091#1079#1083#1072 + #1057#1083#1091#1095#1072#1081#1085#1099#1081) + end + object cbAutoSelMiddleNodesWithoutDir: TCheckBox + Left = 161 + Top = 44 + Width = 195 + Height = 17 + Caption = #1057#1088#1077#1076#1085#1080#1077' '#1091#1079#1083#1099' '#1073#1077#1079' '#1082#1072#1090#1072#1083#1086#1075#1086#1074 + Checked = True + State = cbChecked + TabOrder = 11 + OnClick = OptionsChange + end + end + end + end + object btnApplyOptions: TButton + Left = 572 + Top = 503 + Width = 72 + Height = 19 + Caption = #1055#1088#1080#1084#1077#1085#1080#1090#1100 + DoubleBuffered = True + ParentDoubleBuffered = False + TabOrder = 6 + OnClick = btnApplyOptionsClick + end + object btnCancelOptions: TButton + Left = 648 + Top = 503 + Width = 72 + Height = 19 + Caption = #1054#1090#1084#1077#1085#1072 + DoubleBuffered = True + ParentDoubleBuffered = False + TabOrder = 7 + OnClick = btnCancelOptionsClick + end + object tiTray: TTrayIcon + Hint = #1055#1072#1085#1077#1083#1100' '#1091#1087#1088#1072#1074#1083#1077#1085#1080#1103' Tor' + Icons = lsTray + PopupMenu = mnTray + Visible = True + OnClick = tiTrayClick + Left = 689 + Top = 320 + end + object mnTray: TPopupMenu + AutoHotkeys = maManual + Images = lsMenus + Left = 273 + Top = 1 + object miChangeCircuit: TMenuItem + Caption = #1057#1084#1077#1085#1080#1090#1100' '#1094#1077#1087#1086#1095#1082#1091 + Enabled = False + ImageIndex = 7 + OnClick = miChangeCircuitClick + end + object miDelimiter5: TMenuItem + Caption = '-' + end + object miSwitchTor: TMenuItem + Caption = #1057#1090#1072#1088#1090 + ImageIndex = 0 + OnClick = miSwitchTorClick + end + object miDelimiter1: TMenuItem + Caption = '-' + end + object miShowStatus: TMenuItem + Caption = #1057#1090#1072#1090#1091#1089 + ImageIndex = 36 + OnClick = miShowStatusClick + end + object miShowCircuits: TMenuItem + Caption = #1062#1077#1087#1086#1095#1082#1080 + ImageIndex = 20 + OnClick = miShowCircuitsClick + end + object miShowRouters: TMenuItem + Caption = #1056#1086#1091#1090#1077#1088#1099 + ImageIndex = 37 + OnClick = miShowRoutersClick + end + object miDelimiter15: TMenuItem + Caption = '-' + end + object miShowOptions: TMenuItem + Caption = #1053#1072#1089#1090#1088#1086#1081#1082#1080 + ImageIndex = 4 + OnClick = miShowOptionsClick + end + object miShowLog: TMenuItem + Caption = #1046#1091#1088#1085#1072#1083 + ImageIndex = 5 + OnClick = miShowLogClick + end + object miDelimiter2: TMenuItem + Caption = '-' + end + object miAbout: TMenuItem + Caption = #1054' '#1087#1088#1086#1075#1088#1072#1084#1084#1077 + ImageIndex = 45 + OnClick = miAboutClick + end + object miExit: TMenuItem + Caption = #1042#1099#1093#1086#1076 + ImageIndex = 6 + OnClick = miExitClick + end + end + object tmUpdateIp: TTimer + Enabled = False + OnTimer = tmUpdateIpTimer + Left = 640 + Top = 97 + end + object mnLog: TPopupMenu + AutoHotkeys = maManual + Images = lsMenus + OnPopup = mnLogPopup + Left = 338 + Top = 1 + object miLogOptions: TMenuItem + Caption = #1053#1072#1089#1090#1088#1086#1081#1082#1080 + ImageIndex = 11 + object miWriteLogFile: TMenuItem + AutoCheck = True + Caption = #1047#1072#1087#1080#1089#1099#1074#1072#1090#1100' '#1074' '#1092#1072#1081#1083 + Checked = True + OnClick = miWriteLogFileClick + end + object miLogSeparate: TMenuItem + Caption = #1056#1072#1079#1076#1077#1083#1077#1085#1080#1077' '#1092#1072#1081#1083#1072' '#1078#1091#1088#1085#1072#1083#1072 + object miLogSeparateNone: TMenuItem + Caption = #1053#1077' '#1088#1072#1079#1076#1077#1083#1103#1090#1100 + RadioItem = True + OnClick = SelectLogSeparater + end + object miLogSeparateMonth: TMenuItem + Tag = 1 + Caption = #1055#1086' '#1084#1077#1089#1103#1094#1072#1084 + Checked = True + RadioItem = True + OnClick = SelectLogSeparater + end + object miLogSeparateDay: TMenuItem + Tag = 2 + Caption = #1055#1086' '#1076#1085#1103#1084 + RadioItem = True + OnClick = SelectLogSeparater + end + end + object miDelimiter59: TMenuItem + Caption = '-' + end + object miAutoClear: TMenuItem + AutoCheck = True + Caption = #1054#1095#1080#1097#1072#1090#1100' '#1087#1088#1080' '#1082#1072#1078#1076#1086#1084' '#1079#1072#1087#1091#1089#1082#1077 + Checked = True + OnClick = miAutoClearClick + end + object miAutoScroll: TMenuItem + AutoCheck = True + Caption = #1040#1074#1090#1086#1084#1072#1090#1080#1095#1077#1089#1082#1072#1103' '#1087#1088#1086#1082#1088#1091#1090#1082#1072 + Checked = True + OnClick = miAutoScrollClick + end + object miScrollBars: TMenuItem + Caption = #1055#1086#1083#1086#1089#1072' '#1087#1088#1086#1082#1088#1091#1090#1082#1080 + object miSbVertical: TMenuItem + Caption = #1042#1077#1088#1090#1080#1082#1072#1083#1100#1085#1072#1103 + Checked = True + RadioItem = True + OnClick = SelectLogScrollbar + end + object miSbHorizontal: TMenuItem + Tag = 1 + Caption = #1043#1086#1088#1080#1079#1086#1085#1090#1072#1083#1100#1085#1072#1103 + RadioItem = True + OnClick = SelectLogScrollbar + end + object miSbBoth: TMenuItem + Tag = 2 + Caption = #1042#1089#1077 + RadioItem = True + OnClick = SelectLogScrollbar + end + object miSbNone: TMenuItem + Tag = 3 + Caption = #1053#1077#1090 + RadioItem = True + OnClick = SelectLogScrollbar + end + end + object miWordWrap: TMenuItem + AutoCheck = True + Caption = #1055#1077#1088#1077#1085#1086#1089' '#1089#1090#1088#1086#1082 + OnClick = miWordWrapClick + end + object miSafeLogging: TMenuItem + AutoCheck = True + Caption = #1057#1082#1088#1099#1074#1072#1090#1100' '#1089#1077#1090#1077#1074#1099#1077' '#1072#1076#1088#1077#1089#1072 + Checked = True + OnClick = miSafeLoggingClick + end + object miLogLevel: TMenuItem + Caption = #1059#1088#1086#1074#1077#1085#1100' '#1078#1091#1088#1085#1072#1083#1080#1088#1086#1074#1072#1085#1080#1103 + object miDebug: TMenuItem + Caption = #1054#1090#1083#1072#1076#1082#1072 + RadioItem = True + OnClick = SetLogLevel + end + object miInfo: TMenuItem + Caption = #1048#1085#1092#1086#1088#1084#1072#1094#1080#1103 + RadioItem = True + OnClick = SetLogLevel + end + object miNotice: TMenuItem + Caption = #1059#1074#1077#1076#1086#1084#1083#1077#1085#1080#1103 + Checked = True + RadioItem = True + OnClick = SetLogLevel + end + object miWarn: TMenuItem + Caption = #1055#1088#1077#1076#1091#1087#1088#1077#1078#1076#1077#1085#1080#1103 + RadioItem = True + OnClick = SetLogLevel + end + object miErr: TMenuItem + Caption = #1054#1096#1080#1073#1082#1080 + RadioItem = True + OnClick = SetLogLevel + end + end + object miDelimiter6: TMenuItem + Caption = '-' + end + object miOpenFileLog: TMenuItem + Caption = #1054#1090#1082#1088#1099#1090#1100' '#1092#1072#1081#1083' '#1078#1091#1088#1085#1072#1083#1072 + ImageIndex = 19 + OnClick = miOpenFileLogClick + end + end + object miDelimiter3: TMenuItem + Caption = '-' + end + object miLogCopy: TMenuItem + Tag = 2 + Caption = #1050#1086#1087#1080#1088#1086#1074#1072#1090#1100 + ImageIndex = 12 + ShortCut = 16451 + OnClick = EditMenuClick + end + object miLogSelectAll: TMenuItem + Tag = 4 + Caption = #1042#1099#1076#1077#1083#1080#1090#1100' '#1074#1089#1105 + ImageIndex = 16 + ShortCut = 16449 + OnClick = EditMenuClick + end + object miLogFind: TMenuItem + Tag = 7 + Caption = #1053#1072#1081#1090#1080'...' + ImageIndex = 55 + ShortCut = 16454 + OnClick = EditMenuClick + end + object miDelimiter4: TMenuItem + Caption = '-' + end + object miLogClear: TMenuItem + Tag = 5 + Caption = #1054#1095#1080#1089#1090#1080#1090#1100 + ImageIndex = 13 + OnClick = EditMenuClick + end + end + object lsFlags: TImageList + ColorDepth = cd24Bit + Height = 13 + Width = 20 + Left = 690 + Top = 98 + end + object lsButtons: TImageList + ColorDepth = cd32Bit + Height = 20 + Width = 20 + Left = 689 + Top = 229 + end + object lsMenus: TImageList + ColorDepth = cd32Bit + Left = 690 + Top = 186 + end + object mnChangeCircuit: TPopupMenu + AutoHotkeys = maManual + Images = lsMenus + OnPopup = mnChangeCircuitPopup + Left = 435 + Top = 1 + object miCacheOperations: TMenuItem + Caption = #1054#1087#1077#1088#1072#1094#1080#1080' '#1089' '#1082#1101#1096#1077#1084 + object miUpdateIpToCountryCache: TMenuItem + Caption = #1054#1073#1085#1086#1074#1080#1090#1100' '#1089#1090#1088#1072#1085#1099' '#1074' '#1089#1077#1090#1077#1074#1086#1084' '#1082#1101#1096#1077 + OnClick = miUpdateIpToCountryCacheClick + end + object miDelimiter46: TMenuItem + Caption = '-' + end + object miClearDNSCache: TMenuItem + Caption = #1054#1095#1080#1089#1090#1080#1090#1100' DNS-'#1082#1101#1096 + OnClick = miClearDNSCacheClick + end + object miClearServerCache: TMenuItem + Caption = #1054#1095#1080#1089#1090#1080#1090#1100' '#1089#1077#1088#1074#1077#1088#1085#1099#1081' '#1082#1101#1096 + OnClick = miClearServerCacheClick + end + object miDelimiter51: TMenuItem + Caption = '-' + end + object miClearBridgeCacheUnnecessary: TMenuItem + Caption = #1054#1095#1080#1089#1090#1080#1090#1100' '#1082#1101#1096' '#1086#1090' '#1085#1077#1085#1091#1078#1085#1099#1093' '#1084#1086#1089#1090#1086#1074 + OnClick = ClearBridgesCache + end + object miClearBridgesCacheAll: TMenuItem + Tag = 1 + Caption = #1054#1095#1080#1089#1090#1080#1090#1100' '#1082#1101#1096' '#1074#1089#1077#1093' '#1084#1086#1089#1090#1086#1074 + OnClick = ClearBridgesCache + end + object miClearPingCache: TMenuItem + Tag = 1 + Caption = #1054#1095#1080#1089#1090#1080#1090#1100' '#1082#1101#1096' '#1087#1080#1085#1075'-'#1079#1072#1087#1088#1086#1089#1086#1074 + OnClick = ClearScannerCacheClick + end + object miClearAliveCache: TMenuItem + Tag = 2 + Caption = #1054#1095#1080#1089#1090#1080#1090#1100' '#1082#1101#1096' '#1078#1080#1074#1099#1093' '#1091#1079#1083#1086#1074 + OnClick = ClearScannerCacheClick + end + object miClearUnusedNetworkCache: TMenuItem + Caption = #1054#1095#1080#1089#1090#1080#1090#1100' '#1085#1077#1080#1089#1087#1086#1083#1100#1079#1091#1077#1084#1099#1081' '#1089#1077#1090#1077#1074#1086#1081' '#1082#1101#1096 + OnClick = miClearUnusedNetworkCacheClick + end + object miDelimiter60: TMenuItem + Caption = '-' + end + object miResetScannerSchedule: TMenuItem + Caption = #1057#1073#1088#1086#1089#1080#1090#1100' '#1088#1072#1089#1087#1080#1089#1072#1085#1080#1077' '#1089#1082#1072#1085#1080#1088#1086#1074#1072#1085#1080#1103' '#1091#1079#1083#1086#1074 + OnClick = miResetScannerScheduleClick + end + object miResetTotalsCounter: TMenuItem + Caption = #1057#1073#1088#1086#1089#1080#1090#1100' '#1089#1095#1105#1090#1095#1080#1082' '#1090#1088#1072#1092#1080#1082#1072 + OnClick = miResetTotalsCounterClick + end + end + object miStartScan: TMenuItem + Caption = #1047#1072#1087#1091#1089#1090#1080#1090#1100' '#1089#1082#1072#1085#1080#1088#1086#1074#1072#1085#1080#1077 + object miScanNewNodes: TMenuItem + Tag = 1 + Caption = #1053#1086#1074#1099#1077' '#1091#1079#1083#1099 + OnClick = StartScannerManual + end + object miScanNonResponsed: TMenuItem + Tag = 2 + Caption = #1053#1077' '#1086#1090#1074#1077#1095#1072#1102#1097#1080#1077' '#1091#1079#1083#1099 + OnClick = StartScannerManual + end + object miScanCachedBridges: TMenuItem + Tag = 3 + Caption = #1050#1101#1096#1080#1088#1086#1074#1072#1085#1085#1099#1077' '#1084#1086#1089#1090#1099 + OnClick = StartScannerManual + end + object miScanAll: TMenuItem + Tag = 4 + Caption = #1042#1089#1077' '#1091#1079#1083#1099 + OnClick = StartScannerManual + end + object miDelimiter47: TMenuItem + Caption = '-' + end + object miManualPingMeasure: TMenuItem + AutoCheck = True + Caption = #1048#1079#1084#1077#1088#1103#1090#1100' '#1087#1080#1085#1075 + Checked = True + OnClick = miManualPingMeasureClick + end + object miManualDetectAliveNodes: TMenuItem + AutoCheck = True + Caption = #1054#1087#1088#1077#1076#1077#1083#1103#1090#1100' '#1078#1080#1074#1099#1077' '#1091#1079#1083#1099 + Checked = True + OnClick = miManualDetectAliveNodesClick + end + object miDelimiter61: TMenuItem + Caption = '-' + end + object miStopScan: TMenuItem + Caption = #1054#1089#1090#1072#1085#1086#1074#1080#1090#1100' '#1089#1082#1072#1085#1080#1088#1086#1074#1072#1085#1080#1077 + OnClick = miStopScanClick + end + end + object miResetGuards: TMenuItem + Caption = #1057#1073#1088#1086#1089#1080#1090#1100' '#1089#1090#1086#1088#1086#1078#1077#1074#1099#1077' '#1091#1079#1083#1099 + object miResetGuardsAll: TMenuItem + Tag = 4 + Caption = #1042#1089#1077' '#1089#1090#1086#1088#1086#1078#1077#1074#1099#1077' '#1091#1079#1083#1099 + OnClick = SetResetGuards + end + object miDelimiter57: TMenuItem + Caption = '-' + end + object miResetGuardsBridges: TMenuItem + Tag = 1 + Caption = #1052#1086#1089#1090#1086#1074#1099#1077' '#1091#1079#1083#1099 + OnClick = SetResetGuards + end + object miResetGuardsRestricted: TMenuItem + Tag = 2 + Caption = #1042#1099#1073#1088#1072#1085#1085#1099#1077' '#1074#1093#1086#1076#1085#1099#1077' '#1091#1079#1083#1099 + OnClick = SetResetGuards + end + object miResetGuardsDefault: TMenuItem + Tag = 3 + Caption = #1042#1093#1086#1076#1085#1099#1077' '#1091#1079#1083#1099' '#1087#1086' '#1091#1084#1086#1083#1095#1072#1085#1080#1102 + OnClick = SetResetGuards + end + end + end + object mnFilter: TPopupMenu + AutoHotkeys = maManual + AutoPopup = False + Images = lsMenus + OnPopup = mnFilterPopup + Left = 306 + Top = 1 + object miStat: TMenuItem + Caption = #1057#1090#1072#1090#1080#1089#1090#1080#1082#1072 + ImageIndex = 24 + object miStatRelays: TMenuItem + Caption = #1042#1089#1077 + OnClick = MetricsInfo + end + object miStatGuards: TMenuItem + Caption = #1057#1090#1086#1088#1086#1078#1077#1074#1099#1077 + Hint = ' flag:guard' + OnClick = MetricsInfo + end + object miStatExit: TMenuItem + Caption = #1042#1099#1093#1086#1076#1085#1099#1077 + Hint = ' flag:exit' + OnClick = MetricsInfo + end + object miDelimiter14: TMenuItem + Caption = '-' + end + object miStatAggregate: TMenuItem + Caption = #1054#1073#1097#1072#1103' '#1087#1086' '#1089#1090#1088#1072#1085#1072#1084 + OnClick = miStatAggregateClick + end + end + object miDelimiter13: TMenuItem + Caption = '-' + end + object miSaveTemplate: TMenuItem + Caption = #1057#1086#1093#1088#1072#1085#1080#1090#1100 + ImageIndex = 14 + OnClick = miSaveTemplateClick + end + object miLoadTemplate: TMenuItem + Caption = #1047#1072#1075#1088#1091#1079#1080#1090#1100 + ImageIndex = 15 + end + object miDeleteTemplate: TMenuItem + Caption = #1059#1076#1072#1083#1080#1090#1100 + ImageIndex = 17 + end + object miDelimiter19: TMenuItem + Caption = '-' + end + object miFilterOptions: TMenuItem + Caption = #1053#1072#1089#1090#1088#1086#1081#1082#1080 + ImageIndex = 11 + object miFilterHideUnused: TMenuItem + AutoCheck = True + Caption = #1057#1082#1088#1099#1090#1100' '#1085#1077#1080#1089#1087#1086#1083#1100#1079#1091#1077#1084#1099#1077' '#1089#1090#1088#1072#1085#1099 + Checked = True + OnClick = miFilterHideUnusedClick + end + object miFilterScrollTop: TMenuItem + AutoCheck = True + Caption = #1055#1088#1086#1082#1088#1091#1095#1080#1074#1072#1090#1100' '#1074#1074#1077#1088#1093' '#1087#1088#1080' '#1089#1086#1088#1090#1080#1088#1086#1074#1082#1077 + Checked = True + OnClick = miFilterScrollTopClick + end + object miFilterSelectRow: TMenuItem + AutoCheck = True + Caption = #1042#1099#1076#1077#1083#1103#1090#1100' '#1074#1089#1077' '#1103#1095#1077#1081#1082#1080' '#1074' '#1089#1090#1088#1086#1082#1077 + Checked = True + OnClick = miFilterSelectRowClick + end + object miDelimiter35: TMenuItem + Caption = '-' + end + object miNotLoadEmptyTplData: TMenuItem + AutoCheck = True + Caption = #1053#1077' '#1079#1072#1075#1088#1091#1078#1072#1090#1100' '#1087#1091#1089#1090#1099#1077' '#1076#1072#1085#1085#1099#1077' '#1096#1072#1073#1083#1086#1085#1072 + OnClick = miNotLoadEmptyTplDataClick + end + object miIgnoreTplLoadParamsOutsideTheFilter: TMenuItem + AutoCheck = True + Caption = #1048#1075#1085#1086#1088#1080#1088#1086#1074#1072#1090#1100' '#1087#1072#1088#1072#1084#1077#1090#1088#1099' '#1079#1072#1075#1088#1091#1079#1082#1080' '#1080#1079' '#1096#1072#1073#1083#1086#1085#1072' '#1074#1085#1077' '#1092#1080#1083#1100#1090#1088#1072 + Checked = True + OnClick = miIgnoreTplLoadParamsOutsideTheFilterClick + end + object miReplaceDisabledFavoritesWithCountries: TMenuItem + AutoCheck = True + Caption = #1047#1072#1084#1077#1085#1103#1090#1100' '#1074#1099#1082#1083#1102#1095#1077#1085#1085#1099#1077' '#1089#1087#1080#1089#1082#1080' '#1091#1079#1083#1086#1074' '#1074#1099#1073#1088#1072#1085#1085#1099#1084#1080' '#1089#1090#1088#1072#1085#1072#1084#1080 + Checked = True + OnClick = OptionsChange + end + object miDelimiter30: TMenuItem + Caption = '-' + end + object miTplSave: TMenuItem + Tag = 4 + Caption = #1057#1086#1093#1088#1072#1085#1103#1090#1100' '#1074' '#1096#1072#1073#1083#1086#1085#1077'..' + ImageIndex = 14 + object miTplSaveCountries: TMenuItem + Tag = 1 + AutoCheck = True + Caption = #1042#1099#1073#1088#1072#1085#1085#1099#1077' '#1089#1090#1088#1072#1085#1099 + Checked = True + OnClick = miTplSaveClick + end + object miTplSaveRouters: TMenuItem + Tag = 2 + AutoCheck = True + Caption = #1048#1079#1073#1088#1072#1085#1085#1099#1077' '#1091#1079#1083#1099 + Checked = True + OnClick = miTplSaveClick + end + object miTplSaveExcludes: TMenuItem + Tag = 4 + AutoCheck = True + Caption = #1047#1072#1087#1088#1077#1097#1105#1085#1085#1099#1077' '#1091#1079#1083#1099 + Checked = True + OnClick = miTplSaveClick + end + object miDelimiter31: TMenuItem + Caption = '-' + end + object miTplSaveSA: TMenuItem + Caption = #1042#1099#1073#1088#1072#1090#1100' '#1074#1089#1077 + ImageIndex = 51 + OnClick = SelectorMenuClick + end + object miTplSaveUA: TMenuItem + Caption = #1057#1085#1103#1090#1100' '#1074#1089#1077 + ImageIndex = 52 + OnClick = SelectorMenuClick + end + end + object miTplLoad: TMenuItem + Tag = 5 + Caption = #1047#1072#1075#1088#1091#1078#1072#1090#1100' '#1080#1079' '#1096#1072#1073#1083#1086#1085#1072'..' + ImageIndex = 15 + object miTplLoadCountries: TMenuItem + Tag = 1 + AutoCheck = True + Caption = #1042#1099#1073#1088#1072#1085#1085#1099#1077' '#1089#1090#1088#1072#1085#1099 + Checked = True + OnClick = miTplLoadClick + end + object miTplLoadRouters: TMenuItem + Tag = 2 + AutoCheck = True + Caption = #1048#1079#1073#1088#1072#1085#1085#1099#1077' '#1091#1079#1083#1099 + Checked = True + OnClick = miTplLoadClick + end + object miTplLoadExcludes: TMenuItem + Tag = 4 + AutoCheck = True + Caption = #1047#1072#1087#1088#1077#1097#1105#1085#1085#1099#1077' '#1091#1079#1083#1099 + Checked = True + OnClick = miTplLoadClick + end + object miDelimiter32: TMenuItem + Caption = '-' + end + object miTplLoadSA: TMenuItem + Caption = #1042#1099#1073#1088#1072#1090#1100' '#1074#1089#1077 + ImageIndex = 51 + OnClick = SelectorMenuClick + end + object miTplLoadUA: TMenuItem + Caption = #1057#1085#1103#1090#1100' '#1074#1089#1077 + ImageIndex = 52 + OnClick = SelectorMenuClick + end + end + end + object miDelimiter7: TMenuItem + Caption = '-' + end + object miClearFilter: TMenuItem + Caption = #1054#1095#1080#1089#1090#1080#1090#1100 + ImageIndex = 13 + object miClearFilterEntry: TMenuItem + Caption = #1042#1093#1086#1076#1085#1099#1077 + ImageIndex = 40 + OnClick = ClearFilterClick + end + object miClearFilterMiddle: TMenuItem + Caption = #1057#1088#1077#1076#1085#1080#1077 + ImageIndex = 41 + OnClick = ClearFilterClick + end + object miClearFilterExit: TMenuItem + Caption = #1042#1099#1093#1086#1076#1085#1099#1077 + ImageIndex = 42 + OnClick = ClearFilterClick + end + object miClearFilterExclude: TMenuItem + Caption = #1047#1072#1087#1088#1077#1097#1105#1085#1085#1099#1077 + ImageIndex = 43 + OnClick = ClearFilterClick + end + object miDelimiter20: TMenuItem + Caption = '-' + end + object miClearFilterAll: TMenuItem + Caption = #1042#1089#1077' '#1074#1099#1073#1088#1072#1085#1085#1099#1077 + ImageIndex = 46 + OnClick = ClearFilterClick + end + end + end + object EditMenu: TPopupMenu + AutoHotkeys = maManual + Images = lsMenus + OnPopup = EditMenuPopup + Left = 370 + Top = 1 + object miGetBridges: TMenuItem + Caption = #1055#1086#1083#1091#1095#1080#1090#1100' '#1084#1086#1089#1090#1099 + ImageIndex = 28 + object miGetBridgesSite: TMenuItem + Caption = #1042#1077#1073'-'#1089#1072#1081#1090 + OnClick = miGetBridgesSiteClick + end + object miGetBridgesTelegram: TMenuItem + Caption = #1058#1077#1083#1077#1075#1088#1072#1084'-'#1082#1072#1085#1072#1083 + OnClick = miGetBridgesTelegramClick + end + object miGetBridgesEmail: TMenuItem + Caption = #1069#1083#1077#1082#1090#1088#1086#1085#1085#1072#1103' '#1087#1086#1095#1090#1072 + OnClick = miGetBridgesEmailClick + end + object miDelimiter54: TMenuItem + Caption = '-' + end + object miPreferWebTelegram: TMenuItem + AutoCheck = True + Caption = #1055#1088#1077#1076#1087#1086#1095#1080#1090#1072#1090#1100' '#1074#1077#1073'-'#1074#1077#1088#1089#1080#1102' '#1058#1077#1083#1077#1075#1088#1072#1084#1072 + Checked = True + OnClick = miPreferWebTelegramClick + end + object miRequestObfuscatedBridges: TMenuItem + AutoCheck = True + Caption = #1047#1072#1087#1088#1072#1096#1080#1074#1072#1090#1100' '#1086#1073#1092#1091#1089#1094#1080#1088#1086#1074#1072#1085#1085#1099#1077' '#1084#1086#1089#1090#1099 + Checked = True + OnClick = miRequestObfuscatedBridgesClick + end + object miRequestIPv6Bridges: TMenuItem + AutoCheck = True + Caption = #1047#1072#1087#1088#1072#1096#1080#1074#1072#1090#1100' IPv6-'#1084#1086#1089#1090#1099 + OnClick = miRequestIPv6BridgesClick + end + end + object miDelimiter10: TMenuItem + Caption = '-' + end + object miCut: TMenuItem + Tag = 1 + Caption = #1042#1099#1088#1077#1079#1072#1090#1100 + ImageIndex = 29 + ShortCut = 16472 + OnClick = EditMenuClick + end + object miCopy: TMenuItem + Tag = 2 + Caption = #1050#1086#1087#1080#1088#1086#1074#1072#1090#1100 + ImageIndex = 12 + ShortCut = 16451 + OnClick = EditMenuClick + end + object miPaste: TMenuItem + Tag = 3 + Caption = #1042#1089#1090#1072#1074#1080#1090#1100 + ImageIndex = 27 + ShortCut = 16470 + OnClick = EditMenuClick + end + object miDelete: TMenuItem + Tag = 6 + Caption = #1059#1076#1072#1083#1080#1090#1100 + ImageIndex = 17 + ShortCut = 4142 + OnClick = EditMenuClick + end + object miDelimiter43: TMenuItem + Caption = '-' + end + object miSelectAll: TMenuItem + Tag = 4 + Caption = #1042#1099#1076#1077#1083#1080#1090#1100' '#1074#1089#1105 + ImageIndex = 16 + ShortCut = 16449 + OnClick = EditMenuClick + end + object miFind: TMenuItem + Tag = 7 + Caption = #1053#1072#1081#1090#1080'...' + ImageIndex = 55 + ShortCut = 16454 + OnClick = EditMenuClick + end + object miDelimiter11: TMenuItem + Caption = '-' + end + object miClear: TMenuItem + Tag = 5 + Caption = #1054#1095#1080#1089#1090#1080#1090#1100 + ImageIndex = 13 + ShortCut = 137 + OnClick = EditMenuClick + end + object miClearBridges: TMenuItem + Caption = #1054#1095#1080#1089#1090#1080#1090#1100 + ImageIndex = 13 + object miClearBridgesAll: TMenuItem + Tag = 5 + Caption = #1042#1089#1077' '#1084#1086#1089#1090#1099 + ImageIndex = 3 + OnClick = EditMenuClick + end + object miDelimiter56: TMenuItem + Caption = '-' + end + object miClearBridgesNotAlive: TMenuItem + Caption = #1053#1077' '#1086#1090#1074#1077#1095#1072#1102#1097#1080#1077' '#1085#1072' '#1089#1086#1077#1076#1080#1085#1077#1085#1080#1103 + ImageIndex = 56 + OnClick = miClearBridgesNotAliveClick + end + object miClearBridgesNonCached: TMenuItem + Caption = #1054#1090#1089#1091#1090#1089#1090#1074#1091#1102#1097#1080#1077' '#1074' '#1082#1101#1096#1077 + ImageIndex = 22 + OnClick = ClearBridgesAvailableCache + end + object miClearBridgesCached: TMenuItem + Tag = 1 + Caption = #1053#1072#1081#1076#1077#1085#1085#1099#1077' '#1074' '#1082#1101#1096#1077 + ImageIndex = 21 + OnClick = ClearBridgesAvailableCache + end + end + end + object mnDetails: TPopupMenu + AutoHotkeys = maManual + AutoPopup = False + Images = lsMenus + OnPopup = mnDetailsPopup + Left = 498 + Top = 1 + object miDetailsUpdateIp: TMenuItem + Caption = #1054#1073#1085#1086#1074#1080#1090#1100 + ImageIndex = 18 + OnClick = miDetailsUpdateIpClick + end + object miDelimiter55: TMenuItem + Caption = '-' + end + object miDetailsCopy: TMenuItem + Caption = #1050#1086#1087#1080#1088#1086#1074#1072#1090#1100 + ImageIndex = 12 + object miDetailsCopyNickname: TMenuItem + Caption = #1053#1080#1082 + ImageIndex = 32 + OnClick = CopyCaptionToClipboard + end + object miDetailsCopyIPv4: TMenuItem + Caption = 'IPv4-'#1072#1076#1088#1077#1089 + ImageIndex = 33 + OnClick = CopyCaptionToClipboard + end + object miDetailsCopyIPv6: TMenuItem + Caption = 'IPv6-'#1072#1076#1088#1077#1089 + ImageIndex = 34 + OnClick = CopyCaptionToClipboard + end + object miDetailsCopyFingerprint: TMenuItem + Caption = #1048#1076#1077#1085#1090#1080#1092#1080#1082#1072#1090#1086#1088 + ImageIndex = 23 + OnClick = CopyCaptionToClipboard + end + object miDelimiter45: TMenuItem + Caption = '-' + end + object miDetailsCopyBridgeIPv4: TMenuItem + Caption = #1052#1086#1089#1090' IPv4' + ImageIndex = 28 + OnClick = CopyCaptionToClipboard + end + object miDetailsCopyBridgeIPv6: TMenuItem + Caption = #1052#1086#1089#1090' IPv4' + ImageIndex = 28 + OnClick = CopyCaptionToClipboard + end + end + object miDetailsAddToNodesList: TMenuItem + Caption = #1048#1079#1084#1077#1085#1080#1090#1100' '#1089#1087#1080#1089#1086#1082' '#1091#1079#1083#1086#1074 + ImageIndex = 31 + end + object miDelimiter16: TMenuItem + Caption = '-' + end + object miDetailsRelayInfo: TMenuItem + Caption = #1048#1085#1092#1086#1088#1084#1072#1094#1080#1103' '#1087#1086' '#1088#1077#1090#1088#1072#1085#1089#1083#1103#1090#1086#1088#1091 + ImageIndex = 35 + OnClick = miDetailsRelayInfoClick + end + object miDelimiter8: TMenuItem + Caption = '-' + end + object miDetailsSelectTemplate: TMenuItem + Caption = #1042#1099#1073#1088#1072#1090#1100' '#1096#1072#1073#1083#1086#1085 + ImageIndex = 26 + end + end + object mnServerInfo: TPopupMenu + AutoHotkeys = maManual + AutoPopup = False + Images = lsMenus + Left = 467 + Top = 1 + object miServerCopy: TMenuItem + Caption = #1050#1086#1087#1080#1088#1086#1074#1072#1090#1100 + ImageIndex = 12 + object miServerCopyIPv4: TMenuItem + Caption = #1042#1085#1077#1096#1085#1080#1081' IPv4-'#1072#1076#1088#1077#1089 + ImageIndex = 33 + OnClick = CopyCaptionToClipboard + end + object miServerCopyIPv6: TMenuItem + Caption = #1042#1085#1077#1096#1085#1080#1081' IPv6-'#1072#1076#1088#1077#1089 + ImageIndex = 34 + OnClick = CopyCaptionToClipboard + end + object miServerCopyFingerprint: TMenuItem + Caption = #1048#1076#1077#1085#1090#1080#1092#1080#1082#1072#1090#1086#1088 + ImageIndex = 23 + OnClick = CopyCaptionToClipboard + end + object miServerCopyBridgeIPv4: TMenuItem + Caption = #1052#1086#1089#1090' IPv4' + ImageIndex = 28 + OnClick = CopyCaptionToClipboard + end + object miServerCopyBridgeIPv6: TMenuItem + Caption = #1052#1086#1089#1090' IPv6' + ImageIndex = 28 + OnClick = CopyCaptionToClipboard + end + end + object miServerInfo: TMenuItem + Caption = #1048#1085#1092#1086#1088#1084#1072#1094#1080#1103' '#1087#1086' '#1088#1077#1090#1088#1072#1085#1089#1083#1103#1090#1086#1088#1091 + ImageIndex = 35 + OnClick = miServerInfoClick + end + end + object mnHs: TPopupMenu + AutoHotkeys = maManual + Images = lsMenus + OnPopup = mnHsPopup + Left = 403 + Top = 1 + object miHsOpenDir: TMenuItem + Caption = #1050#1072#1090#1072#1083#1086#1075' '#1089#1077#1088#1074#1080#1089#1072 + ImageIndex = 39 + Visible = False + OnClick = miHsOpenDirClick + end + object miHsCopy: TMenuItem + Caption = #1050#1086#1087#1080#1088#1086#1074#1072#1090#1100 + ImageIndex = 12 + Visible = False + object miHsCopyOnion: TMenuItem + Caption = 'Onion-'#1072#1076#1088#1077#1089 + ImageIndex = 30 + OnClick = miHsCopyOnionClick + end + end + object miDelimiter12: TMenuItem + Caption = '-' + end + object miHsInsert: TMenuItem + Caption = #1044#1086#1073#1072#1074#1080#1090#1100 + ImageIndex = 19 + OnClick = miHsInsertClick + end + object miHsDelete: TMenuItem + Caption = #1059#1076#1072#1083#1080#1090#1100 + ImageIndex = 17 + OnClick = miHsDeleteClick + end + object miDelimiter9: TMenuItem + Caption = '-' + end + object miHsClear: TMenuItem + Caption = #1054#1095#1080#1089#1090#1080#1090#1100 + ImageIndex = 13 + OnClick = miHsClearClick + end + end + object mnShowNodes: TPopupMenu + Tag = 1 + AutoHotkeys = maManual + Images = lsMenus + OnChange = mnShowNodesChange + OnPopup = mnShowNodesPopup + Left = 241 + Top = 1 + object miShowExit: TMenuItem + Tag = 1 + AutoCheck = True + Caption = #1042#1099#1093#1086#1076#1085#1086#1081 + Checked = True + OnClick = SetRoutersFilter + end + object miShowGuard: TMenuItem + Tag = 2 + AutoCheck = True + Caption = #1057#1090#1086#1088#1086#1078#1077#1074#1086#1081 + Checked = True + OnClick = SetRoutersFilter + end + object miShowOther: TMenuItem + Tag = 8 + AutoCheck = True + Caption = #1054#1073#1099#1095#1085#1099#1081 + OnClick = SetRoutersFilter + end + object miShowAuthority: TMenuItem + Tag = 4 + AutoCheck = True + Caption = #1050#1086#1088#1085#1077#1074#1086#1081 + OnClick = SetRoutersFilter + end + object miShowBridge: TMenuItem + Tag = 16 + AutoCheck = True + Caption = #1050#1101#1096#1080#1088#1086#1074#1072#1085#1085#1099#1081' '#1084#1086#1089#1090 + OnClick = SetRoutersFilter + end + object miDelimiter17: TMenuItem + Caption = '-' + end + object miShowFast: TMenuItem + Tag = 32 + AutoCheck = True + Caption = #1041#1099#1089#1090#1088#1099#1081 + Checked = True + Enabled = False + OnClick = SetRoutersFilter + end + object miShowStable: TMenuItem + Tag = 64 + AutoCheck = True + Caption = #1057#1090#1072#1073#1080#1083#1100#1085#1099#1081 + Checked = True + Enabled = False + OnClick = SetRoutersFilter + end + object miDelimiter18: TMenuItem + Caption = '-' + end + object miShowV2Dir: TMenuItem + Tag = 128 + AutoCheck = True + Caption = #1042#1090#1086#1088#1072#1103' '#1074#1077#1088#1089#1080#1103' '#1082#1072#1090#1072#1083#1086#1075#1072 + Checked = True + OnClick = SetRoutersFilter + end + object miShowHSDir: TMenuItem + Tag = 256 + AutoCheck = True + Caption = #1050#1072#1090#1072#1083#1086#1075' '#1089#1082#1088#1099#1090#1099#1093' '#1089#1077#1088#1074#1080#1089#1086#1074 + OnClick = SetRoutersFilter + end + object miShowDirMirror: TMenuItem + Tag = 1024 + AutoCheck = True + Caption = #1047#1077#1088#1082#1072#1083#1086' '#1082#1072#1090#1072#1083#1086#1075#1072 + OnClick = SetRoutersFilter + end + object miDelimiter49: TMenuItem + Caption = '-' + end + object miShowRecommend: TMenuItem + Tag = 512 + AutoCheck = True + Caption = #1056#1077#1082#1086#1084#1077#1085#1076#1091#1077#1084#1072#1103' '#1074#1077#1088#1089#1080#1103 + Checked = True + OnClick = SetRoutersFilter + end + object miShowAlive: TMenuItem + Tag = 2048 + AutoCheck = True + Caption = #1046#1080#1074#1086#1081' '#1091#1079#1077#1083 + OnClick = SetRoutersFilter + end + object miDelimiter58: TMenuItem + Caption = '-' + end + object miReverseConditions: TMenuItem + Tag = 4096 + AutoCheck = True + Caption = #1054#1073#1088#1072#1090#1080#1090#1100' '#1091#1089#1083#1086#1074#1080#1103' '#1092#1080#1083#1100#1090#1088#1072 + OnClick = SetRoutersFilter + end + object miDelimiter50: TMenuItem + Caption = '-' + end + object miShowNodesUA: TMenuItem + Caption = #1057#1085#1103#1090#1100' '#1074#1089#1077 + ImageIndex = 52 + OnClick = SelectorMenuClick + end + end + object tmConsensus: TTimer + Enabled = False + Interval = 3000 + OnTimer = tmConsensusTimer + Left = 642 + Top = 318 + end + object mnRouters: TPopupMenu + AutoHotkeys = maManual + AutoPopup = False + Images = lsMenus + OnPopup = mnRoutersPopup + Left = 530 + Top = 1 + object miRtResetFilter: TMenuItem + Caption = #1057#1073#1088#1086#1089' '#1092#1080#1083#1100#1090#1088#1086#1074 + ImageIndex = 18 + OnClick = miRtResetFilterClick + end + object miDelimiter25: TMenuItem + Caption = '-' + end + object miRtCopy: TMenuItem + Caption = #1050#1086#1087#1080#1088#1086#1074#1072#1090#1100 + ImageIndex = 12 + object miRtCopyNickname: TMenuItem + Caption = #1053#1080#1082 + ImageIndex = 32 + OnClick = CopyCaptionToClipboard + end + object miRtCopyIPv4: TMenuItem + Caption = 'IPv4-'#1072#1076#1088#1077#1089 + ImageIndex = 33 + OnClick = CopyCaptionToClipboard + end + object miRtCopyIPv6: TMenuItem + Caption = 'IPv6-'#1072#1076#1088#1077#1089 + ImageIndex = 34 + OnClick = CopyCaptionToClipboard + end + object miRtCopyFingerprint: TMenuItem + Caption = #1048#1076#1077#1085#1090#1080#1092#1080#1082#1072#1090#1086#1088 + ImageIndex = 23 + OnClick = CopyCaptionToClipboard + end + object miDelimiter44: TMenuItem + Caption = '-' + end + object miRtCopyBridgeIPv4: TMenuItem + Caption = #1052#1086#1089#1090' IPv4' + ImageIndex = 28 + OnClick = CopyCaptionToClipboard + end + object miRtCopyBridgeIpv6: TMenuItem + Caption = #1052#1086#1089#1090' IPv6' + ImageIndex = 28 + OnClick = CopyCaptionToClipboard + end + end + object miRtAddToNodesList: TMenuItem + Caption = #1048#1079#1084#1077#1085#1080#1090#1100' '#1089#1087#1080#1089#1086#1082' '#1091#1079#1083#1086#1074 + ImageIndex = 31 + end + object miRtSelectAsBridge: TMenuItem + Caption = #1042#1099#1073#1088#1072#1090#1100' '#1074' '#1082#1072#1095#1077#1089#1090#1074#1077' '#1084#1086#1089#1090#1072 + ImageIndex = 28 + object miRtSelectAsBridgeIPv4: TMenuItem + Caption = #1052#1086#1089#1090' IPv4' + ImageIndex = 33 + OnClick = SelectNodeAsBridge + end + object miRtSelectAsBridgeIPv6: TMenuItem + Caption = #1052#1086#1089#1090' IPv6' + ImageIndex = 34 + OnClick = SelectNodeAsBridge + end + object miDelimiter48: TMenuItem + Caption = '-' + end + object miRtDisableBridges: TMenuItem + Caption = #1054#1090#1084#1077#1085#1080#1090#1100' '#1080#1089#1087#1086#1083#1100#1079#1086#1074#1072#1085#1080#1077' '#1084#1086#1089#1090#1086#1074 + ImageIndex = 43 + OnClick = miRtDisableBridgesClick + end + end + object miDelimiter29: TMenuItem + Caption = '-' + end + object miRtRelayInfo: TMenuItem + Caption = #1048#1085#1092#1086#1088#1084#1072#1094#1080#1103' '#1087#1086' '#1088#1077#1090#1088#1072#1085#1089#1083#1103#1090#1086#1088#1091 + ImageIndex = 35 + OnClick = miRtRelayInfoClick + end + object miDelimiter21: TMenuItem + Caption = '-' + end + object miRtFilters: TMenuItem + Tag = 2 + Caption = #1060#1080#1083#1100#1090#1088#1099 + ImageIndex = 8 + object miRtFiltersType: TMenuItem + Tag = 1 + AutoCheck = True + Caption = #1058#1080#1087' '#1091#1079#1083#1072 + Checked = True + OnClick = SetRoutersFilterState + end + object miRtFiltersCountry: TMenuItem + Tag = 2 + AutoCheck = True + Caption = #1057#1090#1088#1072#1085#1072 + Checked = True + OnClick = SetRoutersFilterState + end + object miRtFiltersWeight: TMenuItem + Tag = 4 + AutoCheck = True + Caption = #1042#1077#1089' '#1074' '#1082#1086#1085#1089#1077#1085#1089#1091#1089#1077 + Checked = True + OnClick = SetRoutersFilterState + end + object miRtFiltersQuery: TMenuItem + Tag = 8 + AutoCheck = True + Caption = #1047#1072#1087#1088#1086#1089' '#1087#1086#1083#1100#1079#1086#1074#1072#1090#1077#1083#1103 + Checked = True + OnClick = SetRoutersFilterState + end + object miDelimiter34: TMenuItem + Caption = '-' + end + object miRtFilterSA: TMenuItem + Caption = #1042#1099#1073#1088#1072#1090#1100' '#1074#1089#1077 + ImageIndex = 51 + OnClick = SelectorMenuClick + end + object miRtFilterUA: TMenuItem + Caption = #1057#1085#1103#1090#1100' '#1074#1089#1077 + ImageIndex = 52 + OnClick = SelectorMenuClick + end + end + object miRoutersOptions: TMenuItem + Caption = #1053#1072#1089#1090#1088#1086#1081#1082#1080 + ImageIndex = 11 + object miRoutersScrollTop: TMenuItem + AutoCheck = True + Caption = #1055#1088#1086#1082#1088#1091#1095#1080#1074#1072#1090#1100' '#1074#1074#1077#1088#1093' '#1087#1088#1080' '#1089#1086#1088#1090#1080#1088#1086#1074#1082#1077 + Checked = True + OnClick = miRoutersScrollTopClick + end + object miRoutersSelectRow: TMenuItem + AutoCheck = True + Caption = #1042#1099#1076#1077#1083#1103#1090#1100' '#1074#1089#1077' '#1103#1095#1077#1081#1082#1080' '#1074' '#1089#1090#1088#1086#1082#1077 + Checked = True + OnClick = miRoutersSelectRowClick + end + object miShowFlagsHint: TMenuItem + AutoCheck = True + Caption = #1055#1086#1082#1072#1079#1099#1074#1072#1090#1100' '#1087#1086#1076#1089#1082#1072#1079#1082#1080' '#1092#1083#1072#1075#1086#1074' '#1087#1088#1080' '#1085#1072#1074#1077#1076#1077#1085#1080#1080' '#1084#1099#1096#1080 + Checked = True + OnClick = miShowFlagsHintClick + end + object miDelimiter40: TMenuItem + Caption = '-' + end + object miLoadCachedRoutersOnStartup: TMenuItem + AutoCheck = True + Caption = #1047#1072#1075#1088#1091#1078#1072#1090#1100' '#1088#1086#1091#1090#1077#1088#1099' '#1080#1079' '#1082#1101#1096#1072' '#1087#1088#1080' '#1079#1072#1087#1091#1089#1082#1077 + Checked = True + OnClick = miLoadCachedRoutersOnStartupClick + end + object miDisableSelectionUnSuitableAsBridge: TMenuItem + AutoCheck = True + Caption = #1047#1072#1087#1088#1077#1090#1080#1090#1100' '#1074#1099#1073#1086#1088' '#1074' '#1082#1072#1095#1077#1089#1090#1074#1077' '#1084#1086#1089#1090#1072' '#1085#1077#1087#1086#1076#1093#1086#1076#1103#1097#1080#1093' '#1091#1079#1083#1086#1074 + Checked = True + OnClick = miDisableSelectionUnSuitableAsBridgeClick + end + object miDelimiter62: TMenuItem + Caption = '-' + end + object miConvertNodes: TMenuItem + Caption = #1055#1088#1077#1086#1073#1088#1072#1079#1086#1074#1099#1074#1072#1090#1100' IP, CIDR '#1080' '#1082#1086#1076#1099' '#1089#1090#1088#1072#1085' '#1074' '#1093#1101#1096#1080 + object miEnableConvertNodesOnIncorrectClear: TMenuItem + AutoCheck = True + Caption = #1055#1088#1080' '#1086#1095#1080#1089#1090#1082#1077' '#1085#1077#1087#1088#1072#1074#1080#1083#1100#1085#1099#1093' '#1091#1079#1083#1086#1074 + Checked = True + OnClick = miEnableConvertNodesOnIncorrectClearClick + end + object miEnableConvertNodesOnAddToNodesList: TMenuItem + AutoCheck = True + Caption = #1055#1088#1080' '#1076#1086#1073#1072#1074#1083#1077#1085#1080#1080' '#1074' '#1089#1087#1080#1089#1086#1082' '#1091#1079#1083#1086#1074 + Checked = True + OnClick = miEnableConvertNodesOnAddToNodesListClick + end + object miEnableConvertNodesOnRemoveFromNodesList: TMenuItem + AutoCheck = True + Caption = #1055#1088#1080' '#1091#1076#1072#1083#1077#1085#1080#1080' '#1080#1079' '#1089#1087#1080#1089#1082#1072' '#1091#1079#1083#1086#1074 + Checked = True + OnClick = miEnableConvertNodesOnRemoveFromNodesListClick + end + object miDelimiter63: TMenuItem + Caption = '-' + end + object miConvertIpNodes: TMenuItem + AutoCheck = True + Caption = #1055#1088#1077#1086#1073#1088#1072#1079#1086#1074#1099#1074#1072#1090#1100' IP-'#1072#1076#1088#1077#1089#1072 + Checked = True + OnClick = miConvertIpNodesClick + end + object miConvertCidrNodes: TMenuItem + AutoCheck = True + Caption = #1055#1088#1077#1086#1073#1088#1072#1079#1086#1074#1099#1074#1072#1090#1100' CIDR-'#1084#1072#1089#1082#1080 + Checked = True + OnClick = miConvertCidrNodesClick + end + object miConvertCountryNodes: TMenuItem + AutoCheck = True + Caption = #1055#1088#1077#1086#1073#1088#1072#1079#1086#1074#1099#1074#1072#1090#1100' '#1082#1086#1076#1099' '#1089#1090#1088#1072#1085 + Checked = True + OnClick = miConvertCountryNodesClick + end + object miDelimiter64: TMenuItem + Caption = '-' + end + object miIgnoreConvertExcludeNodes: TMenuItem + AutoCheck = True + Caption = #1048#1089#1082#1083#1102#1095#1080#1090#1100' '#1089#1087#1080#1089#1086#1082' '#1079#1072#1087#1088#1077#1097#1105#1085#1085#1099#1093' '#1091#1079#1083#1086#1074 + Checked = True + OnClick = miIgnoreConvertExcludeNodesClick + end + object miAvoidAddingIncorrectNodes: TMenuItem + AutoCheck = True + Caption = #1048#1079#1073#1077#1075#1072#1090#1100' '#1076#1086#1073#1072#1074#1083#1077#1085#1080#1077' '#1085#1077#1087#1088#1072#1074#1080#1083#1100#1085#1099#1093' '#1091#1079#1083#1086#1074 + Checked = True + OnClick = miAvoidAddingIncorrectNodesClick + end + end + object miDisableFiltersOn: TMenuItem + Caption = #1054#1090#1082#1083#1102#1095#1072#1090#1100' '#1092#1080#1083#1100#1090#1088#1099' '#1087#1088#1080' '#1089#1086#1073#1099#1090#1080#1080 + object miDisableFiltersOnUserQuery: TMenuItem + AutoCheck = True + Caption = #1054#1090#1087#1088#1072#1074#1082#1072' '#1079#1072#1087#1088#1086#1089#1072' '#1087#1086#1083#1100#1079#1086#1074#1072#1090#1077#1083#1103 + Checked = True + OnClick = miDisableFiltersOnUserQueryClick + end + object miDisableFiltersOnAuthorityOrBridge: TMenuItem + AutoCheck = True + Caption = #1042#1099#1073#1086#1088' '#1084#1086#1089#1090#1086#1074' '#1080#1083#1080' '#1082#1086#1088#1085#1077#1074#1099#1093' '#1091#1079#1083#1086#1074 + Checked = True + OnClick = miDisableFiltersOnAuthorityOrBridgeClick + end + end + object miDelimiter26: TMenuItem + Caption = '-' + end + object miRtSaveDefault: TMenuItem + Caption = #1057#1086#1093#1088#1072#1085#1080#1090#1100' '#1082#1072#1082' '#1092#1080#1083#1100#1090#1088' '#1087#1086' '#1091#1084#1086#1083#1095#1072#1085#1080#1102 + ImageIndex = 14 + OnClick = miRtSaveDefaultClick + end + end + object miDelimiter23: TMenuItem + Caption = '-' + end + object miClearRouters: TMenuItem + Caption = #1054#1095#1080#1089#1090#1080#1090#1100 + ImageIndex = 13 + object miClearRoutersEntry: TMenuItem + Caption = #1042#1093#1086#1076#1085#1099#1077 + ImageIndex = 40 + OnClick = ClearRoutersClick + end + object miClearRoutersMiddle: TMenuItem + Caption = #1057#1088#1077#1076#1085#1080#1077 + ImageIndex = 41 + OnClick = ClearRoutersClick + end + object miClearRoutersExit: TMenuItem + Caption = #1042#1099#1093#1086#1076#1085#1099#1077 + ImageIndex = 42 + OnClick = ClearRoutersClick + end + object miClearRoutersExclude: TMenuItem + Caption = #1047#1072#1087#1088#1077#1097#1105#1085#1085#1099#1077 + ImageIndex = 43 + OnClick = ClearRoutersClick + end + object miDelimiter22: TMenuItem + Caption = '-' + end + object miClearRoutersFavorites: TMenuItem + Caption = #1042#1089#1077' '#1080#1079#1073#1088#1072#1085#1085#1099#1077 + ImageIndex = 46 + OnClick = ClearRoutersClick + end + object miClearRoutersIncorrect: TMenuItem + Caption = #1053#1077#1087#1088#1072#1074#1080#1083#1100#1085#1099#1077' '#1091#1079#1083#1099 + ImageIndex = 47 + OnClick = miClearRoutersIncorrectClick + end + object miClearRoutersAbsent: TMenuItem + Caption = #1054#1090#1089#1091#1090#1089#1090#1074#1091#1102#1097#1080#1077' '#1074' '#1082#1086#1085#1089#1077#1085#1089#1091#1089#1077 + ImageIndex = 22 + OnClick = miClearRoutersAbsentClick + end + end + end + object tmCircuits: TTimer + Enabled = False + OnTimer = tmCircuitsTimer + Left = 641 + Top = 185 + end + object mnCircuits: TPopupMenu + AutoHotkeys = maManual + Images = lsMenus + OnPopup = mnCircuitsPopup + Left = 562 + Top = 1 + object miCircuitsDestroy: TMenuItem + Caption = #1059#1085#1080#1095#1090#1086#1078#1080#1090#1100 + ImageIndex = 3 + object miDestroyCircuit: TMenuItem + Caption = #1062#1077#1087#1086#1095#1082#1091 + ShortCut = 46 + OnClick = miDestroyCircuitClick + end + object miDestroyStreams: TMenuItem + Caption = #1057#1086#1077#1076#1080#1085#1077#1085#1080#1103 + ShortCut = 8238 + OnClick = miDestroyStreamsClick + end + object miDelimiter36: TMenuItem + Caption = '-' + end + object miDestroyExitCircuits: TMenuItem + Caption = #1042#1089#1077' '#1074#1099#1093#1086#1076#1085#1099#1077' '#1094#1077#1087#1086#1095#1082#1080 + OnClick = miDestroyExitCircuitsClick + end + end + object miDelimiter39: TMenuItem + Caption = '-' + end + object miCircuitsUpdateNow: TMenuItem + Caption = #1054#1073#1085#1086#1074#1080#1090#1100 + ImageIndex = 18 + ShortCut = 116 + OnClick = miCircuitsUpdateNowClick + end + object miCircuitsSort: TMenuItem + Caption = #1057#1086#1088#1090#1080#1088#1086#1074#1082#1072 + ImageIndex = 10 + object miCircuitsSortID: TMenuItem + Caption = #1044#1072#1090#1072' '#1089#1086#1079#1076#1072#1085#1080#1103 + Checked = True + RadioItem = True + OnClick = SelectCircuitsSort + end + object miCircuitsSortPurpose: TMenuItem + Tag = 1 + Caption = #1053#1072#1079#1085#1072#1095#1077#1085#1080#1077 + RadioItem = True + OnClick = SelectCircuitsSort + end + object miCircuitsSortStreams: TMenuItem + Tag = 2 + Caption = #1057#1086#1077#1076#1080#1085#1077#1085#1080#1103 + RadioItem = True + OnClick = SelectCircuitsSort + end + object miCircuitsSortDL: TMenuItem + Tag = 3 + Caption = #1055#1086#1083#1091#1095#1077#1085#1086 + RadioItem = True + OnClick = SelectCircuitsSort + end + object miCircuitsSortUL: TMenuItem + Tag = 4 + Caption = #1054#1090#1087#1088#1072#1074#1083#1077#1085#1086 + RadioItem = True + OnClick = SelectCircuitsSort + end + end + object miCircuitFilter: TMenuItem + Tag = 3 + Caption = #1060#1080#1083#1100#1090#1088#1099 + ImageIndex = 8 + object miCircOneHop: TMenuItem + Tag = 1 + AutoCheck = True + Caption = #1047#1072#1087#1088#1086#1089' '#1082#1072#1090#1072#1083#1086#1075#1072 + Checked = True + OnClick = SetCircuitsFilter + end + object miCircInternal: TMenuItem + Tag = 2 + AutoCheck = True + Caption = #1042#1085#1091#1090#1088#1077#1085#1085#1080#1081' '#1090#1088#1072#1092#1080#1082 + Checked = True + OnClick = SetCircuitsFilter + end + object miCircExit: TMenuItem + Tag = 4 + AutoCheck = True + Caption = #1042#1099#1093#1086#1076#1085#1086#1081' '#1090#1088#1072#1092#1080#1082 + Checked = True + OnClick = SetCircuitsFilter + end + object miCircHsClientDir: TMenuItem + Tag = 8 + AutoCheck = True + Caption = #1050#1083#1080#1077#1085#1090': '#1047#1072#1087#1088#1086#1089' '#1082#1072#1090#1072#1083#1086#1075#1072 + Checked = True + OnClick = SetCircuitsFilter + end + object miCircHsClientIntro: TMenuItem + Tag = 16 + AutoCheck = True + Caption = #1050#1083#1080#1077#1085#1090': '#1058#1086#1095#1082#1072' '#1074#1093#1086#1076#1072 + Checked = True + OnClick = SetCircuitsFilter + end + object miCircHsClientRend: TMenuItem + Tag = 32 + AutoCheck = True + Caption = #1050#1083#1080#1077#1085#1090': '#1052#1077#1089#1090#1086' '#1074#1089#1090#1088#1077#1095#1080 + Checked = True + OnClick = SetCircuitsFilter + end + object miCircHsServiceDir: TMenuItem + Tag = 64 + AutoCheck = True + Caption = #1057#1077#1088#1074#1080#1089': '#1047#1072#1087#1088#1086#1089' '#1082#1072#1090#1072#1083#1086#1075#1072 + Checked = True + OnClick = SetCircuitsFilter + end + object miCircHsServiceIntro: TMenuItem + Tag = 128 + AutoCheck = True + Caption = #1057#1077#1088#1074#1080#1089': '#1058#1086#1095#1082#1072' '#1074#1093#1086#1076#1072 + Checked = True + OnClick = SetCircuitsFilter + end + object miCircHsServiceRend: TMenuItem + Tag = 256 + AutoCheck = True + Caption = #1057#1077#1088#1074#1080#1089': '#1052#1077#1089#1090#1086' '#1074#1089#1090#1088#1077#1095#1080 + Checked = True + OnClick = SetCircuitsFilter + end + object miCircHsVanguards: TMenuItem + Tag = 512 + AutoCheck = True + Caption = #1040#1074#1072#1085#1075#1072#1088#1076' '#1089#1082#1088#1099#1090#1086#1075#1086' '#1089#1077#1088#1074#1080#1089#1072 + Checked = True + OnClick = SetCircuitsFilter + end + object miCircPathBiasTesting: TMenuItem + Tag = 1024 + AutoCheck = True + Caption = #1055#1088#1086#1074#1077#1088#1082#1072' '#1079#1072#1082#1088#1099#1090#1080#1103' '#1094#1077#1087#1086#1095#1082#1080 + Checked = True + OnClick = SetCircuitsFilter + end + object miCircTesting: TMenuItem + Tag = 2048 + AutoCheck = True + Caption = #1055#1088#1086#1074#1077#1088#1082#1072' '#1076#1086#1089#1090#1091#1087#1085#1086#1089#1090#1080 + Checked = True + OnClick = SetCircuitsFilter + end + object miCircCircuitPadding: TMenuItem + Tag = 4096 + AutoCheck = True + Caption = #1052#1072#1089#1082#1080#1088#1086#1074#1082#1072' '#1074#1088#1077#1084#1077#1085#1080 + Checked = True + OnClick = SetCircuitsFilter + end + object miCircMeasureTimeout: TMenuItem + Tag = 8192 + AutoCheck = True + Caption = #1048#1079#1084#1077#1088#1077#1085#1080#1077' '#1086#1078#1080#1076#1072#1085#1080#1103 + Checked = True + OnClick = SetCircuitsFilter + end + object miCircOther: TMenuItem + Tag = 16384 + AutoCheck = True + Caption = #1044#1088#1091#1075#1086#1077' '#1085#1072#1079#1085#1072#1095#1077#1085#1080#1077 + Checked = True + OnClick = SetCircuitsFilter + end + object miDelimiter33: TMenuItem + Caption = '-' + end + object miCircSA: TMenuItem + Caption = #1042#1099#1073#1088#1072#1090#1100' '#1074#1089#1077 + ImageIndex = 51 + OnClick = SelectorMenuClick + end + object miCircUA: TMenuItem + Caption = #1057#1085#1103#1090#1100' '#1074#1089#1077 + ImageIndex = 52 + OnClick = SelectorMenuClick + end + end + object miDelimiter24: TMenuItem + Caption = '-' + end + object miCircuitOptions: TMenuItem + Caption = #1053#1072#1089#1090#1088#1086#1081#1082#1080 + ImageIndex = 11 + object miHideCircuitsWithoutStreams: TMenuItem + AutoCheck = True + Caption = #1057#1082#1088#1099#1074#1072#1090#1100' '#1094#1077#1087#1086#1095#1082#1080' '#1073#1077#1079' '#1089#1086#1077#1076#1080#1085#1077#1085#1080#1081 + OnClick = miHideCircuitsWithoutStreamsClick + end + object miAlwaysShowExitCircuit: TMenuItem + AutoCheck = True + Caption = #1042#1089#1077#1075#1076#1072' '#1087#1086#1082#1072#1079#1099#1074#1072#1090#1100' '#1074#1099#1093#1086#1076#1085#1091#1102' '#1094#1077#1087#1086#1095#1082#1091 + Checked = True + OnClick = miAlwaysShowExitCircuitClick + end + object miSelectExitCircuitWhetItChanges: TMenuItem + AutoCheck = True + Caption = #1042#1099#1076#1077#1083#1103#1090#1100' '#1074#1099#1093#1086#1076#1085#1091#1102' '#1094#1077#1087#1086#1095#1082#1091' '#1087#1088#1080' '#1077#1105' '#1080#1079#1084#1077#1085#1077#1085#1080#1080 + Checked = True + OnClick = miSelectExitCircuitWhetItChangesClick + end + object miDelimiter38: TMenuItem + Caption = '-' + end + object miShowCircuitsTraffic: TMenuItem + Tag = 1 + AutoCheck = True + Caption = #1055#1086#1082#1072#1079#1099#1074#1072#1090#1100' '#1090#1088#1072#1092#1080#1082' '#1094#1077#1087#1086#1095#1077#1082 + Checked = True + OnClick = ShowTrafficSelect + end + object miShowStreamsTraffic: TMenuItem + Tag = 2 + AutoCheck = True + Caption = #1055#1086#1082#1072#1079#1099#1074#1072#1090#1100' '#1090#1088#1072#1092#1080#1082' '#1089#1086#1077#1076#1080#1085#1077#1085#1080#1081 + Checked = True + OnClick = ShowTrafficSelect + end + object miShowStreamsInfo: TMenuItem + AutoCheck = True + Caption = #1055#1086#1082#1072#1079#1099#1074#1072#1090#1100' '#1087#1086#1076#1088#1086#1073#1085#1086#1089#1090#1080' '#1089#1086#1077#1076#1080#1085#1077#1085#1080#1081 + Checked = True + OnClick = miShowStreamsInfoClick + end + object miDelimiter41: TMenuItem + Caption = '-' + end + object miCircuitsUpdateSpeed: TMenuItem + Caption = #1057#1082#1086#1088#1086#1089#1090#1100' '#1086#1073#1085#1086#1074#1083#1077#1085#1080#1103 + object miCircuitsUpdateHigh: TMenuItem + Tag = 500 + Caption = #1042#1099#1089#1086#1082#1072#1103 + RadioItem = True + OnClick = SetCircuitsUpdateInterval + end + object miCircuitsUpdateNormal: TMenuItem + Tag = 1000 + Caption = #1053#1086#1088#1084#1072#1083#1100#1085#1072#1103 + Checked = True + RadioItem = True + OnClick = SetCircuitsUpdateInterval + end + object miCircuitsUpdateLow: TMenuItem + Tag = 4000 + Caption = #1053#1080#1079#1082#1072#1103 + RadioItem = True + OnClick = SetCircuitsUpdateInterval + end + object miDelimiter37: TMenuItem + Caption = '-' + end + object miCircuitsUpdateManual: TMenuItem + Caption = #1054#1073#1085#1086#1074#1083#1103#1090#1100' '#1074#1088#1091#1095#1085#1091#1102 + RadioItem = True + OnClick = SetCircuitsUpdateInterval + end + end + end + end + object mnStreams: TPopupMenu + AutoHotkeys = maManual + Images = lsMenus + OnPopup = mnStreamsPopup + Left = 595 + Top = 1 + object miStreamsDestroyStream: TMenuItem + Caption = #1059#1085#1080#1095#1090#1086#1078#1080#1090#1100 + ImageIndex = 3 + ShortCut = 46 + OnClick = miStreamsDestroyStreamClick + end + object miDelimiter27: TMenuItem + Caption = '-' + end + object miStreamsOpenInBrowser: TMenuItem + Caption = #1054#1090#1082#1088#1099#1090#1100' '#1074' '#1073#1088#1072#1091#1079#1077#1088#1077 + ImageIndex = 25 + ShortCut = 13 + OnClick = miStreamsOpenInBrowserClick + end + object miStreamsBindToExitNode: TMenuItem + Caption = #1055#1088#1080#1074#1103#1079#1072#1090#1100' '#1082' '#1074#1099#1093#1086#1076#1085#1086#1084#1091' '#1091#1079#1083#1091 + ImageIndex = 21 + end + object miDelimiter28: TMenuItem + Caption = '-' + end + object miStreamsSort: TMenuItem + Caption = #1057#1086#1088#1090#1080#1088#1086#1074#1082#1072 + ImageIndex = 10 + object miStreamsSortID: TMenuItem + Caption = #1044#1072#1090#1072' '#1089#1086#1079#1076#1072#1085#1080#1103 + Checked = True + RadioItem = True + OnClick = SelectStreamsSort + end + object miStreamsSortTarget: TMenuItem + Tag = 1 + Caption = #1062#1077#1083#1077#1074#1086#1081' '#1072#1076#1088#1077#1089 + RadioItem = True + OnClick = SelectStreamsSort + end + object miStreamsSortTrack: TMenuItem + Tag = 2 + Caption = #1055#1088#1080#1074#1103#1079#1082#1072' '#1082' '#1074#1099#1093#1086#1076#1085#1086#1084#1091' '#1091#1079#1083#1091 + RadioItem = True + OnClick = SelectStreamsSort + end + object miStreamsSortStreams: TMenuItem + Tag = 3 + Caption = #1057#1086#1077#1076#1080#1085#1077#1085#1080#1103 + RadioItem = True + OnClick = SelectStreamsSort + end + object miStreamsSortDL: TMenuItem + Tag = 4 + Caption = #1055#1086#1083#1091#1095#1077#1085#1086 + RadioItem = True + OnClick = SelectStreamsSort + end + object miStreamsSortUL: TMenuItem + Tag = 5 + Caption = #1054#1090#1087#1088#1072#1074#1083#1077#1085#1086 + RadioItem = True + OnClick = SelectStreamsSort + end + end + end + object lsTray: TImageList + ColorDepth = cd4Bit + GrayscaleFactor = 255 + Height = 20 + Width = 20 + Left = 689 + Top = 275 + Bitmap = { + 494C010103000800040014001400FFFFFFFF0510FFFFFFFFFFFFFFFF424D7600 + 0000000000007600000028000000500000001400000001000400000000002003 + 0000000000000000000000000000000000000000000000008000008000000080 + 8000800000008000800080800000C0C0C000808080000000FF0000FF000000FF + FF00FF000000FF00FF00FFFF0000FFFFFF000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000000FFFFFFFFFFF + FFFFFFF00BBBBBBBBBBBBBBBBBB00AAAAAAAAAAAAAAAAAA00000000000000000 + 00000F0000000000000000F00B0000000000000000B00A0000000000000000A0 + 000000000000000000000F0000000000000000F00B0000000000000000B00A00 + 00000000000000A0000000000000000000000F0000000000000000F00B000000 + 0000000000B00A0000000000000000A0000000000000000000000F0000000000 + 000000F00B0000000000000000B00A0000000000000000A00000000000000000 + 00000F0000F0000FFFFF00F00B0000B0000BBBBB00B00A0000A0000AAAAA00A0 + 000000000000000000000F0000F0000F000F00F00B0000B0000B000B00B00A00 + 00A0000A000A00A0000000000000000000000F0000F0000F000000F00B0000B0 + 000B000000B00A0000A0000A000000A0000000000000000000000F0000F0000F + 000000F00B0000B0000B000000B00A0000A0000A000000A00000000000000000 + 00000F0000F0000F000000F00B0000B0000B000000B00A0000A0000A000000A0 + 000000000000000000000F0000F0000F000000F00B0000B0000B000000B00A00 + 00A0000A000000A0000000000000000000000F0000F0000F000F00F00B0000B0 + 000B000B00B00A0000A0000A000A00A0000000000000000000000F00FFFFF00F + FFFF00F00B00BBBBB00BBBBB00B00A00AAAAA00AAAAA00A00000000000000000 + 00000F0000000000000000F00B0000000000000000B00A0000000000000000A0 + 000000000000000000000F0000000000000000F00B0000000000000000B00A00 + 00000000000000A0000000000000000000000F0000000000000000F00B000000 + 0000000000B00A0000000000000000A0000000000000000000000F0000000000 + 000000F00B0000000000000000B00A0000000000000000A00000000000000000 + 00000FFFFFFFFFFFFFFFFFF00BBBBBBBBBBBBBBBBBB00AAAAAAAAAAAAAAAAAA0 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000424D3E000000000000003E000000 + 2800000050000000140000000100010000000000F00000000000000000000000 + 000000000000000000000000FFFFFF0000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000} + end + object lsMain: TImageList + ColorDepth = cd32Bit + Left = 690 + Top = 142 + end + object mnStreamsInfo: TPopupMenu + AutoHotkeys = maManual + Images = lsMenus + OnPopup = mnStreamsInfoPopup + Left = 628 + Top = 1 + object miStreamsInfoDestroyStream: TMenuItem + Caption = #1059#1085#1080#1095#1090#1086#1078#1080#1090#1100 + ImageIndex = 3 + ShortCut = 46 + OnClick = miStreamsInfoDestroyStreamClick + end + object miDelimiter42: TMenuItem + Caption = '-' + end + object miStreamsInfoSort: TMenuItem + Caption = #1057#1086#1088#1090#1080#1088#1086#1074#1082#1072 + ImageIndex = 10 + object miStreamsInfoSortID: TMenuItem + Caption = #1044#1072#1090#1072' '#1089#1086#1079#1076#1072#1085#1080#1103 + Checked = True + RadioItem = True + OnClick = SelectStreamsInfoSort + end + object miStreamsInfoSortSource: TMenuItem + Tag = 1 + Caption = #1048#1089#1090#1086#1095#1085#1080#1082 + RadioItem = True + OnClick = SelectStreamsInfoSort + end + object miStreamsInfoSortDest: TMenuItem + Tag = 2 + Caption = #1053#1072#1079#1085#1072#1095#1077#1085#1080#1077 + RadioItem = True + OnClick = SelectStreamsInfoSort + end + object miStreamsInfoSortPurpose: TMenuItem + Tag = 3 + Caption = #1062#1077#1083#1100 + RadioItem = True + OnClick = SelectStreamsInfoSort + end + object miStreamsInfoSortDL: TMenuItem + Tag = 4 + Caption = #1055#1086#1083#1091#1095#1077#1085#1086 + RadioItem = True + OnClick = SelectStreamsInfoSort + end + object miStreamsInfoSortUL: TMenuItem + Tag = 5 + Caption = #1054#1090#1087#1088#1072#1074#1083#1077#1085#1086 + RadioItem = True + OnClick = SelectStreamsInfoSort + end + end + end + object FindDialog: TFindDialog + OnFind = FindDialogFind + Left = 644 + Top = 361 + end + object tmScanner: TTimer + Enabled = False + OnTimer = tmScannerTimer + Left = 642 + Top = 229 + end + object mnTransports: TPopupMenu + AutoHotkeys = maManual + Images = lsMenus + OnPopup = mnTransportsPopup + Left = 660 + Top = 1 + object miTransportsInsert: TMenuItem + Caption = #1044#1086#1073#1072#1074#1080#1090#1100 + ImageIndex = 19 + OnClick = miTransportsInsertClick + end + object miTransportsDelete: TMenuItem + Caption = #1059#1076#1072#1083#1080#1090#1100 + ImageIndex = 17 + OnClick = miTransportsDeleteClick + end + object miDelimiter52: TMenuItem + Caption = '-' + end + object miTransportsOpenDir: TMenuItem + Caption = #1050#1072#1090#1072#1083#1086#1075' '#1090#1088#1072#1085#1089#1087#1086#1088#1090#1086#1074 + ImageIndex = 39 + OnClick = miTransportsOpenDirClick + end + object miTransportsReset: TMenuItem + Caption = #1053#1072#1089#1090#1088#1086#1081#1082#1080' '#1087#1086' '#1091#1084#1086#1083#1095#1072#1085#1080#1102 + ImageIndex = 18 + OnClick = miTransportsResetClick + end + object miDelimiter53: TMenuItem + Caption = '-' + Default = True + end + object miTransportsClear: TMenuItem + Caption = #1054#1095#1080#1089#1090#1080#1090#1100 + ImageIndex = 13 + OnClick = miTransportsClearClick + end + end + object tmSaveTotals: TTimer + Enabled = False + Interval = 2000 + OnTimer = tmSaveTotalsTimer + Left = 641 + Top = 143 + end + object mnTraffic: TPopupMenu + AutoHotkeys = maManual + Left = 693 + Top = 1 + object miTrafficPeriod: TMenuItem + Caption = #1055#1077#1088#1080#1086#1076 + object miPeriod1m: TMenuItem + Caption = '1 '#1084#1080#1085'.' + RadioItem = True + OnClick = SelectTrafficPeriod + end + object miPeriod5m: TMenuItem + Tag = 1 + Caption = '5 '#1084#1080#1085'.' + Checked = True + RadioItem = True + OnClick = SelectTrafficPeriod + end + object miPeriod15m: TMenuItem + Tag = 2 + Caption = '15 '#1084#1080#1085'.' + RadioItem = True + OnClick = SelectTrafficPeriod + end + object miPeriod30m: TMenuItem + Tag = 3 + Caption = '30 '#1084#1080#1085'.' + RadioItem = True + OnClick = SelectTrafficPeriod + end + object miPeriod1h: TMenuItem + Tag = 4 + Caption = '1 '#1095'.' + RadioItem = True + OnClick = SelectTrafficPeriod + end + object miPeriod3h: TMenuItem + Tag = 5 + Caption = '3 '#1095'.' + RadioItem = True + OnClick = SelectTrafficPeriod + end + object miPeriod6h: TMenuItem + Tag = 6 + Caption = '6 '#1095 + RadioItem = True + OnClick = SelectTrafficPeriod + end + object miPeriod12h: TMenuItem + Tag = 7 + Caption = '12 '#1095'.' + RadioItem = True + OnClick = SelectTrafficPeriod + end + object miPeriod24h: TMenuItem + Tag = 8 + Caption = '24 '#1095'.' + RadioItem = True + OnClick = SelectTrafficPeriod + end + end + object miSelectGraph: TMenuItem + Caption = #1055#1086#1082#1072#1079#1099#1074#1072#1090#1100' '#1075#1088#1072#1092#1080#1082#1080 + object miSelectGraphDL: TMenuItem + AutoCheck = True + Caption = #1047#1072#1075#1088#1091#1079#1082#1072 + Checked = True + OnClick = miSelectGraphDLClick + end + object miSelectGraphUL: TMenuItem + AutoCheck = True + Caption = #1054#1090#1087#1088#1072#1074#1082#1072 + Checked = True + OnClick = miSelectGraphULClick + end + end + end + object tmTraffic: TTimer + Enabled = False + OnTimer = tmTrafficTimer + Left = 642 + Top = 274 + end +end diff --git a/source/Main.pas b/source/Main.pas new file mode 100644 index 0000000..cbf8ff7 --- /dev/null +++ b/source/Main.pas @@ -0,0 +1,14765 @@ +unit Main; + +interface + +uses + Winapi.Windows, Winapi.Messages, Winapi.CommCtrl, Winapi.Winsock, Winapi.ShellApi, + Winapi.ShlObj, Winapi.GDIPAPI, Winapi.GDIPOBJ, System.SysUtils, System.IniFiles, + System.Generics.Collections, System.ImageList, System.DateUtils, System.Math, + Vcl.Forms, System.Classes, System.Masks, Vcl.ImgList, Vcl.Controls, Vcl.ExtCtrls, + Vcl.Menus, Vcl.StdCtrls, Vcl.Grids, Vcl.ComCtrls, Vcl.Clipbrd, Vcl.Dialogs, Vcl.Graphics, + Vcl.Themes, Vcl.Buttons, blcksock, dnssend, httpsend, pingsend, synacode, synautil, + ConstData, Functions, Addons, Languages; + +type + TUserGrid = class(TCustomGrid); + + TRouterFlag = (rfAuthority, rfBadExit, rfExit, rfFast, rfGuard, rfHSDir, rfStable, rfV2Dir, rfBridge, rfRelay); + TRouterFlags = set of TRouterFlag; + TRouterInfo = record + Name: string; + IPv4: string; + IPv6: string; + OrPort: Word; + DirPort: Word; + Flags: TRouterFlags; + Version: string; + Bandwidth: Integer; + Params: Byte; + end; + + TSpeedData = record + DL: Integer; + UL: Integer; + end; + + TTransportInfo = record + TransportID: Byte; + BridgeType: TBridgeTypes; + end; + + TBridgeInfo = record + Router: TRouterInfo; + Kind: Byte; + Transport: string; + Params: string; + end; + + TFilterInfo = record + cc: Byte; + Data: TNodeTypes; + end; + + TGeoIpInfo = record + cc: Byte; + ping: Integer; + ports: string; + end; + + TBuildFlag = (bfOneHop, bfInternal, bfNeedCapacity, bfNeedUptime); + TBuildFlags = set of TBuildFlag; + TCircuitInfo = record + BuildFlags: TBuildFlags; + PurposeID: Integer; + Streams: Integer; + Nodes: string; + Date: string; + BytesRead: int64; + BytesWritten: int64; + end; + + TStreamInfo = record + CircuitID: string; + Target: string; + SourceAddr: string; + DestAddr: string; + PurposeID: Integer; + BytesRead: int64; + BytesWritten: int64; + end; + + TReadPipeThread = class(TThread) + public + hStdOut: THandle; + VersionCheck: Boolean; + private + Data: string; + DataSize, dwRead: DWORD; + Buffer: PAnsiChar; + procedure UpdateLog; + procedure UpdateVersionInfo; + protected + procedure Execute; override; + end; + + TSendHttpThread = class(TThread) + protected + procedure Execute; override; + end; + + TDNSSendThread = class(TThread) + private + Temp: string; + procedure UpdateIpStage; + protected + procedure Execute; override; + end; + + TScanThread = class(TThread) + public + sScanPortionSize, sMaxThreads, sAttemptsDelay: Integer; + sMaxPortAttempts, sMaxPingAttempts: Byte; + sScanType: TScanType; + sScanPurpose: TScanPurpose; + sPingTimeout, sPortTimeout, sScanPortionTimeout: Integer; + protected + procedure Execute; override; + end; + + TScanItemThread = class(TThread) + public + IpStr: string; + Port: Word; + MaxPortAttempts, MaxPingAttempts: Byte; + ScanType: TScanType; + PingTimeout, PortTimeout, AttemptsDelay: Integer; + Result: Integer; + protected + procedure Execute; override; + end; + + TConsensusThread = class(TThread) + protected + procedure Execute; override; + end; + + TDescriptorsThread = class(TThread) + protected + procedure Execute; override; + end; + + TControlThread = class(TThread) + private + Socket: TTCPBlockSocket; + StreamStatusID, CircuitStatusID: Integer; + CircuitInfo: TCircuitInfo; + StreamInfo: TStreamInfo; + SendBuffer: string; + Data, AuthParam: string; + Ip, Temp, CircuitID, StreamID: string; + ParseStr: ArrOfStr; + SearchPos, InfoCount: Integer; + CountryCode, IpID: Byte; + procedure GetData; + procedure SendData(cmd: string); + protected + procedure Execute; override; + end; + + TUTF8EncodingNoBOM = class(TUTF8Encoding) + public + function GetPreamble: TBytes; override; + end; + + TPageControl = class(Vcl.ComCtrls.TPageControl) + private + procedure TCMAdjustRect(var Msg: TMessage); message TCM_ADJUSTRECT; + end; + + TTcp = class(TForm) + tiTray: TTrayIcon; + mnTray: TPopupMenu; + miExit: TMenuItem; + tmUpdateIp: TTimer; + miSwitchTor: TMenuItem; + mnLog: TPopupMenu; + miLogClear: TMenuItem; + miAutoScroll: TMenuItem; + miShowOptions: TMenuItem; + miShowLog: TMenuItem; + miDelimiter1: TMenuItem; + miDelimiter2: TMenuItem; + miWriteLogFile: TMenuItem; + miSafeLogging: TMenuItem; + miLogOptions: TMenuItem; + miLogSelectAll: TMenuItem; + miLogCopy: TMenuItem; + miDelimiter3: TMenuItem; + miDelimiter4: TMenuItem; + miLogLevel: TMenuItem; + miDebug: TMenuItem; + miInfo: TMenuItem; + miNotice: TMenuItem; + miWarn: TMenuItem; + miErr: TMenuItem; + miWordWrap: TMenuItem; + miScrollBars: TMenuItem; + miSbVertical: TMenuItem; + miSbHorizontal: TMenuItem; + miSbBoth: TMenuItem; + miSbNone: TMenuItem; + lsFlags: TImageList; + lsButtons: TImageList; + lsMenus: TImageList; + btnCancelOptions: TButton; + miAutoClear: TMenuItem; + miOpenFileLog: TMenuItem; + miDelimiter6: TMenuItem; + miChangeCircuit: TMenuItem; + mnChangeCircuit: TPopupMenu; + miDelimiter5: TMenuItem; + mnFilter: TPopupMenu; + miLoadTemplate: TMenuItem; + miSaveTemplate: TMenuItem; + miDeleteTemplate: TMenuItem; + miDelimiter7: TMenuItem; + miClearFilter: TMenuItem; + miClearFilterAll: TMenuItem; + miClearFilterEntry: TMenuItem; + miClearFilterMiddle: TMenuItem; + miClearDNSCache: TMenuItem; + EditMenu: TPopupMenu; + miCut: TMenuItem; + miCopy: TMenuItem; + miPaste: TMenuItem; + miSelectAll: TMenuItem; + miDelimiter11: TMenuItem; + miClear: TMenuItem; + miDelimiter10: TMenuItem; + miGetBridges: TMenuItem; + btnApplyOptions: TButton; + mnDetails: TPopupMenu; + miDetailsUpdateIp: TMenuItem; + miDetailsCopy: TMenuItem; + miDetailsCopyFingerprint: TMenuItem; + miDetailsCopyIPv4: TMenuItem; + miDetailsSelectTemplate: TMenuItem; + miDelimiter8: TMenuItem; + miDetailsCopyNickname: TMenuItem; + paStatus: TPanel; + gbSpeedGraph: TGroupBox; + miDetailsRelayInfo: TMenuItem; + miDelimiter16: TMenuItem; + gbSession: TGroupBox; + lbSessionDLCaption: TLabel; + lbSessionULCaption: TLabel; + lbSessionDL: TLabel; + lbSessionUL: TLabel; + gbServerInfo: TGroupBox; + lbServerExternalIpCaption: TLabel; + lbFingerprintCaption: TLabel; + miShowStatus: TMenuItem; + mnServerInfo: TPopupMenu; + miServerCopy: TMenuItem; + miServerCopyIPv4: TMenuItem; + miServerCopyFingerprint: TMenuItem; + miDetailsAddToNodesList: TMenuItem; + miServerInfo: TMenuItem; + gbTraffic: TGroupBox; + lbDownloadSpeedCaption: TLabel; + lbUploadSpeedCaption: TLabel; + lbDLSpeed: TLabel; + lbULSpeed: TLabel; + gbMaxTraffic: TGroupBox; + lbMaxDLSpeedCaption: TLabel; + lbMaxULSpeedCaption: TLabel; + lbMaxDLSpeed: TLabel; + lbMaxULSpeed: TLabel; + gbInfo: TGroupBox; + lbClientVersionCaption: TLabel; + lbClientVersion: TLabel; + mnHs: TPopupMenu; + miHsInsert: TMenuItem; + miHsDelete: TMenuItem; + lbUserDirCaption: TLabel; + lbUserDir: TLabel; + lbServerExternalIp: TLabel; + lbFingerprint: TLabel; + miServerCopyBridgeIPv4: TMenuItem; + lbBridgeCaption: TLabel; + lbBridge: TLabel; + miDelimiter9: TMenuItem; + miHsClear: TMenuItem; + miDelimiter12: TMenuItem; + miHsCopy: TMenuItem; + miHsCopyOnion: TMenuItem; + miHsOpenDir: TMenuItem; + miDelimiter13: TMenuItem; + miStat: TMenuItem; + miStatRelays: TMenuItem; + miStatGuards: TMenuItem; + miStatExit: TMenuItem; + miDelimiter14: TMenuItem; + miStatAggregate: TMenuItem; + paRouters: TPanel; + sgRouters: TStringGrid; + miShowRouters: TMenuItem; + miDelimiter15: TMenuItem; + btnShowNodes: TButton; + mnShowNodes: TPopupMenu; + lbRoutersCount: TLabel; + miShowExit: TMenuItem; + miShowGuard: TMenuItem; + miShowStable: TMenuItem; + miShowFast: TMenuItem; + miDelimiter17: TMenuItem; + miDelimiter18: TMenuItem; + miShowV2Dir: TMenuItem; + miShowHSDir: TMenuItem; + miShowOther: TMenuItem; + cbxRoutersCountry: TComboBox; + edRoutersWeight: TEdit; + udRoutersWeight: TUpDown; + lbSpeed3: TLabel; + pcOptions: TPageControl; + tsMain: TTabSheet; + gbProfile: TGroupBox; + lbCreateProfile: TLabel; + btnCreateProfile: TButton; + tsNetwork: TTabSheet; + lbReachableAddresses: TLabel; + lbProxyAddress: TLabel; + lbProxyUser: TLabel; + lbProxyPort: TLabel; + lbProxyPassword: TLabel; + lbProxyType: TLabel; + cbUseReachableAddresses: TCheckBox; + edReachableAddresses: TEdit; + cbUseProxy: TCheckBox; + edProxyAddress: TEdit; + edProxyUser: TEdit; + edProxyPassword: TEdit; + cbxProxyType: TComboBox; + cbUseBridges: TCheckBox; + meBridges: TMemo; + cbxSocksHost: TComboBox; + edProxyPort: TEdit; + udProxyPort: TUpDown; + edSOCKSPort: TEdit; + udSOCKSPort: TUpDown; + cbEnableSocks: TCheckBox; + tsFilter: TTabSheet; + lbFilterMode: TLabel; + cbxFilterMode: TComboBox; + sgFilter: TStringGrid; + tsServer: TTabSheet; + lbORPort: TLabel; + lbNickname: TLabel; + lbServerMode: TLabel; + lbRelayBandwidthRate: TLabel; + lbRelayBandwidthBurst: TLabel; + lbSpeed1: TLabel; + lbSpeed2: TLabel; + lbContactInfo: TLabel; + lbDirPort: TLabel; + lbExitPolicy: TLabel; + lbMaxMemInQueues: TLabel; + lbSizeMb: TLabel; + lbBridgeType: TLabel; + lbNumCPUs: TLabel; + lbTransportPort: TLabel; + imUPnPTest: TImage; + edNickname: TEdit; + cbxServerMode: TComboBox; + cbUseRelayBandwidth: TCheckBox; + edContactInfo: TEdit; + cbxExitPolicyType: TComboBox; + cbUseUPnP: TCheckBox; + cbUseMaxMemInQueues: TCheckBox; + cbxBridgeType: TComboBox; + meExitPolicy: TMemo; + cbUseNumCPUs: TCheckBox; + cbPublishServerDescriptor: TCheckBox; + cbUseDirPort: TCheckBox; + cbDirReqStatistics: TCheckBox; + cbIPv6Exit: TCheckBox; + cbHiddenServiceStatistics: TCheckBox; + edORPort: TEdit; + udORPort: TUpDown; + edDirPort: TEdit; + udDirPort: TUpDown; + edTransportPort: TEdit; + udTransportPort: TUpDown; + edMaxMemInQueues: TEdit; + udMaxMemInQueues: TUpDown; + edNumCPUs: TEdit; + udNumCPUs: TUpDown; + edRelayBandwidthRate: TEdit; + udRelayBandwidthRate: TUpDown; + edRelayBandwidthBurst: TEdit; + udRelayBandwidthBurst: TUpDown; + meMyFamily: TMemo; + tsHs: TTabSheet; + sgHsPorts: TStringGrid; + sgHs: TStringGrid; + gbHsEdit: TGroupBox; + lbHsSocket: TLabel; + lbHsVirtualPort: TLabel; + lbHsVersion: TLabel; + lbHsNumIntroductionPoints: TLabel; + lbRendPostPeriod: TLabel; + lbMinutes: TLabel; + lbHsMaxStreams: TLabel; + lbHsName: TLabel; + cbxHsAddress: TComboBox; + cbxHsVersion: TComboBox; + cbHsMaxStreams: TCheckBox; + edHsName: TEdit; + edHsNumIntroductionPoints: TEdit; + udHsNumIntroductionPoints: TUpDown; + edHsMaxStreams: TEdit; + udHsMaxStreams: TUpDown; + udRendPostPeriod: TUpDown; + edRendPostPeriod: TEdit; + edHsRealPort: TEdit; + udHsRealPort: TUpDown; + edHsVirtualPort: TEdit; + udHsVirtualPort: TUpDown; + tsLists: TTabSheet; + lbSeconds4: TLabel; + lbTotalHosts: TLabel; + lbTrackHostExitsExpire: TLabel; + lbTotalNodesList: TLabel; + meTrackHostExits: TMemo; + cbUseTrackHostExits: TCheckBox; + cbEnableNodesList: TCheckBox; + meNodesList: TMemo; + edTrackHostExitsExpire: TEdit; + udTrackHostExitsExpire: TUpDown; + lbTotalMyFamily: TLabel; + tmConsensus: TTimer; + miFilterOptions: TMenuItem; + miDelimiter19: TMenuItem; + miFilterHideUnused: TMenuItem; + miFilterScrollTop: TMenuItem; + mnRouters: TPopupMenu; + miRtCopy: TMenuItem; + miRtCopyNickname: TMenuItem; + miRtCopyIPv4: TMenuItem; + miRtCopyFingerprint: TMenuItem; + miRtRelayInfo: TMenuItem; + lbFilterCount: TLabel; + lbFilterEntry: TLabel; + lbFilterMiddle: TLabel; + lbFilterExit: TLabel; + miClearFilterExit: TMenuItem; + miDelimiter20: TMenuItem; + lbFavoritesChar: TLabel; + lbFavoritesEntry: TLabel; + lbFavoritesMiddle: TLabel; + lbFavoritesExit: TLabel; + lbExcludeNodes: TLabel; + lbExcludeChar: TLabel; + miDelimiter21: TMenuItem; + miClearRouters: TMenuItem; + miClearRoutersEntry: TMenuItem; + miClearRoutersMiddle: TMenuItem; + miClearRoutersExit: TMenuItem; + miDelimiter22: TMenuItem; + miClearRoutersFavorites: TMenuItem; + miClearRoutersExclude: TMenuItem; + lbNodesListType: TLabel; + cbxNodesListType: TComboBox; + miRtCopyIPv6: TMenuItem; + miDetailsCopyIPv6: TMenuItem; + paCircuits: TPanel; + tmCircuits: TTimer; + mnCircuits: TPopupMenu; + miDestroyCircuit: TMenuItem; + miFilterSelectRow: TMenuItem; + miRoutersOptions: TMenuItem; + miDelimiter23: TMenuItem; + miRoutersSelectRow: TMenuItem; + miRoutersScrollTop: TMenuItem; + sgStreams: TStringGrid; + sgCircuitInfo: TStringGrid; + lbDetailsTime: TLabel; + lbNodesListTypeCaption: TLabel; + sgCircuits: TStringGrid; + miCircuitsDestroy: TMenuItem; + miDestroyStreams: TMenuItem; + miCircuitsSort: TMenuItem; + miCircuitsSortID: TMenuItem; + miCircuitsSortPurpose: TMenuItem; + miCircuitsSortStreams: TMenuItem; + miResetGuards: TMenuItem; + miShowCircuits: TMenuItem; + miCircuitOptions: TMenuItem; + miDelimiter24: TMenuItem; + miShowBridge: TMenuItem; + lbTotalBridges: TLabel; + miRtSaveDefault: TMenuItem; + miRtResetFilter: TMenuItem; + miDelimiter25: TMenuItem; + miDelimiter26: TMenuItem; + lbFavoritesTotal: TLabel; + miRtFilters: TMenuItem; + miRtFiltersType: TMenuItem; + miRtFiltersCountry: TMenuItem; + miRtFiltersWeight: TMenuItem; + miShowAuthority: TMenuItem; + lbPorts: TLabel; + cbDirCache: TCheckBox; + cbListenIPv6: TCheckBox; + cbAssumeReachable: TCheckBox; + lbAddress: TLabel; + cbUseAddress: TCheckBox; + edAddress: TEdit; + lbStatusProxyAddrCaption: TLabel; + lbStatusProxyAddr: TLabel; + miCircuitFilter: TMenuItem; + miCircOneHop: TMenuItem; + miCircInternal: TMenuItem; + miCircExit: TMenuItem; + miCircHsClientDir: TMenuItem; + miCircHsClientIntro: TMenuItem; + miCircHsClientRend: TMenuItem; + miCircHsServiceDir: TMenuItem; + miCircHsServiceIntro: TMenuItem; + miCircHsServiceRend: TMenuItem; + miCircHsVanguards: TMenuItem; + miCircPathBiasTesting: TMenuItem; + miCircTesting: TMenuItem; + miCircCircuitPadding: TMenuItem; + miCircMeasureTimeout: TMenuItem; + miCircOther: TMenuItem; + miHideCircuitsWithoutStreams: TMenuItem; + miAlwaysShowExitCircuit: TMenuItem; + lbCircuitsCount: TLabel; + lbStreamsCount: TLabel; + mnStreams: TPopupMenu; + miStreamsSort: TMenuItem; + miStreamsSortStreams: TMenuItem; + miStreamsSortID: TMenuItem; + miStreamsSortTarget: TMenuItem; + miStreamsDestroyStream: TMenuItem; + miStreamsOpenInBrowser: TMenuItem; + miDelimiter28: TMenuItem; + miDelimiter27: TMenuItem; + miStreamsBindToExitNode: TMenuItem; + cbUseHiddenServiceVanguards: TCheckBox; + lbVanguardLayerType: TLabel; + cbxVanguardLayerType: TComboBox; + miLoadCachedRoutersOnStartup: TMenuItem; + miUpdateIpToCountryCache: TMenuItem; + gbControlAuth: TGroupBox; + lbControlPort: TLabel; + lbAuthMetod: TLabel; + lbControlPassword: TLabel; + imGeneratePassword: TImage; + edControlPort: TEdit; + udControlPort: TUpDown; + cbxAuthMetod: TComboBox; + edControlPassword: TEdit; + gbInterface: TGroupBox; + cbStayOnTop: TCheckBox; + cbShowBalloonOnlyWhenHide: TCheckBox; + cbShowBalloonHint: TCheckBox; + cbMinimizeOnClose: TCheckBox; + cbMinimizeOnStartup: TCheckBox; + cbConnectOnStartup: TCheckBox; + cbRestartOnControlFail: TCheckBox; + cbNoDesktopBorders: TCheckBox; + cbRememberEnlargedPosition: TCheckBox; + gbOptions: TGroupBox; + lbMaxCircuitDirtiness: TLabel; + lbSeconds1: TLabel; + lbCircuitBuildTimeout: TLabel; + lbSeconds2: TLabel; + lbSeconds3: TLabel; + lbNewCircuitPeriod: TLabel; + cbAvoidDiskWrites: TCheckBox; + cbLearnCircuitBuildTimeout: TCheckBox; + cbEnforceDistinctSubnets: TCheckBox; + edMaxCircuitDirtiness: TEdit; + udMaxCircuitDirtiness: TUpDown; + edNewCircuitPeriod: TEdit; + udNewCircuitPeriod: TUpDown; + edCircuitBuildTimeout: TEdit; + udCircuitBuildTimeout: TUpDown; + cbUseOpenDNS: TCheckBox; + cbUseOpenDNSOnlyWhenUnknown: TCheckBox; + miStreamsSortTrack: TMenuItem; + miSelectExitCircuitWhetItChanges: TMenuItem; + lsTray: TImageList; + paButtons: TPanel; + sbShowLog: TSpeedButton; + sbShowOptions: TSpeedButton; + paLog: TPanel; + meLog: TMemo; + sbShowStatus: TSpeedButton; + sbShowCircuits: TSpeedButton; + sbShowRouters: TSpeedButton; + sbDecreaseForm: TSpeedButton; + btnChangeCircuit: TButton; + imExitFlag: TImage; + lbExitCountryCaption: TLabel; + lbExitIpCaption: TLabel; + lbExitIp: TLabel; + lbExitCountry: TLabel; + cbUseNetworkCache: TCheckBox; + lbTheme: TLabel; + cbxThemes: TComboBox; + btnSwitchTor: TButton; + lsMain: TImageList; + lbLanguage: TLabel; + cbxLanguage: TComboBox; + cbUseMyFamily: TCheckBox; + cbxRoutersQuery: TComboBox; + edRoutersQuery: TEdit; + cbxBridgeDistribution: TComboBox; + lbBridgeDistribution: TLabel; + miShowRecommend: TMenuItem; + miAbout: TMenuItem; + miShowDirMirror: TMenuItem; + miRtFiltersQuery: TMenuItem; + miDisableFiltersOnUserQuery: TMenuItem; + miClearRoutersAbsent: TMenuItem; + cbHideIPv6Addreses: TCheckBox; + miClearRoutersIncorrect: TMenuItem; + sgStreamsInfo: TStringGrid; + miDelimiter29: TMenuItem; + miRtAddToNodesList: TMenuItem; + miDelimiter30: TMenuItem; + miTplLoadExcludes: TMenuItem; + miTplLoadCountries: TMenuItem; + miTplLoadRouters: TMenuItem; + miTplSaveCountries: TMenuItem; + miTplSaveRouters: TMenuItem; + miTplSaveExcludes: TMenuItem; + miTplSave: TMenuItem; + miTplLoad: TMenuItem; + miTplSaveSA: TMenuItem; + miDelimiter31: TMenuItem; + miDelimiter32: TMenuItem; + miTplLoadSA: TMenuItem; + miDelimiter33: TMenuItem; + miCircSA: TMenuItem; + miDelimiter34: TMenuItem; + miRtFilterSA: TMenuItem; + miCircUA: TMenuItem; + miTplSaveUA: TMenuItem; + miTplLoadUA: TMenuItem; + miRtFilterUA: TMenuItem; + miIgnoreTplLoadParamsOutsideTheFilter: TMenuItem; + miNotLoadEmptyTplData: TMenuItem; + miDelimiter35: TMenuItem; + miGetBridgesSite: TMenuItem; + miGetBridgesEmail: TMenuItem; + miDelimiter36: TMenuItem; + miDestroyExitCircuits: TMenuItem; + miCircuitsUpdateSpeed: TMenuItem; + miCircuitsUpdateHigh: TMenuItem; + miCircuitsUpdateNormal: TMenuItem; + miCircuitsUpdateLow: TMenuItem; + miDelimiter37: TMenuItem; + miCircuitsUpdateManual: TMenuItem; + miDelimiter38: TMenuItem; + miCircuitsUpdateNow: TMenuItem; + miDelimiter39: TMenuItem; + cbStrictNodes: TCheckBox; + tsOther: TTabSheet; + miReplaceDisabledFavoritesWithCountries: TMenuItem; + miDelimiter40: TMenuItem; + lbULCirc: TLabel; + lbDLCirc: TLabel; + miCircuitsSortDL: TMenuItem; + miCircuitsSortUL: TMenuItem; + miDelimiter41: TMenuItem; + miShowCircuitsTraffic: TMenuItem; + miShowStreamsTraffic: TMenuItem; + mnStreamsInfo: TPopupMenu; + miStreamsInfoDestroyStream: TMenuItem; + miDelimiter42: TMenuItem; + miStreamsInfoSort: TMenuItem; + miStreamsInfoSortID: TMenuItem; + miStreamsInfoSortSource: TMenuItem; + miStreamsInfoSortPurpose: TMenuItem; + miStreamsInfoSortDL: TMenuItem; + miStreamsInfoSortUL: TMenuItem; + miStreamsSortDL: TMenuItem; + miStreamsSortUL: TMenuItem; + miStreamsInfoSortDest: TMenuItem; + miShowStreamsInfo: TMenuItem; + cbNoDesktopBordersOnlyEnlarged: TCheckBox; + lbMaxClientCircuitsPending: TLabel; + edMaxClientCircuitsPending: TEdit; + udMaxClientCircuitsPending: TUpDown; + miDelimiter43: TMenuItem; + miDelete: TMenuItem; + miFind: TMenuItem; + miLogFind: TMenuItem; + FindDialog: TFindDialog; + miRtCopyBridgeIPv4: TMenuItem; + miDetailsCopyBridgeIPv4: TMenuItem; + miDelimiter44: TMenuItem; + miDelimiter45: TMenuItem; + gbNetworkScanner: TGroupBox; + tmScanner: TTimer; + miClearServerCache: TMenuItem; + miDelimiter47: TMenuItem; + miCacheOperations: TMenuItem; + miDelimiter46: TMenuItem; + miShowAlive: TMenuItem; + miDelimiter49: TMenuItem; + miDelimiter50: TMenuItem; + miShowNodesUA: TMenuItem; + miDelimiter51: TMenuItem; + miClearPingCache: TMenuItem; + miClearAliveCache: TMenuItem; + lbFilterExclude: TLabel; + lbStatusScannerCaption: TLabel; + lbStatusScanner: TLabel; + miShowFlagsHint: TMenuItem; + lbHsState: TLabel; + cbxHsState: TComboBox; + gbTransports: TGroupBox; + sgTransports: TStringGrid; + lbTransports: TLabel; + edTransports: TEdit; + lbTransportsHandler: TLabel; + edTransportsHandler: TEdit; + lbHandlerParams: TLabel; + meHandlerParams: TMemo; + mnTransports: TPopupMenu; + miTransportsInsert: TMenuItem; + miTransportsDelete: TMenuItem; + miDelimiter53: TMenuItem; + miTransportsClear: TMenuItem; + miDelimiter52: TMenuItem; + miTransportsOpenDir: TMenuItem; + miTransportsReset: TMenuItem; + lbTransportType: TLabel; + cbxTransportType: TComboBox; + lbBridgesType: TLabel; + cbxBridgesType: TComboBox; + cbxBridgesList: TComboBox; + lbBridgesList: TLabel; + miDelimiter54: TMenuItem; + miRequestIPv6Bridges: TMenuItem; + miRequestObfuscatedBridges: TMenuItem; + miGetBridgesTelegram: TMenuItem; + miPreferWebTelegram: TMenuItem; + miDelimiter55: TMenuItem; + miClearBridgesNotAlive: TMenuItem; + lbScanBridgesStatus: TLabel; + miClearBridges: TMenuItem; + miClearBridgesAll: TMenuItem; + miDelimiter56: TMenuItem; + miClearBridgesNonCached: TMenuItem; + miResetGuardsDefault: TMenuItem; + miResetGuardsAll: TMenuItem; + miDelimiter57: TMenuItem; + miResetGuardsRestricted: TMenuItem; + miResetGuardsBridges: TMenuItem; + cbUsePreferredBridge: TCheckBox; + edPreferredBridge: TEdit; + lbPreferredBridge: TLabel; + cbClearPreviousSearchQuery: TCheckBox; + miRtSelectAsBridge: TMenuItem; + miServerCopyIPv6: TMenuItem; + miServerCopyBridgeIPv6: TMenuItem; + miRtCopyBridgeIpv6: TMenuItem; + miDetailsCopyBridgeIPv6: TMenuItem; + miDisableSelectionUnSuitableAsBridge: TMenuItem; + miRtSelectAsBridgeIPv4: TMenuItem; + miRtSelectAsBridgeIPv6: TMenuItem; + miRtDisableBridges: TMenuItem; + btnFindPreferredBridge: TButton; + miClearBridgesCacheAll: TMenuItem; + lbFullScanInterval: TLabel; + lbHours1: TLabel; + lbNonResponsedScanInterval: TLabel; + lbHours2: TLabel; + cbAutoScanNewNodes: TCheckBox; + cbEnableDetectAliveNodes: TCheckBox; + cbEnablePingMeasure: TCheckBox; + edFullScanInterval: TEdit; + udFullScanInterval: TUpDown; + edNonResponsedScanInterval: TEdit; + udNonResponsedScanInterval: TUpDown; + lbPartialScansCounts: TLabel; + edPartialScansCounts: TEdit; + udPartialScansCounts: TUpDown; + lbScanMaxThread: TLabel; + lbScanPortAttempts: TLabel; + lbScanPortionSize: TLabel; + edScanMaxThread: TEdit; + udScanMaxThread: TUpDown; + edScanPortAttempts: TEdit; + udScanPortAttempts: TUpDown; + edScanPortionSize: TEdit; + udScanPortionSize: TUpDown; + lbScanPingAttempts: TLabel; + edScanPingAttempts: TEdit; + udScanPingAttempts: TUpDown; + lbScanPortTimeout: TLabel; + edScanPortTimeout: TEdit; + udScanPortTimeout: TUpDown; + lbMiliseconds2: TLabel; + lbScanPingTimeout: TLabel; + lbMiliseconds1: TLabel; + edScanPingTimeout: TEdit; + udScanPingTimeout: TUpDown; + lbDelayBetweenAttempts: TLabel; + lbMiliseconds3: TLabel; + edDelayBetweenAttempts: TEdit; + udDelayBetweenAttempts: TUpDown; + lbScanPortionTimeout: TLabel; + edScanPortionTimeout: TEdit; + udScanPortionTimeout: TUpDown; + lbMiliseconds4: TLabel; + miDelimiter48: TMenuItem; + gbTotal: TGroupBox; + lbTotalDLCaption: TLabel; + lbTotalULCaption: TLabel; + lbTotalDL: TLabel; + lbTotalUL: TLabel; + tmSaveTotals: TTimer; + miDelimiter60: TMenuItem; + miResetTotalsCounter: TMenuItem; + miResetScannerSchedule: TMenuItem; + miLogSeparate: TMenuItem; + miDelimiter59: TMenuItem; + miLogSeparateNone: TMenuItem; + miLogSeparateMonth: TMenuItem; + miLogSeparateDay: TMenuItem; + miDelimiter58: TMenuItem; + miReverseConditions: TMenuItem; + miStopScan: TMenuItem; + miStartScan: TMenuItem; + miScanNewNodes: TMenuItem; + miScanCachedBridges: TMenuItem; + miScanNonResponsed: TMenuItem; + miScanAll: TMenuItem; + miManualDetectAliveNodes: TMenuItem; + miManualPingMeasure: TMenuItem; + gbAutoSelectRouters: TGroupBox; + miDelimiter61: TMenuItem; + miClearBridgesCached: TMenuItem; + miClearBridgeCacheUnnecessary: TMenuItem; + miDelimiter62: TMenuItem; + miDisableFiltersOn: TMenuItem; + miDisableFiltersOnAuthorityOrBridge: TMenuItem; + miClearUnusedNetworkCache: TMenuItem; + miClearFilterExclude: TMenuItem; + miConvertNodes: TMenuItem; + miEnableConvertNodesOnIncorrectClear: TMenuItem; + miEnableConvertNodesOnAddToNodesList: TMenuItem; + miDelimiter63: TMenuItem; + miIgnoreConvertExcludeNodes: TMenuItem; + miConvertIpNodes: TMenuItem; + miConvertCidrNodes: TMenuItem; + miConvertCountryNodes: TMenuItem; + miDelimiter64: TMenuItem; + miAvoidAddingIncorrectNodes: TMenuItem; + lbMaxAdvertisedBandwidth: TLabel; + edMaxAdvertisedBandwidth: TEdit; + udMaxAdvertisedBandwidth: TUpDown; + lbSpeed4: TLabel; + edAutoSelExitCount: TEdit; + udAutoSelExitCount: TUpDown; + edAutoSelMiddleCount: TEdit; + udAutoSelMiddleCount: TUpDown; + edAutoSelEntryCount: TEdit; + udAutoSelEntryCount: TUpDown; + lbAutoSelEntry: TLabel; + lbAutoSelMiddle: TLabel; + lbAutoSelExit: TLabel; + miEnableConvertNodesOnRemoveFromNodesList: TMenuItem; + cbAutoSelNodesWithPingOnly: TCheckBox; + cbAutoSelUniqueNodes: TCheckBox; + cbAutoSelStableOnly: TCheckBox; + lbAutoSelMaxPing: TLabel; + lbAutoSelMinWeight: TLabel; + lbSpeed5: TLabel; + lbMiliseconds5: TLabel; + edAutoSelMaxPing: TEdit; + udAutoSelMaxPing: TUpDown; + edAutoSelMinWeight: TEdit; + udAutoSelMinWeight: TUpDown; + lbCount1: TLabel; + lbCount2: TLabel; + lbCount3: TLabel; + cbAutoSelFilterCountriesOnly: TCheckBox; + lbAutoSelPriority: TLabel; + cbxAutoSelPriority: TComboBox; + pbTraffic: TPaintBox; + mnTraffic: TPopupMenu; + miTrafficPeriod: TMenuItem; + miSelectGraph: TMenuItem; + miPeriod1m: TMenuItem; + miPeriod5m: TMenuItem; + miPeriod15m: TMenuItem; + miPeriod30m: TMenuItem; + miPeriod1h: TMenuItem; + miPeriod3h: TMenuItem; + miPeriod6h: TMenuItem; + miPeriod12h: TMenuItem; + miPeriod24h: TMenuItem; + miSelectGraphDL: TMenuItem; + miSelectGraphUL: TMenuItem; + tmTraffic: TTimer; + cbAutoSelMiddleNodesWithoutDir: TCheckBox; + function CheckCacheOpConfirmation(OpStr: string): Boolean; + function CheckVanguards(Silent: Boolean = False): Boolean; + function CheckNetworkOptions: Boolean; + function CheckHsPorts: Boolean; + function CheckHsTable: Boolean; + function CheckTransports: Boolean; + function CheckSimilarPorts: Boolean; + function NodesToFavorites(NodesID: Integer): Integer; + function FavoritesToNodes(FavoritesID: Integer): Integer; + function GetFavoritesLabel(FavoritesID: Integer): TLabel; + function GetFilterLabel(FilterID: Integer): TLabel; + function GetFormPositionStr: string; + function FindTrackHost(Host: string): Boolean; + function FindInRanges(IpStr: string): string; + function RouterInNodesList(RouterID: string; RouterInfo: TRouterInfo; NodeType: TNodeType; SkipCodes: Boolean = False): Boolean; + function GetTrackHostDomains(Host: string; OnlyExists: Boolean): string; + function GetControlEvents: string; + function GetCheckBorders: Boolean; + function GetTorHs: Integer; + function LoadHiddenServices(ini: TMemIniFile): Integer; + function PreferredBridgeFound: Boolean; + function CheckRouterFlags(NodeTypeID: Integer; RouterInfo: TRouterInfo): Boolean; + procedure UpdateBridgesControls(UpdateList: Boolean = True; UpdateUserBridges: Boolean = True); + procedure ShowRoutersParamsHint; + procedure CalculateFilterNodes(AlwaysUpdate: Boolean = True); + procedure CalculateTotalNodes(AlwaysUpdate: Boolean = True); + procedure CloseCircuit(CircuitID: string; AutoUpdate: Boolean = True); + procedure CloseStream(StreamID: string); + procedure CloseStreams(CircuitID: string; FindTarget: Boolean = False; TargetID: string = ''); + procedure CheckOptionsChanged; + procedure LoadNetworkCache; + procedure SaveNetworkCache; + procedure LoadBridgesCache; + procedure SaveBridgesCache; + procedure SetServerPort(PortControl: TUpDown); + procedure SetNodes(FilterEntry, FilterMiddle, FilterExit, FavoritesEntry, FavoritesMiddle, FavoritesExit, ExcludeNodes: string); + procedure ShowFilter; + procedure ApplyOptions(AutoResolveErrors: Boolean = False); + procedure InsertNodesMenu(ParentMenu: TMenuItem; NodeID: string; AutoSave: Boolean = True); + procedure InsertNodesListMenu(ParentMenu: TmenuItem; NodeID: string; NodeTypeID: Integer; AutoSave: Boolean = True); + procedure InsertNodesToDeleteMenu(ParentMenu: TmenuItem; NodeID: string; AutoSave: Boolean = True); + procedure ChangeFilter; + procedure ChangeRouters; + procedure UpdateRoutersAfterFilterUpdate; + procedure UpdateOptionsAfterRoutersUpdate; + procedure UpdateRoutersAfterBridgesUpdate; + procedure SaveRoutersFilterdata(Default: Boolean = False; SaveFilters: Boolean = True); + procedure LoadRoutersFilterData(Data: string; AutoUpdate: Boolean = True; ResetCustomFilter: Boolean = False); + procedure ChangeHsTable(Param: Integer); + procedure ChangeTransportTable(Param: Integer); + procedure LoadOptions; + procedure GetTorVersion; + procedure CheckAuthMetodContols; + procedure CheckAutoSelControls; + procedure CheckFilterMode; + procedure CheckHsVersion; + procedure CheckStatusControls; + procedure CheckOpenPorts(PortSpin: TUpDown; IP: string; var PortStr: string); + procedure CheckServerControls; + procedure CheckScannerControls; + procedure CheckShowRouters; + procedure CheckCachedFiles; + procedure ClearFilter(NodeType: TNodeType; Silent: Boolean = True); + procedure ClearRouters(NodeType: TNodeType; Silent: Boolean = True); + procedure ControlPortConnect; + procedure LogListenerStart(hStdOut: THandle); + procedure CheckVersionStart(hStdOut: THandle); + procedure DecreaseFormSize(AutoRestore: Boolean = True); + procedure ChangeButtonsCaption; + procedure UpdateFormSize; + procedure HsMaxStreamsEnable(State: Boolean); + procedure HsPortsEnable(State: Boolean); + procedure TransportsEnable(State: Boolean); + procedure ServerAddressEnable(State: Boolean); + procedure BridgesCheckControls; + procedure EnableOptionButtons(State: Boolean = True); + procedure FindInFilter(IpAddr: string); + procedure FindInRouters(RouterID: string); + procedure FindInCircuits(CircID, NodeID: string; AutoSelect: Boolean = False); + procedure SendDataThroughProxy; + procedure GetDNSExternalAddress(UpdateExternalIp: Boolean = True); + procedure GetServerInfo(UpdateExternalIp: Boolean = True); + procedure UpdateServerInfo; + procedure IncreaseFormSize; + procedure SetDownState; + procedure InitPortForwarding(Test: Boolean); + procedure ResetFocus; + procedure ScanStart(ScanType: TScanType; ScanPurpose: TScanPurpose); + procedure ScanNetwork(ScanType: TScanType; ScanPurpose: TScanPurpose); + procedure LoadConsensus; + procedure LoadDescriptors; + procedure CheckCountryIndexInList; + procedure CheckNodesListControls; + procedure CheckFavoritesState(FavoritesID: Integer = -1); + procedure LoadNodesList(UseDic: Boolean = True; NodesStr: string = ''); + procedure SaveNodesList(NodesID: Integer); + procedure LoadFilterTotals; + procedure LoadRoutersCountries; + procedure MaxMemInQueuesEnable(State: Boolean); + procedure NumCPUsEnable(State: Boolean); + procedure OpenMetricsUrl(Page, Query: string); + procedure ProxyParamCheck; + procedure RelayBandwidthEnable(State: Boolean); + procedure ReloadTorConfig; + procedure CheckRequiredFiles; + procedure SetIconsColor; + procedure SaveHiddenServices(ini: TMemIniFile); + procedure UpdateConfigVersion; + procedure LoadUserBridges(ini: TMemIniFile); + procedure LoadBuiltinBridges(UpdateBridges, UpdateList: Boolean; ListName: string = ''); + procedure ResetTransports; + procedure LoadTransportsData(Data: TStringList); + procedure LoadUserOverrides; + procedure SaveReachableAddresses(ini: TMemIniFile); + procedure SaveProxyData(ini: TMemIniFile); + procedure SaveTransportsData(ini: TMemIniFile; ReloadServerTransport: Boolean); + procedure SaveBridgesData(ini: TMemIniFile); + procedure SetButtonGlyph(ls: TImageList; Index: Integer; Button: TSpeedButton); + procedure LoadStaticArray(Data: array of TStaticPair); + procedure ResetOptions; + procedure RestartTor(RestartCode: Byte = 0); + procedure RestoreForm; + procedure SelectHs; + procedure SelectHsPorts; + procedure SelectTransports; + procedure CheckStreamsControls; + procedure SendCommand(const cmd: string); + procedure CheckSelectRowOptions(aSg: TStringGrid; Checked: Boolean; Save: Boolean = False); + procedure SetButtonsProp(Btn: TSpeedButton; LeftSmall, LeftBig: Integer); + procedure SetVisible(vOptions, vLog, vStatus, vCircuits, vRouters, vButtons: Boolean); + procedure ShowBalloon(Msg: string; Title: string = ''; Notice: Boolean = False; MsgType: TMsgType = mtInfo); + procedure ShowCircuits; + procedure ShowStreams(CircID: string); + procedure ShowStreamsInfo(CircID, Target: string); + procedure ShowCircuitInfo(CircID: string); + procedure ShowRouters; + procedure CheckNodesListState(NodeTypeID: Integer); + procedure CheckCircuitExists(CircID: string; UpdateStreamsCount: Boolean = False); + procedure CheckCircuitStreams(CircID: string; TargetStreams: Integer); + procedure SelectRowPopup(aSg: TStringGrid; aPopup: TPopupMenu); + procedure SaveTrackHostExits(ini: TMemIniFile; UseDic: Boolean = False); + procedure SaveServerOptions(ini: TMemIniFile); + procedure SetOptionsEnable(State: Boolean); + procedure StartTor(AutoResolveErrors: Boolean = False); + procedure StopTor; + procedure SetSortMenuData(aSg: TStringGrid); + procedure SetCustomFilterStyle(CustomFilterID: Integer); + procedure ResetGuards(GuardType: TGuardType); + procedure MyFamilyEnable(State: Boolean); + procedure TransportPortEnable(State: Boolean); + procedure FastAndStableEnable(State: Boolean; AutoCheck: Boolean = True); + procedure HsControlsEnable(State: Boolean); + procedure CheckLogAutoScroll(AlwaysUpdate: Boolean = False); + procedure UpdateBridgeCopyMenu(Menu: TMenuItem; RouterID: string; Router: TRouterInfo; UseIPv6: Boolean); + procedure UpdateHs; + procedure UpdateHsPorts; + procedure UpdateTransports; + procedure UseDirPortEnable(State: Boolean); + procedure SaveSortData; + procedure UpdateScaleFactor; + procedure CheckTorAutoStart; + procedure CheckPrefferedBridgeExclude(RouterID: string); + function PrepareNodesToRemove(Data: string; NodeType: TNodeType; out Nodes: ArrOfNodes): Boolean; + procedure RemoveFromNodesListWithConvert(Nodes: ArrOfNodes; NodeType: TNodeType); + procedure SortPrepare(aSg: TStringGrid; ACol: Integer; ManualSort: Boolean = False); + procedure GridSort(aSg: TStringGrid); + procedure SelectLogSeparater(Sender: TObject); + procedure SelectLogScrollbar(Sender: TObject); + procedure StartScannerManual(Sender: TObject); + procedure SelectCircuitsSort(Sender: TObject); + procedure ShowTrafficSelect(Sender: TObject); + procedure SelectStreamsSort(Sender: TObject); + procedure SelectStreamsInfoSort(Sender: TObject); + procedure ClearScannerCacheClick(Sender: TObject); + procedure SetLogLevel(Sender: TObject); + procedure EditMenuClick(Sender: TObject); + procedure ConnectOnStartupTimer(Sender: TObject); + procedure CursorStopTimer(Sender: TObject); + procedure RestartTimer(Sender: TObject); + procedure SetCircuitsFilter(Sender: TObject); + procedure RoutersAutoSelectClick(Sender: TObject); + procedure ClearFilterClick(Sender: TObject); + procedure ClearRoutersClick(Sender: TObject); + procedure SetRoutersFilter(Sender: TObject); + procedure SetRoutersFilterState(Sender: TObject); + procedure SetLogScrollBar(ScrollType: Byte; Menu: TMenuItem = nil); + procedure EditMenuPopup(Sender: TObject); + procedure FilterDeleteClick(Sender: TObject); + procedure FilterLoadClick(Sender: TObject); + procedure SelectNodeAsBridge(Sender: TObject); + procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure lbExitCountryDblClick(Sender: TObject); + procedure lbExitMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); + procedure lbServerInfoMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); + procedure EditChange(Sender: TObject); + procedure MemoExit(Sender: TObject); + procedure SpinChanging(Sender: TObject; var AllowChange: Boolean); + procedure SetCircuitsUpdateInterval(Sender: TObject); + procedure MainButtonssMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); + procedure AddToNodesListClick(Sender: TObject); + procedure RemoveFromNodeListClick(Sender: TObject); + procedure ScanThreadTerminate(Sender: TObject); + procedure LogThreadTerminate(Sender: TObject); + procedure VersionCheckerThreadTerminate(Sender: TObject); + procedure ControlThreadTerminate(Sender: TObject); + procedure TConsensusThreadTerminate(Sender: TObject); + procedure TDescriptorsThreadTerminate(Sender: TObject); + procedure btnApplyOptionsClick(Sender: TObject); + procedure btnCancelOptionsClick(Sender: TObject); + procedure btnCreateProfileClick(Sender: TObject); + procedure cbEnableNodesListClick(Sender: TObject); + procedure cbHsMaxStreamsClick(Sender: TObject); + procedure cbLearnCircuitBuildTimeoutClick(Sender: TObject); + procedure cbUseMaxMemInQueuesClick(Sender: TObject); + procedure cbUseNumCPUsClick(Sender: TObject); + procedure cbUseRelayBandwidthClick(Sender: TObject); + procedure cbShowBalloonHintClick(Sender: TObject); + procedure cbStayOnTopClick(Sender: TObject); + procedure cbUseTrackHostExitsClick(Sender: TObject); + procedure cbUseBridgesClick(Sender: TObject); + procedure cbUseDirPortClick(Sender: TObject); + procedure cbUseProxyClick(Sender: TObject); + procedure cbUseUPnPClick(Sender: TObject); + procedure cbxBridgeTypeChange(Sender: TObject); + procedure cbxExitPolicyTypeChange(Sender: TObject); + procedure cbxHsAddressChange(Sender: TObject); + procedure cbxHsVersionChange(Sender: TObject); + procedure cbxProxyTypeChange(Sender: TObject); + procedure cbxServerModeChange(Sender: TObject); + procedure cbxSocksHostDropDown(Sender: TObject); + procedure edHsChange(Sender: TObject); + procedure edTransportsChange(Sender: TObject); + procedure edReachableAddressesKeyPress(Sender: TObject; var Key: Char); + procedure MemoKeyPress(Sender: TObject; var Key: Char); + procedure imGeneratePasswordClick(Sender: TObject); + procedure imUPnPTestClick(Sender: TObject); + procedure lbStatusProxyAddrClick(Sender: TObject); + procedure lbUserDirClick(Sender: TObject); + procedure meNodesListChange(Sender: TObject); + procedure meTrackHostExitsChange(Sender: TObject); + procedure MetricsInfo(Sender: TObject); + procedure miAutoClearClick(Sender: TObject); + procedure miAutoScrollClick(Sender: TObject); + procedure miChangeCircuitClick(Sender: TObject); + procedure miClearDNSCacheClick(Sender: TObject); + procedure miExitClick(Sender: TObject); + procedure miHsDeleteClick(Sender: TObject); + procedure miHsInsertClick(Sender: TObject); + procedure miOpenFileLogClick(Sender: TObject); + procedure miDetailsRelayInfoClick(Sender: TObject); + procedure miSafeLoggingClick(Sender: TObject); + procedure miSaveTemplateClick(Sender: TObject); + procedure miServerInfoClick(Sender: TObject); + procedure miShowLogClick(Sender: TObject); + procedure miShowOptionsClick(Sender: TObject); + procedure miShowStatusClick(Sender: TObject); + procedure miSwitchTorClick(Sender: TObject); + procedure miWordWrapClick(Sender: TObject); + procedure miWriteLogFileClick(Sender: TObject); + procedure mnDetailsPopup(Sender: TObject); + procedure mnFilterPopup(Sender: TObject); + procedure mnHsPopup(Sender: TObject); + procedure mnLogPopup(Sender: TObject); + procedure SelectorMenuClick(Sender: TObject); + procedure sgFilterDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); + procedure sgFilterKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure sgFilterKeyPress(Sender: TObject; var Key: Char); + procedure sgFilterMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure sgHsDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); + procedure sgHsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); + procedure sgHsPortsDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); + procedure sgHsPortsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); + procedure sgHsPortsSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); + procedure sgHsSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); + procedure tiTrayClick(Sender: TObject); + procedure tmUpdateIpTimer(Sender: TObject); + procedure udHsMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure miHsClearClick(Sender: TObject); + procedure edControlPasswordDblClick(Sender: TObject); + procedure miHsCopyOnionClick(Sender: TObject); + procedure miHsOpenDirClick(Sender: TObject); + procedure miStatAggregateClick(Sender: TObject); + procedure sgFilterMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); + procedure sgFilterSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); + procedure cbEnableSocksClick(Sender: TObject); + procedure sgRoutersDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); + procedure miShowRoutersClick(Sender: TObject); + procedure sgRoutersFixedCellClick(Sender: TObject; ACol, ARow: Integer); + procedure btnShowNodesClick(Sender: TObject); + procedure cbeRoutersCountrySelect(Sender: TObject); + procedure cbxRoutersCountryEnter(Sender: TObject); + procedure udRoutersWeightClick(Sender: TObject; Button: TUDBtnType); + procedure edRoutersWeightKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure sgFilterFixedCellClick(Sender: TObject; ACol, ARow: Integer); + procedure tmConsensusTimer(Sender: TObject); + procedure miFilterHideUnusedClick(Sender: TObject); + procedure miFilterScrollTopClick(Sender: TObject); + procedure sgRoutersKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure sgRoutersSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); + procedure sgRoutersMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); + procedure sgRoutersDblClick(Sender: TObject); + procedure CopyCaptionToClipboard(Sender: TObject); + procedure mnRoutersPopup(Sender: TObject); + procedure miRtRelayInfoClick(Sender: TObject); + procedure sgRoutersMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure sgRoutersKeyPress(Sender: TObject; var Key: Char); + procedure paRoutersClick(Sender: TObject); + procedure lbClientVersionClick(Sender: TObject); + procedure meMyFamilyChange(Sender: TObject); + procedure tmCircuitsTimer(Sender: TObject); + procedure sgCircuitsSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); + procedure miFilterSelectRowClick(Sender: TObject); + procedure miRoutersSelectRowClick(Sender: TObject); + procedure miRoutersScrollTopClick(Sender: TObject); + procedure sgCircuitsDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); + procedure sgCircuitsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); + procedure mnCircuitsPopup(Sender: TObject); + procedure sgStreamsDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); + procedure sgCircuitInfoDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); + procedure sgCircuitInfoDblClick(Sender: TObject); + procedure sgCircuitInfoMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); + procedure sgCircuitInfoSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); + procedure sgCircuitsKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure sgStreamsSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); + procedure sgStreamsKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure sgCircuitInfoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure miDestroyCircuitClick(Sender: TObject); + procedure miDestroyStreamsClick(Sender: TObject); + procedure sgCircuitInfoMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure sgCircuitsMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure mnChangeCircuitPopup(Sender: TObject); + procedure sgStreamsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); + procedure miShowCircuitsClick(Sender: TObject); + procedure sgHsKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure sgHsPortsKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure sgHsPortsEnter(Sender: TObject); + procedure sgHsEnter(Sender: TObject); + procedure meBridgesChange(Sender: TObject); + procedure OptionsChange(Sender: TObject); + procedure SetResetGuards(Sender: TObject); + procedure cbxHsAddressDropDown(Sender: TObject); + procedure miRtSaveDefaultClick(Sender: TObject); + procedure miRtResetFilterClick(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure miDetailsUpdateIpClick(Sender: TObject); + procedure ShowFavoritesRouters(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure cbListenIPv6Click(Sender: TObject); + procedure cbDirCacheMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure cbUseAddressClick(Sender: TObject); + procedure cbUseOpenDNSClick(Sender: TObject); + procedure cbUseOpenDNSOnlyWhenUnknownClick(Sender: TObject); + procedure miHideCircuitsWithoutStreamsClick(Sender: TObject); + procedure miAlwaysShowExitCircuitClick(Sender: TObject); + procedure sgStreamsMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure mnStreamsPopup(Sender: TObject); + procedure miStreamsDestroyStreamClick(Sender: TObject); + procedure miStreamsOpenInBrowserClick(Sender: TObject); + procedure BindToExitNodeClick(Sender: TObject); + procedure cbUseHiddenServiceVanguardsClick(Sender: TObject); + procedure miLoadCachedRoutersOnStartupClick(Sender: TObject); + procedure miUpdateIpToCountryCacheClick(Sender: TObject); + procedure pcOptionsChange(Sender: TObject); + procedure cbUseNetworkCacheClick(Sender: TObject); + procedure cbUseReachableAddressesClick(Sender: TObject); + procedure miSelectExitCircuitWhetItChangesClick(Sender: TObject); + procedure sgStreamsFixedCellClick(Sender: TObject; ACol, ARow: Integer); + procedure sgCircuitsFixedCellClick(Sender: TObject; ACol, ARow: Integer); + procedure sbShowOptionsClick(Sender: TObject); + procedure sbShowLogClick(Sender: TObject); + procedure sbShowStatusClick(Sender: TObject); + procedure sbShowCircuitsClick(Sender: TObject); + procedure sbShowRoutersClick(Sender: TObject); + procedure sbShowCircuitsMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure paButtonsDblClick(Sender: TObject); + procedure cbxThemesDropDown(Sender: TObject); + procedure FormResize(Sender: TObject); + procedure btnSwitchTorClick(Sender: TObject); + procedure sbDecreaseFormClick(Sender: TObject); + procedure cbUseMyFamilyClick(Sender: TObject); + procedure lbExitIpMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure cbxRoutersCountryDropDown(Sender: TObject); + procedure edRoutersQueryKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure miAboutClick(Sender: TObject); + procedure meNodesListExit(Sender: TObject); + procedure cbxAuthMetodChange(Sender: TObject); + procedure cbxThemesChange(Sender: TObject); + procedure cbxRoutersCountryChange(Sender: TObject); + procedure cbxRoutersQueryChange(Sender: TObject); + procedure cbxNodesListTypeChange(Sender: TObject); + procedure miClearRoutersAbsentClick(Sender: TObject); + procedure sgFilterExit(Sender: TObject); + procedure miClearRoutersIncorrectClick(Sender: TObject); + procedure sbShowRoutersMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure sgStreamsInfoSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); + procedure sgStreamsInfoMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); + procedure sgStreamsInfoMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure sgStreamsInfoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure miTplSaveClick(Sender: TObject); + procedure miTplLoadClick(Sender: TObject); + procedure mnShowNodesChange(Sender: TObject; Source: TMenuItem; Rebuild: Boolean); + procedure miIgnoreTplLoadParamsOutsideTheFilterClick(Sender: TObject); + procedure miNotLoadEmptyTplDataClick(Sender: TObject); + procedure sbShowOptionsMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure miGetBridgesSiteClick(Sender: TObject); + procedure miGetBridgesEmailClick(Sender: TObject); + procedure miDestroyExitCircuitsClick(Sender: TObject); + procedure miCircuitsUpdateNowClick(Sender: TObject); + procedure sgStreamsInfoDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); + procedure sgStreamsInfoFixedCellClick(Sender: TObject; ACol, ARow: Integer); + procedure miStreamsInfoDestroyStreamClick(Sender: TObject); + procedure mnStreamsInfoPopup(Sender: TObject); + procedure miShowStreamsInfoClick(Sender: TObject); + procedure cbNoDesktopBordersClick(Sender: TObject); + procedure FindDialogFind(Sender: TObject); + procedure sgStreamsDblClick(Sender: TObject); + procedure tmScannerTimer(Sender: TObject); + procedure cbEnablePingMeasureClick(Sender: TObject); + procedure cbEnableDetectAliveNodesClick(Sender: TObject); + procedure miClearServerCacheClick(Sender: TObject); + procedure mnShowNodesPopup(Sender: TObject); + procedure cbAutoScanNewNodesClick(Sender: TObject); + procedure edRoutersQueryChange(Sender: TObject); + procedure miShowFlagsHintClick(Sender: TObject); + procedure cbxHsStateChange(Sender: TObject); + procedure sgTransportsDrawCell(Sender: TObject; ACol, ARow: Integer; + Rect: TRect; State: TGridDrawState); + procedure sgTransportsKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); + procedure sgTransportsMouseMove(Sender: TObject; Shift: TShiftState; X, + Y: Integer); + procedure miTransportsOpenDirClick(Sender: TObject); + procedure mnTransportsPopup(Sender: TObject); + procedure miTransportsResetClick(Sender: TObject); + procedure sgTransportsSelectCell(Sender: TObject; ACol, ARow: Integer; + var CanSelect: Boolean); + procedure miTransportsInsertClick(Sender: TObject); + procedure miTransportsDeleteClick(Sender: TObject); + procedure miTransportsClearClick(Sender: TObject); + procedure btnChangeCircuitClick(Sender: TObject); + procedure cbxTransportTypeChange(Sender: TObject); + procedure cbxBridgesTypeChange(Sender: TObject); + procedure cbxBridgesListChange(Sender: TObject); + procedure cbxBridgesTypeKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); + procedure cbxBridgesListKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); + procedure cbxNodesListTypeKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); + procedure cbxBridgesTypeCloseUp(Sender: TObject); + procedure cbxBridgesListCloseUp(Sender: TObject); + procedure miRequestIPv6BridgesClick(Sender: TObject); + procedure miRequestObfuscatedBridgesClick(Sender: TObject); + procedure miGetBridgesTelegramClick(Sender: TObject); + procedure miPreferWebTelegramClick(Sender: TObject); + procedure miClearBridgesNotAliveClick(Sender: TObject); + procedure ClearBridgesAvailableCache(Sender: TObject); + procedure cbUsePreferredBridgeClick(Sender: TObject); + procedure miDisableSelectionUnSuitableAsBridgeClick(Sender: TObject); + procedure miRtDisableBridgesClick(Sender: TObject); + procedure edPreferredBridgeChange(Sender: TObject); + procedure edPreferredBridgeExit(Sender: TObject); + procedure cbUsePreferredBridgeExit(Sender: TObject); + procedure cbUseBridgesExit(Sender: TObject); + procedure btnFindPreferredBridgeClick(Sender: TObject); + procedure ClearBridgesCache(Sender: TObject); + procedure tmSaveTotalsTimer(Sender: TObject); + procedure miResetTotalsCounterClick(Sender: TObject); + procedure miResetScannerScheduleClick(Sender: TObject); + procedure miDisableFiltersOnUserQueryClick(Sender: TObject); + procedure miStopScanClick(Sender: TObject); + procedure miDisableFiltersOnAuthorityOrBridgeClick(Sender: TObject); + procedure miClearUnusedNetworkCacheClick(Sender: TObject); + procedure miEnableConvertNodesOnIncorrectClearClick(Sender: TObject); + procedure miEnableConvertNodesOnAddToNodesListClick(Sender: TObject); + procedure miIgnoreConvertExcludeNodesClick(Sender: TObject); + procedure miConvertIpNodesClick(Sender: TObject); + procedure miConvertCidrNodesClick(Sender: TObject); + procedure miConvertCountryNodesClick(Sender: TObject); + procedure miAvoidAddingIncorrectNodesClick(Sender: TObject); + procedure edRoutersWeightMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); + procedure meLogMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); + procedure meLogMouseUp(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); + procedure miEnableConvertNodesOnRemoveFromNodesListClick(Sender: TObject); + procedure miManualPingMeasureClick(Sender: TObject); + procedure miManualDetectAliveNodesClick(Sender: TObject); + procedure cbxAutoSelPriorityChange(Sender: TObject); + procedure pbTrafficPaint(Sender: TObject); + procedure SelectTrafficPeriod(Sender: TObject); + procedure tmTrafficTimer(Sender: TObject); + procedure miSelectGraphDLClick(Sender: TObject); + procedure miSelectGraphULClick(Sender: TObject); + procedure FormPaint(Sender: TObject); + + private + procedure WMExitSizeMove(var msg: TMessage); message WM_EXITSIZEMOVE; + procedure WMDpiChanged(var msg: TWMDpi); message WM_DPICHANGED; + end; + +var + Tcp: TTcp; + TorConfig: TStringList; + CountryTotals: array [0..MAX_TOTALS - 1, 0..MAX_COUNTRIES - 1] of Integer; + SpeedData: array [0..MAX_SPEED_DATA_LENGTH - 1] of TSpeedData; + RoutersDic: TDictionary; + FilterDic: TDictionary; + GeoIpDic: TDictionary; + NodesDic: TDictionary; + CircuitsDic: TDictionary; + StreamsDic: TDictionary; + TrackHostDic: TDictionary; + VersionsDic: TDictionary; + TransportsDic: TDictionary; + BridgesDic: TDictionary; + RangesDic: TDictionary; + PortsDic: TDictionary; + ConstDic: TDictionary; + DefaultsDic: TDictionary; + ProgramDir, UserDir, HsDir, ThemesDir, TransportsDir, OnionAuthDir, LogsDir: string; + DefaultsFile, UserConfigFile, TorConfigFile, TorStateFile, TorLogFile, + TorExeFile, GeoIpFile, GeoIpv6File, NetworkCacheFile, BridgesCacheFile, + UserProfile, LangFile, ConsensusFile, DescriptorsFile, NewDescriptorsFile: string; + ControlPassword, SelectedNode, SearchStr, UPnPMsg: string; + Circuit, LastRoutersFilter, LastPreferredBridgeHash, ExitNodeID, ServerIPv4, ServerIPv6, TorVersion: string; + jLimit: TJobObjectExtendedLimitInformation; + TorVersionProcess, TorMainProcess: TProcessInfo; + hJob: THandle; + DLSpeed, ULSpeed, MaxDLSpeed, MaxULSpeed, CurrentTrafficPeriod: Integer; + SessionDL, SessionUL, TotalDL, TotalUL: Int64; + ConnectState, StopCode, FormSize, LastPlace, InfoStage, GetIpStage, NodesListStage: Byte; + EncodingNoBom: TUTF8EncodingNoBOM; + SearchTimer: Cardinal; + DecFormPos, IncFormPos: TPoint; + RoutersCustomFilter, LastRoutersCustomFilter, RoutersFilters, LastFilters: Integer; + GeoIpExists, FirstLoad, Restarting, Closing, CursorShow, GeoIpUpdating, ServerIsObfs4: Boolean; + CursorStop, StartTimer, RestartTimeout: TTimer; + Controller: TControlThread; + Consensus: TConsensusThread; + Descriptors: TDescriptorsThread; + Logger, VersionChecker: TReadPipeThread; + OptionsLocked, OptionsChanged, ShowNodesChanged, Connected, AlreadyStarted, SearchFirst, StopScan: Boolean; + ConsensusUpdated, DescriptorsUpdated, FilterUpdated, RoutersUpdated, ExcludeUpdated, OpenDNSUpdated, LanguageUpdated, BridgesUpdated: Boolean; + SelectExitCircuit, TotalsNeedSave: Boolean; + Scale: Real; + HsToDelete: ArrOfStr; + SystemLanguage: Word; + LastAuthCookieDate, LastConsensusDate, LastNewDescriptorsDate, LastTorrcDate: TDateTime; + LastFullScanDate, LastNonResponsedScanDate, TotalStartDate: Int64; + LastPartialScansCounts: Integer; + LockCircuits, LockCircuitInfo, LockStreams, LockStreamsInfo, UpdateTraffic: Boolean; + FindObject: TMemo; + ScanStage, AutoScanStage: Byte; + CurrentScanType: TScanType; + CurrentScanPurpose, CurrentAutoScanPurpose: TScanPurpose; + ScanThreads, CurrentScans, TotalScans, AliveNodesCount, PingNodesCount: Integer; + Scanner: TScanThread; + +implementation + +{$R *.dfm} +{$R TorControlPanel.icons.res} + +function TTcp.GetCheckBorders: Boolean; +begin + if FormSize = 0 then + Result := not cbNoDesktopBorders.Checked + or not (cbNoDesktopBorders.Checked and not cbNoDesktopBordersOnlyEnlarged.Checked) + else + Result := not cbNoDesktopBorders.Checked; +end; + +procedure TTcp.WMExitSizeMove(var msg: TMessage); +begin + if FormSize = 0 then + SetDesktopPosition(Tcp.Left, Tcp.Top, GetCheckBorders, True) + else + SetDesktopPosition(Tcp.Left, Tcp.Top, GetCheckBorders, True); +end; + +procedure TTcp.WMDpiChanged(var msg: TWMDpi); +begin + inherited; + UpdateScaleFactor; + UpdateFormSize; +end; + +procedure TTcp.SendCommand(const cmd: string); +begin + if Assigned(Controller) then + Controller.SendData(cmd); +end; + +procedure TTcp.LogThreadTerminate(Sender: TObject); +begin + Logger := nil; +end; + +procedure TTcp.VersionCheckerThreadTerminate(Sender: TObject); +begin + VersionChecker := nil; +end; + +procedure TReadPipeThread.UpdateVersionInfo; +var + ParseStr: ArrOfStr; +begin + ParseStr := Explode(' ', Data); + if Length(ParseStr) > 1 then + TorVersion := ParseStr[2] + else + TorVersion := '0.0.0.0'; + Tcp.LoadOptions; + Terminate; +end; + +procedure TReadPipeThread.UpdateLog; +var + SelStart, SelLength, CharFromPos: Integer; + Caret: TPoint; +begin + if Tcp.miAutoScroll.Checked and (Tcp.meLog.Tag = 0) then + Tcp.meLog.Lines.Add(Data) + else + begin + GetCaretPos(Caret); + CharFromPos := SendMessage(Tcp.meLog.Handle, EM_CHARFROMPOS, 0, Caret.Y * $FFFF + Caret.X) AND $FFFF; + SelStart := Tcp.meLog.SelStart; + SelLength := Tcp.meLog.SelLength; + Tcp.meLog.Lines.BeginUpdate; + Tcp.meLog.Lines.Add(Data); + Tcp.meLog.Lines.EndUpdate; + + if SelStart <> CharFromPos then + begin + Tcp.meLog.SelStart := SelStart; + if SelLength > 0 then + Tcp.meLog.SelLength := SelLength; + end + else + begin + Tcp.meLog.SelStart := SelStart + SelLength; + Tcp.meLog.SelLength := - SelLength; + end; + end; + if Tcp.miWriteLogFile.Checked then + SaveToLog(Data, TorLogFile); + + if ConnectState = 1 then + begin + if Pos('Failed to parse/validate config', Data) <> 0 then + StopCode := STOP_CONFIG_ERROR; + end; +end; + +procedure TReadPipeThread.Execute; +begin + while not Terminated do + begin + if PeekNamedPipe(hStdOut, nil, 0, nil, @DataSize, nil) then + begin + if DataSize > 0 then + begin + Buffer := AllocMem(DataSize + 1); + if ReadFile(hStdOut, Buffer^, DataSize, dwRead, nil) then + begin + Data := Trim(string(Buffer)); + Data := StringReplace(Data, CR + BR, BR, [rfReplaceAll]); + Data := StringReplace(Data, BR + BR, BR, [rfReplaceAll]); + if Data <> '' then + begin + if VersionCheck then + Synchronize(UpdateVersionInfo) + else + Synchronize(UpdateLog); + end; + end; + FreeMem(Buffer); + end; + end + else + begin + if GetLastError = ERROR_BROKEN_PIPE then + begin + if VersionCheck and (TorVersion = '') then + begin + Data := ''; + Synchronize(UpdateVersionInfo) + end + else + Terminate; + end; + end; + Sleep(1); + end; +end; + +procedure TDNSSendThread.UpdateIpStage; +begin + ServerIPv4 := Temp; + if ConnectState = 2 then + GetIpStage := 2 + else + begin + GetIpStage := 0; + Tcp.UpdateServerInfo; + end; +end; + +procedure TDNSSendThread.Execute; +var + DNS: TDNSSend; + ls: TStringList; +begin + DNS := TDNSSend.Create; + ls := TStringList.Create; + try + DNS.TargetHost := 'resolver1.opendns.com'; + DNS.DNSQuery('myip.opendns.com', QTYPE_A, ls); + Temp := Trim(ls.Text); + Synchronize(UpdateIpStage); + finally + DNS.Free; + ls.Free; + end; +end; + +procedure TSendHttpThread.Execute; +var + Http: THTTPSend; +begin + Http := THTTPSend.Create; + try + Http.Sock.SocksType := ST_Socks5; + Http.Sock.SocksIP := GetHost(Tcp.cbxSocksHost); + Http.Sock.SocksPort := IntToStr(Tcp.udSOCKSPort.Position); + Http.HTTPMethod('HEAD', GetDefaultsValue('CheckUrl', CHECK_URL)); + finally + Http.Free; + end; +end; + +procedure TScanItemThread.Execute; +var + GeoIpInfo: TGeoIpInfo; + ParseStr: ArrOfStr; + i, Search, ALength: Integer; + PortStr, PortsData: string; +begin + try + if ScanType = stPing then + begin + for i := 1 to MaxPingAttempts do + begin + if StopScan then + Exit; + Result := SendPing(IpStr, PingTimeOut); + if Result <> -1 then + Break; + if i <> MaxPingAttempts then + Sleep(AttemptsDelay); + end; + if GeoIpDic.TryGetValue(IpStr, GeoIpInfo) then + begin + GeoIpInfo.ping := Result; + GeoIpDic.AddOrSetValue(IpStr, GeoIpInfo); + end + else + begin + GeoIpInfo.ping := Result; + GeoIpInfo.ports := ''; + GeoIpInfo.cc := DEFAULT_COUNTRY_ID; + GeoIpDic.AddOrSetValue(IpStr, GeoIpInfo); + end; + end; + + if ScanType = stAlive then + begin + for i := 1 to MaxPortAttempts do + begin + if StopScan then + Exit; + if PortTCPIsOpen(Port, IpStr, PortTimeout) then + begin + Result := 1; + Break; + end + else + Result := -1; + if i <> MaxPortAttempts then + Sleep(AttemptsDelay); + end; + PortStr := IntToStr(Port); + if GeoIpDic.TryGetValue(IpStr, GeoIpInfo) then + begin + if GeoIpInfo.ports = '' then + GeoIpInfo.ports := PortStr + ':' + IntToStr(Result) + else + begin + ParseStr := Explode('|', GeoIpInfo.ports); + Search := -1; + ALength := Length(ParseStr); + for i := 0 to ALength - 1 do + begin + if Pos(PortStr + ':', ParseStr[i]) = 1 then + begin + Search := i; + Break; + end; + end; + if Search < 0 then + GeoIpInfo.ports := GeoIpInfo.ports + '|' + PortStr + ':' + IntToStr(Result) + else + begin + ParseStr[Search] := PortStr + ':' + IntToStr(Result); + PortsData := ''; + for i := 0 to ALength - 1 do + PortsData := PortsData + '|' + ParseStr[i]; + Delete(PortsData, 1, 1); + GeoIpInfo.ports := PortsData; + end; + end; + GeoIpDic.AddOrSetValue(IpStr, GeoIpInfo); + end + else + begin + GeoIpInfo.ping := 0; + GeoIpInfo.ports := PortStr + ':' + IntToStr(Result); + GeoIpInfo.cc := DEFAULT_COUNTRY_ID; + GeoIpDic.AddOrSetValue(IpStr, GeoIpInfo); + end; + end; + finally + InterlockedDecrement(ScanThreads); + end; +end; + +procedure TTcp.ScanThreadTerminate(Sender: TObject); +begin + Scanner := nil; +end; + +procedure TScanThread.Execute; +var + MemoryStatus: TMemoryStatusEx; + ls: TStringList; + Item: TPair; + RouterInfo: TRouterInfo; + GeoIpInfo: TGeoIpInfo; + AvailMemoryBefore: Int64; + NeedScan: Boolean; + ParseStr: ArrOfStr; + i, LastResult: Integer; + IpToScan, SocketStr: string; + PortToScan: Word; +begin + ls := TStringList.Create; + try + if CurrentAutoScanPurpose <> spNone then + sScanPurpose := CurrentAutoScanPurpose; + + if sScanPurpose = spUserBridges then + begin + ParseStr := Explode('|', MemoToLine(Tcp.meBridges, ltBridge, False, '|')); + for i := 0 to Length(ParseStr) - 1 do + begin + if TryGetDataFromStr(ParseStr[i], ltSocket, SocketStr) then + ls.Append(SocketStr); + end; + end + else + begin + for Item in RoutersDic do + begin + LastResult := 0; + NeedScan := False; + if GeoIpDic.TryGetValue(Item.Value.IPv4, GeoIpInfo) then + begin + if sScanType = stAlive then + begin + if GeoIpInfo.ports <> '' then + begin + ParseStr := Explode('|', GeoIpInfo.ports); + for i := 0 to Length(ParseStr) - 1 do + begin + if Pos(IntToStr(Item.Value.OrPort) + ':', ParseStr[i]) = 1 then + begin + LastResult := StrToIntDef(SeparateRight(ParseStr[i], ':'), 0); + Break; + end; + end; + end; + end; + + case sScanPurpose of + spAll: NeedScan := True; + spNew: + begin + case sScanType of + stPing: NeedScan := GeoIpInfo.ping = 0; + stAlive: NeedScan := LastResult = 0; + end; + end; + spFailed: + begin + case sScanType of + stPing: NeedScan := GeoIpInfo.ping = -1; + stAlive: NeedScan := LastResult = -1; + end; + end; + spNewAndFailed: + begin + case sScanType of + stPing: NeedScan := GeoIpInfo.ping < 1; + stAlive: NeedScan := LastResult < 1; + end; + end; + spBridges: NeedScan := rfBridge in Item.Value.Flags; + end; + + if NeedScan then + ls.Append(Item.Key); + end; + end; + end; + + if ls.Count > 0 then + begin + TotalScans := ls.Count; + i := 0; + PortToScan := 0; + IpToScan := ''; + MemoryStatus.dwLength := SizeOf(MemoryStatus); + GlobalMemoryStatusEx(MemoryStatus); + AvailMemoryBefore := MemoryStatus.ullAvailVirtual; + while not Terminated do + begin + NeedScan := False; + if ScanThreads < sMaxThreads then + begin + if sScanPurpose = spUserBridges then + begin + IpToScan := GetAddressFromSocket(ls[i]); + PortToScan := GetPortFromSocket(ls[i]); + NeedScan := True; + end + else + begin + if RoutersDic.TryGetValue(ls[i], RouterInfo) then + begin + IpToScan := RouterInfo.IPv4; + PortToScan := RouterInfo.OrPort; + NeedScan := True; + end; + end; + if NeedScan then + begin + with TScanItemThread.Create(True) do + begin + IpStr := IpToScan; + Port := PortToScan; + ScanType := sScanType; + MaxPortAttempts := sMaxPortAttempts; + MaxPingAttempts := sMaxPingAttempts; + AttemptsDelay := sAttemptsDelay; + PingTimeout := sPingTimeout; + PortTimeout := sPortTimeout; + FreeOnTerminate := True; + Priority := tpNormal; + Start; + end; + CurrentScans := i + 1; + InterlockedIncrement(ScanThreads); + end; + + if (i = ls.Count - 1) or StopScan then + Exit; + Inc(i); + + GlobalMemoryStatusEx(MemoryStatus); + if MemoryStatus.ullAvailVirtual < Round(AvailMemoryBefore * 0.2) then + sMaxThreads := ScanThreads; + if i mod sScanPortionSize = 0 then + Sleep(sScanPortionTimeout); + end + else + Sleep(1); + end; + end; + finally + ls.Free; + end; +end; + +procedure TTcp.CheckTorAutoStart; +begin + if FirstLoad then + begin + if cbConnectOnStartup.Checked then + begin + StartTimer := TTimer.Create(Tcp); + StartTimer.OnTimer := ConnectOnStartupTimer; + StartTimer.Interval := 25; + end; + FirstLoad := False; + end; +end; + +procedure TTcp.ConnectOnStartupTimer(Sender: TObject); +begin + if TorVersion <> '' then + begin + StartTor(True); + FreeAndNil(StartTimer); + end; +end; + +procedure TTcp.TConsensusThreadTerminate(Sender: TObject); +begin + Consensus := nil; + ConsensusUpdated := False; + if cbUseBridges.Checked or DescriptorsUpdated then + LoadDescriptors + else + begin + if ConnectState = 0 then + begin + LoadFilterTotals; + LoadRoutersCountries; + ShowFilter; + ShowRouters; + ShowCircuits; + BridgesCheckControls; + CheckTorAutoStart; + end + else + InfoStage := 1; + SaveBridgesCache; + end; +end; + +procedure TTcp.TDescriptorsThreadTerminate(Sender: TObject); +begin + Descriptors := nil; + DescriptorsUpdated := False; + if ConnectState = 0 then + begin + LoadFilterTotals; + LoadRoutersCountries; + ShowFilter; + ShowRouters; + ShowCircuits; + BridgesCheckControls; + CheckTorAutoStart; + end + else + InfoStage := 1; + SaveBridgesCache; +end; + +procedure TConsensusThread.Execute; +var + ls, lb: TStringList; + i, j: Integer; + Find: Boolean; + RouterID: string; + ParseStr: ArrOfStr; + Router: TRouterInfo; + Bridge: TPair; + BridgeInfo: TBridgeInfo; +begin + if not FileExists(ConsensusFile) then + Exit; + RoutersDic.Clear; + VersionsDic.Clear; + ls := TStringList.Create; + try + ls.LoadFromFile(ConsensusFile); + for i := 0 to ls.Count - 1 do + begin + if Pos('r ', ls[i]) = 1 then + begin + ParseStr := Explode(' ', ls[i]); + RouterID := AnsiStrToHex(decodebase64(AnsiString(ParseStr[2]))); + Router.Name := ParseStr[1]; + Router.IPv4 := ParseStr[5]; + Router.IPv6 := ''; + Router.OrPort := StrToInt(ParseStr[6]); + Router.DirPort := StrToInt(ParseStr[7]); + Router.Flags := [rfRelay]; + Router.Version := ''; + Router.Params := 0; + if Router.DirPort <> 0 then + Inc(Router.Params, ROUTER_DIR_MIRROR); + Continue; + end; + if Pos('a ', ls[i]) = 1 then + begin + Router.IPv6 := Copy(ls[i], 3, RPos(':', ls[i]) - 3); + Inc(Router.Params, ROUTER_REACHABLE_IPV6); + Continue; + end; + if Pos('s ', ls[i]) = 1 then + begin + if Pos('Authority', ls[i]) <> 0 then + begin + Include(Router.Flags, rfAuthority); + Inc(Router.Params, ROUTER_AUTHORITY); + end; + if Pos('BadExit', ls[i]) <> 0 then + begin + Include(Router.Flags, rfBadExit); + Inc(Router.Params, ROUTER_BAD_EXIT); + end; + if Pos('Exit', ls[i]) <> 0 then + Include(Router.Flags, rfExit); + if Pos('Fast', ls[i]) <> 0 then + Include(Router.Flags, rfFast); + if Pos('Guard', ls[i]) <> 0 then + Include(Router.Flags, rfGuard); + if Pos('HSDir', ls[i]) <> 0 then + begin + Include(Router.Flags, rfHSDir); + Inc(Router.Params, ROUTER_HS_DIR); + end; + if Pos('Stable', ls[i]) <> 0 then + Include(Router.Flags, rfStable); + if Pos('V2Dir', ls[i]) <> 0 then + Include(Router.Flags, rfV2Dir); + Continue; + end; + if Pos('v ', ls[i]) = 1 then + begin + Router.Version := Copy(ls[i], 7); + if not VersionsDic.ContainsKey(Router.Version) then + Inc(Router.Params, ROUTER_NOT_RECOMMENDED); + Continue; + end; + + if Pos('w ', ls[i]) = 1 then + begin + ParseStr := Explode(' ', ls[i]); + Router.Bandwidth := StrToInt(SeparateRight(ParseStr[1], '=')); + + if BridgesDic.TryGetValue(RouterID, BridgeInfo) then + begin + Include(Router.Flags, rfBridge); + Inc(Router.Params, ROUTER_BRIDGE); + BridgeInfo.Router := Router; + BridgeInfo.Kind := BRIDGE_RELAY; + BridgesDic.AddOrSetValue(RouterID, BridgeInfo); + end; + + RoutersDic.AddOrSetValue(RouterID, Router); + Continue; + end; + + if Pos('server-versions', ls[i]) = 1 then + begin + ParseStr := Explode(',', ls[i]); + for j := 0 to Length(ParseStr) - 1 do + VersionsDic.AddOrSetValue(ParseStr[j], 0); + Continue; + end; + + if Pos('directory-footer', ls[i]) = 1 then + Break; + end; + FileAge(ConsensusFile, LastConsensusDate); + + if BridgesDic.Count > 0 then + begin + lb := TStringList.Create; + try + for Bridge in BridgesDic do + begin + Find := RoutersDic.ContainsKey(Bridge.Key); + if Bridge.Value.Kind = BRIDGE_RELAY then + begin + if not Find then + begin + lb.Append(Bridge.Key); + Continue; + end; + end + else + begin + BridgeInfo := Bridge.Value; + if TryUpdateMask(BridgeInfo.Router.Params, ROUTER_NOT_RECOMMENDED, + not VersionsDic.ContainsKey(BridgeInfo.Router.Version)) then + BridgesDic.AddOrSetValue(Bridge.Key, BridgeInfo); + RoutersDic.AddOrSetValue(Bridge.Key, BridgeInfo.Router); + end; + end; + if lb.Count > 0 then + begin + for i := 0 to lb.Count - 1 do + BridgesDic.Remove(lb[i]); + end; + finally + lb.Free; + end; + end; + finally + ls.Free; + end; +end; + +procedure TDescriptorsThread.Execute; +var + ls, lb: TStringList; + i: Integer; + ParseStr: ArrOfStr; + DescRouter, Router: TRouterInfo; + UserBridges: TDictionary; + Bridge: TBridge; + RouterID, Temp: string; + BridgeRelay, UpdateFromDesc: Boolean; + + procedure LoadDesc(FileName: string); + var + Desc: TStringList; + begin + if not FileExists(FileName) then + Exit; + Desc := TStringList.Create; + try + Desc.LoadFromFile(FileName); + if Desc.Count > 0 then + ls.AddStrings(Desc); + finally + Desc.Free; + end; + end; + + procedure UpdateBridges(var RouterInfo: TRouterInfo); + var + BridgeInfo, BridgeInfoDic: TBridgeInfo; + begin + if UserBridges.TryGetValue(RouterID, Bridge) then + begin + if not IpInRanges(Bridge.Ip, DocRanges) then + RouterInfo.OrPort := Bridge.Port; + BridgeInfo.Transport := Bridge.Transport; + BridgeInfo.Params := Bridge.Params; + end + else + begin + if BridgesDic.TryGetValue(RouterID, BridgeInfoDic) then + begin + RouterInfo.OrPort := BridgeInfoDic.Router.OrPort; + BridgeInfo.Transport := BridgeInfoDic.Transport; + BridgeInfo.Params := BridgeInfoDic.Params; + end + else + begin + BridgeInfo.Transport := ''; + BridgeInfo.Params := ''; + end; + end; + if rfRelay in RouterInfo.Flags then + BridgeInfo.Kind := BRIDGE_RELAY + else + BridgeInfo.Kind := BRIDGE_NATIVE; + BridgeInfo.Router := RouterInfo; + BridgesDic.AddOrSetValue(RouterID, BridgeInfo); + end; + +begin + ls := TStringList.Create; + lb := TStringList.Create; + UserBridges := TDictionary.Create; + try + if Tcp.cbUsePreferredBridge.Checked then + lb.Append(Tcp.edPreferredBridge.Text) + else + lb.Text := Tcp.meBridges.Text; + + for i := 0 to lb.Count - 1 do + begin + if TryParseBridge(lb[i], Bridge) then + UserBridges.AddOrSetValue(Bridge.Hash, Bridge); + end; + BridgeRelay := False; + UpdateFromDesc := False; + LoadDesc(DescriptorsFile); + LoadDesc(NewDescriptorsFile); + for i := 0 to ls.Count - 1 do + begin + if Pos('@purpose bridge', ls[i]) = 1 then + begin + BridgeRelay := True; + UpdateFromDesc := True; + Continue; + end; + if BridgeRelay then + begin + if Pos('router ', ls[i]) = 1 then + begin + ParseStr := Explode(' ', ls[i]); + DescRouter.Name := ParseStr[1]; + DescRouter.IPv4 := ParseStr[2]; + DescRouter.IPv6 := ''; + DescRouter.OrPort := StrToInt(ParseStr[3]); + DescRouter.DirPort := 0; + DescRouter.Flags := [rfBridge]; + DescRouter.Params := ROUTER_BRIDGE; + DescRouter.Version := ''; + Continue; + end; + + if Pos('or-address ', ls[i]) = 1 then + begin + Temp := Copy(ls[i], 12, RPos(':', ls[i]) - 12); + if ValidAddress(Temp, False, True) = 2 then + begin + DescRouter.IPv6 := Temp; + Inc(DescRouter.Params, ROUTER_REACHABLE_IPV6); + end; + Continue; + end; + + if Pos('platform ', ls[i]) = 1 then + begin + ParseStr := Explode(' ', ls[i]); + DescRouter.Version := ParseStr[2]; + if not VersionsDic.ContainsKey(ParseStr[2]) then + Inc(DescRouter.Params, ROUTER_NOT_RECOMMENDED); + Continue; + end; + + if Pos('fingerprint ', ls[i]) = 1 then + begin + RouterID := StringReplace(Copy(ls[i], 13), ' ', '', [rfReplaceAll]); + Continue; + end; + + if Pos('bandwidth ', ls[i]) = 1 then + begin + ParseStr := Explode(' ', ls[i]); + DescRouter.Bandwidth := Round(StrToInt(ParseStr[3]) / 1024); + Continue; + end; + + if Pos('tunnelled-dir-server', ls[i]) = 1 then + begin + Include(DescRouter.Flags, rfV2Dir); + Continue; + end; + + if Pos('router-signature', ls[i]) = 1 then + begin + if RoutersDic.TryGetValue(RouterID, Router) then + begin + if (rfRelay in Router.Flags) and not (rfBridge in Router.Flags) then + begin + Include(Router.Flags, rfBridge); + Inc(Router.Params, ROUTER_BRIDGE); + if Router.Bandwidth < DescRouter.Bandwidth then + Router.Bandwidth := DescRouter.Bandwidth; + UpdateBridges(Router); + RoutersDic.AddOrSetValue(RouterID, Router); + UpdateFromDesc := False; + end; + end; + if UpdateFromDesc then + begin + UpdateBridges(DescRouter); + RoutersDic.AddOrSetValue(RouterID, DescRouter); + UpdateFromDesc := False; + end; + BridgeRelay := False; + Continue; + end; + end; + end; + FileAge(NewDescriptorsFile, LastNewDescriptorsDate); + finally + ls.Free; + lb.Free; + UserBridges.Free; + end; +end; + +procedure TTcp.ControlThreadTerminate(Sender: TObject); +begin + Connected := False; + Controller := nil; + if (ConnectState > 0) then + begin + case StopCode of + STOP_NORMAL: RestartTor; + STOP_CONFIG_ERROR: + begin + StopTor; + Tcp.Show; + sbShowLog.Click; + ShowMsg(TransStr('236'), '', mtError); + end; + STOP_AUTH_ERROR: + begin + StopTor; + ShowMsg(TransStr('237'), '', mtWarning); + end; + end; + end; +end; + +function TTcp.GetControlEvents: string; +begin + Result := 'BW CIRC STREAM STATUS_CLIENT'; + if cbxServerMode.ItemIndex <> 0 then + Result := Result + ' STATUS_SERVER'; + if miShowCircuitsTraffic.Checked then + Result := Result + ' CIRC_BW'; + if miShowStreamsTraffic.Checked then + Result := Result + ' STREAM_BW'; +end; + +procedure TControlThread.Execute; +begin + Socket := TTCPBlockSocket.Create; + try + repeat + Socket.Connect('127.0.0.1', IntToStr(Tcp.udControlPort.Position)); + if StopCode <> STOP_NORMAL then + Terminate; + until (Terminated = True) or (Socket.LastError = 0); + + repeat + Sleep(1); + until (Terminated = True) or (AuthStageReady(Tcp.cbxAuthMetod.ItemIndex) = True); + + case Tcp.cbxAuthMetod.ItemIndex of + 0: AuthParam := FileGetString(UserDir + 'control_auth_cookie', True); + 1: AuthParam := '"' + Decrypt(ControlPassword, 'True') + '"'; + end; + Socket.SendString('AUTHENTICATE ' + AnsiString(AuthParam) + BR); + Socket.SendString('SETEVENTS ' + AnsiString(Tcp.GetControlEvents) + BR); + Connected := True; + while not Terminated do + begin + Data := string(socket.RecvString(1)); + if Socket.LastError = 0 then + Synchronize(GetData); + + if SendBuffer <> '' then + begin + Socket.SendString(AnsiString(SendBuffer)); + SendBuffer := ''; + end; + + if Socket.LastError = WSAECONNRESET then + Terminate; + end; + finally + Socket.CloseSocket; + Socket.Free; + end; +end; + +procedure TControlThread.SendData(cmd: string); +begin + if Connected then + SendBuffer := SendBuffer + cmd + BR; +end; + +procedure TControlThread.GetData; +var + i: Integer; + UpdateCountry: Boolean; + Item: TPair; + GeoIpItem: TPair; + GeoIpInfo: TGeoIpInfo; + FilterInfo: TFilterInfo; + RouterInfo: TRouterInfo; +begin + if InfoStage > 0 then + begin + + if InfoStage = 1 then + begin + Temp := ''; + InfoCount := 0; + + if GeoIpExists then + begin + if GeoIpUpdating then + begin + for GeoIpItem in GeoIpDic do + begin + Inc(InfoCount); + Temp := Temp + ' ip-to-country/' + GeoIpItem.Key; + end; + end + else + begin + for Item in RoutersDic do + begin + UpdateCountry := True; + if GeoIpDic.TryGetValue(Item.Value.IPv4, GeoIpInfo) then + begin + if GeoIpInfo.cc <> DEFAULT_COUNTRY_ID then + UpdateCountry := False; + end; + if UpdateCountry then + begin + Inc(InfoCount); + Temp := Temp + ' ip-to-country/' + Item.Value.IPv4; + end; + end; + end; + end; + + if InfoCount > 0 then + begin + SendData('GETINFO' + Temp); + InfoStage := 2; + end + else + InfoStage := 3; + end; + + if InfoStage = 2 then + begin + if Pos('250-ip-to-country/', Data) = 1 then + begin + ParseStr := Explode('=', copy(Data, 19)); + if FilterDic.TryGetValue(ParseStr[1], FilterInfo) then + CountryCode := FilterInfo.cc + else + CountryCode := DEFAULT_COUNTRY_ID; + + if GeoIpDic.TryGetValue(ParseStr[0], GeoIpInfo) then + GeoIpInfo.cc := CountryCode + else + begin + GeoIpInfo.cc := CountryCode; + GeoIpInfo.ping := 0; + GeoIpInfo.ports := ''; + end; + GeoIpDic.AddOrSetValue(ParseStr[0], GeoIpInfo); + + Dec(InfoCount); + + if InfoCount = 0 then + begin + GeoIpUpdating := False; + InfoStage := 3; + end + else + Exit; + end; + end; + + if InfoStage = 3 then + begin + InfoStage := 0; + Tcp.LoadFilterTotals; + Tcp.LoadRoutersCountries; + Tcp.ShowFilter; + Tcp.ShowRouters; + Tcp.tmConsensus.Enabled := True; + if (ConnectState = 2) and (Circuit = '') then + Tcp.SendDataThroughProxy; + + if AutoScanStage = 0 then + begin + if Tcp.cbAutoScanNewNodes.Checked and + (Tcp.cbEnablePingMeasure.Checked or Tcp.cbEnableDetectAliveNodes.Checked) then + AutoScanStage := 1; + end + else + begin + if AutoScanStage = 3 then + AutoScanStage := 0; + end; + Tcp.SaveNetworkCache; + end; + end; + + if GetIpStage > 0 then + begin + if GetIpStage = 1 then + begin + if (Pos('250-address', Data) = 1) then + begin + ServerIPv4 := SeparateRight(Data, '='); + GetIpStage := 2; + end; + + if Pos('551 Address unknown', Data) = 1 then + begin + if Tcp.cbUseOpenDNS.Checked and Tcp.cbUseOpenDNSOnlyWhenUnknown.Checked then + begin + Tcp.GetDNSExternalAddress; + Exit; + end + else + begin + ServerIPv4 := ''; + GetIpStage := 2; + end; + end; + end; + + if GetIpStage = 2 then + begin + Tcp.UpdateServerInfo; + GetIpStage := 0; + Exit; + end; + end; + + if ConnectState = 1 then + begin + if Pos('515 Authentication failed', Data) = 1 then + begin + StopCode := STOP_AUTH_ERROR; + Exit; + end; + + SearchPos := Pos('BOOTSTRAP PROGRESS', Data); + if SearchPos <> 0 then + begin + Temp := copy(Data, SearchPos + 19, Pos('TAG', Data) - (SearchPos + 20)); + Tcp.btnChangeCircuit.Caption := Temp + ' %'; + + if Temp = '75' then + begin + Tcp.LoadConsensus; + Exit; + end; + if Temp = '100' then + begin + ConnectState := 2; + AlreadyStarted := True; + Tcp.btnChangeCircuit.Caption := TransStr('103'); + Tcp.tiTray.IconIndex := 2; + Tcp.btnSwitchTor.ImageIndex := 2; + Tcp.btnSwitchTor.Caption := TransStr('102'); + Tcp.miSwitchTor.ImageIndex := 2; + Tcp.miSwitchTor.Caption := Tcp.btnSwitchTor.Caption; + Tcp.SetOptionsEnable(True); + Tcp.GetServerInfo; + if Tcp.cbEnableSocks.Checked then + Tcp.SendDataThroughProxy; + end; + Exit; + end; + end; + + if Pos('650 CIRC ', Data) = 1 then + begin + ParseStr := Explode(' ', Data); + CircuitID := ParseStr[2]; + CircuitStatusID := GetConstantIndex(ParseStr[3]); + case CircuitStatusID of + BUILT: + begin + CircuitInfo.BuildFlags := []; + CircuitInfo.Streams := 0; + CircuitInfo.BytesRead := 0; + CircuitInfo.BytesWritten := 0; + if Pos('ONEHOP_TUNNEL', ParseStr[5]) <> 0 then + Include(CircuitInfo.BuildFlags, bfOneHop); + if Pos('IS_INTERNAL', ParseStr[5]) <> 0 then + Include(CircuitInfo.BuildFlags, bfInternal); + if Pos('NEED_CAPACITY', ParseStr[5]) <> 0 then + Include(CircuitInfo.BuildFlags, bfNeedCapacity); + if Pos('NEED_UPTIME', ParseStr[5]) <> 0 then + Include(CircuitInfo.BuildFlags, bfNeedUptime); + CircuitInfo.PurposeID := GetConstantIndex(SeparateRight(ParseStr[6], '=')); + for i := 7 to Length(ParseStr) - 1 do + begin + if Pos('TIME_CREATED', ParseStr[i]) <> 0 then + begin + CircuitInfo.Date := TorDateFormat(SeparateRight(ParseStr[i], '=')); + Break; + end; + end; + ParseStr := Explode(',', ParseStr[4]); + Temp := ''; + for i := 0 to Length(ParseStr) - 1 do + Temp := Temp + ',' + Copy(SeparateLeft(ParseStr[i], '~'), 2); + Delete(Temp, 1, 1); + CircuitInfo.Nodes := Temp; + CircuitsDic.AddOrSetValue(CircuitID, CircuitInfo); + end; + CLOSED: + begin + CircuitsDic.Remove(CircuitID); + if CircuitID = Circuit then + Tcp.SendDataThroughProxy; + end; + end; + Exit; + end; + + if Pos('650 STREAM ', Data) = 1 then + begin + ParseStr := Explode(' ', Data); + StreamID := ParseStr[2]; + StreamStatusID := GetConstantIndex(ParseStr[3]); + CircuitID := ParseStr[4]; + case StreamStatusID of + NEW: + begin + StreamInfo.CircuitID := CircuitID; + StreamInfo.Target := ParseStr[5]; + StreamInfo.SourceAddr := ''; + StreamInfo.DestAddr := ''; + StreamInfo.BytesRead := 0; + StreamInfo.BytesWritten := 0; + for i := 6 to Length(ParseStr) - 1 do + begin + if Pos('SOURCE_ADDR', ParseStr[i]) = 1 then + StreamInfo.SourceAddr := SeparateRight(ParseStr[i], '='); + if Pos('PURPOSE', ParseStr[i]) = 1 then + begin + StreamInfo.PurposeID := GetConstantIndex(SeparateRight(ParseStr[i], '=')); + Break; + end; + end; + StreamsDic.AddOrSetValue(StreamID, StreamInfo); + Exit; + end; + SENTCONNECT: + begin + if StreamsDic.TryGetValue(StreamID, StreamInfo) then + begin + StreamInfo.CircuitID := CircuitID; + StreamsDic.AddOrSetValue(StreamID, StreamInfo); + if (Circuit <> CircuitID) and (StreamInfo.PurposeID = USER) then + begin + if CircuitsDic.TryGetValue(CircuitID, CircuitInfo) then + begin + if not (bfInternal in CircuitInfo.BuildFlags) then + begin + ParseStr := Explode(',', CircuitInfo.Nodes); + Temp := ParseStr[Length(ParseStr) - 1]; + if RoutersDic.TryGetValue(Temp, RouterInfo) then + begin + Circuit := CircuitID; + Ip := RouterInfo.IPv4; + CountryCode := GetCountryValue(Ip); + if ExitNodeID = '' then + begin + Tcp.lbExitIp.Cursor := crHandPoint; + Tcp.lbExitCountry.Cursor := crHandPoint; + Tcp.miChangeCircuit.Enabled := True; + end; + ExitNodeID := Temp; + Tcp.lbExitIp.Caption := Ip; + Tcp.lbExitCountry.Caption := TransStr(CountryCodes[CountryCode]); + Tcp.lbExitCountry.Left := Round(198 * Scale); + Tcp.imExitFlag.Picture := nil; + Tcp.lsFlags.GetBitmap(CountryCode, Tcp.imExitFlag.Picture.Bitmap); + Tcp.imExitFlag.Visible := True; + CheckLabelEndEllipsis(Tcp.lbExitCountry, 150, epEndEllipsis, True, False); + if CountryCode = DEFAULT_COUNTRY_ID then + Tcp.ShowBalloon(TransStr('113') + ': ' + Ip, TransStr('258')) + else + Tcp.ShowBalloon(TransStr('113') + ': ' + Ip + BR + ' ' + TransStr('114') + ': ' + TransStr(CountryCodes[CountryCode]), TransStr('258')); + Tcp.btnChangeCircuit.Enabled := True; + Tcp.miChangeCircuit.Enabled := True; + Tcp.tmUpdateIp.Interval := Tcp.udMaxCircuitDirtiness.Position * 1000; + Tcp.tmUpdateIp.Enabled := True; + if Tcp.miSelectExitCircuitWhetItChanges.Checked then + SelectExitCircuit := True; + end; + end; + end; + end; + end; + end; + REMAP: + begin + if StreamsDic.TryGetValue(StreamID, StreamInfo) then + begin + StreamInfo.DestAddr := ParseStr[5]; + StreamsDic.AddOrSetValue(StreamID, StreamInfo); + end; + Exit; + end; + end; + if CircuitsDic.TryGetValue(CircuitID, CircuitInfo) then + begin + if StreamsDic.ContainsKey(StreamID) then + begin + case StreamStatusID of + SENTCONNECT: Inc(CircuitInfo.Streams); + DETACHED: Dec(CircuitInfo.Streams); + CLOSED: + begin + Dec(CircuitInfo.Streams); + StreamsDic.Remove(StreamID); + end; + end; + CircuitsDic.AddOrSetValue(CircuitID, CircuitInfo); + end; + end + else + begin + if StreamStatusID = CLOSED then + begin + if Tcp.cbEnableSocks.Checked and (ConnectState = 2) and (ExitNodeID = '') then + begin + if ExtractDomain(ParseStr[5], True) = ExtractDomain(GetDefaultsValue('CheckUrl', CHECK_URL)) then + Tcp.SendDataThroughProxy; + end; + StreamsDic.Remove(StreamID); + end; + end; + Exit; + end; + + if Pos('650 BW ', Data) = 1 then + begin + ParseStr := Explode(' ', Data); + DLSpeed := StrToIntDef(ParseStr[2], 0); + ULSpeed := StrToIntDef(ParseStr[3], 0); + if DLSpeed > MaxDLSpeed then + begin + MaxDLSpeed := DLSpeed; + Tcp.lbMaxDLSpeed.Caption := BytesFormat(MaxDLSpeed) + '/' + TransStr('180'); + end; + if ULSpeed > MaxULSpeed then + begin + MaxULSpeed := ULSpeed; + Tcp.lbMaxULSpeed.Caption := BytesFormat(MaxULSpeed) + '/' + TransStr('180'); + end; + if DLSpeed > 0 then + begin + Inc(SessionDL, DLSpeed); + inc(TotalDL, DLSpeed); + Tcp.lbSessionDL.Caption := BytesFormat(SessionDL); + Tcp.lbTotalDL.Caption := BytesFormat(TotalDL); + TotalsNeedSave := True; + end; + if ULSpeed > 0 then + begin + Inc(SessionUL, ULSpeed); + inc(TotalUL, ULSpeed); + Tcp.lbSessionUL.Caption := BytesFormat(SessionUL); + Tcp.lbTotalUL.Caption := BytesFormat(TotalUL); + TotalsNeedSave := True; + end; + + Exit; + end; + if Tcp.miShowCircuitsTraffic.Checked then + begin + if Pos('650 CIRC_BW ', Data) = 1 then + begin + ParseStr := Explode(' ', Data); + CircuitID := SeparateRight(ParseStr[2], '='); + if CircuitsDic.TryGetValue(CircuitID, CircuitInfo) then + begin + Inc(CircuitInfo.BytesRead, StrToInt64Def(SeparateRight(ParseStr[3], '='), 0)); + Inc(CircuitInfo.BytesWritten, StrToInt64Def(SeparateRight(ParseStr[4], '='), 0)); + CircuitsDic.AddOrSetValue(CircuitID, CircuitInfo); + end; + Exit; + end; + end; + + if Tcp.miShowStreamsTraffic.Checked then + begin + if Pos('650 STREAM_BW ', Data) = 1 then + begin + ParseStr := Explode(' ', Data); + StreamID := SeparateRight(ParseStr[2], '='); + if StreamsDic.TryGetValue(StreamID, StreamInfo) then + begin + Inc(StreamInfo.BytesWritten, StrToInt64Def(SeparateRight(ParseStr[3], '='), 0)); + Inc(StreamInfo.BytesRead, StrToInt64Def(SeparateRight(ParseStr[4], '='), 0)); + StreamsDic.AddOrSetValue(StreamID, StreamInfo); + end; + Exit; + end; + end; + + if Tcp.cbxServerMode.ItemIndex <> 0 then + begin + if Pos('650 STATUS_SERVER ', Data) = 1 then + begin + ParseStr := Explode(' ', Data); + for i := 2 to Length(ParseStr) - 1 do + begin + if Pos('ADDRESS=', ParseStr[i]) = 1 then + begin + Temp := SeparateRight(ParseStr[i], '='); + IpID := ValidAddress(Temp); + case IpID of + 1: if Temp <> ServerIPv4 then ServerIPv4 := Temp; + 2: if Temp <> ServerIPv6 then ServerIPv6 := Temp; + end; + if IpID <> 0 then + Tcp.UpdateServerInfo; + end; + end; + Exit; + end; + end; + +end; + +function TUTF8EncodingNoBOM.GetPreamble: TBytes; +begin + SetLength(Result, 0); +end; + +procedure TPageControl.TCMAdjustRect(var Msg: TMessage); +begin + inherited; + if Msg.WParam = 0 then + InflateRect(PRect(Msg.LParam)^, 3, 1) + else + InflateRect(PRect(Msg.LParam)^, -3, -3); +end; + +procedure TTcp.sgCircuitInfoDblClick(Sender: TObject); +begin + if sgCircuitInfo.MovRow > 0 then + begin + case sgCircuitInfo.MovCol of + CIRC_INFO_IP: FindInRouters(sgCircuitInfo.Cells[CIRC_INFO_ID, sgCircuitInfo.MovRow]); + CIRC_INFO_FLAG, CIRC_INFO_COUNTRY: + FindInFilter(sgCircuitInfo.Cells[CIRC_INFO_IP, sgCircuitInfo.MovRow]); + end; + end; +end; + +procedure TTcp.sgCircuitInfoDrawCell(Sender: TObject; ACol, ARow: Integer; + Rect: TRect; State: TGridDrawState); +begin + if (ARow = 0) and (ACol > 0) then + begin + case ACol of + CIRC_INFO_FLAG: GridDrawIcon(sgCircuitInfo, Rect, lsMain, 6); + else + DrawText(sgCircuitInfo.Canvas.Handle, PChar(DetailsHeader[ACol - 1]), Length(DetailsHeader[ACol - 1]), Rect, DT_CENTER); + end; + end; + if ARow > 0 then + begin + if ACol = CIRC_INFO_FLAG then + begin + if sgCircuitInfo.Cells[CIRC_INFO_IP, ARow] <> '' then + GridDrawIcon(sgCircuitInfo, Rect, lsFlags, GetCountryValue(sgCircuitInfo.Cells[CIRC_INFO_IP, ARow]), 20, 13); + end; + end; +end; + +procedure TTcp.sgCircuitInfoKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + GridKeyDown(sgCircuitInfo, Shift, Key); + case Key of + VK_F5: ShowCircuits; + end; +end; + +procedure TTcp.sgCircuitInfoMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + if Button = mbRight then + sgCircuitInfo.MouseToCell(X, Y, sgCircuitInfo.MovCol, sgCircuitInfo.MovRow); +end; + +procedure TTcp.sgCircuitInfoMouseMove(Sender: TObject; Shift: TShiftState; X, + Y: Integer); +begin + lbExitIp.Tag := 0; + sgCircuitInfo.MouseToCell(X, Y, sgCircuitInfo.MovCol, sgCircuitInfo.MovRow); + GridSetFocus(sgCircuitInfo); + GridShowHints(sgCircuitInfo); + GridCheckAutoPopup(sgCircuitInfo, sgCircuitInfo.MovRow); + if (sgCircuitInfo.MovCol in [CIRC_INFO_IP..CIRC_INFO_COUNTRY]) and (sgCircuitInfo.MovRow > 0) and not IsEmptyRow(sgCircuitInfo, sgCircuitInfo.MovRow) then + sgCircuitInfo.Cursor := crHandPoint + else + sgCircuitInfo.Cursor := crDefault; +end; + +procedure TTcp.sgCircuitInfoSelectCell(Sender: TObject; ACol, ARow: Integer; + var CanSelect: Boolean); +begin + GridSelectCell(sgCircuitInfo, ACol, ARow); +end; + +procedure TTcp.sgCircuitsDrawCell(Sender: TObject; ACol, ARow: Integer; + Rect: TRect; State: TGridDrawState); +begin + if ARow = 0 then + begin + case ACol of + CIRC_PURPOSE: DrawText(sgCircuits.Canvas.Handle, PChar(CircuitsHeader[ACol - 1]), Length(CircuitsHeader[ACol - 1]), Rect, DT_CENTER); + CIRC_STREAMS: GridDrawIcon(sgCircuits, Rect, lsMain, 8); + end; + if (ACol = sgCircuits.SortCol) and (ACol = CIRC_PURPOSE) then + GridDrawSortArrows(sgCircuits, Rect); + end; +end; + +procedure TTcp.sgCircuitsKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + GridKeyDown(sgCircuits, Shift, Key); +end; + +procedure TTcp.sgCircuitsMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + if Button = mbRight then + sgCircuits.MouseToCell(X, Y, sgCircuits.MovCol, sgCircuits.MovRow); +end; + +procedure TTcp.sgCircuitsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); +begin + sgCircuits.MouseToCell(X, Y, sgCircuits.MovCol, sgCircuits.MovRow); + GridSetFocus(sgCircuits); + GridShowHints(sgCircuits); + GridCheckAutoPopup(sgCircuits, sgCircuits.MovRow, True); +end; + +procedure TTcp.sgCircuitsSelectCell(Sender: TObject; ACol, ARow: Integer; + var CanSelect: Boolean); +begin + GridSelectCell(sgCircuits, ACol, ARow); + ShowCircuitInfo(sgCircuits.Cells[CIRC_ID, ARow]); +end; + +procedure TTcp.sgFilterDrawCell(Sender: TObject; ACol, ARow: Integer; + Rect: TRect; State: TGridDrawState); +begin + if ARow = 0 then + begin + case ACol of + FILTER_FLAG: GridDrawIcon(sgFilter, Rect, lsMain, 6); + FILTER_ENTRY_NODES: GridDrawIcon(sgFilter, Rect, lsMain, 7); + FILTER_MIDDLE_NODES: GridDrawIcon(sgFilter, Rect, lsMain, 8); + FILTER_EXIT_NODES: GridDrawIcon(sgFilter, Rect, lsMain, 9); + FILTER_EXCLUDE_NODES: GridDrawIcon(sgFilter, Rect, lsMain, 10); + else + DrawText(sgFilter.Canvas.Handle, PChar(FilterHeader[ACol]), Length(FilterHeader[ACol]), Rect, DT_CENTER); + end; + if (ACol = sgFilter.SortCol) and (ACol < FILTER_ENTRY_NODES) then + GridDrawSortArrows(sgFilter, Rect); + end; + if ARow > 0 then + begin + if (ACol = FILTER_FLAG) and (sgFilter.Cells[FILTER_ID, ARow] <> '') then + GridDrawIcon(sgFilter, Rect, lsFlags, FilterDic.Items[AnsiLowerCase(sgFilter.Cells[FILTER_ID, ARow])].cc, 20, 13); + end; +end; + +procedure TTcp.UpdateRoutersAfterBridgesUpdate; +begin + if BridgesUpdated then + begin + if LastPreferredBridgeHash <> '' then + ShowRouters; + BridgesUpdated := False; + end; +end; + +procedure TTcp.UpdateRoutersAfterFilterUpdate; +begin + if FilterUpdated then + begin + if (cbxRoutersCountry.Tag = -2) or ExcludeUpdated then + ShowRouters; + if ExcludeUpdated then + begin + CalculateTotalNodes; + LoadNodesList; + ExcludeUpdated := False; + end; + FilterUpdated := False; + end; +end; + +procedure TTcp.UpdateOptionsAfterRoutersUpdate; +begin + if FilterUpdated then + begin + CalculateFilterNodes; + ShowFilter; + FilterUpdated := False; + end; + if RoutersUpdated then + begin + LoadNodesList; + RoutersUpdated := False; + end; +end; + +procedure TTcp.sgFilterExit(Sender: TObject); +begin + UpdateRoutersAfterFilterUpdate; +end; + +procedure TTcp.sgFilterFixedCellClick(Sender: TObject; ACol, ARow: Integer); +begin + if ACol = FILTER_FLAG then + Exit; + SortPrepare(sgFilter, ACol, True); +end; + +procedure TTcp.ChangeFilter; +var + i: Integer; + Key: string; + FNodeType: TNodeType; + FilterInfo: TFilterInfo; + + procedure DeleteExclude; + begin + if sgFilter.Cells[FILTER_EXCLUDE_NODES, sgFilter.SelRow] = EXCLUDE_CHAR then + begin + sgFilter.Cells[FILTER_EXCLUDE_NODES, sgFilter.SelRow] := ''; + NodesDic.Remove(Key); + FilterInfo.Data := []; + ExcludeUpdated := True; + end; + end; + +begin + Key := AnsiLowerCase(sgFilter.Cells[FILTER_ID, sgFilter.SelRow]); + if not FilterDic.ContainsKey(Key) then + Exit; + case sgFilter.SelCol of + FILTER_ENTRY_NODES: FNodeType := ntEntry; + FILTER_MIDDLE_NODES: FNodeType := ntMiddle; + FILTER_EXIT_NODES: FNodeType := ntExit; + FILTER_EXCLUDE_NODES: FNodeType := ntExclude; + else + Exit; + end; + FilterDic.TryGetValue(Key, FilterInfo); + + if FNodeType = ntExclude then + begin + if sgFilter.Cells[FILTER_EXCLUDE_NODES, sgFilter.SelRow] = '' then + begin + sgFilter.Cells[FILTER_EXCLUDE_NODES, sgFilter.SelRow] := EXCLUDE_CHAR; + for i := FILTER_ENTRY_NODES to FILTER_EXIT_NODES do + sgFilter.Cells[i, sgFilter.SelRow] := ''; + NodesDic.AddOrSetValue(Key, [ntExclude]); + FilterInfo.Data := []; + ExcludeUpdated := True; + end + else + DeleteExclude; + end + else + begin + if sgFilter.Cells[sgFilter.SelCol, sgFilter.SelRow] = '' then + begin + DeleteExclude; + sgFilter.Cells[sgFilter.SelCol, sgFilter.SelRow] := SELECT_CHAR; + Include(FilterInfo.Data, FNodeType); + end + else + begin + sgFilter.Cells[sgFilter.SelCol, sgFilter.SelRow] := ''; + Exclude(FilterInfo.Data, FNodeType); + end; + end; + + FilterDic.AddOrSetValue(Key, FilterInfo); + CheckNodesListState(EXCLUDE_ID); + CalculateFilterNodes(False); + FilterUpdated := True; + EnableOptionButtons; +end; + +procedure TTcp.sgFilterKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + if (Key = VK_RETURN) and (sgFilter.SelCol > FILTER_PING) then + ChangeFilter; + GridKeyDown(sgFilter, Shift, Key); +end; + +procedure TTcp.sgFilterKeyPress(Sender: TObject; var Key: Char); +begin + if sgFilter.SelCol < FILTER_ENTRY_NODES then + FindInGridColumn(sgFilter, sgFilter.SelCol, Key); +end; + +procedure TTcp.sgFilterMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +var + CountryIndex: Integer; +begin + if Button = mbRight then + sgFilter.MouseToCell(X, Y, sgFilter.MovCol, sgFilter.MovRow); + + if (Button = mbLeft) and (ssDouble in Shift) then + begin + if (sgFilter.MovCol in [FILTER_TOTAL..FILTER_ALIVE]) and (sgFilter.MovRow > 0) and (sgFilter.Cells[sgFilter.MovCol, sgFilter.MovRow] <> NONE_CHAR) then + begin + LoadRoutersFilterData(LastRoutersFilter, False, True); + case sgFilter.MovCol of + FILTER_TOTAL: RoutersCustomFilter := FILTER_BY_TOTAL; + FILTER_GUARD: + begin + RoutersCustomFilter := FILTER_BY_GUARD; + IntToMenu(mnShowNodes.Items, 2); + end; + FILTER_EXIT: + begin + RoutersCustomFilter := FILTER_BY_EXIT; + IntToMenu(mnShowNodes.Items, 1); + end; + FILTER_ALIVE: + begin + RoutersCustomFilter := FILTER_BY_ALIVE; + IntToMenu(mnShowNodes.Items, 2048); + end; + end; + CountryIndex := FilterDic.Items[AnsiLowerCase(sgFilter.Cells[FILTER_ID, sgFilter.MovRow])].cc; + cbxRoutersCountry.ItemIndex := cbxRoutersCountry.Items.IndexOf(TransStr(CountryCodes[CountryIndex])); + cbxRoutersCountry.Tag := CountryIndex; + CheckShowRouters; + ShowRouters; + sbShowRouters.Click; + SaveRoutersFilterdata(False, False); + end; + end; + if (sgFilter.SelCol > FILTER_PING) and (sgFilter.MovRow > 0) and (Button = mbLeft) then + ChangeFilter; +end; + +procedure TTcp.sgFilterMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); +begin + sgFilter.MouseToCell(X, Y, sgFilter.MovCol, sgFilter.MovRow); + GridSetFocus(sgFilter); + GridShowHints(sgFilter); + GridCheckAutoPopup(sgFilter, sgFilter.MovRow); + if (sgFilter.MovCol in [FILTER_TOTAL..FILTER_ALIVE]) and (sgFilter.MovRow > 0) and (sgFilter.Cells[sgFilter.MovCol, sgFilter.MovRow] <> NONE_CHAR) then + sgFilter.Cursor := crHandPoint + else + sgFilter.Cursor := crDefault; +end; + +procedure TTcp.sgFilterSelectCell(Sender: TObject; ACol, ARow: Integer; + var CanSelect: Boolean); +begin + GridSelectCell(sgFilter, ACol, ARow); +end; + +procedure TTcp.sgHsDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); +begin + if ARow = 0 then + begin + case ACol of + HS_STATE: GridDrawIcon(sgHs, Rect, lsMain, 17); + else + if ACol < HS_STATE then + DrawText(sgHs.Canvas.Handle, PChar(HsHeader[ACol]), Length(HsHeader[ACol]), Rect, DT_CENTER); + end; + end; + GridScrollCheck(sgHs, HS_NAME, 163); +end; + +procedure TTcp.sgHsEnter(Sender: TObject); +begin + tsHs.Tag := 1; +end; + +procedure TTcp.sgHsKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); +begin + GridKeyDown(sgHs, Shift, Key); +end; + +procedure TTcp.sgHsPortsDrawCell(Sender: TObject; ACol, ARow: Integer; + Rect: TRect; State: TGridDrawState); +begin + if ARow = 0 then + DrawText(sgHsPorts.Canvas.Handle, PChar(HsPortsHeader[ACol]), Length(HsPortsHeader[ACol]), Rect, DT_CENTER); + GridScrollCheck(sgHsPorts, HSP_INTERFACE, 139); +end; + +procedure TTcp.sgHsPortsEnter(Sender: TObject); +begin + tsHs.Tag := 2; +end; + +procedure TTcp.sgHsPortsKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + GridKeyDown(sgHsPorts, Shift, Key); +end; + +procedure TTcp.sgHsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); +begin + sgHs.MouseToCell(X, Y, sgHs.MovCol, sgHs.MovRow); + GridSetFocus(sgHs); + GridShowHints(sgHs); + GridCheckAutoPopup(sgHs, sgHs.MovRow, True); +end; + +procedure TTcp.sgHsPortsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); +begin + sgHsPorts.MouseToCell(X, Y, sgHsPorts.MovCol, sgHsPorts.MovRow); + GridSetFocus(sgHsPorts); + GridShowHints(sgHsPorts); + GridCheckAutoPopup(sgHsPorts, sgHsPorts.MovRow, True); +end; + +procedure TTcp.UpdateTransports; +begin + if IsEmptyGrid(sgTransports) then + begin + edTransports.Text := ''; + edTransportsHandler.Text := ''; + cbxTransportType.ItemIndex := 0; + meHandlerParams.Clear; + TransportsEnable(False); + end; +end; + +procedure TTcp.UpdateHs; +begin + if IsEmptyGrid(sgHs) then + begin + ClearGrid(sgHsPorts); + edHsName.Text := ''; + cbxHsVersion.ItemIndex := HS_VERSION_3; + cbxHsState.ItemIndex := HS_STATE_DISABLED; + udHsNumIntroductionPoints.Position := 3; + cbHsMaxStreams.Checked := False; + cbxHsAddress.ItemIndex := 0; + udHsRealPort.Position := 80; + udHsVirtualPort.Position := 80; + HsControlsEnable(False); + end; +end; + +procedure TTcp.UpdateHsPorts; +var + i: Integer; + Ports: string; +begin + Ports := ''; + if IsEmptyGrid(sgHsPorts) then + begin + sgHs.Cells[HS_PORTS_DATA, sgHs.SelRow] := ''; + cbxHsAddress.ItemIndex := 0; + udHsRealPort.Position := 80; + udHsVirtualPort.Position := 80; + HsPortsEnable(False); + end + else + begin + for i := 1 to sgHsPorts.RowCount - 1 do + Ports := Ports + '|' + + sgHsPorts.Cells[HSP_INTERFACE, i] + ',' + + sgHsPorts.Cells[HSP_REAL_PORT, i] + ',' + + sgHsPorts.Cells[HSP_VIRTUAL_PORT, i]; + Delete(Ports, 1, 1); + sgHs.Cells[HS_PORTS_DATA, sgHs.SelRow] := Ports; + end; +end; + +procedure TTcp.sgHsSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); +begin + GridSelectCell(sgHs, ACol, ARow); + SelectHs; +end; + +procedure TTcp.sgRoutersDblClick(Sender: TObject); +begin + if (sgRouters.MovCol in [ROUTER_FLAG, ROUTER_COUNTRY]) and (sgRouters.MovRow > 0) then + FindInFilter(sgRouters.Cells[ROUTER_IP, sgRouters.MovRow]); +end; + +procedure TTcp.sgRoutersDrawCell(Sender: TObject; ACol, ARow: Integer; + Rect: TRect; State: TGridDrawState); +var + RouterID: string; + RouterInfo: TRouterInfo; + Indent, Mask, Interval: Integer; + + procedure DrawFlagIcon(Flag: Byte; Index: Integer); + begin + if Mask and Flag <> 0 then + begin + lsMenus.Draw(sgRouters.Canvas, Rect.Left + (Rect.Width - Indent) div 2 + Interval, Rect.Top + (Rect.Height - 16) div 2, Index, True); + Inc(Interval, 16); + end; + end; + +begin + if ARow = 0 then + begin + if ACol = ROUTER_WEIGHT then + Rect.Right := Rect.Right + 2; + case ACol of + ROUTER_FLAG: GridDrawIcon(sgRouters, Rect, lsMain, 6); + ROUTER_ENTRY_NODES: GridDrawIcon(sgRouters, Rect, lsMain, 7); + ROUTER_MIDDLE_NODES: GridDrawIcon(sgRouters, Rect, lsMain, 8); + ROUTER_EXIT_NODES: GridDrawIcon(sgRouters, Rect, lsMain, 9); + ROUTER_EXCLUDE_NODES: GridDrawIcon(sgRouters, Rect, lsMain, 10); + else + DrawText(sgRouters.Canvas.Handle, PChar(RoutersHeader[ACol - 1]), Length(RoutersHeader[ACol - 1]), Rect, DT_CENTER); + end; + if (ACol = sgRouters.SortCol) and (ACol < ROUTER_ENTRY_NODES) then + GridDrawSortArrows(sgRouters, Rect); + end; + if ARow > 0 then + begin + if ACol = ROUTER_FLAG then + begin + if sgRouters.Cells[ROUTER_IP, ARow] <> '' then + GridDrawIcon(sgRouters, Rect, lsFlags, GetCountryValue(sgRouters.Cells[ROUTER_IP, ARow]), 20, 13); + end; + if ACol = ROUTER_FLAGS then + begin + RouterID := sgRouters.Cells[ROUTER_ID, ARow]; + + if RoutersDic.TryGetValue(RouterID, RouterInfo) then + begin + Mask := RouterInfo.Params; + if Mask <> 0 then + begin + Interval := 0; + Indent := GetRoutersParamsCount(Mask) * 16; + DrawFlagIcon(ROUTER_BRIDGE, 28); + DrawFlagIcon(ROUTER_AUTHORITY, 54); + DrawFlagIcon(ROUTER_ALIVE, 56); + DrawFlagIcon(ROUTER_REACHABLE_IPV6, 34); + DrawFlagIcon(ROUTER_HS_DIR, 53); + DrawFlagIcon(ROUTER_DIR_MIRROR, 38); + DrawFlagIcon(ROUTER_NOT_RECOMMENDED, 44); + DrawFlagIcon(ROUTER_BAD_EXIT, 43); + end; + end; + end; + end; +end; + +procedure TTcp.sgRoutersFixedCellClick(Sender: TObject; ACol, ARow: Integer); +begin + if ACol = ROUTER_FLAG then + Exit; + SortPrepare(sgRouters, ACol, True); +end; + +procedure TTcp.sgRoutersKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + if (Key = VK_RETURN) and (sgRouters.SelCol > ROUTER_FLAGS) then + ChangeRouters; + GridKeyDown(sgRouters, Shift, Key); +end; + +procedure TTcp.sgRoutersKeyPress(Sender: TObject; var Key: Char); +begin + if sgRouters.SelCol < ROUTER_FLAGS then + FindInGridColumn(sgRouters, sgRouters.SelCol, Key); +end; + +procedure TTcp.sgRoutersMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + if Button = mbRight then + sgRouters.MouseToCell(X, Y, sgRouters.MovCol, sgRouters.MovRow); + + if (sgRouters.SelCol > ROUTER_FLAGS) and (sgRouters.MovRow > 0) and (Button = mbLeft) then + ChangeRouters; +end; + +function TTcp.GetFilterLabel(FilterID: Integer): TLabel; +begin + case FilterID of + FILTER_ENTRY_NODES: Result := lbFilterEntry; + FILTER_MIDDLE_NODES: Result := lbFilterMiddle; + FILTER_EXIT_NODES: Result := lbFilterExit; + FILTER_EXCLUDE_NODES: Result := lbFilterExclude; + else + Result := nil; + end; +end; + +function TTcp.GetFavoritesLabel(FavoritesID: Integer): TLabel; +begin + case FavoritesID of + ENTRY_ID: Result := lbFavoritesEntry; + MIDDLE_ID: Result := lbFavoritesMiddle; + EXIT_ID: Result := lbFavoritesExit; + EXCLUDE_ID: Result := lbExcludeNodes; + FAVORITES_ID: Result := lbFavoritesTotal; + else + Result := nil; + end; +end; + +procedure TTcp.ChangeRouters; +var + i: Integer; + Key, CountryCode, FindCidr, NodeStr, SelData, ConvertMsg: string; + FNodeTypes: TNodeTypes; + NodeTypeID: TNodeType; + RouterInfo: TRouterInfo; + NodesList: TStringList; + HashMode, FindCountry, ConvertNodes: Boolean; + PreferredBridge: TBridge; + ItemID: TListType; + Nodes: ArrOfNodes; + + function IsHashMode: Boolean; + begin + case NodesList.Count of + 0: Result := True; + 1: Result := ValidHash(NodesList[0]); + else + Result := False; + end; + end; + + procedure FindNode(NodeStr: string; NodeType: TNodeType; IsCountry: Boolean = False); + begin + if NodesDic.ContainsKey(NodeStr) then + begin + if NodeType in NodesDic.Items[NodeStr] then + begin + if IsCountry then + begin + NodesList.Append(AnsiUpperCase(NodeStr) + ' (' + TransStr(NodeStr) + ')'); + FindCountry := True; + end + else + NodesList.Append(NodeStr); + end; + end; + end; + + procedure CreateNodesList(NodeType: TNodeType); + var + i: Integer; + ParseStr: ArrOfStr; + begin + NodesList.Clear; + FindNode(Key, NodeType); + FindNode(RouterInfo.IPv4, NodeType); + FindCidr := FindInRanges(RouterInfo.IPv4); + if FindCidr <> '' then + begin + ParseStr := Explode(',', FindCidr); + for i := 0 to Length(ParseStr) - 1 do + FindNode(ParseStr[i], NodeType); + SortNodesList(NodesList, True); + end; + FindNode(CountryCode, NodeType, True); + end; + +begin + if ConnectState = 1 then + Exit; + Key := sgRouters.Cells[ROUTER_ID, sgRouters.SelRow]; + SelData := sgRouters.Cells[sgRouters.SelCol, sgRouters.SelRow]; + if (SelData = NONE_CHAR) or (SelData = BOTH_CHAR) then + Exit; + if RoutersDic.TryGetValue(Key, RouterInfo) then + begin + + FindCountry := False; + NodeTypeID := TNodeType(sgRouters.SelCol); + CountryCode := CountryCodes[GetCountryValue(RouterInfo.IPv4)]; + + NodesList := TStringList.Create; + try + NodesList.QuoteChar := #0; + CreateNodesList(NodeTypeID); + HashMode := IsHashMode; + if HashMode then + begin + NodesDic.TryGetValue(Key, FNodeTypes); + if SelData = '' then + begin + if sgRouters.SelCol = ROUTER_EXCLUDE_NODES then + begin + sgRouters.Cells[ROUTER_EXCLUDE_NODES, sgRouters.SelRow] := EXCLUDE_CHAR; + for i := ROUTER_ENTRY_NODES to ROUTER_EXIT_NODES do + begin + if sgRouters.Cells[i, sgRouters.SelRow] <> NONE_CHAR then + begin + CreateNodesList(TNodeType(i)); + if IsHashMode then + begin + if CheckRouterFlags(i, RouterInfo) then + sgRouters.Cells[i, sgRouters.SelRow] := '' + else + sgRouters.Cells[i, sgRouters.SelRow] := NONE_CHAR; + end + else + sgRouters.Cells[i, sgRouters.SelRow] := FAVERR_CHAR; + end; + end; + FNodeTypes := []; + end + else + begin + if sgRouters.Cells[ROUTER_EXCLUDE_NODES, sgRouters.SelRow] = EXCLUDE_CHAR then + sgRouters.Cells[sgRouters.SelCol, sgRouters.SelRow] := FAVERR_CHAR + else + sgRouters.Cells[sgRouters.SelCol, sgRouters.SelRow] := SELECT_CHAR; + end; + Include(FNodeTypes, NodeTypeID); + end + else + begin + if sgRouters.SelCol = ROUTER_EXCLUDE_NODES then + begin + sgRouters.Cells[ROUTER_EXCLUDE_NODES, sgRouters.SelRow] := ''; + for i := ROUTER_ENTRY_NODES to ROUTER_EXIT_NODES do + begin + if sgRouters.Cells[i, sgRouters.SelRow] <> NONE_CHAR then + begin + if (sgRouters.Cells[i, sgRouters.SelRow] = FAVERR_CHAR) and CheckRouterFlags(i, RouterInfo) then + sgRouters.Cells[i, sgRouters.SelRow] := SELECT_CHAR; + end; + end; + end + else + begin + if (SelData = FAVERR_CHAR) and not CheckRouterFlags(Integer(NodeTypeID), RouterInfo) then + sgRouters.Cells[sgRouters.SelCol, sgRouters.SelRow] := NONE_CHAR + else + sgRouters.Cells[sgRouters.SelCol, sgRouters.SelRow] := ''; + end; + Exclude(FNodeTypes, NodeTypeID); + end; + NodesDic.AddOrSetValue(Key, FNodeTypes); + end + else + begin + if SelData <> '' then + begin + ConvertNodes := PrepareNodesToRemove(NodesList.DelimitedText, NodeTypeID, Nodes);; + if ConvertNodes then + ConvertMsg := BR + BR + TransStr('146') + else + ConvertMsg := ''; + if ShowMsg(Format(TransStr('362'), [StringReplace(NodesList.DelimitedText, ',', BR, [rfReplaceAll]), TransStr(GetFavoritesLabel(Integer(NodeTypeID)).Hint), ConvertMsg]), '', mtQuestion, True) then + begin + for i := 0 to NodesList.Count - 1 do + begin + NodeStr := SeparateLeft(NodesList[i], ' '); + ItemID := GetNodeType(NodeStr); + if ItemID = ltCode then + NodeStr := AnsiLowerCase(NodeStr); + if NodesDic.TryGetValue(NodeStr, FNodeTypes) then + begin + Exclude(FNodeTypes, NodeTypeID); + NodesDic.AddOrSetValue(NodeStr, FNodeTypes); + end; + end; + if ConvertNodes then + RemoveFromNodesListWithConvert(Nodes, NodeTypeID); + end + else + Exit; + end; + end; + finally + NodesList.Free; + end; + if TryParseBridge(edPreferredBridge.Text, PreferredBridge) then + CheckPrefferedBridgeExclude(PreferredBridge.Hash); + CheckNodesListState(Integer(NodeTypeID)); + CalculateTotalNodes(False); + if not HashMode then + begin + ShowRouters; + FilterUpdated := FindCountry; + end; + RoutersUpdated := True; + EnableOptionButtons; + end; +end; + +procedure TTcp.ShowRoutersParamsHint; +var + RouterInfo: TRouterInfo; + Mask, MaxItems: Integer; + Fail: Boolean; + CellRect, CellPoint: TRect; + Data: array of Byte; + ArrayIndex: Integer; + + procedure CheckMask(Param: Integer); + begin + if Mask and Param <> 0 then + begin + SetLength(Data, MaxItems + 1); + Data[MaxItems] := Param; + Inc(MaxItems); + end; + end; + +begin + Fail := True; + if not IsEmptyRow(sgRouters, sgRouters.MovRow) then + begin + if RoutersDic.TryGetValue(sgRouters.Cells[ROUTER_ID, sgRouters.MovRow], RouterInfo) then + begin + Mask := RouterInfo.Params; + if Mask > 0 then + begin + MaxItems := 0; + CheckMask(ROUTER_BRIDGE); + CheckMask(ROUTER_AUTHORITY); + CheckMask(ROUTER_ALIVE); + CheckMask(ROUTER_REACHABLE_IPV6); + CheckMask(ROUTER_HS_DIR); + CheckMask(ROUTER_DIR_MIRROR); + CheckMask(ROUTER_NOT_RECOMMENDED); + CheckMask(ROUTER_BAD_EXIT); + + CellRect := sgRouters.CellRect(9, sgRouters.MovRow); + CellPoint := sgRouters.ClientToScreen(CellRect); + + ArrayIndex := (Mouse.CursorPos.X - CellPoint.Left - (CellRect.Width - MaxItems * 16) div 2); + if InRange(ArrayIndex, 0, MaxItems * 16) then + begin + case Data[ArrayIndex div 16] of + ROUTER_BRIDGE: sgRouters.Hint := TransStr('384'); + ROUTER_AUTHORITY: sgRouters.Hint := TransStr('385'); + ROUTER_ALIVE: sgRouters.Hint := TransStr('386'); + ROUTER_REACHABLE_IPV6: sgRouters.Hint := TransStr('387'); + ROUTER_HS_DIR: sgRouters.Hint := TransStr('388'); + ROUTER_DIR_MIRROR: sgRouters.Hint := Format(TransStr('389'), [RouterInfo.DirPort]); + ROUTER_NOT_RECOMMENDED: sgRouters.Hint := TransStr('390'); + ROUTER_BAD_EXIT: sgRouters.Hint := TransStr('391'); + else + sgRouters.Hint := TransStr('392'); + end; + Application.ActivateHint(Mouse.CursorPos); + Exit; + end; + end; + end; + end; + + if Fail then + begin + Application.CancelHint; + sgRouters.Hint := ''; + end; +end; + +procedure TTcp.sgRoutersMouseMove(Sender: TObject; Shift: TShiftState; X, + Y: Integer); +begin + sgRouters.MouseToCell(X, Y, sgRouters.MovCol, sgRouters.MovRow); + if not (edRoutersQuery.Focused or edRoutersWeight.Focused) then + GridSetFocus(sgRouters); + if miShowFlagsHint.Checked and (sgRouters.MovCol = ROUTER_FLAGS) then + ShowRoutersParamsHint + else + GridShowHints(sgRouters); + GridCheckAutoPopup(sgRouters, sgRouters.MovRow, True); + if (sgRouters.MovCol in [ROUTER_FLAG, ROUTER_COUNTRY]) and (sgRouters.MovRow > 0) and not IsEmptyRow(sgRouters, sgRouters.MovRow) then + sgRouters.Cursor := crHandPoint + else + sgRouters.Cursor := crDefault; +end; + +procedure TTcp.sgRoutersSelectCell(Sender: TObject; ACol, ARow: Integer; + var CanSelect: Boolean); +begin + GridSelectCell(sgRouters, ACol, ARow); +end; + +procedure TTcp.sgStreamsInfoDrawCell(Sender: TObject; ACol, ARow: Integer; + Rect: TRect; State: TGridDrawState); +begin + if ARow = 0 then + begin + if ACol > 0 then + begin + case ACol of + STREAMS_INFO_BYTES_READ: GridDrawIcon(sgStreamsInfo, Rect, lsMain, 15); + STREAMS_INFO_BYTES_WRITTEN: GridDrawIcon(sgStreamsInfo, Rect, lsMain, 16); + else + DrawText(sgStreamsInfo.Canvas.Handle, PChar(StreamsInfoHeader[ACol - 1]), Length(StreamsInfoHeader[ACol - 1]), Rect, DT_CENTER); + end; + if ACol = sgStreamsInfo.SortCol then + GridDrawSortArrows(sgStreamsInfo, Rect); + end; + end; +end; + +procedure TTcp.sgStreamsInfoFixedCellClick(Sender: TObject; ACol, + ARow: Integer); +begin + miStreamsInfoSort.Items[ACol].Checked := True; + SortPrepare(sgStreamsInfo, ACol, True); +end; + +procedure TTcp.sgStreamsInfoKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + GridKeyDown(sgStreamsInfo, Shift, Key); + case Key of + VK_F5: ShowCircuits; + end; +end; + +procedure TTcp.sgStreamsInfoMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + if Button = mbRight then + sgStreamsInfo.MouseToCell(X, Y, sgStreamsInfo.MovCol, sgStreamsInfo.MovRow); +end; + +procedure TTcp.sgStreamsInfoMouseMove(Sender: TObject; Shift: TShiftState; X, + Y: Integer); +begin + sgStreamsInfo.MouseToCell(X, Y, sgStreamsInfo.MovCol, sgStreamsInfo.MovRow); + GridSetFocus(sgStreamsInfo); + GridShowHints(sgStreamsInfo); + GridCheckAutoPopup(sgStreamsInfo, sgStreamsInfo.MovRow, True); +end; + +procedure TTcp.sgStreamsInfoSelectCell(Sender: TObject; ACol, ARow: Integer; + var CanSelect: Boolean); +begin + GridSelectCell(sgStreamsInfo, ACol, ARow); +end; + +procedure TTcp.sgStreamsDblClick(Sender: TObject); +begin + if (sgStreams.MovRow > 0) and (sgStreams.MovCol = STREAMS_TARGET) then + ShellOpen(sgStreams.Cells[STREAMS_TARGET, sgStreams.SelRow]); +end; + +procedure TTcp.sgStreamsDrawCell(Sender: TObject; ACol, ARow: Integer; + Rect: TRect; State: TGridDrawState); +begin + if ARow = 0 then + begin + if ACol > 0 then + begin + case ACol of + STREAMS_TRACK: GridDrawIcon(sgStreams, Rect, lsMain, 11); + STREAMS_COUNT: GridDrawIcon(sgStreams, Rect, lsMain, 8); + STREAMS_BYTES_READ: GridDrawIcon(sgStreams, Rect, lsMain, 15); + STREAMS_BYTES_WRITTEN: GridDrawIcon(sgStreams, Rect, lsMain, 16); + else + DrawText(sgStreams.Canvas.Handle, PChar(StreamsHeader[ACol - 1]), Length(StreamsHeader[ACol - 1]), Rect, DT_CENTER); + end; + if (ACol = sgStreams.SortCol) and (ACol in [STREAMS_TARGET, STREAMS_BYTES_READ, STREAMS_BYTES_WRITTEN]) then + GridDrawSortArrows(sgStreams, Rect); + end; + end; +end; + +procedure TTcp.sgStreamsKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + GridKeyDown(sgStreams, Shift, Key); + case Key of + VK_F5: ShowCircuits; + end; +end; + +procedure TTcp.sgStreamsMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + if Button = mbRight then + sgStreams.MouseToCell(X, Y, sgStreams.MovCol, sgStreams.MovRow); +end; + +procedure TTcp.sgStreamsMouseMove(Sender: TObject; Shift: TShiftState; X, + Y: Integer); +begin + sgStreams.MouseToCell(X, Y, sgStreams.MovCol, sgStreams.MovRow); + GridSetFocus(sgStreams); + GridShowHints(sgStreams); + GridCheckAutoPopup(sgStreams, sgStreams.MovRow, True); + if (sgStreams.MovCol = STREAMS_TARGET) and (sgStreams.MovRow > 0) and not IsEmptyRow(sgStreams, sgStreams.MovRow) then + sgStreams.Cursor := crHandPoint + else + sgStreams.Cursor := crDefault; +end; + +procedure TTcp.sgStreamsSelectCell(Sender: TObject; ACol, ARow: Integer; + var CanSelect: Boolean); +begin + GridSelectCell(sgStreams, ACol, ARow); + ShowStreamsInfo(sgCircuits.Cells[CIRC_ID, sgCircuits.SelRow], sgStreams.Cells[STREAMS_TARGET, sgStreams.SelRow]); +end; + +procedure TTcp.sgTransportsDrawCell(Sender: TObject; ACol, ARow: Integer; + Rect: TRect; State: TGridDrawState); +begin + if (ARow = 0) and (ACol < PT_PARAMS) then + DrawText(sgTransports.Canvas.Handle, PChar(TransportsHeader[ACol]), Length(TransportsHeader[ACol]), Rect, DT_CENTER); + GridScrollCheck(sgTransports, PT_TRANSPORTS, 179); +end; + +procedure TTcp.sgTransportsKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + GridKeyDown(sgTransports, Shift, Key); +end; + +procedure TTcp.sgTransportsMouseMove(Sender: TObject; Shift: TShiftState; X, + Y: Integer); +begin + sgTransports.MouseToCell(X, Y, sgTransports.MovCol, sgTransports.MovRow); + GridSetFocus(sgTransports); + GridShowHints(sgTransports); + GridCheckAutoPopup(sgTransports, sgTransports.MovRow, True); +end; + +procedure TTcp.sgTransportsSelectCell(Sender: TObject; ACol, ARow: Integer; + var CanSelect: Boolean); +begin + GridSelectCell(sgTransports, ACol, ARow); + SelectTransports; +end; + +procedure TTcp.sgHsPortsSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean); +begin + GridSelectCell(sgHsPorts, ACol, ARow); + SelectHsPorts; +end; + +procedure TTcp.SelectHs; +var + i: Integer; + ParseStr, Items: ArrOfStr; +begin + if sgHs.SelRow = 0 then + sgHs.SelRow := 1; + if IsEmptyRow(sgHs, sgHs.SelRow) then + Exit; + edHsName.Text := sgHs.Cells[HS_NAME, sgHs.SelRow]; + case StrToIntDef(sgHs.Cells[HS_VERSION, sgHs.SelRow], HS_VERSION_3) of + 2: cbxHsVersion.ItemIndex := HS_VERSION_2; + 3: cbxHsVersion.ItemIndex := HS_VERSION_3; + end; + if sgHs.Cells[HS_STATE, sgHs.SelRow] = SELECT_CHAR then + cbxHsState.ItemIndex := HS_STATE_ENABLED + else + cbxHsState.ItemIndex := HS_STATE_DISABLED; + udHsNumIntroductionPoints.Position := StrToInt(sgHs.Cells[HS_INTRO_POINTS, sgHs.SelRow]); + CheckHsVersion; + if sgHs.Cells[HS_MAX_STREAMS, sgHs.SelRow] = NONE_CHAR then + begin + cbHsMaxStreams.Checked := False; + HsMaxStreamsEnable(False); + end + else + begin + cbHsMaxStreams.Checked := True; + HsMaxStreamsEnable(True); + udHsMaxStreams.Position := StrToInt(sgHs.Cells[HS_MAX_STREAMS, sgHs.SelRow]); + end; + if sgHs.Cells[HS_PORTS_DATA, sgHs.SelRow] <> '' then + begin + Items := Explode('|', sgHs.Cells[HS_PORTS_DATA, sgHs.SelRow]); + sgHsPorts.RowCount := Length(Items) + 1; + for i := 0 to Length(Items) - 1 do + begin + ParseStr := Explode(',', Items[i]); + sgHsPorts.Cells[HSP_INTERFACE, i + 1] := ParseStr[0]; + sgHsPorts.Cells[HSP_REAL_PORT, i + 1] := ParseStr[1]; + sgHsPorts.Cells[HSP_VIRTUAL_PORT, i + 1] := ParseStr[2]; + end; + SelectHsPorts; + HsPortsEnable(True); + end + else + begin + ClearGrid(sgHsPorts); + HsPortsEnable(False); + end; +end; + +procedure TTcp.SelectHsPorts; +begin + if sgHsPorts.SelRow = 0 then + sgHsPorts.SelRow := 1; + if IsEmptyRow(sgHsPorts, sgHsPorts.SelRow) then + Exit; + cbxHsAddress.ItemIndex := cbxHsAddress.Items.IndexOf(sgHsPorts.Cells[HSP_INTERFACE, sgHsPorts.SelRow]); + udHsRealPort.Position := StrToInt(sgHsPorts.Cells[HSP_REAL_PORT, sgHsPorts.SelRow]); + udHsVirtualPort.Position := StrToInt(sgHsPorts.Cells[HSP_VIRTUAL_PORT, sgHsPorts.SelRow]); +end; + +procedure TTcp.SelectTransports; +begin + if sgTransports.SelRow = 0 then + sgTransports.SelRow := 1; + edTransports.Text := sgTransports.Cells[PT_TRANSPORTS, sgTransports.SelRow]; + edTransportsHandler.Text := sgTransports.Cells[PT_HANDLER, sgTransports.SelRow]; + meHandlerParams.Text := sgTransports.Cells[PT_PARAMS, sgTransports.SelRow]; + cbxTransportType.ItemIndex := GetTransportID(sgTransports.Cells[PT_TYPE, sgTransports.SelRow]); +end; + +procedure TTcp.SelectorMenuClick(Sender: TObject); +var + i: Integer; + Parent: TMenuItem; + State, HandleDisabled: Boolean; +begin + State := Boolean(TMenuItem(Sender).Tag); + Parent := TMenuItem(Sender).Parent; + HandleDisabled := Boolean(TMenuItem(Sender).HelpContext); + + for i := 0 to Parent.Count - 1 do + begin + if Parent.Items[i].AutoCheck and (Parent.Items[i].Enabled or HandleDisabled) then + Parent.Items[i].Checked := State; + end; + case Parent.Tag of + 1: SetRoutersFilter(Sender); + 2: SetRoutersFilterState(Sender); + 3: SetCircuitsFilter(Sender); + 4: miTplSaveClick(Sender); + 5: miTplLoadClick(Sender); + end; +end; + +procedure TTcp.EnableOptionButtons(State: Boolean = True); +begin + if State and OptionsLocked then + Exit; + btnApplyOptions.Enabled := State; + btnCancelOptions.Enabled := State; + OptionsChanged := State; +end; + +procedure TTcp.ShowBalloon(Msg: string; Title: string = ''; Notice: Boolean = False; MsgType: TMsgType = mtInfo); +var + MsgIcon: TBalloonFlags; +begin + MsgIcon := bfNone; + case MsgType of + mtInfo: MsgIcon := bfInfo; + mtWarning: MsgIcon := bfWarning; + mtError: MsgIcon := bfError; + end; + if (Notice or ((cbShowBalloonHint.Checked) and (not cbShowBalloonOnlyWhenHide.Checked or + (cbShowBalloonOnlyWhenHide.Checked and Visible = False)))) and not Closing then + begin + tiTray.BalloonFlags := MsgIcon; + tiTray.BalloonTitle := GetMsgCaption(Title, MsgType); + tiTray.BalloonHint := Msg; + tiTray.ShowBalloonHint; + end; +end; + +procedure TTcp.SendDataThroughProxy; +var + Http: TSendHttpThread; +begin + if cbEnableSocks.Checked and (ConnectState = 2) then + begin + Http := TSendHttpThread.Create(True); + Http.FreeOnTerminate := True; + Http.Priority := tpNormal; + Http.Start; + end; +end; + +procedure TTcp.GetDNSExternalAddress(UpdateExternalIp: Boolean = True); +var + Dns: TDNSSendThread; +begin + if not UpdateExternalIp then + begin + if ValidAddress(ServerIPv4) = 1 then + begin + GetIpStage := 0; + UpdateServerInfo; + Exit; + end; + end; + Dns := TDNSSendThread.Create(True); + Dns.FreeOnTerminate := True; + Dns.Priority := tpNormal; + Dns.Start; +end; + +procedure TTcp.GetServerInfo(UpdateExternalIp: Boolean = True); +begin + if cbxServerMode.ItemIndex > 0 then + begin + GetIpStage := 1; + if cbUseOpenDNS.Checked and not cbUseOpenDNSOnlyWhenUnknown.Checked then + GetDNSExternalAddress(UpdateExternalIp) + else + begin + if ConnectState = 2 then + begin + if UpdateExternalIp then + SendCommand('GETINFO address') + end + else + UpdateServerInfo; + end; + end; +end; + +procedure TTcp.UpdateServerInfo; +var + Fingerprint, ServerIp, BridgeStr: string; + IsIPv4, IsIPv6, IsFingerprint, ServerIsBridge: Boolean; + + function ReplaceIp(Str: string): string; + begin + Result := StringReplace(Str, ServerIPv4, FormatHost(ServerIPv6), [rfReplaceAll]); + end; + +begin + miServerCopyBridgeIPv4.Visible := False; + miServerCopyBridgeIPv6.Visible := False; + miServerCopyBridgeIPv4.Hint := ''; + miServerCopyBridgeIPv6.Hint := ''; + + Fingerprint := SeparateRight(Trim(FileGetString(UserDir + 'fingerprint')), ' '); + IsFingerprint := ValidHash(Fingerprint); + if IsFingerprint then + lbFingerprint.Caption := Fingerprint + else + lbFingerprint.Caption := TransStr('260'); + miServerCopyFingerprint.Caption := Fingerprint; + miServerCopyFingerprint.Visible := IsFingerprint; + + IsIPv4 := ValidAddress(ServerIPv4) = 1; + IsIPv6 := (ValidAddress(ServerIPv6) = 2) and cbListenIPv6.Checked; + ServerIsBridge := cbxServerMode.ItemIndex = 3; + + miServerCopyIPv4.Caption := ServerIPv4; + miServerCopyIPv6.Caption := FormatHost(ServerIPv6); + miServerCopyIPv4.Visible := IsIPv4; + miServerCopyIPv6.Visible := IsIPv6; + + if IsIPv4 then + begin + if IsIPv6 then + ServerIp := ServerIPv4 + ', ' + FormatHost(ServerIPv6) + else + ServerIp := ServerIPv4; + lbServerExternalIp.Caption := ServerIp; + + if ServerIsBridge and IsFingerprint then + begin + if cbxBridgeType.ItemIndex = 0 then + BridgeStr := ServerIPv4 + ':' + edORPort.Text + ' ' + lbFingerprint.Caption + else + begin + BridgeStr := cbxBridgeType.Text + ' ' + ServerIPv4 + ':' + edTransportPort.Text + ' ' + lbFingerprint.Caption; + if ServerIsObfs4 then + begin + miServerCopyBridgeIPv4.Hint := BridgeStr + ' ' + GetBridgeCert; + BridgeStr := BridgeStr + '...'; + end; + end; + miServerCopyBridgeIPv4.Caption := BridgeStr; + + if IsIPv6 then + begin + lbBridge.Caption := BridgeStr + BR + ReplaceIp(BridgeStr); + miServerCopyBridgeIPv6.Hint := ReplaceIp(miServerCopyBridgeIPv4.Hint); + miServerCopyBridgeIPv6.Caption := ReplaceIp(BridgeStr); + end + else + lbBridge.Caption := BridgeStr; + + miServerCopyBridgeIPv4.Visible := True; + miServerCopyBridgeIPv6.Visible := IsIPv6; + end + end + else + begin + lbServerExternalIp.Caption := TransStr('260'); + lbBridge.Caption := TransStr('260'); + end; +end; + +procedure TTcp.InitPortForwarding(Test: Boolean); +var + i: Integer; +begin + UPnPMsg := ''; + GetLocalInterfaces(cbxSocksHost); + if (cbxServerMode.ItemIndex > 0) and (cbUseUPnP.Checked) then + begin + for i := 0 to cbxSocksHost.items.Count - 1 do + begin + if not IpInRanges(cbxSocksHost.Items[i], PrivateRanges) then + Continue; + AddUPnPEntry(udORPort.Position, 'ORPort', cbxSocksHost.Items[i], Test, UPnPMsg); + udORPort.Tag := udORPort.Position; + if cbUseDirPort.Checked then + begin + AddUPnPEntry(udDirPort.Position, 'DirPort', cbxSocksHost.Items[i], Test, UPnPMsg); + udDirPort.Tag := udDirPort.Position; + end; + if (cbxServerMode.ItemIndex = 3) and (cbxBridgeType.ItemIndex > 0) then + begin + AddUPnPEntry(udTransportPort.Position, 'PTPort', cbxSocksHost.Items[i], Test, UPnPMsg); + udTransportPort.Tag := udTransportPort.Position; + end; + end; + end; +end; + +procedure TTcp.LogListenerStart(hStdOut: THandle); +begin + if not Assigned(Logger) then + begin + Logger := TReadPipeThread.Create(True); + Logger.hStdOut := hStdOut; + Logger.FreeOnTerminate := True; + Logger.Priority := tpNormal; + Logger.OnTerminate := LogThreadTerminate; + Logger.Start; + end; +end; + +procedure TTcp.CheckVersionStart(hStdOut: THandle); +begin + if not Assigned(VersionChecker) then + begin + VersionChecker := TReadPipeThread.Create(True); + VersionChecker.hStdOut := hStdOut; + VersionChecker.VersionCheck := True; + VersionChecker.FreeOnTerminate := True; + VersionChecker.Priority := tpNormal; + VersionChecker.OnTerminate := VersionCheckerThreadTerminate; + VersionChecker.Start; + end; +end; + +procedure TTcp.ControlPortConnect; +begin + if not Assigned(Controller) then + begin + Controller := TControlThread.Create(True); + Controller.FreeOnTerminate := True; + Controller.Priority := tpNormal; + Controller.OnTerminate := ControlThreadTerminate; + Controller.Start; + end; +end; + +procedure TTcp.CheckOpenPorts(PortSpin: TUpDown; IP: string; var PortStr: string); +var + Port: Integer; +begin + if PortTCPIsOpen(PortSpin.Position, IP, 1) then + begin + PortStr := PortStr + ', ' + IntToStr(PortSpin.Position); + Randomize; + repeat + Port := RandomRange(9000, 10000) + until not PortTCPIsOpen(Port, IP, 1); + PortSpin.Position := Port; + end; +end; + +procedure TTcp.CheckStatusControls; +var + ServerIsBridge, ServerEnabled: Boolean; +begin + if cbEnableSocks.Checked then + lbStatusProxyAddr.Caption := FormatHost(GetHost(cbxSocksHost)) + ':' + IntToStr(udSOCKSPort.Position) + else + lbStatusProxyAddr.Caption := TransStr('226'); + CheckLabelEndEllipsis(lbStatusProxyAddr, 300, epPathEllipsis, False, True); + + ServerEnabled := cbxServerMode.ItemIndex > 0; + ServerIsBridge := cbxServerMode.ItemIndex = 3; + + lbBridge.Visible := ServerIsBridge; + lbBridgeCaption.Visible := ServerIsBridge; + gbServerInfo.Visible := ServerEnabled; + if ServerEnabled then + GetServerInfo(False); + + if cbEnablePingMeasure.Checked or cbEnableDetectAliveNodes.Checked then + begin + if cbAutoScanNewNodes.Checked then + lbStatusScanner.Caption := TransStr('380') + else + lbStatusScanner.Caption := TransStr('381') + end + else + lbStatusScanner.Caption := TransStr('226'); + + if TorVersion = '0.0.0.0' then + lbClientVersion.Caption := TransStr('110') + else + lbClientVersion.Caption := TorVersion; +end; + +procedure TTcp.SetOptionsEnable(State: Boolean); +var + i: Integer; +begin + for i := 0 to pcOptions.PageCount - 1 do + pcOptions.Pages[i].Enabled := State; +end; + +procedure TTcp.CheckOptionsChanged; +var + TorrcDate: TDateTime; + TorrcChanged: Boolean; +begin + FileAge(TorConfigFile, TorrcDate); + TorrcChanged := TorrcDate <> LastTorrcDate; + if OptionsChanged or TorrcChanged then + begin + if Restarting or TorrcChanged then + ResetOptions + else + begin + if ShowMsg(TransStr('354'), '', mtWarning, True) then + begin + if NodesListStage = 1 then + SaveNodesList(cbxNodesListType.ItemIndex); + ApplyOptions(True); + end + else + ResetOptions; + end; + end; +end; + +procedure TTcp.StartTor(AutoResolveErrors: Boolean = False); +var + PortStr, Msg: string; +begin + CheckOptionsChanged; + if FileExists(TorExeFile) then + begin + PortStr := ''; + OptionsLocked := True; + ForceDirectories(LogsDir); + ForceDirectories(OnionAuthDir); + CheckOpenPorts(udSOCKSPort, cbxSocksHost.Text, PortStr); + CheckOpenPorts(udControlPort, '127.0.0.1', PortStr); + if cbxServerMode.ItemIndex > 0 then + begin + CheckOpenPorts(udORPort, '127.0.0.1', PortStr); + if cbUseDirPort.Checked then + CheckOpenPorts(udDirPort, '127.0.0.1', PortStr); + if cbxBridgeType.ItemIndex > 0 then + CheckOpenPorts(udTransportPort, '127.0.0.1', PortStr); + end; + Delete(PortStr, 1, 1); + if PortStr <> '' then + begin + if ShowMsg(Format(TransStr('259'), [PortStr]), TransStr('246'), mtWarning, True) then + ApplyOptions + else + begin + ResetOptions; + Exit; + end; + end; + OptionsLocked := False; + FileAge(UserDir + 'control_auth_cookie', LastAuthCookieDate); + TorMainProcess := ExecuteProcess(TorExeFile + ' -f "' + TorConfigFile + '"', [pfHideWindow, pfReadStdOut], hJob); + if TorMainProcess.hProcess <> 0 then + begin + if CheckFileVersion(TorVersion, '0.4.0.5') then + begin + StopCode := STOP_NORMAL; + if miAutoClear.Checked then + meLog.Clear; + StreamsDic.Clear; + CircuitsDic.Clear; + ExitNodeID := ''; + Circuit := ''; + DLSpeed := 0; + ULSpeed := 0; + SessionDL := 0; + SessionUL := 0; + MaxDLSpeed := 0; + MaxULSpeed := 0; + ConnectState := 1; + TotalsNeedSave := False; + GeoIpUpdating := False; + SelectExitCircuit := False; + LockCircuits := False; + LockCircuitInfo := False; + LockStreams := False; + LockStreamsInfo := False; + tmTraffic.Enabled := True; + tmCircuits.Enabled := True; + tmSaveTotals.Enabled := True; + btnSwitchTor.ImageIndex := 1; + btnSwitchTor.Caption := TransStr('101'); + btnChangeCircuit.Caption := '0 %'; + if cbEnableSocks.Checked then + begin + lbExitIp.Caption := TransStr('111'); + lbExitCountry.Caption := TransStr('112'); + end; + SetOptionsEnable(False); + ControlsDisable(tsNetwork); + ControlsDisable(tsServer); + edControlPort.Enabled := False; + lbControlPort.Enabled := False; + cbxAuthMetod.Enabled := False; + lbAuthMetod.Enabled := False; + if cbxAuthMetod.ItemIndex = 1 then + begin + edControlPassword.Enabled := False; + lbControlPassword.Enabled := False; + imGeneratePassword.Enabled := False; + end; + tiTray.IconIndex := 1; + miSwitchTor.ImageIndex := 1; + miSwitchTor.Caption := btnSwitchTor.Caption; + CheckStatusControls; + if(cbShowBalloonHint.Checked and not cbShowBalloonOnlyWhenHide.Checked) + or (not cbConnectOnStartup.Checked or (cbConnectOnStartup.Checked and cbMinimizeOnStartup.Checked)) then + if not Restarting then + ShowBalloon(TransStr('240')); + ControlPortConnect; + if TorMainProcess.hStdOutput <> 0 then + LogListenerStart(TorMainProcess.hStdOutput); + InitPortForwarding(False); + end + else + begin + TerminateProcess(TorMainProcess.hProcess, 0); + if not AutoResolveErrors then + begin + if Win32MajorVersion = 5 then + Msg := TransStr('377') + BR + BR + TransStr('397') + else + Msg := TransStr('377'); + ShowMsg(Msg, '', mtWarning); + end; + end; + end + else + if not AutoResolveErrors then + ShowMsg(TransStr('238'), '', mtWarning); + end + else + begin + if not AutoResolveErrors then + begin + if (ShowMsg(TransStr('239'),'', mtWarning, True)) then + ShellOpen(GetDefaultsValue('DownloadUrl', DOWNLOAD_URL)); + end; + end; +end; + +procedure TTcp.StopTor; +begin + TerminateProcess(TorMainProcess.hProcess, 0); + if Assigned(Controller) then + Controller.Terminate; + if Assigned(Consensus) then + Consensus.Terminate; + if Assigned(Descriptors) then + Descriptors.Terminate; + if Assigned(Logger) then + Logger.Terminate; + ConnectState := 0; + InfoStage := 0; + GetIpStage := 0; + AutoScanStage := 0; + + LockCircuits := False; + LockCircuitInfo := False; + LockStreams := False; + LockStreamsInfo := False; + tmUpdateIp.Enabled := False; + tmConsensus.Enabled := False; + tmCircuits.Enabled := False; + tmSaveTotals.Enabled := False; + btnChangeCircuit.Caption := TransStr('103'); + btnChangeCircuit.Enabled := True; + btnSwitchTor.ImageIndex := 0; + btnSwitchTor.Caption := TransStr('100'); + imExitFlag.Visible := False; + lbExitCountry.Left := Round(174 * Scale); + lbExitCountry.Caption := TransStr('110'); + lbExitCountry.Cursor := crDefault; + lbExitCountry.Hint := ''; + lbExitIp.Caption := TransStr('109'); + lbExitIp.Cursor := crDefault; + tiTray.IconIndex := 0; + miChangeCircuit.Enabled := False; + miSwitchTor.ImageIndex := 0; + miSwitchTor.Caption := btnSwitchTor.Caption; + if not Restarting then + begin + SetOptionsEnable(True); + edControlPort.Enabled := True; + lbControlPort.Enabled := True; + cbxAuthMetod.Enabled := True; + lbAuthMetod.Enabled := True; + if cbxAuthMetod.ItemIndex = 1 then + begin + edControlPassword.Enabled := True; + lbControlPassword.Enabled := True; + imGeneratePassword.Enabled := True; + end; + ControlsEnable(tsNetwork); + ControlsEnable(tsServer); + BridgesCheckControls; + ShowBalloon(TransStr('241')); + end; + RemoveUPnPEntry(udORPort.Tag, udDirPort.Tag, udTransportPort.Tag); + udORPort.Tag := 0; + udDirPort.Tag := 0; + udTransportPort.Tag := 0; +end; + +procedure TTcp.RestartTor(RestartCode: Byte = 0); +begin + if not Assigned(RestartTimeout) then + begin + if (RestartCode > 0) or cbRestartOnControlFail.Checked then + Restarting := True; + StopTor; + RestartTimeout := TTimer.Create(Tcp); + RestartTimeout.Tag := RestartCode; + RestartTimeout.OnTimer := RestartTimer; + RestartTimeout.Interval := 200; + end; +end; + +procedure TTcp.RestartTimer(Sender: TObject); +begin + if not Assigned(Controller) and not Assigned(Logger) and not Assigned(Consensus) and not Assigned(Descriptors) then + begin + case TTimer(Sender).Tag of + 1: + begin + ResetGuards(TGuardType(miResetGuards.Tag)); + StartTor; + end; + else + if cbRestartOnControlFail.Checked then + StartTor; + end; + Restarting := False; + FreeAndNil(RestartTimeout); + end +end; + +procedure TTcp.ReloadTorConfig; +begin + if ConnectState = 2 then + begin + SendCommand('SIGNAL RELOAD'); + SendDataThroughProxy; + end; +end; + +procedure TTcp.imGeneratePasswordClick(Sender: TObject); +begin + edControlPassword.Text := RandomString(15); + EnableOptionButtons; +end; + +procedure TTcp.imUPnPTestClick(Sender: TObject); +begin + InitPortForwarding(True); + if UPnPMsg <> '' then + ShowMsg(UPnPMsg, TransStr('181')) + else + ShowMsg(TransStr('242'), TransStr('181'), mtWarning); +end; + +procedure TTcp.CheckRequiredFiles; +begin + SetTorConfig('DataDirectory', ExcludeTrailingPathDelimiter(UserDir)); + SetTorConfig('ClientOnionAuthDir', ExcludeTrailingPathDelimiter(OnionAuthDir)); + + GeoIpExists := FileExists(GeoIpFile); + if GeoIpExists then + SetTorConfig('GeoIPFile', GeoIpFile) + else + DeleteTorConfig('GeoIPFile'); + + if FileExists(GeoIpv6File) then + SetTorConfig('GeoIPv6File', GeoIpv6File) + else + DeleteTorConfig('GeoIPv6File'); +end; + +procedure TTcp.SetIconsColor; + function GetRGBSum(AColor: TColor): Integer; + begin + Result := GetRValue(AColor) + GetGValue(AColor) + GetBValue(AColor); + end; +begin + if GetRGBSum(ColorToRGB(StyleServices.GetStyleColor(scButtonNormal))) >= 384 then + LoadIconsFromResource(lsButtons, 'ICON_BUTTONS_DARK') + else + LoadIconsFromResource(lsButtons, 'ICON_BUTTONS_LIGHT'); + if GetRGBSum(ColorToRGB(StyleServices.GetStyleColor(scWindow))) >= 384 then + LoadIconsFromResource(lsMain, 'ICON_MAIN_DARK') + else + LoadIconsFromResource(lsMain, 'ICON_MAIN_LIGHT'); + if GetRGBSum(ColorToRGB(StyleServices.GetStyleColor(scEdit))) >= 384 then + begin + lsMenus.GrayscaleFactor := 0; + LoadIconsFromResource(lsMenus, 'ICON_MENUS_DARK') + end + else + begin + lsMenus.GrayscaleFactor := 128; + LoadIconsFromResource(lsMenus, 'ICON_MENUS_LIGHT'); + end; + + if StyleServices.Enabled and StyleServices.IsSystemStyle then + pbTraffic.Color := clWindow + else + pbTraffic.Color := ColorToRGB(StyleServices.GetStyleColor(scWindow)); + + lsButtons.GetIcon(6, imGeneratePassword.Picture.Icon); + lsButtons.GetIcon(7, imUPnPTest.Picture.Icon); + SetButtonGlyph(lsButtons, 4, sbShowOptions); + SetButtonGlyph(lsButtons, 5, sbShowLog); + SetButtonGlyph(lsButtons, 9, sbShowStatus); + SetButtonGlyph(lsButtons, 10, sbShowCircuits); + SetButtonGlyph(lsButtons, 8, sbShowRouters); + SetButtonGlyph(lsButtons, 11, sbDecreaseForm); + + btnSwitchTor.ImageIndex := ConnectState; + btnSwitchTor.Refresh; + btnChangeCircuit.Refresh; + if FormSize = 1 then + begin + case LastPlace of + LP_OPTIONS: sgFilter.Refresh; + LP_CIRCUITS: sgCircuits.Refresh; + LP_ROUTERS: sgRouters.Refresh; + end; + end; +end; + +procedure TTcp.SetButtonGlyph(ls: TImageList; Index: Integer; Button: TSpeedButton); +begin + Button.Glyph := nil; + ls.GetBitmap(Index, Button.Glyph); +end; + +procedure TTcp.UpdateConfigVersion; +var + ini: TMemIniFile; + TemplateList: TStringlist; + TemplateName, Temp: string; + ParseStr: ArrOfStr; + FirstRun: Boolean; + i, ConfigVersion: Integer; + + function ConvertCodes(Str: string): string; + var + Mas: ArrOfStr; + i: Integer; + begin + Result := ''; + Mas := Explode(',', Str); + for i := 0 to Length(Mas) - 1 do + if ValidInt(Mas[i], 0, MAX_COUNTRIES - 1) then + Result := Result + ',' + CountryCodes[StrToInt(Mas[i])] + else + Result := Result + ',' + Mas[i]; + Delete(Result, 1, 1); + end; + + function ConvertNodes(FilterData: string; TorFormat: Boolean): string; + var + ParsedData: ArrOfStr; + NodesList: TStringlist; + EntryNodes, MiddleNodes, ExitNodes, ExcludeList, IncludeList: string; + FMode, FNodes: Byte; + i: Integer; + begin + ParsedData := Explode(';', FilterData); + if (Length(ParsedData) in [4,5]) then + begin + if ValidInt(ParsedData[1], 0, 2) then + FMode := StrToInt(ParsedData[1]) + else + FMode := 0; + + if (Length(ParsedData) = 5) and ValidInt(ParsedData[4], 1, 7) then + FNodes := StrToInt(ParsedData[4]) + else + FNodes := 4; + + ExcludeList := ConvertCodes(ParsedData[2]); + IncludeList := ConvertCodes(ParsedData[3]); + + if FMode in [0, 2] then + begin + NodesList := TStringList.Create; + try + ParseParametersEx(RemoveBrackets(DEFAULT_EXIT_NODES), ',', NodesList); + for i := NodesList.Count - 1 downto 0 do + begin + if Pos(NodesList[i], ExcludeList) <> 0 then + NodesList.Delete(i); + end; + for i := 0 to NodesList.Count - 1 do + begin + if TorFormat then + ExitNodes := ExitNodes + ',{' + NodesList[i] + '}' + else + ExitNodes := ExitNodes + ',' + NodesList[i]; + end; + Delete(ExitNodes, 1, 1); + finally + NodesList.Free; + end; + end; + case FMode of + 0: Fmode := 1; + 1: ExitNodes := IncludeList; + 2: FMode := 0; + end; + case FNodes of + 1: begin EntryNodes := ExitNodes; ExitNodes := ''; end; + 2: begin MiddleNodes := ExitNodes; ExitNodes := ''; end; + 3: begin EntryNodes := ExitNodes; MiddleNodes := ExitNodes; ExitNodes := ''; end; + 5: begin EntryNodes := ExitNodes; end; + 6: begin MiddleNodes := ExitNodes; end; + 7: begin EntryNodes := ExitNodes; MiddleNodes := ExitNodes; end; + end; + Result := ParsedData[0] + ';' + IntToStr(FMode) + ';' + EntryNodes + ';' + MiddleNodes + ';' + ExitNodes; + end; + end; + +begin + if FileExists(UserConfigFile) and FileExists(TorConfigFile) then + FirstRun := False + else + FirstRun := True; + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + ConfigVersion := ini.ReadInteger('Main', 'ConfigVersion', 1); + if ConfigVersion = CURRENT_CONFIG_VERSION then + Exit; + if not FirstRun then + begin + if ConfigVersion = 1 then + begin + case ini.ReadInteger('Main', 'Language', 0) of + 1: ini.WriteInteger('Main', 'Language', 1033); + 2: ini.WriteInteger('Main', 'Language', 1031); + else + ini.WriteInteger('Main', 'Language', 1049); + end; + + if ini.ReadInteger('Server', 'BridgeType', 0) = 1 then + ini.WriteString('Server', 'BridgeType', 'obfs4'); + + ParseStr := Explode(';', ConvertNodes( + ';' + IntToStr(ini.ReadInteger('Main', 'FilterMode', 0)) + + ';' + GetTorConfig('ExcludeExitNodes', '', [cfFindComments]) + + ';' + GetTorConfig('ExitNodes', '', [cfFindComments]) + + ';' + IntToStr(ini.ReadInteger('Main', 'FilterNodes', 4)), True + )); + ini.WriteInteger('Filter', 'FilterMode', StrToInt(ParseStr[1])); + ini.WriteString('Filter', 'EntryNodes', ParseStr[2]); + ini.WriteString('Filter', 'MiddleNodes', ParseStr[3]); + ini.WriteString('Filter', 'ExitNodes', ParseStr[4]); + + SetTorConfig('EntryNodes', ParseStr[2], [cfFindComments]); + SetTorConfig('MiddleNodes', ParseStr[3], [cfFindComments]); + SetTorConfig('ExitNodes', ParseStr[4], [cfFindComments]); + DeleteTorConfig('ExcludeExitNodes', [cfFindComments]); + + Temp := GetTorConfig('ExcludeNodes', '', [cfFindComments]); + ini.WriteString('Routers', 'ExcludeNodes', Temp); + if GetTorConfig('ExcludeNodes', '0', [cfExistCheck]) = '1' then + ini.WriteBool('Lists', 'UseExcludeNodes', True) + else + DeleteTorConfig('ExcludeNodes', [cfFindComments]); + + Temp := GetTorConfig('TrackHostExits', '', [cfFindComments]); + ini.WriteString('Lists', 'TrackHostExits', Temp); + if GetTorConfig('TrackHostExits', '0', [cfExistCheck]) = '1' then + ini.WriteBool('Lists', 'UseTrackHostExits', True) + else + DeleteTorConfig('TrackHostExits', [cfFindComments]); + + Temp := GetTorConfig('TrackHostExitsExpire', '1800', [cfFindComments], ptInteger, Tcp.udTrackHostExitsExpire.Min, Tcp.udTrackHostExitsExpire.Max); + ini.WriteInteger('Lists', 'TrackHostExitsExpire', StrToInt(Temp)); + if GetTorConfig('TrackHostExitsExpire', '0', [cfExistCheck]) = '0' then + DeleteTorConfig('TrackHostExitsExpire', [cfFindComments]); + + Temp := GetTorConfig('HashedControlPassword', '', [cfFindComments]); + ini.WriteString('Main', 'HashedControlPassword', Temp); + if GetTorConfig('HashedControlPassword', '0', [cfExistCheck]) = '0' then + DeleteTorConfig('HashedControlPassword', [cfFindComments]); + + Temp := GetTorConfig('Bridge', '', [cfMultiLine, cfFindComments]); + if Temp <> '' then + begin + ParseStr := Explode('|', Temp); + for i := 0 to Length(ParseStr) - 1 do + ini.WriteString('Bridges', IntToStr(i), ParseStr[i]); + ini.WriteBool('Network', 'UseBridges', StrToBool(GetTorConfig('UseBridges', '0', [], ptBoolean))); + ini.WriteInteger('Network', 'BridgesType', 1); + DeleteTorConfig('Bridge', [cfMultiLine, cfFindComments]); + end; + + ini.WriteBool('Server', 'UseNumCPUs', StrToBool(GetTorConfig('NumCPUs', '0', [cfExistCheck]))); + ini.WriteBool('Server', 'UseRelayBandwidth', StrToBool(GetTorConfig('RelayBandwidthRate', '0', [cfExistCheck])) or StrToBool(GetTorConfig('RelayBandwidthBurst', '0', [cfExistCheck])) or StrToBool(GetTorConfig('MaxAdvertisedBandwidth', '0', [cfExistCheck]))); + ini.WriteBool('Server', 'UseMaxMemInQueues', StrToBool(GetTorConfig('MaxMemInQueues', '0', [cfExistCheck]))); + ini.WriteBool('Server', 'UseDirPort', StrToBool(GetTorConfig('DirPort', '0', [cfExistCheck]))); + ini.WriteBool('Server', 'PublishServerDescriptor', StrToBool(GetTorConfig('PublishServerDescriptor', '1', [], ptBoolean))); + ini.WriteBool('Server', 'DirReqStatistics', StrToBool(GetTorConfig('DirReqStatistics', '1', [], ptBoolean))); + ini.WriteBool('Server', 'HiddenServiceStatistics', StrToBool(GetTorConfig('HiddenServiceStatistics', '1', [], ptBoolean))); + ini.WriteBool('Server', 'IPv6Exit', StrToBool(GetTorConfig('IPv6Exit', '0', [], ptBoolean))); + + GetLocalInterfaces(cbxHsAddress); + GetTorHs; + SaveHiddenServices(ini); + + ini.WriteString('Main', 'FormPosition', + IntToStr(ini.ReadInteger('Main', 'PositionLeft', -1)) + ',' + + IntToStr(ini.ReadInteger('Main', 'PositionTop', -1)) + ',-1,-1'); + + ini.DeleteKey('Main', 'ConfirmBanRelay'); + ini.DeleteKey('Main', 'PositionLeft'); + ini.DeleteKey('Main', 'PositionTop'); + ini.DeleteKey('Main', 'FilterMode'); + ini.DeleteKey('Main', 'FilterNodes'); + ini.DeleteKey('Main', 'UseExcludeNodes'); + ini.DeleteKey('Main', 'UseTrackHostExits'); + + TemplateList := TStringlist.Create; + try + ini.ReadSectionValues('Templates', TemplateList); + if TemplateList.Count > 0 then + begin + for i := 0 to TemplateList.Count - 1 do + begin + TemplateName := SeparateLeft(TemplateList[i], '='); + ini.WriteString('Templates', TemplateName, ConvertNodes(ini.ReadString('Templates', TemplateName, ''), False)); + end; + end; + finally + TemplateList.Free; + end; + ForceDirectories(LogsDir); + RenameFile(UserDir + 'console.log', LogsDir + 'console.log'); + ConfigVersion := 2; + end; + end + else + ConfigVersion := CURRENT_CONFIG_VERSION; + ini.WriteInteger('Main', 'ConfigVersion', ConfigVersion); + finally + ini.UpdateFile; + ini.Free; + end; +end; + +function TTcp.GetTorHs: Integer; +const + DEFAULT_ADDRESS = '127.0.0.1'; + DEFAULT_PORT = '80'; +var + Name, Version, MaxStreams, IntroPoints, Port, Temp, Data, Delimiter: string; + VirtualPort, RealPort, Address: string; + ParseStr: ArrOfStr; + Reset: Boolean; + i, Min, Max: Integer; + + function GetParam(Param, Str: string): string; + var + p, CommentPos, ParamSize: Integer; + begin + p := InsensPosEx(Param + ' ', Str); + if p = 1 then + begin + ParamSize := Length(Param); + CommentPos := Pos('#', Str); + if CommentPos > p + ParamSize then + Result := Trim(copy(Str, p + ParamSize + 1, CommentPos - ParamSize - 2)) + else + Result := Trim(copy(Str, p + ParamSize + 1, Length(Str) - ParamSize - 1)); + end + else + Result := ''; + end; + +begin + Result := 0; + Min := 0; + Max := 0; + + for i := 0 to TorConfig.Count - 1 do + begin + Name := GetParam('HiddenServiceDir', TorConfig[i]); + if Name <> '' then + begin + Inc(Result); + sgHs.Cells[HS_VERSION, Result] := '3'; + sgHs.Cells[HS_INTRO_POINTS, Result] := '3'; + sgHs.Cells[HS_MAX_STREAMS, Result] := NONE_CHAR; + sgHs.cells[HS_STATE, Result] := SELECT_CHAR; + sgHs.Cells[HS_PORTS_DATA, Result] := ''; + if Result > 1 then + sgHs.RowCount := sgHs.RowCount + 1; + Name := ExcludeTrailingPathDelimiter(Name); + Name := copy(Name, RPos('\', Name) + 1); + TorConfig[i] := 'HiddenServiceDir ' + HsDir + Name; + + sgHs.Cells[HS_NAME, Result] := Name; + sgHs.Cells[HS_PREVIOUS_NAME, Result] := sgHs.Cells[HS_NAME, Result]; + + continue; + end; + + Version := GetParam('HiddenServiceVersion', TorConfig[i]); + if Version <> '' then + begin + if ValidInt(Version, 2, 3) then + sgHs.Cells[HS_VERSION, Result] := Version + else + TorConfig[i] := 'HiddenServiceVersion 3'; + continue; + end; + + Port := GetParam('HiddenServicePort', TorConfig[i]); + if Port <> '' then + begin + Reset := False; + Delimiter := ''; + Address := ''; + RealPort := ''; + VirtualPort := ''; + Temp := sgHs.Cells[HS_PORTS_DATA, Result]; + if Temp <> '' then + Delimiter := '|'; + ParseStr := Explode(' ', Port); + VirtualPort := ParseStr[0]; + if not ValidInt(VirtualPort, 1, 65535) then + begin + VirtualPort := DEFAULT_PORT; + Reset := True; + end; + if Length(ParseStr) > 1 then + begin + if ValidSocket(ParseStr[1]) then + begin + Address := GetAddressFromSocket(ParseStr[1]); + RealPort := IntToStr(GetPortFromSocket(ParseStr[1])); + if Reset then + VirtualPort := RealPort; + if Tcp.cbxHsAddress.Items.IndexOf(Address) = -1 then + begin + Address := DEFAULT_ADDRESS; + Reset := True; + end; + end + else + begin + Address := RemoveBrackets(ParseStr[1], True); + if ValidAddress(Address) <> 0 then + begin + RealPort := VirtualPort; + if Tcp.cbxHsAddress.Items.IndexOf(Address) = -1 then + begin + Address := DEFAULT_ADDRESS; + Reset := True; + end; + end + else + begin + Address := DEFAULT_ADDRESS; + if ValidInt(ParseStr[1], 1, 65535) then + begin + RealPort := ParseStr[1]; + if Reset then + VirtualPort := RealPort; + end + else + begin + RealPort := VirtualPort; + Reset := True; + end; + end; + end + end + else + begin + Address := DEFAULT_ADDRESS; + RealPort := VirtualPort; + end; + Data := Address + ',' + RealPort + ',' + VirtualPort; + sgHs.Cells[HS_PORTS_DATA, Result] := Temp + Delimiter + Data; + if Reset then + TorConfig[i] := 'HiddenServicePort ' + VirtualPort + ' ' + FormatHost(Address) + ':' + RealPort; + continue; + end; + + IntroPoints := GetParam('HiddenServiceNumIntroductionPoints', TorConfig[i]); + if IntroPoints <> '' then + begin + case StrToInt(sgHs.Cells[HS_VERSION, Result]) of + 2: begin Min := 1; Max := 10 end; + 3: begin Min := 3; Max := 20 end; + end; + if ValidInt(IntroPoints, Min, Max) then + sgHs.Cells[HS_INTRO_POINTS, Result] := IntroPoints + else + TorConfig[i] := 'HiddenServiceNumIntroductionPoints 3'; + continue; + end; + + MaxStreams := GetParam('HiddenServiceMaxStreams', TorConfig[i]); + if MaxStreams <> '' then + begin + if ValidInt(MaxStreams, 1, 65535) then + sgHs.Cells[HS_MAX_STREAMS, Result] := MaxStreams + else + TorConfig[i] := ''; + continue; + end; + end; + udRendPostPeriod.Position := Round(StrToInt(GetTorConfig('RendPostPeriod', '3600', [], ptInteger, Tcp.udRendPostPeriod.Min * 60, Tcp.udRendPostPeriod.Max * 60)) / 60); +end; + +function TTcp.LoadHiddenServices(ini: TMemIniFile): Integer; +const + DEFAULT_ADDRESS = '127.0.0.1'; + DEFAULT_PORT = '80'; +var + HsList, PortList: TStringList; + i, j, Min, Max: Integer; + ParseStr, PortsStr: ArrOfStr; + Address, RealPort, VirtualPort: string; + Name, Version, MaxStreams, IntroPoints, PortsData, State: string; +begin + Result := 0; + Min := 0; + Max := 0; + + BeginUpdateTable(sgHs); + HsList := TStringList.Create; + PortList := TStringList.Create; + try + LoadSettings('HiddenServices', udRendPostPeriod, ini); + ini.ReadSectionValues('HiddenServices', HsList); + for i := 0 to HsList.Count - 1 do + begin + if ValidInt(SeparateLeft(HsList[i], '='), 0, MAXINT) then + begin + ParseStr := Explode(';', SeparateRight(HsList[i], '=')); + if Length(ParseStr) = 6 then + begin + Name := ParseStr[0]; + Version := ParseStr[1]; + IntroPoints := ParseStr[2]; + MaxStreams := ParseStr[3]; + State := ParseStr[4]; + PortsData := ParseStr[5]; + if not ValidInt(Version, 2, 3) then + Version := '3'; + case StrToInt(Version) of + 2: begin Min := 1; Max := 10 end; + 3: begin Min := 3; Max := 20 end; + end; + if not ValidInt(IntroPoints, Min, Max) then + IntroPoints := '3'; + if not ValidInt(MaxStreams, 1, 65535) then + MaxStreams := NONE_CHAR; + if State = '1' then + State := SELECT_CHAR + else + State := FAVERR_CHAR; + PortList.Clear; + ParseStr := Explode('|', PortsData); + for j := 0 to Length(ParseStr) - 1 do + begin + PortsStr := Explode(',', ParseStr[j]); + if Length(PortsStr) = 3 then + begin + Address := PortsStr[0]; + RealPort := PortsStr[1]; + VirtualPort := PortsStr[2]; + if (ValidAddress(Address) = 0) or (cbxHsAddress.Items.IndexOf(Address) = -1) then + Address := DEFAULT_ADDRESS; + if not ValidInt(RealPort, 1, 65535) then + RealPort := DEFAULT_PORT; + if not ValidInt(VirtualPort, 1, 65535) then + VirtualPort := DEFAULT_PORT; + end + else + begin + Address := DEFAULT_ADDRESS; + RealPort := DEFAULT_PORT; + VirtualPort := DEFAULT_PORT; + end; + PortList.Append(Address + ',' + RealPort + ',' + VirtualPort); + end; + DeleteDuplicatesFromList(PortList); + PortsData := ''; + for j := 0 to PortList.Count - 1 do + PortsData := PortsData + '|' + PortList[j]; + Delete(PortsData, 1, 1); + + Inc(Result); + sgHs.Cells[HS_NAME, Result] := Name; + sgHs.Cells[HS_VERSION, Result] := Version; + sgHs.Cells[HS_INTRO_POINTS, Result] := IntroPoints; + sgHs.Cells[HS_MAX_STREAMS, Result] := MaxStreams; + sgHs.Cells[HS_STATE, Result] := State; + sgHs.Cells[HS_PORTS_DATA, Result] := PortsData; + sgHs.Cells[HS_PREVIOUS_NAME, Result] := Name; + end; + end; + end; + if Result > 0 then + sgHs.RowCount := Result + 1 + else + sgHs.RowCount := 2; + + EndUpdateTable(sgHs); + finally + HsList.Free; + PortList.Free; + end; +end; + +procedure TTcp.SaveHiddenServices(ini: TMemIniFile); +var + i, j, Count: Integer; + ParseStr, ParsePort: ArrOfStr; + Name, PrevName, Version, MaxStreams, IntroPoints, PortsData, State: string; +begin + DeleteTorConfig('HiddenServiceDir', [cfMultiLine]); + DeleteTorConfig('HiddenServiceVersion', [cfMultiLine]); + DeleteTorConfig('HiddenServicePort', [cfMultiLine]); + DeleteTorConfig('HiddenServiceNumIntroductionPoints', [cfMultiLine]); + DeleteTorConfig('HiddenServiceMaxStreams', [cfMultiLine]); + DeleteTorConfig('RendPostPeriod'); + ini.EraseSection('HiddenServices'); + + if Length(HsToDelete) > 0 then + begin + for i := 0 to Length(HsToDelete) - 1 do + DeleteDir(HsDir + HsToDelete[i]); + HsToDelete := nil; + end; + ini.WriteInteger('HiddenServices', 'RendPostPeriod', Tcp.udRendPostPeriod.Position); + + if not IsEmptyGrid(sgHs) then + begin + if not DirectoryExists(UserDir + 'services') then + ForceDirectories(UserDir + 'services'); + Count := 0; + for i := 1 to sgHs.RowCount - 1 do + begin + Name := sgHs.Cells[HS_NAME, i]; + PrevName := sgHs.Cells[HS_PREVIOUS_NAME, i]; + Version := sgHs.Cells[HS_VERSION, i]; + IntroPoints := sgHs.Cells[HS_INTRO_POINTS, i]; + MaxStreams := sgHs.Cells[HS_MAX_STREAMS, i]; + State := sgHs.Cells[HS_STATE, i]; + PortsData := sgHs.Cells[HS_PORTS_DATA, i]; + + if not ValidInt(MaxStreams, 1, 65535) then MaxStreams := '0'; + if State = SELECT_CHAR then State := '1' else State := '0'; + + if State = '1' then + begin + Inc(Count); + if DirectoryExists(HsDir + PrevName) then + begin + if Name <> PrevName then + begin + RenameFile(HsDir + PrevName, HsDir + Name); + sgHs.Cells[HS_PREVIOUS_NAME, i] := Name; + end; + end; + TorConfig.Append('HiddenServiceDir ' + HsDir + Name); + TorConfig.Append('HiddenServiceVersion ' + Version); + ParseStr := Explode('|', PortsData); + for j := 0 to Length(ParseStr) - 1 do + begin + ParsePort := Explode(',', ParseStr[j]); + TorConfig.Append('HiddenServicePort ' + ParsePort[2] + ' ' + FormatHost(ParsePort[0]) + ':' + ParsePort[1]); + end; + if IntroPoints <> '3' then + TorConfig.Append('HiddenServiceNumIntroductionPoints ' + IntroPoints); + if MaxStreams <> '0' then + TorConfig.Append('HiddenServiceMaxStreams ' + MaxStreams); + end; + + ini.WriteString('HiddenServices', IntToStr(i - 1), + Name + ';' + + Version + ';' + + IntroPoints + ';' + + MaxStreams + ';' + + State + ';' + + PortsData + ); + end; + if Count > 0 then + SetTorConfig('RendPostPeriod', IntToStr(Tcp.udRendPostPeriod.Position * 60)); + end; +end; + +procedure TTcp.ResetTransports; +var + ls: TStringList; + ini: TMemIniFile; +begin + if FileExists(DefaultsFile) then + begin + ini := TMemIniFile.Create(DefaultsFile, TEncoding.UTF8); + try + ls := TStringList.Create; + try + ini.ReadSectionValues('Transports', ls); + if ls.Count > 0 then + LoadTransportsData(ls); + finally + ls.Free; + end; + finally + ini.Free; + end; + end; +end; + +procedure TTcp.LoadUserOverrides; +var + ini: TMemIniFile; +begin + if FileExists(DefaultsFile) then + begin + ini := TMemIniFile.Create(DefaultsFile, TEncoding.UTF8); + try + DefaultsDic.AddOrSetValue('BridgesBot', ini.ReadString('UserOverrides', 'BridgesBot', BRIDGES_BOT)); + DefaultsDic.AddOrSetValue('BridgesEmail', ini.ReadString('UserOverrides', 'BridgesEmail', BRIDGES_EMAIL)); + DefaultsDic.AddOrSetValue('BridgesSite', ini.ReadString('UserOverrides', 'BridgesSite', BRIDGES_SITE)); + DefaultsDic.AddOrSetValue('CheckUrl', ini.ReadString('UserOverrides', 'CheckUrl', CHECK_URL)); + DefaultsDic.AddOrSetValue('DownloadUrl', ini.ReadString('UserOverrides', 'DownloadUrl', DOWNLOAD_URL)); + DefaultsDic.AddOrSetValue('MetricsUrl', ini.ReadString('UserOverrides', 'MetricsUrl', METRICS_URL)); + finally + ini.Free; + end; + end; +end; + +procedure TTcp.LoadTransportsData(Data: TStringList); +var + i, j, TotalTransports: Integer; + TransportID: Byte; + ParseStr, TransList: ArrOfStr; + Transports, Handler, Params, StrType, Item: string; + T: TTransportInfo; + IsValid: Boolean; +begin + TotalTransports := 0; + sgTransports.RowID := sgTransports.Cells[PT_HANDLER, sgTransports.SelRow]; + BeginUpdateTable(sgTransports); + ClearGrid(sgTransports); + TransportsDic.Clear; + + for i := 0 to Data.Count - 1 do + begin + ParseStr := Explode('|', SeparateRight(Data[i], '=')); + if Length(ParseStr) in [3, 4] then + begin + Transports := ParseStr[0]; + Handler := ParseStr[1]; + StrType := GetTransportChar(StrToIntDef(ParseStr[2], 0)); + TransportID := GetTransportID(StrType); + + if Length(ParseStr) = 4 then + Params := ParseStr[3] + else + Params := ''; + + if FileExists(TransportsDir + Handler) then + begin + TransList := Explode(',', Transports); + Transports := ''; + for j := 0 to Length(TransList) - 1 do + begin + IsValid := False; + Item := Trim(TransList[j]); + if (Item <> '') and (CheckEditString(Item, '_', False) = '') then + begin + if TransportsDic.TryGetValue(Item, T) then + begin + if T.TransportID = TRANSPORT_BOTH then + Continue + else + begin + if (TransportID <> TRANSPORT_BOTH) and (TransportID <> T.TransportID) then + begin + T.TransportID := TRANSPORT_BOTH; + IsValid := True; + end; + end; + end + else + begin + T.TransportID := TransportID; + IsValid := True; + end; + if IsValid then + begin + T.BridgeType := []; + TransportsDic.AddOrSetValue(Item, T); + Transports := Transports + ',' + Item; + end; + end; + end; + Delete(Transports, 1, 1); + end; + + if Transports <> '' then + begin + Inc(TotalTransports); + sgTransports.Cells[PT_TRANSPORTS, TotalTransports] := Transports; + sgTransports.Cells[PT_HANDLER, TotalTransports] := Handler; + sgTransports.Cells[PT_TYPE, TotalTransports] := StrType; + sgTransports.Cells[PT_PARAMS, TotalTransports] := Params; + end; + end; + end; + + if TotalTransports > 0 then + begin + sgTransports.RowCount := TotalTransports + 1; + TransportsEnable(True); + SelectTransports; + end + else + UpdateTransports; + SetGridLastCell(sgTransports, True, False, False, -1, -1, PT_HANDLER); + EndUpdateTable(sgTransports); +end; + +procedure TTcp.SaveTransportsData(ini: TMemIniFile; ReloadServerTransport: Boolean); +var + i, j, TransportID: Integer; + Transports, UsedTransports, Handler, Params, StrType, ServerTransport: string; + ParseStr: ArrOfStr; + Find, InBridges: Boolean; + T: TTransportInfo; +begin + DeleteTorConfig('ClientTransportPlugin', [cfMultiLine]); + DeleteTorConfig('ServerTransportPlugin', [cfMultiLine]); + DeleteTorConfig('ServerTransportListenAddr', [cfMultiLine]); + DeleteTorConfig('ExtORPort', [cfMultiLine]); + ini.EraseSection('Transports'); + + if ReloadServerTransport then + ServerTransport := ini.ReadString('Server', 'BridgeType', '') + else + ServerTransport := cbxBridgeType.Text; + + cbxBridgeType.Clear; + cbxBridgeType.Items.Insert(0, TransStr('206')); + if not IsEmptyGrid(sgTransports) then + begin + for i := 1 to sgTransports.RowCount - 1 do + begin + Transports := sgTransports.Cells[PT_TRANSPORTS, i]; + Handler := sgTransports.Cells[PT_HANDLER, i]; + StrType := sgTransports.Cells[PT_TYPE, i]; + Params := sgTransports.Cells[PT_PARAMS, i]; + + TransportID := GetTransportID(StrType); + ParseStr := Explode(',', Transports); + Transports := ''; + UsedTransports := ''; + Find := False; + for j := 0 to Length(ParseStr) - 1 do + begin + ParseStr[j] := Trim(ParseStr[j]); + if TransportsDic.TryGetValue(ParseStr[j], T) then + begin + if cbUsePreferredBridge.Checked then + InBridges := btPrefer in T.BridgeType + else + InBridges := btList in T.BridgeType; + if (T.TransportID <> TRANSPORT_SERVER) and InBridges then + begin + UsedTransports := UsedTransports + ',' + ParseStr[j]; + Find := True; + end; + end; + if TransportID <> TRANSPORT_CLIENT then + begin + cbxBridgeType.Items.Append(ParseStr[j]); + if (cbxServerMode.ItemIndex = 3) and (ServerTransport = ParseStr[j]) then + begin + SetTorConfig('ServerTransportPlugin', Trim(ServerTransport + ' exec ' + TransportsDir + Handler + ' ' + Params)); + SetTorConfig('ServerTransportListenAddr', ServerTransport + ' 0.0.0.0:' + IntToStr(udTransportPort.Position)); + SetTorConfig('ExtORPort', 'auto'); + end; + end; + Transports := Transports + ',' + ParseStr[j]; + end; + Delete(Transports, 1, 1); + Delete(UsedTransports, 1, 1); + + if cbUseBridges.Checked and Find then + TorConfig.Append('ClientTransportPlugin ' + UsedTransports + ' exec ' + TransportsDir + Handler + ' ' + Params); + + if Params <> '' then + Params := '|' + Params; + + ini.WriteString('Transports', IntToStr(i - 1), + Transports + '|' + Handler + '|' + IntToStr(TransportID) + Params); + end; + end; + cbxBridgeType.ItemIndex := GetIntDef(cbxBridgeType.Items.IndexOf(ServerTransport), 0, 0, MAXINT); + ini.WriteString('Server', 'BridgeType', cbxBridgeType.Text); + ServerIsObfs4 := cbxBridgeType.Text = 'obfs4'; +end; + +procedure TTcp.LoadUserBridges(ini: TMemIniFile); +var + Bridges: TStringList; + i: Integer; +begin + meBridges.Clear; + Bridges := TStringList.Create; + try + ini.ReadSectionValues('Bridges', Bridges); + if Bridges.Count > 0 then + begin + for i := Bridges.Count - 1 downto 0 do + begin + Bridges[i] := Trim(SeparateRight(Bridges[i], '=')); + if not ValidBridge(Bridges[i], btList) then + Bridges.Delete(i); + end; + meBridges.Text := Bridges.Text; + end; + finally + Bridges.Free; + end; +end; + +procedure TTcp.LoadBuiltinBridges(UpdateBridges, UpdateList: Boolean; ListName: string = ''); +const + Delimiter = '|'; +var + ini: TMemIniFile; + ls: TStringList; + i: Integer; + Key, Value, Str: string; + Bridges: TDictionary; + Bridge: TBridge; +begin + if UpdateBridges then + meBridges.Clear; + if FileExists(DefaultsFile) then + begin + ini := TMemIniFile.Create(DefaultsFile, TEncoding.UTF8); + try + ls := TStringList.Create; + Bridges := TDictionary.Create; + try + if UpdateList then + cbxBridgesList.Clear; + ini.ReadSectionValues('Bridges', ls); + if ls.Count > 0 then + begin + for i := 0 to ls.Count - 1 do + begin + Key := SeparateLeft(SeparateLeft(ls[i], '='), '.'); + Value := SeparateRight(ls[i], '='); + if Pos(Delimiter, Value) = 0 then + begin + if TryParseBridge(Value, Bridge) then + begin + if Bridges.TryGetValue(Key, Str) then + Str := Str + Delimiter + Value + else + begin + Str := Value; + if UpdateList then + cbxBridgesList.Items.Append(Key); + end; + Bridges.AddOrSetValue(Key, Str) + end; + end; + end; + if Bridges.Count > 0 then + begin + if UpdateList then + begin + cbxBridgesList.ItemIndex := cbxBridgesList.Items.IndexOf(ListName); + if cbxBridgesList.ItemIndex = -1 then + cbxBridgesList.ItemIndex := 0; + end; + if UpdateBridges then + begin + if Bridges.TryGetValue(cbxBridgesList.Text, Str) then + LineToMemo(Str, meBridges, ltBridge, False, Delimiter); + end; + end; + end; + finally + ls.Free; + Bridges.Free; + end; + finally + ini.Free; + end; + end; +end; + +procedure TTcp.SaveBridgesData(ini: TMemIniFile); +var + Bridges, PreferredBridge: string; + i: Integer; +begin + DeleteTorConfig('Bridge', [cfMultiLine]); + PreferredBridge := Trim(edPreferredBridge.Text); + if not ValidBridge(PreferredBridge, btPrefer) then + begin + PreferredBridge := ''; + cbUsePreferredBridge.Checked := False; + end; + edPreferredBridge.Text := PreferredBridge; + + Bridges := MemoToLine(meBridges, ltBridge, False, '|'); + + if (Bridges = '') and ((cbUsePreferredBridge.Checked and (PreferredBridge = '')) or not cbUsePreferredBridge.Checked) then + cbUseBridges.Checked := False; + + SetTorConfig('UseBridges', IntToStr(Integer(cbUseBridges.Checked))); + if cbUseBridges.Checked then + begin + if cbUsePreferredBridge.Checked then + SetTorConfig('Bridge', PreferredBridge) + else + SetTorConfig('Bridge', Bridges, [cfMultiLine], '|'); + end; + + if cbxBridgesType.ItemIndex = BRIDGES_TYPE_USER then + begin + ini.EraseSection('Bridges'); + for i := 0 to meBridges.Lines.Count - 1 do + ini.WriteString('Bridges', IntToStr(i), meBridges.Lines[i]); + end; + + ini.WriteBool('Network', 'UseBridges', cbUseBridges.Checked); + ini.WriteString('Network', 'BridgesList', cbxBridgesList.Text); + ini.WriteInteger('Network', 'BridgesType', cbxBridgesType.ItemIndex); + ini.WriteBool('Network', 'UsePreferredBridge', cbUsePreferredBridge.Checked); + ini.WriteString('Network', 'PreferredBridge', edPreferredBridge.Text); + BridgesCheckControls; +end; + +procedure TTcp.SaveProxyData(ini: TMemIniFile); +begin + DeleteTorConfig('Socks4Proxy'); + DeleteTorConfig('Socks5Proxy'); + DeleteTorConfig('Socks5ProxyUsername'); + DeleteTorConfig('Socks5ProxyPassword'); + DeleteTorConfig('HTTPProxy'); + DeleteTorConfig('HTTPProxyAuthenticator'); + DeleteTorConfig('HTTPSProxy'); + DeleteTorConfig('HTTPSProxyAuthenticator'); + edProxyAddress.Text := ExtractDomain(Trim(edProxyAddress.Text)); + edProxyUser.Text := Trim(edProxyUser.Text); + edProxyPassword.Text := Trim(edProxyPassword.Text); + if (cbUseProxy.Checked) and ValidHost(edProxyAddress.Text) then + begin + case cbxProxyType.ItemIndex of + PROXY_TYPE_SOCKS4: + SetTorConfig('Socks4Proxy', FormatHost(edProxyAddress.Text) + ':' + IntToStr(udProxyPort.Position)); + PROXY_TYPE_SOCKS5: + begin + SetTorConfig('Socks5Proxy', FormatHost(edProxyAddress.Text) + ':' + IntToStr(udProxyPort.Position)); + if (edProxyUser.Text <> '') and (edProxyPassword.Text <> '') then + begin + SetTorConfig('Socks5ProxyUsername', edProxyUser.Text); + SetTorConfig('Socks5ProxyPassword', edProxyPassword.Text); + end; + end; + PROXY_TYPE_HTTPS: + begin + SetTorConfig('HTTPSProxy', FormatHost(edProxyAddress.Text) + ':' + IntToStr(udProxyPort.Position)); + if (edProxyUser.Text <> '') and (edProxyPassword.Text <> '') then + SetTorConfig('HTTPSProxyAuthenticator', edProxyUser.Text + ':' + edProxyPassword.Text); + end; + end; + end + else + cbUseProxy.Checked := False; + ini.WriteBool('Network', 'UseProxy', cbUseProxy.Checked); + ini.WriteInteger('Network', 'ProxyType', cbxProxyType.ItemIndex); + ini.WriteString('Network', 'ProxyAddress', FormatHost(edProxyAddress.Text)); + ini.WriteInteger('Network', 'ProxyPort', udProxyPort.Position); + ini.WriteString('Network', 'ProxyUser', edProxyUser.Text); + ini.WriteString('Network', 'ProxyPassword', edProxyPassword.Text); +end; + +procedure TTcp.SaveReachableAddresses(ini: TMemIniFile); +var + AllowedPorts: TStringList; + Data: string; + i: Integer; +begin + DeleteTorConfig('ReachableAddresses'); + AllowedPorts := TStringList.Create; + try + AllowedPorts.CommaText := edReachableAddresses.Text; + for i := AllowedPorts.Count - 1 downto 0 do + begin + AllowedPorts[i] := Trim(AllowedPorts[i]); + if not ValidInt(AllowedPorts[i], 1, 65535) or (AllowedPorts.IndexOf(AllowedPorts[i]) <> i) then + AllowedPorts.Delete(i); + end; + + if AllowedPorts.Count > 0 then + begin + AllowedPorts.CustomSort(CompTextAsc); + edReachableAddresses.Text := AllowedPorts.CommaText; + Data := ''; + for i := 0 to AllowedPorts.Count - 1 do + Data := Data + ',*:' + AllowedPorts[i]; + Delete(Data, 1, 1); + if cbUseReachableAddresses.Checked then + SetTorConfig('ReachableAddresses', Data); + end + else + begin + cbUseReachableAddresses.Checked := False; + edReachableAddresses.Text := DEFAULT_ALLOWED_PORTS; + end; + ini.WriteBool('Network', 'UseReachableAddresses', cbUseReachableAddresses.Checked); + ini.WriteString('Network', 'ReachableAddresses', edReachableAddresses.Text); + finally + AllowedPorts.Free; + end; +end; + +procedure TTcp.ResetOptions; +var + i, Search, LogID: Integer; + ini: TMemIniFile; + ScrollBars, SeparateType: Byte; + ParseStr: ArrOfStr; + Transports: TStringList; + SocksHost, Temp: string; + FilterEntry, FilterMiddle, FilterExit: string; + FavoritesEntry, FavoritesMiddle, FavoritesExit, ExcludeNodes: string; + Fail: Boolean; +begin + OptionsLocked := False; + Fail := False; + LoadTorConfig; + LoadUserOverrides; + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + cbxLanguage.ItemIndex := cbxLanguage.Items.IndexOfObject(TObject(Integer(ini.ReadInteger('Main', 'Language', GetLangList)))); + cbxLanguage.ResetValue := cbxLanguage.Items.IndexOf('Русский'); + if cbxLanguage.ItemIndex = -1 then + begin + cbxLanguage.ItemIndex := cbxLanguage.ResetValue; + ini.WriteInteger('Main', 'Language', 1049); + end; + cbxLanguage.Tag := cbxLanguage.ItemIndex; + if FirstLoad then + Translate(cbxLanguage.Text); + + LoadThemesList(cbxThemes, ini.ReadString('Main', 'Theme', 'Windows')); + LoadStyle(cbxThemes); + SetIconsColor; + + if TorConfig.Count = 0 then + begin + TorConfig.Append('# ' + TransStr('271')); + TorConfig.Append(''); + end; + CheckRequiredFiles; + + LoadSettings('Main', cbConnectOnStartup, ini); + LoadSettings('Main', cbRestartOnControlFail, ini); + LoadSettings('Main', cbMinimizeOnClose, ini); + LoadSettings('Main', cbMinimizeOnStartup, ini); + LoadSettings('Main', cbShowBalloonHint, ini); + LoadSettings('Main', cbShowBalloonOnlyWhenHide, ini); + LoadSettings('Main', cbStayOnTop, ini); + LoadSettings('Main', cbNoDesktopBorders, ini); + LoadSettings('Main', cbNoDesktopBordersOnlyEnlarged, ini); + LoadSettings('Main', cbHideIPv6Addreses, ini); + LoadSettings('Main', cbUseNetworkCache, ini); + LoadSettings('Main', cbUseOpenDNS, ini); + LoadSettings('Main', cbUseOpenDNSOnlyWhenUnknown, ini); + LoadSettings('Main', cbRememberEnlargedPosition, ini); + LoadSettings('Main', cbClearPreviousSearchQuery, ini); + + LoadSettings('Log', miWriteLogFile, ini); + LoadSettings('Log', miAutoScroll, ini); + LoadSettings('Log', miWordWrap, ini, False); + LoadSettings('Log', miAutoClear, ini); + + LoadSettings('Network', miPreferWebTelegram, ini); + LoadSettings('Network', miRequestIPv6Bridges, ini, False); + LoadSettings('Network', miRequestObfuscatedBridges, ini); + + LoadSettings('Lists', cbUseHiddenServiceVanguards, ini); + LoadSettings('Lists', cbxVanguardLayerType, ini); + + LoadSettings('Filter', miFilterHideUnused, ini); + LoadSettings('Filter', miFilterScrollTop, ini); + LoadSettings('Filter', miFilterSelectRow, ini); + LoadSettings('Filter', miIgnoreTplLoadParamsOutsideTheFilter, ini); + LoadSettings('Filter', miNotLoadEmptyTplData, ini, False); + LoadSettings('Filter', miReplaceDisabledFavoritesWithCountries, ini); + + LoadSettings('Routers', miRoutersScrollTop, ini); + LoadSettings('Routers', miRoutersSelectRow, ini); + LoadSettings('Routers', miShowFlagsHint, ini); + LoadSettings('Routers', miDisableSelectionUnSuitableAsBridge, ini); + LoadSettings('Routers', miDisableFiltersOnAuthorityOrBridge, ini); + LoadSettings('Routers', miLoadCachedRoutersOnStartup, ini); + LoadSettings('Routers', miDisableFiltersOnUserQuery, ini); + LoadSettings('Routers', miEnableConvertNodesOnIncorrectClear, ini); + LoadSettings('Routers', miEnableConvertNodesOnAddToNodesList, ini); + LoadSettings('Routers', miEnableConvertNodesOnRemoveFromNodesList, ini); + LoadSettings('Routers', miConvertIpNodes, ini); + LoadSettings('Routers', miConvertCidrNodes, ini); + LoadSettings('Routers', miConvertCountryNodes, ini); + LoadSettings('Routers', miIgnoreConvertExcludeNodes, ini); + LoadSettings('Routers', miAvoidAddingIncorrectNodes, ini); + + LoadSettings('Circuits', miHideCircuitsWithoutStreams, ini, False); + LoadSettings('Circuits', miAlwaysShowExitCircuit, ini); + LoadSettings('Circuits', miSelectExitCircuitWhetItChanges, ini); + LoadSettings('Circuits', miShowCircuitsTraffic, ini); + LoadSettings('Circuits', miShowStreamsTraffic, ini); + LoadSettings('Circuits', miShowStreamsInfo, ini); + + LoadSettings('Scanner', cbEnablePingMeasure, ini); + LoadSettings('Scanner', cbEnableDetectAliveNodes, ini); + LoadSettings('Scanner', cbAutoScanNewNodes, ini); + LoadSettings('Scanner', miManualPingMeasure, ini); + LoadSettings('Scanner', miManualDetectAliveNodes, ini); + LoadSettings('Scanner', udScanPortTimeout, ini); + LoadSettings('Scanner', udScanPingTimeout, ini); + LoadSettings('Scanner', udScanPortionTimeout, ini); + LoadSettings('Scanner', udDelayBetweenAttempts, ini); + LoadSettings('Scanner', udScanPingAttempts, ini); + LoadSettings('Scanner', udScanPortAttempts, ini); + LoadSettings('Scanner', udScanMaxThread, ini); + LoadSettings('Scanner', udScanPortionSize, ini); + LoadSettings('Scanner', udFullScanInterval, ini); + LoadSettings('Scanner', udNonResponsedScanInterval, ini); + LoadSettings('Scanner', udPartialScansCounts, ini); + + LoadSettings('AutoSelNodes', cbxAutoSelPriority, ini); + LoadSettings('AutoSelNodes', udAutoSelEntryCount, ini); + LoadSettings('AutoSelNodes', udAutoSelMiddleCount, ini); + LoadSettings('AutoSelNodes', udAutoSelExitCount, ini); + LoadSettings('AutoSelNodes', udAutoSelMinWeight, ini); + LoadSettings('AutoSelNodes', udAutoSelMaxPing, ini); + LoadSettings('AutoSelNodes', cbAutoSelStableOnly, ini); + LoadSettings('AutoSelNodes', cbAutoSelFilterCountriesOnly, ini); + LoadSettings('AutoSelNodes', cbAutoSelUniqueNodes, ini); + LoadSettings('AutoSelNodes', cbAutoSelNodesWithPingOnly, ini); + LoadSettings('AutoSelNodes', cbAutoSelMiddleNodesWithoutDir, ini); + + CheckAutoSelControls; + + LoadSettings('Status', miSelectGraphDL, ini); + LoadSettings('Status', miSelectGraphUL, ini); + CurrentTrafficPeriod := GetIntDef(ini.ReadInteger('Status', 'CurrentTrafficPeriod', 1), 1, 0, 8); + miTrafficPeriod.items[CurrentTrafficPeriod].Checked := True; + + LastFullScanDate := ini.ReadInt64('Scanner', 'LastFullScanDate', 0); + LastNonResponsedScanDate := ini.ReadInt64('Scanner', 'LastNonResponsedScanDate', 0); + LastPartialScansCounts := ini.ReadInteger('Scanner', 'LastPartialScansCounts', 0); + + tmCircuits.Interval := GetIntDef(ini.ReadInteger('Circuits', 'UpdateInterval', 1000), 1000, 0, 4000); + case tmCircuits.Interval of + 0: miCircuitsUpdateManual.Checked := True; + 500: miCircuitsUpdateHigh.Checked := True; + 1000: miCircuitsUpdateNormal.Checked := True; + 4000: miCircuitsUpdateLow.Checked := True; + else + begin + miCircuitsUpdateNormal.Checked := True; + tmCircuits.Interval := 1000; + end; + end; + + IntToMenu(miCircuitFilter, ini.ReadInteger('Circuits', 'PurposeFilter', CIRCUIT_FILTER_DEFAULT)); + IntToMenu(miTplSave, ini.ReadInteger('Filter', 'TplSave', TPL_MENU_DEFAULT)); + IntToMenu(miTplLoad, ini.ReadInteger('Filter', 'TplLoad', TPL_MENU_DEFAULT)); + + CheckSelectRowOptions(sgFilter, miFilterSelectRow.Checked); + CheckSelectRowOptions(sgRouters, miRoutersSelectRow.Checked); + + ParseStr := Explode(',', ini.ReadString('Main', 'SortData', + Format('%d,%d,%d,%d,%d,%d,%d,%d,%d,%d', [ + SORT_DESC, FILTER_TOTAL, + SORT_DESC, ROUTER_WEIGHT, + SORT_DESC, CIRC_ID, + SORT_DESC, STREAMS_ID, + SORT_DESC, STREAMS_INFO_ID + ]) + )); + for i := 0 to Length(ParseStr) - 1 do + case i of + 0: sgFilter.SortType := StrToIntDef(ParseStr[i], SORT_DESC); + 1: sgFilter.SortCol := StrToIntDef(ParseStr[i], FILTER_TOTAL); + 2: sgRouters.SortType := StrToIntDef(ParseStr[i], SORT_DESC); + 3: sgRouters.SortCol := StrToIntDef(ParseStr[i], ROUTER_WEIGHT); + 4: sgCircuits.SortType := StrToIntDef(ParseStr[i], SORT_DESC); + 5: sgCircuits.SortCol := StrToIntDef(ParseStr[i], CIRC_ID); + 6: sgStreams.SortType := StrToIntDef(ParseStr[i], SORT_DESC); + 7: sgStreams.SortCol := StrToIntDef(ParseStr[i], STREAMS_ID); + 8: sgStreamsInfo.SortType := StrToIntDef(ParseStr[i], SORT_DESC); + 9: sgStreamsInfo.SortCol := StrToIntDef(ParseStr[i], STREAMS_INFO_ID); + end; + + LoadSettings('Network', cbUseProxy, ini); + LoadSettings('Network', cbxProxyType, ini, PROXY_TYPE_SOCKS5); + LoadSettings('Network', edProxyAddress, ini); + LoadSettings('Network', udProxyPort, ini); + LoadSettings('Network', edProxyUser, ini); + LoadSettings('Network', edProxyPassword, ini); + SaveProxyData(ini); + + LoadSettings('Network', edReachableAddresses, ini); + LoadSettings('Network', cbUseReachableAddresses, ini); + SaveReachableAddresses(ini); + + meLog.WordWrap := miWordWrap.Checked; + SeparateType := GetIntDef(ini.ReadInteger('Log', 'SeparateType', 1), 1, 0, 2); + miLogSeparate.items[SeparateType].Checked := True; + TorLogFile := GetLogFileName(SeparateType); + + ScrollBars := GetIntDef(ini.ReadInteger('Log', 'ScrollBars', 0), 0, 0, 3); + miScrollBars.items[ScrollBars].Checked := True; + SetLogScrollBar(ScrollBars); + LogID := GetArrayIndex(LogLevels, AnsiLowerCase(SeparateLeft(GetTorConfig('Log', 'notice stdout', [cfAutoAppend]), ' '))); + if LogID <> -1 then + miLogLevel.items[LogID].Checked := True + else + begin + miNotice.Checked := True; + SetTorConfig('Log', 'notice stdout'); + end; + + ControlPassword := ini.ReadString('Main', 'ControlPassword', ''); + Temp := ini.ReadString('Main', 'HashedControlPassword', ''); + if Temp = '' then + begin + ControlPassword := ''; + ini.WriteString('Main', 'ControlPassword', ''); + end; + if (ControlPassword = '')then + begin + SetTorConfig('CookieAuthentication', '1'); + edControlPassword.Text := ''; + end + else + edControlPassword.Text := Decrypt(ControlPassword, 'True'); + if GetTorConfig('CookieAuthentication', '0') = '1' then + begin + cbxAuthMetod.ItemIndex := 0; + DeleteTorConfig('HashedControlPassword'); + end + else + begin + cbxAuthMetod.ItemIndex := 1; + SetTorConfig('HashedControlPassword', Temp); + end; + CheckAuthMetodContols; + + LoadSettings(miSafeLogging); + LoadSettings(cbLearnCircuitBuildTimeout); + LoadSettings(cbAvoidDiskWrites); + LoadSettings(cbStrictNodes, [cfBoolInvert]); + LoadSettings(cbEnforceDistinctSubnets); + LoadSettings(udMaxCircuitDirtiness); + LoadSettings(udCircuitBuildTimeout); + LoadSettings(udNewCircuitPeriod); + LoadSettings(udMaxClientCircuitsPending); + LoadSettings(udControlPort, [cfAutoAppend]); + + LoadSettings('Network', udSOCKSPort, ini); + SocksHost := ini.ReadString('Network', 'SOCKSHost', '127.0.0.1'); + ParseStr := Explode(' ', GetTorConfig('SOCKSPort', '127.0.0.1:9050', [cfAutoAppend])); + Temp := ''; + if Length(ParseStr) > 1 then + begin + for i := 1 to Length(ParseStr) - 1 do + begin + ParseStr[i] := Trim(ParseStr[i]); + if ParseStr[i] <> '' then + Temp := Temp + ' ' + ParseStr[i]; + end; + end; + cbxSocksHost.Hint := Temp; + Search := RPos(':', ParseStr[0]); + if Search = 0 then + begin + if ValidInt(ParseStr[0], 0, udSOCKSPort.Max) then + begin + cbEnableSocks.Checked := StrToBool(ParseStr[0]); + if StrToInt(ParseStr[0]) > 0 then + udSOCKSPort.Position := StrToInt(ParseStr[0]); + end + else + Fail := True; + end + else + begin + cbEnableSocks.Checked := True; + if ValidSocket(ParseStr[0]) then + begin + udSOCKSPort.Position := GetPortFromSocket(ParseStr[0]); + SocksHost := GetAddressFromSocket(ParseStr[0]); + end + else + Fail := True; + end; + if Fail or CheckSimilarPorts then + SetTorConfig('SOCKSPort', FormatHost(SocksHost) + ':' + IntToStr(udSOCKSPort.Position) + cbxSocksHost.Hint); + GetLocalInterfaces(cbxSocksHost, SocksHost, True); + + if ini.SectionExists('Transports') then + begin + Transports := TStringList.Create; + try + ini.ReadSectionValues('Transports', Transports); + if Transports.Count > 0 then + LoadTransportsData(Transports); + finally + Transports.Free; + end; + end + else + ResetTransports; + + LoadSettings('Network', cbUseBridges, ini); + LoadSettings('Network', cbUsePreferredBridge, ini); + LoadSettings('Network', cbxBridgesType, ini); + LoadSettings('Network', edPreferredBridge, ini); + LoadBuiltinBridges(cbxBridgesType.ItemIndex = BRIDGES_TYPE_BUILTIN, True, ini.ReadString('Network', 'BridgesList', '')); + if cbxBridgesType.ItemIndex = BRIDGES_TYPE_USER then + LoadUserBridges(ini); + SaveBridgesData(ini); + + LoadSettings('Filter', cbxFilterMode, ini, FILTER_TYPE_COUNTRIES); + FilterEntry := ini.ReadString('Filter', 'EntryNodes', DEFAULT_ENTRY_NODES); + FilterMiddle := ini.ReadString('Filter', 'MiddleNodes', DEFAULT_MIDDLE_NODES); + FilterExit := ini.ReadString('Filter', 'ExitNodes', DEFAULT_EXIT_NODES); + if not FirstLoad then + ClearFilter(ntNone); + GetNodes(FilterEntry, ntEntry, False, ini); + GetNodes(FilterMiddle, ntMiddle, False, ini); + GetNodes(FilterExit, ntExit, False, ini); + + FavoritesEntry := ini.ReadString('Routers', 'EntryNodes', ''); + FavoritesMiddle := ini.ReadString('Routers', 'MiddleNodes', ''); + FavoritesExit := ini.ReadString('Routers', 'ExitNodes', ''); + ExcludeNodes := ini.ReadString('Routers', 'ExcludeNodes', ''); + if not FirstLoad then + ClearRouters(ntNone); + GetNodes(FavoritesEntry, ntEntry, True, ini); + GetNodes(FavoritesMiddle, ntMiddle, True, ini); + GetNodes(FavoritesExit, ntExit, True, ini); + GetNodes(ExcludeNodes, ntExclude, True, ini); + + CalculateTotalNodes; + CalculateFilterNodes; + + lbFavoritesEntry.HelpContext := GetIntDef(ini.ReadInteger('Lists', 'UseFavoritesEntry', 0), 0, 0, 1); + lbFavoritesMiddle.HelpContext := GetIntDef(ini.ReadInteger('Lists', 'UseFavoritesMiddle', 0), 0, 0, 1); + lbFavoritesExit.HelpContext := GetIntDef(ini.ReadInteger('Lists', 'UseFavoritesExit', 0), 0, 0, 1); + lbExcludeNodes.HelpContext := GetIntDef(ini.ReadInteger('Lists', 'UseExcludeNodes', 0), 0, 0, 1); + + LoadSettings('Lists', cbxNodesListType, ini, NL_TYPE_EXLUDE); + case cbxNodesListType.ItemIndex of + NL_TYPE_ENTRY: LoadNodesList(False, FavoritesEntry); + NL_TYPE_MIDDLE: LoadNodesList(False, FavoritesMiddle); + NL_TYPE_EXIT: LoadNodesList(False, FavoritesExit); + NL_TYPE_EXLUDE: LoadNodesList(False, ExcludeNodes); + end; + CheckFilterMode; + CheckFavoritesState; + CheckVanguards(True); + + SetNodes(FilterEntry, FilterMiddle, FilterExit, FavoritesEntry, FavoritesMiddle, FavoritesExit, ExcludeNodes); + ini.WriteInteger('Filter', 'FilterMode', cbxFilterMode.ItemIndex); + + LoadSettings('Server', edNickname, ini); + LoadSettings('Server', edContactInfo, ini); + LoadSettings('Server', edAddress, ini); + LoadSettings('Server', cbxServerMode, ini); + LoadSettings('Server', udORPort, ini); + LoadSettings('Server', udDirPort, ini); + LoadSettings('Server', cbUseDirPort, ini); + LoadSettings('Server', cbDirCache, ini); + LoadSettings('Server', cbListenIPv6, ini); + LoadSettings('Server', cbUseAddress, ini); + LoadSettings('Server', udNumCPUs, ini); + LoadSettings('Server', udTransportPort, ini); + LoadSettings('Server', cbUseNumCPUs, ini); + LoadSettings('Server', udNumCPUs, ini); + LoadSettings('Server', cbUseMaxMemInQueues, ini); + LoadSettings('Server', udMaxMemInQueues, ini); + LoadSettings('Server', cbUseRelayBandwidth, ini); + LoadSettings('Server', udRelayBandwidthRate, ini); + LoadSettings('Server', udRelayBandwidthBurst, ini); + LoadSettings('Server', udMaxAdvertisedBandwidth,ini); + LoadSettings('Server', cbUseUPnP, ini); + LoadSettings('Server', cbIPv6Exit, ini); + LoadSettings('Server', cbPublishServerDescriptor, ini); + LoadSettings('Server', cbDirReqStatistics, ini); + LoadSettings('Server', cbHiddenServiceStatistics, ini); + LoadSettings('Server', cbAssumeReachable, ini); + LoadSettings('Server', cbUseMyFamily, ini); + LoadSettings('Server', cbxBridgeDistribution, ini); + LoadSettings('Server', cbxExitPolicyType, ini); + LineToMemo(ini.ReadString('Server', 'CustomExitPolicy', DEFAULT_CUSTOM_EXIT_POLICY), meExitPolicy, ltPolicy); + LineToMemo(ini.ReadString('Server', 'MyFamily', ''), meMyFamily, ltHash, True); + SaveServerOptions(ini); + + SaveTransportsData(ini, True); + + LoadSettings('Lists', cbUseTrackHostExits, ini); + LoadSettings('Lists', udTrackHostExitsExpire, ini); + LineToMemo(ini.ReadString('Lists', 'TrackHostExits', ''), meTrackHostExits, ltHost, True); + SaveTrackHostExits(ini); + + CheckServerControls; + CheckScannerControls; + CheckStatusControls; + CheckStreamsControls; + CheckCachedFiles; + + HsToDelete := nil; + ClearGrid(sgHs); + ClearGrid(sgHsPorts); + GetLocalInterfaces(cbxHsAddress); + if LoadHiddenServices(ini) = 0 then + UpdateHs + else + begin + HsControlsEnable(True); + SelectHs; + end; + SaveHiddenServices(ini); + + LoadRoutersFilterData(ini.ReadString('Routers', 'CurrentFilter', DEFAULT_ROUTERS_FILTER_DATA), False); + ParseStr := Explode(';', ini.ReadString('Routers', 'DefaultFilter', DEFAULT_ROUTERS_FILTER_DATA)); + if Length(ParseStr) > 4 then + udRoutersWeight.ResetValue := StrToIntDef(ParseStr[4], 10); + + CheckShowRouters; + if FirstLoad then + begin + if ini.ReadBool('Main', 'Terminated', False) = True then + begin + if (cbUseUPnP.Checked) and (cbxServerMode.ItemIndex > 0) then + RemoveUPnPEntry(udORPort.Position, udDirPort.Position, udTransportPort.Position); + end; + TotalDL := ini.ReadInt64('Status', 'TotalDL', 0); + TotalUL := ini.ReadInt64('Status', 'TotalUL', 0); + TotalStartDate := ini.ReadInt64('Status', 'TotalStartDate', 0); + + lbTotalDL.Caption := BytesFormat(TotalDL); + lbTotalUL.Caption := BytesFormat(TotalUL); + if (TotalStartDate = 0) then + begin + TotalStartDate := DateTimeToUnix(Now); + ini.WriteInteger('Status', 'TotalStartDate', TotalStartDate); + end; + gbTotal.Hint := Format(TransStr('402'), [DateTimeToStr(UnixToDateTime(TotalStartDate))]); + + LastPlace := GetIntDef(ini.ReadInteger('Main', 'LastPlace', LP_OPTIONS), LP_OPTIONS, LP_OPTIONS, LP_ROUTERS); + pcOptions.TabIndex := GetIntDef(ini.ReadInteger('Main', 'OptionsPage', 0), 0, 0, pcOptions.PageCount - 1); + ParseStr := Explode(',', ini.ReadString('Main', 'FormPosition', '-1,-1,-1,-1')); + for i := 0 to Length(ParseStr) - 1 do + case i of + 0: DecFormPos.X := StrToIntDef(ParseStr[i], -1); + 1: DecFormPos.Y := StrToIntDef(ParseStr[i], -1); + 2: IncFormPos.X := StrToIntDef(ParseStr[i], -1); + 3: IncFormPos.Y := StrToIntDef(ParseStr[i], -1); + end; + + SetDesktopPosition(IncFormPos.X, IncFormPos.Y, GetCheckBorders, True); + DecreaseFormSize; + SetDesktopPosition(DecFormPos.X, DecFormPos.Y, GetCheckBorders, True); + ini.WriteBool('Main', 'Terminated', True); + LoadNetworkCache; + LoadBridgesCache; + if miLoadCachedRoutersOnStartup.Checked then + LoadConsensus + else + begin + LoadRoutersCountries; + ShowFilter; + ShowRouters; + ShowCircuits; + CheckTorAutoStart; + end; + end + else + begin + SetDesktopPosition(Tcp.Left, Tcp.Top, GetCheckBorders, True); + if ConsensusUpdated then + LoadConsensus + else + begin + CheckCountryIndexInList; + ShowFilter; + ShowRouters; + if ConnectState = 0 then + ShowCircuits; + end; + RoutersUpdated := False; + FilterUpdated := False; + end; + SaveTorConfig; + EnableOptionButtons(False); + finally + ini.UpdateFile; + ini.Free; + end; +end; + +procedure TTcp.LoadNetworkCache; +var + DataLength, i: Integer; + ParseStr: ArrOfStr; + GeoIpCache: TStringList; + GeoIpInfo: TGeoIpInfo; + FilterInfo: TFilterInfo; +begin + if FileExists(NetworkCacheFile) then + begin + GeoIpCache := TStringList.Create; + try + GeoIpCache.LoadFromFile(NetworkCacheFile); + for i := 0 to GeoIpCache.Count - 1 do + begin + ParseStr := Explode(',', GeoIpCache[i]); + DataLength := Length(ParseStr); + if DataLength in [2..4] then + begin + if FilterDic.TryGetValue(ParseStr[1], FilterInfo) then + begin + if ValidAddress(ParseStr[0]) = 1 then + begin + GeoIpInfo.cc := FilterInfo.cc; + if DataLength > 2 then + GeoIpInfo.ping := StrToIntDef(ParseStr[2], 0) + else + GeoIpInfo.ping := 0; + if DataLength > 3 then + GeoIpInfo.ports := ParseStr[3] + else + GeoIpInfo.ports := ''; + GeoIpDic.AddOrSetValue(ParseStr[0], GeoIpInfo); + end; + end; + end; + end; + finally + GeoIpCache.Free; + end; + end; +end; + +procedure TTcp.SaveNetworkCache; +var + GeoIpCache: TStringList; + Item: TPair; + PingData, PortsData: string; +begin + if cbUseNetworkCache.Checked then + begin + GeoIpCache := TStringList.Create; + try + for Item in GeoIpDic do + begin + if Item.Value.ports = '' then + PortsData := '' + else + PortsData := ',' + Item.Value.ports; + + if Item.Value.ping = 0 then + begin + if PortsData = '' then + PingData := '' + else + PingData := ',0' + end + else + PingData := ',' + IntToStr(Item.Value.ping); + + GeoIpCache.Append(Item.Key + ',' + CountryCodes[Item.Value.cc] + PingData + PortsData); + end; + if GeoIpCache.Count > 0 then + GeoIpCache.SaveToFile(NetworkCacheFile); + finally + GeoIpCache.Free; + end; + end; +end; + +procedure TTCP.LoadBridgesCache; +var + DataLength, i, j: Integer; + BridgesCache: TStringList; + BridgeInfo: TBridgeInfo; + ParseStr, IpStr: ArrOfStr; + BridgeStr: string; +begin + if FileExists(BridgesCacheFile) then + begin + BridgesCache := TStringList.Create; + try + BridgesCache.LoadFromFile(BridgesCacheFile); + if BridgesCache.Count = 0 then + Exit; + for i := 0 to BridgesCache.Count - 1 do + begin + ParseStr := Explode('|', BridgesCache[i]); + DataLength := Length(ParseStr); + if DataLength in [8..10] then + begin + BridgeInfo.Router.Flags := [rfBridge]; + BridgeInfo.Router.Params := ROUTER_BRIDGE; + BridgeInfo.Router.Name := ParseStr[1]; + BridgeInfo.Router.IPv4 := ''; + BridgeInfo.Router.IPv6 := ''; + IpStr := Explode(',', ParseStr[2]); + for j := 0 to Length(IpStr) - 1 do + begin + case ValidAddress(IpStr[j], False, True) of + 1: BridgeInfo.Router.IPv4 := IpStr[j]; + 2: BridgeInfo.Router.IPv6 := IpStr[j]; + end; + end; + if BridgeInfo.Router.IPv6 <> '' then + Inc(BridgeInfo.Router.Params, ROUTER_REACHABLE_IPV6); + BridgeInfo.Router.OrPort := StrToIntDef(ParseStr[3], 0); + BridgeInfo.Router.DirPort := 0; + BridgeInfo.Router.Bandwidth := StrToIntDef(ParseStr[4], 0); + BridgeInfo.Router.Version := ParseStr[5]; + BridgeInfo.Kind := GetIntDef(StrToIntDef(ParseStr[6], BRIDGE_RELAY), BRIDGE_RELAY, BRIDGE_RELAY, BRIDGE_NATIVE); + if ParseStr[7] = '1' then + Include(BridgeInfo.Router.Flags, rfV2Dir); + if DataLength > 8 then + BridgeInfo.Transport := ParseStr[8] + else + BridgeInfo.Transport := ''; + if DataLength > 9 then + BridgeInfo.Params := ParseStr[9] + else + BridgeInfo.Params := ''; + + BridgeStr := Trim( + BridgeInfo.Transport + ' ' + + BridgeInfo.Router.IPv4 + ':' + + IntToStr(BridgeInfo.Router.OrPort) + ' ' + + ParseStr[0] + ' ' + + BridgeInfo.Params + ); + if ValidBridge(BridgeStr, btNone) then + BridgesDic.AddOrSetValue(ParseStr[0], BridgeInfo); + end; + end; + finally + BridgesCache.Free; + end; + end; +end; + +procedure TTcp.SaveBridgesCache; +var + BridgesCache: TStringList; + Item: TPair; + Address, Transport, Params: string; +begin + BridgesCache := TStringList.Create; + try + for Item in BridgesDic do + begin + if Item.Value.Router.IPv6 = '' then + Address := Item.Value.Router.IPv4 + else + Address := Item.Value.Router.IPv4 + ',' + Item.Value.Router.IPv6; + + if Item.Value.Transport = '' then + Transport := '' + else + Transport := '|' + Item.Value.Transport; + + if Item.Value.Params <> '' then + begin + Params := '|' + Item.Value.Params; + if Transport = '' then + Params := '|' + Params; + end + else + Params := ''; + BridgesCache.Append( + Item.Key + '|' + + Item.Value.Router.Name + '|' + + Address + '|' + + IntToStr(Item.Value.Router.OrPort) + '|' + + IntToStr(Item.Value.Router.Bandwidth) + '|' + + Item.Value.Router.Version + '|' + + IntToStr(Item.Value.Kind) + '|' + + IntToStr(Integer(rfV2Dir in Item.Value.Router.Flags)) + + Transport + + Params + ); + end; + if BridgesDic.Count > 0 then + BridgesCache.SaveToFile(BridgesCacheFile) + else + DeleteFile(BridgesCacheFile); + finally + BridgesCache.Free; + end; +end; + +procedure TTcp.SetServerPort(PortControl: TUpDown); +var + PortName, FlagsStr: string; +begin + PortName := Copy(PortControl.Name, 3); + if cbListenIPv6.Checked then + FlagsStr := '' + else + FlagsStr := ' IPv4Only'; + SetTorConfig(PortName, IntToStr(PortControl.Position) + FlagsStr); +end; + +procedure TTcp.CheckFilterMode; +var + FMode: Integer; +begin + FMode := cbxFilterMode.ItemIndex; + if (FMode = 2) and (lbFavoritesTotal.Tag = 0) then + FMode := 1; + if (FMode = 2) and (lbFavoritesEntry.HelpContext = 0) and (lbFavoritesMiddle.HelpContext = 0) and (lbFavoritesExit.HelpContext = 0) then + FMode := 1; + if (FMode = 1) and (lbFilterEntry.Tag = 0) and (lbFilterMiddle.Tag = 0) and (lbFilterExit.Tag = 0) then + FMode := 0; + if (FMode = 1) and not GeoIpExists then + FMode := 0; + cbxFilterMode.ItemIndex := FMode; +end; + +function TTcp.CheckTransports: Boolean; +var + i, j, ResultCode: Integer; + TransportID: Byte; + T: TTransportInfo; + Transports, Item, Handler, Params, Msg, ResultMsg: string; + ParseStr: ArrOfStr; +begin + Result := True; + ResultCode := 0; + TransportsDic.Clear; + if not edTransports.Enabled then + Exit; + edTransports.Text := StringReplace(edTransports.Text, ' ', '', [rfReplaceAll]); + edTransportsHandler.Text := StringReplace(edTransportsHandler.Text, ' ', '', [rfReplaceAll]); + meHandlerParams.Text := Trim(meHandlerParams.Text); + Msg := TTabSheet(gbTransports.GetParentComponent).Caption + ' - ' + gbTransports.Caption + BR + BR; + for i := 1 to sgTransports.RowCount - 1 do + begin + TransportID := GetTransportID(sgTransports.Cells[PT_TYPE, i]); + Transports := sgTransports.Cells[PT_TRANSPORTS, i]; + Handler := sgTransports.Cells[PT_HANDLER, i]; + Params := sgTransports.Cells[PT_PARAMS, i]; + + if not FileExists(TransportsDir + Handler) then + begin + ResultCode := 2; + Break; + end; + + if Pos('|', Params) <> 0 then + begin + ResultCode := 5; + Break; + end; + + ParseStr := Explode(',', Transports); + for j := 0 to Length(ParseStr) - 1 do + begin + Item := Trim(ParseStr[j]); + if Item = '' then + begin + ResultCode := 1; + Break; + end; + + ResultMsg := CheckEditString(Item, '_', False); + if ResultMsg <> '' then + begin + ResultCode := 3; + Break; + end; + + if TransportsDic.TryGetValue(Item, T) then + begin + if (T.TransportID = TransportID) or + (T.TransportID = TRANSPORT_BOTH) or + (TransportID = TRANSPORT_BOTH) then + begin + ResultCode := 4; + Break; + end; + end; + T.TransportID := TransportID; + T.BridgeType := []; + TransportsDic.AddOrSetValue(Item, T); + end; + + if ResultCode > 0 then + Break; + + end; + if ResultCode > 0 then + begin + Result := False; + sgTransports.Row := i; + SelectTransports; + case ResultCode of + 1: GoToInvalidOption(tsOther, Msg + TransStr('394'), edTransports); + 2: GoToInvalidOption(tsOther, Msg + TransStr('395'), edTransportsHandler); + 3: GoToInvalidOption(tsOther, Msg + ResultMsg, edTransports); + 4: GoToInvalidOption(tsOther, Msg + TransStr('399'), edTransports); + 5: GoToInvalidOption(tsOther, Msg + Format(TransStr('255'), ['|']), meHandlerParams); + end; + end; +end; + +function TTcp.CheckHsTable: Boolean; +var + Duplicate: Boolean; + DirName, Msg, ResultMsg: string; + i, j, ResultCode: Integer; +begin + Result := True; + ResultCode := 0; + j := 0; + Duplicate := False; + if not edHsName.Enabled then + Exit; + Msg := TTabSheet(sgHs.GetParentComponent).Caption + ' - ' + lbHsName.Caption + BR + BR; + for i := 1 to sgHs.RowCount - 1 do + begin + DirName := sgHs.Cells[HS_NAME, i]; + if DirName = '' then + begin + ResultCode := 1; + Break; + end; + ResultMsg := CheckEditString(DirName, '_'); + if ResultMsg <> '' then + begin + ResultCode := 3; + Break; + end; + for j := 1 to sgHs.RowCount - 1 do + if (i <> j) and (DirName = sgHs.Cells[HS_NAME, j]) then + begin + Duplicate := True; + Break; + end; + if Duplicate then + begin + ResultCode := 2; + Break; + end; + end; + if ResultCode > 0 then + begin + Result := False; + if Duplicate then + sgHs.Row := j + else + sgHs.Row := i; + SelectHs; + case ResultCode of + 1: GoToInvalidOption(tsHs, Msg + TransStr('248'), edHsName); + 2: GoToInvalidOption(tsHs, Msg + TransStr('249'), edHsName); + 3: GoToInvalidOption(tsHs, Msg + ResultMsg, edHsName); + end; + end; +end; + +function TTcp.CheckHsPorts: Boolean; +var + Duplicate: Boolean; + i, j, k, ResultCode: Integer; + Msg: string; + ParseStr: ArrOfStr; +begin + ResultCode := 0; + Result := True; + Duplicate := False; + if not sgHsPorts.Enabled then + Exit; + Msg := TTabSheet(sgHs.GetParentComponent).Caption + ' - ' + TransStr('250') + BR + BR; + k := 0; + for i := 1 to sgHs.RowCount - 1 do + begin + if (sgHs.Cells[HS_PORTS_DATA, i]) = '' then + begin + ResultCode := 1; + Break; + end; + ParseStr := Explode('|', sgHs.Cells[HS_PORTS_DATA, i]); + if Length(ParseStr) > 1 then + begin + for j := 0 to Length(ParseStr) - 1 do + begin + for k := j + 1 to Length(ParseStr) - 1 do + begin + if ParseStr[j] = ParseStr[k] then + begin + Duplicate := True; + Break; + end; + end; + if Duplicate then + Break; + end; + if Duplicate then + begin + ResultCode := 2; + Break; + end; + end; + end; + + if ResultCode > 0 then + begin + Result := False; + sgHs.Row := i; + SelectHs; + if Duplicate then + begin + sgHsPorts.Row := k + 1; + SelectHsPorts; + end; + case ResultCode of + 1: GoToInvalidOption(tsHs, Msg + TransStr('251')); + 2: GoToInvalidOption(tsHs, Msg + TransStr('252')); + end; + end; +end; + +function TTcp.CheckNetworkOptions: Boolean; +begin + if (cbxServerMode.ItemIndex > 0) and (cbUseReachableAddresses.Checked or cbUseProxy.Checked or cbUseBridges.Checked) then + begin + Result := False; + if ShowMsg(TransStr('261'), TransStr('324'), mtWarning, True) then + begin + cbUseReachableAddresses.Checked := False; + cbUseProxy.Checked := False; + cbUseBridges.Checked := False; + ApplyOptions; + end + else + GoToInvalidOption(tsNetwork); + end + else + Result := True; +end; + +function TTcp.RouterInNodesList(RouterID: string; RouterInfo: TRouterInfo; NodeType: TNodeType; SkipCodes: Boolean = False): Boolean; +var + ParseStr: ArrOfStr; + KeyStr: string; + i,j: Integer; +begin + Result := False; + for i := 0 to 3 do + begin + if i < 3 then + begin + if SkipCodes and (i = 1) then + Continue; + case i of + 0: KeyStr := RouterID; + 1: KeyStr := CountryCodes[GetCountryValue(RouterInfo.IPv4)]; + 2: KeyStr := RouterInfo.IPv4; + end; + if NodesDic.ContainsKey(KeyStr) then + Result := NodeType in NodesDic.Items[KeyStr]; + end + else + begin + KeyStr := FindInRanges(RouterInfo.IPv4); + if KeyStr <> '' then + begin + ParseStr := Explode(',', KeyStr); + for j := 0 to Length(ParseStr) - 1 do + begin + if NodesDic.ContainsKey(ParseStr[j]) then + begin + Result := NodeType in NodesDic.Items[ParseStr[j]]; + if Result then + Exit; + end; + end; + end; + end; + if Result then + Exit; + end; +end; + +function TTcp.CheckVanguards(Silent: Boolean = False): Boolean; +var + SupportVanguardsLite: Boolean; + Router: TPair; + NodesCount: Integer; + + function GetMinGuards: Integer; + begin + case cbxVanguardLayerType.ItemIndex of + 1: Result := L1_NUM_GUARDS + L2_NUM_GUARDS; + 2: Result := L1_NUM_GUARDS + L3_NUM_GUARDS; + 3: Result := L1_NUM_GUARDS + L2_NUM_GUARDS + L3_NUM_GUARDS; + else + Result := L1_NUM_GUARDS; + end; + end; + + procedure ResetVanguards; + begin + if SupportVanguardsLite then + cbxVanguardLayerType.ItemIndex := 0 + else + cbUseHiddenServiceVanguards.Checked := False; + end; + +begin + Result := True; + SupportVanguardsLite := CheckFileVersion(TorVersion, '0.4.7.1'); + if cbUseHiddenServiceVanguards.Checked then + begin + NodesCount := 0; + if RoutersDic.Count > 0 then + begin + for Router in RoutersDic do + begin + if (rfGuard in Router.Value.Flags) then + begin + if RouterInNodesList(Router.Key, Router.Value, ntEntry, True) then + begin + if not RouterInNodesList(Router.Key, Router.Value, ntExclude) then + Inc(NodesCount); + end; + end; + end; + end; + + if ((NodesCount < GetMinGuards) and (RoutersDic.Count > 0)) and (cbxVanguardLayerType.ItemIndex <> 0) then + begin + if Silent then + ResetVanguards + else + begin + Result := False; + if ShowMsg(Format(TransStr('161'), [GetMinGuards, NodesCount]), TransStr('324'), mtWarning, True) then + begin + ResetVanguards; + ApplyOptions; + end + else + GoToInvalidOption(tsLists); + end; + end + else + begin + if cbxVanguardLayerType.ItemIndex = 0 then + ResetVanguards; + end; + end; +end; + +procedure TTcp.SetNodes(FilterEntry, FilterMiddle, FilterExit, FavoritesEntry, FavoritesMiddle, FavoritesExit, ExcludeNodes: string); +var + Vanguards: string; + ParseStr: ArrOfStr; + i: Integer; +begin + DeleteTorConfig('HSLayer2Nodes'); + DeleteTorConfig('HSLayer3Nodes'); + DeleteTorConfig('VanguardsLiteEnabled'); + if cbUseHiddenServiceVanguards.Checked then + begin + ParseStr := Explode(',', RemoveBrackets(FavoritesEntry)); + Vanguards := ''; + for i := 0 to Length(ParseStr) - 1 do + begin + if Length(ParseStr[i]) > 2 then + Vanguards := Vanguards + ',' + ParseStr[i]; + end; + Delete(Vanguards, 1, 1); + + case cbxVanguardLayerType.ItemIndex of + 1: SetTorConfig('HSLayer2Nodes', Vanguards); + 2: SetTorConfig('HSLayer3Nodes', Vanguards); + 3: + begin + SetTorConfig('HSLayer2Nodes', Vanguards); + SetTorConfig('HSLayer3Nodes', Vanguards); + end; + end; + end + else + begin + if CheckFileVersion(TorVersion, '0.4.7.1') then + SetTorConfig('VanguardsLiteEnabled', '0'); + end; + + case cbxFilterMode.ItemIndex of + 0: + begin + DeleteTorConfig('EntryNodes'); + DeleteTorConfig('MiddleNodes'); + DeleteTorConfig('ExitNodes'); + end; + 1: + begin + if cbUseBridges.Checked then + DeleteTorConfig('EntryNodes') + else + SetTorConfig('EntryNodes', FilterEntry); + SetTorConfig('MiddleNodes', FilterMiddle); + SetTorConfig('ExitNodes', FilterExit); + end; + 2: + begin + if miReplaceDisabledFavoritesWithCountries.Checked and + ((FavoritesEntry = '') or (lbFavoritesEntry.HelpContext = 0)) then + FavoritesEntry := FilterEntry; + if miReplaceDisabledFavoritesWithCountries.Checked and + ((FavoritesMiddle = '') or (lbFavoritesMiddle.HelpContext = 0)) then + FavoritesMiddle := FilterMiddle; + if miReplaceDisabledFavoritesWithCountries.Checked and + ((FavoritesExit = '') or (lbFavoritesExit.HelpContext = 0)) then + FavoritesExit := FilterExit; + + if cbUseBridges.Checked then + DeleteTorConfig('EntryNodes') + else + SetTorConfig('EntryNodes', FavoritesEntry); + SetTorConfig('MiddleNodes', FavoritesMiddle); + SetTorConfig('ExitNodes', FavoritesExit); + end; + end; + if lbExcludeNodes.HelpContext = 1 then + SetTorConfig('ExcludeNodes', ExcludeNodes) + else + DeleteTorConfig('ExcludeNodes'); + DeleteTorConfig('ExcludeExitNodes'); +end; + +procedure TTcp.ApplyOptions(AutoResolveErrors: Boolean = False); +var + ini: TMemIniFile; + i: Integer; + Item: TPair; + NodeItem: TPair; + Temp: string; + FilterEntry, FilterMiddle, FilterExit, ExcludeNodes, NodeStr: string; + FavoritesEntry, FavoritesMiddle, FavoritesExit: string; + StyleName: string; +begin + OptionsLocked := False; + if (cbxAuthMetod.ItemIndex = 1) and (CheckEditString(edControlPassword.Text, '', True, lbControlPassword.Caption, edControlPassword) <> '') then + Exit; + if (cbxServerMode.ItemIndex > 0) and (CheckEditString(edNickname.Text, '', True, lbNickname.Caption, edNickname) <> '') then + Exit; + if not CheckVanguards(AutoResolveErrors) then + Exit; + if not CheckNetworkOptions then + Exit; + if not CheckHsTable then + Exit; + if not CheckHsPorts then + Exit; + if not CheckTransports then + Exit; + LoadTorConfig; + CheckRequiredFiles; + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + if cbxLanguage.ItemIndex <> cbxLanguage.Tag then + Translate(cbxLanguage.Text); + + if cbxThemes.ItemIndex = 0 then + StyleName := 'Windows' + else + StyleName := cbxThemes.Text; + + if (ConnectState = 2) and (AutoScanStage = 0) and not ConsensusUpdated and + (ini.ReadBool('Scanner', 'AutoScanNewNodes', True) = False) then + begin + if Tcp.cbAutoScanNewNodes.Checked and + (Tcp.cbEnablePingMeasure.Checked or Tcp.cbEnableDetectAliveNodes.Checked) then + AutoScanStage := 1; + end; + + ini.WriteInteger('Main', 'Language', Integer(cbxLanguage.Items.Objects[cbxLanguage.ItemIndex])); + ini.WriteString('Main', 'Theme', StyleName); + ini.WriteInteger('Main', 'LastPlace', LastPlace); + ini.WriteInteger('Main', 'OptionsPage', pcOptions.TabIndex); + + ini.WriteBool('Main', 'ConnectOnStartup', cbConnectOnStartup.Checked); + ini.WriteBool('Main', 'RestartOnControlFail', cbRestartOnControlFail.Checked); + ini.WriteBool('Main', 'MinimizeOnClose', cbMinimizeOnClose.Checked); + ini.WriteBool('Main', 'MinimizeOnStartup', cbMinimizeOnStartup.Checked); + ini.WriteBool('Main', 'ShowBalloonHint', cbShowBalloonHint.Checked); + ini.WriteBool('Main', 'ShowBalloonOnlyWhenHide', cbShowBalloonOnlyWhenHide.Checked); + ini.WriteBool('Main', 'StayOnTop', cbStayOnTop.Checked); + ini.WriteBool('Main', 'NoDesktopBorders', cbNoDesktopBorders.Checked); + ini.WriteBool('Main', 'NoDesktopBordersOnlyEnlarged', cbNoDesktopBordersOnlyEnlarged.Checked); + ini.WriteBool('Main', 'HideIPv6Addreses', cbHideIPv6Addreses.Checked); + ini.WriteBool('Main', 'UseOpenDNS', cbUseOpenDNS.Checked); + ini.WriteBool('Main', 'UseOpenDNSOnlyWhenUnknown', cbUseOpenDNSOnlyWhenUnknown.Checked); + ini.WriteBool('Main', 'RememberEnlargedPosition', cbRememberEnlargedPosition.Checked); + ini.WriteBool('Main', 'ClearPreviousSearchQuery', cbClearPreviousSearchQuery.Checked); + ini.WriteBool('Main', 'UseNetworkCache', cbUseNetworkCache.Checked); + + ini.WriteBool('Scanner', 'EnablePingMeasure', cbEnablePingMeasure.Checked); + ini.WriteBool('Scanner', 'EnableDetectAliveNodes', cbEnableDetectAliveNodes.Checked); + ini.WriteBool('Scanner', 'AutoScanNewNodes', cbAutoScanNewNodes.Checked); + ini.WriteInteger('Scanner', 'ScanPortTimeout', udScanPortTimeout.Position); + ini.WriteInteger('Scanner', 'ScanPingTimeout', udScanPingTimeout.Position); + ini.WriteInteger('Scanner', 'ScanPortionTimeout', udScanPortionTimeout.Position); + ini.WriteInteger('Scanner', 'DelayBetweenAttempts', udDelayBetweenAttempts.Position); + ini.WriteInteger('Scanner', 'ScanPingAttempts', udScanPingAttempts.Position); + ini.WriteInteger('Scanner', 'ScanPortAttempts', udScanPortAttempts.Position); + ini.WriteInteger('Scanner', 'ScanMaxThread', udScanMaxThread.Position); + ini.WriteInteger('Scanner', 'ScanPortionSize', udScanPortionSize.Position); + ini.WriteInteger('Scanner', 'FullScanInterval', udFullScanInterval.Position); + ini.WriteInteger('Scanner', 'NonResponsedScanInterval', udNonResponsedScanInterval.Position); + ini.WriteInteger('Scanner', 'PartialScansCounts', udPartialScansCounts.Position); + + ini.WriteInteger('AutoSelNodes', 'AutoSelEntryCount', udAutoSelEntryCount.Position); + ini.WriteInteger('AutoSelNodes', 'AutoSelMiddleCount', udAutoSelMiddleCount.Position); + ini.WriteInteger('AutoSelNodes', 'AutoSelExitCount', udAutoSelExitCount.Position); + ini.WriteInteger('AutoSelNodes', 'AutoSelMinWeight', udAutoSelMinWeight.Position); + ini.WriteInteger('AutoSelNodes', 'AutoSelMaxPing', udAutoSelMaxPing.Position); + ini.WriteInteger('AutoSelNodes', 'AutoSelPriority', cbxAutoSelPriority.ItemIndex); + ini.WriteBool('AutoSelNodes', 'AutoSelFastAndStableOnly', cbAutoSelStableOnly.Checked); + ini.WriteBool('AutoSelNodes', 'AutoSelFilterCountriesOnly', cbAutoSelFilterCountriesOnly.Checked); + ini.WriteBool('AutoSelNodes', 'AutoSelUniqueNodes', cbAutoSelUniqueNodes.Checked); + ini.WriteBool('AutoSelNodes', 'AutoSelNodesWithPingOnly', cbAutoSelNodesWithPingOnly.Checked); + ini.WriteBool('AutoSelNodes', 'AutoSelMiddleNodesWithoutDir', cbAutoSelMiddleNodesWithoutDir.Checked); + + SetDesktopPosition(Tcp.Left, Tcp.Top, GetCheckBorders, True); + ini.WriteString('Main', 'FormPosition', GetFormPositionStr); + + edControlPassword.Hint := ini.ReadString('Main', 'HashedControlPassword', ''); + if cbxAuthMetod.ItemIndex = 1 then + begin + if edControlPassword.Text <> '' then + begin + if (edControlPassword.Text <> Decrypt(ControlPassword, 'True')) or (edControlPassword.Hint = '') then + begin + ControlPassword := Crypt(edControlPassword.Text, 'True'); + Temp := GetPasswordHash(edControlPassword.Text); + SetTorConfig('HashedControlPassword', Temp); + ini.WriteString('Main', 'HashedControlPassword', Temp); + ShowBalloon(TransStr('253')); + end + else + SetTorConfig('HashedControlPassword', edControlPassword.Hint); + end + else + cbxAuthMetod.ItemIndex := 0; + end; + if cbxAuthMetod.ItemIndex = 0 then + begin + SetTorConfig('CookieAuthentication', '1'); + if edControlPassword.Text <> '' then + ini.WriteString('Main', 'HashedControlPassword', edControlPassword.Hint) + else + begin + ControlPassword := ''; + ini.WriteString('Main', 'HashedControlPassword', ''); + end; + DeleteTorConfig('HashedControlPassword'); + end + else + DeleteTorConfig('CookieAuthentication'); + ini.WriteString('Main', 'ControlPassword', ControlPassword); + CheckAuthMetodContols; + + for i := 0 to miLogLevel.Count - 1 do + begin + if miLogLevel.items[i].Checked then + begin + SetTorConfig('Log', AnsiLowerCase(copy(miLogLevel.items[i].Name, 3, Length(miLogLevel.items[i].Name) - 2)) + ' stdout'); + Break; + end; + end; + + SetTorConfig('SafeLogging', IntToStr(Integer(miSafeLogging.Checked))); + SetTorConfig('MaxCircuitDirtiness', IntToStr(udMaxCircuitDirtiness.Position)); + SetTorConfig('CircuitBuildTimeout', IntToStr(udCircuitBuildTimeout.Position)); + SetTorConfig('MaxClientCircuitsPending', IntToStr(udMaxClientCircuitsPending.Position)); + SetTorConfig('LearnCircuitBuildTimeout', IntToStr(Integer(cbLearnCircuitBuildTimeout.Checked))); + SetTorConfig('EnforceDistinctSubnets', IntToStr(Integer(cbEnforceDistinctSubnets.Checked))); + SetTorConfig('StrictNodes', IntToStr(Integer(not cbStrictNodes.Checked))); + SetTorConfig('NewCircuitPeriod', IntToStr(udNewCircuitPeriod.Position)); + SetTorConfig('AvoidDiskWrites', IntToStr(Integer(cbAvoidDiskWrites.Checked))); + + CheckSimilarPorts; + if cbEnableSocks.Checked then + SetTorConfig('SOCKSPort', FormatHost(cbxSocksHost.Text) + ':' + IntToStr(udSOCKSPort.Position) + cbxSocksHost.Hint) + else + SetTorConfig('SOCKSPort', '0' + cbxSocksHost.Hint); + ini.WriteString('Network', 'SOCKSHost', FormatHost(cbxSocksHost.Text)); + ini.WriteInteger('Network', 'SOCKSPort', udSOCKSPort.Position); + SetTorConfig('ControlPort', IntToStr(udControlPort.Position)); + + SaveReachableAddresses(ini); + SaveProxyData(ini); + UpdateBridgesControls(True, False); + SaveBridgesData(ini); + + for Item in FilterDic do + begin + if ntEntry in Item.Value.Data then + FilterEntry := FilterEntry + ',{' + Item.Key + '}'; + if ntMiddle in Item.Value.Data then + FilterMiddle := FilterMiddle + ',{' + Item.Key + '}'; + if ntExit in Item.Value.Data then + FilterExit := FilterExit + ',{' + Item.Key + '}'; + end; + Delete(FilterEntry, 1, 1); + Delete(FilterMiddle, 1, 1); + Delete(FilterExit, 1, 1); + ini.WriteString('Filter', 'EntryNodes', FilterEntry); + ini.WriteString('Filter', 'MiddleNodes', FilterMiddle); + ini.WriteString('Filter', 'ExitNodes', FilterExit); + + for NodeItem in NodesDic do + begin + NodeStr := NodeItem.Key; + if FilterDic.ContainsKey(NodeStr) then + NodeStr := '{' + NodeStr + '}'; + if ntEntry in NodeItem.Value then + FavoritesEntry := FavoritesEntry + ',' + NodeStr; + if ntMiddle in NodeItem.Value then + FavoritesMiddle := FavoritesMiddle + ',' + NodeStr; + if ntExit in NodeItem.Value then + FavoritesExit := FavoritesExit + ',' + NodeStr; + if ntExclude in NodeItem.Value then + ExcludeNodes := ExcludeNodes + ',' + NodeStr; + end; + Delete(FavoritesEntry, 1, 1); + Delete(FavoritesMiddle, 1, 1); + Delete(FavoritesExit, 1, 1); + Delete(ExcludeNodes, 1, 1); + + CheckFilterMode; + CheckFavoritesState; + SetNodes(FilterEntry, FilterMiddle, FilterExit, FavoritesEntry, FavoritesMiddle, FavoritesExit, ExcludeNodes); + + ini.WriteString('Routers', 'EntryNodes', FavoritesEntry); + ini.WriteString('Routers', 'MiddleNodes', FavoritesMiddle); + ini.WriteString('Routers', 'ExitNodes', FavoritesExit); + ini.WriteString('Routers', 'ExcludeNodes', ExcludeNodes); + ini.WriteInteger('Lists', 'UseFavoritesEntry', lbFavoritesEntry.HelpContext); + ini.WriteInteger('Lists', 'UseFavoritesMiddle', lbFavoritesMiddle.HelpContext); + ini.WriteInteger('Lists', 'UseFavoritesExit', lbFavoritesExit.HelpContext); + ini.WriteInteger('Lists', 'UseExcludeNodes', lbExcludeNodes.HelpContext); + ini.WriteInteger('Lists', 'NodesListType', cbxNodesListType.ItemIndex); + ini.WriteBool('Lists', 'UseHiddenServiceVanguards', cbUseHiddenServiceVanguards.Checked); + ini.WriteInteger('Lists', 'VanguardLayerType', cbxVanguardLayerType.ItemIndex); + ini.WriteInteger('Filter', 'FilterMode', cbxFilterMode.ItemIndex); + ini.WriteBool('Filter', 'ReplaceDisabledFavoritesWithCountries', miReplaceDisabledFavoritesWithCountries.Checked); + + SaveServerOptions(ini); + SaveTransportsData(ini, False); + SaveHiddenServices(ini); + SaveTrackHostExits(ini); + + CheckCachedFiles; + CheckStatusControls; + EnableOptionButtons(False); + if ConsensusUpdated then + LoadConsensus + else + begin + if cbxLanguage.ItemIndex <> cbxLanguage.Tag then + begin + LoadRoutersCountries; + ShowFilter; + ShowRouters; + if ConnectState = 0 then + ShowCircuits; + end + else + begin + if RoutersUpdated then + ShowRouters; + end; + end; + + if cbxLanguage.ItemIndex <> cbxLanguage.Tag then + cbxLanguage.Tag := cbxLanguage.ItemIndex; + + UpdateOptionsAfterRoutersUpdate; + + SaveTorConfig; + ReloadTorConfig; + if OpenDNSUpdated then + begin + OpenDNSUpdated := False; + GetServerInfo; + end; + finally + ini.UpdateFile; + ini.Free; + end; +end; + +procedure TTcp.CheckCachedFiles; +begin + if ConnectState = 0 then + begin + if ((cbxServerMode.ItemIndex = 0) and not cbUseBridges.checked) or + ((cbxServerMode.ItemIndex > 0) and not cbDirCache.Checked) then + begin + RenameFile(UserDir + 'cached-consensus', UserDir + 'cached-consensus.tmp'); + RenameFile(UserDir + 'cached-descriptors', UserDir + 'cached-descriptors.tmp'); + RenameFile(UserDir + 'cached-descriptors.new', UserDir + 'cached-descriptors.new.tmp'); + end + else + begin + RenameFile(UserDir + 'cached-consensus.tmp', UserDir + 'cached-consensus'); + RenameFile(UserDir + 'cached-descriptors.tmp', UserDir + 'cached-descriptors'); + RenameFile(UserDir + 'cached-descriptors.new.tmp', UserDir + 'cached-descriptors.new'); + ConsensusUpdated := True; + end; + end; +end; + +procedure TTcp.ClearFilter(NodeType: TNodeType; Silent: Boolean = True); +var + Item: TPair; + Filter: TFilterInfo; +begin + for Item in FilterDic do + begin + Filter := Item.Value; + case NodeType of + ntNone: Filter.Data := []; + ntExclude: NodesDic.Remove(CountryCodes[Filter.cc]); + else + Exclude(Filter.Data, NodeType); + end; + if NodeType <> ntExclude then + FilterDic.AddOrSetValue(Item.Key, Filter); + end; + + if not Silent then + begin + CalculateFilterNodes; + FilterUpdated := True; + if NodeType = ntExclude then + ExcludeUpdated := True; + ShowFilter; + EnableOptionButtons; + end; +end; + +procedure TTcp.ClearRouters(NodeType: TNodeType; Silent: Boolean = True); +var + Item: TPair; + Data, ExcludeData: TNodeTypes; +begin + if NodeType = ntNone then + begin + NodesDic.Clear; + RangesDic.Clear; + end + else + begin + if NodeType = ntFavorites then + ExcludeData := [ntEntry, ntMiddle, ntExit] + else + ExcludeData := [NodeType]; + for Item in NodesDic do + begin + Data := Item.Value; + Data := Data - ExcludeData; + NodesDic.AddOrSetValue(Item.Key, Data); + end; + end; + if not Silent then + begin + CalculateTotalNodes(False); + ShowRouters; + RoutersUpdated := True; + if NodeType = ntExclude then + FilterUpdated := True; + EnableOptionButtons; + end; +end; + +procedure TTcp.miClearRoutersAbsentClick(Sender: TObject); +var + IpList: TDictionary; + NodeItem: TPair; + RouterItem: TPair; + ListItem: TPair; + DeleteExcludeNodes, Search: Boolean; + Cidr: TIPv4Range; + + procedure SetNodesData; + begin + if DeleteExcludeNodes or not (ntExclude in NodeItem.Value) then + NodesDic.AddOrSetValue(NodeItem.Key, []) + else + NodesDic.AddOrSetValue(NodeItem.Key, [ntExclude]); + end; + +begin + if (InfoStage > 0) or Assigned(Consensus) or Assigned(Descriptors) or (RoutersDic.Count = 0) then + Exit; + DeleteExcludeNodes := not ShowMsg(TransStr('358'), '', mtQuestion, True); + IpList := TDictionary.Create; + try + for RouterItem in RoutersDic do + IpList.AddOrSetValue(RouterItem.Value.IPv4, 0); + + for NodeItem in NodesDic do + begin + if ValidHash(NodeItem.Key) then + begin + if not RoutersDic.ContainsKey(NodeItem.Key) then + SetNodesData; + end + else + begin + if ValidAddress(NodeItem.Key, True, True) = 1 then + begin + if Pos('/', NodeItem.Key) = 0 then + begin + if not IpList.ContainsKey(NodeItem.Key) then + SetNodesData; + end + else + begin + Search := False; + Cidr := CidrToRange(NodeItem.Key); + for ListItem in IpList do + if InRange(IpToInt(ListItem.Key), Cidr.IpStart, Cidr.IpEnd) then + begin + Search := True; + Break; + end; + if not Search then + begin + RangesDic.Remove(NodeItem.Key); + SetNodesData; + end; + end; + end + else + begin + if GeoIpDic.Count > 0 then + begin + if FilterDic.ContainsKey(NodeItem.Key) then + begin + if CountryTotals[TOTAL_RELAYS][FilterDic.Items[NodeItem.Key].cc] = 0 then + SetNodesData; + end; + end; + end; + end; + end; + CalculateTotalNodes(False); + ShowRouters; + FilterUpdated := True; + RoutersUpdated := True; + EnableOptionButtons; + finally + IpList.Free; + end; +end; + +procedure TTcp.miClearRoutersIncorrectClick(Sender: TObject); +var + IpList: TDictionary; + UpdateList: TDictionary; + NodeItem: TPair; + RouterItem: TPair; + UpdateItem: TPair; + ConvertToHash: Boolean; + RouterInfo: TRouterInfo; + Ip, CountryCode: string; + + procedure CheckNode(NodeID: string; NodeTypes: TNodeTypes; HashID: string = ''); + var + NodeIsChanged, NodeIsExcluded, NodeIsBridge: Boolean; + Flags: TRouterFlags; + Node, CountryCode: string; + begin + NodeIsChanged := False; + NodeIsExcluded := False; + + if HashID = '' then + Node := NodeID + else + Node := HashID; + + if RoutersDic.TryGetValue(Node, RouterInfo) then + begin + if NodesDic.ContainsKey(NodeID) then + begin + Flags := RouterInfo.Flags; + NodeIsBridge := (NodeTypes <> [ntExclude]) and (rfBridge in Flags) and not (rfRelay in Flags); + + if GeoIpDic.Count > 0 then + begin + CountryCode := CountryCodes[GetCountryValue(RouterInfo.IPv4)]; + if NodesDic.ContainsKey(CountryCode) then + NodeIsExcluded := ntExclude in NodesDic.Items[CountryCode]; + end; + + if NodeIsExcluded or NodeIsBridge then + NodesDic.AddOrSetValue(NodeID, []) + else + begin + if (ntEntry in NodeTypes) and not (rfGuard in Flags) then + begin + Exclude(NodeTypes, ntEntry); + NodeIsChanged := True; + end; + if (ntExit in NodeTypes) and not (rfExit in Flags) then + begin + Exclude(NodeTypes, ntExit); + NodeIsChanged := True; + end; + if NodeIsChanged then + NodesDic.AddOrSetValue(NodeID, NodeTypes); + end; + end; + end; + end; + + procedure CheckRanges(NodeIp: string; NodeTypes: TNodeTypes; HashID: string = ''); + var + RangeItem: TPair; + RangeInfo: TNodeTypes; + NodeID: string; + begin + if RangesDic.Count > 0 then + begin + if HashID = '' then + NodeID := NodeIp + else + NodeID := HashID; + for RangeItem in RangesDic do + begin + if InRange(IpToInt(NodeIp), RangeItem.Value.IpStart, RangeItem.Value.IpEnd) then + begin + if NodesDic.TryGetValue(RangeItem.Key, RangeInfo) then + begin + if NodeTypes = [ntNone] then + CheckNode(RangeItem.Key, RangeInfo, HashID) + else + begin + if NodesDic.ContainsKey(NodeID) then + begin + if (ntExclude in RangeInfo) then + begin + if NodeTypes <> [ntExclude] then + NodesDic.AddOrSetValue(NodeID, []) + end + else + begin + if ntExclude in NodesDic.Items[NodeID] then + NodesDic.AddOrSetValue(RangeItem.Key, []) + end; + end; + end; + end; + end; + end; + end; + end; + + procedure CheckIp(NodeIp: string; NodeTypes: TNodeTypes; HashID: string = ''); + var + ParseStr: ArrOfStr; + NodesList, CountryCode: string; + i: Integer; + begin + + if HashID <> '' then + begin + CheckRanges(NodeIp, NodeTypes, HashID); + CheckNode(HashID, NodeTypes); + Exit; + end + else + CheckRanges(NodeIp, NodeTypes); + + if IpList.TryGetValue(NodeIp, NodesList) then + begin + ParseStr := Explode(',', NodesList); + for i := 0 to Length(ParseStr) - 1 do + begin + if NodesDic.ContainsKey(ParseStr[i]) then + begin + CheckRanges(NodeIp, NodeTypes, ParseStr[i]); + + if (ntExclude in NodeTypes) and (NodesDic.Items[ParseStr[i]] <> [ntExclude]) then + NodesDic.AddOrSetValue(ParseStr[i], []) + else + CheckNode(ParseStr[i], NodesDic.Items[ParseStr[i]]); + + if NodesDic.ContainsKey(NodeIp) then + begin + if NodesDic.Items[NodeIp] <> [ntExclude] then + begin + if (NodesDic.Items[ParseStr[i]] = [ntExclude]) then + NodesDic.AddOrSetValue(NodeIp, []) + else + CheckNode(NodeIp, NodeTypes, ParseStr[i]); + end; + end; + end + else + CheckNode(NodeIp, NodeTypes, ParseStr[i]); + end; + end + else + begin + if NodesDic.ContainsKey(NodeIp) then + begin + if GeoIpDic.Count > 0 then + begin + CountryCode := CountryCodes[GetCountryValue(NodeIp)]; + if NodesDic.ContainsKey(CountryCode) then + begin + if ntExclude in NodesDic.Items[CountryCode] then + NodesDic.AddOrSetValue(NodeIp, []); + end; + end; + end; + end; + end; + + procedure CheckCountry(NodeIp, HashID: string); + begin + if GeoIpDic.Count > 0 then + begin + CountryCode := CountryCodes[GetCountryValue(NodeIp)]; + if NodesDic.ContainsKey(CountryCode) then + begin + if not (ntExclude in NodesDic.Items[CountryCode]) then + CheckNode(CountryCode, NodesDic.Items[CountryCode], HashID); + end; + end; + end; + + procedure CheckRangesNesting(RangeID: string; NodeTypes: TNodeTypes); + var + RangeItem: TPair; + Range: TIpv4Range; + begin + if RangesDic.Count > 1 then + begin + if RangesDic.ContainsKey(RangeID) then + Range := RangesDic.Items[RangeID] + else + Range := CidrToRange(RangeID); + for RangeItem in RangesDic do + begin + if RangeID <> RangeItem.Key then + begin + if InRange(Range.IpStart, RangeItem.Value.IpStart, RangeItem.Value.IpEnd) and + InRange(Range.IpEnd, RangeItem.Value.IpStart, RangeItem.Value.IpEnd) then + begin + if NodesDic.ContainsKey(RangeItem.Key) then + begin + if (ntExclude in NodesDic.Items[RangeItem.Key]) then + begin + if NodesDic.ContainsKey(RangeID) then + NodesDic.AddOrSetValue(RangeID, []); + end + else + begin + if (ntExclude in NodeTypes) then + NodesDic.AddOrSetValue(RangeItem.Key, []) + else + if NodesDic.Items[RangeItem.Key] = NodeTypes then + begin + if NodesDic.ContainsKey(RangeID) then + NodesDic.AddOrSetValue(RangeID, []); + end; + end; + end; + end; + end; + end; + end; + end; + + procedure ConvertNodesToHash(NodeIp, HashID: string); + var + RangeItem: TPair; + CountryCode: string; + IgnoreExclude: Boolean; + + procedure UpdateNodes(NodeID: string); + begin + if NodesDic.ContainsKey(NodeID) then + begin + if NodesDic.ContainsKey(HashID) then + begin + if (ntExclude in NodesDic.Items[NodeID]) then + begin + if IgnoreExclude then + Exit; + NodesDic.AddOrSetValue(HashID, [ntExclude]); + end + else + begin + if NodesDic.Items[HashID] <> [ntExclude] then + NodesDic.AddOrSetValue(HashID, NodesDic.Items[HashID] + NodesDic.Items[NodeID]); + end; + end + else + begin + if IgnoreExclude and (ntExclude in NodesDic.Items[NodeID]) then + Exit; + NodesDic.AddOrSetValue(HashID, NodesDic.Items[NodeID]); + end; + UpdateList.AddOrSetValue(NodeID, 0); + end; + end; + + begin + IgnoreExclude := miIgnoreConvertExcludeNodes.Checked; + + if miConvertIpNodes.Checked then + UpdateNodes(NodeIp); + + if miConvertCidrNodes.Checked then + begin + if RangesDic.Count > 0 then + begin + for RangeItem in RangesDic do + begin + if InRange(IpToInt(NodeIp), RangeItem.Value.IpStart, RangeItem.Value.IpEnd) then + UpdateNodes(RangeItem.Key); + end; + end; + end + else + CheckRanges(NodeIp, [ntNone], HashID); + + if miConvertCountryNodes.Checked then + begin + if GeoIpDic.Count > 0 then + begin + CountryCode := CountryCodes[GetCountryValue(NodeIp)]; + UpdateNodes(CountryCode); + end; + end + else + CheckCountry(NodeIp, HashID); + end; + +begin + + if (RoutersDic.Count = 0) or (InfoStage > 0) or Assigned(Consensus) or Assigned(Descriptors) then + Exit; + + ConvertToHash := miEnableConvertNodesOnIncorrectClear.Checked; + + IpList := TDictionary.Create; + UpdateList := TDictionary.Create; + try + for NodeItem in NodesDic do + begin + if (ntExclude in NodeItem.Value) and (NodeItem.Value <> [ntExclude]) then + NodesDic.AddOrSetValue(NodeItem.Key, [ntExclude]); + if Pos('/', NodeItem.Key) <> 0 then + CheckRangesNesting(NodeItem.Key, NodeItem.Value) + end; + + for RouterItem in RoutersDic do + begin + if IpList.ContainsKey(RouterItem.Value.IPv4) then + IpList.AddOrSetValue(RouterItem.Value.IPv4, IpList.Items[RouterItem.Value.IPv4] + ',' + RouterItem.Key) + else + IpList.AddOrSetValue(RouterItem.Value.IPv4, RouterItem.Key); + if ConvertToHash then + ConvertNodesToHash(RouterItem.Value.IPv4, RouterItem.Key) + else + begin + CheckCountry(RouterItem.Value.IPv4, RouterItem.Key); + CheckRanges(RouterItem.Value.IPv4, [ntNone], RouterItem.Key); + end; + end; + + if ConvertToHash then + begin + for UpdateItem in UpdateList do + begin + if NodesDic.ContainsKey(UpdateItem.Key) then + begin + NodesDic.AddOrSetValue(UpdateItem.Key, []); + if Pos('/', UpdateItem.Key) <> 0 then + RangesDic.Remove(UpdateItem.Key); + end; + end; + end; + + for NodeItem in NodesDic do + begin + if NodeItem.Value <> [] then + begin + if RoutersDic.ContainsKey(NodeItem.Key) then + begin + Ip := RoutersDic.Items[NodeItem.Key].IPv4; + if NodesDic.ContainsKey(Ip) then + CheckIp(Ip, NodesDic.Items[Ip]) + else + CheckIp(Ip, NodeItem.Value, NodeItem.Key); + end + else + begin + if ValidAddress(NodeItem.Key) = 1 then + CheckIp(NodeItem.Key, NodeItem.Value) + end; + end; + end; + finally + IpList.Free; + UpdateList.Free; + end; + + CalculateTotalNodes(False); + ShowRouters; + FilterUpdated := True; + RoutersUpdated := True; + EnableOptionButtons; +end; + +procedure TTcp.miClearServerCacheClick(Sender: TObject); +begin + if not CheckCacheOpConfirmation(TMenuItem(Sender).Caption) then + Exit; + if FileExists(UserDir + 'cached-consensus') or + FileExists(UserDir + 'cached-consensus.tmp') then + begin + DeleteFile(UserDir + 'cached-consensus'); + DeleteFile(UserDir + 'cached-descriptors'); + DeleteFile(UserDir + 'cached-descriptors.new'); + DeleteFile(UserDir + 'cached-descriptors.tmp'); + DeleteFile(UserDir + 'cached-consensus.tmp'); + DeleteFile(UserDir + 'cached-descriptors.new.tmp'); + DeleteDir(UserDir + 'diff-cache'); + end; +end; + +procedure TTcp.miClearUnusedNetworkCacheClick(Sender: TObject); +var + IpList: TDictionary; + DeleteList: TStringList; + Router: TPair; + Item: TPair; + i: Integer; +begin + if not CheckCacheOpConfirmation(TMenuItem(Sender).Caption) then + Exit; + DeleteList := TStringList.Create; + IpList := TDictionary.Create; + try + for Router in RoutersDic do + IpList.AddOrSetValue(Router.Value.IPv4, 0); + for Item in GeoIpDic do + begin + if not IpList.ContainsKey(Item.Key) then + DeleteList.Append(Item.Key); + end; + for i := 0 to DeleteList.Count - 1 do + GeoIpDic.Remove(DeleteList[i]); + finally + IpList.Free; + DeleteList.Free; + end; + SaveNetworkCache; +end; + +procedure TTcp.miConvertCidrNodesClick(Sender: TObject); +begin + SetConfigBoolean('Routers', 'ConvertCidrNodes', miConvertCidrNodes.Checked); +end; + +procedure TTcp.miConvertCountryNodesClick(Sender: TObject); +begin + SetConfigBoolean('Routers', 'ConvertCountryNodes', miConvertCountryNodes.Checked); +end; + +procedure TTcp.miConvertIpNodesClick(Sender: TObject); +begin + SetConfigBoolean('Routers', 'ConvertIpNodes', miConvertIpNodes.Checked); +end; + +procedure TTcp.miIgnoreConvertExcludeNodesClick(Sender: TObject); +begin + SetConfigBoolean('Routers', 'IgnoreConvertExcludeNodes', miIgnoreConvertExcludeNodes.Checked); +end; + +procedure TTcp.ClearFilterClick(Sender: TObject); +begin + ClearFilter(TNodeType(TMenuItem(Sender).Tag), False); +end; + +procedure TTcp.ClearRoutersClick(Sender: TObject); +begin + ClearRouters(TNodeType(TMenuItem(Sender).Tag), False); +end; + +procedure TTcp.cbxExitPolicyTypeChange(Sender: TObject); +begin + if cbxExitPolicyType.ItemIndex = 2 then + meExitPolicy.Enabled := True + else + meExitPolicy.Enabled := False; + EnableOptionButtons; +end; + +procedure TTcp.miWriteLogFileClick(Sender: TObject); +begin + SetConfigBoolean('Log', 'WriteLogFile', miWriteLogFile.Checked); +end; + +procedure TTcp.FilterDeleteClick(Sender: TObject); +var + ini: TMemIniFile; + TemplateName, Temp: string; +begin + TemplateName := TMenuItem(Sender).Caption; + if TemplateName = TransStr('264') then + Temp := '' + else + Temp := TransStr('366') + ' '; + + if ShowMsg(Format(TransStr('263'), [Temp, TemplateName]), '', mtQuestion, True) then + begin + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + if TMenuItem(Sender).Tag = 0 then + ini.EraseSection('Templates') + else + ini.DeleteKey('Templates', IntToStr(TMenuItem(Sender).Tag)); + finally + ini.UpdateFile; + ini.Free; + end; + ShowBalloon(Format(TransStr('365'), [TemplateName])); + end; +end; + +procedure TTcp.FilterLoadClick(Sender: TObject); +var + ParseStr: ArrOfStr; + FUpdated, RUpdated, ImmediateApplyOptions, IgnoreSettings: Boolean; + EmptyCountries, EmptyFavorites, EmptyExcludes: Boolean; + LoadCountries, LoadFavorites, LoadExcludes: Boolean; + ini: TMemIniFile; + n: Integer; +begin + + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + ParseStr := Explode(';', ini.ReadString('Templates', IntToStr(TMenuItem(Sender).Tag), '')); + n := Length(ParseStr); + if n in [5,9] then + begin + if ValidInt(ParseStr[1], 0, 2) then + cbxFilterMode.ItemIndex := StrToInt(ParseStr[1]) + else + begin + ShowMsg(TransStr('254'), '', mtError); + Exit; + end; + + FUpdated := False; + RUpdated := False; + ImmediateApplyOptions := TMenuItem(Sender).Hint = 'ApplyOptions'; + IgnoreSettings := miIgnoreTplLoadParamsOutsideTheFilter.Checked and ImmediateApplyOptions; + EmptyCountries := ((ParseStr[2] = '') and (ParseStr[3] = '') and (ParseStr[4] = '')) and miNotLoadEmptyTplData.Checked; + LoadCountries := (miTplLoadCountries.Checked or IgnoreSettings) and not EmptyCountries; + + if LoadCountries then + begin + ClearFilter(ntNone); + GetNodes(ParseStr[2], ntEntry, False); + GetNodes(ParseStr[3], ntMiddle, False); + GetNodes(ParseStr[4], ntExit, False); + FUpdated := True; + end; + + if n = 9 then + begin + EmptyFavorites := ((ParseStr[5] = '') and (ParseStr[6] = '') and (ParseStr[7] = '')) and miNotLoadEmptyTplData.Checked; + EmptyExcludes := (ParseStr[8] = '') and miNotLoadEmptyTplData.Checked; + LoadFavorites := (miTplLoadRouters.Checked or IgnoreSettings) and not EmptyFavorites; + LoadExcludes := (miTplLoadExcludes.Checked or IgnoreSettings) and not EmptyExcludes; + + if LoadFavorites then + begin + if LoadExcludes then + ClearRouters(ntNone) + else + ClearRouters(ntFavorites); + GetNodes(ParseStr[5], ntEntry, True); + GetNodes(ParseStr[6], ntMiddle, True); + GetNodes(ParseStr[7], ntExit, True); + RUpdated := True; + end; + + if LoadExcludes then + begin + if not LoadFavorites then + ClearRouters(ntExclude); + GetNodes(ParseStr[8], ntExclude, True); + RUpdated := True; + end; + end; + + CalculateTotalNodes; + CalculateFilterNodes; + + if FUpdated then + begin + FilterUpdated := True; + ShowFilter; + if not RUpdated then + begin + CheckFilterMode; + UpdateRoutersAfterFilterUpdate; + end; + end; + + if RUpdated then + begin + RoutersUpdated := True; + UpdateOptionsAfterRoutersUpdate; + ShowRouters; + FilterUpdated := False; + end; + + if FUpdated or RUpdated then + begin + if ImmediateApplyOptions and not OptionsChanged then + ApplyOptions(True) + else + EnableOptionButtons; + ShowBalloon(Format(TransStr('364'), [ParseStr[0]])); + end; + end + else + ShowMsg(TransStr('254'), '', mtError); + finally + ini.Free; + end; +end; + +procedure TTcp.CopyCaptionToClipboard(Sender: TObject); +begin + if TMenuItem(Sender).Hint = '' then + Clipboard.AsText := TMenuItem(Sender).Caption + else + Clipboard.AsText := TMenuItem(Sender).Hint; +end; + +procedure TTcp.mnDetailsPopup(Sender: TObject); +var + ini: TMemIniFile; + SelectMenu: TMenuItem; + i, TimeStampIndex, TemplateNameIndex: Integer; + TimeStamp: Int64; + TemplateList: TStringList; + TemplateName, TimeStampStr: string; + Router: TRouterInfo; + Search, IsIPv6: Boolean; +begin + if lbExitIp.Tag = 1 then + SelectedNode := ExitNodeID + else + begin + SelectRowPopup(sgCircuitInfo, mnDetails); + SelectedNode := sgCircuitInfo.Cells[CIRC_INFO_ID, sgCircuitInfo.SelRow]; + end; + miDetailsCopyFingerprint.Caption := SelectedNode; + + Search := False; + IsIPv6 := False; + if RoutersDic.TryGetValue(SelectedNode, Router) then + begin + Search := True; + IsIPv6 := Router.IPv6 <> ''; + miDetailsCopyNickname.Caption := Router.Name; + miDetailsCopyIPv4.Caption := Router.IPv4; + miDetailsCopyIPv6.Caption := Router.IPv6; + UpdateBridgeCopyMenu(miDetailsCopyBridgeIPv4, SelectedNode, Router, False); + UpdateBridgeCopyMenu(miDetailsCopyBridgeIPv6, SelectedNode, Router, True); + end; + + miDetailsCopyNickname.Visible := Search; + miDetailsCopyIPv4.Visible := Search; + miDetailsCopyIPv6.Visible := IsIPv6; + miDetailsCopyBridgeIPv4.Visible := Search; + miDetailsCopyBridgeIPv6.Visible := IsIPv6; + + miDetailsUpdateIp.Enabled := ConnectState = 2; + miDetailsAddToNodesList.Enabled := Search and (ConnectState <> 1); + miDetailsSelectTemplate.Enabled := False; + + if miDetailsAddToNodesList.Enabled then + InsertNodesMenu(miDetailsAddToNodesList, SelectedNode); + + if ConnectState = 1 then + Exit; + + miDetailsSelectTemplate.Clear; + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + TemplateList := TStringList.Create; + try + ini.ReadSectionValues('Templates', TemplateList); + if TemplateList.Count > 0 then + begin + miDetailsSelectTemplate.Enabled := True; + for i := 0 to TemplateList.Count - 1 do + begin + TimeStampIndex := Pos('=', TemplateList[i]); + TemplateNameIndex := Pos(';', TemplateList[i]); + TimeStampStr := copy(TemplateList[i], 0, TimeStampIndex - 1); + if ValidInt(TimeStampStr, 0, MaxInt) then + TimeStamp := StrToInt(TimeStampStr) + else + begin + TimeStamp := DateTimeToUnix(Now); + ini.WriteString('Templates', IntToStr(TimeStamp), SeparateRight(TemplateList[i], '=')); + ini.DeleteKey('Templates', TimeStampStr); + ini.UpdateFile; + end; + TemplateName := copy(TemplateList[i], TimeStampIndex + 1, (TemplateNameIndex - TimeStampIndex) - 1); + SelectMenu := TMenuItem.Create(self); + SelectMenu.Caption := TemplateName; + SelectMenu.Tag := TimeStamp; + SelectMenu.Hint := 'ApplyOptions'; + SelectMenu.OnClick := Tcp.FilterLoadClick; + miDetailsSelectTemplate.Add(SelectMenu); + end; + end; + finally + TemplateList.Free; + end; + finally + ini.Free; + end; +end; + + +procedure TTcp.SetSortMenuData(aSg: TStringGrid); +var + SortMenu: TMenuItem; + Fail: Boolean; +begin + Fail := False; + if not (aSg.SortCol in [0..aSg.ColCount - 1]) then + begin + aSg.SortCol := 0; + Fail := True; + end; + if not aSg.SortType in [SORT_ASC..SORT_DESC] then + begin + aSg.SortType := SORT_DESC; + Fail := True; + end; + case aSg.Tag of + GRID_CIRCUITS: SortMenu := miCircuitsSort; + GRID_STREAMS: SortMenu := miStreamsSort; + GRID_STREAM_INFO: SortMenu := miStreamsInfoSort; + else + SortMenu := nil; + end; + if Assigned(SortMenu) then + begin + SortMenu.Items[aSg.SortCol].Checked := True; + case aSg.SortType of + SORT_ASC: SortMenu.ImageIndex := 9; + SORT_DESC: SortMenu.ImageIndex := 10; + end; + end; + if Fail then + SaveSortData; +end; + +procedure TTcp.mnCircuitsPopup(Sender: TObject); +begin + SetSortMenuData(sgCircuits); + SelectRowPopup(sgCircuits, mnCircuits); + MenuSelectPrepare(miCircSA, miCircUA); + + miCircuitsDestroy.Enabled := ConnectState = 2; + miCircuitsUpdateNow.Enabled := ConnectState = 2; + if IsEmptyRow(sgCircuits, sgCircuits.SelRow) or (ConnectState <> 2) then + begin + miDestroyCircuit.Enabled := False; + miDestroyStreams.Enabled := False; + end + else + begin + miDestroyCircuit.Enabled := sgCircuits.Cells[CIRC_STREAMS, sgCircuits.SelRow] <> EXCLUDE_CHAR; + miDestroyStreams.Enabled := ValidInt(sgCircuits.Cells[CIRC_STREAMS, sgCircuits.SelRow], 1, MaxInt); + end; + miDestroyExitCircuits.Enabled := ConnectState = 2; + miShowCircuitsTraffic.Enabled := ConnectState <> 1; + miShowStreamsTraffic.Enabled := ConnectState <> 1; + miCircuitsSortDL.Enabled := miShowCircuitsTraffic.Checked; + miCircuitsSortUL.Enabled := miShowCircuitsTraffic.Checked; +end; + +procedure TTcp.SelectRowPopup(aSg: TStringGrid; aPopup: TPopupMenu); +var + Origin: TPoint; +begin + aSg.SelRow := aSg.Row; + aSg.SelCol := aSg.Col; + Origin := aSg.ClientOrigin; + if ((Origin.X <> TPoint(aPopup.PopupPoint).X) and (Origin.Y <> TPoint(aPopup.PopupPoint).Y)) then + begin + if aSg.MovRow > 0 then + aSg.SelRow := aSg.MovRow; + if aSg.MovCol > -1 then + aSg.SelCol := aSg.MovCol; + end; + if aSg.SelRow < 1 then + aSg.SelRow := 0; + if aSg.SelRow >= aSg.RowCount then + aSg.SelRow := aSg.RowCount - 1; + if aSg.SelCol < 0 then + aSg.SelCol := 0; + if aSg.SelCol >= aSg.ColCount then + aSg.SelCol := aSg.ColCount - 1; + TUserGrid(aSg).MoveColRow(aSg.SelCol, aSg.SelRow, True, True); +end; + +procedure TTcp.mnFilterPopup(Sender: TObject); +var + ini: TMemIniFile; + DeleteMenu, LoadMenu: TMenuItem; + i, TimeStampIndex, TemplateNameIndex: Integer; + TimeStamp: Int64; + TemplateList: TStringList; + TemplateName, TimeStampStr: string; + State: Boolean; +begin + SelectRowPopup(sgFilter, mnFilter); + State := not IsEmptyGrid(sgFilter); + miStatRelays.Enabled := State; + miStatGuards.Enabled := State; + miStatExit.Enabled := State; + miClearFilterEntry.Enabled := lbFilterEntry.Tag > 0; + miClearFilterMiddle.Enabled := lbFilterMiddle.Tag > 0; + miClearFilterExit.Enabled := lbFilterExit.Tag > 0; + miClearFilterExclude.Enabled := lbFilterExclude.Tag > 0; + miClearFilterAll.Enabled := miClearFilterEntry.Enabled or miClearFilterMiddle.Enabled or miClearFilterExit.Enabled; + + MenuSelectPrepare(miTplSaveSA, miTplSaveUA); + MenuSelectPrepare(miTplLoadSA, miTplLoadUA); + + miLoadTemplate.Clear; + miDeleteTemplate.Clear; + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + TemplateList := TStringList.Create; + try + ini.ReadSectionValues('Templates', TemplateList); + if TemplateList.Count > 0 then + begin + miDeleteTemplate.Enabled := True; + miLoadTemplate.Enabled := True; + for i := 0 to TemplateList.Count - 1 do + begin + TimeStampIndex := Pos('=', TemplateList[i]); + TemplateNameIndex := Pos(';', TemplateList[i]); + TimeStampStr := copy(TemplateList[i], 0, TimeStampIndex - 1); + if ValidInt(TimeStampStr, 0, MaxInt) then + TimeStamp := StrToInt(TimeStampStr) + else + begin + TimeStamp := DateTimeToUnix(Now); + ini.WriteString('Templates', IntToStr(TimeStamp), SeparateRight(TemplateList[i], '=')); + ini.DeleteKey('Templates', TimeStampStr); + ini.UpdateFile; + end; + TemplateName := copy(TemplateList[i], TimeStampIndex + 1, (TemplateNameIndex - TimeStampIndex) - 1); + LoadMenu := TMenuItem.Create(self); + LoadMenu.Caption := TemplateName; + LoadMenu.Tag := TimeStamp; + LoadMenu.OnClick := Tcp.FilterLoadClick; + miLoadTemplate.Add(LoadMenu); + + DeleteMenu := TMenuItem.Create(self); + DeleteMenu.Caption := TemplateName; + if TemplateList.Count > 1 then + DeleteMenu.Tag := TimeStamp + else + DeleteMenu.Tag := 0; + DeleteMenu.OnClick := Tcp.FilterDeleteClick; + miDeleteTemplate.Add(DeleteMenu); + end; + DeleteMenu := TMenuItem.Create(self); + DeleteMenu.Caption := '-'; + miDeleteTemplate.Add(DeleteMenu); + + DeleteMenu := TMenuItem.Create(self); + DeleteMenu.Caption := TransStr('264'); + DeleteMenu.Tag := 0; + DeleteMenu.OnClick := Tcp.FilterDeleteClick; + miDeleteTemplate.Add(DeleteMenu); + end + else + begin + miDeleteTemplate.Enabled := False; + miLoadTemplate.Enabled := False; + end; + finally + TemplateList.Free; + end; + finally + ini.Free; + end; +end; + +procedure TTcp.mnHsPopup(Sender: TObject); +begin + if tsHs.Tag = 1 then + begin + SelectRowPopup(sgHs, mnHs); + if DirectoryExists(HsDir + sgHs.Cells[HS_NAME, sgHs.SelRow]) and (sgHs.Cells[HS_NAME, sgHs.SelRow] <> '') then + miHsOpenDir.Visible := True + else + miHsOpenDir.Visible := False; + + if FileExists(HsDir + sgHs.Cells[HS_NAME, sgHs.SelRow] + '\hostname') then + begin + miHsCopyOnion.Caption := Trim(FileGetString(HsDir + sgHs.Cells[HS_NAME, sgHs.SelRow] + '\hostname')); + miHsCopy.Visible := True; + end + else + miHsCopy.Visible := False; + + if IsEmptyGrid(sgHs) then + begin + miHsDelete.Enabled := False; + miHsClear.Enabled := False; + end + else + begin + miHsDelete.Enabled := True; + miHsClear.Enabled := True; + end; + SelectHs; + end; + + if tsHs.Tag = 2 then + begin + SelectRowPopup(sgHsPorts, mnHs); + miHsOpenDir.Visible := False; + miHsCopy.Visible := False; + if IsEmptyGrid(sgHsPorts) then + begin + miHsDelete.Enabled := False; + miHsClear.Enabled := False; + end + else + begin + miHsDelete.Enabled := True; + miHsClear.Enabled := True; + end; + SelectHsPorts; + end; +end; + +procedure TTcp.mnLogPopup(Sender: TObject); +var + State: Boolean; +begin + State := ConnectState <> 1; + miLogLevel.Enabled := State; + miSafeLogging.Enabled := State; + miOpenFileLog.Enabled := FileExists(TorLogFile); + miLogSeparate.Enabled := miWriteLogFile.Checked; + + EditMenuEnableCheck(miLogCopy, emCopy); + EditMenuEnableCheck(miLogSelectAll, emSelectAll); + EditMenuEnableCheck(miLogClear, emClear); + EditMenuEnableCheck(miLogFind, emFind); +end; + +procedure TTcp.UpdateBridgeCopyMenu(Menu: TMenuItem; RouterID: string; Router: TRouterInfo; UseIPv6: Boolean); +var + Data, BridgeStr, Transport, IpStr: string; + BridgeInfo: TBridgeInfo; +begin + if UseIPv6 then + IpStr := Router.IPv6 + else + IpStr := Router.IPv4; + Menu.Hint := ''; + Menu.Caption := ''; + Menu.Visible := IpStr <> ''; + if not Menu.Visible then + Exit; + Data := IpStr + ':' + IntToStr(Router.OrPort) + ' ' + RouterID; + + if BridgesDic.TryGetValue(RouterID, BridgeInfo) then + BridgeStr := Trim(BridgeInfo.Transport + ' ' + IpStr + ':' + IntToStr(BridgeInfo.Router.OrPort) + ' ' + RouterID + ' ' + BridgeInfo.Params) + else + BridgeStr := ''; + + if TryGetDataFromStr(BridgeStr, ltTransport, Transport) then + begin + Data := Transport + ' ' + Data; + if BridgesDic.ContainsKey(RouterID) then + Menu.Hint := BridgeStr + else + Menu.Hint := Data + Copy(BridgeStr, Pos(RouterID, BridgeStr) + Length(RouterID)); + Data := Data + '...'; + end; + Menu.Caption := Data; +end; + +procedure TTcp.mnRoutersPopup(Sender: TObject); +var + State, ClearState, ActionState, TypeState, NotStarting: Boolean; + + Router: TRouterInfo; + RouterID: string; +begin + SelectRowPopup(sgRouters, mnRouters); + NotStarting := ConnectState <> 1; + State := not IsEmptyRow(sgRouters, sgRouters.SelRow); + + miRtCopy.Visible := State; + miRtRelayInfo.Visible := State; + miRtAddToNodesList.Visible := State; + miRtAddToNodesList.Enabled := NotStarting; + miRtSelectAsBridge.Visible := State; + miRtSelectAsBridge.Enabled := NotStarting; + + miClearRouters.Enabled := NotStarting; + miClearRoutersEntry.Enabled := lbFavoritesEntry.Tag > 0; + miClearRoutersMiddle.Enabled := lbFavoritesMiddle.Tag > 0; + miClearRoutersExit.Enabled := lbFavoritesExit.Tag > 0; + miClearRoutersExclude.Enabled := lbExcludeNodes.Tag > 0; + miClearRoutersFavorites.Enabled := lbFavoritesTotal.Tag > 0; + + ClearState := ((lbFavoritesTotal.Tag > 0) or (lbExcludeNodes.Tag > 0)) and (RoutersDic.Count > 0) and (InfoStage = 0) and not (Assigned(Consensus) or Assigned(Descriptors)); + miClearRoutersIncorrect.Enabled := ClearState; + miClearRoutersAbsent.Enabled := ClearState; + + ActionState := miEnableConvertNodesOnIncorrectClear.Checked or miEnableConvertNodesOnAddToNodesList.Checked or miEnableConvertNodesOnRemoveFromNodesList.Checked; + TypeState := miConvertIpNodes.Checked or miConvertCidrNodes.Checked or miConvertCountryNodes.Checked; + + miEnableConvertNodesOnIncorrectClear.Enabled := TypeState; + miEnableConvertNodesOnAddToNodesList.Enabled := TypeState; + miEnableConvertNodesOnRemoveFromNodesList.Enabled := TypeState; + miConvertIpNodes.Enabled := ActionState; + miConvertCidrNodes.Enabled := ActionState; + miConvertCountryNodes.Enabled := ActionState; + miIgnoreConvertExcludeNodes.Enabled := ActionState and TypeState; + miAvoidAddingIncorrectNodes.Enabled := ActionState and TypeState; + + MenuSelectPrepare(miRtFilterSA, miRtFilterUA); + + if State then + begin + RouterID := sgRouters.Cells[ROUTER_ID, sgRouters.SelRow]; + if RoutersDic.TryGetValue(RouterID, Router) then + begin + miRtCopyNickname.Caption := Router.Name; + miRtCopyFingerprint.Caption := RouterID; + miRtCopyIPv4.Caption := Router.IPv4; + miRtCopyIPv6.Caption := Router.IPv6; + miRtCopyIPv6.Visible := Router.IPv6 <> ''; + UpdateBridgeCopyMenu(miRtCopyBridgeIPv4, RouterID, Router, False); + UpdateBridgeCopyMenu(miRtCopyBridgeIPv6, RouterID, Router, True); + miRtSelectAsBridgeIPv4.Caption := miRtCopyBridgeIPv4.Caption; + miRtSelectAsBridgeIPv4.Hint := miRtCopyBridgeIPv4.Hint; + miRtSelectAsBridgeIPv4.Visible := miRtCopyBridgeIPv4.Caption <> ''; + miRtSelectAsBridgeIPv6.Caption := miRtCopyBridgeIPv6.Caption; + miRtSelectAsBridgeIPv6.Hint := miRtCopyBridgeIPv6.Hint; + miRtSelectAsBridgeIPv6.Visible := miRtCopyBridgeIPv6.Caption <> ''; + + miRtSelectAsBridge.Visible := (cbxServerMode.ItemIndex = 0) and + (sgRouters.Cells[ROUTER_EXCLUDE_NODES, sgRouters.SelRow] <> EXCLUDE_CHAR) and + ((((rfBridge in Router.Flags) or (rfGuard in Router.Flags)) and ((Router.Params and ROUTER_ALIVE <> 0)) or (AliveNodesCount = 0)) or (not miDisableSelectionUnSuitableAsBridge.Checked)); + miRtDisableBridges.Visible := cbUseBridges.Checked; + end; + InsertNodesMenu(miRtAddToNodesList, RouterID, False); + end; +end; + +function TTcp.GetTrackHostDomains(Host: string; OnlyExists: Boolean): string; +var + DotIndex: Integer; +begin + Result := ''; + Host := ExtractDomain(Host, True); + if ValidHost(Host, True, True) then + begin + DotIndex := 1; + while DotIndex > 0 do + begin + if (OnlyExists and TrackHostDic.ContainsKey(Host)) or not OnlyExists then + Result := Result + ';' + Host; + DotIndex := Pos('.', Host, 2); + if DotIndex <> -1 then + Host := Copy(Host, DotIndex); + end; + if OnlyExists and TrackHostDic.ContainsKey('.') then + Result := Result + ';' + TransStr('353'); + Delete(Result, 1, 1); + end; +end; + +procedure TTcp.mnShowNodesChange(Sender: TObject; Source: TMenuItem; + Rebuild: Boolean); +begin + mnShowNodes.Items.Tag := mnShowNodes.Tag; + ShowNodesChanged := True; +end; + +procedure TTcp.mnShowNodesPopup(Sender: TObject); +begin + MenuSelectPrepare(nil, miShowNodesUA, True); +end; + +procedure TTcp.mnStreamsInfoPopup(Sender: TObject); +var + Flag: Boolean; +begin + SelectRowPopup(sgStreamsInfo, mnStreamsInfo); + SetSortMenuData(sgStreamsInfo); + Flag := (ConnectState = 2) and not IsEmptyRow(sgStreamsInfo, sgStreamsInfo.SelRow); + miStreamsInfoDestroyStream.Enabled := Flag and (sgStreams.Cells[STREAMS_COUNT, sgStreams.SelRow] <> EXCLUDE_CHAR); + miStreamsInfoSortDL.Enabled := miShowStreamsTraffic.Checked; + miStreamsInfoSortUL.Enabled := miShowStreamsTraffic.Checked; +end; + +procedure TTcp.mnStreamsPopup(Sender: TObject); +var + i: Integer; + Flag, Search: Boolean; + ParseStr: ArrOfStr; + HostMenu: TMenuItem; + Domains: string; +begin + SetSortMenuData(sgStreams); + SelectRowPopup(sgStreams, mnStreams); + Flag := IsEmptyRow(sgStreams, sgStreams.SelRow); + if Flag or (ConnectState <> 2) or (sgStreams.Cells[STREAMS_COUNT, sgStreams.SelRow] = EXCLUDE_CHAR) then + miStreamsDestroyStream.Enabled := False + else + miStreamsDestroyStream.Enabled := True; + miStreamsOpenInBrowser.Enabled := not Flag; + miStreamsBindToExitNode.Enabled := False; + miStreamsBindToExitNode.Clear; + miStreamsSortDL.Enabled := miShowStreamsTraffic.Checked; + miStreamsSortUL.Enabled := miShowStreamsTraffic.Checked; + + miStreamsBindToExitNode.Caption := TransStr('351'); + miStreamsBindToExitNode.ImageIndex := 21; + + if not Flag then + begin + Search := sgStreams.Cells[STREAMS_TRACK, sgStreams.SelRow] <> NONE_CHAR; + if Search then + begin + miStreamsBindToExitNode.Caption := TransStr('352'); + miStreamsBindToExitNode.ImageIndex := 22; + end; + + Domains := GetTrackHostDomains(sgStreams.Cells[STREAMS_TARGET, sgStreams.SelRow], Search); + if Domains <> '' then + begin + ParseStr := Explode(';', Domains); + for i := 0 to Length(ParseStr) - 1 do + begin + HostMenu := TMenuItem.Create(self); + HostMenu.Caption := ParseStr[i]; + HostMenu.Tag := Integer(Search); + HostMenu.OnClick := Tcp.BindToExitNodeClick; + miStreamsBindToExitNode.Add(HostMenu); + end; + miStreamsBindToExitNode.Enabled := True; + end; + end; +end; + +procedure TTcp.mnTransportsPopup(Sender: TObject); +begin + SelectRowPopup(sgTransports, mnTransports); + miTransportsOpenDir.Enabled := DirectoryExists(TransportsDir); + miTransportsReset.Enabled := FileExists(DefaultsFile); + if IsEmptyGrid(sgTransports) then + begin + miTransportsDelete.Enabled := False; + miTransportsClear.Enabled := False; + end + else + begin + miTransportsDelete.Enabled := True; + miTransportsClear.Enabled := True; + end; +end; + +procedure TTcp.mnChangeCircuitPopup(Sender: TObject); +var + State, StartScanState, ClearNetworkState, ClearBridgesState, ScanState: Boolean; + NotStarting: Boolean; +begin + NotStarting := ConnectState <> 1; + State := (InfoStage = 0) and not (Assigned(Consensus) or Assigned(Descriptors)); + ScanState := State and NotStarting and not tmScanner.Enabled; + StartScanState := ScanState and + ((cbEnablePingMeasure.Checked and miManualPingMeasure.Checked) or + (miManualDetectAliveNodes.Checked and cbEnableDetectAliveNodes.Checked)); + ClearNetworkState := ScanState and FileExists(NetworkCacheFile); + ClearBridgesState := ScanState and (ConnectState = 0) and FileExists(BridgesCacheFile); + + miCacheOperations.Enabled := NotStarting; + miUpdateIpToCountryCache.Enabled := ClearNetworkState and GeoIpExists and (ConnectState = 2); + miClearDNSCache.Enabled := ConnectState = 2; + miClearServerCache.Enabled := (ConnectState = 0) and + (FileExists(UserDir + 'cached-consensus') or FileExists(UserDir + 'cached-consensus.tmp')); + miClearPingCache.Enabled := ClearNetworkState; + miClearAliveCache.Enabled := ClearNetworkState; + miClearUnusedNetworkCache.Enabled := ClearNetworkState; + miClearBridgesCacheAll.Enabled := ClearBridgesState; + miClearBridgeCacheUnnecessary.Enabled := ClearBridgesState; + + miStartScan.Enabled := NotStarting; + miScanNewNodes.Enabled := StartScanState; + miScanNonResponsed.Enabled := StartScanState; + miScanCachedBridges.Enabled := StartScanState; + miScanAll.Enabled := StartScanState; + miManualPingMeasure.Enabled := cbEnablePingMeasure.Checked and ScanState; + miManualDetectAliveNodes.Enabled := cbEnableDetectAliveNodes.Checked and ScanState; + miStopScan.Enabled := NotStarting and tmScanner.Enabled; + + miResetGuards.Enabled := NotStarting; + miResetTotalsCounter.Enabled := NotStarting and (TotalDL <> 0) and (TotalUL <> 0); + miResetScannerSchedule.Enabled := ScanState; +end; + +procedure TTcp.EditMenuPopup(Sender: TObject); +var + IsBridgeEdit, IsUserBridges, State: Boolean; +begin + IsBridgeEdit := Screen.ActiveControl = meBridges; + IsUserBridges := IsBridgeEdit and IsBridgeEdit and (cbxBridgesType.ItemIndex = BRIDGES_TYPE_USER) and (meBridges.Lines.Count > 0); + State := IsUserBridges and not tmScanner.Enabled; + + miGetBridges.Visible := IsBridgeEdit; + miClear.Visible := not IsUserBridges; + miClearBridges.Visible := IsUserBridges; + + miGetBridgesEmail.Enabled := IsBridgeEdit and RegistryFileExists(HKEY_CLASSES_ROOT, 'mailto\shell\open\command', ''); + miGetBridgesTelegram.Enabled := IsBridgeEdit and (RegistryFileExists(HKEY_CLASSES_ROOT, 'tg\shell\open\command', '') or miPreferWebTelegram.Checked); + + miClearBridgesNotAlive.Enabled := State and cbEnableDetectAliveNodes.Checked; + miClearBridgesCached.Enabled := State; + miClearBridgesNonCached.Enabled := State; + + EditMenuEnableCheck(miCopy, emCopy); + EditMenuEnableCheck(miCut, emCut); + EditMenuEnableCheck(miPaste, emPaste); + EditMenuEnableCheck(miSelectAll, emSelectAll); + if IsUserBridges then + miClearBridgesAll.Enabled := State + else + EditMenuEnableCheck(miClear, emClear); + EditMenuEnableCheck(miDelete, emDelete); + EditMenuEnableCheck(miFind, emFind); +end; + +procedure TTcp.ResetFocus; +begin + if FormSize = 0 then + Exit; + if Closing then + Exit; + case LastPlace of + LP_OPTIONS: if pcOptions.CanFocus then pcOptions.SetFocus; + LP_LOG: if meLog.CanFocus then meLog.SetFocus; + LP_STATUS: if paStatus.CanFocus then paStatus.SetFocus; + LP_CIRCUITS: if paCircuits.CanFocus then paCircuits.SetFocus; + LP_ROUTERS: if paRouters.CanFocus then paRouters.SetFocus; + end; +end; + +procedure TTcp.lbServerInfoMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); +begin + if TLabel(Sender).Caption <> TransStr('260') then + TLabel(Sender).Cursor := crHandPoint + else + TLabel(Sender).Cursor := crDefault; + if (cbxServerMode.ItemIndex > 0) and (TLabel(Sender).Cursor = crHandPoint) then + mnServerInfo.AutoPopup := True + else + mnServerInfo.AutoPopup := False; +end; + +procedure TTcp.lbStatusProxyAddrClick(Sender: TObject); +begin + Clipboard.AsText := lbStatusProxyAddr.Caption; +end; + +procedure TTcp.lbUserDirClick(Sender: TObject); +begin + ShellOpen(GetFullFileName(UserDir)); +end; + +procedure TTcp.paButtonsDblClick(Sender: TObject); +begin + if FormSize = 1 then + begin + CheckOptionsChanged; + DecreaseFormSize; + end + else + begin + case LastPlace of + LP_OPTIONS: sbShowOptions.Click; + LP_LOG: sbShowLog.Click; + LP_STATUS: sbShowStatus.Click; + LP_CIRCUITS: sbShowCircuits.Click; + LP_ROUTERS: sbShowRouters.Click; + end; + end; +end; + +procedure TTcp.paRoutersClick(Sender: TObject); +begin + ResetFocus; +end; + +procedure TTcp.pbTrafficPaint(Sender: TObject); +const + GRID_XN = 6; + GRID_YN = 4; +var + i, IntervalSize, Threshold, StepSpeed: Integer; + MinIndex, MaxIndex, MinValue, MaxValue: Integer; + ZeroX, ZeroY, CurrX, CurrY, LastX, LastY: Integer; + AText: string; + ARect: TRect; + AHeight, AWidth: Integer; + APen: TGPPen; + Plot : TGPGraphics; + Data, ScaledData: ArrOfPoint; + StepX, StepY: Real; + + procedure DrawData(AColor: TColor; IsDL: Boolean); + var + i, j, DataLength: Integer; + begin + j := 0; + for i := MinIndex to MaxIndex do + begin + Data[j].X := j; + if IsDL then + Data[j].Y := SpeedData[i].DL + else + Data[j].Y := SpeedData[i].UL; + Inc(j); + end; + ScaledData := SampleDown(Data, Threshold); + DataLength := Length(ScaledData) - 1; + + APen.SetColor(ColorRefToARGB(AColor)); + LastX := ZeroX + AWidth; + LastY := AHeight - Round((ScaledData[DataLength].Y - MinValue) / StepY); + for i := DataLength - 1 downto 1 do + begin + CurrX := Round(LastX - StepX); + CurrY := AHeight - Round((ScaledData[i].Y - MinValue) / StepY); + if ScaledData[i].Y <> -1 then + Plot.DrawLine(APen, LastX, LastY, CurrX, CurrY); + LastX := CurrX; + LastY := CurrY; + end; + end; + +begin + IntervalSize := PlotIntervals[CurrentTrafficPeriod]; + MaxIndex := MAX_SPEED_DATA_LENGTH - 1; + MinIndex := MaxIndex - IntervalSize + 1; + + MinValue := 0; + MaxValue := 0; + + for i := MinIndex to MaxIndex do + begin + if miSelectGraphDL.Checked then + begin + if SpeedData[i].DL > -1 then + begin + if SpeedData[i].DL > MaxValue then + MaxValue := SpeedData[i].DL; + if SpeedData[i].DL < MinValue then + MinValue := SpeedData[i].DL; + end; + end; + if miSelectGraphUL.Checked then + begin + if SpeedData[i].UL > -1 then + begin + if SpeedData[i].UL > MaxValue then + MaxValue := SpeedData[i].UL; + if SpeedData[i].UL < MinValue then + MinValue := SpeedData[i].UL; + end; + end; + end; + + ZeroX := 55; + ZeroY := 0; + + AWidth := pbTraffic.Width - ZeroX - 8; + AHeight := pbTraffic.Height - ZeroY - 8; + + StepY := Round(AHeight / GRID_YN); + StepX := Round(AWidth / GRID_XN); + StepSpeed := Round(MaxValue / GRID_YN); + + with pbTraffic.Canvas do + begin + Pen.Color := clSilver; + Pen.Style := psDot; + Pen.Width := 1; + Font.Color := StyleServices.GetStyleFontColor(sfWindowTextNormal); + + CurrX := ZeroX; + for i := 1 to GRID_XN + 1 do + begin + MoveTo(CurrX, ZeroY); + LineTo(CurrX, AHeight); + CurrX := Floor(CurrX + StepX); + end; + + CurrY := ZeroY; + for i := GRID_YN + 1 downto 1 do + begin + MoveTo(ZeroX, CurrY); + LineTo(AWidth + ZeroX, CurrY); + if i <> 1 then + begin + ARect := ClipRect; + ARect.Right := ZeroX - 3; + ARect.Top := CurrY; + AText := BytesFormat(StepSpeed * (i - 1)); + TextRect(ARect, AText, [tfRight, tfSingleLine]); + end; + CurrY := Floor(CurrY + StepY); + end; + end; + + case CurrentTrafficPeriod of + 0: Threshold := IntervalSize; + 1: Threshold := Floor(AWidth / 2); + else + Threshold := AWidth; + end; + + Dec(AHeight, 2); + StepX := AWidth / Threshold; + StepY := (MaxValue - MinValue) / AHeight; + + if StepY = 0 then + Exit; + + Plot := TGPGraphics.Create(pbTraffic.Canvas.Handle); + APen := TGPPen.Create(ColorRefToARGB(clDefault), 1); + try + Plot.SetSmoothingMode(SmoothingModeAntiAlias); + SetLength(Data, IntervalSize); + + if miSelectGraphUL.Checked then + DrawData($00FF9932, False); + + if miSelectGraphDL.Checked then + DrawData($003FC486, True); + finally + Plot.Free; + APen.Free; + end; +end; + +procedure TTcp.pcOptionsChange(Sender: TObject); +begin + SetConfigInteger('Main', 'OptionsPage', pcOptions.TabIndex); +end; + +function TTcp.CheckSimilarPorts: Boolean; +begin + if udControlPort.Position <> udSOCKSPort.Position then + Result := False + else + begin + Result := True; + udSOCKSPort.Position := udControlPort.Position - 1; + end; +end; + +procedure TTcp.SetVisible(vOptions, vLog, vStatus, vCircuits, vRouters, vButtons: Boolean); +begin + paRouters.Visible := vRouters; + paCircuits.Visible := vCircuits; + paStatus.Visible := vStatus; + paLog.Visible := vLog; + pcOptions.Visible := vOptions; + btnApplyOptions.Visible := vButtons; + btnCancelOptions.Visible := vButtons; +end; + +procedure TTcp.SetButtonsProp(Btn: TSpeedButton; LeftSmall, LeftBig: Integer); +begin + if FormSize = 0 then + begin + Btn.Hint := Btn.Caption; + Btn.Caption := ''; + Btn.ShowHint := True; + Btn.Margin := -1; + Btn.Width := Round(41 * Scale); + Btn.Left := Round(LeftSmall * Scale); + end + else + begin + Btn.Caption := Btn.Hint; + Btn.ShowHint := False; + Btn.Hint := ''; + Btn.Margin := 8; + Btn.Width := Round(111 * Scale); + Btn.Left := Round(LeftBig * Scale); + end; +end; + +procedure TTcp.ChangeButtonsCaption; +begin + if FormSize = 0 then + begin + btnChangeCircuit.Width := Round(111 * Scale); + btnSwitchTor.Width := Round(111 * Scale); + end + else + begin + btnChangeCircuit.Width := Round(111 * Scale); + btnSwitchTor.Width := Round(111 * Scale); + end; + SetButtonsProp(sbShowOptions, 116, 116); + SetButtonsProp(sbShowLog, 159, 229); + SetButtonsProp(sbShowStatus, 202, 342); + SetButtonsProp(sbShowCircuits, 245, 455); + SetButtonsProp(sbShowRouters, 288, 568); + CheckLabelEndEllipsis(lbExitCountry, 150, epEndEllipsis, True, False); +end; + +procedure TTcp.UpdateFormSize; +var + H, W: Integer; +begin + if FormSize = 0 then + begin + H := Round(91 * Scale); + W := Round(332 * Scale); + if (ClientHeight = H) and (ClientWidth = W) then + Exit; + Tcp.ClientHeight := H; + Tcp.ClientWidth := W; + end + else + begin + H := Round(531 * Scale); + W := Round(728 * Scale); + if (ClientHeight = H) and (ClientWidth = W) then + Exit; + Tcp.ClientHeight := H; + Tcp.ClientWidth := W; + end; +end; + +procedure TTcp.DecreaseFormSize(AutoRestore: Boolean = True); +begin + FindDialog.CloseDialog; + if FormSize = 1 then + begin + FormSize := 0; + sbShowOptions.AllowAllUp := True; + sbShowOptions.Down := False; + sbShowLog.Down := False; + sbShowStatus.Down := False; + sbShowCircuits.Down := False; + sbShowRouters.Down := False; + sbShowOptions.AllowAllUp := False; + UpdateFormSize; + ChangeButtonsCaption; + Tcp.Left := DecFormPos.X; + Tcp.Top := DecFormPos.Y; + if not FirstLoad then + SetDesktopPosition(Tcp.Left, Tcp.Top, GetCheckBorders, True); + end; +end; + +procedure TTcp.IncreaseFormSize; +begin + SetDownState; + if FormSize = 0 then + begin + FormSize := 1; + paButtons.Visible := False; + SetVisible(False, False, False, False, False, False); + UpdateFormSize; + ChangeButtonsCaption; + if cbRememberEnlargedPosition.Checked then + begin + Tcp.Left := IncFormPos.X; + Tcp.Top := IncFormPos.Y; + end + else + begin + Tcp.Left := Round((Screen.Width - Width) / 2); + Tcp.Top := Round((Screen.Height - Height) / 2); + end; + end; + case LastPlace of + LP_OPTIONS: SetVisible(True, False, False, False, False, True); + LP_LOG: SetVisible(False, True, False, False, False, False); + LP_STATUS: SetVisible(False, False, True, False, False, False); + LP_CIRCUITS: SetVisible(False, False, False, True, False, False); + LP_ROUTERS: SetVisible(False, False, False, False, True, True); + end; + paButtons.Visible := True; + SetConfigInteger('Main', 'LastPlace', LastPlace); +end; + +procedure TTcp.MainButtonssMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); +begin + if ssLeft in Shift then + TButton(Sender).Perform(BM_SETSTATE, 1, 0); +end; + +procedure TTcp.MetricsInfo(Sender: TObject); +var + cc: string; +begin + if sgFilter.Cells[FILTER_ID, sgFilter.SelRow] <> '??' then + cc := AnsiLowerCase(sgFilter.Cells[FILTER_ID, sgFilter.SelRow]) + else + cc := 'xz'; + OpenMetricsUrl('#search', 'country:' + cc + TMenuItem(Sender).Hint); +end; + +procedure TTcp.miStatAggregateClick(Sender: TObject); +begin + OpenMetricsUrl('#aggregate', 'cc'); +end; + +procedure TTcp.miStopScanClick(Sender: TObject); +begin + if tmScanner.Enabled then + StopScan := True; +end; + +procedure TTcp.SaveTrackHostExits(ini: TMemIniFile; UseDic: Boolean = False); +var + TrackHostExits: string; + ls: TStringList; + Item: TPair; + i: Integer; +begin + if UseDic then + begin + ls := TStringList.Create;; + try + for Item in TrackHostDic do + ls.Append(Item.Key); + ls.CustomSort(CompTextAsc); + TrackHostExits := ''; + for i := 0 to ls.Count - 1 do + TrackHostExits := TrackHostExits + ',' + ls[i]; + Delete(TrackHostExits, 1, 1); + meTrackHostExits.Text := ls.Text; + finally + ls.Free; + end; + end + else + begin + TrackHostExits := MemoToLine(meTrackHostExits, ltHost, True); + TrackHostDic.Clear; + if TrackHostExits <> '' then + for i := 0 to meTrackHostExits.Lines.Count - 1 do + TrackHostDic.AddOrSetValue(meTrackHostExits.Lines[i], 0); + end; + if cbUseTrackHostExits.Checked and (TrackHostExits <> '') then + begin + SetTorConfig('TrackHostExits', TrackHostExits); + SetTorConfig('TrackHostExitsExpire', IntToStr(udTrackHostExitsExpire.Position)); + end + else + begin + cbUseTrackHostExits.Checked := False; + DeleteTorConfig('TrackHostExits'); + DeleteTorConfig('TrackHostExitsExpire'); + end; + ini.WriteBool('Lists', 'UseTrackHostExits', cbUseTrackHostExits.Checked); + ini.WriteString('Lists', 'TrackHostExits', TrackHostExits); + ini.WriteInteger('Lists', 'TrackHostExitsExpire', udTrackHostExitsExpire.Position); + if UseDic and (ConnectState = 2) then + begin + if cbUseTrackHostExits.Checked then + SendCommand('SETCONF TrackHostExits=' + TrackHostExits) + else + SendCommand('SETCONF TrackHostExits='); + end; +end; + +procedure TTcp.SaveServerOptions(ini: TMemIniFile); +var + ExitPolicy, MyFamily, Address: string; + ParseStr: ArrOfStr; + i: Integer; +begin + DeleteTorConfig('Nickname'); + DeleteTorConfig('ContactInfo'); + DeleteTorConfig('Address', [cfMultiLine]); + DeleteTorConfig('RelayBandwidthRate'); + DeleteTorConfig('RelayBandwidthBurst'); + DeleteTorConfig('MaxAdvertisedBandwidth'); + DeleteTorConfig('MaxMemInQueues'); + DeleteTorConfig('NumCPUs'); + DeleteTorConfig('PublishServerDescriptor'); + DeleteTorConfig('DirReqStatistics'); + DeleteTorConfig('HiddenServiceStatistics'); + DeleteTorConfig('AssumeReachable'); + DeleteTorConfig('DirCache'); + DeleteTorConfig('ORPort'); + DeleteTorConfig('DirPort'); + DeleteTorConfig('BridgeRelay'); + DeleteTorConfig('BridgeDistribution'); + DeleteTorConfig('ExitRelay'); + DeleteTorConfig('ExitPolicy', [cfMultiLine]); + DeleteTorConfig('IPv6Exit'); + DeleteTorConfig('ReducedExitPolicy'); + DeleteTorConfig('MyFamily'); + + MyFamily := MemoToLine(meMyFamily, ltHash, True); + ExitPolicy := MemoToLine(meExitPolicy, ltPolicy); + if ExitPolicy = '' then + begin + if cbxExitPolicyType.ItemIndex <> 1 then + cbxExitPolicyType.ItemIndex := 0; + meExitPolicy.Text := StringReplace(DEFAULT_CUSTOM_EXIT_POLICY, ',', BR, [rfReplaceAll]); + meExitPolicy.Enabled := False; + end; + if cbxServerMode.ItemIndex > 0 then + begin + SetTorConfig('Nickname', edNickname.Text); + edContactInfo.Text := Trim(edContactInfo.Text); + SetTorConfig('ContactInfo', edContactInfo.Text); + + SetServerPort(udORPort); + if cbUseDirPort.Checked then + SetServerPort(udDirPort); + + ParseStr := Explode(',', RemoveBrackets(edAddress.Text, True)); + Address := ''; + for i := 0 to Length(ParseStr) - 1 do + begin + ParseStr[i] := ExtractDomain(Trim(ParseStr[i])); + if ValidHost(ParseStr[i]) then + begin + if cbUseAddress.Checked then + TorConfig.Append('Address ' + FormatHost(ParseStr[i])); + Address := Address + ',' + ParseStr[i]; + end; + end; + Delete(Address, 1, 1); + edAddress.Text := Address; + if Address = '' then + cbUseAddress.Checked := False; + + if cbUseRelayBandwidth.Checked then + begin + SetTorConfig('RelayBandwidthRate', IntToStr(udRelayBandwidthRate.Position) + ' kb'); + SetTorConfig('RelayBandwidthBurst', IntToStr(udRelayBandwidthBurst.Position) + ' kb'); + SetTorConfig('MaxAdvertisedBandwidth', IntToStr(udMaxAdvertisedBandwidth.Position) + ' kb'); + end; + if cbUseMaxMemInQueues.Checked then + SetTorConfig('MaxMemInQueues', IntToStr(udMaxMemInQueues.Position) + ' mb'); + if cbUseNumCPUs.Checked then + SetTorConfig('NumCPUs', IntToStr(udNumCPUs.Position)); + if cbxServerMode.ItemIndex = 2 then + begin + if cbListenIPv6.Checked and cbIPv6Exit.Checked then + SetTorConfig('IPv6Exit', '1') + else + SetTorConfig('ExitRelay', '1'); + case cbxExitPolicyType.ItemIndex of + 1: SetTorConfig('ReducedExitPolicy', '1'); + 2: SetTorConfig('ExitPolicy', ExitPolicy); + end; + end; + if cbxServerMode.ItemIndex = 3 then + begin + SetTorConfig('BridgeRelay', '1'); + SetTorConfig('BridgeDistribution', BridgeDistributions[cbxBridgeDistribution.ItemIndex]); + + end; + if cbxServerMode.ItemIndex in [1, 3] then + SetTorConfig('ExitPolicy', 'reject *:*'); + + if MyFamily <> '' then + begin + if cbUseMyFamily.Checked and (cbxServerMode.ItemIndex <> 3) then + SetTorConfig('MyFamily', MyFamily) + end + else + begin + cbUseMyFamily.Checked := False; + MyFamilyEnable(False); + end; + + SetTorConfig('PublishServerDescriptor', IntToStr(Integer(cbPublishServerDescriptor.Checked))); + SetTorConfig('DirReqStatistics', IntToStr(Integer(cbDirReqStatistics.Checked))); + SetTorConfig('HiddenServiceStatistics', IntToStr(Integer(cbHiddenServiceStatistics.Checked))); + SetTorConfig('DirCache', IntToStr(Integer(cbDirCache.Checked))); + SetTorConfig('AssumeReachable', IntToStr(Integer(cbAssumeReachable.Checked))); + end; + + ini.WriteInteger('Server', 'ServerMode', cbxServerMode.ItemIndex); + ini.WriteString('Server', 'Nickname', edNickname.Text); + ini.WriteString('Server', 'ContactInfo', edContactInfo.Text); + ini.WriteString('Server', 'Address', FormatHost(edAddress.Text)); + ini.WriteInteger('Server', 'ORPort', udORPort.Position); + ini.WriteInteger('Server', 'DirPort', udDirPort.Position); + ini.WriteInteger('Server', 'TransportPort', udTransportPort.Position); + ini.WriteInteger('Server', 'RelayBandwidthRate', udRelayBandwidthRate.Position); + ini.WriteInteger('Server', 'RelayBandwidthBurst', udRelayBandwidthBurst.Position); + ini.WriteInteger('Server', 'MaxAdvertisedBandwidth', udMaxAdvertisedBandwidth.Position); + ini.WriteInteger('Server', 'MaxMemInQueues', udMaxMemInQueues.Position); + ini.WriteInteger('Server', 'NumCPUs', udNumCPUs.Position); + ini.WriteInteger('Server', 'ExitPolicyType', cbxExitPolicyType.ItemIndex); + ini.WriteInteger('Server', 'BridgeDistribution', cbxBridgeDistribution.ItemIndex); + ini.WriteString('Server', 'CustomExitPolicy', ExitPolicy); + ini.WriteBool('Server', 'UseRelayBandwidth', cbUseRelayBandwidth.Checked); + ini.WriteBool('Server', 'UseNumCPUs', cbUseNumCPUs.Checked); + ini.WriteBool('Server', 'UseMaxMemInQueues', cbUseMaxMemInQueues.Checked); + ini.WriteBool('Server', 'UseAddress', cbUseAddress.Checked); + ini.WriteBool('Server', 'UseDirPort', cbUseDirPort.Checked); + ini.WriteBool('Server', 'UseUPnP', cbUseUPnP.Checked); + ini.WriteBool('Server', 'AssumeReachable', cbAssumeReachable.Checked); + ini.WriteBool('Server', 'DirCache', cbDirCache.Checked); + ini.WriteBool('Server', 'DirReqStatistics', cbDirReqStatistics.Checked); + ini.WriteBool('Server', 'IPv6Exit', cbIPv6Exit.Checked); + ini.WriteBool('Server', 'ListenIPv6', cbListenIPv6.Checked); + ini.WriteBool('Server', 'HiddenServiceStatistics', cbHiddenServiceStatistics.Checked); + ini.WriteBool('Server', 'PublishServerDescriptor', cbPublishServerDescriptor.Checked); + ini.WriteBool('Server', 'UseMyFamily', cbUseMyFamily.Checked); + ini.WriteString('Server', 'MyFamily', MyFamily); +end; + +procedure TTcp.BindToExitNodeClick(Sender: TObject); +var + ini: TMemIniFile; + Host: string; +begin + Host := TMenuItem(Sender).Caption; + if Host = TransStr('353') then + Host := '.'; + OptionsLocked := True; + if TMenuItem(Sender).Tag = 0 then + begin + if TrackHostDic.Count = 0 then + cbUseTrackHostExits.Checked := True; + TrackHostDic.AddOrSetValue(Host, 0) + end + else + TrackHostDic.Remove(Host); + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + SaveTrackHostExits(ini, True); + finally + ini.UpdateFile; + ini.Free; + end; + OptionsLocked := False; + SaveTorConfig; + ShowStreams(sgCircuits.Cells[CIRC_ID, sgCircuits.Row]); +end; + +procedure TTcp.miStreamsDestroyStreamClick(Sender: TObject); +begin + CloseStreams(sgCircuits.Cells[CIRC_ID, sgCircuits.SelRow], True, sgStreams.Cells[STREAMS_TARGET, sgStreams.SelRow]); +end; + +procedure TTcp.miStreamsInfoDestroyStreamClick(Sender: TObject); +begin + CloseStream(sgStreamsInfo.Cells[STREAMS_INFO_ID, sgStreamsInfo.SelRow]); +end; + +procedure TTcp.miStreamsOpenInBrowserClick(Sender: TObject); +begin + ShellOpen(sgStreams.Cells[STREAMS_TARGET, sgStreams.SelRow]); +end; + +procedure TTcp.ScanStart(ScanType: TScanType; ScanPurpose: TScanPurpose); +begin + TotalScans := 0; + CurrentScans := 0; + CurrentScanType := ScanType; + Scanner := TScanThread.Create(True); + Scanner.sScanType := ScanType; + Scanner.sScanPurpose := ScanPurpose; + Scanner.sMaxPortAttempts := udScanPortAttempts.Position; + Scanner.sMaxPingAttempts := udScanPingAttempts.Position; + Scanner.sAttemptsDelay := udDelayBetweenAttempts.Position; + Scanner.sMaxThreads := udScanMaxThread.Position; + Scanner.sPingTimeout := udScanPingTimeout.Position; + Scanner.sPortTimeout := udScanPortTimeout.Position; + Scanner.sScanPortionTimeout := udScanPortionTimeout.Position; + Scanner.sScanPortionSize := udScanPortionSize.Position; + Scanner.FreeOnTerminate := True; + Scanner.Priority := tpNormal; + Scanner.OnTerminate := ScanThreadTerminate; + Scanner.Start; +end; + +procedure TTcp.ScanNetwork(ScanType: TScanType; ScanPurpose: TScanPurpose); +var + CurrentDate: Int64; +begin + if (ScanType = stNone) or (ScanPurpose = spNone) then + Exit; + if cbEnablePingMeasure.Checked or cbEnableDetectAliveNodes.Checked or (ScanPurpose = spUserBridges) then + begin + if not tmScanner.Enabled then + begin + CurrentDate := DateTimeToUnix(Now); + CurrentScanPurpose := ScanPurpose; + ScanStage := 1; + if ScanType = stBoth then + begin + if (cbEnablePingMeasure.Checked and cbEnableDetectAliveNodes.Checked) or (ScanPurpose = spUserBridges) then + ScanStage := 2 + else + begin + if cbEnablePingMeasure.Checked then + ScanType := stPing + else + ScanType := stAlive; + end; + end; + + if CurrentScanPurpose = spAuto then + begin + if CurrentDate >= (LastFullScanDate + (udFullScanInterval.Position * 3600)) then + begin + CurrentAutoScanPurpose := spAll; + LastFullScanDate := CurrentDate; + LastPartialScansCounts := udPartialScansCounts.Position; + end + else + begin + if (LastPartialScansCounts > 0) and (CurrentDate >= (LastNonResponsedScanDate + (udNonResponsedScanInterval.Position * 3600))) then + begin + CurrentAutoScanPurpose := spNewAndFailed; + LastNonResponsedScanDate := CurrentDate; + Dec(LastPartialScansCounts); + end + else + CurrentAutoScanPurpose := spNew; + end; + AutoScanStage := 2; + end + else + CurrentAutoScanPurpose := spNone; + + case ScanStage of + 1: ScanStart(ScanType, CurrentScanPurpose); + 2: ScanStart(stPing, CurrentScanPurpose); + end; + if CurrentScanPurpose = spUserBridges then + begin + lbScanBridgesStatus.Visible := True; + lbScanBridgesStatus.Caption := TransStr('396') + ' (0%)'; + SetOptionsEnable(False); + end; + tmScanner.Enabled := True; + end; + end; +end; + +procedure TTcp.tmSaveTotalsTimer(Sender: TObject); +var + ini: TMemIniFile; +begin + if TotalsNeedSave then + begin + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + ini.WriteInt64('Status', 'TotalDL', TotalDL); + ini.WriteInt64('Status', 'TotalUL', TotalUL); + finally + ini.UpdateFile; + ini.Free; + end; + TotalsNeedSave := False; + end; +end; + +procedure TTcp.tmScannerTimer(Sender: TObject); +var + ls: TStringList; + i, j: Integer; + PortsData: ArrOfStr; + IpStr, PortStr, StatusStr, SocketStr: string; + GeoIpInfo: TGeoIpInfo; + ini: TMemIniFile; +begin + if not Assigned(Scanner) and (ScanThreads = 0) then + begin + if (ScanStage = 2) and not StopScan then + begin + ScanStart(stAlive, CurrentScanPurpose); + ScanStage := 1; + end + else + begin + if (CurrentScanPurpose = spUserBridges) and (CurrentScanType = stAlive) then + begin + if meBridges.Text <> '' then + begin + ls := TStringList.Create; + try + ls.Text := meBridges.Text; + for i := ls.Count - 1 downto 0 do + begin + if TryGetDataFromStr(ls[i], ltSocket, SocketStr) then + begin + IpStr := GetAddressFromSocket(SocketStr); + PortStr := IntToStr(GetPortFromSocket(SocketStr)); + if GeoIpDic.TryGetValue(IpStr, GeoIpInfo) then + begin + PortsData := Explode('|', GeoIpInfo.ports); + for j := 0 to Length(PortsData) - 1 do + begin + if Pos(PortStr + ':', PortsData[j]) = 1 then + begin + if SeparateRight(PortsData[j], ':') <> '1' then + begin + ls.Delete(i); + Break; + end; + end; + end; + if (GeoIpInfo.cc = DEFAULT_COUNTRY_ID) and (GeoIpInfo.ping = 0) then + GeoIpDic.Remove(IpStr); + end; + end; + end; + if not StopScan then + meBridges.Text := ls.Text; + finally + ls.Free; + end; + end; + end; + + case CurrentScanPurpose of + spUserBridges: + begin + lbScanBridgesStatus.Visible := False; + SetOptionsEnable(True); + end; + spAuto: + begin + if not StopScan then + begin + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + case CurrentAutoScanPurpose of + spAll: ini.WriteInt64('Scanner', 'LastFullScanDate', LastFullScanDate); + spFailed, spNewAndFailed: ini.WriteInt64('Scanner', 'LastNonResponsedScanDate', LastNonResponsedScanDate); + end; + ini.WriteInteger('Scanner', 'LastPartialScansCounts', LastPartialScansCounts); + finally + ini.UpdateFile; + ini.Free; + end; + end; + end; + end; + if AutoScanStage = 2 then + AutoScanStage := 3; + LoadConsensus; + if ConnectState = 0 then + SaveNetworkCache; + CheckStatusControls; + ScanStage := 0; + CurrentScanPurpose := spNone; + CurrentAutoScanPurpose := spNone; + CurrentScanType := stNone; + StopScan := False; + tmScanner.Enabled := False + end; + end + else + begin + if TotalScans > 0 then + begin + if StopScan then + StatusStr := TransStr('404') + else + begin + case CurrentScanType of + stPing: StatusStr := TransStr('382') + ' (' + IntToStr(Round((CurrentScans - ScanThreads) / TotalScans * 100)) + ' %)'; + stAlive: + begin + if CurrentScanPurpose = spUserBridges then + StatusStr := TransStr('396') + ' (' + IntToStr(Round((CurrentScans - ScanThreads) / TotalScans * 100)) + ' %)' + else + StatusStr := TransStr('383') + ' (' + IntToStr(Round((CurrentScans - ScanThreads) / TotalScans * 100)) + ' %)'; + end; + end; + end; + lbStatusScanner.Caption := StatusStr; + if CurrentScanPurpose = spUserBridges then + lbScanBridgesStatus.Caption := StatusStr; + end; + end; +end; + +procedure TTcp.tmTrafficTimer(Sender: TObject); +begin + if ConnectState = 0 then + begin + DLSpeed := 0; + ULSpeed := 0; + end; + Move(SpeedData[1], SpeedData[0], (MAX_SPEED_DATA_LENGTH - 1) * Sizeof(TSpeedData)); + SpeedData[MAX_SPEED_DATA_LENGTH - 1].DL := DLSpeed; + SpeedData[MAX_SPEED_DATA_LENGTH - 1].UL := ULSpeed; + + lbDLSpeed.Caption := BytesFormat(DLSpeed) + '/' + TransStr('180'); + lbULSpeed.Caption := BytesFormat(ULSpeed) + '/' + TransStr('180'); + + if UpdateTraffic then + begin + UpdateTraffic := False; + pbTraffic.Repaint; + end + else + UpdateTraffic := True; +end; + +procedure TTCp.LoadConsensus; +begin + if not Assigned(Consensus) then + begin + Consensus := TConsensusThread.Create(True); + Consensus.FreeOnTerminate := True; + Consensus.Priority := tpNormal; + Consensus.OnTerminate := TConsensusThreadTerminate; + Consensus.Start; + end; +end; + +procedure TTcp.LoadDescriptors; +begin + if not Assigned(Descriptors) then + begin + Descriptors := TDescriptorsThread.Create(True); + Descriptors.FreeOnTerminate := True; + Descriptors.Priority := tpNormal; + Descriptors.OnTerminate := TDescriptorsThreadTerminate; + Descriptors.Start; + end; +end; + +procedure TTcp.ShowFilter; +var + FilterCount: Integer; + Item: TPair; + cdTotal, cdUser, HideRow, IsExclude: Boolean; + NodeTypes: TNodeTypes; + CountryID: Byte; +begin + FilterCount := 0; + if sgFilter.SelRow = 0 then + sgFilter.SelRow := 1; + sgFilter.RowID := sgFilter.Cells[FILTER_ID, sgFilter.SelRow]; + BeginUpdateTable(sgFilter); + ClearGrid(sgFilter, False); + if (lbFilterEntry.Tag = 0) and (lbFilterMiddle.Tag = 0) and (lbFilterExit.Tag = 0) and (lbFilterExclude.Tag = 0) and not AlreadyStarted then + HideRow := False + else + HideRow := miFilterHideUnused.Checked; + for Item in FilterDic do + begin + CountryID := Item.Value.cc; + if HideRow then + begin + if CountryTotals[TOTAL_RELAYS][CountryID] > 0 then + cdTotal := True + else + cdTotal := False; + + if (Item.Value.Data = []) then + begin + if NodesDic.TryGetValue(Item.Key, NodeTypes) then + cdUser := ntExclude in NodeTypes + else + cdUser := False; + end + else + cdUser := True; + end + else + begin + cdTotal := True; + cdUser := True; + end; + if cdTotal or cdUser then + begin + Inc(FilterCount); + sgFilter.Cells[FILTER_ID, FilterCount] := UpperCase(Item.Key); + sgFilter.Cells[FILTER_NAME, FilterCount] := TransStr(Item.Key); + + if CountryTotals[TOTAL_RELAYS][CountryID] > 0 then + sgFilter.Cells[FILTER_TOTAL, FilterCount] := IntToStr(CountryTotals[TOTAL_RELAYS][CountryID]) + else + sgFilter.Cells[FILTER_TOTAL, FilterCount] := NONE_CHAR; + + if CountryTotals[TOTAL_GUARDS][CountryID] > 0 then + sgFilter.Cells[FILTER_GUARD, FilterCount] := IntToStr(CountryTotals[TOTAL_GUARDS][CountryID]) + else + sgFilter.Cells[FILTER_GUARD, FilterCount] := NONE_CHAR; + + if CountryTotals[TOTAL_EXITS][CountryID] > 0 then + sgFilter.Cells[FILTER_EXIT, FilterCount] := IntToStr(CountryTotals[TOTAL_EXITS][CountryID]) + else + sgFilter.Cells[FILTER_EXIT, FilterCount] := NONE_CHAR; + + if CountryTotals[TOTAL_ALIVES][CountryID] > 0 then + sgFilter.Cells[FILTER_ALIVE, FilterCount] := IntToStr(CountryTotals[5][CountryID]) + else + sgFilter.Cells[FILTER_ALIVE, FilterCount] := NONE_CHAR; + + if CountryTotals[TOTAL_PING_COUNTS][CountryID] > 0 then + sgFilter.Cells[FILTER_PING, FilterCount] := IntToStr(Round(CountryTotals[TOTAL_PING_SUM][CountryID] / CountryTotals[TOTAL_PING_COUNTS][CountryID])) + ' ' + TransStr('379') + else + sgFilter.Cells[FILTER_PING, FilterCount] := NONE_CHAR; + + IsExclude := False; + if NodesDic.ContainsKey(Item.Key) then + IsExclude := ntExclude in NodesDic.Items[Item.Key]; + + if IsExclude then + sgFilter.Cells[FILTER_EXCLUDE_NODES, FilterCount] := EXCLUDE_CHAR + else + begin + if ntEntry in Item.Value.Data then + sgFilter.Cells[FILTER_ENTRY_NODES, FilterCount] := SELECT_CHAR; + if ntMiddle in Item.Value.Data then + sgFilter.Cells[FILTER_MIDDLE_NODES, FilterCount] := SELECT_CHAR; + if ntExit in Item.Value.Data then + sgFilter.Cells[FILTER_EXIT_NODES, FilterCount] := SELECT_CHAR; + end; + end; + end; + if FilterCount > 0 then + sgFilter.RowCount := FilterCount + 1 + else + sgFilter.RowCount := 2; + GridSort(sgFilter); + SetGridLastCell(sgFilter, True, miFilterScrollTop.Checked); + if cbEnablePingMeasure.Checked and cbEnableDetectAliveNodes.Checked then + GridScrollCheck(sgFilter, FILTER_NAME, 280) + else + begin + if cbEnablePingMeasure.Checked or cbEnableDetectAliveNodes.Checked then + GridScrollCheck(sgFilter, FILTER_NAME, 336) + else + GridScrollCheck(sgFilter, FILTER_NAME, 392); + end; + EndUpdateTable(sgFilter); + lbFilterCount.Caption := Format(TransStr('321'), [FilterCount, FilterDic.Count]); +end; + +function TTcp.FindInRanges(IpStr: string): string; +var + RangeItem: TPair; +begin + Result := ''; + if RangesDic.Count > 0 then + begin + for RangeItem in RangesDic do + if InRange(IpToInt(IpStr), RangeItem.Value.IpStart, RangeItem.Value.IpEnd) then + Result := Result + ',' + RangeItem.Key; + Delete(Result, 1, 1); + end; +end; + +procedure TTcp.ShowRouters; +var + RoutersCount, i, j: Integer; + cdExit, cdGuard, cdAuthority, cdOther, cdBridge, cdFast, cdStable, cdV2Dir, cdHSDir, cdRecommended, cdDirMirror, cdAlive: Boolean; + cdRouterType, cdCountry, cdWeight, cdQuery, cdFavorites: Boolean; + Item: TPair; + CountryCode: string; + CountryID: Byte; + FindCountry, FindHash, FindIp, IsExclude, IsNativeBridge, IsPrefferedBridge, WrongQuery: Boolean; + FindCidr, Query, Temp: string; + ParseStr, RangeStr: ArrOfStr; + GeoIpInfo: TGeoIpInfo; + PreferredBridge: TBridge; + + procedure SelectNodes(KeyStr: string; Exclude: Boolean); + var + i: Integer; + begin + for i := ROUTER_ENTRY_NODES to ROUTER_EXIT_NODES do + begin + if TNodeType(i) in NodesDic.Items[KeyStr] then + begin + if sgRouters.Cells[i, RoutersCount] <> FAVERR_CHAR then + begin + if (sgRouters.Cells[i, RoutersCount] = NONE_CHAR) or Exclude then + sgRouters.Cells[i, RoutersCount] := FAVERR_CHAR + else + begin + if not IsPrefferedBridge then + sgRouters.Cells[i, RoutersCount] := SELECT_CHAR; + end; + end; + end; + end; + end; + + function CheckRouterType(Menu: TMenuItem; Condition: Boolean): Boolean; + begin + if Menu.Enabled and Menu.Checked then + begin + Result := Condition; + if miReverseConditions.Checked then + Result := not Result; + end + else + Result := True; + end; + + function CheckNodesDic(KeyStr: string): Boolean; + var + NodeTypes: TNodeTypes; + begin + if NodesDic.TryGetValue(KeyStr, NodeTypes) then + begin + if NodeTypes <> [] then + begin + case RoutersCustomFilter of + ENTRY_ID: Result := ntEntry in NodeTypes; + MIDDLE_ID: Result := ntMiddle in NodeTypes; + EXIT_ID: Result := ntExit in NodeTypes; + EXCLUDE_ID: Result := ntExclude in NodeTypes; + FAVORITES_ID: Result := (ntEntry in NodeTypes) or + (ntMiddle in NodeTypes) or (ntExit in NodeTypes); + else + Result := False; + end; + Exit; + end; + end; + Result := False; + end; + +begin + if Assigned(Consensus) or Assigned(Descriptors) then + Exit; + WrongQuery := False; + Query := StringReplace(Trim(edRoutersQuery.Text), ';', '', [rfReplaceAll]); + if miRtFiltersQuery.Checked and (Query <> '') then + begin + case cbxRoutersQuery.ItemIndex of + 4,5: + begin + PortsDic.Clear; + ParseStr := Explode(',', Query); + Temp := ''; + for i := 0 to Length(ParseStr) - 1 do + begin + ParseStr[i] := Trim(ParseStr[i]); + if ValidInt(ParseStr[i], 0, 65535) then + PortsDic.AddOrSetValue(StrToInt(ParseStr[i]), 0) + else + begin + RangeStr := Explode('-', ParseStr[i]); + if Length(RangeStr) <> 2 then + ParseStr[i] := '' + else + begin + if ValidInt(RangeStr[0], 0, 65535) and ValidInt(RangeStr[1], 1, 65535) then + begin + if StrToInt(RangeStr[0]) <= StrToInt(RangeStr[1]) then + begin + for j := StrToInt(RangeStr[0]) to StrToInt(RangeStr[1]) do + PortsDic.AddOrSetValue(j, 0); + end + else + ParseStr[i] := ''; + end + else + ParseStr[i] := ''; + end; + end; + if ParseStr[i] <> '' then + Temp := Temp + ',' + ParseStr[i]; + end; + Delete(Temp, 1, 1); + Query := Temp; + end; + 7: + begin + if not (ValidInt(Query, -1, 65535) or (CharInSet(AnsiChar(Query[1]), [NONE_CHAR, INFINITY_CHAR]) and (Length(Query) = 1))) then + WrongQuery := True + end; + else + begin + try + MatchesMask('', Query); + except + on E:Exception do + WrongQuery := True; + end; + end; + end; + + edRoutersQuery.Text := Query; + edRoutersQuery.SelStart := Length(Query); + if Query = '' then + WrongQuery := True; + end; + + RoutersCount := 0; + if sgRouters.SelRow = 0 then + sgRouters.SelRow := 1; + + sgRouters.RowID := sgRouters.Cells[ROUTER_ID, sgRouters.SelRow]; + BeginUpdateTable(sgRouters); + ClearGrid(sgRouters, False); + + if not WrongQuery then + begin + LastPreferredBridgeHash := ''; + if cbUseBridges.Checked and cbUsePreferredBridge.Checked then + TryParseBridge(edPreferredBridge.Text, PreferredBridge); + + for Item in RoutersDic do + begin + FindCidr := ''; + CountryID := GetCountryValue(Item.Value.IPv4); + CountryCode := CountryCodes[CountryID]; + if miRtFiltersCountry.Checked then + begin + case cbxRoutersCountry.Tag of + -1: cdCountry := True; + -2: cdCountry := FilterDic.Items[CountryCode].Data <> []; + else + cdCountry := CountryID = cbxRoutersCountry.Tag; + end; + end + else + cdCountry := True; + + if miRtFiltersWeight.Checked then + cdWeight := Item.Value.Bandwidth >= udRoutersWeight.Position * 1024 + else + cdWeight := True; + + if miRtFiltersQuery.Checked and (Query <> '') then + begin + case cbxRoutersQuery.ItemIndex of + 0: cdQuery := FindStr(Query, Item.Key); + 1: cdQuery := FindStr(Query, Item.Value.Name); + 2: cdQuery := FindStr(Query, Item.Value.IPv4); + 3: cdQuery := FindStr(RemoveBrackets(Query, True), RemoveBrackets(Item.Value.IPv6, True)); + 4: cdQuery := PortsDic.ContainsKey(Item.Value.OrPort); + 5: cdQuery := PortsDic.ContainsKey(Item.Value.DirPort); + 6: cdQuery := FindStr(Query, Item.Value.Version); + 7: + begin + if GeoIpDic.TryGetValue(Item.Value.IPv4, GeoIpInfo) then + begin + case AnsiChar(Query[1]) of + NONE_CHAR: cdQuery := GeoIpInfo.ping = 0; + INFINITY_CHAR: cdQuery := GeoIpInfo.ping = -1; + else + cdQuery := (GeoIpInfo.ping <= StrToInt(Query)) and (GeoIpInfo.ping > 0); + end; + end + else + cdQuery := False; + end; + else + cdQuery := True; + end; + end + else + cdQuery := True; + + if miRtFiltersType.Checked then + begin + cdBridge := CheckRouterType(miShowBridge, rfBridge in Item.Value.Flags); + cdAuthority := CheckRouterType(miShowAuthority, rfAuthority in Item.Value.Flags); + cdExit := CheckRouterType(miShowExit, rfExit in Item.Value.Flags); + cdGuard := CheckRouterType(miShowGuard, rfGuard in Item.Value.Flags); + cdOther := CheckRouterType(miShowOther, not (rfExit in Item.Value.Flags) and not (rfGuard in Item.Value.Flags) and not (rfBridge in Item.Value.Flags) and not (rfAuthority in Item.Value.Flags)); + cdFast := CheckRouterType(miShowFast, rfFast in Item.Value.Flags); + cdStable := CheckRouterType(miShowStable, rfStable in Item.Value.Flags); + cdHSDir := CheckRouterType(miShowHSDir, rfHSDir in Item.Value.Flags); + cdDirMirror := CheckRouterType(miShowDirMirror, Item.Value.DirPort > 0); + cdV2Dir := CheckRouterType(miShowV2Dir, rfV2Dir in Item.Value.Flags); + cdAlive := CheckRouterType(miShowAlive, Item.Value.Params and ROUTER_ALIVE <> 0); + cdRecommended := CheckRouterType(miShowRecommend, VersionsDic.ContainsKey(Item.Value.Version)); + + cdRouterType := cdExit and cdGuard and cdBridge and cdAuthority and cdOther and cdFast and cdStable and cdV2Dir and cdHSDir and cdDirMirror and cdRecommended and cdAlive; + end + else + cdRouterType := True; + + if RoutersCustomFilter in [ENTRY_ID..FAVORITES_ID] then + begin + if CheckNodesDic(Item.Key) then + cdFavorites := True + else + begin + if CheckNodesDic(Item.Value.IPv4) then + cdFavorites := True + else + begin + if CheckNodesDic(CountryCode) then + cdFavorites := True + else + begin + FindCidr := FindInRanges(Item.Value.IPv4); + if FindCidr <> '' then + begin + cdFavorites := False; + ParseStr := Explode(',', FindCidr); + for i := 0 to Length(ParseStr) - 1 do + begin + if not cdFavorites then + cdFavorites := CheckNodesDic(ParseStr[i]) + else + Break; + end; + end + else + cdFavorites := False; + end; + end; + end; + end + else + cdFavorites := True; + + if cdRouterType and cdWeight and cdCountry and cdFavorites and cdQuery then + begin + Inc(RoutersCount); + sgRouters.Cells[ROUTER_ID, RoutersCount] := Item.Key; + sgRouters.Cells[ROUTER_NAME, RoutersCount] := Item.Value.Name; + sgRouters.Cells[ROUTER_IP, RoutersCount] := Item.Value.IPv4; + sgRouters.Cells[ROUTER_COUNTRY, RoutersCount] := TransStr(CountryCode); + sgRouters.Cells[ROUTER_WEIGHT, RoutersCount] := BytesFormat(Item.Value.Bandwidth * 1024) + '/' + TransStr('180'); + sgRouters.Cells[ROUTER_PORT, RoutersCount] := IntToStr(Item.Value.OrPort); + if Item.Value.Version <> '' then + sgRouters.Cells[ROUTER_VERSION, RoutersCount] := Item.Value.Version + else + sgRouters.Cells[ROUTER_VERSION, RoutersCount] := NONE_CHAR; + if GeoIpDic.TryGetValue(Item.Value.IPv4, GeoIpInfo) then + begin + if GeoIpInfo.ping > 0 then + sgRouters.Cells[ROUTER_PING, RoutersCount] := IntToStr(GeoIpInfo.ping) + ' ' + TransStr('379') + else + begin + if GeoIpInfo.ping < 0 then + sgRouters.Cells[ROUTER_PING, RoutersCount] := INFINITY_CHAR + else + sgRouters.Cells[ROUTER_PING, RoutersCount] := NONE_CHAR; + end; + end + else + sgRouters.Cells[ROUTER_PING, RoutersCount] := NONE_CHAR; + + if Item.Value.Params = 0 then + sgRouters.Cells[ROUTER_FLAGS, RoutersCount] := NONE_CHAR; + + IsNativeBridge := (rfBridge in Item.Value.Flags) and not (rfRelay in Item.Value.Flags); + IsPrefferedBridge := Item.Key = PreferredBridge.Hash; + + if not (rfGuard in Item.Value.Flags) or IsNativeBridge then + sgRouters.Cells[ROUTER_ENTRY_NODES, RoutersCount] := NONE_CHAR; + if not (rfExit in Item.Value.Flags) or IsNativeBridge then + sgRouters.Cells[ROUTER_EXIT_NODES, RoutersCount] := NONE_CHAR; + if IsNativeBridge then + sgRouters.Cells[ROUTER_MIDDLE_NODES, RoutersCount] := NONE_CHAR; + + FindHash := NodesDic.ContainsKey(Item.Key); + FindIp := NodesDic.ContainsKey(Item.Value.IPv4); + FindCountry := NodesDic.ContainsKey(CountryCode); + FindCidr := FindInRanges(Item.Value.IPv4); + + IsExclude := False; + + if FindHash then + if ntExclude in NodesDic.Items[Item.Key] then + IsExclude := True; + if FindCountry then + if ntExclude in NodesDic.Items[CountryCode] then + IsExclude := True; + if FindIp then + if ntExclude in NodesDic.Items[Item.Value.IPv4] then + IsExclude := True; + if FindCidr <> '' then + begin + ParseStr := Explode(',', FindCidr); + for i := 0 to Length(ParseStr) - 1 do + begin + if NodesDic.ContainsKey(ParseStr[i]) then + begin + if ntExclude in NodesDic.Items[ParseStr[i]] then + begin + IsExclude := True; + Break; + end; + end; + end; + end; + + if IsExclude then + sgRouters.Cells[ROUTER_EXCLUDE_NODES, RoutersCount] := EXCLUDE_CHAR; + + if IsPrefferedBridge then + begin + sgRouters.Cells[ROUTER_ENTRY_NODES, RoutersCount] := BOTH_CHAR; + LastPreferredBridgeHash := Item.Key; + end; + + if FindHash then + SelectNodes(Item.Key, IsExclude); + if FindCountry then + SelectNodes(CountryCode, IsExclude); + if FindIp then + SelectNodes(Item.Value.IPv4, IsExclude); + if FindCidr <> '' then + begin + for i := 0 to Length(ParseStr) - 1 do + begin + if NodesDic.ContainsKey(ParseStr[i]) then + SelectNodes(ParseStr[i], IsExclude); + end; + end; + + end; + end; + end; + + if RoutersCount > 0 then + sgRouters.RowCount := RoutersCount + 1 + else + sgRouters.RowCount := 2; + + GridSort(sgRouters); + SetGridLastCell(sgRouters, True, miRoutersScrollTop.Checked); + if cbEnablePingMeasure.Checked then + GridScrollCheck(sgRouters, ROUTER_COUNTRY, 105) + else + GridScrollCheck(sgRouters, ROUTER_COUNTRY, 125); + EndUpdateTable(sgRouters); + lbRoutersCount.Caption := Format(TransStr('321'), [RoutersCount, RoutersDic.Count]); + + if PortsDic.Count > 0 then + PortsDic.Clear; +end; + + +procedure TTcp.CheckCountryIndexInList; +var + Index: Integer; +begin + Index := cbxRoutersCountry.Items.IndexOfObject(TObject(cbxRoutersCountry.Tag)); + if Index = -1 then + begin + Index := 0; + cbxRoutersCountry.Tag := -1; + end; + if cbxRoutersCountry.ItemIndex <> Index then + cbxRoutersCountry.ItemIndex := Index; +end; + +procedure TTcp.LoadFilterTotals; +var + Item: TPair; + RouterInfo: TRouterInfo; + Flags: TRouterFlags; + GeoIpInfo: TGeoIpInfo; + CountryID: Byte; + ParseStr: ArrOfStr; + i, j: Integer; +begin + AliveNodesCount := 0; + PingNodesCount := 0; + for j := 0 to MAX_TOTALS - 1 do + for i := 0 to MAX_COUNTRIES - 1 do + CountryTotals[j][i] := 0; + + for Item in RoutersDic do + begin + if GeoIpDic.TryGetValue(Item.Value.IPv4, GeoIpInfo) then + begin + CountryID := GeoIpInfo.cc; + if GeoIpInfo.ping > 0 then + begin + Inc(CountryTotals[TOTAL_PING_SUM][CountryID], GeoIpInfo.ping); + Inc(CountryTotals[TOTAL_PING_COUNTS][CountryID]); + Inc(PingNodesCount); + end; + if GeoIpInfo.ports <> '' then + begin + ParseStr := Explode('|', GeoIpInfo.ports); + for i := 0 to Length(ParseStr) - 1 do + begin + if Pos(IntToStr(Item.Value.OrPort) + ':1', ParseStr[i]) = 1 then + begin + Inc(CountryTotals[TOTAL_ALIVES][CountryID]); + if Item.Value.Params and ROUTER_ALIVE = 0 then + begin + RouterInfo := Item.Value; + Inc(RouterInfo.Params, ROUTER_ALIVE); + RoutersDic.AddOrSetValue(Item.Key, RouterInfo); + Inc(AliveNodesCount); + end; + Break; + end; + end; + end; + end + else + CountryID := DEFAULT_COUNTRY_ID; + Flags := Item.Value.Flags; + + Inc(CountryTotals[TOTAL_RELAYS][CountryID]); + if rfGuard in Flags then + Inc(CountryTotals[TOTAL_GUARDS][CountryID]); + if rfExit in Flags then + Inc(CountryTotals[TOTAL_EXITS][CountryID]); + end; +end; + +procedure TTcp.LoadRoutersCountries; +var + i: Integer; +begin + cbxRoutersCountry.Clear; + cbxRoutersCountry.AddItem(TransStr('347'), TObject(-1)); + cbxRoutersCountry.AddItem(TransStr('348'), TObject(-2)); + for i := 0 to MAX_COUNTRIES - 1 do + if CountryTotals[TOTAL_RELAYS][i] > 0 then + cbxRoutersCountry.AddItem(TransStr(CountryCodes[i]), TObject(i)); + CheckCountryIndexInList; +end; + +procedure TTcp.ShowCircuits; +var + CircuitsCount: Integer; + Item: TPair; + PurposeStr: string; + TotalConnections: Integer; +begin + if LockCircuits then + Exit; + LockCircuits := True; + CircuitsCount := 0; + TotalConnections := 0; + PurposeStr := ''; + if sgCircuits.SelRow = 0 then + sgCircuits.SelRow := 1; + sgCircuits.RowID := sgCircuits.Cells[CIRC_ID, sgCircuits.SelRow]; + BeginUpdateTable(sgCircuits); + ClearGrid(sgCircuits, False); + for Item in CircuitsDic do + begin + Inc(TotalConnections, Item.Value.Streams); + if miHideCircuitsWithoutStreams.Checked then + begin + if Item.Value.Streams = 0 then + begin + if (Item.Key = Circuit) then + begin + if not miAlwaysShowExitCircuit.Checked then + Continue; + end + else + Continue; + end; + end; + PurposeStr := ''; + if bfOneHop in (Item.Value.BuildFlags) then + begin + if miCircOneHop.Checked then + PurposeStr := TransStr('331') + end + else + begin + case Item.Value.PurposeID of + GENERAL: + begin + if bfInternal in (Item.Value.BuildFlags) then + begin + if miCircInternal.Checked then + PurposeStr := TransStr('332') + end + else + if miCircExit.Checked or (miAlwaysShowExitCircuit.Checked and (Item.Key = Circuit)) then + PurposeStr := TransStr('333') + end; + HS_CLIENT_HSDIR: if miCircHsClientDir.Checked then PurposeStr := TransStr('334'); + HS_CLIENT_INTRO: if miCircHsClientIntro.Checked then PurposeStr := TransStr('335'); + HS_CLIENT_REND: if miCircHsClientRend.Checked then PurposeStr := TransStr('336'); + HS_SERVICE_HSDIR: if miCircHsServiceDir.Checked then PurposeStr := TransStr('337'); + HS_SERVICE_INTRO: if miCircHsServiceIntro.Checked then PurposeStr := TransStr('338'); + HS_SERVICE_REND: if miCircHsServiceRend.Checked then PurposeStr := TransStr('339'); + HS_VANGUARDS: if miCircHsVanguards.Checked then PurposeStr := TransStr('340'); + PATH_BIAS_TESTING: if miCircPathBiasTesting.Checked then PurposeStr := TransStr('341'); + TESTING: if miCircTesting.Checked then PurposeStr := TransStr('342'); + CIRCUIT_PADDING: if miCircCircuitPadding.Checked then PurposeStr := TransStr('343'); + MEASURE_TIMEOUT: if miCircMeasureTimeout.Checked then PurposeStr := TransStr('344'); + else + if miCircOther.Checked then PurposeStr := TransStr('345'); + end; + end; + if PurposeStr <> '' then + begin + Inc(CircuitsCount); + sgCircuits.Cells[CIRC_ID, CircuitsCount] := Item.Key; + sgCircuits.Cells[CIRC_PURPOSE, CircuitsCount] := PurposeStr; + if Item.Value.Streams > 0 then + sgCircuits.Cells[CIRC_STREAMS, CircuitsCount] := IntToStr(Item.Value.Streams) + else + sgCircuits.Cells[CIRC_STREAMS, CircuitsCount] := NONE_CHAR; + sgCircuits.Cells[CIRC_BYTES_READ, CircuitsCount] := IntToStr(Item.Value.BytesRead); + sgCircuits.Cells[CIRC_BYTES_WRITTEN, CircuitsCount] := IntToStr(Item.Value.BytesWritten); + end; + end; + if CircuitsCount > 0 then + sgCircuits.RowCount := CircuitsCount + 1 + else + sgCircuits.RowCount := 2; + GridSort(sgCircuits); + if SelectExitCircuit then + FindInCircuits(Circuit, ExitNodeID) + else + SetGridLastCell(sgCircuits, False); + GridScrollCheck(sgCircuits, CIRC_PURPOSE, 170); + EndUpdateTable(sgCircuits); + lbCircuitsCount.Caption := Format(TransStr('349'), [CircuitsCount, CircuitsDic.Count]); + lbStreamsCount.Caption := TransStr('350') + ': ' + IntToStr(TotalConnections); + ShowCircuitInfo(sgCircuits.Cells[CIRC_ID, sgCircuits.SelRow]); + LockCircuits := False; +end; + +procedure TTcp.ShowCircuitInfo(CircID: string); +var + NodesCount, i: Integer; + Router: TRouterInfo; + NodesData: ArrOfStr; + CountryCode: Byte; + CircuitInfo: TCircuitInfo; + GeoIpInfo: TGeoIpInfo; + PingData: string; +begin + if LockCircuitInfo then + Exit; + LockCircuitInfo := True; + NodesCount := 0; + BeginUpdateTable(sgCircuitInfo); + ClearGrid(sgCircuitInfo, False); + + if CircuitsDic.TryGetValue(CircID, CircuitInfo) then + begin + NodesData := Explode(',', CircuitInfo.Nodes); + for i := 0 to Length(NodesData) - 1 do + begin + PingData := NONE_CHAR; + inc(NodesCount); + if RoutersDic.TryGetValue(NodesData[i], Router) then + begin + CountryCode := GetCountryValue(Router.IPv4); + sgCircuitInfo.Cells[CIRC_INFO_ID, NodesCount] := NodesData[i]; + sgCircuitInfo.Cells[CIRC_INFO_NAME, NodesCount] := Router.Name; + sgCircuitInfo.Cells[CIRC_INFO_IP, NodesCount] := Router.IPv4; + sgCircuitInfo.Cells[CIRC_INFO_COUNTRY, NodesCount] := TransStr(CountryCodes[CountryCode]); + sgCircuitInfo.Cells[CIRC_INFO_WEIGHT, NodesCount] := BytesFormat(Router.Bandwidth * 1024) + '/' + TransStr('180'); + if GeoIpDic.TryGetValue(Router.IPv4, GeoIpInfo) then + begin + if GeoIpInfo.ping > 0 then + PingData := IntToStr(GeoIpInfo.ping) + ' ' + TransStr('379') + else + begin + if GeoIpInfo.ping < 0 then + PingData := INFINITY_CHAR; + end; + end; + end + else + begin + sgCircuitInfo.Cells[CIRC_INFO_ID, NodesCount] := NodesData[i]; + sgCircuitInfo.Cells[CIRC_INFO_NAME, NodesCount] := TransStr('260'); + sgCircuitInfo.Cells[CIRC_INFO_IP, NodesCount] := TransStr('260'); + sgCircuitInfo.Cells[CIRC_INFO_COUNTRY, NodesCount] := TransStr(CountryCodes[DEFAULT_COUNTRY_ID]); + sgCircuitInfo.Cells[CIRC_INFO_WEIGHT, NodesCount] := BytesFormat(0) + '/' + TransStr('180'); + end; + sgCircuitInfo.Cells[CIRC_INFO_PING, NodesCount] := PingData; + end; + lbDetailsTime.Caption := TransStr('221') + ': ' + CircuitInfo.Date; + end + else + begin + lbDetailsTime.Caption := TransStr('221') + ': ' + TransStr('110'); + CheckCircuitExists(CircID); + end; + + if NodesCount > 0 then + sgCircuitInfo.RowCount := NodesCount + 1 + else + sgCircuitInfo.RowCount := 2; + EndUpdateTable(sgCircuitInfo); + ShowStreams(CircID); + LockCircuitInfo := False; +end; + +procedure TTcp.CheckCircuitExists(CircID: string; UpdateStreamsCount: Boolean = False); +var + Search, i: Integer; +begin + if miCircuitsUpdateLow.Checked or miCircuitsUpdateManual.Checked or (ConnectState = 0) then + begin + Search := sgCircuits.Cols[CIRC_ID].IndexOf(CircID); + if Search > 0 then + begin + sgCircuits.Cells[CIRC_STREAMS, Search] := EXCLUDE_CHAR; + if (Search = sgCircuits.Row) and not IsEmptyGrid(sgStreams) then + begin + for i := 1 to sgStreams.RowCount - 1 do + sgStreams.Cells[STREAMS_COUNT, i] := EXCLUDE_CHAR; + end; + end; + if UpdateStreamsCount and not IsEmptyGrid(sgCircuits) then + lbStreamsCount.Caption := TransStr('350') + ': ' + IntToStr(StreamsDic.Count); + end; +end; + +procedure TTcp.CheckCircuitStreams(CircID: string; TargetStreams: Integer); +var + CircuitInfo: TCircuitInfo; + i: Integer; +begin + if miCircuitsUpdateLow.Checked or miCircuitsUpdateManual.Checked then + begin + if CircuitsDic.TryGetValue(CircID, CircuitInfo) then + begin + if CircuitInfo.Streams > 0 then + sgCircuits.Cells[CIRC_STREAMS, sgCircuits.SelRow] := IntToStr(CircuitInfo.Streams) + else + begin + sgCircuits.Cells[CIRC_STREAMS, sgCircuits.SelRow] := NONE_CHAR; + if not IsEmptyGrid(sgStreams) then + for i := 1 to sgStreams.RowCount - 1 do + sgStreams.Cells[STREAMS_COUNT, i] := EXCLUDE_CHAR; + end; + end; + + if StrToIntDef(sgStreams.Cells[STREAMS_COUNT, sgStreams.SelRow], 0) > 0 then + begin + if TargetStreams = 0 then + sgStreams.Cells[STREAMS_COUNT, sgStreams.SelRow] := EXCLUDE_CHAR + else + sgStreams.Cells[STREAMS_COUNT, sgStreams.SelRow] := IntToStr(TargetStreams); + end; + + if not IsEmptyGrid(sgCircuits) then + lbStreamsCount.Caption := TransStr('350') + ': ' + IntToStr(StreamsDic.Count); + end; +end; + +procedure TTcp.ShowStreams(CircID: string); +var + StreamsCount, Search, i: Integer; + Item: TPair; + Target, FoundStr: String; + CircuitInfo: TCircuitInfo; + ReadSum, WrittenSum: Int64; +begin + if LockStreams then + Exit; + LockStreams := True; + StreamsCount := 0; + if sgStreams.SelRow = 0 then + sgStreams.SelRow := 1; + sgStreams.RowID := sgStreams.Cells[STREAMS_TARGET, sgStreams.SelRow]; + BeginUpdateTable(sgStreams); + ClearGrid(sgStreams, False); + if CircuitsDic.TryGetValue(CircID, CircuitInfo) then + begin + for Item in StreamsDic do + begin + if Item.Value.CircuitID = CircID then + begin + Target := Item.Value.Target; + Search := -1; + for i := 1 to StreamsCount do + if sgStreams.Cells[STREAMS_TARGET, i] = Target then + begin + Search := i; + Break; + end; + if Search > 0 then + begin + sgStreams.Cells[STREAMS_ID, Search] := Item.Key; + sgStreams.Cells[STREAMS_COUNT, Search] := IntToStr(StrToIntDef(sgStreams.Cells[STREAMS_COUNT, Search], 0) + 1); + ReadSum := FormatSizeToBytes(sgStreams.Cells[STREAMS_BYTES_READ, Search]) + Item.Value.BytesRead; + WrittenSum := FormatSizeToBytes(sgStreams.Cells[STREAMS_BYTES_WRITTEN, Search]) + Item.Value.BytesWritten; + sgStreams.Cells[STREAMS_BYTES_READ, Search] := BytesFormat(ReadSum); + sgStreams.Cells[STREAMS_BYTES_WRITTEN, Search] := BytesFormat(WrittenSum); + end + else + begin + if FindTrackHost(Target) then + begin + if cbUseTrackHostExits.Checked then + FoundStr := SELECT_CHAR + else + FoundStr := FAVERR_CHAR; + end + else + FoundStr := NONE_CHAR; + Inc(StreamsCount); + sgStreams.Cells[STREAMS_ID, StreamsCount] := Item.Key; + sgStreams.Cells[STREAMS_TARGET, StreamsCount] := Target; + sgStreams.Cells[STREAMS_TRACK, StreamsCount] := FoundStr; + sgStreams.Cells[STREAMS_COUNT, StreamsCount] := '1'; + sgStreams.Cells[STREAMS_BYTES_READ, StreamsCount] := BytesFormat(Item.Value.BytesRead); + sgStreams.Cells[STREAMS_BYTES_WRITTEN, StreamsCount] := BytesFormat(Item.Value.BytesWritten); + end; + end; + end; + lbDLCirc.Caption := TransStr('214') + ': ' + BytesFormat(CircuitInfo.BytesRead); + lbULCirc.Caption := TransStr('215') + ': ' + BytesFormat(CircuitInfo.BytesWritten); + end + else + begin + lbDLCirc.Caption := TransStr('214') + ': ' + INFINITY_CHAR; + lbULCirc.Caption := TransStr('215') + ': ' + INFINITY_CHAR; + end; + + if StreamsCount > 0 then + sgStreams.RowCount := StreamsCount + 1 + else + sgStreams.RowCount := 2; + + GridSort(sgStreams); + SetGridLastCell(sgStreams, False, False, False, -1, -1, 1); + if miShowStreamsTraffic.Checked then + GridScrollCheck(sgStreams, STREAMS_TARGET, 301) + else + GridScrollCheck(sgStreams, STREAMS_TARGET, 424); + EndUpdateTable(sgStreams); + ShowStreamsInfo(CircID, sgStreams.Cells[STREAMS_TARGET, sgStreams.SelRow]); + LockStreams := False; +end; + +procedure TTcp.ShowStreamsInfo(CircID, Target: string); +var + StreamsCount, i: Integer; + Item: TPair; + PurposeStr, DestAddr: string; + CircuitInfo: TCircuitInfo; +begin + if LockStreamsInfo then + Exit; + LockStreamsInfo := True; + StreamsCount := 0; + DestAddr := ''; + if sgStreamsInfo.SelRow = 0 then + sgStreamsInfo.SelRow := 1; + sgStreamsInfo.RowID := sgStreamsInfo.Cells[STREAMS_INFO_ID, sgStreamsInfo.SelRow]; + BeginUpdateTable(sgStreamsInfo); + ClearGrid(sgStreamsInfo, False); + + if CircuitsDic.TryGetValue(CircID, CircuitInfo) then + begin + if CircuitInfo.Streams > 0 then + begin + for Item in StreamsDic do + begin + if (Item.Value.CircuitID = CircID) and (Item.Value.Target = Target) then + begin + Inc(StreamsCount); + sgStreamsInfo.Cells[STREAMS_INFO_ID, StreamsCount] := Item.Key; + if Item.Value.SourceAddr <> '' then + sgStreamsInfo.Cells[STREAMS_INFO_SOURCE_ADDR, StreamsCount] := Item.Value.SourceAddr + else + sgStreamsInfo.Cells[STREAMS_INFO_SOURCE_ADDR, StreamsCount] := TransStr('376'); + + if Item.Value.DestAddr <> '' then + begin + DestAddr := Item.Value.DestAddr; + sgStreamsInfo.Cells[STREAMS_INFO_DEST_ADDR, StreamsCount] := DestAddr; + end + else + begin + if RPos('.onion:', Target) <> 0 then + sgStreamsInfo.Cells[STREAMS_INFO_DEST_ADDR, StreamsCount] := TransStr('122') + else + begin + if RPos('.exit:', Target) <> 0 then + sgStreamsInfo.Cells[STREAMS_INFO_DEST_ADDR, StreamsCount] := Copy(Target, 1, Pos('.$', Target) - 1) + ':' + IntToStr(GetPortFromSocket(Target)) + else + sgStreamsInfo.Cells[STREAMS_INFO_DEST_ADDR, StreamsCount] := TransStr('401'); + end; + end; + + case Item.Value.PurposeID of + DIR_FETCH: PurposeStr := TransStr('370'); + DIR_UPLOAD: PurposeStr := TransStr('371'); + DIRPORT_TEST: PurposeStr := TransStr('372'); + DNS_REQUEST: PurposeStr := TransStr('373'); + USER: PurposeStr := TransStr('374'); + else + PurposeStr := TransStr('375'); + end; + sgStreamsInfo.Cells[STREAMS_INFO_PURPOSE, StreamsCount] := PurposeStr; + sgStreamsInfo.Cells[STREAMS_INFO_BYTES_READ, StreamsCount] := BytesFormat(Item.Value.BytesRead); + sgStreamsInfo.Cells[STREAMS_INFO_BYTES_WRITTEN, StreamsCount] := BytesFormat(Item.Value.BytesWritten); + end; + end; + end; + end; + + if StreamsCount > 0 then + begin + sgStreamsInfo.RowCount := StreamsCount + 1; + if DestAddr <> '' then + begin + for i := 1 to sgStreamsInfo.RowCount - 1 do + if sgStreamsInfo.Cells[STREAMS_INFO_DEST_ADDR, i] = TransStr('401') then + sgStreamsInfo.Cells[STREAMS_INFO_DEST_ADDR, i] := DestAddr; + end; + end + else + sgStreamsInfo.RowCount := 2; + + GridSort(sgStreamsInfo); + SetGridLastCell(sgStreamsInfo, False); + if miShowStreamsTraffic.Checked then + GridScrollCheck(sgStreamsInfo, STREAMS_INFO_PURPOSE, 119) + else + GridScrollCheck(sgStreamsInfo, STREAMS_INFO_PURPOSE, 163); + EndUpdateTable(sgStreamsInfo); + CheckCircuitStreams(CircID, StreamsCount); + LockStreamsInfo := False; +end; + +function TTcp.FindTrackHost(Host: string): Boolean; +var + DotIndex: Integer; +begin + if TrackHostDic.ContainsKey('.') then + begin + Result := True; + Exit; + end + else + begin + Host := ExtractDomain(Host, True); + if ValidHost(Host, True, True) then + begin + DotIndex := 1; + while DotIndex > 0 do + begin + if TrackHostDic.ContainsKey(Host) then + begin + Result := True; + Exit; + end; + DotIndex := Pos('.', Host, 2); + if DotIndex <> -1 then + Host := Copy(Host, DotIndex); + end; + end; + end; + Result := False; +end; + +procedure TTcp.btnCreateProfileClick(Sender: TObject); +var + Input: string; +begin + Input := InputBox(TransStr('265'), TransStr('266') + ':', ''); + if Trim(Input) <> '' then + begin + CreateShortcut(ParamStr(0), '-profile="' + Input + '"', ExtractFileDir(ParamStr(0)), + GetSystemDir(CSIDL_DESKTOPDIRECTORY) + '\TCP (' + Input + ').lnk', ParamStr(0)); + end; +end; + +procedure TTcp.btnFindPreferredBridgeClick(Sender: TObject); +begin + FindInRouters(LastPreferredBridgeHash); +end; + +procedure TTcp.cbEnableSocksClick(Sender: TObject); +var + State: Boolean; +begin + State := cbEnableSocks.Checked; + edSOCKSPort.Enabled := State; + udSOCKSPort.Enabled := State; + cbxSocksHost.Enabled := State; + EnableOptionButtons; +end; + +procedure TTcp.cbeRoutersCountrySelect(Sender: TObject); +begin + ResetFocus; +end; + +procedure TTcp.ServerAddressEnable(State: Boolean); +begin + edAddress.Enabled := State; + lbAddress.Enabled := State; +end; + +procedure TTcp.cbUseAddressClick(Sender: TObject); +begin + if cbUseAddress.Checked then + ServerAddressEnable(True) + else + ServerAddressEnable(False); + EnableOptionButtons; +end; + +procedure TTcp.cbAutoScanNewNodesClick(Sender: TObject); +begin + if cbAutoScanNewNodes.Focused then + begin + CheckScannerControls; + CheckStatusControls; + EnableOptionButtons; + end; +end; + +procedure TTcp.cbDirCacheMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + if (Button = mbLeft) and (cbxServerMode.ItemIndex in [1,2]) and cbDirCache.Checked then + begin + if ShowMsg(TransStr('204'), '', mtWarning, True) then + begin + cbDirCache.Checked := False; + EnableOptionButtons; + end + else + cbDirCache.Checked := True; + end + else + EnableOptionButtons; +end; + +procedure TTcp.cbEnableNodesListClick(Sender: TObject); +begin + if not cbEnableNodesList.Focused then + Exit; + GetFavoritesLabel(NodesToFavorites(cbxNodesListType.ItemIndex)).HelpContext := Integer(cbEnableNodesList.Checked); + CheckNodesListControls; + EnableOptionButtons; +end; + +procedure TTcp.CheckScannerControls; +var + PingState, AliveState, State, AutoState: Boolean; +begin + PingState := cbEnablePingMeasure.Checked; + AliveState := cbEnableDetectAliveNodes.Checked; + State := PingState or AliveState; + AutoState := State and cbAutoScanNewNodes.Checked; + + edFullScanInterval.Enabled := AutoState; + edNonResponsedScanInterval.Enabled := AutoState; + edPartialScansCounts.Enabled := AutoState; + edScanPingTimeout.Enabled := PingState; + edScanPortTimeout.Enabled := AliveState; + edDelayBetweenAttempts.Enabled := State; + edScanPortAttempts.Enabled := AliveState; + edScanPingAttempts.Enabled := PingState; + edScanMaxThread.Enabled := State; + edScanPortionTimeout.Enabled := State; + edScanPortionSize.Enabled := State; + udFullScanInterval.Enabled := AutoState; + udNonResponsedScanInterval.Enabled := AutoState; + udPartialScansCounts.Enabled := AutoState; + udScanPingTimeout.Enabled := PingState; + udScanPortTimeout.Enabled := AliveState; + udDelayBetweenAttempts.Enabled := State; + udScanPortAttempts.Enabled := AliveState; + udScanPingAttempts.Enabled := PingState; + udScanMaxThread.Enabled := State; + udScanPortionTimeout.Enabled := State; + udScanPortionSize.Enabled := State; + lbFullScanInterval.Enabled := AutoState; + lbHours1.Enabled := AutoState; + lbNonResponsedScanInterval.Enabled := AutoState; + lbHours2.Enabled := AutoState; + lbPartialScansCounts.Enabled := AutoState; + lbScanPingTimeout.Enabled := PingState; + lbMiliseconds1.Enabled := PingState; + lbScanPortTimeout.Enabled := AliveState; + lbMiliseconds2.Enabled := AliveState; + lbDelayBetweenAttempts.Enabled := State; + lbMiliseconds3.Enabled := State; + lbScanPortAttempts.Enabled := AliveState; + lbScanPingAttempts.Enabled := PingState; + lbScanMaxThread.Enabled := State; + lbScanPortionTimeout.Enabled := State; + lbMiliseconds4.Enabled := State; + lbScanPortionSize.Enabled := State; + cbAutoScanNewNodes.Enabled := State; + + if PingState and AliveState then + begin + sgFilter.ColWidths[FILTER_ALIVE] := Round(55 * Scale); + sgFilter.ColWidths[FILTER_PING] := Round(55 * Scale); + GridScrollCheck(sgFilter, FILTER_NAME, 280); + end + else + begin + if PingState and not AliveState then + begin + sgFilter.ColWidths[FILTER_ALIVE] := -1; + sgFilter.ColWidths[FILTER_PING] := Round(55 * Scale); + GridScrollCheck(sgFilter, FILTER_NAME, 336); + end + else + begin + if AliveState and not PingState then + begin + sgFilter.ColWidths[FILTER_ALIVE] := Round(55 * Scale); + sgFilter.ColWidths[FILTER_PING] := -1; + GridScrollCheck(sgFilter, FILTER_NAME, 336); + end + else + begin + sgFilter.ColWidths[FILTER_ALIVE] := -1; + sgFilter.ColWidths[FILTER_PING] := -1; + GridScrollCheck(sgFilter, FILTER_NAME, 392); + end; + end; + end; + + if PingState then + begin + sgCircuitInfo.ColWidths[CIRC_INFO_NAME] := Round(111 * Scale); + sgCircuitInfo.ColWidths[CIRC_INFO_IP] := Round(100 * Scale); + sgCircuitInfo.ColWidths[CIRC_INFO_COUNTRY] := Round(120 * Scale); + sgCircuitInfo.ColWidths[CIRC_INFO_PING] := Round(48 * Scale); + sgRouters.ColWidths[ROUTER_NAME] := Round(90 * Scale); + sgRouters.ColWidths[ROUTER_IP] := Round(88 * Scale); + sgRouters.ColWidths[ROUTER_PING] := Round(44 * Scale); + GridScrollCheck(sgRouters, ROUTER_COUNTRY, 105); + end + else + begin + sgCircuitInfo.ColWidths[CIRC_INFO_NAME] := Round(126 * Scale); + sgCircuitInfo.ColWidths[CIRC_INFO_IP] := Round(115 * Scale); + sgCircuitInfo.ColWidths[CIRC_INFO_COUNTRY] := Round(140 * Scale); + sgCircuitInfo.ColWidths[CIRC_INFO_PING] := -1; + sgRouters.ColWidths[ROUTER_NAME] := Round(105 * Scale); + sgRouters.ColWidths[ROUTER_IP] := Round(98 * Scale); + sgRouters.ColWidths[ROUTER_PING] := Round(-1 * Scale); + GridScrollCheck(sgRouters, ROUTER_COUNTRY, 125); + end; +end; + +procedure TTcp.cbEnablePingMeasureClick(Sender: TObject); +begin + if cbEnablePingMeasure.Focused then + begin + CheckScannerControls; + CheckStatusControls; + if cbEnablePingMeasure.Checked then + ConsensusUpdated := True; + EnableOptionButtons; + end; +end; + +procedure TTcp.cbEnableDetectAliveNodesClick(Sender: TObject); +begin + if cbEnableDetectAliveNodes.Focused then + begin + CheckScannerControls; + CheckStatusControls; + if cbEnableDetectAliveNodes.Checked then + ConsensusUpdated := True; + EnableOptionButtons; + end; +end; + +procedure TTcp.cbHsMaxStreamsClick(Sender: TObject); +begin + if not TCheckBox(Sender).Focused then + Exit; + HsMaxStreamsEnable(cbHsMaxStreams.Checked); + ChangeHsTable(2); +end; + +procedure TTcp.meBridgesChange(Sender: TObject); +begin + lbTotalBridges.Caption := TransStr('203') + ': ' + IntToStr(meBridges.Lines.Count); + EnableOptionButtons; +end; + +procedure TTcp.meLogMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + if Button = mbLeft then + meLog.Tag := 1; +end; + +procedure TTcp.meLogMouseUp(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + if Button = mbLeft then + begin + if meLog.SelLength = 0 then + begin + meLog.Tag := 0; + CheckLogAutoScroll; + end; + end; +end; + +procedure TTcp.MemoKeyPress(Sender: TObject; var Key: Char); +begin + if CtrlKeyPressed('A') then + TMemo(Sender).SelectAll; +end; + +procedure TTcp.SaveSortData; +begin + SetConfigString('Main', 'SortData', + IntToStr(sgFilter.SortType) + ',' + IntToStr(sgFilter.SortCol) + ',' + + IntToStr(sgRouters.SortType) + ',' + IntToStr(sgRouters.SortCol) + ',' + + IntToStr(sgCircuits.SortType) + ',' + IntToStr(sgCircuits.SortCol) + ',' + + IntToStr(sgStreams.SortType) + ',' + IntToStr(sgStreams.SortCol) + ',' + + IntToStr(sgStreamsInfo.SortType) + ',' + IntToStr(sgStreamsInfo.SortCol) + ); +end; + +procedure TTcp.GridSort(aSg: TStringGrid); +var + aCompare: TStringListSortCompare; + aCol: Integer; +begin + case aSg.ColsDataType[aSg.SortCol] of + dtInteger: + if aSg.SortType = SORT_ASC then aCompare := CompIntAsc else aCompare := CompIntDesc; + dtSize: + if aSg.SortType = SORT_ASC then aCompare := CompSizeAsc else aCompare := CompSizeDesc; + dtParams: + if aSg.SortType = SORT_ASC then aCompare := CompParamsAsc else aCompare := CompParamsDesc; + else + if aSg.SortType = SORT_ASC then aCompare := CompTextAsc else aCompare := CompTextDesc; + end; + if aSg.ColsDataType[aSg.SortCol] = dtParams then + aCol := 0 + else + aCol := aSg.SortCol; + sgSort(aSg, aCol, aCompare); +end; + +procedure TTcp.SortPrepare(aSg: TStringGrid; ACol: Integer; ManualSort: Boolean = False); +var + ScrollTop: Boolean; +begin + if (aSg.SortCol = ACol) then + case aSg.SortType of + SORT_ASC: aSg.SortType := SORT_DESC; + SORT_DESC: aSg.SortType := SORT_ASC; + end + else + aSg.SortType := SORT_ASC; + aSg.SortCol := ACol; + aSg.RowID := aSg.Cells[0, aSg.SelRow]; + + GridSort(aSg); + case aSg.Tag of + GRID_FILTER: ScrollTop := miFilterScrollTop.Checked; + GRID_ROUTERS: ScrollTop := miRoutersScrollTop.Checked; + else + ScrollTop := False; + end; + SetGridLastCell(aSg, True, ScrollTop, ManualSort); + SaveSortData; +end; + +procedure TTcp.SelectCircuitsSort(Sender: TObject); +begin + TMenuItem(Sender).Checked := True; + SortPrepare(sgCircuits, TMenuItem(Sender).Tag); +end; + +procedure TTcp.sgCircuitsFixedCellClick(Sender: TObject; ACol, ARow: Integer); +begin + miCircuitsSort.Items[ACol].Checked := True; + SortPrepare(sgCircuits, ACol, True); +end; + +procedure TTcp.SelectStreamsSort(Sender: TObject); +begin + TMenuItem(Sender).Checked := True; + SortPrepare(sgStreams, TMenuItem(Sender).Tag); +end; + +procedure TTcp.SelectStreamsInfoSort(Sender: TObject); +begin + TMenuItem(Sender).Checked := True; + SortPrepare(sgStreamsInfo, TMenuItem(Sender).Tag); +end; + +procedure TTcp.sgStreamsFixedCellClick(Sender: TObject; ACol, ARow: Integer); +begin + miStreamsSort.Items[ACol].Checked := True; + SortPrepare(sgStreams, ACol, True); +end; + +procedure TTcp.meNodesListChange(Sender: TObject); +begin + lbTotalNodesList.Caption := TransStr('203') + ': ' + IntToStr(meNodesList.Lines.Count); + if not meNodesList.Focused then + Exit; + NodesListStage := 1; + EnableOptionButtons; +end; + +procedure TTcp.meNodesListExit(Sender: TObject); +begin + FindDialog.CloseDialog; + if NodesListStage = 1 then + SaveNodesList(cbxNodesListType.ItemIndex); +end; + +procedure TTcp.meMyFamilyChange(Sender: TObject); +begin + lbTotalMyFamily.Caption := TransStr('203') + ': ' + IntToStr(meMyFamily.Lines.Count); + EnableOptionButtons; +end; + +procedure TTcp.MaxMemInQueuesEnable(State: Boolean); +begin + edMaxMemInQueues.Enabled := State; + udMaxMemInQueues.Enabled := State; + lbMaxMemInQueues.Enabled := State; + lbSizeMb.Enabled := State; +end; + +procedure TTcp.cbUseMaxMemInQueuesClick(Sender: TObject); +begin + MaxMemInQueuesEnable(cbUseMaxMemInQueues.Checked); + EnableOptionButtons; +end; + +procedure TTcp.NumCPUsEnable(State: Boolean); +begin + edNumCPUs.Enabled := State; + udNumCPUs.Enabled := State; + lbNumCPUs.Enabled := State; +end; + +procedure TTcp.cbNoDesktopBordersClick(Sender: TObject); +begin + cbNoDesktopBordersOnlyEnlarged.Enabled := cbNoDesktopBorders.Checked; + EnableOptionButtons; +end; + +procedure TTcp.cbUseNumCPUsClick(Sender: TObject); +begin + NumCPUsEnable(cbUseNumCPUs.Checked); + EnableOptionButtons; +end; + +procedure TTcp.RelayBandwidthEnable(State: Boolean); +begin + edRelayBandwidthRate.Enabled := State; + edRelayBandwidthBurst.Enabled := State; + edMaxAdvertisedBandwidth.Enabled := State; + udRelayBandwidthRate.Enabled := State; + udRelayBandwidthBurst.Enabled := State; + udMaxAdvertisedBandwidth.Enabled := State; + lbRelayBandwidthRate.Enabled := State; + lbRelayBandwidthBurst.Enabled := State; + lbMaxAdvertisedBandwidth.Enabled := State; + lbSpeed1.Enabled := State; + lbSpeed2.Enabled := State; + lbSpeed4.Enabled := State; +end; + +procedure TTcp.cbUseReachableAddressesClick(Sender: TObject); +var + State: Boolean; +begin + State := cbUseReachableAddresses.Checked; + edReachableAddresses.Enabled := State; + lbReachableAddresses.Enabled := State; + EnableOptionButtons; +end; + +procedure TTcp.cbUseRelayBandwidthClick(Sender: TObject); +begin + RelayBandwidthEnable(cbUseRelayBandwidth.Checked); + EnableOptionButtons; +end; + +procedure TTcp.cbxRoutersCountryChange(Sender: TObject); +begin + if cbxRoutersCountry.ItemIndex <> -1 then + begin + cbxRoutersCountry.Tag := Integer(cbxRoutersCountry.Items.Objects[cbxRoutersCountry.ItemIndex]); + ShowRouters; + SaveRoutersFilterdata; + end; +end; + +procedure TTcp.cbxRoutersCountryDropDown(Sender: TObject); +begin + ComboBoxAutoWidth(cbxRoutersCountry); +end; + +procedure TTcp.cbxRoutersCountryEnter(Sender: TObject); +begin + ActivateKeyboardLayout(CurrentLanguage, 0); +end; + +procedure TTcp.cbxRoutersQueryChange(Sender: TObject); +begin + SaveRoutersFilterdata(False, False); +end; + +procedure TTcp.cbShowBalloonHintClick(Sender: TObject); +begin + cbShowBalloonOnlyWhenHide.Enabled := cbShowBalloonHint.Checked; + EnableOptionButtons; +end; + +procedure TTcp.cbStayOnTopClick(Sender: TObject); +begin + if cbStayOnTop.Checked then + FormStyle := fsStayOnTop + else + FormStyle := fsNormal; + EnableOptionButtons; +end; + +procedure TTcp.cbUseTrackHostExitsClick(Sender: TObject); +var + State: Boolean; +begin + State := cbUseTrackHostExits.Checked; + edTrackHostExitsExpire.Enabled := State; + udTrackHostExitsExpire.Enabled := State; + meTrackHostExits.Enabled := State; + lbTrackHostExitsExpire.Enabled := State; + lbSeconds4.Enabled := State; + lbTotalHosts.Enabled := State; + EnableOptionButtons; +end; + +function TTcp.PreferredBridgeFound: Boolean; +var + RouterID: string; +begin + LastPreferredBridgeHash := ''; + Result := TryGetDataFromStr(edPreferredBridge.Text, ltHash, RouterID); + if Result then + begin + Result := RoutersDic.ContainsKey(RouterID); + if Result then + LastPreferredBridgeHash := RouterID; + end; +end; + +procedure TTcp.BridgesCheckControls; +var + State, BuiltinState, PreferredState: Boolean; +begin + if cbUseBridges.HelpContext = 1 then + Exit; + State := cbUseBridges.Checked; + PreferredState := State and cbUsePreferredBridge.Checked; + BuiltinState := State and (cbxBridgesType.ItemIndex = BRIDGES_TYPE_BUILTIN) and (cbxBridgesList.Items.Count > 0); + + edPreferredBridge.Enabled := PreferredState; + cbxBridgesType.Enabled := State; + cbxBridgesList.Enabled := BuiltinState; + cbUsePreferredBridge.Enabled := State; + meBridges.Enabled := BuiltinState or (State and (cbxBridgesType.ItemIndex = BRIDGES_TYPE_USER)); + meBridges.ReadOnly := cbxBridgesType.ItemIndex = BRIDGES_TYPE_BUILTIN; + btnFindPreferredBridge.Enabled := PreferredState and PreferredBridgeFound; + lbBridgesType.Enabled := State; + lbBridgesList.Enabled := BuiltinState; + lbTotalBridges.Enabled := State; + lbTotalBridges.Caption := TransStr('203') + ': ' + IntToStr(meBridges.Lines.Count); + lbPreferredBridge.Enabled := PreferredState; +end; + +procedure TTcp.cbUseBridgesClick(Sender: TObject); +begin + if not cbUseBridges.Focused then + Exit; + BridgesUpdated := True; + BridgesCheckControls; + EnableOptionButtons; +end; + +procedure TTcp.cbUseBridgesExit(Sender: TObject); +begin + UpdateRoutersAfterBridgesUpdate; +end; + +procedure TTcp.UseDirPortEnable(State: Boolean); +begin + edDirPort.Enabled := State; + udDirPort.Enabled := State; + if State then + begin + cbDirCache.Checked := True; + cbDirCache.Enabled := False; + end + else + begin + if cbxServerMode.ItemIndex > 0 then + cbDirCache.Enabled := True + else + cbDirCache.Enabled := False; + end; + lbDirPort.Enabled := State; +end; + +procedure TTcp.cbUseDirPortClick(Sender: TObject); +begin + UseDirPortEnable(cbUseDirPort.Checked); + EnableOptionButtons; +end; + +procedure TTcp.cbUseNetworkCacheClick(Sender: TObject); +begin + if not cbUseNetworkCache.Focused then + Exit; + SaveNetworkCache; + EnableOptionButtons; +end; + +procedure TTcp.cbUseHiddenServiceVanguardsClick(Sender: TObject); +var + State: Boolean; +begin + State := cbUseHiddenServiceVanguards.Checked; + cbxVanguardLayerType.Enabled := State; + lbVanguardLayerType.Enabled := State; + if cbUseHiddenServiceVanguards.Focused then + EnableOptionButtons; +end; + +procedure TTcp.cbUseMyFamilyClick(Sender: TObject); +begin + if FirstLoad then + Exit; + MyFamilyEnable(cbUseMyFamily.Checked); + if cbUseMyFamily.Checked then + begin + if meMyFamily.CanFocus then + meMyFamily.SetFocus; + end; + EnableOptionButtons; +end; + +procedure TTcp.cbUseOpenDNSClick(Sender: TObject); +begin + cbUseOpenDNSOnlyWhenUnknown.Enabled := cbUseOpenDNS.Checked; + OpenDNSUpdated := True; + EnableOptionButtons; +end; + +procedure TTcp.cbUseOpenDNSOnlyWhenUnknownClick(Sender: TObject); +begin + OpenDNSUpdated := True; + EnableOptionButtons; +end; + +procedure TTcp.ProxyParamCheck; +var + State: Boolean; +begin + State := cbxProxyType.ItemIndex <> PROXY_TYPE_SOCKS4; + edProxyUser.Enabled := State; + edProxyPassword.Enabled := State; + if not State then + begin + edProxyUser.Text := ''; + edProxyPassword.Text := ''; + end; + lbProxyUser.Enabled := State; + lbProxyPassword.Enabled := State; +end; + +procedure TTcp.cbxProxyTypeChange(Sender: TObject); +begin + ProxyParamCheck; + EnableOptionButtons; +end; + +procedure TTcp.cbUsePreferredBridgeClick(Sender: TObject); +begin + if not cbUsePreferredBridge.Focused then + Exit; + BridgesUpdated := True; + BridgesCheckControls; + EnableOptionButtons; +end; + +procedure TTcp.cbUsePreferredBridgeExit(Sender: TObject); +begin + UpdateRoutersAfterBridgesUpdate; +end; + +procedure TTcp.cbUseProxyClick(Sender: TObject); +var + State: Boolean; +begin + State := cbUseProxy.Checked; + edProxyAddress.Enabled := State; + edProxyPort.Enabled := State; + udProxyPort.Enabled := State; + cbxProxyType.Enabled := State; + if State then + ProxyParamCheck + else + begin + edProxyUser.Enabled := False; + edProxyPassword.Enabled := False; + lbProxyUser.Enabled := False; + lbProxyPassword.Enabled := False; + end; + lbProxyType.Enabled := State; + lbProxyAddress.Enabled := State; + lbProxyPort.Enabled := State; + EnableOptionButtons; +end; + +procedure TTcp.cbUseUPnPClick(Sender: TObject); +begin + imUPnPTest.Visible := cbUseUPnP.Checked; + EnableOptionButtons; +end; + +procedure TTcp.CheckAuthMetodContols; +var + State: Boolean; +begin + State := cbxAuthMetod.ItemIndex = 1; + edControlPassword.PasswordChar := '*'; + edControlPassword.Enabled := State; + lbControlPassword.Enabled := State; + imGeneratePassword.Enabled := State; + imGeneratePassword.ShowHint := State; +end; + +procedure TTcp.cbLearnCircuitBuildTimeoutClick(Sender: TObject); +var + State: Boolean; +begin + State := not cbLearnCircuitBuildTimeout.Checked; + edCircuitBuildTimeout.Enabled := State; + udCircuitBuildTimeout.Enabled := State; + lbCircuitBuildTimeout.Enabled := State; + lbSeconds2.Enabled := State; + EnableOptionButtons; +end; + +procedure TTcp.cbListenIPv6Click(Sender: TObject); +begin + if cbListenIPv6.Checked and (cbxServerMode.ItemIndex = 2) then + cbIPv6Exit.Enabled := True + else + cbIPv6Exit.Enabled := False; + EnableOptionButtons; +end; + +procedure TTcp.cbxAuthMetodChange(Sender: TObject); +begin + CheckAuthMetodContols; + EnableOptionButtons; +end; + +procedure TTcp.cbxAutoSelPriorityChange(Sender: TObject); +begin + CheckAutoSelControls; + EnableOptionButtons; +end; + +procedure TTCP.CheckAutoSelControls; +begin + cbAutoSelNodesWithPingOnly.Enabled := cbxAutoSelPriority.ItemIndex in [1, 3]; +end; + +procedure TTcp.TransportPortEnable(State: Boolean); +begin + edTransportPort.Enabled := State; + udTransportPort.Enabled := State; + lbTransportPort.Enabled := State; +end; + +procedure TTcp.cbxBridgesListChange(Sender: TObject); +begin + UpdateBridgesControls(False); +end; + +procedure TTcp.cbxBridgesListCloseUp(Sender: TObject); +begin + if meBridges.CanFocus then + meBridges.SetFocus; +end; + +procedure TTcp.cbxBridgesListKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + if (Key = VK_RETURN) and meBridges.CanFocus then + meBridges.SetFocus; +end; + +procedure TTcp.cbxBridgeTypeChange(Sender: TObject); +begin + TransportPortEnable(cbxBridgeType.ItemIndex > 0); + EnableOptionButtons; +end; + +procedure TTcp.UpdateBridgesControls(UpdateList: Boolean = True; UpdateUserBridges: Boolean = True); +var + ini: TMemIniFile; +begin + case cbxBridgesType.ItemIndex of + BRIDGES_TYPE_BUILTIN: + LoadBuiltinBridges(True, UpdateList, cbxBridgesList.Text); + BRIDGES_TYPE_USER: + begin + if UpdateUserBridges and FileExists(UserConfigFile) then + begin + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + LoadUserBridges(ini); + finally + ini.Free; + end; + end; + end; + end; + BridgesCheckControls; + EnableOptionButtons; +end; + +procedure TTcp.cbxBridgesTypeChange(Sender: TObject); +begin + UpdateBridgesControls; +end; + +procedure TTcp.cbxBridgesTypeCloseUp(Sender: TObject); +begin + if meBridges.CanFocus then + meBridges.SetFocus; +end; + +procedure TTcp.cbxBridgesTypeKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + if (Key = VK_RETURN) and meBridges.CanFocus then + meBridges.SetFocus; +end; + +procedure TTcp.cbxHsAddressChange(Sender: TObject); +begin + sgHsPorts.Cells[HSP_INTERFACE, sgHsPorts.SelRow] := cbxHsAddress.Text; + UpdateHsPorts; + EnableOptionButtons; +end; + +procedure TTcp.cbxHsAddressDropDown(Sender: TObject); +begin + GetLocalInterfaces(cbxHsAddress); +end; + +procedure TTcp.CheckHsVersion; +begin + case cbxHsVersion.ItemIndex of + HS_VERSION_2: + begin + udHsNumIntroductionPoints.Min := 1; + udHsNumIntroductionPoints.Max := 10; + end; + HS_VERSION_3: + begin + udHsNumIntroductionPoints.Min := 3; + udHsNumIntroductionPoints.Max := 20; + end; + end; + if udHsNumIntroductionPoints.Position < udHsNumIntroductionPoints.Min then + begin + udHsNumIntroductionPoints.Position := udHsNumIntroductionPoints.Min; + sgHs.Cells[HS_INTRO_POINTS, sgHs.SelRow] := IntToStr(udHsNumIntroductionPoints.Position); + end; + + if udHsNumIntroductionPoints.Position > udHsNumIntroductionPoints.Max then + begin + udHsNumIntroductionPoints.Position := udHsNumIntroductionPoints.Max; + sgHs.Cells[HS_INTRO_POINTS, sgHs.SelRow] := IntToStr(udHsNumIntroductionPoints.Position); + end; +end; + +procedure TTcp.cbxHsVersionChange(Sender: TObject); +begin + if cbxHsVersion.ItemIndex = HS_VERSION_2 then + begin + if not ShowMsg(TransStr('326'), '', mtWarning, True) then + begin + cbxHsVersion.ItemIndex := HS_VERSION_3; + Exit; + end; + end; + CheckHsVersion; + case cbxHsVersion.ItemIndex of + HS_VERSION_2: sgHs.Cells[HS_VERSION, sgHs.SelRow] := '2'; + HS_VERSION_3: sgHs.Cells[HS_VERSION, sgHs.SelRow] := '3'; + end; + EnableOptionButtons; +end; + +procedure TTcp.MyFamilyEnable(State: Boolean); +begin + meMyFamily.Enabled := State; + lbTotalMyFamily.Enabled := State; +end; + +function TTcp.NodesToFavorites(NodesID: Integer): Integer; +begin + case NodesID of + NL_TYPE_ENTRY: Result := ENTRY_ID; + NL_TYPE_MIDDLE: Result := MIDDLE_ID; + NL_TYPE_EXIT: Result := EXIT_ID; + NL_TYPE_EXLUDE: Result := EXCLUDE_ID; + else + Result := -1; + end; +end; + +function TTcp.FavoritesToNodes(FavoritesID: Integer): Integer; +begin + case FavoritesID of + ENTRY_ID: Result := NL_TYPE_ENTRY; + MIDDLE_ID: Result := NL_TYPE_MIDDLE; + EXIT_ID: Result := NL_TYPE_EXIT; + EXCLUDE_ID: Result := NL_TYPE_EXLUDE; + else + Result := -1; + end; +end; + +procedure TTcp.CalculateFilterNodes(AlwaysUpdate: Boolean = True); +const + differ = FILTER_ENTRY_NODES; +var + FilterItem: TPair; + NodeType: TNodeTypes; + Counters: array[0..3] of integer; + lbComponent: TLabel; + IsExclude: Boolean; + i, j: Integer; +begin + for i := 0 to Length(Counters) - 1 do + Counters[i] := 0; + for FilterItem in FilterDic do + begin + if NodesDic.TryGetValue(FilterItem.Key, NodeType) then + IsExclude := ntExclude in NodeType + else + IsExclude := False; + + if IsExclude then + Inc(Counters[3]) + else + begin + NodeType := FilterItem.Value.Data; + if ntEntry in NodeType then Inc(Counters[0]); + if ntMiddle in NodeType then Inc(Counters[1]); + if ntExit in NodeType then Inc(Counters[2]); + end; + end; + + for i := FILTER_ENTRY_NODES to FILTER_EXCLUDE_NODES do + begin + lbComponent := GetFilterLabel(i); + j := i - differ; + if AlwaysUpdate or (lbComponent.Tag <> Counters[j]) then + begin + lbComponent.Tag := Counters[j]; + lbComponent.Caption := TransStr(lbComponent.Hint) + ': ' + IntToStr(Counters[j]) + end; + end; +end; + +procedure TTCP.CalculateTotalNodes(AlwaysUpdate: Boolean = True); +const + differ = ENTRY_ID; +var + NodeItem: TPair; + Counters: array[0..4] of integer; + lbComponent: TLabel; + ls: TStringList; + i, j: Integer; +begin + for i := 0 to Length(Counters) - 1 do + Counters[i] := 0; + + ls := TStringList.Create; + try + for NodeItem in NodesDic do + begin + if NodeItem.Value = [] then + begin + RangesDic.Remove(NodeItem.Key); + ls.Add(NodeItem.Key); + end; + end; + for i := 0 to ls.Count - 1 do + NodesDic.Remove(ls[i]); + finally + ls.Free; + end; + + for NodeItem in NodesDic do + begin + if ntEntry in NodeItem.Value then Inc(Counters[0]); + if ntMiddle in NodeItem.Value then Inc(Counters[1]); + if ntExit in NodeItem.Value then Inc(Counters[2]); + if ntExclude in NodeItem.Value then Inc(Counters[3]) else Inc(Counters[4]); + end; + + for i := ENTRY_ID to FAVORITES_ID do + begin + lbComponent := GetFavoritesLabel(i); + j := i - differ; + if AlwaysUpdate or (lbComponent.Tag <> Counters[j]) then + begin + lbComponent.Tag := Counters[j]; + lbComponent.Caption := TransStr(lbComponent.Hint) + ': ' + IntToStr(Counters[j]) + end; + end; +end; + +procedure TTcp.cbxNodesListTypeChange(Sender: TObject); +begin + LoadNodesList; + SetConfigInteger('Lists', 'NodesListType', cbxNodesListType.ItemIndex); +end; + +procedure TTcp.cbxNodesListTypeKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + if (Key = VK_RETURN) and meNodesList.CanFocus then + meNodesList.SetFocus; +end; + +procedure TTcp.SaveNodesList(NodesID: Integer); +var + FavoritesID: Integer; + NodesList: string; +begin + FavoritesID := NodesToFavorites(NodesID); + ClearRouters(TNodeType(FavoritesID)); + NodesList := MemoToLine(meNodesList, ltNode, True); + GetNodes(NodesList, TNodeType(FavoritesID), True); + CalculateTotalNodes; + if NodesListStage > 0 then + NodesListStage := 0; + ShowRouters; + FilterUpdated := True; + UpdateOptionsAfterRoutersUpdate; +end; + +procedure TTcp.LoadNodesList(UseDic: Boolean = True; NodesStr: string = ''); +var + NodeItem: TPair; + NodeType: TNodeType; + FavoritesID: Integer; +begin + FavoritesID := NodesToFavorites(cbxNodesListType.ItemIndex); + if UseDic then + begin + NodesStr := ''; + NodeType := TNodeType(FavoritesID); + for NodeItem in NodesDic do + if NodeType in NodeItem.Value then + NodesStr := NodesStr + ',' + NodeItem.Key; + Delete(NodesStr, 1, 1); + end; + + LineToMemo(RemoveBrackets(NodesStr), meNodesList, ltNode, True); + if UseDic then + CheckFavoritesState(FavoritesID); +end; + +procedure TTcp.CheckFavoritesState(FavoritesID: Integer = -1); +var + StartPos, EndPos, i: Integer; + lbComponent: TLabel; +begin + if FavoritesID in [ENTRY_ID..EXCLUDE_ID] then + begin + StartPos := FavoritesID; + EndPos := FavoritesID; + end + else + begin + StartPos := ENTRY_ID; + EndPos := EXCLUDE_ID; + end; + for i := StartPos to EndPos do + begin + lbComponent := GetFavoritesLabel(i); + if lbComponent.Tag = 0 then + lbComponent.HelpContext := 0; + if NodesToFavorites(cbxNodesListType.ItemIndex) = i then + cbEnableNodesList.Checked := Boolean(lbComponent.HelpContext); + end; + CheckNodesListControls; +end; + +procedure TTcp.CheckNodesListControls; +var + State: Boolean; +begin + State := cbEnableNodesList.Checked; + meNodesList.Enabled := State; + lbTotalNodesList.Enabled := State; +end; + +procedure TTcp.CheckServerControls; +var + State: Boolean; +begin + if cbxServerMode.HelpContext = 1 then + Exit; + State := cbxServerMode.ItemIndex <> 0; + edNickname.Enabled := State; + edContactInfo.Enabled := State; + edORPort.Enabled := State; + udOrPort.Enabled := State; + cbUseRelayBandwidth.Enabled := State; + cbUseMaxMemInQueues.Enabled := State; + cbUseNumCPUs.Enabled := State; + cbUseUPnP.Enabled := State; + cbPublishServerDescriptor.Enabled := State; + cbDirReqStatistics.Enabled := State; + cbHiddenServiceStatistics.Enabled := State; + cbAssumeReachable.Enabled := State; + cbListenIPv6.Enabled := State; + cbUseAddress.Enabled := State; + if State then + begin + if cbUseRelayBandwidth.Checked then + RelayBandwidthEnable(True); + if cbUseMaxMemInQueues.Checked then + MaxMemInQueuesEnable(True); + if cbUseNumCPUs.Checked then + NumCPUsEnable(True); + if cbUseAddress.Checked then + ServerAddressEnable(True); + if cbxServerMode.ItemIndex <> 3 then + begin + MyFamilyEnable(cbUseMyFamily.Checked); + UseDirPortEnable(cbUseDirPort.Checked); + cbUseMyFamily.Enabled := True; + end + else + begin + cbUseMyFamily.Enabled := False; + MyFamilyEnable(False); + end; + imUPnPTest.Visible := True; + lbNickname.Enabled := True; + lbContactInfo.Enabled := True; + lbPorts.Enabled := True; + lbORPort.Enabled := True; + end + else + begin + cbUseDirPort.Enabled := False; + cbUseMyFamily.Enabled := False; + TransportPortEnable(False); + UseDirPortEnable(False); + RelayBandwidthEnable(False); + MaxMemInQueuesEnable(False); + NumCPUsEnable(False); + MyFamilyEnable(False); + ServerAddressEnable(False); + meExitPolicy.Enabled := False; + imUPnPTest.Visible := False; + lbNickname.Enabled := False; + lbContactInfo.Enabled := False; + lbPorts.Enabled := False; + lbORPort.Enabled := False; + lbTotalMyFamily.Enabled := False; + end; + + if cbxServerMode.ItemIndex = 2 then + begin + if cbListenIPv6.Checked then + cbIPv6Exit.Enabled := True; + cbxExitPolicyType.Enabled := True; + meExitPolicy.enabled := cbxExitPolicyType.ItemIndex = 2; + lbExitPolicy.Enabled := True; + end + else + begin + cbIPv6Exit.Enabled := False; + cbxExitPolicyType.Enabled := False; + meExitPolicy.enabled := False; + lbExitPolicy.Enabled := False; + end; + + if cbxServerMode.ItemIndex = 3 then + begin + cbUseDirPort.Checked := False; + cbUseDirPort.Enabled := False; + cbDirCache.Enabled := False; + cbDirCache.Checked := True; + cbxBridgeType.Enabled := True; + cbxBridgeDistribution.Enabled := True; + cbUseMyFamily.Checked := False; + TransportPortEnable(cbxBridgeType.ItemIndex > 0); + lbBridgeType.Enabled := True; + lbBridgeDistribution.Enabled := True; + end + else + begin + cbxBridgeType.Enabled := False; + cbxBridgeDistribution.Enabled := False; + if cbxServerMode.ItemIndex > 0 then + cbUseDirPort.Enabled := True; + TransportPortEnable(False); + lbBridgeType.Enabled := False; + lbBridgeDistribution.Enabled := False; + end; +end; + +procedure TTcp.cbxServerModeChange(Sender: TObject); +begin + CheckServerControls; + EnableOptionButtons +end; + +procedure TTcp.cbxHsStateChange(Sender: TObject); +begin + case cbxHsState.ItemIndex of + HS_STATE_ENABLED: sgHs.Cells[HS_STATE, sgHs.SelRow] := SELECT_CHAR; + HS_STATE_DISABLED: sgHs.Cells[HS_STATE, sgHs.SelRow] := FAVERR_CHAR; + end; + EnableOptionButtons; +end; + +procedure TTcp.cbxSocksHostDropDown(Sender: TObject); +begin + GetLocalInterfaces(cbxSocksHost, '', True); +end; + +procedure TTcp.cbxThemesChange(Sender: TObject); +begin + LoadStyle(cbxThemes); + SetIconsColor; + EnableOptionButtons; +end; + +procedure TTcp.cbxThemesDropDown(Sender: TObject); +begin + LoadThemesList(cbxThemes, ''); +end; + +procedure TTcp.cbxTransportTypeChange(Sender: TObject); +begin + sgTransports.Cells[PT_TYPE, sgTransports.SelRow] := GetTransportChar(cbxTransportType.ItemIndex); + EnableOptionButtons; +end; + +procedure TTcp.ChangeTransportTable(Param: Integer); +begin + case Param of + 1: sgTransports.Cells[PT_TRANSPORTS, sgTransports.SelRow] := StringReplace(edTransports.Text, ' ', '', [rfReplaceAll]); + 2: sgTransports.Cells[PT_HANDLER, sgTransports.SelRow] := StringReplace(edTransportsHandler.Text, ' ', '', [rfReplaceAll]); + 3: sgTransports.Cells[PT_PARAMS, sgTransports.SelRow] := Trim(meHandlerParams.Text); + end; + EnableOptionButtons; +end; + +procedure TTcp.ChangeHsTable(Param: Integer); +begin + if mnHs.Tag = 1 then + Exit; + case Param of + 0: sgHs.Cells[HS_NAME, sgHs.SelRow] := edHsName.Text; + 1: sgHs.Cells[HS_INTRO_POINTS, sgHs.SelRow] := IntToStr(udHsNumIntroductionPoints.Position); + 2: + begin + if cbHsMaxStreams.Checked then + sgHs.Cells[HS_MAX_STREAMS, sgHs.SelRow] := IntToStr(udHsMaxStreams.Position) + else + begin + sgHs.Cells[HS_MAX_STREAMS, sgHs.SelRow] := NONE_CHAR; + udHsMaxStreams.Position := 32; + end; + end; + 3: sgHsPorts.Cells[HSP_REAL_PORT, sgHsPorts.SelRow] := IntToStr(udHsRealPort.Position); + 4: sgHsPorts.Cells[HSP_VIRTUAL_PORT, sgHsPorts.SelRow] := IntToStr(udHsVirtualPort.Position); + end; + if Param in [3, 4] then + UpdateHsPorts; + EnableOptionButtons; +end; + +procedure TTcp.edControlPasswordDblClick(Sender: TObject); +begin + if edControlPassword.PasswordChar = '*' then + edControlPassword.PasswordChar := #0 + else + edControlPassword.PasswordChar := '*'; +end; + +procedure TTcp.edTransportsChange(Sender: TObject); +begin + if CtrlKeyPressed('A') then + Exit; + if TCustomEdit(Sender).Focused then + ChangeTransportTable(TEdit(Sender).Tag) +end; + +procedure TTcp.edHsChange(Sender: TObject); +var + UD: TUpDown; +begin + if CtrlKeyPressed('A') then + Exit; + if TEdit(Sender).Focused then + ChangeHsTable(TEdit(Sender).HelpContext) + else + begin + UD := GetAssocUpDown(TEdit(Sender).Name); + if UD <> nil then + UD.Enabled := TEdit(Sender).Enabled; + end; +end; + +procedure TTcp.udHsMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +begin + ChangeHsTable(TUpDown(Sender).Tag); +end; + +procedure TTcp.udRoutersWeightClick(Sender: TObject; Button: TUDBtnType); +begin + ShowRouters; + SaveRoutersFilterdata; +end; + +procedure TTcp.EditChange(Sender: TObject); +begin + if TEdit(Sender).Focused then + begin + if CtrlKeyPressed('A') then + Exit; + EnableOptionButtons; + end; +end; + +procedure TTcp.MemoExit(Sender: TObject); +begin + FindDialog.CloseDialog; +end; + +procedure TTcp.SetDownState; +begin + case LastPlace of + LP_OPTIONS: sbShowOptions.Down := True; + LP_LOG: sbShowLog.Down := True; + LP_STATUS: sbShowStatus.Down := True; + LP_CIRCUITS: sbShowCircuits.Down := True; + LP_ROUTERS: sbShowRouters.Down := True; + end; +end; + +procedure TTcp.sbShowOptionsClick(Sender: TObject); +begin + LastPlace := LP_OPTIONS; + UpdateOptionsAfterRoutersUpdate; + IncreaseFormSize; + ResetFocus; +end; + +procedure TTcp.sbShowOptionsMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + if (pcOptions.TabIndex = 2) and (ssDouble in Shift) and (Button = mbLeft) then + SetGridLastCell(sgFilter, True, True, True); +end; + +procedure TTcp.sbShowRoutersClick(Sender: TObject); +begin + LastPlace := LP_ROUTERS; + IncreaseFormSize; + ResetFocus; +end; + +procedure TTcp.sbShowRoutersMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + if (ssDouble in Shift) and (Button = mbLeft) then + SetGridLastCell(sgRouters, True, True, True); +end; + +procedure TTcp.sbShowStatusClick(Sender: TObject); +begin + LastPlace := LP_STATUS; + IncreaseFormSize; + ResetFocus; +end; + +procedure TTcp.sbDecreaseFormClick(Sender: TObject); +begin + CheckOptionsChanged; + DecreaseFormSize; +end; + +procedure TTcp.sbShowCircuitsClick(Sender: TObject); +begin + LastPlace := LP_CIRCUITS; + IncreaseFormSize; + ResetFocus; +end; + +procedure TTcp.sbShowCircuitsMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + if (ssDouble in Shift) and (Button = mbLeft) then + begin + ShowCircuits; + FindInCircuits(Circuit, ExitNodeID, True); + end; +end; + +procedure TTcp.CheckLogAutoScroll(AlwaysUpdate: Boolean = False); +begin + if AlwaysUpdate or (miAutoScroll.Checked and (meLog.Tag = 0)) then + meLog.Perform(WM_VSCROLL, SB_BOTTOM, 0); +end; + +procedure TTcp.sbShowLogClick(Sender: TObject); +begin + LastPlace := LP_LOG; + CheckLogAutoScroll; + IncreaseFormSize; + ResetFocus; +end; + +procedure TTcp.SpinChanging(Sender: TObject; var AllowChange: Boolean); +begin + EnableOptionButtons; +end; + +procedure TTcp.edPreferredBridgeChange(Sender: TObject); +begin + if CtrlKeyPressed('A') then + Exit; + if not TEdit(Sender).Focused then + Exit; + btnFindPreferredBridge.Enabled := PreferredBridgeFound; + BridgesUpdated := True; + EnableOptionButtons; +end; + +procedure TTcp.edPreferredBridgeExit(Sender: TObject); +begin + UpdateRoutersAfterBridgesUpdate; +end; + +procedure TTcp.edReachableAddressesKeyPress(Sender: TObject; + var Key: Char); +begin + if not CharInSet(Key, ['0'..'9', #44, #8]) then + Key := #0; +end; + +procedure TTcp.edRoutersWeightKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + if Key = VK_RETURN then + begin + ShowRouters; + SaveRoutersFilterdata; + end; +end; + +procedure TTcp.edRoutersWeightMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + ShowRouters; + SaveRoutersFilterdata; +end; + +procedure TTcp.edRoutersQueryChange(Sender: TObject); +var + Query: string; + Data: Integer; + procedure SetIndex(Index: Integer); + begin + if (cbxRoutersQuery.ItemIndex <> Index) and + InRange(Index, 0, cbxRoutersQuery.Items.Count - 1) then + cbxRoutersQuery.ItemIndex := Index; + end; +begin + Query := Trim(edRoutersQuery.Text); + if ValidHash(Query) then + SetIndex(0) + else + begin + Data := ValidAddress(RemoveBrackets(Query, True)); + if Data <> 0 then + begin + if Data = 1 then + begin + if SeparateLeft(Query, '.') <> '0' then + SetIndex(2) + else + SetIndex(6) + end + else + SetIndex(3) + end; + end; +end; + +procedure TTcp.edRoutersQueryKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + if Key = VK_RETURN then + begin + SaveRoutersFilterdata(False, False); + LoadRoutersFilterData(LastRoutersFilter, False, True); + if Trim(edRoutersQuery.Text) <> '' then + begin + if (miDisableFiltersOnUserQuery.Checked and not (ssCtrl in Shift)) + or (not miDisableFiltersOnUserQuery.Checked and (ssCtrl in Shift)) then + RoutersCustomFilter := FILTER_BY_QUERY; + end + else + edRoutersQuery.Text := ''; + CheckShowRouters; + ShowRouters; + SaveRoutersFilterdata(False, False); + end; +end; + +procedure TTcp.RestoreForm; +begin + Tcp.Visible := True; + Application.Restore; + Application.BringToFront; +end; + +procedure TTcp.miShowLogClick(Sender: TObject); +begin + RestoreForm; + sbShowLog.Click; +end; + +procedure TTcp.miShowOptionsClick(Sender: TObject); +begin + RestoreForm; + sbShowOptions.Click; +end; + +procedure TTcp.miShowStatusClick(Sender: TObject); +begin + RestoreForm; + sbShowStatus.Click; +end; + +procedure TTcp.miShowStreamsInfoClick(Sender: TObject); +begin + CheckStreamsControls; + SetConfigBoolean('Circuits', 'ShowStreamsInfo', miShowStreamsInfo.Checked); +end; + +procedure TTcp.miShowCircuitsClick(Sender: TObject); +begin + RestoreForm; + sbShowCircuits.Click; +end; + +procedure TTcp.miShowFlagsHintClick(Sender: TObject); +begin + SetConfigBoolean('Routers', 'ShowFlagsHint', miShowFlagsHint.Checked); +end; + +procedure TTcp.CheckStreamsControls; +begin + lbDLCirc.Visible := miShowCircuitsTraffic.Checked; + lbULCirc.Visible := miShowCircuitsTraffic.Checked; + sgStreamsInfo.Visible := miShowStreamsInfo.Checked; + if miShowStreamsInfo.Checked then + sgStreams.Height := Round(158 * Scale) + else + sgStreams.Height := Round(275 * Scale); + + if miShowStreamsTraffic.Checked then + begin + sgStreams.ColWidths[STREAMS_BYTES_READ] := Round(60 * Scale); + sgStreams.ColWidths[STREAMS_BYTES_WRITTEN] := Round(60 * Scale); + GridScrollCheck(sgStreams, STREAMS_TARGET, 301); + sgStreamsInfo.ColWidths[STREAMS_INFO_SOURCE_ADDR] := Round(118 * Scale); + sgStreamsInfo.ColWidths[STREAMS_INFO_DEST_ADDR] := Round(118 * Scale); + sgStreamsInfo.ColWidths[STREAMS_INFO_BYTES_READ] := Round(60 * Scale); + sgStreamsInfo.ColWidths[STREAMS_INFO_BYTES_WRITTEN] := Round(60 * Scale); + GridScrollCheck(sgStreamsInfo, STREAMS_INFO_PURPOSE, 119); + end + else + begin + sgStreams.ColWidths[STREAMS_BYTES_READ] := -1; + sgStreams.ColWidths[STREAMS_BYTES_WRITTEN] := -1; + GridScrollCheck(sgStreams, STREAMS_TARGET, 424); + sgStreamsInfo.ColWidths[STREAMS_INFO_SOURCE_ADDR] := Round(158 * Scale); + sgStreamsInfo.ColWidths[STREAMS_INFO_DEST_ADDR] := Round(158 * Scale); + sgStreamsInfo.ColWidths[STREAMS_INFO_BYTES_READ] := -1; + sgStreamsInfo.ColWidths[STREAMS_INFO_BYTES_WRITTEN] := -1; + GridScrollCheck(sgStreamsInfo, STREAMS_INFO_PURPOSE, 163); + end; +end; + +procedure TTcp.ShowTrafficSelect(Sender: TObject); +begin + CheckStreamsControls; + if ConnectState = 2 then + SendCommand('SETEVENTS ' + GetControlEvents); + case TMenuItem(Sender).Tag of + 1: SetConfigBoolean('Circuits', 'ShowCircuitsTraffic', miShowCircuitsTraffic.Checked); + 2: SetConfigBoolean('Circuits', 'ShowStreamsTraffic', miShowStreamsTraffic.Checked); + end; +end; + +procedure TTcp.FastAndStableEnable(State: Boolean; AutoCheck: Boolean = True); +begin + miShowFast.Enabled := State; + miShowStable.Enabled := State; + if AutoCheck and not State then + begin + miShowFast.Checked := True; + miShowStable.Checked := True; + end; +end; + +procedure TTcp.CheckShowRouters; +var + AuthorityState, BridgeState, AuthorityOrBridgeState: Boolean; +begin + AuthorityState := not miShowAuthority.Checked; + BridgeState := not miShowBridge.Checked; + AuthorityOrBridgeState := AuthorityState and BridgeState; + + if (RoutersCustomFilter > 0) then + begin + case RoutersCustomFilter of + FILTER_BY_ALIVE: IntToMenu(miRtFilters, 3); + FILTER_BY_TOTAL: IntToMenu(miRtFilters, 2); + FILTER_BY_GUARD: IntToMenu(miRtFilters, 3); + FILTER_BY_EXIT: IntToMenu(miRtFilters, 3); + FILTER_BY_QUERY: IntToMenu(miRtFilters, 8); + ENTRY_ID..FAVORITES_ID: IntToMenu(miRtFilters, 0, True); + end; + end; + + if miShowOther.Checked or miShowBridge.Checked or miShowAuthority.Checked then + begin + miShowExit.Checked := False; + miShowGuard.Checked := False; + end; + + if miShowGuard.Checked or miShowHSDir.Checked then + begin + FastAndStableEnable(False); + if miShowGuard.Checked then + miShowV2Dir.Checked := True; + miShowV2Dir.Enabled := not miShowGuard.Checked; + end + else + begin + FastAndStableEnable(AuthorityOrBridgeState, False); + miShowV2Dir.Enabled := True; + end; + + miShowHsDir.Enabled := AuthorityOrBridgeState; + miShowDirMirror.Enabled := AuthorityOrBridgeState; + + edRoutersQuery.Enabled := miRtFiltersQuery.Checked; + cbxRoutersQuery.Enabled := miRtFiltersQuery.Checked; + edRoutersWeight.Enabled := miRtFiltersWeight.Checked; + udRoutersWeight.Enabled := miRtFiltersWeight.Checked; + cbxRoutersCountry.Enabled := miRtFiltersCountry.Checked; + btnShowNodes.Enabled := miRtFiltersType.Checked; + lbSpeed3.Enabled := miRtFiltersWeight.Checked; + SetCustomFilterStyle(RoutersCustomFilter); +end; + +procedure TTcp.SetCustomFilterStyle(CustomFilterID: Integer); +begin + if not FirstLoad then + begin + TFont(lbFavoritesEntry.Font).Style := []; + TFont(lbFavoritesMiddle.Font).Style := []; + TFont(lbFavoritesExit.Font).Style := []; + TFont(lbFavoritesTotal.Font).Style := []; + TFont(lbExcludeNodes.Font).Style := []; + end; + if CustomFilterID in [ENTRY_ID..FAVORITES_ID] then + TFont(GetFavoritesLabel(CustomFilterID).Font).Style := [fsUnderline]; +end; + +procedure TTcp.SetRoutersFilter(Sender: TObject); +var + Mask: Integer; +begin + Mask := TMenuItem(Sender).Tag; + case Mask of + 1:if miShowExit.Checked then + begin + miShowOther.Checked := False; miShowBridge.Checked := False; miShowAuthority.Checked := False; + end; + 2:if miShowGuard.Checked then + begin + miShowOther.Checked := False; miShowBridge.Checked := False; miShowAuthority.Checked := False; + end; + 4:if miShowAuthority.Checked then + begin + miShowBridge.Checked := False; miShowOther.Checked := False; + end; + 8:if miShowOther.Checked then + begin + miShowBridge.Checked := False; miShowAuthority.Checked := False; + end; + 16:if miShowBridge.Checked then + begin + miShowOther.Checked := False; miShowAuthority.Checked := False; + end; + end; + + if ShowNodesChanged and miDisableFiltersOnAuthorityOrBridge.Checked then + begin + if (Mask in [1,2,8]) or ((Mask in [4,16]) and not TMenuItem(Sender).Checked) then + begin + if LastFilters > -1 then + begin + IntToMenu(miRtFilters, LastFilters); + LastFilters := -1; + end; + end + else + begin + if TMenuItem(Sender).Checked and (Mask in [4,16])then + begin + if LastFilters = -1 then + LastFilters := MenuToInt(miRtFilters); + if miRtFiltersCountry.Checked and (cbxRoutersCountry.Tag <> -1) then + miRtFiltersCountry.Checked := False; + if miRtFiltersWeight.Checked and (udRoutersWeight.Position > 0) then + miRtFiltersWeight.Checked := False; + if miRtFiltersQuery.Checked and (Trim(edRoutersQuery.Text) <> '') then + miRtFiltersQuery.Checked := False; + end; + end; + end; + + ShowNodesChanged := False; + CheckShowRouters; + ShowRouters; + SaveRoutersFilterdata(False, True); +end; + +procedure TTcp.SetRoutersFilterState(Sender: TObject); +begin + if RoutersCustomFilter in [FILTER_BY_ALIVE..FILTER_BY_QUERY] then + RoutersCustomFilter := 0; + LastFilters := -1; + CheckShowRouters; + ShowRouters; + SaveRoutersFilterdata; +end; + +procedure TTcp.LoadRoutersFilterData(Data: string; AutoUpdate: Boolean = True; ResetCustomFilter: Boolean = False); +var + ParseStr: ArrOfStr; + i, QueryType: Integer; +begin + if not FirstLoad then + LastRoutersFilter := Data; + ParseStr := Explode(';', Data); + + for i := 0 to Length(ParseStr) - 1 do + begin + case i of + 0: + begin + RoutersFilters := StrToIntDef(ParseStr[i], ROUTER_FILTER_DEFAULT); + IntToMenu(miRtFilters, RoutersFilters); + end; + 1: LastFilters := StrToIntDef(ParseStr[i], -1); + 2: IntToMenu(mnShowNodes.Items, StrToIntDef(ParseStr[i], SHOW_NODES_FILTER_DEFAULT)); + 3: cbxRoutersCountry.Tag := StrToIntDef(ParseStr[i], -1); + 4: udRoutersWeight.Position := StrToIntDef(ParseStr[i], 10); + 5: + begin + if ResetCustomFilter then + RoutersCustomFilter := 0 + else + begin + RoutersCustomFilter := StrToIntDef(ParseStr[i], 0); + if not (RoutersCustomFilter in [0, FILTER_BY_ALIVE..FAVORITES_ID]) then + RoutersCustomFilter := 0; + end; + end; + 6: + begin + LastRoutersCustomFilter := StrToIntDef(ParseStr[i], 0); + if not (LastRoutersCustomFilter in [0, FILTER_BY_ALIVE..FAVORITES_ID]) then + LastRoutersCustomFilter := 0; + end; + 7: + begin + QueryType := StrToIntDef(ParseStr[i], -1); + if (QueryType < 0) or (QueryType > cbxRoutersQuery.Items.Count - 1) then + begin + cbxRoutersQuery.ItemIndex := 0; + edRoutersQuery.Text := ''; + Break; + end + else + if FirstLoad then + cbxRoutersQuery.ItemIndex := QueryType; + end; + 8: edRoutersQuery.Text := ParseStr[i]; + end; + end; + + if AutoUpdate then + begin + CheckCountryIndexInList; + CheckShowRouters; + ShowRouters; + end; +end; + +procedure TTcp.SaveRoutersFilterdata(Default: Boolean = False; SaveFilters: Boolean = True); +var + Ident, UserQuery: string; + Filters, Search: Integer; +begin + if Default then + begin + Ident := 'DefaultFilter'; + LastFilters := -1; + udRoutersWeight.ResetValue := udRoutersWeight.Position; + end + else + Ident := 'CurrentFilter'; + if SaveFilters then + begin + RoutersFilters := MenuToInt(miRtFilters); + Filters := RoutersFilters; + end + else + Filters := RoutersFilters; + + UserQuery := Trim(edRoutersQuery.Text); + Search := Pos(';', UserQuery); + if Search <> 0 then + begin + case cbxRoutersQuery.ItemIndex of + 4,5: UserQuery := StringReplace(UserQuery, ';', ',', [rfReplaceAll]); + else + SetLength(UserQuery, Pred(Search)); + end; + end; + LastRoutersFilter := IntToStr(Filters) + ';' + + IntToStr(LastFilters) + ';' + + IntToStr(MenuToInt(mnShowNodes.Items)) + ';' + + IntToStr(cbxRoutersCountry.Tag) + ';' + + IntToStr(udRoutersWeight.Position) + ';' + + IntToStr(RoutersCustomFilter) + ';' + + IntToStr(LastRoutersCustomFilter) + ';' + + IntToStr(cbxRoutersQuery.ItemIndex) + ';' + + UserQuery; + SetConfigString('Routers', Ident, LastRoutersFilter); +end; + +procedure TTcp.miShowRoutersClick(Sender: TObject); +begin + RestoreForm; + sbShowRouters.Click; +end; + +procedure TTcp.miSwitchTorClick(Sender: TObject); +begin + btnSwitchTor.Click; +end; + +procedure TTcp.miTplSaveClick(Sender: TObject); +begin + SetConfigInteger('Filter', 'TplSave', MenuToInt(miTplSave)); +end; + +procedure TTcp.miTransportsClearClick(Sender: TObject); +begin + ClearGrid(sgTransports); + UpdateTransports; + EnableOptionButtons; +end; + +procedure TTcp.miTransportsDeleteClick(Sender: TObject); +begin + DeleteARow(sgTransports, sgTransports.SelRow); + UpdateTransports; + EnableOptionButtons; +end; + +procedure TTcp.miTransportsInsertClick(Sender: TObject); +begin + if IsEmptyGrid(sgTransports) then + TransportsEnable(True) + else + begin + sgTransports.RowCount := sgTransports.RowCount + 1; + sgTransports.Row := sgTransports.RowCount - 1; + end; + sgTransports.Cells[PT_TRANSPORTS, sgTransports.SelRow] := 'transport'; + sgTransports.Cells[PT_HANDLER, sgTransports.SelRow] := 'program.exe'; + sgTransports.Cells[PT_Type, sgTransports.SelRow] := FAVERR_CHAR; + sgTransports.Cells[PT_PARAMS, sgTransports.SelRow] := ''; + SelectTransports; + EnableOptionButtons; +end; + +procedure TTcp.miTransportsOpenDirClick(Sender: TObject); +begin + ShellOpen(GetFullFileName(TransportsDir)); +end; + +procedure TTcp.miTransportsResetClick(Sender: TObject); +begin + ResetTransports; + EnableOptionButtons; +end; + +procedure TTcp.StartScannerManual(Sender: TObject); +var + ScanPurpose: TScanPurpose; + ScanType: TScanType; + ScanPing, ScanAlive: Boolean; +begin + ScanPing := miManualPingMeasure.Checked; + ScanAlive := miManualDetectAliveNodes.Checked; + if ScanPing or ScanAlive then + begin + if ScanPing and ScanAlive then + ScanType := stBoth + else + begin + if miManualPingMeasure.Checked then + ScanType := stPing + else + ScanType := stAlive; + end; + end + else + ScanType := stNone; + + case TMenuItem(Sender).Tag of + 1: ScanPurpose := spNew; + 2: ScanPurpose := spFailed; + 3: ScanPurpose := spBridges; + 4: ScanPurpose := spAll; + else + ScanPurpose := spNone; + end; + + ScanNetwork(ScanType, ScanPurpose); +end; + +procedure TTcp.miTplLoadClick(Sender: TObject); +begin + SetConfigInteger('Filter', 'TplLoad', MenuToInt(miTplLoad)); +end; + +procedure TTcp.miSelectExitCircuitWhetItChangesClick(Sender: TObject); +begin + ShowCircuits; + SetConfigBoolean('Circuits', 'SelectExitCircuitWhetItChanges', miSelectExitCircuitWhetItChanges.Checked); +end; + +procedure TTcp.miSelectGraphDLClick(Sender: TObject); +begin + pbTraffic.Repaint; + SetConfigBoolean('Status', 'SelectGraphDL', miSelectGraphDL.Checked); +end; + +procedure TTcp.miSelectGraphULClick(Sender: TObject); +begin + pbTraffic.Repaint; + SetConfigBoolean('Status', 'SelectGraphUL', miSelectGraphUL.Checked); +end; + +procedure TTcp.btnApplyOptionsClick(Sender: TObject); +begin + ApplyOptions; +end; + +procedure TTcp.btnCancelOptionsClick(Sender: TObject); +begin + ResetOptions; +end; + +procedure TTcp.CursorStopTimer(Sender: TObject); +begin + if CursorShow then + begin + CursorShow := False; + btnChangeCircuit.Enabled := True; + btnChangeCircuit.Cursor := crDefault; + FreeAndNil(CursorStop); + end + else + begin + btnChangeCircuit.Cursor := crNo; + CursorStop.Interval := 250; + CursorShow := True; + btnChangeCircuit.Enabled := False; + end; +end; + +procedure TTcp.btnChangeCircuitClick(Sender: TObject); +begin + if CheckSplitButton(btnChangeCircuit) then + Exit; + if cbEnableSocks.Checked and (ConnectState = 2) and (Circuit <> '') then + begin + btnChangeCircuit.Enabled := False; + miChangeCircuit.Enabled := False; + CloseCircuit(Circuit, False); + CheckCircuitExists(Circuit, True); + ResetFocus; + end + else + begin + if not Assigned(CursorStop) then + begin + CursorStop := TTimer.Create(Tcp); + CursorStop.OnTimer := CursorStopTimer; + CursorStop.Interval := 25; + end; + end; +end; + +procedure TTcp.btnShowNodesClick(Sender: TObject); +var + P: TPoint; +begin + P := btnShowNodes.ClientOrigin; + btnShowNodes.DropDownMenu.Popup(P.X, P.Y + btnShowNodes.Height); +end; + +procedure TTcp.btnSwitchTorClick(Sender: TObject); +begin + if ConnectState = 0 then + begin + if not Assigned(Controller) and not Assigned(Logger) and not Assigned(Consensus) and not Assigned(Descriptors) then + begin + if CurrentScanPurpose = spUserBridges then + ShowMsg(TransStr('400')) + else + StartTor; + end; + end + else + StopTor; + if paButtons.CanFocus then + paButtons.SetFocus; +end; + +procedure TTcp.miChangeCircuitClick(Sender: TObject); +begin + btnChangeCircuit.Click; +end; + +procedure TTcp.SetCircuitsUpdateInterval(Sender: TObject); +begin + if TMenuItem(Sender).Checked then + Exit; + TMenuItem(Sender).Checked := True; + tmCircuits.Interval := TMenuItem(Sender).Tag; + SetConfigInteger('Circuits', 'UpdateInterval', TMenuItem(Sender).Tag); +end; + +procedure TTcp.miCircuitsUpdateNowClick(Sender: TObject); +begin + ShowCircuits; +end; + +procedure TTcp.SetCircuitsFilter(Sender: TObject); +begin + ShowCircuits; + SetConfigInteger('Circuits', 'PurposeFilter', MenuToInt(miCircuitFilter)); +end; + +procedure TTcp.miEnableConvertNodesOnIncorrectClearClick(Sender: TObject); +begin + SetConfigBoolean('Routers', 'EnableConvertNodesOnIncorrectClear', miEnableConvertNodesOnIncorrectClear.Checked); +end; + +procedure TTcp.miEnableConvertNodesOnRemoveFromNodesListClick(Sender: TObject); +begin + SetConfigBoolean('Routers', 'EnableConvertNodesOnRemoveFromNodesList', miEnableConvertNodesOnRemoveFromNodesList.Checked); +end; + +procedure TTcp.miEnableConvertNodesOnAddToNodesListClick(Sender: TObject); +begin + SetConfigBoolean('Routers', 'EnableConvertNodesOnAddToNodesList', miEnableConvertNodesOnAddToNodesList.Checked); +end; + +procedure TTcp.miExitClick(Sender: TObject); +begin + Closing := True; + Tcp.Close; +end; + +procedure TTcp.miFilterHideUnusedClick(Sender: TObject); +begin + ShowFilter; + SetConfigBoolean('Filter', 'FilterHideUnused', miFilterHideUnused.Checked); +end; + +procedure TTcp.miFilterScrollTopClick(Sender: TObject); +begin + SetConfigBoolean('Filter', 'FilterScrollTop', miFilterScrollTop.Checked); +end; + +procedure TTcp.CheckSelectRowOptions(aSg: TStringGrid; Checked: Boolean; Save: Boolean = False); +begin + if Checked then + aSg.Options := aSg.Options + [goRowSelect] + else + begin + aSg.Options := aSg.Options - [goRowSelect]; + if aSg.SelRow > 0 then + begin + aSg.Row := aSg.SelRow; + aSg.Col := aSg.SelCol; + end; + end; + if Save then + begin + case aSg.Tag of + GRID_FILTER: SetConfigBoolean(Copy(aSg.Name, 3), 'FilterSelectRow', Checked); + GRID_ROUTERS: SetConfigBoolean(Copy(aSg.Name, 3), 'RoutersSelectRow', Checked); + end; + end; +end; + +procedure TTcp.miFilterSelectRowClick(Sender: TObject); +begin + CheckSelectRowOptions(sgFilter, miFilterSelectRow.Checked, True); +end; + +procedure TTcp.miGetBridgesEmailClick(Sender: TObject); +var + Param: AnsiString; +begin + if miRequestIPv6Bridges.Checked then + Param := 'get ipv6' + else + begin + if miRequestObfuscatedBridges.Checked then + Param := 'get transport obfs4' + else + Param := 'get vanilla'; + end; + ShellOpen('mailto:' + GetDefaultsValue('BridgesEmail', BRIDGES_EMAIL) + '?Body=' + string(EncodeURL(Param))); +end; + +procedure TTcp.miRequestIPv6BridgesClick(Sender: TObject); +begin + SetConfigBoolean('Network', 'RequestIPv6Bridges', miRequestIPv6Bridges.Checked); +end; + +procedure TTcp.miRequestObfuscatedBridgesClick(Sender: TObject); +begin + SetConfigBoolean('Network', 'RequestObfuscatedBridges', miRequestObfuscatedBridges.Checked); +end; + +function TTCP.CheckCacheOpConfirmation(OpStr: string): Boolean; +begin + Result := ShowMsg(Format(TransStr('405'),[OpStr]), '', mtQuestion, True); +end; + +procedure TTcp.miResetScannerScheduleClick(Sender: TObject); +var + ini: TMemIniFile; +begin + if not CheckCacheOpConfirmation(TMenuItem(Sender).Caption) then + Exit; + LastFullScanDate := 0; + LastNonResponsedScanDate := 0; + LastPartialScansCounts := udPartialScansCounts.Position; + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + ini.WriteInt64('Scanner', 'LastFullScanDate', LastFullScanDate); + ini.WriteInt64('Scanner', 'LastNonResponsedScanDate', LastNonResponsedScanDate); + ini.WriteInteger('Scanner', 'LastPartialScansCounts', LastPartialScansCounts); + finally + ini.UpdateFile; + ini.Free; + end; +end; + +procedure TTcp.miResetTotalsCounterClick(Sender: TObject); +var + ini: TMemIniFile; +begin + if not CheckCacheOpConfirmation(TMenuItem(Sender).Caption) then + Exit; + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + TotalDL := 0; + TotalUL := 0; + TotalStartDate := DateTimeToUnix(Now); + ini.WriteInt64('Status', 'TotalDL', TotalDL); + ini.WriteInt64('Status', 'TotalUL', TotalUL); + ini.WriteInt64('Status', 'TotalStartDate', TotalStartDate); + lbTotalDL.Caption := BytesFormat(TotalDL); + lbTotalUL.Caption := BytesFormat(TotalUL); + gbTotal.Hint := Format(TransStr('402'), [DateTimeToStr(UnixToDateTime(TotalStartDate))]); + finally + ini.UpdateFile; + ini.Free; + end; +end; + +procedure TTcp.miGetBridgesSiteClick(Sender: TObject); +var + Transport, IPv6: string; +begin + if miRequestObfuscatedBridges.Checked then + Transport := 'transport=obfs4' + else + Transport := 'transport=0'; + if miRequestIPv6Bridges.Checked then + IPv6 := '&ipv6=yes' + else + IPv6 := ''; + ShellOpen(GetDefaultsValue('BridgesSite', BRIDGES_SITE) + '?' + Transport + IPv6); +end; + +procedure TTcp.miGetBridgesTelegramClick(Sender: TObject); +var + Url: string; +begin + if RegistryFileExists(HKEY_CLASSES_ROOT, 'tg\shell\open\command', '') and not miPreferWebTelegram.Checked then + Url := 'tg://resolve?domain=' + else + Url := 'https://t.me/'; + ShellOpen(Url + GetDefaultsValue('BridgesBot', BRIDGES_BOT)); +end; + +procedure TTcp.FindInFilter(IpAddr: string); +var + Index: Integer; + GeoIpInfo: TGeoIpInfo; +begin + if ValidAddress(IpAddr) <> 0 then + begin + sbShowOptions.Click; + pcOptions.TabIndex := tsFilter.TabIndex; + if GeoIpDic.TryGetValue(IpAddr, GeoIpInfo) then + Index := sgFilter.Cols[FILTER_ID].IndexOf(CountryCodes[GeoIpInfo.cc]) + else + Index := sgFilter.Cols[FILTER_ID].IndexOf('??'); + SetGridLastCell(sgFilter, True, False, False, Index, FILTER_NAME); + end; +end; + +procedure TTcp.FindInRouters(RouterID: string); +var + Index: Integer; + Router: TRouterInfo; + Sum, Temp: Integer; +begin + if ValidHash(RouterID) then + begin + if RoutersDic.TryGetValue(RouterID, Router) then + begin + LoadRoutersFilterData(LastRoutersFilter, False, True); + + if miRtFiltersType.Checked then + begin + Sum := 0; + if rfExit in Router.Flags then Inc(Sum, 1); + if rfGuard in Router.Flags then Inc(Sum, 2); + if rfAuthority in Router.Flags then Inc(Sum, 4); + if rfBridge in Router.Flags then Inc(Sum, 16); + if Sum = 0 then Inc(Sum, 8); + if rfFast in Router.Flags then Inc(Sum, 32); + if rfStable in Router.Flags then Inc(Sum, 64); + if rfV2Dir in Router.Flags then Inc(Sum, 128); + if rfHSDir in Router.Flags then Inc(Sum, 256); + if VersionsDic.ContainsKey(Router.Version) then Inc(Sum, 512); + if Router.DirPort > 0 then Inc(Sum, 1024); + if (Router.Params and ROUTER_ALIVE <> 0) then Inc(Sum, 2048); + + IntToMenu(mnShowNodes.Items, Sum); + end; + + if miRtFiltersCountry.Checked then + begin + if cbxRoutersCountry.Tag <> -1 then + begin + Temp := GetCountryValue(Router.IPv4); + if cbxRoutersCountry.Tag = -2 then + if FilterDic.Items[CountryCodes[Temp]].Data <> [] then + Temp := -2; + if cbxRoutersCountry.Tag <> Temp then + begin + cbxRoutersCountry.ItemIndex := 0; + cbxRoutersCountry.Tag := -1; + end; + end; + end; + + if miRtFiltersWeight.Checked then + begin + if Router.Bandwidth < udRoutersWeight.Position * 1024 then + begin + Temp := Floor(Router.Bandwidth/1024); + if Temp < 5 then + Temp := 0 + else + Temp := Temp - (Temp mod 5); + udRoutersWeight.Position := Temp; + end; + end; + + if miRtFiltersQuery.Checked then + begin + if Trim(edRoutersQuery.Text) <> '' then + edRoutersQuery.Text := ''; + end; + + CheckShowRouters; + ShowRouters; + Index := sgRouters.Cols[FILTER_ID].IndexOf(RouterID); + if Index < 0 then + Index := 1; + SetGridLastCell(sgRouters, True, False, False, Index, ROUTER_IP); + sbShowRouters.Click; + SaveRoutersFilterdata; + end; + end; +end; + +procedure TTcp.HsMaxStreamsEnable(State: Boolean); +begin + edHsMaxStreams.Enabled := State; + udHsMaxStreams.Enabled := State; + if not State then + udHsMaxStreams.Position := 32; + lbHsMaxStreams.Enabled := State; +end; + +procedure TTcp.TransportsEnable(State: Boolean); +begin + edTransports.Enabled := State; + edTransportsHandler.Enabled := State; + cbxTRansportType.Enabled := State; + meHandlerParams.Enabled := State; + lbTransports.Enabled := State; + lbTransportsHandler.Enabled := State; + lbTransportType.Enabled := State; + lbHandlerParams.Enabled := State; +end; + +procedure TTcp.HsPortsEnable(State: Boolean); +begin + edHsRealPort.Enabled := State; + edHsVirtualPort.Enabled := State; + udHsRealPort.Enabled := State; + udHsVirtualPort.Enabled := State; + cbxHsAddress.Enabled := State; + lbHsSocket.Enabled := State; + lbHsVirtualPort.Enabled := State; +end; + +procedure TTcp.HsControlsEnable(State: Boolean); +begin + sgHsPorts.Enabled := State; + edHsName.Enabled := State; + edHsNumIntroductionPoints.Enabled := State; + edRendPostPeriod.Enabled := State; + udHsNumIntroductionPoints.Enabled := State; + udRendPostPeriod.Enabled := State; + cbxHsVersion.Enabled := State; + cbxHsState.Enabled := State; + cbHsMaxStreams.Enabled := State; + HsMaxStreamsEnable(State); + HsPortsEnable(State); + lbHsName.Enabled := State; + lbHsVersion.Enabled := State; + lbHsNumIntroductionPoints.Enabled := State; + lbRendPostPeriod.Enabled := State; + lbMinutes.Enabled := State; + lbHsState.Enabled := State; +end; + +procedure TTcp.miHideCircuitsWithoutStreamsClick(Sender: TObject); +begin + ShowCircuits; + SetConfigBoolean('Circuits', 'HideCircuitsWithoutStreams', miHideCircuitsWithoutStreams.Checked); +end; + +procedure TTcp.miHsClearClick(Sender: TObject); +var + i: Integer; +begin + if tsHs.Tag = 1 then + begin + if ShowMsg(Format(TransStr('263'), ['', TransStr('267')]), '', mtQuestion, True) then + begin + for i := 1 to sgHs.RowCount - 1 do + begin + if sgHs.Cells[HS_PREVIOUS_NAME, i] <> '' then + begin + SetLength(HsToDelete, Length(HsToDelete) + 1); + HsToDelete[Length(HsToDelete) - 1] := sgHs.Cells[HS_PREVIOUS_NAME, i]; + end; + end; + ClearGrid(sgHs); + UpdateHs; + EnableOptionButtons; + end; + end; + + if tsHs.Tag = 2 then + begin + ClearGrid(sgHsPorts); + UpdateHsPorts; + EnableOptionButtons; + end; +end; + +procedure TTcp.miHsCopyOnionClick(Sender: TObject); +begin + Clipboard.AsText := miHsCopyOnion.Caption; +end; + +procedure TTcp.miHsDeleteClick(Sender: TObject); +begin + mnHs.Tag := 1; + + if tsHs.Tag = 1 then + begin + if ShowMsg(Format(TransStr('263'), [TransStr('367') + ' ', sgHs.Cells[HS_NAME, sgHs.SelRow]]), '', mtQuestion, True) then + begin + if sgHs.Cells[HS_PREVIOUS_NAME, sgHs.SelRow] <> '' then + begin + SetLength(HsToDelete, Length(HsToDelete) + 1); + HsToDelete[Length(HsToDelete) - 1] := sgHs.Cells[HS_PREVIOUS_NAME, sgHs.SelRow]; + end; + DeleteARow(sgHs, sgHs.SelRow); + UpdateHs; + EnableOptionButtons; + end; + end; + + if tsHs.Tag = 2 then + begin + DeleteARow(sgHsPorts, sgHsPorts.SelRow); + UpdateHsPorts; + EnableOptionButtons; + end; + + mnHs.Tag := 0; +end; + +procedure TTcp.miHsInsertClick(Sender: TObject); +begin + mnHs.Tag := 1; + + if tsHs.Tag = 1 then + begin + if IsEmptyGrid(sgHs) then + HsControlsEnable(True) + else + begin + sgHs.RowCount := sgHs.RowCount + 1; + sgHs.Row := sgHs.RowCount - 1; + end; + sgHs.Cells[HS_NAME, sgHs.SelRow] := ''; + sgHs.Cells[HS_VERSION, sgHs.SelRow] := '3'; + sgHs.Cells[HS_INTRO_POINTS, sgHs.SelRow] := '3'; + sgHs.Cells[HS_MAX_STREAMS, sgHs.SelRow] := NONE_CHAR; + sgHs.Cells[HS_STATE, sgHs.SelRow] := SELECT_CHAR; + sgHs.Cells[HS_PORTS_DATA, sgHs.SelRow] := '127.0.0.1,80,80'; + ClearGrid(sgHsPorts); + SelectHs; + if edHsName.CanFocus then + edHsName.SetFocus; + end; + + if tsHs.Tag = 2 then + begin + if IsEmptyGrid(sgHsPorts) then + HsControlsEnable(True) + else + begin + sgHsPorts.RowCount := sgHsPorts.RowCount + 1; + sgHsPorts.Row := sgHsPorts.RowCount - 1; + end; + sgHsPorts.Cells[HSP_INTERFACE, sgHsPorts.SelRow] := '127.0.0.1'; + sgHsPorts.Cells[HSP_REAL_PORT, sgHsPorts.SelRow] := '80'; + sgHsPorts.Cells[HSP_VIRTUAL_PORT, sgHsPorts.SelRow] := '80'; + UpdateHsPorts; + SelectHsPorts; + end; + mnHs.Tag := 0; + EnableOptionButtons; +end; + +procedure TTcp.meTrackHostExitsChange(Sender: TObject); +begin + lbTotalHosts.Caption := TransStr('203') + ': ' + IntToStr(meTrackHostExits.Lines.Count); + EnableOptionButtons; +end; + +procedure TTcp.InsertNodesMenu(ParentMenu: TMenuItem; NodeID: string; AutoSave: Boolean = True); +var + SubMenu: TMenuItem; + i: Integer; +begin + ParentMenu.Clear; + if ConnectState = 1 then + Exit; + for i := ENTRY_ID to EXCLUDE_ID do + begin + SubMenu := TMenuItem.Create(self); + SubMenu.Tag := i; + case i of + ENTRY_ID: + begin + SubMenu.Caption := TransStr('288'); SubMenu.ImageIndex := 40; + end; + MIDDLE_ID: + begin + SubMenu.Caption := TransStr('289'); SubMenu.ImageIndex := 41; + end; + EXIT_ID: + begin + SubMenu.Caption := TransStr('290'); SubMenu.ImageIndex := 42; + end; + EXCLUDE_ID: + begin + SubMenu.Caption := TransStr('287'); SubMenu.ImageIndex := 43; + end; + end; + InsertNodesListMenu(SubMenu, NodeID, i, AutoSave); + ParentMenu.Add(SubMenu); + end; + + for i := 1 to 4 do + begin + SubMenu := TMenuItem.Create(self); + SubMenu.Tag := i; + case i of + 1,3: SubMenu.Caption := '-'; + 2: + begin + SubMenu.Caption := TransStr('359'); + SubMenu.ImageIndex := 17; + InsertNodesToDeleteMenu(SubMenu, NodeID, AutoSave); + end; + 4: + begin + SubMenu.Caption := TransStr('360'); + SubMenu.ImageIndex := 50; + SubMenu.OnClick := RoutersAutoSelectClick; + Submenu.Enabled := (RoutersDic.Count > 0) and (InfoStage = 0) and not (Assigned(Consensus) or Assigned(Descriptors) or tmScanner.Enabled); + Submenu.Visible := not AutoSave; + end; + end; + ParentMenu.Add(SubMenu); + end; +end; + +procedure TTcp.InsertNodesToDeleteMenu(ParentMenu: TmenuItem; NodeID: string; AutoSave: Boolean = True); +var + Router: TRouterInfo; + ls: TStringList; + i: Integer; + ItemID: TListType; + RangesStr, NodeStr, DeleteList, CountryCode: string; + ParseStr: ArrOfStr; + SubMenu: TMenuItem; +begin + if RoutersDic.TryGetValue(NodeID, Router) then + begin + CountryCode := CountryCodes[GetCountryValue(Router.IPv4)]; + ls := TStringList.Create; + try + ls.Add(NodeID); + ls.Add(Router.IPv4); + RangesStr := FindInRanges(Router.IPv4); + if RangesStr <> '' then + begin + ParseStr := Explode(',', RangesStr); + for i := 0 to Length(ParseStr) - 1 do + ls.Add(ParseStr[i]); + end; + SortNodesList(ls, True); + ls.Add(AnsiUpperCase(CountryCode) + ' (' + TransStr(CountryCode) + ')'); + + DeleteList := ''; + for i := 0 to ls.Count - 1 do + begin + NodeStr := SeparateLeft(ls[i], ' '); + ItemID := GetNodeType(NodeStr); + if ItemID = ltCode then + NodeStr := AnsiLowerCase(NodeStr); + + if NodesDic.ContainsKey(NodeStr) then + begin + if NodesDic.Items[NodeStr] <> [] then + begin + SubMenu := TMenuItem.Create(self); + SubMenu.Tag := Integer(AutoSave); + case ItemID of + ltHash: SubMenu.ImageIndex := 23; + ltIp: SubMenu.ImageIndex := 33; + ltCidr: SubMenu.ImageIndex := 48; + ltCode: SubMenu.ImageIndex := 57; + end; + SubMenu.Caption := ls[i]; + SubMenu.Hint := ''; + SubMenu.OnClick := RemoveFromNodeListClick; + ParentMenu.Add(SubMenu); + DeleteList := DeleteList + ',' + ls[i]; + end; + end; + end; + Delete(DeleteList, 1, 1); + if ParentMenu.Count > 1 then + begin + ls.Clear; + ls.Add('-'); + ls.Add(TransStr('406')); + for i := 0 to ls.Count - 1 do + begin + SubMenu := TMenuItem.Create(self); + SubMenu.Tag := Integer(AutoSave); + SubMenu.Caption := ls[i]; + if SubMenu.Caption <> '-' then + begin + SubMenu.ImageIndex := 17; + SubMenu.Hint := DeleteList; + SubMenu.OnClick := RemoveFromNodeListClick; + end; + ParentMenu.Add(SubMenu); + end; + end; + ParentMenu.Visible := ParentMenu.Count > 0; + finally + ls.Free; + end; + end; +end; + +procedure TTcp.InsertNodesListMenu(ParentMenu: TmenuItem; NodeID: string; NodeTypeID: Integer; AutoSave: Boolean = True); +var + SubMenu: TMenuItem; + ls, lr: TStringList; + i: Integer; + CountryID: Byte; + Router: TRouterInfo; + RangesStr: string; + ParseStr: ArrOfStr; + ItemID: TListType; + NodeStr: string; + + function IpToMask(IpStr: string; Mask: Byte): string; + var + i, n: Byte; + ParseStr: ArrOfStr; + begin + ParseStr := Explode('.', IpStr); + n := 32; + for i := Length(ParseStr) - 1 downto 0 do + begin + dec(n, 8); + if n >= Mask then + ParseStr[i] := '0'; + end; + Result := Format('%s.%s.%s.%s/%d', [ParseStr[0], ParseStr[1], ParseStr[2], ParseStr[3], Mask]); + end; + +begin + ls := TStringList.Create; + try + ls.Add(NodeID); + if RoutersDic.TryGetValue(NodeID, Router) then + begin + CountryID := GetCountryValue(Router.IPv4); + ls.Add(Router.IPv4); + ls.Add('-'); + ls.Add(IpToMask(Router.IPv4, 24)); + ls.Add(IpToMask(Router.IPv4, 16)); + ls.Add(IpToMask(Router.IPv4, 8)); + RangesStr := FindInRanges(Router.IPv4); + if RangesStr <> '' then + begin + lr := TStringList.Create; + try + ls.Add('-'); + ParseStr := Explode(',', RangesStr); + for i := 0 to Length(ParseStr) - 1 do + if ls.IndexOf(ParseStr[i]) < 0 then + lr.Add(ParseStr[i]); + SortNodesList(lr, True); + ls.AddStrings(lr); + finally + lr.Free; + end; + end; + ls.Add('-'); + ls.Add(AnsiUpperCase(CountryCodes[CountryID]) + ' (' + TransStr(CountryCodes[CountryID]) + ')'); + end; + + for i := 0 to ls.Count - 1 do + begin + NodeStr := SeparateLeft(ls[i], ' '); + ItemID := GetNodeType(NodeStr); + if ItemID = ltCode then + NodeStr := AnsiLowerCase(NodeStr); + + SubMenu := TMenuItem.Create(self); + SubMenu.Hint := BoolToStr(AutoSave); + SubMenu.Tag := NodeTypeID; + SubMenu.Caption := ls[i]; + + if NodesDic.ContainsKey(NodeStr) then + begin + if TNodeType(NodeTypeID) in NodesDic.Items[NodeStr] then + SubMenu.Enabled := False; + end; + + if SubMenu.Enabled and (ItemID in [ltHash]) then + begin + if not CheckRouterFlags(NodeTypeID, Router) and (NodeTypeID <> EXCLUDE_ID) then + SubMenu.Visible := False; + end; + + if ItemID <> ltNoCheck then + begin + case ItemID of + ltHash: SubMenu.ImageIndex := 23; + ltIp: SubMenu.ImageIndex := 33; + ltCidr: SubMenu.ImageIndex := 48; + ltCode: SubMenu.ImageIndex := 57; + end; + if SubMenu.Enabled then + SubMenu.OnClick := Tcp.AddToNodesListClick; + end; + ParentMenu.Add(SubMenu); + end; + finally + ls.Free; + end; +end; + +procedure TTcp.CheckNodesListState(NodeTypeID: Integer); +var + lbComponent: TLabel; +begin + lbComponent := GetFavoritesLabel(NodeTypeID); + if Assigned(lbComponent) then + begin + if lbComponent.Tag = 0 then + lbComponent.HelpContext := 1; + end; + if NodeTypeID <> EXCLUDE_ID then + begin + if (lbFavoritesTotal.Tag = 0) and (cbxFilterMode.ItemIndex <> 2) then + cbxFilterMode.ItemIndex := 2; + end; +end; + +function TTCP.CheckRouterFlags(NodeTypeID: Integer; RouterInfo: TRouterInfo): Boolean; +begin + Result := False; + if (rfBridge in RouterInfo.Flags) and not (rfRelay in RouterInfo.Flags) then + Exit; + if (NodeTypeID = ENTRY_ID) and not (rfGuard in RouterInfo.Flags) then + Exit; + if (NodeTypeID = EXIT_ID) and not (rfExit in RouterInfo.Flags) then + Exit; + Result := True; +end; + +procedure TTcp.CheckPrefferedBridgeExclude(RouterID: string); +var + RouterInfo: TRouterInfo; +begin + if cbUsePreferredBridge.Checked then + begin + if RoutersDic.TryGetValue(RouterID, RouterInfo) then + begin + if RouterInNodesList(RouterID, RouterInfo, ntExclude) then + begin + cbUseBridges.Checked := False; + cbUsePreferredBridge.Checked := False; + edPreferredBridge.Text := ''; + BridgesCheckControls; + end; + end; + end; +end; + +procedure TTCP.AddToNodesListClick(Sender: TObject); +var + NodeStr, NodeCap, ConvertMsg: string; + ConvertNodes, CtrlPressed, EnableConvertNodes: Boolean; + NodeTypeID: Integer; + FNodeTypes: TNodeTypes; + FilterInfo: TFilterInfo; + ItemID: TListType; + Router: TPair; + Range: TIPv4Range; + PreferredBridge: TBridge; + + procedure AddRouterToNodesList(RouterID: string; RouterInfo: TRouterInfo); + begin + if NodeTypeID <> EXCLUDE_ID then + begin + if miAvoidAddingIncorrectNodes.Checked then + begin + if not CheckRouterFlags(NodeTypeID, RouterInfo) then + Exit; + if RouterInNodesList(RouterID, RouterInfo, ntExclude) then + Exit; + end; + end; + NodesDic.TryGetValue(RouterID, FNodeTypes); + if (ntExclude in FNodeTypes) or (NodeTypeID = EXCLUDE_ID) then + FNodeTypes := []; + Include(FNodeTypes, TNodeType(NodeTypeID)); + NodesDic.AddOrSetValue(RouterID, FNodeTypes); + end; + +begin + ConvertMsg := ''; + CtrlPressed := CtrlKeyPressed(#0); + NodeCap := TMenuItem(Sender).Caption; + NodeStr := SeparateLeft(NodeCap, ' '); + NodeTypeID := TMenuItem(Sender).Tag; + ItemID := GetNodeType(NodeStr); + case ItemID of + ltCode: NodeStr := AnsiLowerCase(NodeStr); + ltCidr: Range := CidrToRange(NodeStr); + end; + ConvertNodes := miEnableConvertNodesOnAddToNodesList.Checked and + (((ItemID = ltIp) and miConvertIpNodes.Checked) or + ((ItemID = ltCidr) and miConvertCidrNodes.Checked) or + ((ItemID = ltCode) and miConvertCountryNodes.Checked)) and + (((NodeTypeID = EXCLUDE_ID) and not miIgnoreConvertExcludeNodes.Checked) or + (NodeTypeID <> EXCLUDE_ID)); + + EnableConvertNodes := (ConvertNodes and not CtrlPressed) or (not ConvertNodes and CtrlPressed); + if EnableConvertNodes then + ConvertMsg := BR + BR + TransStr('146'); + + if ShowMsg(Format(TransStr('268'), [NodeCap, TMenuItem(Sender).Parent.Caption, ConvertMsg]), '', mtQuestion, True) then + begin + if EnableConvertNodes then + begin + for Router in RoutersDic do + begin + case ItemID of + ltIp: + begin + if Router.Value.IPv4 = NodeStr then + AddRouterToNodesList(Router.Key, Router.Value); + end; + ltCidr: + begin + if InRange(IpToInt(Router.Value.IPv4), Range.IpStart, Range.IpEnd) then + AddRouterToNodesList(Router.Key, Router.Value); + end; + ltCode: + begin + if CountryCodes[GetCountryValue(Router.Value.IPv4)] = NodeStr then + AddRouterToNodesList(Router.Key, Router.Value); + end; + end; + end; + end + else + begin + NodesDic.TryGetValue(NodeStr, FNodeTypes); + if (ntExclude in FNodeTypes) or (NodeTypeID = EXCLUDE_ID) then + FNodeTypes := []; + Include(FNodeTypes, TNodeType(NodeTypeID)); + NodesDic.AddOrSetValue(NodeStr, FNodeTypes); + + if NodeTypeID = EXCLUDE_ID then + begin + if FilterDic.TryGetValue(NodeStr, FilterInfo) then + begin + FilterInfo.Data := []; + FilterDic.AddOrSetValue(NodeStr, FilterInfo); + end; + end; + + if ItemID = ltCidr then + RangesDic.AddOrSetValue(NodeStr, CidrToRange(NodeStr)); + end; + if TryParseBridge(edPreferredBridge.Text, PreferredBridge) then + CheckPrefferedBridgeExclude(PreferredBridge.Hash); + CheckNodesListState(NodeTypeID); + CalculateTotalNodes; + ShowRouters; + RoutersUpdated := True; + FilterUpdated := True; + UpdateOptionsAfterRoutersUpdate; + + if StrToBool(TMenuItem(Sender).Hint) then + ApplyOptions + else + EnableOptionButtons; + end; +end; + +procedure TTcp.RemoveFromNodeListClick(Sender: TObject); +var + ConvertNodes: Boolean; + NodesList, NodeStr, ConvertMsg: string; + ParseStr: ArrOfStr; + ItemID: TListType; + i: Integer; + Nodes: ArrOfNodes; + +begin + if TMenuItem(Sender).Hint = '' then + NodesList := TMenuItem(Sender).Caption + else + NodesList := TMenuItem(Sender).Hint; + + ConvertNodes := PrepareNodesToRemove(NodesList, ntNone, Nodes);; + if ConvertNodes then + ConvertMsg := BR + BR + TransStr('146') + else + ConvertMsg := ''; + + if ShowMsg(Format(TransStr('361'), [StringReplace(NodesList, ',', BR, [rfReplaceAll]), ConvertMsg]), '', mtQuestion, True) then + begin + ParseStr := Explode(',', NodesList); + for i := 0 to Length(ParseStr) - 1 do + begin + NodeStr := SeparateLeft(ParseStr[i], ' '); + ItemID := GetNodeType(NodeStr); + if ItemID = ltCode then + NodeStr := AnsiLowerCase(NodeStr); + + NodesDic.Remove(NodeStr); + if ItemID = ltCidr then + RangesDic.Remove(NodeStr); + end; + if ConvertNodes then + RemoveFromNodesListWithConvert(Nodes, ntNone); + + CalculateTotalNodes; + ShowRouters; + RoutersUpdated := True; + FilterUpdated := True; + UpdateOptionsAfterRoutersUpdate; + + if Boolean(TMenuItem(Sender).Tag) then + ApplyOptions + else + EnableOptionButtons; + end; +end; + +function TTcp.PrepareNodesToRemove(Data: string; NodeType: TNodeType; out Nodes: ArrOfNodes): Boolean; +var + ParseStr: ArrOfStr; + i, j: Integer; + NodeStr: string; + NodeID: TListType; + CtrlPressed, ConvertNodes: Boolean; +begin + Result := False; + Nodes := nil; + CtrlPressed := CtrlKeyPressed(#0); + ParseStr := Explode(',', Data); + if Length(ParseStr) = 0 then + Exit; + j := 0; + for i := 0 to Length(ParseStr) - 1 do + begin + NodeStr := SeparateLeft(ParseStr[i], ' '); + NodeID := GetNodeType(NodeStr); + + ConvertNodes := miEnableConvertNodesOnRemoveFromNodesList.Checked and + (((NodeID = ltIp) and miConvertIpNodes.Checked) or + ((NodeID = ltCidr) and miConvertCidrNodes.Checked) or + ((NodeID = ltCode) and miConvertCountryNodes.Checked)); + + if (ConvertNodes and not CtrlPressed) or + (not ConvertNodes and CtrlPressed and (NodeID <> ltHash)) then + begin + SetLength(Nodes, j + 1); + case NodeID of + ltCode: NodeStr := AnsiLowerCase(NodeStr); + ltCidr: Nodes[j].RangeData := CidrToRange(NodeStr); + end; + Nodes[j].NodeStr := NodeStr; + Nodes[j].NodeID := NodeID; + Inc(j); + end; + end; + + Result := Assigned(Nodes); +end; + +procedure TTcp.RemoveFromNodesListWithConvert(Nodes: ArrOfNodes; NodeType: TNodeType); +var + NodesCount, i: Integer; + Router: TPair; + + procedure RemoveRouterFromNodesList(RouterID: string); + var + FNodeTypes: TNodeTypes; + begin + if NodeType = ntNone then + NodesDic.Remove(RouterID) + else + begin + if NodesDic.TryGetValue(RouterID, FNodeTypes) then + begin + Exclude(FNodeTypes, NodeType); + NodesDic.AddOrSetValue(RouterID, FNodeTypes); + end; + end; + end; + +begin + NodesCount := Length(Nodes); + if NodesCount = 0 then + Exit; + for Router in RoutersDic do + begin + for i := 0 to NodesCount - 1 do + begin + case Nodes[i].NodeID of + ltIp: + begin + if Router.Value.IPv4 = Nodes[i].NodeStr then + RemoveRouterFromNodesList(Router.Key); + end; + ltCidr: + begin + if InRange(IpToInt(Router.Value.IPv4), Nodes[i].RangeData.IpStart, Nodes[i].RangeData.IpEnd) then + RemoveRouterFromNodesList(Router.Key); + end; + ltCode: + begin + if CountryCodes[GetCountryValue(Router.Value.IPv4)] = Nodes[i].NodeStr then + RemoveRouterFromNodesList(Router.Key); + end; + end; + end; + end; + +end; + +procedure TTcp.RoutersAutoSelectClick(Sender: TObject); +var + Router: Tpair; + ParseStr: ArrOfStr; + cdWeight, cdPing, CheckEntryPorts: Boolean; + GeoIpInfo: TGeoIpInfo; + Flags: TRouterFlags; + PriorityType, PingData, PingSum, PingCount, PingAvg, i: Integer; + NodeTypes: TNodeTypes; + FilterInfo: TFilterInfo; + CountryID: Byte; + EntryStr, MiddleStr, ExitStr, CountryCode, PortsData: string; + EntryNodes, MiddleNodes, ExitNodes: TStringList; + UniqueList: TDictionary; + SortCompare: TStringListSortCompare; + + function ListToStr(ls: TStringList; Max: Integer): string; + var + i, Count: Integer; + Search: Boolean; + RouterInfo: TRouterInfo; + GeoIpInfo: TGeoIpInfo; + begin + Result := ''; + Count := 0; + + for i := 0 to ls.Count - 1 do + begin + if PriorityType = PRIORITY_BALANCED then + begin + Search := False; + if RoutersDic.TryGetValue(ls[i], RouterInfo) then + begin + if GeoIpDic.TryGetValue(RouterInfo.IPv4, GeoIpInfo) then + Search := InRange(GeoIpInfo.ping, 1 , PingAvg); + end; + end + else + Search := True; + + if Count < Max then + begin + if Search then + begin + if cbAutoSelUniqueNodes.Checked then + begin + if UniqueList.ContainsKey(ls[i]) then + Continue + else + begin + UniqueList.AddOrSetValue(ls[i], 0); + Result := Result + ',' + ls[i]; + Inc(Count); + end; + end + else + begin + Result := Result + ',' + ls[i]; + Inc(Count); + end; + end; + + end + else + Break; + end; + Delete(Result, 1, 1); + end; + + procedure AddRouterToList(ls: TStringList; NodeType: TNodeType); + begin + if NodeType in NodeTypes then + begin + case PriorityType of + PRIORITY_BALANCED: + begin + ls.AddObject(Router.Key, TObject(Router.Value.Bandwidth)); + if not UniqueList.ContainsKey(Router.Key) then + begin + if (PingData <= udAutoSelMaxPing.Position) then + begin + UniqueList.AddOrSetValue(Router.Key, 0); + Inc(PingSum, PingData); + Inc(PingCount); + end; + end; + end; + PRIORITY_WEIGHT: ls.AddObject(Router.Key, TObject(Router.Value.Bandwidth)); + PRIORITY_PING: ls.AddObject(Router.Key, TObject(PingData)); + else + ls.AddObject(Router.Key, TObject(Random(MAXWORD))); + end; + end; + end; + +begin + if (RoutersDic.Count = 0) or (InfoStage > 0) or Assigned(Consensus) or Assigned(Descriptors) or tmScanner.Enabled then + Exit; + + EntryNodes := TStringList.Create; + MiddleNodes := TStringList.Create; + ExitNodes := TStringList.Create; + UniqueList := TDictionary.Create; + PriorityType := cbxAutoSelPriority.ItemIndex; + + PingCount := 0; + PingSum := 0; + PingAvg := 0; + + try + if cbUseReachableAddresses.Checked then + begin + PortsDic.Clear; + ParseStr := Explode(',', StringReplace(edReachableAddresses.Text, ' ', '', [rfReplaceAll])); + for i := 0 to Length(ParseStr) - 1 do + begin + if ValidInt(ParseStr[i], 1, 65535) then + PortsDic.AddOrSetValue(StrToInt(ParseStr[i]), 0); + end; + end; + CheckEntryPorts := PortsDic.Count > 0; + + for Router in RoutersDic do + begin + Flags := Router.Value.Flags; + CountryID := DEFAULT_COUNTRY_ID; + PingData := MAXWORD; + PortsData := ''; + NodeTypes := [ntEntry, ntMiddle, ntExit]; + + if PingNodesCount > 0 then + begin + if GeoIpDic.TryGetValue(Router.Value.IPv4, GeoIpInfo) then + begin + CountryID := GeoIpInfo.cc; + case GeoIpInfo.ping of + -1: PingData := MAXINT; + 0: PingData := MAXWORD; + else + PingData := GeoIpInfo.ping; + end; + PortsData := GeoIpInfo.ports; + end; + end; + + cdPing := (PingData <= udAutoSelMaxPing.Position) or ((PingData >= MAXWORD) and not cbAutoSelNodesWithPingOnly.Checked); + + CountryCode := CountryCodes[CountryID]; + + cdWeight := Router.Value.Bandwidth >= udAutoSelMinWeight.Position * 1024; + + if cdWeight and cdPing and (rfRelay in Flags) and not RouterInNodesList(Router.Key, Router.Value, ntExclude) then + begin + if cbAutoSelFilterCountriesOnly.Checked then + begin + if FilterDic.TryGetValue(CountryCode, FilterInfo) then + NodeTypes := FilterInfo.Data; + end; + + if (rfStable in Flags) or not cbAutoSelStableOnly.Checked then + begin + if (rfGuard in Flags) then + begin + if (Router.Value.Params and ROUTER_ALIVE <> 0) or (AliveNodesCount = 0) then + begin + if CheckEntryPorts then + begin + if PortsDic.ContainsKey(Router.Value.OrPort) then + AddRouterToList(EntryNodes, ntEntry); + end + else + AddRouterToList(EntryNodes, ntEntry); + end; + end; + + if (rfExit in Flags) and not (rfBadExit in Flags) then + AddRouterToList(ExitNodes, ntExit); + + if (not (rfHsDir in Flags) and (Router.Value.DirPort = 0)) or not cbAutoSelMiddleNodesWithoutDir.Checked then + AddRouterToList(MiddleNodes, ntMiddle); + end; + end; + end; + if PriorityType = PRIORITY_BALANCED then + begin + if PingCount > 0 then + PingAvg := Round(PingSum / PingCount); + end; + + case PriorityType of + PRIORITY_PING: SortCompare := CompIntObjectAsc + else + SortCompare := CompIntObjectDesc; + end; + + EntryNodes.CustomSort(SortCompare); + ExitNodes.CustomSort(SortCompare); + MiddleNodes.CustomSort(SortCompare); + + UniqueList.Clear; + EntryStr := ListToStr(EntryNodes, udAutoSelEntryCount.Position); + ExitStr := ListToStr(ExitNodes, udAutoSelExitCount.Position); + MiddleStr := ListToStr(MiddleNodes, udAutoSelMiddleCount.Position); + + ClearRouters(ntFavorites); + GetNodes(ExitStr, ntExit, True); + GetNodes(EntryStr, ntEntry, True); + GetNodes(MiddleStr, ntMiddle, True); + + CheckNodesListState(FAVORITES_ID); + CalculateTotalNodes; + ShowRouters; + RoutersUpdated := True; + EnableOptionButtons; + + finally + EntryNodes.Free; + MiddleNodes.Free; + ExitNodes.Free; + UniqueList.Free; + if PortsDic.Count > 0 then + PortsDic.Clear; + end; + +end; + +procedure TTcp.miAboutClick(Sender: TObject); +begin + if ShowMsg(Format(TransStr('356'), + [ + TransStr('105'), + GetFileVersionStr(Paramstr(0)), + 'Copyright © 2020, abysshint', + TransStr('357') + ]), TransStr('355'), mtInfo, True) then + begin + ShellOpen(GITHUB_URL); + end; +end; + +procedure TTcp.miDisableFiltersOnAuthorityOrBridgeClick(Sender: TObject); +begin + SetConfigBoolean('Routers', 'DisableFiltersOnAuthorityOrBridge', miDisableFiltersOnAuthorityOrBridge.Checked); +end; + +procedure TTcp.miDisableFiltersOnUserQueryClick(Sender: TObject); +begin + SetConfigBoolean('Routers', 'DisableFiltersOnUserQuery', miDisableFiltersOnUserQuery.Checked); +end; + +procedure TTcp.miDisableSelectionUnSuitableAsBridgeClick(Sender: TObject); +begin + SetConfigBoolean('Routers', 'DisableSelectionUnSuitableAsBridge', miDisableSelectionUnSuitableAsBridge.Checked); +end; + +procedure TTcp.miAlwaysShowExitCircuitClick(Sender: TObject); +begin + ShowCircuits; + SetConfigBoolean('Circuits', 'AlwaysShowExitCircuit', miAlwaysShowExitCircuit.Checked); +end; + +procedure TTcp.miAutoClearClick(Sender: TObject); +begin + SetConfigBoolean('Log', 'AutoClear', miAutoClear.Checked); +end; + +procedure TTcp.miAutoScrollClick(Sender: TObject); +begin + SetConfigBoolean('Log', 'AutoScroll', miAutoScroll.Checked); + CheckLogAutoScroll; +end; + +procedure TTcp.miAvoidAddingIncorrectNodesClick(Sender: TObject); +begin + SetConfigBoolean('Routers', 'AvoidAddingIncorrectNodes', miAvoidAddingIncorrectNodes.Checked); +end; + +procedure TTcp.miClearDNSCacheClick(Sender: TObject); +begin + if not CheckCacheOpConfirmation(TMenuItem(Sender).Caption) then + Exit; + SendCommand('SIGNAL CLEARDNSCACHE'); +end; + +procedure TTcp.ClearScannerCacheClick(Sender: TObject); +var + GeoIpItem: TPair; + GeoIpInfo: TGeoIpInfo; + ClearType: Byte; +begin + if not CheckCacheOpConfirmation(TMenuItem(Sender).Caption) then + Exit; + ClearType := TMenuItem(Sender).Tag; + for GeoIpItem in GeoIpDic do + begin + GeoIpInfo := GeoIpItem.Value; + case ClearType of + 1: GeoIpInfo.ping := 0; + 2: GeoIpInfo.ports := ''; + end; + GeoIpDic.AddOrSetValue(GeoIpItem.Key, GeoIpInfo); + end; + LoadConsensus; + if ConnectState = 0 then + SaveNetworkCache; +end; + +procedure TTcp.EditMenuClick(Sender: TObject); +begin + case TMenuItem(Sender).Tag of + 1: EditMenuHandle(emCut); + 2: EditMenuHandle(emCopy); + 3: EditMenuHandle(emPaste); + 4: EditMenuHandle(emSelectAll); + 5: EditMenuHandle(emClear); + 6: EditMenuHandle(emDelete); + 7: EditMenuHandle(emFind); + end; +end; + +procedure TTcp.FormClose(Sender: TObject; var Action: TCloseAction); +begin + Closing := True; +end; + +procedure TTcp.FormCloseQuery(Sender: TObject; var CanClose: Boolean); +begin + if (cbMinimizeOnClose.Checked) and not Closing then + begin + CanClose := False; + Hide; + end; +end; + +procedure TTcp.LoadStaticArray(Data: array of TStaticPair); +var + i: Integer; +begin + for i := 0 to Length(Data) - 1 do + ConstDic.AddOrSetValue(Data[i].Key, Data[i].Value); +end; + +procedure TTcp.UpdateScaleFactor; +var + Factor: Integer; +begin + Scale := 1.0; + if Screen.PixelsPerInch <> Screen.DefaultPixelsPerInch then + Scale := Screen.PixelsPerInch / Screen.DefaultPixelsPerInch + else + begin + if (Win32MajorVersion = 6) and (Win32MinorVersion = 3) then + begin + Factor := StrToIntDef(RegistryGetValue(HKEY_CURRENT_USER, 'Control Panel\Desktop', 'DesktopDPIOverride'), 0); + if Factor <> 0 then + begin + case Factor of + 1: Scale := 1.25; + 2: Scale := 1.50; + 3: Scale := 2.0; + end; + end; + end; + end; + + sgHs.ColWidths[HS_VERSION] := Round(50 * Scale); + sgHs.ColWidths[HS_INTRO_POINTS] := Round(80 * Scale); + sgHs.ColWidths[HS_MAX_STREAMS] := Round(90 * Scale); + sgHs.ColWidths[HS_STATE] := Round(24 * Scale); + sgHs.ColWidths[HS_PORTS_DATA] := -1; + sgHs.ColWidths[HS_PREVIOUS_NAME] := -1; + sgHsPorts.ColWidths[HSP_REAL_PORT] := Round(40 * Scale); + sgHsPorts.ColWidths[HSP_VIRTUAL_PORT] := Round(87 * Scale); + sgFilter.ColWidths[FILTER_ID] := Round(35 * Scale); + sgFilter.ColWidths[FILTER_FLAG] := Round(23 * Scale); + sgFilter.ColWidths[FILTER_TOTAL] := Round(55 * Scale); + sgFilter.ColWidths[FILTER_GUARD] := Round(55 * Scale); + sgFilter.ColWidths[FILTER_EXIT] := Round(55 * Scale); + sgFilter.ColWidths[FILTER_ALIVE] := Round(55 * Scale); + sgFilter.ColWidths[FILTER_PING] := Round(55 * Scale); + sgFilter.ColWidths[FILTER_ENTRY_NODES] := Round(23 * Scale); + sgFilter.ColWidths[FILTER_MIDDLE_NODES] := Round(23 * Scale); + sgFilter.ColWidths[FILTER_EXIT_NODES] := Round(23 * Scale); + sgFilter.ColWidths[FILTER_EXCLUDE_NODES] := Round(23 * Scale); + sgRouters.ColWidths[ROUTER_ID] := -1; + sgRouters.ColWidths[ROUTER_FLAG] := Round(23 * Scale); + sgRouters.ColWidths[ROUTER_WEIGHT] := Round(63 * Scale); + sgRouters.ColWidths[ROUTER_PORT] := Round(43 * Scale); + sgRouters.ColWidths[ROUTER_VERSION] := Round(60 * Scale); + sgRouters.ColWidths[ROUTER_FLAGS] := Round(96 * Scale); + sgRouters.ColWidths[ROUTER_ENTRY_NODES] := Round(23 * Scale); + sgRouters.ColWidths[ROUTER_MIDDLE_NODES] := Round(23 * Scale); + sgRouters.ColWidths[ROUTER_EXIT_NODES] := Round(23 * Scale); + sgRouters.ColWidths[ROUTER_EXCLUDE_NODES] := Round(23 * Scale); + sgCircuits.ColWidths[CIRC_ID] := -1; + sgCircuits.ColWidths[CIRC_STREAMS] := Round(30 * Scale); + sgCircuits.ColWidths[CIRC_BYTES_READ] := 0; + sgCircuits.ColWidths[CIRC_BYTES_WRITTEN] := 0; + sgCircuitInfo.ColWidths[CIRC_INFO_ID] := -1; + sgCircuitInfo.ColWidths[CIRC_INFO_FLAG] := Round(23 * Scale); + sgCircuitInfo.ColWidths[CIRC_INFO_WEIGHT] := Round(72 * Scale); + sgStreams.ColWidths[STREAMS_ID] := -1; + sgStreams.ColWidths[STREAMS_TRACK] := Round(24 * Scale); + sgStreams.ColWidths[STREAMS_COUNT] := Round(30 * Scale); + sgStreamsInfo.ColWidths[STREAMS_INFO_ID] := -1; + sgTransports.ColWidths[PT_HANDLER] := Round(120 * Scale); + sgTransports.ColWidths[PT_TYPE] := Round(35 * Scale); + sgTransports.ColWidths[PT_PARAMS] := -1; + CheckScannerControls; + CheckStreamsControls; +end; + +procedure TTcp.FormCreate(Sender: TObject); +var + i: Integer; + Filter: TFilterInfo; +begin + FirstLoad := True; + FormSize := 1; + + udNumCPUs.Max := GetCPUCount; + udMaxMemInQueues.Max := GetAvailPhysMemory; + LoadIconsFromResource(lsFlags, 'ICON_FLAGS'); + if not StyleServices.Enabled then + begin + paStatus.Color := clBtnFace; + paCircuits.Color := clBtnFace; + paRouters.Color := clBtnFace; + end; + + if (Win32MajorVersion = 5) then + begin + btnChangeCircuit.ImageMargins.Right := btnChangeCircuit.ImageMargins.Right - 16; + btnShowNodes.Images := lsMain; + btnShowNodes.ImageIndex := 14; + btnShowNodes.ImageMargins.Left := -32; + end; + + UpdateScaleFactor; + + hJob := CreateJob(nil, PAnsiChar(AnsiString('TCP-' + UserProfile))); + if hJob <> 0 then + begin + jLimit.BasicLimitInformation.LimitFlags := JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, @jLimit, SizeOf(TJobObjectExtendedLimitInformation)); + end; + + EncodingNoBom := TUTF8EncodingNoBOM.Create; + ThemesDir := ProgramDir + 'Skins\'; + TransportsDir := ProgramDir + 'Tor\PluggableTransports\'; + HsDir := UserDir + 'services\'; + OnionAuthDir := UserDir + 'onion-auth\'; + LogsDir := UserDir + 'logs\'; + ConsensusFile:= UserDir + 'cached-microdesc-consensus'; + DescriptorsFile := UserDir + 'cached-descriptors'; + NewDescriptorsFile := UserDir + 'cached-descriptors.new'; + UserConfigFile := UserDir + 'settings.ini'; + LangFile := ProgramDir + 'Translations.ini'; + DefaultsFile := ProgramDir + 'Defaults.ini'; + TorConfigFile := UserDir + 'torrc'; + TorStateFile := UserDir + 'state'; + TorExeFile := ProgramDir + 'Tor\tor.exe'; + GeoIpFile := ProgramDir + 'Data\Tor\geoip'; + GeoIpv6File := ProgramDir + 'Data\Tor\geoip6'; + NetworkCacheFile := UserDir + 'network-cache'; + BridgesCacheFile := UserDir + 'bridges-cache'; + + GeoIpDic := TDictionary.Create; + CircuitsDic := TDictionary.Create; + StreamsDic := TDictionary.Create; + RoutersDic := TDictionary.Create; + FilterDic := TDictionary.Create; + NodesDic := TDictionary.Create; + TrackHostDic := TDictionary.Create; + VersionsDic := TDictionary.Create; + RangesDic := TDictionary.Create; + PortsDic := TDictionary.Create; + ConstDic := TDictionary.Create; + TransportsDic := TDictionary.Create; + BridgesDic := TDictionary.Create; + + DefaultsDic := TDictionary.Create; + DefaultsDic.AddOrSetValue('MaxCircuitDirtiness', '600'); + DefaultsDic.AddOrSetValue('CircuitBuildTimeout', '60'); + DefaultsDic.AddOrSetValue('NewCircuitPeriod', '30'); + DefaultsDic.AddOrSetValue('MaxClientCircuitsPending', '32'); + DefaultsDic.AddOrSetValue('AvoidDiskWrites', '0'); + DefaultsDic.AddOrSetValue('TrackHostExitsExpire', '1800'); + DefaultsDic.AddOrSetValue('LearnCircuitBuildTimeout', '1'); + DefaultsDic.AddOrSetValue('SafeLogging', '1'); + DefaultsDic.AddOrSetValue('UseBridges', '0'); + DefaultsDic.AddOrSetValue('BridgeDistribution', 'any'); + DefaultsDic.AddOrSetValue('DirCache', '1'); + DefaultsDic.AddOrSetValue('Nickname', 'Unnamed'); + DefaultsDic.AddOrSetValue('PublishServerDescriptor', '1'); + DefaultsDic.AddOrSetValue('DirReqStatistics', '1'); + DefaultsDic.AddOrSetValue('HiddenServiceStatistics', '1'); + DefaultsDic.AddOrSetValue('EnforceDistinctSubnets', '1'); + DefaultsDic.AddOrSetValue('AssumeReachable', '0'); + DefaultsDic.AddOrSetValue('RendPostPeriod', '3600'); + DefaultsDic.AddOrSetValue('StrictNodes', '0'); + + cbEnableSocks.ResetValue := cbEnableSocks.Checked; + udHsMaxStreams.ResetValue := udHsMaxStreams.Position; + udHsNumIntroductionPoints.ResetValue := udHsNumIntroductionPoints.Position; + udHsRealPort.ResetValue := udHsRealPort.Position; + udHsVirtualPort.ResetValue := udHsVirtualPort.Position; + cbxHsVersion.ResetValue := HS_VERSION_3; + + for i := 0 to MAX_COUNTRIES - 1 do + begin + Filter.cc := i; + Filter.Data := []; + FilterDic.Add(CountryCodes[i], Filter); + end; + for i := 0 to MAX_SPEED_DATA_LENGTH - 1 do + begin + SpeedData[i].DL := -1; + SpeedData[i].UL := -1; + end; + + LoadStaticArray(CircuitStatuses); + LoadStaticArray(CircuitPurposes); + LoadStaticArray(StreamStatuses); + LoadStaticArray(StreamPurposes); + + sgHs.ColsDefaultAlignment[HS_VERSION] := taCenter; + sgHs.ColsDefaultAlignment[HS_INTRO_POINTS] := taCenter; + sgHs.ColsDefaultAlignment[HS_MAX_STREAMS] := taCenter; + sgHs.ColsDefaultAlignment[HS_STATE] := taCenter; + sgHsPorts.ColsDefaultAlignment[HSP_INTERFACE] := taCenter; + sgHsPorts.ColsDefaultAlignment[HSP_REAL_PORT] := taCenter; + sgHsPorts.ColsDefaultAlignment[HSP_VIRTUAL_PORT] := taCenter; + sgFilter.ColsDefaultAlignment[FILTER_ID] := taCenter; + sgFilter.ColsDefaultAlignment[FILTER_TOTAL] := taCenter; + sgFilter.ColsDefaultAlignment[FILTER_GUARD] := taCenter; + sgFilter.ColsDefaultAlignment[FILTER_EXIT] := taCenter; + sgFilter.ColsDefaultAlignment[FILTER_ALIVE] := taCenter; + sgFilter.ColsDefaultAlignment[FILTER_PING] := taCenter; + sgFilter.ColsDefaultAlignment[FILTER_ENTRY_NODES] := taCenter; + sgFilter.ColsDefaultAlignment[FILTER_MIDDLE_NODES] := taCenter; + sgFilter.ColsDefaultAlignment[FILTER_EXIT_NODES] := taCenter; + sgFilter.ColsDefaultAlignment[FILTER_EXCLUDE_NODES] := taCenter; + sgRouters.ColsDefaultAlignment[ROUTER_WEIGHT] := taRightJustify; + sgRouters.ColsDefaultAlignment[ROUTER_PORT] := taCenter; + sgRouters.ColsDefaultAlignment[ROUTER_VERSION] := taCenter; + sgRouters.ColsDefaultAlignment[ROUTER_PING] := taCenter; + sgRouters.ColsDefaultAlignment[ROUTER_FLAGS] := taCenter; + sgRouters.ColsDefaultAlignment[ROUTER_ENTRY_NODES] := taCenter; + sgRouters.ColsDefaultAlignment[ROUTER_MIDDLE_NODES] := taCenter; + sgRouters.ColsDefaultAlignment[ROUTER_EXIT_NODES] := taCenter; + sgRouters.ColsDefaultAlignment[ROUTER_EXCLUDE_NODES] := taCenter; + sgCircuits.ColsDefaultAlignment[CIRC_STREAMS] := taCenter; + sgCircuitInfo.ColsDefaultAlignment[CIRC_INFO_WEIGHT] := taRightJustify; + sgCircuitInfo.ColsDefaultAlignment[CIRC_INFO_PING] := taCenter; + sgStreams.ColsDefaultAlignment[STREAMS_TRACK] := taCenter; + sgStreams.ColsDefaultAlignment[STREAMS_COUNT] := taCenter; + sgStreams.ColsDefaultAlignment[STREAMS_BYTES_READ] := taRightJustify; + sgStreams.ColsDefaultAlignment[STREAMS_BYTES_WRITTEN] := taRightJustify; + sgStreamsInfo.ColsDefaultAlignment[STREAMS_INFO_SOURCE_ADDR] := taCenter; + sgStreamsInfo.ColsDefaultAlignment[STREAMS_INFO_DEST_ADDR] := taCenter; + sgStreamsInfo.ColsDefaultAlignment[STREAMS_INFO_PURPOSE] := taCenter; + sgStreamsInfo.ColsDefaultAlignment[STREAMS_INFO_BYTES_READ] := taRightJustify; + sgStreamsInfo.ColsDefaultAlignment[STREAMS_INFO_BYTES_WRITTEN] := taRightJustify; + sgTransports.ColsDefaultAlignment[PT_TYPE] := taCenter; + + sgFilter.ColsDataType[FILTER_TOTAL] := dtInteger; + sgFilter.ColsDataType[FILTER_GUARD] := dtInteger; + sgFilter.ColsDataType[FILTER_EXIT] := dtInteger; + sgFilter.ColsDataType[FILTER_ALIVE] := dtInteger; + sgRouters.ColsDataType[ROUTER_WEIGHT] := dtSize; + sgRouters.ColsDataType[ROUTER_PORT] := dtInteger; + sgRouters.ColsDataType[ROUTER_FLAGS] := dtParams; + sgCircuits.ColsDataType[CIRC_ID] := dtInteger; + sgCircuits.ColsDataType[CIRC_STREAMS] := dtInteger; + sgStreams.ColsDataType[STREAMS_ID] := dtInteger; + sgStreams.ColsDataType[STREAMS_TRACK] := dtInteger; + sgStreams.ColsDataType[STREAMS_BYTES_READ] := dtSize; + sgStreams.ColsDataType[STREAMS_BYTES_WRITTEN] := dtSize; + sgStreamsInfo.ColsDataType[STREAMS_INFO_ID] := dtInteger; + sgStreamsInfo.ColsDataType[STREAMS_INFO_BYTES_READ] := dtSize; + sgStreamsInfo.ColsDataType[STREAMS_INFO_BYTES_WRITTEN] := dtSize; + + sgFilter.Tag := GRID_FILTER; + sgRouters.Tag := GRID_ROUTERS; + sgCircuits.Tag := GRID_CIRCUITS; + sgStreams.Tag := GRID_STREAMS; + sgHs.Tag := GRID_HS; + sgHsPorts.Tag := GRID_HSP; + sgCircuitInfo.Tag := GRID_CIRC_INFO; + sgStreamsInfo.Tag := GRID_STREAM_INFO; + sgTransports.Tag := GRID_TRANSPORTS; + + miClearFilterEntry.Tag := ENTRY_ID; + miClearFilterMiddle.Tag := MIDDLE_ID; + miClearFilterExit.Tag := EXIT_ID; + miClearFilterExclude.Tag := EXCLUDE_ID; + miClearFilterAll.Tag := NONE_ID; + + miClearRoutersEntry.Tag := ENTRY_ID; + miClearRoutersMiddle.Tag := MIDDLE_ID; + miClearRoutersExit.Tag := EXIT_ID; + miClearRoutersExclude.Tag := EXCLUDE_ID; + miClearRoutersFavorites.Tag := FAVORITES_ID; + + lbFavoritesEntry.HelpKeyword := IntToStr(ENTRY_ID); + lbFavoritesMiddle.HelpKeyword := IntToStr(MIDDLE_ID); + lbFavoritesExit.HelpKeyword := IntToStr(EXIT_ID); + lbExcludeNodes.HelpKeyword := IntToStr(EXCLUDE_ID); + lbFavoritesTotal.HelpKeyword := IntToStr(FAVORITES_ID); + + GetTorVersion; +end; + +procedure TTcp.LoadOptions; +begin + CheckFileEncoding(UserConfigFile); + UpdateConfigVersion; + ResetOptions; + if cbMinimizeOnStartup.Checked then + Application.ShowMainForm := False + else + RestoreForm; +end; + +procedure TTCP.GetTorVersion; +var + ErrorMode: DWORD; + Fail: Boolean; +begin + Fail := True; + if FileExists(TorExeFile) then + begin + if not Assigned(GetProcAddress(GetModuleHandle('IPHLPAPI.DLL'), 'if_nametoindex')) then + begin + ErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS); + SetErrorMode(ErrorMode or SEM_FAILCRITICALERRORS); + end; + TorVersionProcess := ExecuteProcess(TorExeFile + ' --version', [pfHideWindow, pfReadStdOut], hJob); + if TorVersionProcess.hProcess <> 0 then + begin + CheckVersionStart(TorVersionProcess.hStdOutput); + Fail := False; + end; + SetErrorMode(0); + end; + if Fail then + begin + TorVersion := '0.0.0.0'; + LoadOptions; + end; +end; + +procedure TTcp.FindDialogFind(Sender: TObject); +begin + if Assigned(FindObject) then + begin + if SearchEdit(FindObject, FindDialog.FindText, FindDialog.Options, SearchFirst) then + SearchFirst := False + else + begin + if frDown in FindDialog.Options then + FindObject.SelStart := 1 + else + FindObject.SelStart := FindObject.GetTextLen; + + if SearchEdit(FindObject, FindDialog.FindText, FindDialog.Options, SearchFirst) then + SearchFirst := False + else + ShowMsg(Format(TransStr('378'), [FindDialog.FindText])); + end; + if FindObject.CanFocus then + FindObject.SetFocus; + end; +end; + +procedure TTcp.FindInCircuits(CircID, NodeID: string; AutoSelect: Boolean = False); +var + CircuitIndex: Integer; + NodeIndex: Integer; +begin + if AutoSelect then + SelectExitCircuit := True; + if (not cbEnableSocks.Checked) or + (not miAlwaysShowExitCircuit.Checked and + (miHideCircuitsWithoutStreams.Checked or not miCircExit.Checked)) then + begin + SelectExitCircuit := False; + Exit; + end; + CircuitIndex := sgCircuits.Cols[CIRC_ID].IndexOf(CircID); + if CircuitIndex > 0 then + begin + SetGridLastCell(sgCircuits, True, False, False, CircuitIndex, CIRC_PURPOSE); + NodeIndex := sgCircuitInfo.Cols[CIRC_ID].IndexOf(NodeID); + if NodeIndex > 0 then + begin + SelectExitCircuit := False; + SetGridLastCell(sgCircuitInfo, True, False, False, NodeIndex, CIRC_INFO_NAME); + Exit; + end; + end; +end; + +procedure TTcp.lbClientVersionClick(Sender: TObject); +begin + ShellOpen(GetDefaultsValue('DownloadUrl', DOWNLOAD_URL)); +end; + +procedure TTcp.lbExitCountryDblClick(Sender: TObject); +begin + if cbEnableSocks.Checked and (ConnectState = 2) then + FindInFilter(lbExitIp.Caption); +end; + +procedure TTcp.lbExitIpMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + if cbEnableSocks.Checked and (ConnectState = 2) then + begin + if (Button = mbLeft) and (ssDouble in Shift) then + begin + if ssCtrl in Shift then + FindInRouters(ExitNodeID) + else + begin + ShowCircuits; + FindInCircuits(Circuit, ExitNodeID, True); + sbShowCircuits.Click; + end; + end; + end; +end; + +procedure TTcp.lbExitMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); +var + State: Boolean; +begin + State := cbEnableSocks.Checked and (ConnectState = 2); + if State then + begin + lbExitIp.Tag := 1; + if (TLabel(Sender) = lbExitCountry) and (lbExitCountry.Hint <> '') then + Application.ActivateHint(Mouse.CursorPos) + else + Application.CancelHint; + end; + mnDetails.AutoPopup := State and (ExitNodeID <> ''); +end; + +procedure TTcp.ShowFavoritesRouters(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +var + FavoritesID: Integer; +begin + if (Button = mbLeft) and (ssDouble in Shift) then + begin + FavoritesID := StrToInt(TLabel(Sender).HelpKeyword); + if (ssCtrl in Shift) and (FavoritesID in [ENTRY_ID..EXCLUDE_ID]) then + begin + sbShowOptions.Click; + pcOptions.TabIndex := tsLists.TabIndex; + cbxNodesListType.ItemIndex := FavoritesToNodes(FavoritesID); + LoadNodesList; + end + else + begin + if RoutersCustomFilter = FavoritesID then + begin + IntToMenu(miRtFilters, RoutersFilters); + RoutersCustomFilter := LastRoutersCustomFilter; + LastRoutersCustomFilter := 0; + end + else + begin + if RoutersCustomFilter in [ENTRY_ID..FAVORITES_ID] then + LastRoutersCustomFilter := 0 + else + LastRoutersCustomFilter := RoutersCustomFilter; + RoutersCustomFilter := FavoritesID; + end; + CheckShowRouters; + ShowRouters; + SaveRoutersFilterdata(False, False); + end; + end; +end; + +function TTcp.GetFormPositionStr: string; +begin + Result := Format('%d,%d,%d,%d', [DecFormPos.X, DecFormPos.Y, IncFormPos.X, IncFormPos.Y]); +end; + +procedure TTcp.FormDestroy(Sender: TObject); +var + ini: TMemIniFile; +begin + if ConnectState > 0 then + StopTor; + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + ini.WriteString('Main', 'FormPosition', GetFormPositionStr); + ini.WriteInteger('Main', 'OptionsPage', pcOptions.TabIndex); + ini.WriteInteger('Main', 'LastPlace', LastPlace); + ini.WriteBool('Main', 'Terminated', False); + ini.WriteInt64('Status', 'TotalDL', TotalDL); + ini.WriteInt64('Status', 'TotalUL', TotalUL); + finally + ini.UpdateFile; + ini.Free; + end; + tiTray.Free; + StreamsDic.Free; + CircuitsDic.Free; + FilterDic.Free; + RoutersDic.Free; + GeoIpDic.Free; + NodesDic.Free; + TrackHostDic.Free; + VersionsDic.Free; + TransportsDic.Free; + BridgesDic.Free; + RangesDic.Free; + PortsDic.Free; + ConstDic.Free; + DefaultsDic.Free; + LangStr.Free; + TorConfig.Free; + EncodingNoBom.Free; + ExitProcess(Handle); +end; + +procedure TTcp.FormPaint(Sender: TObject); +begin + EnableComposited(Tcp.gbOptions); + EnableComposited(Tcp.gbControlAuth); + EnableComposited(Tcp.gbInterface); + EnableComposited(Tcp.gbProfile); + EnableComposited(Tcp.gbHsEdit); + EnableComposited(Tcp.gbNetworkScanner); + EnableComposited(Tcp.gbAutoSelectRouters); +end; + +procedure TTcp.FormResize(Sender: TObject); +begin + UpdateFormSize; +end; + +procedure TTcp.tiTrayClick(Sender: TObject); +begin + if Tcp.Visible then + begin + FindDialog.CloseDialog; + Tcp.Visible := False; + end + else + RestoreForm; +end; + +procedure TTcp.tmCircuitsTimer(Sender: TObject); +begin + ShowCircuits; +end; + +procedure TTcp.tmConsensusTimer(Sender: TObject); +var + ConsensusDate, NewDescriptorsDate: TDatetime; +begin + if FileAge(ConsensusFile, ConsensusDate) then + begin + if (ConsensusDate <> LastConsensusDate) then + LoadConsensus + else + begin + if cbUseBridges.Checked then + begin + if FileAge(NewDescriptorsFile, NewDescriptorsDate) then + begin + if (NewDescriptorsDate <> LastNewDescriptorsDate) then + LoadDescriptors; + end; + end; + end; + end; + if (AutoScanStage = 1) and not (Assigned(Consensus) or Assigned(Descriptors)) then + ScanNetwork(stBoth, spAuto); +end; + +procedure TTcp.tmUpdateIpTimer(Sender: TObject); +begin + SendDataThroughProxy; +end; + +procedure TTcp.miSafeLoggingClick(Sender: TObject); +begin + SetTorConfig('SafeLogging', IntToStr(Integer(miSafeLogging.Checked)), [cfAutoSave]); + ReloadTorConfig; +end; + +procedure TTcp.miSaveTemplateClick(Sender: TObject); +var + ini: TMemIniFile; + TemplateName, EntryNodes, MiddleNodes, ExitNodes: string; + FavoritesEntry, FavoritesMiddle, FavoritesExit, ExcludeNodes: string; + Item: TPair; + NodeItem: TPair; +begin + TemplateName := InputBox(TransStr('256'), TransStr('257') + ':', ''); + if Trim(TemplateName) <> '' then + begin + if Pos(';', TemplateName) = 0 then + begin + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + EntryNodes := ''; + MiddleNodes := ''; + ExitNodes := ''; + FavoritesEntry := ''; + FavoritesMiddle := ''; + FavoritesExit := ''; + ExcludeNodes := ''; + + if miTplSaveCountries.Checked then + begin + for Item in FilterDic do + begin + if ntEntry in Item.Value.Data then + EntryNodes := EntryNodes + ',' + Item.Key; + if ntMiddle in Item.Value.Data then + MiddleNodes := MiddleNodes + ',' + Item.Key; + if ntExit in Item.Value.Data then + ExitNodes := ExitNodes + ',' + Item.Key; + end; + Delete(EntryNodes, 1, 1); + Delete(MiddleNodes, 1, 1); + Delete(ExitNodes, 1, 1); + end; + + if miTplSaveRouters.Checked or miTplSaveExcludes.Checked then + begin + for NodeItem in NodesDic do + begin + if miTplSaveRouters.Checked then + begin + if ntEntry in NodeItem.Value then + FavoritesEntry := FavoritesEntry + ',' + NodeItem.Key; + if ntMiddle in NodeItem.Value then + FavoritesMiddle := FavoritesMiddle + ',' + NodeItem.Key; + if ntExit in NodeItem.Value then + FavoritesExit := FavoritesExit + ',' + NodeItem.Key; + end; + if miTplSaveExcludes.Checked then + if ntExclude in NodeItem.Value then + ExcludeNodes := ExcludeNodes + ',' + NodeItem.Key; + end; + if miTplSaveRouters.Checked then + begin + Delete(FavoritesEntry, 1, 1); + Delete(FavoritesMiddle, 1, 1); + Delete(FavoritesExit, 1, 1); + end; + if miTplSaveExcludes.Checked then + Delete(ExcludeNodes, 1, 1); + end; + + ini.WriteString('Templates', IntToStr(DateTimeToUnix(Now)), TemplateName + ';' + + IntToStr(cbxFilterMode.ItemIndex) + ';' + + EntryNodes + ';' + MiddleNodes + ';' + ExitNodes + ';' + + FavoritesEntry + ';' + FavoritesMiddle + ';' + FavoritesExit + ';' + ExcludeNodes + ); + + finally + ini.UpdateFile; + ini.Free; + end; + ShowBalloon(Format(TransStr('363'), [TemplateName])); + end + else + ShowMsg(Format(TransStr('255'), [';']), '', mtWarning); + end; +end; + +procedure TTcp.SelectLogSeparater(Sender: TObject); +var + SeparateType: Byte; +begin + TMenuItem(Sender).Checked := True; + SeparateType := TMenuItem(Sender).Tag; + TorLogFile := GetLogFileName(SeparateType); + SetConfigInteger('Log', 'SeparateType', SeparateType); +end; + +procedure TTcp.SelectLogScrollbar(Sender: TObject); +begin + SetLogScrollBar(TMenuItem(Sender).Tag, TMenuItem(Sender)); +end; + +procedure TTcp.SetLogScrollBar(ScrollType: Byte; Menu: TMenuItem = nil); +begin + case ScrollType of + 0: meLog.ScrollBars := ssVertical; + 1: meLog.ScrollBars := ssHorizontal; + 2: meLog.ScrollBars := ssBoth; + 3: meLog.ScrollBars := ssNone; + end; + if ScrollType in [1,2] then + miWordWrap.Enabled := False + else + miWordWrap.Enabled := True; + + if Menu <> nil then + begin + Menu.Checked := True; + CheckLogAutoScroll(True); + SetConfigInteger('Log', 'ScrollBars', ScrollType); + end; +end; + +procedure TTcp.miServerInfoClick(Sender: TObject); +begin + OpenMetricsUrl('#details', lbFingerprint.Caption); +end; + +procedure TTcp.SetLogLevel(Sender: TObject); +begin + if TMenuItem(Sender).Checked then + Exit; + TMenuItem(Sender).Checked := True; + SetTorConfig('Log', AnsiLowerCase(copy(TMenuItem(Sender).Name, 3, Length(TMenuItem(Sender).Name) - 2)) + ' stdout', [cfAutoSave]); + ReloadTorConfig; +end; + +procedure TTcp.miOpenFileLogClick(Sender: TObject); +begin + ShellOpen(TorLogFile); +end; + +procedure TTcp.SelectTrafficPeriod(Sender: TObject); +begin + if TMenuItem(Sender).Checked then + Exit; + TMenuItem(Sender).Checked := True; + CurrentTrafficPeriod := TMenuItem(Sender).Tag; + pbTraffic.Repaint; + SetConfigInteger('Status', 'CurrentTrafficPeriod', CurrentTrafficPeriod); +end; + +procedure TTcp.miPreferWebTelegramClick(Sender: TObject); +begin + SetConfigBoolean('Network', 'PreferWebTelegram', miPreferWebTelegram.Checked); +end; + +procedure TTcp.ResetGuards(GuardType: TGuardType); +var + ls: TStringList; + i: Integer; + TypeStr: string; +begin + if not FileExists(TorStateFile) then + Exit; + case Byte(GuardType) of + 1: TypeStr := 'in=bridges'; + 2: TypeStr := 'in=restricted'; + 3: TypeStr := 'in=default'; + else + TypeStr := ''; + end; + + ls := TStringList.Create; + try + ls.LoadFromFile(TorStateFile); + for i := ls.Count - 1 downto 0 do + begin + if (Pos('Guard ' + TypeStr, ls[i]) = 1) then + ls.Delete(i); + end; + ls.SaveToFile(TorStateFile); + miResetGuards.Tag := 0; + finally + ls.Free; + end; +end; + +procedure TTcp.miUpdateIpToCountryCacheClick(Sender: TObject); +begin + if not CheckCacheOpConfirmation(TMenuItem(Sender).Caption) then + Exit; + GeoIpUpdating := True; + InfoStage := 1; +end; + +procedure TTcp.SetResetGuards(Sender: TObject); +var + Temp: string; +begin + miResetGuards.Tag := TMenuItem(Sender).Tag; + if ConnectState = 2 then + Temp := TransStr('164') + '. ' + else + Temp := ''; + if ShowMsg(Format(TransStr('346'), [Temp]), '', mtWarning, True) then + begin + if ConnectState = 2 then + RestartTor(1) + else + ResetGuards(TGuardType(miResetGuards.Tag)); + end; +end; + +procedure TTcp.miRtDisableBridgesClick(Sender: TObject); +begin + cbUseBridges.Checked := False; + ShowRouters; + BridgesCheckControls; + EnableOptionButtons; +end; + +procedure TTcp.miRtRelayInfoClick(Sender: TObject); +begin + OpenMetricsUrl('#details', miRtCopyFingerprint.Caption); +end; + +procedure TTcp.miRtResetFilterClick(Sender: TObject); +var + ini: TMemIniFile; + Data: string; + ParseStr: ArrOfStr; + i: Integer; +begin + ini := TMemIniFile.Create(UserConfigFile, TEncoding.UTF8); + try + Data := ini.ReadString('Routers', 'DefaultFilter', DEFAULT_ROUTERS_FILTER_DATA); + LoadRoutersFilterData(Data); + ParseStr := Explode(';', Data); + if Length(ParseStr) > 7 then + begin + if Trim(ParseStr[8]) = '' then + ParseStr[7] := IntToStr(cbxRoutersQuery.ItemIndex); + Data := ''; + for i := 0 to Length(ParseStr) - 1 do + Data := Data + ';' + ParseStr[i]; + Delete(Data, 1, 1); + end; + + ini.WriteString('Routers', 'CurrentFilter', Data); + finally + ini.UpdateFile; + ini.Free; + end; +end; + +procedure TTcp.miRtSaveDefaultClick(Sender: TObject); +begin + SaveRoutersFilterdata(True); +end; + +procedure TTcp.miRoutersScrollTopClick(Sender: TObject); +begin + SetConfigBoolean('Routers', 'RoutersScrollTop', miRoutersScrollTop.Checked); +end; + +procedure TTcp.SelectNodeAsBridge(Sender: TObject); +var + BridgeStr: string; +begin + cbUseBridges.Checked := True; + cbUsePreferredBridge.Checked := True; + BridgeStr := TMenuItem(Sender).Hint; + if BridgeStr = '' then + BridgeStr := TMenuItem(Sender).Caption; + edPreferredBridge.Text := BridgeStr; + ShowRouters; + BridgesCheckControls; + EnableOptionButtons; +end; + +procedure TTcp.miRoutersSelectRowClick(Sender: TObject); +begin + CheckSelectRowOptions(sgRouters, miRoutersSelectRow.Checked, True); +end; + +procedure TTcp.OpenMetricsUrl(Page, Query: string); +begin + if Query = '' then + Exit; + ShellOpen(GetDefaultsValue('MetricsUrl', METRICS_URL) + Page + '/' + Query); +end; + +procedure TTcp.OptionsChange(Sender: TObject); +begin + EnableOptionButtons; +end; + +procedure TTcp.miDetailsRelayInfoClick(Sender: TObject); +begin + OpenMetricsUrl('#details', SelectedNode); +end; + +procedure TTcp.miDetailsUpdateIpClick(Sender: TObject); +begin + SendDataThroughProxy; +end; + +procedure TTcp.miDestroyExitCircuitsClick(Sender: TObject); +var + Item: TPair; + ParseStr: ArrOfStr; + Temp: string; + i: Integer; +begin + if (ConnectState <> 2) then + Exit; + + Temp := ''; + for Item in CircuitsDic do + if not (bfInternal in Item.Value.BuildFlags) then + Temp := Temp + ',' + Item.Key; + Delete(Temp, 1, 1); + + if Temp <> '' then + begin + btnChangeCircuit.Enabled := False; + miChangeCircuit.Enabled := False; + ParseStr := Explode(',', Temp); + Temp := ''; + for i := 0 to Length(ParseStr) - 1 do + begin + CircuitsDic.Remove(ParseStr[i]); + Temp := Temp + BR + 'CLOSECIRCUIT ' + ParseStr[i]; + end; + Delete(Temp, 1, Length(BR)); + ShowCircuits; + SendCommand(Temp); + end; +end; + +procedure TTcp.CloseCircuit(CircuitID: string; AutoUpdate: Boolean = True); +begin + if (CircuitID = '') or (ConnectState <> 2) then + Exit; + if CircuitsDic.ContainsKey(CircuitID) then + begin + CircuitsDic.Remove(CircuitID); + SendCommand('CLOSECIRCUIT ' + CircuitID); + end; + if AutoUpdate then + ShowCircuits; +end; + +procedure TTcp.ClearBridgesCache(Sender: TObject); +var + Item: TPair; + GeoIpInfo: TGeoIpInfo; + RouterInfo: TRouterInfo; + PortsData: ArrOfStr; + PreferredBridge: TBridge; + LastPreferredBridge: string; + ClearAll, Deleted: Boolean; + Search, i: Integer; + ls: TStringList; +begin + if not CheckCacheOpConfirmation(TMenuItem(Sender).Caption) then + Exit; + ClearAll := TMenuItem(Sender).Tag = 1; + if ClearAll then + begin + DeleteFile(DescriptorsFile); + DeleteFile(NewDescriptorsFile); + BridgesDic.Clear; + end + else + begin + ls := TStringList.Create; + try + LastPreferredBridge := ''; + if TryParseBridge(edPreferredBridge.Text, PreferredBridge) then; + LastPreferredBridge := PreferredBridge.Hash; + for Item in BridgesDic do + begin + Deleted := False; + if RoutersDic.TryGetValue(Item.Key, RouterInfo) then + begin + if rfRelay in RouterInfo.Flags then + begin + if LastPreferredBridge <> Item.Key then + begin + ls.Append(Item.Key); + Deleted := True; + end; + end; + end; + if not Deleted then + begin + if GeoIpDic.TryGetValue(Item.Value.Router.IPv4, GeoIpInfo) then + begin + Search := -1; + PortsData := Explode('|', GeoIpInfo.ports); + for i := 0 to Length(PortsData) - 1 do + begin + if Pos(IntToStr(Item.Value.Router.OrPort) + ':', PortsData[i]) = 1 then + begin + Search := i; + Break; + end; + end; + if Search <> -1 then + begin + if SeparateRight(PortsData[Search], ':') <> '1' then + ls.Append(Item.Key); + end; + end; + end; + end; + for i := 0 to ls.Count - 1 do + BridgesDic.Remove(ls[i]); + finally + ls.Free; + end; + end; + DescriptorsUpdated := True; + LoadConsensus; +end; + +procedure TTcp.ClearBridgesAvailableCache(Sender: TObject); +var + ls: TStringList; + i: Integer; + HashStr: string; + DeleteFound: Boolean; +begin + DeleteFound := TMenuItem(Sender).Tag = 1; + ls := TStringList.Create; + try + ls.Text := meBridges.Text; + for i := ls.Count - 1 downto 0 do + begin + if TryGetDataFromStr(ls[i], ltHash, HashStr) then + begin + if BridgesDic.ContainsKey(HashStr) then + begin + if DeleteFound then + ls.Delete(i); + end + else + begin + if not DeleteFound then + ls.Delete(i); + end; + end; + end; + meBridges.Text := ls.Text; + finally + ls.Free; + end; +end; + +procedure TTcp.miClearBridgesNotAliveClick(Sender: TObject); +begin + ScanNetwork(stAlive, spUserBridges); +end; + +procedure TTcp.miDestroyCircuitClick(Sender: TObject); +begin + CloseCircuit(sgCircuits.Cells[CIRC_ID, sgCircuits.SelRow]); +end; + +procedure TTcp.CloseStream(StreamID: string); +var + CircuitInfo: TCircuitInfo; + StreamInfo: TStreamInfo; +begin + if (ConnectState <> 2) or (StreamID = '') then + Exit; + if StreamsDic.TryGetValue(StreamID, StreamInfo) then + begin + if CircuitsDic.TryGetValue(StreamInfo.CircuitID, CircuitInfo) then + begin + Dec(CircuitInfo.Streams); + CircuitsDic.AddOrSetValue(StreamInfo.CircuitID, CircuitInfo); + end; + StreamsDic.Remove(StreamID); + SendCommand('CLOSESTREAM ' + StreamID + ' 1'); + ShowCircuits; + end; +end; + +procedure TTcp.CloseStreams(CircuitID: string; FindTarget: Boolean = False; TargetID: string = ''); +var + Item: TPair; + CircuitInfo: TCircuitInfo; + Temp: string; + ParseStr: ArrOfStr; + i: Integer; + Flag: Boolean; + StreamsCount: Integer; +begin + if (ConnectState <> 2) or (CircuitID = '') then + Exit; + if FindTarget and (TargetID = '') then + Exit; + if sgCircuits.Cells[CIRC_STREAMS, sgCircuits.SelRow] = EXCLUDE_CHAR then + Exit; + if CircuitsDic.TryGetValue(CircuitID, CircuitInfo) then + begin + StreamsCount := 0; + Temp := ''; + for Item in StreamsDic do + begin + if TargetID = '' then + Flag := Item.Value.CircuitID = CircuitID + else + Flag := (Item.Value.CircuitID = CircuitID) and (Item.Value.Target = TargetID); + if Flag then + begin + Temp := Temp + ',' + Item.Key; + Inc(StreamsCount); + end; + end; + Delete(Temp, 1, 1); + if StreamsCount > 0 then + begin + ParseStr := Explode(',', Temp); + Temp := ''; + for i := 0 to Length(ParseStr) - 1 do + begin + StreamsDic.Remove(ParseStr[i]); + Temp := Temp + BR + 'CLOSESTREAM ' + ParseStr[i] + ' 1'; + end; + Delete(Temp, 1, Length(BR)); + Dec(CircuitInfo.Streams, StreamsCount); + CircuitsDic.AddOrSetValue(CircuitID, CircuitInfo); + SendCommand(Temp); + ShowCircuits; + end; + end; +end; + +procedure TTcp.miDestroyStreamsClick(Sender: TObject); +begin + CloseStreams(sgCircuits.Cells[CIRC_ID, sgCircuits.SelRow]); +end; + +procedure TTcp.miWordWrapClick(Sender: TObject); +begin + SetConfigBoolean('Log', 'WordWrap', miWordWrap.Checked); + meLog.WordWrap := miWordWrap.Checked; + CheckLogAutoScroll(True); +end; + +procedure TTcp.miHsOpenDirClick(Sender: TObject); +begin + ShellOpen(GetFullFileName(HsDir + sgHs.Cells[HS_NAME, sgHs.SelRow])); +end; + +procedure TTcp.miIgnoreTplLoadParamsOutsideTheFilterClick(Sender: TObject); +begin + SetConfigBoolean('Filter', 'IgnoreTplLoadParamsOutsideTheFilter', miIgnoreTplLoadParamsOutsideTheFilter.Checked); +end; + +procedure TTcp.miLoadCachedRoutersOnStartupClick(Sender: TObject); +begin + if (ConnectState = 0) and miLoadCachedRoutersOnStartup.Checked and (RoutersDic.Count = 0) then + LoadConsensus; + SetConfigBoolean('Routers', 'LoadCachedRoutersOnStartup', miLoadCachedRoutersOnStartup.Checked); +end; + +procedure TTcp.miManualDetectAliveNodesClick(Sender: TObject); +begin + SetConfigBoolean('Scanner', 'ManualDetectAliveNodes', miManualDetectAliveNodes.Checked); +end; + +procedure TTcp.miManualPingMeasureClick(Sender: TObject); +begin + SetConfigBoolean('Scanner', 'ManualPingMeasure', miManualPingMeasure.Checked); +end; + +procedure TTcp.miNotLoadEmptyTplDataClick(Sender: TObject); +begin + SetConfigBoolean('Filter', 'NotLoadEmptyTplData', miNotLoadEmptyTplData.Checked); +end; + +end. diff --git a/source/TCP-RSP-31045-PATCHER.exe b/source/TCP-RSP-31045-PATCHER.exe new file mode 100644 index 0000000..733aac5 Binary files /dev/null and b/source/TCP-RSP-31045-PATCHER.exe differ diff --git a/source/TorControlPanel.dpr b/source/TorControlPanel.dpr new file mode 100644 index 0000000..f7d9d1f --- /dev/null +++ b/source/TorControlPanel.dpr @@ -0,0 +1,64 @@ +program TorControlPanel; + +uses + System.SysUtils, + Vcl.Forms, + Vcl.Styles, + Winapi.Windows, + synautil, + Main in 'Main.pas' {Tcp}, + Functions in 'Functions.pas', + Languages in 'Languages.pas', + Addons in 'Addons.pas', + ConstData in 'ConstData.pas'; + +var + i, FH: Integer; + +{$IFDEF RELEASE} + {$SETPEFlAGS + IMAGE_FILE_DEBUG_STRIPPED or + IMAGE_FILE_LINE_NUMS_STRIPPED or + IMAGE_FILE_LOCAL_SYMS_STRIPPED or + IMAGE_FILE_RELOCS_STRIPPED or + IMAGE_FILE_LARGE_ADDRESS_AWARE + } + {$WEAKLINKRTTI ON} + {$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])} +{$ENDIF} + +{$R *.res} + +begin +{$IFDEF DEBUG} + ReportMemoryLeaksOnShutdown := True; +{$ENDIF} + UserProfile := 'User'; + if ParamCount > 0 then + begin + for i := 1 to ParamCount do + begin + if pos('-profile=', ParamStr(i)) <> 0 then + UserProfile := SeparateRight(ParamStr(i), '='); + end; + end; + ProgramDir := ExtractShortPathName(GetCurrentDir + '\'); + if IsDirectoryWritable(ProgramDir) then + UserDir := ProgramDir + 'Data\' + UserProfile + '\' + else + UserDir := GetEnvironmentVariable('appdata') + '\Tcp\' + UserProfile + '\'; + ForceDirectories(UserDir); + + FH := FileCreate(UserDir + 'lock.tcp'); + if FH = -1 then + Exit; + UserDir := ExtractShortPathName(UserDir); + + Application.Initialize; + Application.MainFormOnTaskbar := False; + Application.ShowMainForm := False; + Application.Title := 'Панель управления Tor'; + Application.CreateForm(TTcp, Tcp); + Application.Run; +end. + diff --git a/source/TorControlPanel.dproj b/source/TorControlPanel.dproj new file mode 100644 index 0000000..3681131 --- /dev/null +++ b/source/TorControlPanel.dproj @@ -0,0 +1,183 @@ + + + {D2FF7A62-ADDB-4AF8-98EA-04980D0CD3C2} + TorControlPanel.dpr + True + Release + 3 + Application + VCL + 19.2 + Win32 + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + false + false + false + false + false + 00400000 + TorControlPanel + Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;FMXTee.Chart;$(DCC_Namespace) + 1049 + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;CFBundleName= + .\__Temp\$(Platform)-$(Config) + true + + + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName) + 1033 + $(BDS)\bin\default_app.manifest + TorControlPanel_Icon.ico + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + true + PerMonitorV2 + + + $(BDS)\bin\default_app.manifest + TorControlPanel_Icon.ico + true + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + Debug + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + PerMonitorV2 + + + RELEASE;$(DCC_Define) + 0 + false + 0 + + + 1033 + true + CompanyName=;FileDescription=GUI for Tor Expert Bundle;FileVersion=2.2.11.4;InternalName=;LegalCopyright=Copyright © 2020, abysshint;LegalTrademarks=;OriginalFilename=TorControlPanel.exe;ProductName=Tor Control Panel;ProductVersion=2.2.11.4;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName) + 2 + 11 + 2 + 4 + + + 1033 + true + CompanyName=;FileDescription=GUI for Tor Expert Bundle;FileVersion=2.2.11.4;InternalName=;LegalCopyright=Copyright © 2020, abysshint;LegalTrademarks=;OriginalFilename=TorControlPanel.exe;ProductName=Tor Control Panel;ProductVersion=2.2.11.4;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName) + 2 + 11 + 2 + 4 + + + DEBUG;$(DCC_Define) + false + true + + + 1033 + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName) + + + 1033 + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + + + + MainSource + + +
Tcp
+
+ + + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + + + + + TorControlPanel.dpr + + + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + True + True + + + 12 + + + + +
diff --git a/source/TorControlPanel.icons.res b/source/TorControlPanel.icons.res new file mode 100644 index 0000000..f1c3e65 Binary files /dev/null and b/source/TorControlPanel.icons.res differ diff --git a/source/TorControlPanel_Icon.ico b/source/TorControlPanel_Icon.ico new file mode 100644 index 0000000..44eb812 Binary files /dev/null and b/source/TorControlPanel_Icon.ico differ diff --git a/source/Translations.ini b/source/Translations.ini new file mode 100644 index 0000000..137adf4 --- /dev/null +++ b/source/Translations.ini @@ -0,0 +1,1496 @@ +[English] +Locale=1033 +UseDefaultCountries=1 +100=Start +101=Starting... +102=Stop +103=Change\nCircuit +104=Default +105=Tor Control Panel +106=%s\nProfile: %s +107=Settings +108=Log +109=Not received +110=Not defined +111=Receiving... +112=Defining... +113=IP address +114=Country +115=Apply +116=Cancel +117=Create.. +118=General +119=Network +120=Filter +121=Server +122=Hidden Service +123=Other +124=Change a circuit that exists more than +125=Interval between attempts to build a circuit +126=Maximum time to build a circuit +127=Port +128=Authentication +129="Cookie-file","Password" +130=Password +131=Generate random password +132=Language +133=Program shortcut on desktop with a new profile +134=Profile +135=sec. +136=Automatically select timeout to build a circuit +137=Don't build circuits from nodes of the same subnet +138=Perform less disk operations +139=Connect on program startup +140=Restart on lost connection with client +141=Minimize to tray on startup +142=Minimize to tray on close +143=Show pop-up messages +144=Only when program minimized +145=Always stay on top +146=Conversion to hashes is enabled +147=My firewall let me connect only to these ports +148=Allowed ports +149=Enable built-in proxy +150=I use a proxy to connect to the Internet +151=Type +152=Host +153=Port +154=User +155=Use Bridges +156=Enter password +157=Comma-separated values +158=IP address or hostname +159=Optional +160=Scroll up when sorting +161=The current vanguards configuration for hidden services requires at least %d favorite entry nodes (Found: %d). \n\nCorrect the problem and continue saving your settings? +162=Mode +163=Hide unused countries +164=This operation requires restarting Tor +165="Disabled","Selected countries","Favorite nodes" +166=Work mode +167=Nickname +168=Contact info +169=Bridge type +170=Exit policy +171=Server +172=Directory +173=Transport +174=Limit memory usage +175=Maximum +176=Limit speed +177=Limit CPU usage +178=Max. cores +179=Average +180=s +181=Port Forwarding Check +182=Try to configure port forwarding automatically +183=Publish server in the relay directory +184=Enable the relay directory mirror +185=Collect directory requests statistics +186=Collect statistics about your role as a hidden-service directory +187=Allow IPv6 traffic to exit +188=Name of your relay +189=e-mail address +190=Name +191=Catalog name +192=Limit the number of connections +193=Connections per circuit +194=Protocol version +195=Introduction points +196=Publish Interval +197=min. +198=Service +199=State +200=Virtual port +201=Save exit node for specified hosts +202=Change after expiry +203=Total +204=Warning: Disabling the directory cache will speed up the server, but your server will never become a Guard. Do you want to continue? +205="Disabled","Relay","Exit relay","Bridge" +206=Normal +207="Default","Reduced","Custom" +208=\n Click here to add addresses\n\n Examples:\n\n Ip: 8.8.8.8\n Site: metrics.torproject.org\n Domain:.torproject.org\n All:. +209=\n Click here to add nodes\n\n Examples:\n\n Ip: 8.8.8.8\n CIDR: 8.8.8.8/24\n Country: RU,DE,US,..\n Hash: ABCD1234CDEF567.. +210=\n Click here to add bridges\n\n Examples:\n\n 8.8.8.8:443\n 8.8.8.8:443 ABCD1234CDEF567..\n obfs4 8.8.8.8:443 ABCD1234CDEF567.. cert=.. iat-mode=..\n\n Note:\n\n Bridges override EntryNodes settings. +211=Speed +212=Download +213=Upload +214=Recieved +215=Sent +216=Server +217=External address +218=Fingerprint +219=Bridge Address +220=Speed graph +221=Creation date +222=Information +223=Client version +224=Profile +225=Built-in proxy +226=Disabled +227=Open profile folder +228=Copy to clipboard +229=Total per session +230=Name,Version,Intro points,Connections +231=Interface,Port,Virtual port +232=Nickname,IP address,,Country,Weight,Ping +233=ID,,Country,Total,Guard,Exit,Alive,∑ Ping +234=B,KB,MB,GB,TB,PB,EB +235=Information +236=Error when parsing the torrc configuration file, see the log for details +237=Connect to the Tor network stopped, the password for control port is incorrect! +238=The Tor executable file does not start. Maybe he:\n\n - is corrupted or is not a Windows application\n - is a 64-bit application, while you have a 32-bit operating system +239=The Tor executable file was not found. Download the Tor Windows Expert Bundle and unpack it into the program directory. Go to the download page right now? +240=Connecting to the Tor network... +241=You are disconnected from the Tor network +242=No devices with port forwarding support were found +243=Result +244=Source,Destination,Purpose +245=Successfully +246=Warning +247=Error +248=The name cannot be empty! +249=This name is already in use by another service! +250=Port list +251=You must add at least one port! +252=This combination of interface and ports already exists! +253=Password for control port changed +254=Error when loading the template: parameters set incorrectly! +255=You cannot use the delimiter character " %s " +256=Save template +257=Enter a template name +258=Circuit is changed +259=The launch suspended, the ports specified in the program settings are already in use!\n\nBusy ports: %s\n\nChange ports to random and continue starting? +260=Not defined +261=You can't use bridges, proxies, and allowed ports in server mode!\n\nDisable these options and continue saving settings? +262=Confirmation +263=Do you really want to delete %s"%s"? +264=All templates +265=Create shortcut +266=Enter profile name +267=All services +268=Do you really want to add:\n\n%s\n\nto the list of "%s nodes"?%s +269=Use only Latin letters and numbers +270=and +271=Tor configuration file +272=Edit panel +273=Service Folder +274=Copy +275=Paste +276=Cut +277=Select All +278=Clear +279=Add +280=Delete +281=Relay Info +282=Status +283=Clear DNS Cache +284=Refresh +285=Change node lists +286=Select Template +287=Exclude +288=Entry +289=Middle +290=Exit +291=Get bridges +292=Write to file +293=Clear at every start +294=Auto scroll +295=Scroll bars +296=Vertical +297=Horizontal +298=Both +299=No +300=Word wrap +301=Hide network addresses +302=Logging level +303=Debug +304=Info +305=Notice +306=Warning +307=Error +308=Open log file +309=Statistics +310=Relay +311=Guard +312=Exit +313=Total by countries +314=Save +315=Load +316=All selected +317=Number of pending client circuits +318=Allow exluded nodes for internal circuits +319=Exit +;new +320=Nickname,IP address,,Country,Weight,Port,Version,Ping,Flags +321=Shown: %d of %d +322=\n List of hashes that define your family\n\n Example:\n\n ABCD1234CDEF567.. +323=Relays +324=Incorrect settings +325=Go to the Tor download page +326=The hidden services protocol version 2 is obsolete, its support was discontinued in version 0.4.6.1 and higher. Do you really want to use this version of the protocol? +327=Circuits +328=Reduce window +329=Purpose +330=Target address +331=Directory request +332=Internal traffic +333=Exit traffic +334=HS Client: dir request +335=HS Client: intro point +336=HS Client: rend point +337=HS Service: dir request +338=HS Service: intro point +339=HS Service: rend point +340=HS vanguards +341=Path bias testing +342=Reachability testing +343=Closing time masking +344=Measure timeout +345=Other purpose +346=Attention! Frequent change of Guard-nodes can help attackers to detect you. Use only if absolutely necessary. %sDo you want to continue? +347=(All countries) +348=(Selected in the filter) +349=Circuits: %d of %d +350=Streams +351=Bind to the exit node +352=Unbind from the exit node +353=Global domain +354=The program settings have been changed! Do you want to apply the changes? +355=About.. +356=%s, version: %s\n\n%s\n\n(Windows GUI Client for Tor Expert Bundle)\n\n%s\n\nWould you like to visit the program page on GitHub? +357=This program is free software and is distributed under the MIT license. +358=Nodes missing from the consensus will be removed from user of lists.\n\nIgnore the list of exlude nodes when scanning? +359=Remove from lists +360=Auto select relays +361=Do you really want to remove:\n\n%s\n\nfrom all node lists?%s +362=Do you really want to remove:\n\n%s\n\nfrom the "%s nodes" list?%s +363=Template "%s" saved successfully +364=Template "%s" loaded successfully +365=Template "%s" deleted successfully +366=template +367=service +368=Select All +369=Unselect All +370=Dir request +371=Dir downloading +372=Dir port testing +373=DNS query +374=Normal traffic +375=Other purpose +376=Internal socket +377=Tor Windows Expert Bundle version 0.4.0.5 and higher is required for the normal operation of the program. +378=Can't find "%s" +379=ms +380=Automatic mode +381=Manual mode +382=Ping measuring +383=Alive nodes detecting +384=Bridge (Guard node) +385=Authority +386=Alive (responds to connections) +387=Accepts IPv6 connections +388=Hidden Service Directory +389=Directory mirror (port: %d) +390=Not recommended version +391=Bad exit node +392=Unknown flag +393=Transports,Handler,Type +394=The list of transports cannot contain empty data +395=Handler file not found, copy it to the transport directory and try again +396=Alive bridges detecting +397=Latest supported version for your operating system: 0.4.4.6 +398=Digits at the beginning of a word are not allowed +399=Transport with this name and type already exists +400=Bridges scanning in progress...\n\nPlease wait until the end and try again. +401=No connection +402=Start of accounting: %s +403=Total for all time +404=Stop scanning.. +405=Do you really want: "%s"\n\nThe selected action cannot be undone! +406=Delete all +407=Determine the external address of the server via OpenDNS +408=Only if TOR cannot detect it by itself +409=Cache IP-cc requests and network scanner results +410=Main +411=Interface +412=Control +413=Theme +414=Allow window to go borders screen +415=Only when the program window is enlarged +416=Remember the position of the enlarged window +417=Hide IPv6 addresses in interface lists +418=Clear previous search query in lists +419=List of bridges +420=Set preferred bridge manually +421=Bridge +422=This setting overrides the selected list of bridges +423=Find... +424="Built-in","Custom" +425=Distribution +426="Any","Https","E-mail","Moat","None" +427=Set external address manually +428=Address +429=IP address or hostname +430=Ports settings +431=Advertised +432=Use directory cache +433=Disable server reachability check +434=Listen on IPv6 addresses +435=Use MyFamily option +436="Enabled","Disabled" +437=Use Vanguards for Hidden Services +438=Change the circuit node +439="Auto","Second only","Third only","Second and third" +440=Select the list to edit +441=List +442="Entry nodes","Middle nodes","Exit nodes","Exclude nodes" +443=Enable +444=Network scanner +445=Enable alive node detection +446=Enable ping measurement +447=Port connection timeout +448=Number of port connection attempts +449=Ping request timeout +450=Number of attempts to measure ping +451=Delay between attempts +452=Number of scan threads +453=Delay between portions +454=Number of scans per serving +455=Automatically detect ping and alive nodes +456=Full scan every +457=Scan nodes without response every +458=Number of partial scans +459=msec. +460=Pluggable transports +461=Transports +462=List of supported transports +463=Handler +464=Enter file name +465=Parameters +466="Client","Server","Combined" +467=Auto select relays +468=Weight +469=Ping +470=pcs. +471=Priority +472="Balanced","Consensus Weight","Ping to Node","Random" +473=Only stable +474=Only countries from the Filter +475=Only unique +476=Only nodes responding to a ping +477=h. +478=Cache operations +479=Refresh countries in network cache +480=Clear server cache +481=Clear unnecessary bridges cache +482=Clear all bridges cache +483=Clear ping requests cache +484=Clear alive nodes cache +485=Clear unused network cache +486=Reset nodes scan schedule +487=Reset traffic counter +488=Start the network scanner +489=New nodes +490=Non-responding nodes +491=Cached Bridges +492=All nodes +493=Ping measurement +494=Alive nodes detection +495=Stop scanning... +496=Reset guard nodes +497=All guard nodes +498=Bridge nodes +499=Selected entry nodes +500=Default entry nodes +501=Web site +502=Telegram channel +503=E-mail +504=Prefer the web version of Telegram +505=Request obfuscated bridges +506=Request IPv6 bridges +507=Not responding to connections +508=Missing in the cache +509=Found in the cache +510=All bridges +511=Splitting the log file +512=Don't split +513=By month +514=By days +515=Select all cells in a row +516=Do not load empty template data +517=Ignore loading parameters from a template outside the filter +518=Replace disabled NodeLists with selected countries +519=Save in template.. +520=Load from template.. +521=Selected countries +522=Favorite nodes +523=Exclude nodes +524=Destroy +525=Sort +526=Filters +527=Circuit +528=Streams +529=All exit circuits +530=Purpose +531=Hide circuits without streams +532=Always show last exit circuit +533=Select exit circuit when it changes +534=Show traffic of circuits +535=Show traffic of streams +536=Show streams detail +537=Update rate +538=High +539=Normal +540=Low +541=Update manually +542=Open in browser +543=Binding to the exit node +544=Source +545=Destination +546=Lists +547=Node type +548="Hash","Nickname","IPv4","IPv6","OR-port","DIR-port","Version","Ping" +549=Enter a request +550=Exit +551=Guard +552=Ordinary +553=Authority +554=Cached Bridge +555=Fast +556=Stable +557=2nd Directory version +558=Hidden service directory +559=Directory mirror +560=Recommended version +561=Alive node +562=Reverse filter conditions +563=Reset filters +564=Select as bridge +565=Cancel the use of bridges.. +566=Consensus weight +567=User query +568=Show flag hints on mouse hover +569=Load relays from cache on startup +570=Prevent selection of unsuitable nodes as a bridge +571=Convert IP, CIDR and country codes to hashes +572=When clearing the incorrect nodes +573=When adding to the node list +574=When deleting from the node list +575=Convert IP addresses +576=Convert CIDR masks +577=Convert country codes +578=Ignore the list of excluded nodes +579=Avoid adding incorrect nodes +580=Disable filters on event +581=Sending a user query +582=Choosing Bridges or Authority nodes +583=Save as Default filter +584=All favorites +585=Incorrect nodes +586=Missing from the consensus +587=Transports Folder +588=Default settings +589=Period +590=Show Graphs +591=Middle nodes without directories + +[Deutsch] +Locale=1031 +100=Starten +101=Starte... +102=Anhalten +103=Kette\nändern +104=Standard +105=Tor Control Panel +106=%s\nProfil: %s +107=Einstellungen +108=Protokoll +109=Nicht erhalten +110=Nicht definiert +111=Empfange... +112=Definiere... +113=IP-Adresse +114=Land +115=Übernehmen +116=Abbrechen +117=Erstellen.. +118=Allgemein +119=Netzwerk +120=Filter +121=Server +122=Versteckte Dienste +123=Sonstiges +124=Die Kette ändern der länger existiert als +125=Intervall zwischen Versuchen, eine Kette aufzubauen +126=Maximale Zeit zum Aufbau einer Kette +127=Port +128=Authentifizierung +129="Cookie-Datei","Passwort" +130=Passwort +131=Zufälliges Passwort erstellen +132=Sprache +133=Desktop-Verknüpfung mit neuem Profil +134=Profile +135=Sek. +136=Automatische Auswahl der Zeit zum Aufbau einer Kette +137=Erstellen Sie keine Ketten von Knoten desselben Subnetzes +138=Weniger Festplattenoperationen ausführen +139=Beim Programmstart verbinden +140=Neustart bei verlorener Verbindung zum Client +141=Beim Starten in die Tray minimieren +142=Beim Schließen in die Tray minimieren +143=Pop-Up Benachrichtungen anzeigen +144=Nur wenn Programm minimiert +145=Immer im Vordergrund +146=Umwandlung in Hashes inklusive +147=Firewall lässt Verbindungen nur zu diesen Ports zu +148=Erlaubte Ports +149=Integrierten Proxy aktivieren +150=Ich verwenden einen Proxy +151=Typ +152=Host +153=Port +154=Benutzer +155=Brücken benutzen +156=Passwort eingeben +157=Kommagetrennte Werte +158=IP-Adresse oder Hostname +159=Optional +160=Beim Sortieren nach oben scrollen +161=Die aktuelle vanguards-Konfiguration für versteckte Dienste erfordert mindestens %d Favoriten Eintrag Knoten (Gefunden: %d). \n\nKorrigieren Sie das Problem und speichern Sie Ihre Einstellungen weiter? +162=Modus +163=Nicht verwendete Länder ausblenden +164=Diese Aktion erfordert einen Neustart von Tor +165="Deaktiviert","Ausgewählte Länder","Favoritenknoten" +166=Modus +167=Spitzname +168=Kontaktinfo +169=Brückentyp +170=Exit-Richtlinie +171=Server +172=Verzeichnis +173=Transport +174=Speichernutzung begrenzen +175=Maximum +176=Geschwindigkeit begrenzen +177=CPU-Nutzung begrenzen +178=Max. Kerne +179=Durchschnitt +180=s +181=Port-Weiterleitung prüfen +182=Versuche Port-Weiterleitung automatisch zu konfigurieren +183=Server im Relay-Verzeichnis veröffentlichen +184=Aktivieren Sie den Relay-Verzeichnisspiegel +185=Statistiken über Verzeichnisabfragen sammeln +186=Statistiken über deine Rolle als Verborgener Dienst sammeln +187=IPv6-Verkehr zum Ausgang zulassen +188=Name deines Relays +189=E-Mailadresse +190=Name +191=Katalogname +192=Anzahl der Verbindungen begrenzen +193=Verbindungen pro Zweig +194=Protokollversion +195=Einstiegspunkte +196=Veröffentlichungsintervall +197=Min. +198=Service +199=Zustand +200=Virtueller Post +201=Exit-Knoten für bestimmte Hosts speichern +202=Ändern nach Ablauf von +203=Gesamt +204=Warnung: Die Deaktivierung des Verzeichnis-Caches wird den Server beschleunigen, aber Ihr Server wird nie zu einem Guard. Möchten Sie fortfahren? +205="Deaktiviert","Relais","Exit-relais","Brücke" +206=Normal +207="Standard","Reduziert","Beliebig" +208=\n Hier klicken um Adressen hinzuzufügen\n\n Beispiele:\n\n Ip: 8.8.8.8\n Seite: metrics.torproject.org\n Domäne:.torproject.org\n Alle:. +209=\n Hier klicken um Knotten hinzuzufügen\n\n Beispiele:\n\n Ip: 8.8.8.8\n CIDR: 8.8.8.8/24\n Land: RU,DE,US,..\n Hash: ABCD1234CDEF567.. +210=\n Hier klicken um Brücken hinzuzufügen\n\n Beispiele:\n\n 8.8.8.8:443\n 8.8.8.8:443 ABCD1234CDEF567..\n obfs4 8.8.8.8:443 ABCD1234CDEF567.. cert=.. iat-mode=..\n\n Hinweis:\n\n Brücken überschreiben die EntryNodes-Einstellungen +211=Geschwindigkeit +212=Download +213=Upload +214=Empfangen +215=Gesendet +216=Server +217=Externe Adresse +218=Fingerabdruck +219=Brücken-Addresse +220=Geschwindigkeits-Diagramm +221=Erstelldatum +222=Information +223=Client version +224=Profil +225=Integrierter Proxy +226=Deaktiviert +227=Profil-Ordner öffnen +228=In Zwischenablage kopieren +229=Gesamt pro Sitzung +230=Name,Version,Einstiegepunkte,Verbindungen +231=Schnittstelle,Port,Virtueller Port +232=Spitzname,IP-adresse,,Land,Gewicht,Ping +233=ID,,Land,Gesamt,Guard,Exit,Alive,∑ Ping +234=B,KB,MB,GB,TB,PB,EB +235=Informationen +236=Fehler beim analyiseren der torcc Konfigurationsdatei. Protokolldatei für mehr Details ansehen +237=Verbinden zum Tor Netzwerk angehalten. Das Passwort für den Kontroll-Port ist falsch! +238=Die ausführbare Tor-Datei lässt sich nicht starten. Vielleicht ist er:\n\n - beschädigt oder ist keine Windows-Anwendung\n - ist eine 64-Bit-Anwendung, während du ein 32-Bit-Betriebssystem hast +239=Die ausführbare Tor-Datei wurde nicht gefunden. Lade das Tor Windows Expert Bundle herunter und entpacke es in das Programmverzeichnis. Jetzt gleich zur Download-Seite gehen? +240=Verbinde zum Tor Netzwerk... +241=Sie haben die Verbindung zum Tor Netzwerk getrennt +242=Kein Gerät das Port-Weiterleitungen unterstützt gefunden +243=Ergebnis +244=Quelle,Ziel,Zweck +245=Erfolgreich +246=Warnung +247=Fehler +248=Der Name darf nicht leer sein! +249=Der Name wird bereits von einem anderen Dienst verwendet! +250=Port-Liste +251=Du musst mindestens einen Port hinzufügen! +252=Die Kombination von Schnittstelle und Port existiert bereits! +253=Passwort für Kontroll-Port geändert +254=Fehler beim Laden der Vorlage: Parameter falsch eingestellt! +255=Sie können das Trennzeichen " %s " nicht verwenden. +256=Vorlage speichern +257=Vorlagenname eingeben +258=Die Kette wird geändert +259=Der Start wird gestoppt. Die in den Programmeinstellungen festgelegten Ports sind bereits in Verwendung!\n\nBelegte Ports: %s\n\nZufällige Ports verwenden und fortfahren? +260=Nicht definiert +261=Du kannst Bridges, Proxies und erlaubte Ports nicht im Server-Modus benutzen!\n\nDiese Optionen deaktivieren und die Einstellungen weiterhin speichern? +262=Bestätigung +263=Möchtest Du %s"%s" wirklich löschen? +264=Alle Vorlagen +265=Verknüpfung erstellen +266=Profilname eingeben +267=Alle Dienste +268=Möchten Sie wirklich:\n\n%s\n\nzur Liste der "%s-Knoten" hinzufügen?%s +269=Nur lateinische Buchstaben und Zahlen verwenden +270=und +271=Tor Konfigurationsdatei +272=Panel bearbeiten +273=Dienst-Ordner +274=Kopieren +275=Einfügen +276=Ausschneiden +277=Alle auswählen +278=Leeren +279=Hinzufügen +280=Löschen +281=Relay-Info +282=Status +283=DNS-Cache leeren +284=Aktualisieren +285=Ändern der Knotenliste +286=Vorlage auswähken +287=Exclude +288=Entry +289=Middle +290=Exit +291=Bridges holen +292=In Datei schreiben +293=Bei jedem Start leeren +294=Automatisch Scrollen +295=Scrollbalken +296=Vertikal +297=Horizontal +298=Beide +299=Nein +300=Zeilenumbruch +301=Netzwerk-Adressen ausblenden +302=Protokollstufe +303=Debug +304=Info +305=Notiz +306=Warnung +307=Fehler +308=Protokolldatei öffnen +309=Statistiken +310=Relay +311=Guard +312=Exit +313=Gesamt nach Ländern +314=Speichern +315=Laden +316=Alle ausgewählt +317=Anzahl der wartenden Client-Ketten +318=Ausgeschlossene Knoten für interne Ketten zulassen +319=Schließen +320=Spitzname,IP-Adresse,,Land,Gewicht,Port,Version,Ping,Flags +321=Gezeigt: %d von %d +322=\n Liste der Hashes, die Ihre Familie definieren\n\n Beispiel:\n\n ABCD1234CDEF567.. +323=Relais +324=Falsche Einstellungen +325=Gehen Sie zur Tor-Download-Seite +326=Das Hidden Services Protocol Version 2 ist veraltet, seine Unterstützung wurde in Version 0.4.6.1 und höher eingestellt. Möchten Sie diese Version des Protokolls wirklich verwenden? +327=Ketten +328=Fenster verkleinern +329=Zweck +330=Zieladresse +331=Dir-Anfrage +332=Interner Verkehr +333=Exit Verkehr +334=HS-Client: Dir-Anfrage +335=HS-Client: Intro-punkt +336=HS-Client: Rend-punkt +337=HS-Dienst: Dir-Anfrage +338=HS-Dienst: Intro-punkt +339=HS-Dienst: Rend-punkt +340=HS vanguards +341=Pfad-Bias-Tests +342=Erreichbarkeitstests +343=Schließzeitmaskierung +344=Timeout-Messung +345=Anderer Zweck +346=Aufmerksamkeit! Häufiges Wechseln der Guard-Knoten kann Angreifern helfen, Sie zu entdecken. Nur verwenden, wenn es absolut notwendig ist. %sMöchten Sie fortfahren? +347=(Alle Länder) +348=(Im Filter ausgewählt) +349=Ketten: %d von %d +350=Ströme +351=Bindung an den Exit-knoten +352=Entbinden vom Exit-knoten +353=Globale Domäne +354=Die Programmeinstellungen wurden geändert! Möchtest du die Änderungen anwenden? +355=Über das Programm... +356=%s, version: %s\n\n%s\n\n(Windows GUI Client für Tor Expert Bundle)\n\n%s\n\nMöchten Sie die Programmseite auf GitHub besuchen? +357=Dieses Programm ist freie Software und wird unter der MIT-Lizenz vertrieben. +358=Knoten, die im Konsens fehlen, werden aus Benutzerlisten entfernt.\n\nIgnore die Liste der Exlude-Knoten beim Scannen? +359=Aus Listen entfernen +360=Automatische Relais-Auswahl +361=Wollen Sie wirklich entfernen:\n\n%s\n\naus allen Knotenlisten?%s +362=Wollen Sie wirklich entfernen:\n\n%s\n\naus der Liste "%s Knoten"?%s +363=Vorlage "%s" erfolgreich gespeichert +364=Vorlage "%s" erfolgreich geladen +365=Vorlage "%s" erfolgreich gelöscht +366=vorlage +367=dienst +368=Alle auswählen +369=Alle abwählen +370=Dir-Anfrage +371=Dir-Download +372=Dir-Port-Tests +373=DNS-Abfrage +374=Normaler Verkehr +375=Anderer Zweck +376=Interner Sockel +377=Tor Windows Expert Bundle Version 0.4.0.5 und höher ist für den normalen Betrieb des Programms erforderlich. +378=Kann "%s" nicht finden +379=ms +380=Automatischer Modus +381=Manueller Modus +382=Ping-Messung +383=Erkennung Alive Knoten +384=Brücke (Guard-Knoten) +385=Behörde +386=Alive (reagiert auf Verbindungen) +387=Akzeptiert IPv6-Verbindungen +388=Versteckte Dienste-Katalog +389=Verzeichnisspiegel (Port: %d) +390=Nicht empfohlene Version +391=Schlechter Exit-Knoten +392=Unbekannte Flagge +393=Transporte,Handler,Typ +394=Die Transportliste darf keine leeren Daten enthalten +395=Handler-Datei nicht gefunden, kopieren Sie sie in das Transportverzeichnis und versuchen Sie es erneut +396=Erkennung lebenden Brücken +397=Neueste unterstützte Version für Ihr Betriebssystem: 0.4.4.6 +398=Ziffern am Wortanfang sind nicht erlaubt +399=Transport mit diesem Namen und Typ ist bereits vorhanden +400=Brücken werden gescannt...\n\nBitte warten Sie bis zum Ende und versuchen Sie es erneut. +401=Keine Verbindung +402=Beginn der zählung: %s +403=Insgesamt für alle Zeiten +404=Hör auf zu scannen.. +405=Möchten Sie wirklich: "%s"\n\nDie ausgewählte Aktion kann nicht rückgängig gemacht werden! +406=Alles löschen +407=Ermitteln Sie die externe Adresse des Servers über OpenDNS +408=Nur wenn TOR es nicht selbst erkennen kann +409=IP-cc Anfragen und Netzwerkscanner-Ergebnisse zwischenspeichern +410=Grundeinstellungen +411=Schnittstelle +412=Kontrolle +413=Thema +414=Erlauben, dass das Fenster über den Bildschirm hinausgeht +415=Nur wenn das Programmfenster vergrößert wird +416=Merken Sie sich die Position des vergrößerten Fensters +417=IPv6-Adressen in Schnittstellenlisten ausblenden +418=Vorherige Suchanfrage in Listen löschen +419=Liste der Brücken +420=Bevorzugte Brücke manuell einstellen +421=Brücke +422=Diese Einstellung überschreibt die ausgewählte Liste der Brücken +423=Finden... +424="Eingebaut","Benutzerdefiniert" +425=Verbreitung +426="Irgendein","Https","E-mail","Moat","Nicht verteilen" +427=Externe Adresse manuell einstellen +428=Adresse +429=IP-Adresse oder Hostname +430=Ports-Einstellungen +431=Angepriesene +432=Verwenden Sie den Verzeichnis-Cache +433=Server-Erreichbarkeitsprüfung deaktivieren +434=Lauschen auf IPv6-Adressen +435=MyFamily-Option verwenden +436="Aktiviert","Deaktiviert" +437=Verwenden Sie Vanguards für versteckte Dienste +438=Ändern Sie den Kettenknoten +439="Automatisch","Nur Zweiter","Nur Dritter","Zweiter und dritter" +440=Wählen Sie die zu bearbeitende Liste aus +441=Liste +442="Entry-Knoten","Middle-Knoten","Exit-Knoten","Exclude-Knoten" +443=Aktiviert +444=Netzwerkscanner +445=Erkennung Alive Knoten aktivieren +446=Ping-Messung aktivieren +447=Timeout der Portverbindung +448=Anzahl der Port-Verbindungsversuche +449=Timeout für Ping-Anfragen +450=Anzahl der Versuche, den Ping zu messen +451=Verzögerung zwischen Versuchen +452=Anzahl der Scanfäden +453=Verzögerung zwischen den Portionen +454=Anzahl der Scans pro Portion +455=Automatische Erkennung von Ping und Alive Knoten +456=Vollständiger Scan alle +457=Scan-Knoten ohne Antwort alle +458=Anzahl der Teilscans +459=msek. +460=Steckbare Transporte +461=Transporte +462=Liste der unterstützten Transporte +463=Handler +464=Dateinamen eingeben +465=Parameters +466="Client","Server","Kombiniert" +467=Automatische Relais-Auswahl +468=Gewicht +469=Ping +470=Stk. +471=Priorität +472="Ausgewogen","Gewicht im Konsens","Ping zum Knoten","Zufällig" +473=Nur stabil +474=Nur Länder aus dem Filter +475=Nur einzigartig +476=Nur Knoten, die auf Ping reagieren +477=Uhr. +478=Cache-Operationen +479=Länder im Netzwerk-Cache aktualisieren +480=Server-Cache Leeren +481=Leeren Sie den Cache für unnötige Brücken +482=Leeren Sie den Cache alle Brücken +483=Leeren Sie den Cache Ping-Abfragen +484=Leeren Sie den Cache von Alive-Knoten +485=Leeren Sie den ungenutzter Netzwerk-Cache +486=Scan-Zeitplan für Knoten zurücksetzen +487=Verkehrszähler zurücksetzen +488=Starten Sie den Netzwerkscanner +489=Neue Knoten +490=Nicht reagierende Knoten +491=Zwischengespeicherte Brücken +492=Alle Knoten +493=Ping-Messung +494=Erkennung Alive Knoten +495=Scannen stoppen... +496=Guard-Knoten zurücksetzen +497=Alle Guard-Knoten +498=Brückenknoten +499=Ausgewählte Entry-knoten +500=Standard Entry-Knoten +501=Webseite +502=Telegramm-Kanal +503=Email +504=Bevorzugen Sie die Webversion von Telegram +505=Verschleierte Brücken abfragen +506=IPv6-Brücken anfordern +507=Reagiert nicht auf Verbindungen +508=Fehlt im Cache +509=Im Cache gefunden +510=Alle Brücken +511=Aufteilen der Protokolldatei +512=Nicht spalten +513=Nach Monat +514=Nach Tag +515=Alle Zellen in einer Zeile markieren +516=Laden Sie keine leeren Vorlagendaten +517=Ladeoptionen aus der Vorlage außerhalb des Filters ignorieren +518=Ersetzen Sie deaktivierte Listen von Knoten durch ausgewählte Länder +519=In Vorlage speichern.. +520=Aus Vorlage laden.. +521=Ausgewählte Länder +522=Favoritenknoten +523=Exclude-Knoten +524=Zerstören +525=Sortieren +526=Filters +527=Kette +528=Ströme +529=Alle Exit-Ketten +530=Zweck +531=Ketten ohne Ströme ausblenden +532=Immer letzten Exit-Kette anzeigen +533=Hervorheben der Exit-kette, wenn Sie sie ändern +534=Verkehrs der Ketten anzeigen +535=Verkehrs der Ströme anzeigen +536=Ströme details anzeigen +537=Aktualisierungsrate +538=Hoch +539=Normal +540=Niedrig +541=Manuell aktualisieren +542=Im Browser öffnen +543=Bindung an den Exit-Knoten +544=Quelle +545=Ziel +546=Listen +547=Knotentyp +548="Hash","Spitzname","IPv4","IPv6","OR-port","DIR-port","Version","Ping" +549=Geben Sie eine Abfrage ein +550=Exit +551=Guard +552=Ordinär +553=Behörde +554=Zwischengespeicherte Brücke +555=Schneller +556=Stabiler +557=Zweite Verzeichnisversion +558=Versteckte Dienste-Katalog +559=Verzeichnisspiegel +560=Empfohlene Version +561=Alive-Knoten +562=Umkehrung der Filterbedingungen +563=Filter zurücksetzen +564=Als Brücke auswählen +565=Brechen Sie die Verwendung von Brücken ab.. +566=Gewicht im Konsens +567=Benutzerabfrage +568=Flaggenhinweise beim Mauszeiger anzeigen +569=Relais beim Start aus dem Cache laden +570=Verhindern Sie die Auswahl ungeeigneter Knoten als Brücke +571=Konvertieren Sie IP, CIDR und Ländercodes in Hashes +572=Beim Löschen der falschen Knoten +573=Beim Hinzufügen zur Knotenliste +574=Beim Löschen aus der Knotenliste +575=IP-Adressen konvertieren +576=CIDR-Masken konvertieren +577=Ländercodes konvertieren +578=Ignorieren Sie die Liste der ausgeschlossenen Knoten +579=Vermeiden Sie das Hinzufügen Falscher Knoten +580=Filter bei Ereignis deaktivieren +581=Senden einer Benutzeranfrage +582=Auswahl von Brücken oder Behördenknoten +583=Als Standardfilter speichern +584=Alle Favoriten +585=Falscher Knoten +586=Die im Konsens fehlen +587=Transporte-Ordner +588=Standard-Einstellungen +589=Zeitraum +590=Grafiken anzeigen +591=Middle-Knoten ohne Verzeichnisse + +au=Australien +at=Österreich +az=Aserbaidschan +ax=Alandinseln +al=Albanien +dz=Algerien +as=Amerikanisch-Samoa +ai=Anguilla +ao=Angola +ad=Andorra +aq=Antarktis +ag=Antigua und Barbuda +ar=Argentinien +am=Armenien +aw=Aruba +af=Afghanistan +bs=Bahamas +bd=Bangladesch +bb=Barbados +bh=Bahrain +bz=Belize +by=Weißrussland +be=Belgien +bj=Benin +bm=Bermuda +bg=Bulgarien +bo=Bolivien +bq=Bonaire +ba=Bosnien und Herzegowina +bw=Botswana +br=Brasilien +io=Britisches Territorium im Indischen Ozean +bn=Brunei +bf=Burkina Faso +bi=Burundi +bt=Bhutan +vu=Vanuatu +va=Vatikanstadt +gb=Großbritannien +hu=Ungarn +ve=Venezuela +vg=Britische Jungferninseln +vi=Amerikanische Jungferninseln +um=Amerikanisch-Ozeanien +tl=Timor-Leste +vn=Vietnam +ga=Gabun +gy=Guyana +ht=Haiti +gm=Gambia +gh=Ghana +gp=Guadeloupe +gt=Guatemala +gf=Französisch-Guayana +gn=Guinea +gw=Guinea-Bissau +de=Deutschland +gg=Guernsey +gi=Gibraltar +hn=Honduras +hk=Hongkong +ps=Palästina +gd=Grenada +gl=Grönland +gr=Griechenland +ge=Georgien +gu=Guam +dk=Dänemark +cd=Demokratische Republik Kongo +je=Jersey +dj=Dschibuti +dm=Dominica +do=Dominikanische Republik +eg=Ägypten +zm=Sambia +zw=Simbabwe +ye=Jemen +il=Israel +in=Indien +id=Indonesien +jo=Jordanien +iq=Irak +ir=Iran +ie=Irland +is=Island +es=Spanien +it=Italien +cv=Kapverden +kz=Kasachstan +kh=Kambodscha +cm=Kamerun +ca=Kanada +qa=Katar +ke=Kenia +cy=Zypern +kg=Kirgistan +ki=Kiribati +cn=China +kp=Nordkorea +cc=Kokosinseln +co=Kolumbien +km=Komoren +cr=Costa Rica +ci=Elfenbeinküste +cu=Kuba +kw=Kuwait +cw=Kyurasao +la=Laos +lv=Lettland +ls=Lesotho +lr=Liberia +lb=Libanon +ly=Libyen +lt=Litauen +li=Liechtenstein +lu=Luxemburg +mu=Mauritius +mr=Mauretanien +mg=Madagaskar +yt=Mayotte +mo=Macau +mk=Nordmazedonien +mw=Malawi +my=Malaysia +ml=Mali +mv=Malediven +mt=Malta +ma=Marokko +mq=Martinique +mh=Marshall-Inseln +mx=Mexiko +fm=Mikronesien +mz=Mosambik +md=Moldau +mc=Monaco +mn=Mongolei +ms=Montserrat +mm=Myanmar +na=Namibia +nr=Nauru +np=Nepal +ne=Niger +ng=Nigeria +nl=Niederlande +ni=Nikaragua +nu=Niue +nz=Neuseeland +nc=Neukaledonien +no=Norwegen +ae=Vereinigte Arabische Emirate +om=Oman +bv=Bouvetinsel +im=Isle of Man +nf=Norfolkinsel +cx=Weihnachtsinsel +ky=Kaimaninseln +ck=Cookinseln +pn=Pitcairn +sh=St. Helena +pk=Pakistan +pw=Palau +pa=Panama +pg=Papua-Neuguinea +py=Paraguay +pe=Peru +pl=Polen +pt=Portugal +pr=Puerto Rico +cg=Kongo +kr=Südkorea +re=Réunion +ru=Russland +rw=Ruanda +ro=Rumänien +eh=Westsahara +sv=El Salvador +ws=Samoa +sm=San Marino +st=São Tomé und Príncipe +sa=Saudi-Arabien +sz=Swasiland +mp=Nördliche Marianen +sc=Seychellen +bl=St. Barthélemy +sn=Senegal +mf=St. Martin +pm=St. Pierre und Miquelon +vc=St. Vincent und die Grenadinen +kn=Saint Kitts und Nevis +lc=St. Lucia +rs=Serbien +sg=Singapur +sx=Sint Maarten +sy=Syrien +sk=Slowakei +si=Slowenien +sb=Solomon-Inseln +so=Somalia +sd=Sudan +sr=Suriname +us=USA +sl=Sierra Leone +tj=Tadschikistan +tw=Taiwan +th=Thailand +tz=Tansania +tc=Turks- und Caicosinseln +tg=Togo +tk=Tokelau +to=Tonga +tt=Trinidad und Tobago +tv=Tuwalu +tn=Tunesien +tm=Turkmenistan +tr=Türkei +ug=Uganda +uz=Usbekistan +ua=Ukraine +wf=Wallis und Futuna +uy=Uruguay +fo=Färöer-Inseln +fj=Fidschi +ph=Philippinen +fi=Finnland +fk=Falklandinseln +fr=Frankreich +pf=Französisch-Polynesien +tf=Französische Süd- und Antarktisgebiete +hm=Heard- und McDonald-Inseln +hr=Kroatien +cf=Zentralafrikanische Republik +td=Tschad +me=Montenegro +cz=Tschechien +cl=Chile +ch=Schweiz +se=Schweden +sj=Svalbard und Jan Mayen +lk=Sri Lanka +ec=Ecuador +gq=Äquatorialguinea +er=Eritrea +ee=Estland +et=Äthiopien +za=Südafrika +gs=Südgeorgien und die Südlichen Sandwichinseln +ss=Südsudan +jm=Jamaika +jp=Japan +eu=Europäische Union +??=Unbekannte + +[DefaultCountries] +au=Australia +at=Austria +az=Azerbaijan +ax=Aland Islands +al=Albania +dz=Algeria +as=American Samoa +ai=Anguilla +ao=Angola +ad=Andorra +aq=Antarctica +ag=Antigua and Barbuda +ar=Argentina +am=Armenia +aw=Aruba +af=Afghanistan +bs=Bahamas +bd=Bangladesh +bb=Barbados +bh=Bahrain +bz=Belize +by=Belarus +be=Belgium +bj=Benin +bm=Bermuda +bg=Bulgaria +bo=Bolivia +bq=Bonaire, Sint Eustatius, and Saba +ba=Bosnia and Herzegovina +bw=Botswana +br=Brazil +io=British Indian Ocean Territory +bn=Brunei +bf=Burkina Faso +bi=Burundi +bt=Bhutan +vu=Vanuatu +va=Vatican City +gb=United Kingdom +hu=Hungary +ve=Venezuela +vg=British Virgin Islands +vi=U.S. Virgin Islands +um=U.S. Minor Outlying Islands +tl=East Timor +vn=Vietnam +ga=Gabon +gy=Guyana +ht=Haiti +gm=Gambia +gh=Ghana +gp=Guadeloupe +gt=Guatemala +gf=French Guiana +gn=Guinea +gw=Guinea-Bissau +de=Germany +gg=Guernsey +gi=Gibraltar +hn=Honduras +hk=Hong Kong +ps=Palestine +gd=Grenada +gl=Greenland +gr=Greece +ge=Georgia +gu=Guam +dk=Denmark +cd=Democratic Republic of the Congo +je=Jersey +dj=Djibouti +dm=Dominica +do=Dominican Republic +eg=Egypt +zm=Zambia +zw=Zimbabwe +ye=Yemen +il=Israel +in=India +id=Indonesia +jo=Jordan +iq=Iraq +ir=Iran +ie=Ireland +is=Iceland +es=Spain +it=Italy +cv=Cabo Verde +kz=Kazakhstan +kh=Cambodia +cm=Cameroon +ca=Canada +qa=Qatar +ke=Kenya +cy=Cyprus +kg=Kyrgyzstan +ki=Kiribati +cn=China +kp=North Korea +cc=Cocos Islands +co=Colombia +km=Comoros +cr=Costa Rica +ci=Ivory Coast +cu=Cuba +kw=Kuwait +cw=Kyurasao +la=Laos +lv=Latvia +ls=Lesotho +lr=Liberia +lb=Lebanon +ly=Libya +lt=Lithuania +li=Liechtenstein +lu=Luxembourg +mu=Mauritius +mr=Mauritania +mg=Madagascar +yt=Mayotte +mo=Macao +mk=North Macedonia +mw=Malawi +my=Malaysia +ml=Mali +mv=Maldives +mt=Malta +ma=Morocco +mq=Martinique +mh=Marshall Islands +mx=Mexico +fm=Federated States of Micronesia +mz=Mozambique +md=Moldova +mc=Monaco +mn=Mongolia +ms=Montserrat +mm=Myanmar +na=Namibia +nr=Nauru +np=Nepal +ne=Niger +ng=Nigeria +nl=Netherlands +ni=Nicaragua +nu=Niue +nz=New Zealand +nc=New Caledonia +no=Norway +ae=United Arab Emirates +om=Oman +bv=Bouvet Island +im=Isle of Man +nf=Norfolk Island +cx=Christmas Island +ky=Cayman Islands +ck=Cook Islands +pn=Pitcairn Islands +sh=Saint Helena +pk=Pakistan +pw=Palau +pa=Panama +pg=Papua New Guinea +py=Paraguay +pe=Peru +pl=Poland +pt=Portugal +pr=Puerto Rico +cg=Congo Republic +kr=South Korea +re=Réunion +ru=Russia +rw=Rwanda +ro=Romania +eh=Western Sahara +sv=El Salvador +ws=Samoa +sm=San Marino +st=Sao Tome and Principe +sa=Saudi Arabia +sz=Eswatini +mp=Northern Mariana Islands +sc=Seychelles +bl=Saint Barthélemy +sn=Senegal +mf=Saint Martin +pm=Saint Pierre and Miquelon +vc=Saint Vincent and the Grenadines +kn=St Kitts and Nevis +lc=Saint Lucia +rs=Serbia +sg=Singapore +sx=Sint Maarten +sy=Syria +sk=Slovakia +si=Slovenia +sb=Solomon Islands +so=Somalia +sd=Sudan +sr=Suriname +us=United States +sl=Sierra Leone +tj=Tajikistan +tw=Taiwan +th=Thailand +tz=Tanzania +tc=Turks and Caicos Islands +tg=Togo +tk=Tokelau +to=Tonga +tt=Trinidad and Tobago +tv=Tuvalu +tn=Tunisia +tm=Turkmenistan +tr=Turkey +ug=Uganda +uz=Uzbekistan +ua=Ukraine +wf=Wallis and Futuna +uy=Uruguay +fo=Faroe Islands +fj=Fiji +ph=Philippines +fi=Finland +fk=Falkland Islands +fr=France +pf=French Polynesia +tf=French Southern Territories +hm=Heard Island and McDonald Islands +hr=Croatia +cf=Central African Republic +td=Chad +me=Montenegro +cz=Czechia +cl=Chile +ch=Switzerland +se=Sweden +sj=Svalbard and Jan Mayen +lk=Sri Lanka +ec=Ecuador +gq=Equatorial Guinea +er=Eritrea +ee=Estonia +et=Ethiopia +za=South Africa +gs=South Georgia and the South Sandwich Islands +ss=South Sudan +jm=Jamaica +jp=Japan +eu=European Union +??=Unknown