Vidalia 0.3.1
NetworkPage.cpp
Go to the documentation of this file.
1/*
2** This file is part of Vidalia, and is subject to the license terms in the
3** LICENSE file, found in the top level directory of this distribution. If you
4** did not receive the LICENSE file with this file, you may obtain it from the
5** Vidalia source package distributed by the Vidalia Project at
6** http://www.torproject.org/projects/vidalia.html. No part of Vidalia,
7** including this file, may be copied, modified, propagated, or distributed
8** except according to the terms described in the LICENSE file.
9*/
10
11/*
12** \file NetworkPage.cpp
13** \brief Network and firewall configuration options
14*/
15
16#include "NetworkPage.h"
17#include "NetworkSettings.h"
18#include "VMessageBox.h"
19#include "Vidalia.h"
21#include "DomainValidator.h"
22
23#include "stringutil.h"
24
25#include <QMenu>
26#include <QIntValidator>
27#include <QClipboard>
28#include <QHostAddress>
29#include <QRegExp>
30#include <QMessageBox>
31
32#define IMG_COPY ":/images/22x22/edit-copy.png"
33
34
35/** Constructor */
37: ConfigPage(parent, "Network")
38{
39 /* Invoke the Qt Designer generated object setup routine */
40 ui.setupUi(this);
41
42 connect(ui.btnAddBridge, SIGNAL(clicked()), this, SLOT(addBridge()));
43 connect(ui.btnRemoveBridge, SIGNAL(clicked()), this, SLOT(removeBridge()));
44 connect(ui.btnCopyBridge, SIGNAL(clicked()),
45 this, SLOT(copySelectedBridgesToClipboard()));
46 connect(ui.listBridges, SIGNAL(customContextMenuRequested(QPoint)),
47 this, SLOT(bridgeContextMenuRequested(QPoint)));
48 connect(ui.listBridges, SIGNAL(itemSelectionChanged()),
49 this, SLOT(bridgeSelectionChanged()));
50 connect(ui.lineBridge, SIGNAL(returnPressed()), this, SLOT(addBridge()));
51 connect(ui.lblHelpFindBridges, SIGNAL(linkActivated(QString)),
52 this, SLOT(onLinkActivated(QString)));
53 connect(ui.btnFindBridges, SIGNAL(clicked()), this, SLOT(findBridges()));
54 connect(ui.cmboProxyType, SIGNAL(currentIndexChanged(int)),
55 this, SLOT(proxyTypeChanged(int)));
56
57 ui.lineProxyAddress->setValidator(new DomainValidator(this));
58 ui.lineProxyPort->setValidator(new QIntValidator(1, 65535, this));
59
60 vApp->createShortcut(QKeySequence(QKeySequence::Copy),
61 ui.listBridges, this,
63
65 ui.btnFindBridges->setVisible(false);
66 ui.lblHelpFindBridges->setText(
67 tr("<a href=\"bridges.finding\">How can I find bridges?</a>"));
69 } else {
72 this, SLOT(bridgeRequestFinished(QStringList)));
73 }
74
75#if defined(Q_WS_MAC)
76 /* On OS X, the network page looks better without frame titles. Everywhere
77 * else needs titles or else there's a break in the frame border. */
78 ui.grpProxySettings->setTitle("");
79 ui.grpFirewallSettings->setTitle("");
80 ui.grpBridgeSettings->setTitle("");
81#endif
82}
83
84/** Called when the user changes the UI translation. */
85void
87{
88 ui.retranslateUi(this);
89}
90
91/** Applies the network configuration settings to Tor. Returns true if the *
92 * settings were applied successfully. Otherwise, <b>errmsg</b> is set and *
93 * false is returned. */
94bool
95NetworkPage::apply(QString &errmsg)
96{
97 return NetworkSettings(Vidalia::torControl()).apply(&errmsg);
98}
99
100/** Returns true if the user has changed their server settings since the *
101 * last time they were applied to Tor. */
102bool
104{
106}
107
108/** Reverts the server configuration settings to their values at the last *
109 * time they were successfully applied to Tor. */
110void
112{
114 settings.revert();
115}
116
117/** Called when a link in a label is clicked. <b>url</b> is the target of
118 * the clicked link. */
119void
121{
122 emit helpRequested(url);
123}
124
125/** Adds a bridge to the bridge list box. */
126void
128{
129 QString input = ui.lineBridge->text().trimmed();
130
131 if (input.isEmpty())
132 return;
133 if (!ui.listBridges->findItems(input, Qt::MatchFixedString).isEmpty())
134 return; /* duplicate bridge */
135
136 ui.listBridges->addItem(input);
137 ui.lineBridge->clear();
138}
139
140/** Removes one or more selected bridges from the bridge list box. */
141void
143{
144 qDeleteAll(ui.listBridges->selectedItems());
145}
146
147/** Copies all selected bridges to the clipboard. */
148void
150{
151 QString contents;
152
153 foreach (QListWidgetItem *item, ui.listBridges->selectedItems()) {
154#if defined(Q_WS_WIN)
155 contents += item->text() + "\r\n";
156#else
157 contents += item->text() + "\n";
158#endif
159 }
160 if (!contents.isEmpty())
161 vApp->clipboard()->setText(contents.trimmed());
162}
163
164/** Called when the user right-clicks on a bridge and displays a context
165 * menu. */
166void
168{
169 QMenu menu(this);
170
171 QListWidgetItem *item = ui.listBridges->itemAt(pos);
172 if (!item)
173 return;
174
175 QAction *copyAction =
176 new QAction(QIcon(IMG_COPY), tr("Copy (Ctrl+C)"), &menu);
177 connect(copyAction, SIGNAL(triggered()),
178 this, SLOT(copySelectedBridgesToClipboard()));
179
180 menu.addAction(copyAction);
181 menu.exec(ui.listBridges->mapToGlobal(pos));
182}
183
184/** Called when the user changes which bridges they have selected. */
185void
187{
188 bool enabled = !ui.listBridges->selectedItems().isEmpty();
189 ui.btnCopyBridge->setEnabled(enabled);
190 ui.btnRemoveBridge->setEnabled(enabled);
191}
192
193/** Saves changes made to settings on the Firewall settings page. */
194bool
195NetworkPage::save(QString &errmsg)
196{
198 QString addr;
199 QString user, pass;
201 QStringList bridgeList;
202 QList<quint16> reachablePorts;
203 bool ok;
204
205 if (ui.chkUseProxy->isChecked()) {
206 if (ui.lineProxyAddress->text().isEmpty()
207 || ui.lineProxyPort->text().isEmpty()) {
208 errmsg = tr("You must specify both an IP address or hostname and a "
209 "port number to configure Tor to use a proxy to access "
210 "the Internet.");
211 return false;
212 }
213 if (ui.cmboProxyType->currentIndex() < 0) {
214 errmsg = tr("You must select the proxy type.");
215 return false;
216 }
217 }
218 if (ui.chkFascistFirewall->isChecked()
219 && ui.lineReachablePorts->text().isEmpty()) {
220 errmsg = tr("You must specify one or more ports to which your "
221 "firewall allows you to connect.");
222 return false;
223 }
224
225 if (ui.chkUseProxy->isChecked()) {
226 if (!ui.lineProxyAddress->text().isEmpty()) {
227 addr = ui.lineProxyAddress->text();
228 if (!ui.lineProxyPort->text().isEmpty())
229 addr += ":" + ui.lineProxyPort->text();
230 }
231
232 user = ui.lineProxyUsername->text();
233 pass = ui.lineProxyPassword->text();
234
235 QVariant data;
236 int type;
237
238 data = ui.cmboProxyType->itemData(ui.cmboProxyType->currentIndex());
239 Q_ASSERT(data.isValid());
240 type = data.toInt();
241 Q_ASSERT(type >= NetworkSettings::ProxyTypeMin &&
243 proxy = static_cast<NetworkSettings::ProxyType>(type);
244 }
245
246 settings.setProxyType(proxy);
247 settings.setProxyAddress(addr);
248 settings.setProxyUsername(user);
249 settings.setProxyPassword(pass);
250
251 /* Save the reachable port settings */
252 settings.setFascistFirewall(ui.chkFascistFirewall->isChecked());
253 foreach (QString portString,
254 ui.lineReachablePorts->text().split(",", QString::SkipEmptyParts)) {
255 quint32 port = portString.toUInt(&ok);
256 if (!ok || port < 1 || port > 65535) {
257 errmsg = tr("'%1' is not a valid port number.").arg(portString);
258 return false;
259 }
260 reachablePorts << (quint16)port;
261 }
262 settings.setReachablePorts(reachablePorts);
263
264 if (ui.chkUseBridges->isChecked()) {
265 if (ui.listBridges->count() < 1) {
266 errmsg = tr("You must specify one or more bridges.");
267 return false;
268 }
269 }
270
271 /* Save the bridge settings */
272 settings.setUseBridges(ui.chkUseBridges->isChecked());
273 for (int i = 0; i < ui.listBridges->count(); i++)
274 bridgeList << ui.listBridges->item(i)->text();
275 settings.setBridgeList(bridgeList);
276
277 return true;
278}
279
280/** Loads previously saved settings */
281void
283{
285 QStringList reachablePortStrings;
287
288 /* Load proxy settings */
289 proxyType = settings.getProxyType();
290 ui.chkUseProxy->setChecked(proxyType != NetworkSettings::NoProxy);
291 QStringList proxy = settings.getProxyAddress().split(":");
292 if (proxy.size() >= 1)
293 ui.lineProxyAddress->setText(proxy.at(0));
294 if (proxy.size() >= 2)
295 ui.lineProxyPort->setText(proxy.at(1));
296 ui.lineProxyUsername->setText(settings.getProxyUsername());
297 ui.lineProxyPassword->setText(settings.getProxyPassword());
298
299 /* SOCKS options are only available on Tor >= 0.2.2.1-alpha, so don't show
300 * them if Tor is running and its version is less than that. */
301 ui.cmboProxyType->clear();
302 if (!vApp->torControl()->isRunning()
303 || vApp->torControl()->getTorVersion() >= 0x020201) {
304 ui.cmboProxyType->addItem(tr("SOCKS 4"), NetworkSettings::Socks4Proxy);
305 ui.cmboProxyType->addItem(tr("SOCKS 5"), NetworkSettings::Socks5Proxy);
306 } else if (proxyType == NetworkSettings::Socks4Proxy
307 || proxyType == NetworkSettings::Socks5Proxy) {
308 /* Disable proxy if the settings include a SOCKS proxy and our version of
309 * Tor is not compatible. */
310 proxyType = NetworkSettings::NoProxy;
311 ui.chkUseProxy->setChecked(false);
312 }
313 ui.cmboProxyType->addItem(tr("HTTP / HTTPS"),
315
316 ui.cmboProxyType->setCurrentIndex(ui.cmboProxyType->findData(proxyType));
317
318 /* Load firewall settings */
319 ui.chkFascistFirewall->setChecked(settings.getFascistFirewall());
320 QList<quint16> reachablePorts = settings.getReachablePorts();
321 foreach (quint16 port, reachablePorts) {
322 reachablePortStrings << QString::number(port);
323 }
324 ui.lineReachablePorts->setText(reachablePortStrings.join(","));
325
326 /* Load bridge settings */
327 ui.chkUseBridges->setChecked(settings.getUseBridges());
328 ui.listBridges->clear();
329 ui.listBridges->addItems(settings.getBridgeList());
330}
331
332/** Called when the user clicks the "Find Bridges Now" button.
333 * Attempts to establish an HTTPS connection to bridges.torproject.org
334 * and download one or more bridge addresses. */
335void
337{
339
340 connect(_bridgeDownloader, SIGNAL(statusChanged(QString)),
341 dlg, SLOT(setStatus(QString)));
342 connect(_bridgeDownloader, SIGNAL(downloadProgress(qint64, qint64)),
343 dlg, SLOT(setDownloadProgress(qint64, qint64)));
344 connect(_bridgeDownloader, SIGNAL(bridgeRequestFailed(QString)),
345 dlg, SLOT(bridgeRequestFailed(QString)));
346 connect(_bridgeDownloader, SIGNAL(bridgeRequestFinished(QStringList)),
347 dlg, SLOT(bridgeRequestFinished(QStringList)));
348 connect(dlg, SIGNAL(retry()), this, SLOT(startBridgeRequest()));
349
351 switch (dlg->exec()) {
352 case QDialogButtonBox::Cancel:
354 break;
355
356 case QDialogButtonBox::Help:
357 emit helpRequested("bridges.finding");
358 break;
359 }
360
361 delete dlg;
362}
363
364/** Starts a new request for additional bridge addresses. */
365void
367{
368 if (ui.chkUseProxy->isChecked() &&
369 ui.cmboProxyType->currentIndex() == NetworkSettings::HttpHttpsProxy) {
370 _bridgeDownloader->setProxy(ui.lineProxyAddress->text(),
371 ui.lineProxyPort->text().toUInt(),
372 ui.lineProxyUsername->text(),
373 ui.lineProxyPassword->text());
374 }
375
377}
378
379/** Called when a previous bridge request initiated by the findBridges()
380 * method has completed. <b>bridges</b> contains a list of all bridges
381 * received. */
382void
383NetworkPage::bridgeRequestFinished(const QStringList &bridges)
384{
385 bool foundNewBridges = false;
386 QString normalized;
387
388 foreach (QString bridge, bridges) {
389 QString address = normalized.split(" ").at(0);
390 if (ui.listBridges->findItems(address, Qt::MatchContains).isEmpty()) {
391 ui.listBridges->addItem(normalized);
392 foundNewBridges = true;
393 }
394 }
395
396 if (! foundNewBridges) {
397 QMessageBox dlg(this);
398 dlg.setIcon(QMessageBox::Information);
399 dlg.setText(tr("No new bridges are currently available. You can either "
400 "wait a while and try again, or try another method of "
401 "finding new bridges."));
402 dlg.setInformativeText(tr("Click Help to see other methods of finding "
403 "new bridges."));
404 dlg.setStandardButtons(QMessageBox::Ok | QMessageBox::Help);
405
406 if (dlg.exec() == QMessageBox::Help)
407 emit helpRequested("bridges.finding");
408 }
409}
410
411/** Disable proxy username and password fields when the user wants to use
412 * a SOCKS 4 proxy. */
413void
415{
416 QVariant data = ui.cmboProxyType->itemData(selection);
417
418 if (data.isValid()
419 && data.toInt() == NetworkSettings::Socks4Proxy) {
420 ui.lineProxyUsername->setEnabled(false);
421 ui.lineProxyPassword->setEnabled(false);
422 } else {
423 ui.lineProxyUsername->setEnabled(true);
424 ui.lineProxyPassword->setEnabled(true);
425 }
426}
427
#define IMG_COPY
Definition: NetworkPage.cpp:32
stop errmsg connect(const QHostAddress &address, quint16 port)
stop errmsg QVariant
#define vApp
Definition: Vidalia.h:37
virtual bool changedSinceLastApply() const
static bool isMethodSupported(BridgeDownloadMethod method)
void setProxy(const QString &host, int port, const QString &username=QString(), const QString &password=QString())
bool downloadBridges(BridgeDownloadMethod method)
void helpRequested(const QString &topic)
void findBridges()
void bridgeContextMenuRequested(const QPoint &pos)
bool save(QString &errmsg)
virtual void retranslateUi()
Definition: NetworkPage.cpp:86
bool apply(QString &errmsg)
Definition: NetworkPage.cpp:95
void onLinkActivated(const QString &url)
void bridgeRequestFinished(const QStringList &bridges)
bool changedSinceLastApply()
void addBridge()
void bridgeSelectionChanged()
void removeBridge()
void proxyTypeChanged(int selection)
void copySelectedBridgesToClipboard()
Ui::NetworkPage ui
Definition: NetworkPage.h:89
NetworkPage(QWidget *parent=0)
Definition: NetworkPage.cpp:36
BridgeDownloader * _bridgeDownloader
Definition: NetworkPage.h:86
void startBridgeRequest()
QString getProxyAddress()
QList< quint16 > getReachablePorts()
ProxyType getProxyType()
QStringList getBridgeList()
void setProxyUsername(const QString &user)
void setReachablePorts(const QList< quint16 > &reachablePorts)
QString getProxyUsername()
bool apply(QString *errmsg=0)
void setBridgeList(const QStringList &bridgeList)
void setUseBridges(bool useBridges)
QString getProxyPassword()
void setProxyAddress(const QString &addr)
void setFascistFirewall(bool fascistFirewall)
void setProxyPassword(const QString &pass)
void setProxyType(ProxyType type)
static TorControl * torControl()
Definition: Vidalia.h:76
QString i(QString str)
Definition: html.cpp:32