├── info ├── logo.png └── screenshot.png ├── images ├── icon.ico ├── header.png └── status │ ├── alert.png │ ├── normal.png │ └── inactive.png ├── main.cpp ├── torbridgescollector.qrc ├── showqrcode.cpp ├── showqrcode.h ├── aboutpage.h ├── aboutpage.cpp ├── getbridgeswindow.h ├── TorBridgesCollector.pro ├── getbridgeswindow.cpp ├── entercaptcha.h ├── settingsdialog.h ├── README.md ├── torbridgescollector.h ├── showqrcode.ui ├── entercaptcha.ui ├── getbridgeswindow.ui ├── aboutpage.ui ├── settingsdialog.cpp ├── LICENSE ├── torbridgescollector.cpp ├── torbridgescollector.ui ├── entercaptcha.cpp └── settingsdialog.ui /info/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izmukx/TorBridgesCollector/HEAD/info/logo.png -------------------------------------------------------------------------------- /images/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izmukx/TorBridgesCollector/HEAD/images/icon.ico -------------------------------------------------------------------------------- /images/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izmukx/TorBridgesCollector/HEAD/images/header.png -------------------------------------------------------------------------------- /info/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izmukx/TorBridgesCollector/HEAD/info/screenshot.png -------------------------------------------------------------------------------- /images/status/alert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izmukx/TorBridgesCollector/HEAD/images/status/alert.png -------------------------------------------------------------------------------- /images/status/normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izmukx/TorBridgesCollector/HEAD/images/status/normal.png -------------------------------------------------------------------------------- /images/status/inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izmukx/TorBridgesCollector/HEAD/images/status/inactive.png -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "torbridgescollector.h" 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | QApplication a(argc, argv); 9 | TorBridgesCollector w; 10 | w.show(); 11 | return a.exec(); 12 | } 13 | -------------------------------------------------------------------------------- /torbridgescollector.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/header.png 4 | images/status/normal.png 5 | images/status/inactive.png 6 | images/status/alert.png 7 | 8 | 9 | -------------------------------------------------------------------------------- /showqrcode.cpp: -------------------------------------------------------------------------------- 1 | #include "showqrcode.h" 2 | #include "ui_showqrcode.h" 3 | 4 | ShowQRCode::ShowQRCode(QWidget *parent) : 5 | QDialog(parent), 6 | ui(new Ui::ShowQRCode) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | void ShowQRCode::setQRCode(QPixmap qrcode) 12 | { 13 | ui->QRCode->setPixmap(qrcode); 14 | } 15 | 16 | ShowQRCode::~ShowQRCode() 17 | { 18 | delete ui; 19 | } 20 | -------------------------------------------------------------------------------- /showqrcode.h: -------------------------------------------------------------------------------- 1 | #ifndef SHOWQRCODE_H 2 | #define SHOWQRCODE_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class ShowQRCode; 8 | } 9 | 10 | class ShowQRCode : public QDialog 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit ShowQRCode(QWidget *parent = 0); 16 | ~ShowQRCode(); 17 | void setQRCode(QPixmap qrcode); 18 | 19 | private: 20 | Ui::ShowQRCode *ui; 21 | }; 22 | 23 | #endif // SHOWQRCODE_H 24 | -------------------------------------------------------------------------------- /aboutpage.h: -------------------------------------------------------------------------------- 1 | #ifndef ABOUTPAGE_H 2 | #define ABOUTPAGE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace Ui { 9 | class AboutPage; 10 | } 11 | 12 | class AboutPage : public QDialog 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit AboutPage(QWidget *parent = 0); 18 | ~AboutPage(); 19 | 20 | private slots: 21 | void on_visitTorPage_clicked(); 22 | void on_visitCreatorsPage_pressed(); 23 | 24 | private: 25 | Ui::AboutPage *ui; 26 | }; 27 | 28 | #endif // ABOUTPAGE_H 29 | -------------------------------------------------------------------------------- /aboutpage.cpp: -------------------------------------------------------------------------------- 1 | #include "aboutpage.h" 2 | #include "ui_aboutpage.h" 3 | 4 | AboutPage::AboutPage(QWidget *parent) : 5 | QDialog(parent), 6 | ui(new Ui::AboutPage) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | void AboutPage::on_visitTorPage_clicked() 12 | { 13 | QDesktopServices::openUrl(QUrl("https://www.torproject.org")); 14 | } 15 | 16 | void AboutPage::on_visitCreatorsPage_pressed() 17 | { 18 | QDesktopServices::openUrl(QUrl("https://izmukx.github.io")); 19 | } 20 | 21 | AboutPage::~AboutPage() 22 | { 23 | delete ui; 24 | } 25 | -------------------------------------------------------------------------------- /getbridgeswindow.h: -------------------------------------------------------------------------------- 1 | #ifndef GETBRIDGESWINDOW_H 2 | #define GETBRIDGESWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace Ui { 9 | class GetBridgesWindow; 10 | } 11 | 12 | class GetBridgesWindow : public QDialog 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit GetBridgesWindow(QWidget *parent = 0); 18 | ~GetBridgesWindow(); 19 | void showRetrievedBridges(QString bridges, QPixmap qrcode, QString message); 20 | 21 | private slots: 22 | void on_copyToClipboard_clicked(); 23 | void on_showQRCode_clicked(); 24 | 25 | private: 26 | Ui::GetBridgesWindow *ui; 27 | QPixmap BridgesQRCode; 28 | 29 | }; 30 | #endif // GETBRIDGESWINDOW_H 31 | -------------------------------------------------------------------------------- /TorBridgesCollector.pro: -------------------------------------------------------------------------------- 1 | QT += core gui network 2 | 3 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 | 5 | TARGET = TorBridgesCollector 6 | TEMPLATE = app 7 | 8 | RC_ICONS = images/icon.ico 9 | 10 | DEFINES += QT_DEPRECATED_WARNINGS 11 | 12 | SOURCES += \ 13 | main.cpp \ 14 | torbridgescollector.cpp \ 15 | settingsdialog.cpp \ 16 | getbridgeswindow.cpp \ 17 | entercaptcha.cpp \ 18 | aboutpage.cpp \ 19 | showqrcode.cpp 20 | 21 | HEADERS += \ 22 | torbridgescollector.h \ 23 | settingsdialog.h \ 24 | getbridgeswindow.h \ 25 | entercaptcha.h \ 26 | aboutpage.h \ 27 | showqrcode.h 28 | 29 | FORMS += \ 30 | torbridgescollector.ui \ 31 | settingsdialog.ui \ 32 | getbridgeswindow.ui \ 33 | entercaptcha.ui \ 34 | aboutpage.ui \ 35 | showqrcode.ui 36 | 37 | RESOURCES += \ 38 | torbridgescollector.qrc 39 | -------------------------------------------------------------------------------- /getbridgeswindow.cpp: -------------------------------------------------------------------------------- 1 | #include "getbridgeswindow.h" 2 | #include "ui_getbridgeswindow.h" 3 | 4 | #include "showqrcode.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | GetBridgesWindow::GetBridgesWindow(QWidget *parent) : 11 | QDialog(parent), 12 | ui(new Ui::GetBridgesWindow) 13 | { 14 | ui->setupUi(this); 15 | } 16 | 17 | void GetBridgesWindow::showRetrievedBridges(QString bridges, QPixmap qrcode, QString message) 18 | { 19 | show(); 20 | ui->bridgesText->setPlainText(bridges); 21 | ui->retrievalMessage->setText(message); 22 | BridgesQRCode = qrcode; 23 | } 24 | 25 | void GetBridgesWindow::on_showQRCode_clicked() 26 | { 27 | ShowQRCode *QRCodeWindow = new ShowQRCode(this); 28 | QRCodeWindow->setQRCode(BridgesQRCode); 29 | QRCodeWindow->show(); 30 | } 31 | 32 | void GetBridgesWindow::on_copyToClipboard_clicked() 33 | { 34 | ui->bridgesText->selectAll(); 35 | ui->bridgesText->copy(); 36 | } 37 | 38 | GetBridgesWindow::~GetBridgesWindow() 39 | { 40 | delete ui; 41 | } 42 | -------------------------------------------------------------------------------- /entercaptcha.h: -------------------------------------------------------------------------------- 1 | #ifndef ENTERCAPTCHA_H 2 | #define ENTERCAPTCHA_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace Ui { 12 | class EnterCaptcha; 13 | } 14 | 15 | class EnterCaptcha : public QDialog 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | explicit EnterCaptcha(QWidget *parent = 0); 21 | ~EnterCaptcha(); 22 | void requestCaptcha(); 23 | void requestBridges(QString captchaInput, QString captchaToken); 24 | 25 | signals: 26 | void captchaLoadFinished(bool finished); 27 | void bridgesDataLoaded(QDateTime time); 28 | 29 | public slots: 30 | void bridgesLoaded(); 31 | 32 | private slots: 33 | void on_submitCaptcha_accepted(); 34 | void dataLoaded(); 35 | 36 | private: 37 | void captchaLoaded(); 38 | Ui::EnterCaptcha *ui; 39 | QString enterCaptchaToken; 40 | QNetworkReply *requestLoaded; 41 | QByteArray requestedData; 42 | QNetworkAccessManager networkAccess; 43 | void setProxy(); 44 | }; 45 | 46 | #endif // ENTERCAPTCHA_H 47 | -------------------------------------------------------------------------------- /settingsdialog.h: -------------------------------------------------------------------------------- 1 | #ifndef SETTINGSDIALOG_H 2 | #define SETTINGSDIALOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace Ui { 12 | class SettingsDialog; 13 | } 14 | 15 | class SettingsDialog : public QDialog 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | explicit SettingsDialog(QWidget *parent = 0); 21 | ~SettingsDialog(); 22 | 23 | private slots: 24 | void on_bridgesType_currentIndexChanged(QString type); 25 | void on_proxyType_currentIndexChanged(QString type); 26 | void on_torType_currentIndexChanged(QString type); 27 | void on_chooseTorrc_clicked(); 28 | void on_proxyPort_valueChanged(int port); 29 | void on_ipv6Support_toggled(bool option); 30 | void on_modTorrc_toggled(bool option); 31 | void on_modBridgesPath_toggled(bool option); 32 | void on_chooseBridgesPath_clicked(); 33 | void on_useProxy_toggled(bool option); 34 | 35 | public slots: 36 | void on_showIconInTray_toggled(bool option); 37 | void on_closeToTray_toggled(bool option); 38 | 39 | signals: 40 | void setTrayIcon(int action); 41 | 42 | private: 43 | Ui::SettingsDialog *ui; 44 | QString bridgesType; 45 | QString proxyType; 46 | QString torrcFilePath; 47 | int proxyPort; 48 | bool ipv6Support; 49 | bool useProxy; 50 | bool modTorrc; 51 | }; 52 | 53 | #endif // SETTINGSDIALOG_H 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Tor Bridges Collector 4 | 5 | 6 | 7 | Collects Tor bridges, so you don't have to. 8 | 9 | Tor Bridges Collector helps you frequently update your Tor bridges list. 10 | It also has options for modifying your torrc with new bridges on each retrieval, and storing all previously retrieved bridges in a file. 11 | 12 | # Install 13 | 14 | ### From releases 15 | 16 | [Download precompiled binaries](https://github.com/izmukx/TorBridgesCollector/releases) 17 | 18 | 19 | ### Building from sources 20 | 21 | 22 | **On Linux** 23 | 24 | Clone Tor Bridges Collector's repository 25 | 26 | ``` 27 | git clone https://github.com/izmukx/TorBridgesCollector.git 28 | ``` 29 | 30 | Run qmake 31 | 32 | ``` 33 | qmake TorBridgesCollector.pro -spec linux-g++ 34 | ``` 35 | 36 | Run make 37 | 38 | ``` 39 | make 40 | ``` 41 | 42 | Open the binary 43 | 44 | ``` 45 | ./TorBridgesCollector 46 | ``` 47 | 48 | **On Windows** 49 | 50 | The easiest way probably would be to download [Qt Creator](https://download.qt.io), import the project and build it there. 51 | 52 | 53 | ## LICENSE 54 | Tor Bridges Collector is being distributed under [GNU LGPL version 3 License](https://github.com/izmukx/TorBridgesCollector/blob/master/LICENSE) 55 | 56 | ## NOTICE 57 | This product is produced independently from the Tor® anonymity software and carries no guarantee from The Tor Project about quality, suitability or anything else. 58 | 59 | Created by [izmukx](https://izmukx.github.io) 60 | -------------------------------------------------------------------------------- /torbridgescollector.h: -------------------------------------------------------------------------------- 1 | #ifndef TORBRIDGESCOLLECTOR_H 2 | #define TORBRIDGESCOLLECTOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace Ui { 13 | class TorBridgesCollector; 14 | } 15 | 16 | class TorBridgesCollector : public QMainWindow 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | explicit TorBridgesCollector(QWidget *parent = 0); 22 | ~TorBridgesCollector(); 23 | 24 | public slots: 25 | void updateLastRetrievalTime(QDateTime time); 26 | void setTrayIcon(int action); 27 | 28 | private slots: 29 | void on_setRetrieveTime_returnPressed(); 30 | void on_setRetrieveTimeButton_clicked(); 31 | void on_retrieveNowButton_clicked(); 32 | void on_aboutButton_clicked(); 33 | void on_settingsButton_clicked(); 34 | void on_exitButton_clicked(); 35 | void until_next_retrieve_timer(); 36 | void setBridgesButton(bool active); 37 | void appTrayActivated(QSystemTrayIcon::ActivationReason trayReason); 38 | 39 | private: 40 | Ui::TorBridgesCollector *ui; 41 | QTime setBridgeRetrieval; 42 | QTime bridgeRetrievalTime; 43 | QTimer nextBridgeRetrieval; 44 | QString getTimeFormat(int timesecs); 45 | QSettings settings; 46 | QString torrrcPath; 47 | void getTime(QString timeraw); 48 | QStringList bridgesList; 49 | int bridgesType; 50 | int timeValue; 51 | int lastTimeValue; 52 | bool TorRetrievedBridges = false; 53 | QAction *windowShow; 54 | QAction *windowHide; 55 | QAction *windowQuit; 56 | QSystemTrayIcon *appTray; 57 | QMenu *appTrayMenu; 58 | }; 59 | 60 | #endif // TORBRIDGESCOLLECTOR_H 61 | -------------------------------------------------------------------------------- /showqrcode.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ShowQRCode 4 | 5 | 6 | 7 | 0 8 | 0 9 | 500 10 | 500 11 | 12 | 13 | 14 | 15 | 500 16 | 500 17 | 18 | 19 | 20 | 21 | 500 22 | 500 23 | 24 | 25 | 26 | QR Code 27 | 28 | 29 | 30 | 31 | 20 32 | 450 33 | 461 34 | 31 35 | 36 | 37 | 38 | Qt::Horizontal 39 | 40 | 41 | QDialogButtonBox::Ok 42 | 43 | 44 | true 45 | 46 | 47 | 48 | 49 | 50 | 50 51 | 20 52 | 401 53 | 401 54 | 55 | 56 | 57 | Loading QR Code... 58 | 59 | 60 | Qt::AlignCenter 61 | 62 | 63 | 64 | 65 | 66 | 67 | buttonBox 68 | accepted() 69 | ShowQRCode 70 | accept() 71 | 72 | 73 | 248 74 | 254 75 | 76 | 77 | 157 78 | 274 79 | 80 | 81 | 82 | 83 | buttonBox 84 | rejected() 85 | ShowQRCode 86 | reject() 87 | 88 | 89 | 316 90 | 260 91 | 92 | 93 | 286 94 | 274 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /entercaptcha.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | EnterCaptcha 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 246 11 | 12 | 13 | 14 | 15 | 400 16 | 246 17 | 18 | 19 | 20 | 21 | 400 22 | 246 23 | 24 | 25 | 26 | Enter captcha 27 | 28 | 29 | 30 | 31 | 30 32 | 190 33 | 341 34 | 32 35 | 36 | 37 | 38 | Qt::Horizontal 39 | 40 | 41 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 42 | 43 | 44 | true 45 | 46 | 47 | 48 | 49 | 50 | 30 51 | 150 52 | 331 53 | 21 54 | 55 | 56 | 57 | 58 | 59 | 60 | 30 61 | 29 62 | 331 63 | 111 64 | 65 | 66 | 67 | Loading captcha... 68 | 69 | 70 | Qt::AlignCenter 71 | 72 | 73 | 74 | 75 | 76 | 33 77 | 170 78 | 331 79 | 20 80 | 81 | 82 | 83 | color: red; 84 | 85 | 86 | 87 | 88 | 89 | Qt::AlignCenter 90 | 91 | 92 | 93 | 94 | 95 | 96 | submitCaptcha 97 | rejected() 98 | EnterCaptcha 99 | reject() 100 | 101 | 102 | 316 103 | 260 104 | 105 | 106 | 286 107 | 274 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /getbridgeswindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | GetBridgesWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 256 11 | 12 | 13 | 14 | 15 | 400 16 | 256 17 | 18 | 19 | 20 | 21 | 400 22 | 256 23 | 24 | 25 | 26 | Bridges 27 | 28 | 29 | 30 | 31 | 290 32 | 220 33 | 91 34 | 31 35 | 36 | 37 | 38 | Qt::Horizontal 39 | 40 | 41 | QDialogButtonBox::Ok 42 | 43 | 44 | false 45 | 46 | 47 | 48 | 49 | 50 | 30 51 | 50 52 | 341 53 | 131 54 | 55 | 56 | 57 | 58 | 9 59 | 60 | 61 | 62 | true 63 | 64 | 65 | 66 | 67 | 68 | 120 69 | 10 70 | 161 71 | 31 72 | 73 | 74 | 75 | <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600;">Your new bridges are</span></p></body></html> 76 | 77 | 78 | 79 | 80 | 81 | 30 82 | 220 83 | 261 84 | 31 85 | 86 | 87 | 88 | 89 | 8 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 100 | 101 | 102 | true 103 | 104 | 105 | 106 | 107 | 108 | 150 109 | 190 110 | 121 111 | 25 112 | 113 | 114 | 115 | Copy to clipboard 116 | 117 | 118 | 119 | 120 | 121 | 30 122 | 190 123 | 111 124 | 25 125 | 126 | 127 | 128 | Show QR Code 129 | 130 | 131 | 132 | 133 | 134 | 135 | buttonBox 136 | accepted() 137 | GetBridgesWindow 138 | accept() 139 | 140 | 141 | 248 142 | 254 143 | 144 | 145 | 157 146 | 274 147 | 148 | 149 | 150 | 151 | buttonBox 152 | rejected() 153 | GetBridgesWindow 154 | reject() 155 | 156 | 157 | 316 158 | 260 159 | 160 | 161 | 286 162 | 274 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /aboutpage.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | AboutPage 4 | 5 | 6 | 7 | 0 8 | 0 9 | 442 10 | 269 11 | 12 | 13 | 14 | 15 | 442 16 | 269 17 | 18 | 19 | 20 | 21 | 442 22 | 269 23 | 24 | 25 | 26 | About Tor Bridges Collector 27 | 28 | 29 | 30 | 31 | 20 32 | 220 33 | 401 34 | 32 35 | 36 | 37 | 38 | Qt::Horizontal 39 | 40 | 41 | QDialogButtonBox::Ok 42 | 43 | 44 | true 45 | 46 | 47 | 48 | 49 | 50 | 20 51 | 90 52 | 231 53 | 101 54 | 55 | 56 | 57 | 58 | 9 59 | 60 | 61 | 62 | This product is produced independently from the Tor® anonymity software and carries no guarantee from The Tor Project about quality, suitability or anything else. 63 | 64 | 65 | Qt::PlainText 66 | 67 | 68 | Qt::AlignCenter 69 | 70 | 71 | true 72 | 73 | 74 | 75 | 76 | 77 | 20 78 | 70 79 | 231 80 | 31 81 | 82 | 83 | 84 | <html><head/><body><p align="center"><span style=" font-size:12pt; font-weight:600;">Notice</span></p></body></html> 85 | 86 | 87 | 88 | 89 | 90 | 270 91 | 90 92 | 161 93 | 31 94 | 95 | 96 | 97 | 98 | 9 99 | 100 | 101 | 102 | Visit Tor Project's Website 103 | 104 | 105 | 106 | 107 | 108 | 270 109 | 130 110 | 161 111 | 31 112 | 113 | 114 | 115 | 116 | 9 117 | 118 | 119 | 120 | Visit tool creator's page 121 | 122 | 123 | 124 | 125 | 126 | 20 127 | 10 128 | 401 129 | 51 130 | 131 | 132 | 133 | <html><head/><body><p align="center"><span style=" font-size:16pt; font-weight:600;">About Tor Bridges Collector</span></p></body></html> 134 | 135 | 136 | Qt::AlignCenter 137 | 138 | 139 | 140 | 141 | 142 | 143 | buttonBox 144 | accepted() 145 | AboutPage 146 | accept() 147 | 148 | 149 | 248 150 | 254 151 | 152 | 153 | 157 154 | 274 155 | 156 | 157 | 158 | 159 | buttonBox 160 | rejected() 161 | AboutPage 162 | reject() 163 | 164 | 165 | 316 166 | 260 167 | 168 | 169 | 286 170 | 274 171 | 172 | 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /settingsdialog.cpp: -------------------------------------------------------------------------------- 1 | #include "settingsdialog.h" 2 | #include "ui_settingsdialog.h" 3 | 4 | SettingsDialog::SettingsDialog(QWidget *parent) : 5 | QDialog(parent), 6 | ui(new Ui::SettingsDialog) 7 | { 8 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 9 | ui->setupUi(this); 10 | ui->bridgesType->setCurrentText(settings.value("bridgesType").toString()); 11 | ui->proxyType->setCurrentText(settings.value("proxyType").toString()); 12 | if (!settings.contains("torrcFilePath")) { 13 | ui->displayTorrcPath->setText("Torrc file path.."); 14 | } else if (settings.value("modTorrc").toBool() && settings.contains("torrcFilePath")) { 15 | ui->displayTorrcPath->setText(settings.value("torrcFilePath").toString()); 16 | } 17 | if (!settings.contains("bridgesPath") || !settings.value("bridgesPath").toBool()) { 18 | ui->displayBridgesPath->setText("%user%/tor_bridges.txt"); 19 | } else { 20 | ui->displayBridgesPath->setText(settings.value("bridgesFilePath").toString()); 21 | } 22 | #ifdef QT_NO_SYSTEMTRAYICON 23 | ui->showInTray->setEnabled(false); 24 | ui->closeToTray->setEnabled(false); 25 | #endif 26 | if (!settings.value("showInSystemTray").toBool()) { 27 | ui->closeToTray->setEnabled(false); 28 | } 29 | ui->showIconInTray->setChecked(settings.value("showInSystemTray").toBool()); 30 | ui->closeToTray->setChecked(settings.value("closeToSystemTray").toBool()); 31 | ui->chooseTorrc->setEnabled(settings.value("modTorrc").toBool()); 32 | ui->chooseBridgesPath->setEnabled(settings.value("bridgesPath").toBool()); 33 | ui->displayBridgesPath->setEnabled(settings.value("bridgesPath").toBool()); 34 | ui->chooseTorrc->setEnabled(settings.value("modTorrc").toBool()); 35 | ui->displayTorrcPath->setEnabled(settings.value("modTorrc").toBool()); 36 | ui->torType->setEnabled(settings.value("modTorrc").toBool()); 37 | ui->proxyPort->setValue(settings.value("proxyPort").toInt()); 38 | ui->modBridgesPath->setChecked(settings.value("bridgesPath").toBool()); 39 | ui->ipv6Support->setChecked(settings.value("ipv6Support").toBool()); 40 | ui->useProxy->setChecked(settings.value("useProxy").toBool()); 41 | ui->modTorrc->setChecked(settings.value("modTorrc").toBool()); 42 | ui->proxyPort->setEnabled(settings.value("useProxy").toBool()); 43 | ui->proxyType->setEnabled(settings.value("useProxy").toBool()); 44 | } 45 | 46 | void SettingsDialog::on_bridgesType_currentIndexChanged(QString type) 47 | { 48 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 49 | settings.setValue("bridgesType", type); 50 | } 51 | 52 | void SettingsDialog::on_proxyType_currentIndexChanged(QString type) 53 | { 54 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 55 | settings.setValue("proxyType", type); 56 | } 57 | 58 | void SettingsDialog::on_chooseTorrc_clicked() 59 | { 60 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 61 | QString path = QFileDialog::getOpenFileName(this, tr("Open torrc file"), "", tr("All Files (*)")); 62 | QFile torrcfile(path); 63 | if (torrcfile.exists()) { 64 | ui->displayTorrcPath->setText(path); 65 | settings.setValue("torrcFilePath", path); 66 | } 67 | } 68 | 69 | void SettingsDialog::on_chooseBridgesPath_clicked() 70 | { 71 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 72 | QString path = QFileDialog::getSaveFileName(this, tr("Save bridges in"), "", tr("All Files (*)")); 73 | QFile bridgespathfile(path); 74 | if (bridgespathfile.open(QIODevice::WriteOnly | QIODevice::Text) && bridgespathfile.exists()) { 75 | ui->displayBridgesPath->setText(path); 76 | settings.setValue("bridgesFilePath", path); 77 | } 78 | } 79 | 80 | void SettingsDialog::on_modBridgesPath_toggled(bool option) 81 | { 82 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 83 | ui->displayBridgesPath->setEnabled(option); 84 | ui->chooseBridgesPath->setEnabled(option); 85 | if (!option) { 86 | settings.remove("bridgesPath"); 87 | settings.remove("bridgesFilePath"); 88 | ui->displayBridgesPath->setText("%user%/tor_bridges.txt"); 89 | } else { 90 | settings.setValue("bridgesPath", option); 91 | settings.setValue("bridgesFilePath", QString(QDir::homePath() + "/tor_bridges.txt")); 92 | ui->displayBridgesPath->setText(settings.value("bridgesFilePath").toString()); 93 | } 94 | } 95 | 96 | void SettingsDialog::on_showIconInTray_toggled(bool option) 97 | { 98 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 99 | settings.setValue("showInSystemTray", option); 100 | ui->closeToTray->setEnabled(option); 101 | if (option) { 102 | QApplication::setQuitOnLastWindowClosed(!settings.value("closeToSystemTray").toBool()); 103 | } 104 | emit setTrayIcon(int(option)); 105 | } 106 | 107 | void SettingsDialog::on_closeToTray_toggled(bool option) 108 | { 109 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 110 | settings.setValue("closeToSystemTray", option); 111 | if (QSystemTrayIcon::isSystemTrayAvailable() && settings.value("showInSystemTray").toBool()) { 112 | QApplication::setQuitOnLastWindowClosed(!option); 113 | } 114 | } 115 | 116 | void SettingsDialog::on_proxyPort_valueChanged(int port) 117 | { 118 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 119 | settings.setValue("proxyPort", port); 120 | } 121 | 122 | void SettingsDialog::on_ipv6Support_toggled(bool option) 123 | { 124 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 125 | settings.setValue("ipv6Support", option); 126 | } 127 | 128 | void SettingsDialog::on_torType_currentIndexChanged(QString type) 129 | { 130 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 131 | settings.setValue("torType", type); 132 | } 133 | 134 | void SettingsDialog::on_modTorrc_toggled(bool option) 135 | { 136 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 137 | settings.setValue("modTorrc", option); 138 | ui->displayTorrcPath->setEnabled(option); 139 | ui->chooseTorrc->setEnabled(option); 140 | ui->torType->setEnabled(option); 141 | if (!option) { 142 | settings.remove("torrcFilePath"); 143 | settings.remove("torType"); 144 | ui->displayTorrcPath->setText("Torrc file path.."); 145 | ui->torType->setCurrentText("daemon"); 146 | } 147 | } 148 | 149 | void SettingsDialog::on_useProxy_toggled(bool option) 150 | { 151 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 152 | settings.setValue("useProxy", option); 153 | ui->proxyPort->setEnabled(option); 154 | ui->proxyType->setEnabled(option); 155 | } 156 | 157 | SettingsDialog::~SettingsDialog() 158 | { 159 | delete ui; 160 | } 161 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /torbridgescollector.cpp: -------------------------------------------------------------------------------- 1 | #include "torbridgescollector.h" 2 | #include "settingsdialog.h" 3 | #include "aboutpage.h" 4 | #include "entercaptcha.h" 5 | #include "ui_torbridgescollector.h" 6 | 7 | TorBridgesCollector::TorBridgesCollector(QWidget *parent) : 8 | QMainWindow(parent), 9 | ui(new Ui::TorBridgesCollector) 10 | { 11 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 12 | ui->setupUi(this); 13 | if (!settings.contains("retrieve_interval")) { 14 | settings.setValue("retrieve_interval", 86400); 15 | } 16 | if (!settings.contains("next_retrieval") || !settings.value("next_retrieval").toDateTime().toUTC().isValid()) { 17 | settings.setValue("next_retrieval", QDateTime::currentDateTimeUtc().addSecs(settings.value("retrieve_interval").toInt())); 18 | } 19 | if (!settings.contains("bridgesType")) { 20 | settings.setValue("bridgesType", "obfs4"); 21 | } 22 | if (!settings.contains("proxyType")) { 23 | settings.setValue("proxyType", "socks5"); 24 | } 25 | if (!settings.contains("proxyPort")) { 26 | settings.setValue("proxyPort", 9050); 27 | } 28 | if (!settings.contains("ipv6Support")) { 29 | settings.setValue("ipv6Support", false); 30 | } 31 | if (!settings.contains("useProxy")) { 32 | settings.setValue("useProxy", false); 33 | } 34 | if (!settings.contains("modTorrc")) { 35 | settings.setValue("modTorrc", false); 36 | } 37 | if (!settings.contains("torType")) { 38 | settings.setValue("torType", "daemon"); 39 | } 40 | if (!settings.contains("bridgesPath")) { 41 | settings.setValue("bridgesPath", false); 42 | } 43 | if (!settings.contains("showInSystemTray")) { 44 | settings.setValue("showInSystemTray", true); 45 | } 46 | if (!settings.contains("closeToSystemTray")) { 47 | settings.setValue("closeToSystemTray", true); 48 | } 49 | #ifndef QT_NO_SYSTEMTRAYICON 50 | appTray = new QSystemTrayIcon(this); 51 | appTray->setIcon(QIcon(":/images/status/normal.png")); 52 | windowShow = new QAction(tr("Show"), this); 53 | connect(windowShow, &QAction::triggered, this, &QWidget::showNormal); 54 | windowHide = new QAction(tr("Hide"), this); 55 | connect(windowHide, &QAction::triggered, this, &QWidget::hide); 56 | windowQuit = new QAction(tr("Exit"), this); 57 | connect(windowQuit, &QAction::triggered, this, &QApplication::quit); 58 | appTrayMenu = new QMenu(this); 59 | connect(windowQuit, &QAction::triggered, this, &QApplication::quit); 60 | appTrayMenu->addAction(windowShow); 61 | appTrayMenu->addAction(windowHide); 62 | appTrayMenu->addAction(windowQuit); 63 | appTray->setContextMenu(appTrayMenu); 64 | connect(appTray, &QSystemTrayIcon::messageClicked, this, &TorBridgesCollector::on_retrieveNowButton_clicked); 65 | connect(appTray, &QSystemTrayIcon::activated, this, &TorBridgesCollector::appTrayActivated); 66 | if (QSystemTrayIcon::isSystemTrayAvailable() && settings.value("showInSystemTray").toBool()) { 67 | appTray->show(); 68 | QApplication::setQuitOnLastWindowClosed(!settings.value("closeToSystemTray").toBool()); 69 | } 70 | #endif 71 | lastTimeValue = settings.value("retrieve_interval").toInt(); 72 | ui->setRetrieveTime->setText(getTimeFormat(settings.value("retrieve_interval").toInt())); 73 | ui->retrieveCountDownBar->setMaximum(settings.value("retrieve_interval").toInt()); 74 | ui->retrieveCountDownBar->setValue(settings.value("retrieve_interval").toInt()); 75 | QTimer *nextCheck = new QTimer(this); 76 | connect(nextCheck, SIGNAL(timeout()), this, SLOT(until_next_retrieve_timer())); 77 | nextCheck->start(1000); 78 | until_next_retrieve_timer(); 79 | if (settings.contains("lastRetrievalTime")) { 80 | ui->lastRetrievalTime->setText("Last retrieval time: " + settings.value("lastRetrievalTime").toDateTime().toString()); 81 | } 82 | } 83 | 84 | QString TorBridgesCollector::getTimeFormat(int timesecs) 85 | { 86 | QStringList timecells; 87 | timecells << QString::number(timesecs/(24*3600)) << QString::number((timesecs%(24*3600))/3600) << QString::number((timesecs/60)%60) << QString::number(timesecs%60); 88 | for (int i(0); i < timecells.count(); i++) { 89 | if (timecells[i].size() == 0) { 90 | timecells[i] = "00"; 91 | } else if (timecells[i].size() == 1) { 92 | timecells[i].prepend("0"); 93 | } else if (timecells[i].size() > 2) { 94 | timecells[i].resize(2); 95 | } 96 | } 97 | return timecells.join(":"); 98 | } 99 | 100 | void TorBridgesCollector::setBridgesButton(bool active) 101 | { 102 | if (active) { 103 | ui->retrieveNowButton->setEnabled(true); 104 | ui->retrieveNowButton->setText("Retrieve now"); 105 | } else { 106 | ui->retrieveNowButton->setEnabled(false); 107 | ui->retrieveNowButton->setText("Loading..."); 108 | } 109 | } 110 | 111 | void TorBridgesCollector::updateLastRetrievalTime(QDateTime time) 112 | { 113 | ui->lastRetrievalTime->setText("Last retrieval time: " + time.toString()); 114 | } 115 | 116 | void TorBridgesCollector::on_setRetrieveTime_returnPressed() 117 | { 118 | getTime(ui->setRetrieveTime->text()); 119 | TorRetrievedBridges = false; 120 | } 121 | 122 | void TorBridgesCollector::on_setRetrieveTimeButton_clicked() 123 | { 124 | getTime(ui->setRetrieveTime->text()); 125 | TorRetrievedBridges = false; 126 | } 127 | 128 | void TorBridgesCollector::on_retrieveNowButton_clicked() 129 | { 130 | appTray->setIcon(QIcon(":/images/status/normal.png")); 131 | EnterCaptcha *captchaWindow = new EnterCaptcha(this); 132 | setBridgesButton(false); 133 | connect(captchaWindow, SIGNAL(captchaLoadFinished(bool)), this, SLOT(setBridgesButton(bool))); 134 | connect(captchaWindow, SIGNAL(bridgesDataLoaded(QDateTime)), this, SLOT(updateLastRetrievalTime(QDateTime))); 135 | captchaWindow->requestCaptcha(); 136 | } 137 | 138 | void TorBridgesCollector::on_aboutButton_clicked() 139 | { 140 | AboutPage *aboutWindow = new AboutPage(this); 141 | aboutWindow->show(); 142 | } 143 | 144 | void TorBridgesCollector::on_settingsButton_clicked() 145 | { 146 | SettingsDialog *settingsWindow = new SettingsDialog(this); 147 | connect(settingsWindow, SIGNAL(setTrayIcon(int)), this, SLOT(setTrayIcon(int))); 148 | settingsWindow->show(); 149 | } 150 | 151 | void TorBridgesCollector::on_exitButton_clicked() 152 | { 153 | QApplication::quit(); 154 | } 155 | 156 | void TorBridgesCollector::appTrayActivated(QSystemTrayIcon::ActivationReason trayReason) 157 | { 158 | switch (trayReason) { 159 | case QSystemTrayIcon::Trigger: 160 | case QSystemTrayIcon::DoubleClick: 161 | if (!TorBridgesCollector::isHidden()) { 162 | hide(); 163 | } else { 164 | show(); 165 | } 166 | break; 167 | default: 168 | ; 169 | } 170 | } 171 | 172 | void TorBridgesCollector::getTime(QString timeraw) 173 | { 174 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 175 | QStringList text_time = timeraw.split(":"); 176 | if (text_time.count() == 4) { 177 | int value = ((text_time[0].toInt()*24*3600) + (text_time[1].toInt()*3600) + (text_time[2].toInt()*60) + text_time[3].toInt()); 178 | if (getTimeFormat(value) != timeraw) { 179 | timeraw = getTimeFormat(value); 180 | ui->setRetrieveTime->setText(timeraw); 181 | } 182 | QString time_correct = getTimeFormat(value); 183 | if (value < 31536000 && value > 9) { 184 | if (timeraw != time_correct) { 185 | ui->setRetrieveTime->setText(time_correct); 186 | } 187 | lastTimeValue = value; 188 | settings.setValue("next_retrieval", QDateTime::currentDateTimeUtc().addSecs(value)); 189 | settings.setValue("retrieve_interval", value); 190 | ui->retrieveCountDownBar->setMaximum(value); 191 | ui->retrieveCountDownBar->setValue(value); 192 | } else if (value == 0) { 193 | ui->retrieveCountDownBar->setMaximum(value); 194 | ui->retrieveCountDownBar->setValue(value); 195 | ui->retrieveHoursCountDown->setText("none"); 196 | } else { 197 | ui->retrieveCountDownBar->setMaximum(lastTimeValue); 198 | ui->retrieveCountDownBar->setValue(lastTimeValue); 199 | ui->setRetrieveTime->setText(getTimeFormat(lastTimeValue)); 200 | } 201 | } else { 202 | ui->setRetrieveTime->setText(getTimeFormat(lastTimeValue)); 203 | } 204 | } 205 | 206 | void TorBridgesCollector::setTrayIcon(int action) 207 | { 208 | #ifndef QT_NO_SYSTEMTRAYICON 209 | if (action == 0) { 210 | QApplication::setQuitOnLastWindowClosed(true); 211 | appTray->setVisible(false); 212 | } else if (action == 1) { 213 | appTray->setVisible(true); 214 | } else { 215 | setTrayIcon(int(!appTray->isVisible())); 216 | } 217 | #endif 218 | } 219 | 220 | void TorBridgesCollector::until_next_retrieve_timer() 221 | { 222 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 223 | QDateTime lastRetrieval = settings.value("next_retrieval").toDateTime().toUTC(); 224 | int remaining_time = QDateTime::currentDateTimeUtc().secsTo(lastRetrieval); 225 | if (settings.value("retrieve_interval").toInt() > 0) { 226 | if (remaining_time <= 0) { 227 | while (remaining_time <= 0) { 228 | if (!TorRetrievedBridges) { 229 | appTray->setIcon(QIcon(":/images/status/alert.png")); 230 | appTray->showMessage("Time to get new bridges", "Click to retrieve.", QIcon(":/images/status/alert.png"), 5000); 231 | TorRetrievedBridges = true; 232 | } 233 | lastRetrieval = settings.value("next_retrieval").toDateTime().toUTC().addSecs(settings.value("retrieve_interval").toInt()); 234 | settings.setValue("next_retrieval", lastRetrieval); 235 | remaining_time = QDateTime::currentDateTimeUtc().secsTo(lastRetrieval); 236 | } 237 | } else if (remaining_time > (settings.value("retrieve_interval").toInt() - 5) && TorRetrievedBridges) { 238 | appTray->setIcon(QIcon(":/images/status/alert.png")); 239 | } else { 240 | TorRetrievedBridges = false; 241 | appTray->setIcon(QIcon(":/images/status/normal.png")); 242 | } 243 | ui->retrieveCountDownBar->setValue(remaining_time); 244 | ui->retrieveHoursCountDown->setText(getTimeFormat(remaining_time)); 245 | } else { 246 | appTray->setIcon(QIcon(":/images/status/inactive.png")); 247 | ui->retrieveHoursCountDown->setText("none"); 248 | } 249 | } 250 | 251 | TorBridgesCollector::~TorBridgesCollector() 252 | { 253 | delete ui; 254 | } 255 | -------------------------------------------------------------------------------- /torbridgescollector.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | TorBridgesCollector 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 221 11 | 12 | 13 | 14 | 15 | 400 16 | 221 17 | 18 | 19 | 20 | 21 | 400 22 | 221 23 | 24 | 25 | 26 | Tor Bridges Collector 27 | 28 | 29 | 30 | 31 | 32 | 20 33 | 111 34 | 171 35 | 23 36 | 37 | 38 | 39 | 100 40 | 41 | 42 | 24 43 | 44 | 45 | false 46 | 47 | 48 | %p% 49 | 50 | 51 | 52 | 53 | 54 | 20 55 | 80 56 | 171 57 | 20 58 | 59 | 60 | 61 | 62 | 9 63 | 64 | 65 | 66 | Until next bridge retrieval 67 | 68 | 69 | Qt::PlainText 70 | 71 | 72 | Qt::AlignCenter 73 | 74 | 75 | 76 | 77 | 78 | 230 79 | 80 80 | 151 81 | 21 82 | 83 | 84 | 85 | Remind to retrieve 86 | 87 | 88 | Qt::PlainText 89 | 90 | 91 | Qt::AlignCenter 92 | 93 | 94 | 95 | 96 | 97 | 230 98 | 111 99 | 41 100 | 20 101 | 102 | 103 | 104 | <html><head/><body><p><span style=" font-size:10pt; font-weight:600;">Every</span></p></body></html> 105 | 106 | 107 | 108 | 109 | 110 | 230 111 | 160 112 | 161 113 | 41 114 | 115 | 116 | 117 | Retrieve now 118 | 119 | 120 | 121 | 122 | 123 | 20 124 | 111 125 | 171 126 | 21 127 | 128 | 129 | 130 | 131 | 9 132 | 133 | 134 | 135 | 01:00:00:00 136 | 137 | 138 | Qt::PlainText 139 | 140 | 141 | Qt::AlignCenter 142 | 143 | 144 | 145 | 146 | 147 | 270 148 | 130 149 | 71 150 | 31 151 | 152 | 153 | 154 | 155 | 7 156 | 157 | 158 | 159 | <html><head/><body><p align="center"><span style=" font-style:italic;">dd:hh:mm:ss</span></p></body></html> 160 | 161 | 162 | 163 | 164 | 165 | 270 166 | 111 167 | 81 168 | 25 169 | 170 | 171 | 172 | 173 | 9 174 | 175 | 176 | 177 | 01:00:00:00 178 | 179 | 180 | false 181 | 182 | 183 | 184 | 185 | 186 | 350 187 | 111 188 | 31 189 | 25 190 | 191 | 192 | 193 | 194 | 10 195 | 196 | 197 | 198 | Set 199 | 200 | 201 | 202 | 203 | 204 | 150 205 | 180 206 | 61 207 | 25 208 | 209 | 210 | 211 | Settings 212 | 213 | 214 | 215 | 216 | 217 | 80 218 | 180 219 | 61 220 | 25 221 | 222 | 223 | 224 | About 225 | 226 | 227 | 228 | 229 | 230 | 0 231 | 0 232 | 400 233 | 70 234 | 235 | 236 | 237 | false 238 | 239 | 240 | background-image: url(:/images/header.png); 241 | 242 | 243 | QFrame::NoFrame 244 | 245 | 246 | QFrame::Plain 247 | 248 | 249 | 250 | 251 | 0 252 | 0 253 | 400 254 | 50 255 | 256 | 257 | 258 | background: none; 259 | 260 | 261 | <html><head/><body><p align="center"><span style=" font-size:14pt; font-weight:600; color:#3c0f65;">Tor Bridges Collector</span></p></body></html> 262 | 263 | 264 | 265 | 266 | 267 | 100 268 | 40 269 | 231 270 | 17 271 | 272 | 273 | 274 | 275 | 9 276 | 277 | 278 | 279 | background: none; 280 | 281 | 282 | QFrame::NoFrame 283 | 284 | 285 | Collects Tor bridges, so you don't have to 286 | 287 | 288 | Qt::PlainText 289 | 290 | 291 | 292 | 293 | 294 | 290 295 | 20 296 | 41 297 | 20 298 | 299 | 300 | 301 | 302 | 7 303 | 304 | 305 | 306 | background: none; 307 | 308 | 309 | QFrame::NoFrame 310 | 311 | 312 | v1.0 313 | 314 | 315 | Qt::PlainText 316 | 317 | 318 | Qt::AlignCenter 319 | 320 | 321 | 322 | 323 | 324 | 325 | 10 326 | 130 327 | 191 328 | 31 329 | 330 | 331 | 332 | 333 | 7 334 | 335 | 336 | 337 | Last retrieval time: <unknown> 338 | 339 | 340 | Qt::PlainText 341 | 342 | 343 | Qt::AlignCenter 344 | 345 | 346 | 347 | 348 | 349 | 10 350 | 180 351 | 61 352 | 25 353 | 354 | 355 | 356 | Exit 357 | 358 | 359 | 360 | 361 | 362 | 230 363 | 200 364 | 161 365 | 20 366 | 367 | 368 | 369 | color: red; 370 | 371 | 372 | 373 | 374 | 375 | Qt::AlignCenter 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | -------------------------------------------------------------------------------- /entercaptcha.cpp: -------------------------------------------------------------------------------- 1 | #include "entercaptcha.h" 2 | #include "ui_entercaptcha.h" 3 | 4 | #include "getbridgeswindow.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | EnterCaptcha::EnterCaptcha(QWidget *parent) : 14 | QDialog(parent), 15 | ui(new Ui::EnterCaptcha), 16 | requestLoaded(Q_NULLPTR) 17 | { 18 | ui->setupUi(this); 19 | } 20 | 21 | void EnterCaptcha::setProxy() 22 | { 23 | QNetworkProxy proxy; 24 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 25 | if (settings.value("useProxy").toBool()) { 26 | if (settings.value("proxyType").toString() == "socks5") { 27 | proxy = QNetworkProxy::Socks5Proxy; 28 | } else if (settings.value("proxyType").toString() == "http") { 29 | proxy = QNetworkProxy::HttpProxy; 30 | } 31 | proxy.setHostName("127.0.0.1"); 32 | proxy.setPort(settings.value("proxyPort").toInt()); 33 | proxy.setHeader(QNetworkRequest::UserAgentHeader, "Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0"); 34 | QNetworkProxy::setApplicationProxy(proxy); 35 | } else if (!settings.value("useProxy").toBool()) { 36 | proxy = QNetworkProxy::DefaultProxy; 37 | QNetworkProxy::setApplicationProxy(proxy); 38 | } 39 | } 40 | 41 | void EnterCaptcha::requestCaptcha() 42 | { 43 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 44 | QString bridgesType; 45 | if (!settings.contains("bridgesType")) { 46 | bridgesType = "obfs4"; 47 | } else { 48 | bridgesType = settings.value("bridgesType").toString(); 49 | } 50 | setProxy(); 51 | requestedData.clear(); 52 | QUrl requestbridgesUrl(QStringLiteral("https://bridges.torproject.org/bridges")); 53 | QUrlQuery requestbridgesUrlParams; 54 | requestbridgesUrlParams.addQueryItem(QString("transport"), bridgesType); 55 | if (settings.value("ipv6Support").toBool()) { 56 | requestbridgesUrlParams.addQueryItem(QString("ipv6"), QString("yes")); 57 | } 58 | requestbridgesUrl.setQuery(requestbridgesUrlParams); 59 | QNetworkRequest request(requestbridgesUrl); 60 | requestLoaded = networkAccess.get(request); 61 | connect(requestLoaded, &QNetworkReply::finished, this, &EnterCaptcha::captchaLoaded); 62 | connect(requestLoaded, &QIODevice::readyRead, this, &EnterCaptcha::dataLoaded); 63 | } 64 | 65 | void EnterCaptcha::requestBridges(QString captchaInput, QString captchaToken) 66 | { 67 | ui->submitCaptcha->setEnabled(false); 68 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 69 | QString bridgesType; 70 | if (!settings.contains("bridgesType")) { 71 | bridgesType = "obfs4"; 72 | } else { 73 | bridgesType = settings.value("bridgesType").toString(); 74 | } 75 | setProxy(); 76 | requestedData.clear(); 77 | QUrl requestbridgesUrl(QStringLiteral("https://bridges.torproject.org/bridges")); 78 | QUrlQuery requestbridgesUrlParams; 79 | requestbridgesUrlParams.addQueryItem(QString("transport"), bridgesType); 80 | if (settings.value("ipv6Support").toBool()) { 81 | requestbridgesUrlParams.addQueryItem(QString("ipv6"), QString("yes")); 82 | } 83 | requestbridgesUrl.setQuery(requestbridgesUrlParams); 84 | QUrlQuery postData; 85 | postData.addQueryItem("captcha_challenge_field", captchaToken); 86 | postData.addQueryItem("captcha_response_field", captchaInput); 87 | QNetworkRequest request(requestbridgesUrl); 88 | request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); 89 | requestLoaded = networkAccess.post(request, postData.toString(QUrl::FullyEncoded).toUtf8()); 90 | connect(requestLoaded, &QNetworkReply::finished, this, &EnterCaptcha::bridgesLoaded); 91 | connect(requestLoaded, &QIODevice::readyRead, this, &EnterCaptcha::dataLoaded); 92 | } 93 | 94 | void EnterCaptcha::dataLoaded() 95 | { 96 | requestedData.append(requestLoaded->readAll()); 97 | } 98 | 99 | void EnterCaptcha::on_submitCaptcha_accepted() 100 | { 101 | if (ui->captchaImage->text() != "Failed loading captcha.") { 102 | requestBridges(ui->captchaText->text(), enterCaptchaToken); 103 | } else { 104 | accept(); 105 | } 106 | } 107 | 108 | void EnterCaptcha::captchaLoaded() 109 | { 110 | QRegularExpression parseCaptcha("
\\n
\\n
\\n \\\"Your\\n\\n"); 111 | QRegularExpression parseFormId("\\n"); 112 | QPixmap captchaImage; 113 | QRegularExpressionMatch captchaReceived = parseCaptcha.match(requestedData); 114 | if (captchaReceived.hasMatch()) { 115 | captchaImage.loadFromData(QByteArray::fromBase64(captchaReceived.captured(1).toLatin1())); 116 | show(); 117 | ui->captchaImage->setPixmap(captchaImage.scaledToWidth(330, Qt::SmoothTransformation)); 118 | enterCaptchaToken = parseFormId.match(requestedData).captured(1); 119 | } else { 120 | show(); 121 | ui->captchaImage->setText("Failed loading captcha."); 122 | } 123 | emit captchaLoadFinished(true); 124 | } 125 | 126 | void EnterCaptcha::bridgesLoaded() 127 | { 128 | QRegularExpression parseBridgeLines("
\\n([^\"]*)
\\n
\\n"); 129 | QRegularExpression parseBridgesQRCode("\\\"\\\"\\n"); 130 | QRegularExpression parseNoBridges("There currently aren't any bridges available...\\n"); 131 | QRegularExpression parseCaptcha("
\\n
\\n
\\n \\\"Your\\n\\n"); 132 | QString wrongCaptcha = "\n\n \n \n \n \n click here\n \n\n"; 133 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "TorBridgesCollector", "settings"); 134 | GetBridgesWindow *bridgesWindow = new GetBridgesWindow(this); 135 | QString bridgesOutput; 136 | QString torrcModOutput; 137 | QRegularExpressionMatch bridgesMatch = parseBridgeLines.match(requestedData); 138 | if (bridgesMatch.hasMatch()) { 139 | QPixmap bridgesQRCode; 140 | bridgesQRCode.loadFromData(QByteArray::fromBase64(parseBridgesQRCode.match(requestedData).captured(1).toLatin1())); 141 | QList bridgeLines = bridgesMatch.captured(1).split("
"); 142 | bridgesOutput = bridgeLines.join("\n"); 143 | QDateTime retrievalTime = QDateTime::currentDateTime(); 144 | settings.setValue("lastRetrievalTime", retrievalTime); 145 | emit bridgesDataLoaded(retrievalTime); 146 | if (settings.contains("bridgesPath") && settings.contains("bridgesFilePath")) { 147 | QFile bridgesFile(settings.value("bridgesFilePath").toString()); 148 | QString bridgesFileData; 149 | if (bridgesFile.open(QIODevice::ReadOnly | QIODevice::Text)) { 150 | bridgesFileData = bridgesFile.readAll(); 151 | bridgesFile.close(); 152 | } 153 | if (bridgesFile.open(QIODevice::WriteOnly | QIODevice::Text)) { 154 | QTextStream bridgesFileWrite(&bridgesFile); 155 | bridgesFileWrite << bridgesFileData << "#Retrieved on " + retrievalTime.toString().toUtf8() + ". Bridges type - " + settings.value("bridgesType").toString().toUtf8() + "\n\n" + bridgesOutput.toUtf8() + "\n\n\n"; 156 | bridgesFile.close(); 157 | } 158 | } 159 | foreach (QString bridgeLine, bridgeLines) { 160 | bridgeLines[bridgeLines.indexOf(bridgeLine)].replace("\n", "").prepend("Bridge "); 161 | } 162 | if (settings.contains("modTorrc") && settings.contains("torrcFilePath")) { 163 | QFile torrcFile(settings.value("torrcFilePath").toString()); 164 | QString torrcFileData; 165 | if (torrcFile.exists()) { 166 | if (torrcFile.open(QIODevice::ReadOnly | QIODevice::Text)) { 167 | torrcFileData = torrcFile.readAll(); 168 | torrcFile.close(); 169 | } 170 | if (torrcFileData.contains("\nDataDirectory")) { 171 | QString useBridges; 172 | QString clientTransportLine; 173 | if (settings.value("torType").toString() == "daemon") { 174 | QRegularExpression bridgeLine("Bridge .*\n"); 175 | QRegularExpression bridgeClientTransportLine("\nClientTransportPlugin.*\n"); 176 | if (settings.value("bridgesType").toString() == "fte") { 177 | clientTransportLine = "\nClientTransportPlugin fte exec /usr/bin/fteproxy --managed\n"; 178 | } else { 179 | if (settings.value("bridgesType").toString() != "normal") { 180 | clientTransportLine = "\nClientTransportPlugin obfs2,obfs3,obfs4,scramblesuit exec /usr/bin/obfs4proxy\n"; 181 | } 182 | } 183 | if (!torrcFileData.contains("\nUseBridges 1")) { 184 | useBridges = "\nUseBridges 1"; 185 | } 186 | torrcFileData.replace(bridgeLine, ""); 187 | torrcFileData.replace(bridgeClientTransportLine, ""); 188 | } 189 | QString torrcFileOutput = torrcFileData + useBridges + "\n" + bridgeLines.join("\n") + clientTransportLine; 190 | if (torrcFile.open(QIODevice::WriteOnly | QIODevice::Text) && torrcFile.permissions() & QFileDevice::WriteUser) { 191 | QTextStream torrcFileWrite(&torrcFile); 192 | torrcFileWrite << torrcFileOutput; 193 | torrcFile.close(); 194 | } else { 195 | #ifndef __unix__ 196 | torrcModOutput = "Failed to modify " + settings.value("torrcFilePath").toString() + " torrc file. Perhaps you should try running Tor Bridges Collector as administrator?"; 197 | #else 198 | if (QFile("/usr/bin/pkexec").exists() && QFile("/usr/bin/cp").exists()) { 199 | QFile tempTorrc(QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/.temptorrc"); 200 | if (tempTorrc.open(QIODevice::WriteOnly | QIODevice::Text)) { 201 | QTextStream outTempTorrc(&tempTorrc); 202 | outTempTorrc << torrcFileOutput; 203 | tempTorrc.close(); 204 | system("pkexec cp " + tempTorrc.fileName().toUtf8() + " " + settings.value("torrcFilePath").toString().toUtf8()); 205 | } 206 | tempTorrc.remove(); 207 | } else { 208 | torrcModOutput = "Failed to modify " + settings.value("torrcFilePath").toString() + " torrc file. Perhaps you should try running Tor Bridges Collector as administrator?"; 209 | } 210 | #endif 211 | } 212 | } 213 | } 214 | } 215 | bridgesWindow->showRetrievedBridges(bridgesOutput, bridgesQRCode.scaledToWidth(400, Qt::FastTransformation), torrcModOutput); 216 | accept(); 217 | } else if (parseNoBridges.match(requestedData).hasMatch()) { 218 | ui->errorMessage->setText("Currently no bridges of specified type are available."); 219 | ui->captchaImage->setText("Loading captcha..."); 220 | requestCaptcha(); 221 | } else if (parseCaptcha.match(requestedData).hasMatch() || requestedData == wrongCaptcha) { 222 | ui->errorMessage->setText("Wrong captcha. Please try again."); 223 | ui->captchaImage->setText("Loading captcha..."); 224 | requestCaptcha(); 225 | } else { 226 | ui->errorMessage->setText("Could not get bridges."); 227 | ui->captchaImage->setText("Loading captcha..."); 228 | requestCaptcha(); 229 | } 230 | ui->captchaText->clear(); 231 | ui->submitCaptcha->setEnabled(true); 232 | } 233 | 234 | EnterCaptcha::~EnterCaptcha() 235 | { 236 | delete ui; 237 | } 238 | -------------------------------------------------------------------------------- /settingsdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SettingsDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 265 11 | 12 | 13 | 14 | 15 | 400 16 | 265 17 | 18 | 19 | 20 | 21 | 400 22 | 265 23 | 24 | 25 | 26 | Settings 27 | 28 | 29 | 30 | 31 | 300 32 | 40 33 | 81 34 | 25 35 | 36 | 37 | 38 | 39 | 9 40 | 41 | 42 | 43 | 44 | normal 45 | 46 | 47 | 48 | 49 | obfs4 50 | 51 | 52 | 53 | 54 | obfs3 55 | 56 | 57 | 58 | 59 | fte 60 | 61 | 62 | 63 | 64 | scramblesuit 65 | 66 | 67 | 68 | 69 | 70 | 71 | 290 72 | 20 73 | 101 74 | 17 75 | 76 | 77 | 78 | 79 | 10 80 | 81 | 82 | 83 | <html><head/><body><p><span style=" font-weight:600;">Bridges type</span></p></body></html> 84 | 85 | 86 | Qt::RichText 87 | 88 | 89 | Qt::AlignCenter 90 | 91 | 92 | 93 | 94 | 95 | 290 96 | 70 97 | 101 98 | 23 99 | 100 | 101 | 102 | 103 | 9 104 | 105 | 106 | 107 | IPv6 support? 108 | 109 | 110 | 111 | 112 | 113 | 20 114 | 70 115 | 151 116 | 23 117 | 118 | 119 | 120 | 121 | 9 122 | 123 | 124 | 125 | Modify bridges in torrc 126 | 127 | 128 | 129 | 130 | 131 | 20 132 | 120 133 | 81 134 | 25 135 | 136 | 137 | 138 | 139 | 9 140 | 141 | 142 | 143 | 144 | socks5 145 | 146 | 147 | 148 | 149 | http 150 | 151 | 152 | 153 | 154 | 155 | 156 | 20 157 | 20 158 | 171 159 | 20 160 | 161 | 162 | 163 | 164 | 10 165 | 166 | 167 | 168 | <html><head/><body><p><span style=" font-weight:600;">Modify torrc</span></p></body></html> 169 | 170 | 171 | Qt::AutoText 172 | 173 | 174 | Qt::AlignCenter 175 | 176 | 177 | 178 | 179 | 180 | 20 181 | 100 182 | 81 183 | 17 184 | 185 | 186 | 187 | 188 | 10 189 | 190 | 191 | 192 | <html><head/><body><p><span style=" font-weight:600;">Proxy type</span></p></body></html> 193 | 194 | 195 | Qt::AutoText 196 | 197 | 198 | Qt::AlignCenter 199 | 200 | 201 | 202 | 203 | 204 | 110 205 | 120 206 | 81 207 | 26 208 | 209 | 210 | 211 | 212 | 9 213 | 214 | 215 | 216 | 9999 217 | 218 | 219 | 9050 220 | 221 | 222 | 223 | 224 | 225 | 110 226 | 100 227 | 81 228 | 20 229 | 230 | 231 | 232 | 233 | 10 234 | 235 | 236 | 237 | <html><head/><body><p><span style=" font-weight:600;">Port</span></p></body></html> 238 | 239 | 240 | Qt::AutoText 241 | 242 | 243 | Qt::AlignCenter 244 | 245 | 246 | 247 | 248 | true 249 | 250 | 251 | 252 | 20 253 | 150 254 | 191 255 | 23 256 | 257 | 258 | 259 | 260 | 9 261 | 262 | 263 | 264 | Use proxy to retrieve bridges 265 | 266 | 267 | false 268 | 269 | 270 | 271 | 272 | 273 | 130 274 | 40 275 | 61 276 | 25 277 | 278 | 279 | 280 | 281 | 9 282 | 283 | 284 | 285 | Open file 286 | 287 | 288 | 289 | 290 | 291 | 220 292 | 100 293 | 171 294 | 20 295 | 296 | 297 | 298 | 299 | 10 300 | 301 | 302 | 303 | <html><head/><body><p><span style=" font-weight:600;">Save bridges to</span></p></body></html> 304 | 305 | 306 | Qt::AutoText 307 | 308 | 309 | Qt::AlignCenter 310 | 311 | 312 | 313 | 314 | 315 | 330 316 | 120 317 | 61 318 | 25 319 | 320 | 321 | 322 | 323 | 9 324 | 325 | 326 | 327 | Open file 328 | 329 | 330 | 331 | 332 | 333 | 240 334 | 150 335 | 131 336 | 23 337 | 338 | 339 | 340 | 341 | 9 342 | 343 | 344 | 345 | Save bridges to file 346 | 347 | 348 | 349 | 350 | true 351 | 352 | 353 | 354 | 212 355 | 120 356 | 121 357 | 25 358 | 359 | 360 | 361 | 362 | 9 363 | 364 | 365 | 366 | %user%/tor_bridges 367 | 368 | 369 | true 370 | 371 | 372 | 373 | 374 | true 375 | 376 | 377 | 378 | 12 379 | 40 380 | 121 381 | 25 382 | 383 | 384 | 385 | 386 | 9 387 | 388 | 389 | 390 | 391 | 392 | 393 | true 394 | 395 | 396 | 397 | 398 | 399 | 60 400 | 180 401 | 171 402 | 28 403 | 404 | 405 | 406 | 407 | 9 408 | 409 | 410 | 411 | Show icon in system tray 412 | 413 | 414 | 415 | 416 | 417 | 240 418 | 180 419 | 101 420 | 28 421 | 422 | 423 | 424 | 425 | 9 426 | 427 | 428 | 429 | Close to tray 430 | 431 | 432 | 433 | 434 | 435 | 200 436 | 20 437 | 81 438 | 20 439 | 440 | 441 | 442 | 443 | 10 444 | 445 | 446 | 447 | <html><head/><body><p><span style=" font-weight:600;">Torrc type</span></p></body></html> 448 | 449 | 450 | Qt::RichText 451 | 452 | 453 | Qt::AlignCenter 454 | 455 | 456 | 457 | 458 | 459 | 200 460 | 40 461 | 81 462 | 25 463 | 464 | 465 | 466 | 467 | 9 468 | 469 | 470 | 471 | 472 | daemon 473 | 474 | 475 | 476 | 477 | browser 478 | 479 | 480 | 481 | 482 | 483 | 484 | 20 485 | 230 486 | 361 487 | 25 488 | 489 | 490 | 491 | QDialogButtonBox::Ok 492 | 493 | 494 | true 495 | 496 | 497 | 498 | 499 | 500 | 501 | buttonBox 502 | accepted() 503 | SettingsDialog 504 | accept() 505 | 506 | 507 | 200 508 | 242 509 | 510 | 511 | 199 512 | 149 513 | 514 | 515 | 516 | 517 | 518 | --------------------------------------------------------------------------------