Vidalia  0.2.21
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"
20 #include "DomainValidator.h"
21 
22 #include "stringutil.h"
23 
24 #include <QMenu>
25 #include <QIntValidator>
26 #include <QClipboard>
27 #include <QHostAddress>
28 #include <QRegExp>
29 #include <QMessageBox>
30 
31 #define IMG_COPY ":/images/22x22/edit-copy.png"
32 
33 
34 /** Constructor */
35 NetworkPage::NetworkPage(QWidget *parent)
36 : ConfigPage(parent, "Network")
37 {
38  /* Invoke the Qt Designer generated object setup routine */
39  ui.setupUi(this);
40 
41  connect(ui.btnAddBridge, SIGNAL(clicked()), this, SLOT(addBridge()));
42  connect(ui.btnRemoveBridge, SIGNAL(clicked()), this, SLOT(removeBridge()));
43  connect(ui.btnCopyBridge, SIGNAL(clicked()),
44  this, SLOT(copySelectedBridgesToClipboard()));
45  connect(ui.listBridges, SIGNAL(customContextMenuRequested(QPoint)),
46  this, SLOT(bridgeContextMenuRequested(QPoint)));
47  connect(ui.listBridges, SIGNAL(itemSelectionChanged()),
48  this, SLOT(bridgeSelectionChanged()));
49  connect(ui.lineBridge, SIGNAL(returnPressed()), this, SLOT(addBridge()));
50  connect(ui.lblHelpFindBridges, SIGNAL(linkActivated(QString)),
51  this, SLOT(onLinkActivated(QString)));
52  connect(ui.cmboProxyType, SIGNAL(currentIndexChanged(int)),
53  this, SLOT(proxyTypeChanged(int)));
54 
55  ui.lineProxyAddress->setValidator(new DomainValidator(this));
56  ui.lineProxyPort->setValidator(new QIntValidator(1, 65535, this));
57 
58  vApp->createShortcut(QKeySequence(QKeySequence::Copy),
59  ui.listBridges, this,
61 
62 #if defined(Q_WS_MAC)
63  /* On OS X, the network page looks better without frame titles. Everywhere
64  * else needs titles or else there's a break in the frame border. */
65  ui.grpProxySettings->setTitle("");
66  ui.grpFirewallSettings->setTitle("");
67  ui.grpBridgeSettings->setTitle("");
68 #endif
69 }
70 
71 /** Called when the user changes the UI translation. */
72 void
74 {
75  ui.retranslateUi(this);
76 }
77 
78 /** Applies the network configuration settings to Tor. Returns true if the *
79  * settings were applied successfully. Otherwise, <b>errmsg</b> is set and *
80  * false is returned. */
81 bool
82 NetworkPage::apply(QString &errmsg)
83 {
84  return NetworkSettings(Vidalia::torControl()).apply(&errmsg);
85 }
86 
87 /** Returns true if the user has changed their server settings since the *
88  * last time they were applied to Tor. */
89 bool
91 {
93 }
94 
95 /** Reverts the server configuration settings to their values at the last *
96  * time they were successfully applied to Tor. */
97 void
99 {
101  settings.revert();
102 }
103 
104 /** Called when a link in a label is clicked. <b>url</b> is the target of
105  * the clicked link. */
106 void
107 NetworkPage::onLinkActivated(const QString &url)
108 {
109  emit helpRequested(url);
110 }
111 
112 /** Adds a bridge to the bridge list box. */
113 void
115 {
116  QString input = ui.lineBridge->text().trimmed();
117 
118  if (input.isEmpty())
119  return;
120  if (!ui.listBridges->findItems(input, Qt::MatchFixedString).isEmpty())
121  return; /* duplicate bridge */
122 
123  ui.listBridges->addItem(input);
124  ui.lineBridge->clear();
125 }
126 
127 /** Removes one or more selected bridges from the bridge list box. */
128 void
130 {
131  qDeleteAll(ui.listBridges->selectedItems());
132 }
133 
134 /** Copies all selected bridges to the clipboard. */
135 void
137 {
138  QString contents;
139 
140  foreach (QListWidgetItem *item, ui.listBridges->selectedItems()) {
141 #if defined(Q_WS_WIN)
142  contents += item->text() + "\r\n";
143 #else
144  contents += item->text() + "\n";
145 #endif
146  }
147  if (!contents.isEmpty())
148  vApp->clipboard()->setText(contents.trimmed());
149 }
150 
151 /** Called when the user right-clicks on a bridge and displays a context
152  * menu. */
153 void
155 {
156  QMenu menu(this);
157 
158  QListWidgetItem *item = ui.listBridges->itemAt(pos);
159  if (!item)
160  return;
161 
162  QAction *copyAction =
163  new QAction(QIcon(IMG_COPY), tr("Copy (Ctrl+C)"), &menu);
164  connect(copyAction, SIGNAL(triggered()),
165  this, SLOT(copySelectedBridgesToClipboard()));
166 
167  menu.addAction(copyAction);
168  menu.exec(ui.listBridges->mapToGlobal(pos));
169 }
170 
171 /** Called when the user changes which bridges they have selected. */
172 void
174 {
175  bool enabled = !ui.listBridges->selectedItems().isEmpty();
176  ui.btnCopyBridge->setEnabled(enabled);
177  ui.btnRemoveBridge->setEnabled(enabled);
178 }
179 
180 /** Saves changes made to settings on the Firewall settings page. */
181 bool
182 NetworkPage::save(QString &errmsg)
183 {
185  QString addr;
186  QString user, pass;
188  QStringList bridgeList;
189  QList<quint16> reachablePorts;
190  bool ok;
191 
192  if (ui.chkUseProxy->isChecked()) {
193  if (ui.lineProxyAddress->text().isEmpty()
194  || ui.lineProxyPort->text().isEmpty()) {
195  errmsg = tr("You must specify both an IP address or hostname and a "
196  "port number to configure Tor to use a proxy to access "
197  "the Internet.");
198  return false;
199  }
200  if (ui.cmboProxyType->currentIndex() < 0) {
201  errmsg = tr("You must select the proxy type.");
202  return false;
203  }
204  }
205  if (ui.chkFascistFirewall->isChecked()
206  && ui.lineReachablePorts->text().isEmpty()) {
207  errmsg = tr("You must specify one or more ports to which your "
208  "firewall allows you to connect.");
209  return false;
210  }
211 
212  if (ui.chkUseProxy->isChecked()) {
213  if (!ui.lineProxyAddress->text().isEmpty()) {
214  addr = ui.lineProxyAddress->text();
215  if (!ui.lineProxyPort->text().isEmpty())
216  addr += ":" + ui.lineProxyPort->text();
217  }
218 
219  user = ui.lineProxyUsername->text();
220  pass = ui.lineProxyPassword->text();
221 
222  QVariant data;
223  int type;
224 
225  data = ui.cmboProxyType->itemData(ui.cmboProxyType->currentIndex());
226  Q_ASSERT(data.isValid());
227  type = data.toInt();
228  Q_ASSERT(type >= NetworkSettings::ProxyTypeMin &&
230  proxy = static_cast<NetworkSettings::ProxyType>(type);
231  }
232 
233  settings.setProxyType(proxy);
234  settings.setProxyAddress(addr);
235  settings.setProxyUsername(user);
236  settings.setProxyPassword(pass);
237 
238  /* Save the reachable port settings */
239  settings.setFascistFirewall(ui.chkFascistFirewall->isChecked());
240  foreach (QString portString,
241  ui.lineReachablePorts->text().split(",", QString::SkipEmptyParts)) {
242  quint32 port = portString.toUInt(&ok);
243  if (!ok || port < 1 || port > 65535) {
244  errmsg = tr("'%1' is not a valid port number.").arg(portString);
245  return false;
246  }
247  reachablePorts << (quint16)port;
248  }
249  settings.setReachablePorts(reachablePorts);
250 
251  if (ui.chkUseBridges->isChecked()) {
252  if (ui.listBridges->count() < 1) {
253  errmsg = tr("You must specify one or more bridges.");
254  return false;
255  }
256  }
257 
258  /* Save the bridge settings */
259  settings.setUseBridges(ui.chkUseBridges->isChecked());
260  for (int i = 0; i < ui.listBridges->count(); i++)
261  bridgeList << ui.listBridges->item(i)->text();
262  settings.setBridgeList(bridgeList);
263 
264  return true;
265 }
266 
267 /** Loads previously saved settings */
268 void
270 {
272  QStringList reachablePortStrings;
273  NetworkSettings::ProxyType proxyType;
274 
275  /* Load proxy settings */
276  proxyType = settings.getProxyType();
277  ui.chkUseProxy->setChecked(proxyType != NetworkSettings::NoProxy);
278  QStringList proxy = settings.getProxyAddress().split(":");
279  if (proxy.size() >= 1)
280  ui.lineProxyAddress->setText(proxy.at(0));
281  if (proxy.size() >= 2)
282  ui.lineProxyPort->setText(proxy.at(1));
283  ui.lineProxyUsername->setText(settings.getProxyUsername());
284  ui.lineProxyPassword->setText(settings.getProxyPassword());
285 
286  /* SOCKS options are only available on Tor >= 0.2.2.1-alpha, so don't show
287  * them if Tor is running and its version is less than that. */
288  ui.cmboProxyType->clear();
289  if (!vApp->torControl()->isRunning()
290  || vApp->torControl()->getTorVersion() >= 0x020201) {
291  ui.cmboProxyType->addItem(tr("SOCKS 4"), NetworkSettings::Socks4Proxy);
292  ui.cmboProxyType->addItem(tr("SOCKS 5"), NetworkSettings::Socks5Proxy);
293  } else if (proxyType == NetworkSettings::Socks4Proxy
294  || proxyType == NetworkSettings::Socks5Proxy) {
295  /* Disable proxy if the settings include a SOCKS proxy and our version of
296  * Tor is not compatible. */
297  proxyType = NetworkSettings::NoProxy;
298  ui.chkUseProxy->setChecked(false);
299  }
300  ui.cmboProxyType->addItem(tr("HTTP / HTTPS"),
302 
303  ui.cmboProxyType->setCurrentIndex(ui.cmboProxyType->findData(proxyType));
304 
305  /* Load firewall settings */
306  ui.chkFascistFirewall->setChecked(settings.getFascistFirewall());
307  QList<quint16> reachablePorts = settings.getReachablePorts();
308  foreach (quint16 port, reachablePorts) {
309  reachablePortStrings << QString::number(port);
310  }
311  ui.lineReachablePorts->setText(reachablePortStrings.join(","));
312 
313  /* Load bridge settings */
314  ui.chkUseBridges->setChecked(settings.getUseBridges());
315  ui.listBridges->clear();
316  ui.listBridges->addItems(settings.getBridgeList());
317 }
318 
319 /** Disable proxy username and password fields when the user wants to use
320  * a SOCKS 4 proxy. */
321 void
323 {
324  QVariant data = ui.cmboProxyType->itemData(selection);
325 
326  if (data.isValid()
327  && data.toInt() == NetworkSettings::Socks4Proxy) {
328  ui.lineProxyUsername->setEnabled(false);
329  ui.lineProxyPassword->setEnabled(false);
330  } else {
331  ui.lineProxyUsername->setEnabled(true);
332  ui.lineProxyPassword->setEnabled(true);
333  }
334 }
335