Vidalia  0.2.21
AdvancedPage.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 AdvancedPage.cpp
13 ** \brief Advanced Tor and Vidalia configuration options
14 */
15 
16 #include "AdvancedPage.h"
17 #include "TorrcDialog.h"
18 #include "Vidalia.h"
19 #include "VMessageBox.h"
20 #include "IpValidator.h"
22 
23 #include "file.h"
24 
25 #if defined(Q_WS_WIN)
26 #include "TorService.h"
27 #endif
28 
29 #include <QFile>
30 #include <QFileInfo>
31 #include <QHostAddress>
32 #include <QTextCodec>
33 
34 
35 /** Constructor */
37  : ConfigPage(parent, "Advanced")
38 {
39  /* Invoke the Qt Designer generated object setup routine */
40  ui.setupUi(this);
41 
42  /* Create TorSettings object */
44 
45  /* Set validators for the control port and IP address fields */
46  ui.lineControlAddress->setValidator(new IpValidator(this));
47  ui.lineControlPort->setValidator(new QIntValidator(1, 65535, this));
48 
49  /* Set encoding validators for text boxes containing values that may be
50  * passed to Tor via the control port. */
51  ui.lineTorConfig->setValidator(new Local8BitStringValidator(this));
52  ui.lineTorDataDirectory->setValidator(new Local8BitStringValidator(this));
53  ui.linePassword->setValidator(new Local8BitStringValidator(this));
54 
55  /* Bind event to actions */
56  connect(ui.btnBrowseTorConfig, SIGNAL(clicked()), this, SLOT(browseTorConfig()));
57  connect(ui.btnBrowseTorDataDirectory, SIGNAL(clicked()),
58  this, SLOT(browseTorDataDirectory()));
59  connect(ui.cmbAuthMethod, SIGNAL(currentIndexChanged(int)),
60  this, SLOT(authMethodChanged(int)));
61  connect(ui.chkRandomPassword, SIGNAL(toggled(bool)),
62  ui.linePassword, SLOT(setDisabled(bool)));
63  connect(ui.btnEditTorConfig, SIGNAL(clicked()),
64  this, SLOT(displayTorrcDialog()));
65  connect(ui.rdoControlPort, SIGNAL(toggled(bool)), this, SLOT(toggleControl(bool)));
66  connect(ui.btnBrowseSocketPath, SIGNAL(clicked()), this, SLOT(browseSocketPath()));
67  connect(ui.chkAuto, SIGNAL(toggled(bool)), this, SLOT(toggleAuto(bool)));
68 
69  /* Hide platform specific features */
70 #if defined(Q_WS_WIN)
71 #if 0
72  ui.grpService->setVisible(TorService::isSupported());
73 #endif
74  /* Disable ControlSocket */
75  ui.rdoControlSocket->setEnabled(false);
76 #endif
77 }
78 
79 /** Destructor */
81 {
82  delete _settings;
83 }
84 
85 /** Called when the user changes the UI translation. */
86 void
88 {
89  ui.retranslateUi(this);
90 }
91 
92 /** Applies the network configuration settings to Tor. Returns true if the
93  * settings were applied successfully. Otherwise, <b>errmsg</b> is set
94  * and false is returned. */
95 bool
96 AdvancedPage::apply(QString &errmsg)
97 {
98  return _settings->apply(&errmsg);
99 }
100 
101 /** Reverts the Tor configuration settings to their values at the last
102  * time they were successfully applied to Tor. */
103 bool
105 {
107 }
108 
109 /** Returns true if the user has changed their advanced Tor settings since
110  * the last time they were applied to Tor. */
111 void
113 {
114  return _settings->revert();
115 }
116 
117 /** Saves all settings for this page. */
118 bool
119 AdvancedPage::save(QString &errmsg)
120 {
121  QHostAddress controlAddress(ui.lineControlAddress->text());
122  QString path(ui.lineSocketPath->text());
123 
124  if(ui.chkAuto->isChecked()) {
125  if(ui.lineTorDataDirectory->text().isEmpty()) {
126  errmsg = tr("You've checked the autoconfiguration option for the ControlPort, but"
127  " provided no Data Directory. Please add one, or uncheck the"
128  " \"Configure ControlPort automatically\" option.");
129  return false;
130  }
132  }
133 
134  /* Validate the control settings */
135  if(ui.rdoControlPort->isChecked()) {
136  if (controlAddress.isNull()) {
137  errmsg = tr("'%1' is not a valid IP address.")
138  .arg(ui.lineControlAddress->text());
139  return false;
140  }
142  } else {
143  QFileInfo finfo(path);
144  if(!finfo.exists()) {
145  errmsg = tr("ControlSocket path doesn't exist.");
146  return false;
147  }
149  }
150 
151  /* Validate the selected authentication options */
153  indexToAuthMethod(ui.cmbAuthMethod->currentIndex());
154  if (authMethod == TorSettings::PasswordAuth
155  && ui.linePassword->text().isEmpty()
156  && !ui.chkRandomPassword->isChecked()) {
157  errmsg = tr("You selected 'Password' authentication, but did not "
158  "specify a password.");
159  return false;
160  }
161 
162  /* Ensure that the DataDirectory and torrc options only contain characters
163  * that are valid in the local 8-bit encoding. */
164  if (! Local8BitStringValidator::canEncode(ui.lineTorConfig->text())) {
165  errmsg = tr("The specified Tor configuration file location contains "
166  "characters that cannot be represented in your system's "
167  "current 8-bit character encoding.");
168  return false;
169  }
170  if (! Local8BitStringValidator::canEncode(ui.lineTorDataDirectory->text())) {
171  errmsg = tr("The specified Tor data directory location contains "
172  "characters that cannot be represented in your system's "
173  "current 8-bit character encoding.");
174  return false;
175  }
176 
177  /* Only remember the torrc and datadir values if Vidalia started Tor, or
178  * if the user changed the displayed values. */
179  if (Vidalia::torControl()->isVidaliaRunningTor() or
180  !Vidalia::torControl()->isConnected()) {
181  QString torrc = ui.lineTorConfig->text();
182  if (torrc != _settings->getTorrc()) {
183  _settings->setTorrc(torrc);
184  if(Vidalia::torControl()->isConnected()) {
185  QMessageBox::StandardButtons res = QMessageBox::question(this, tr("Warning"),
186  tr("You changed torrc path, would you like to restart Tor?"),
187  QMessageBox::Yes | QMessageBox::No);
188  if(res == QMessageBox::Yes)
189  emit restartTor();
190  }
191  }
192 
193  QString dataDir = ui.lineTorDataDirectory->text();
194  if (dataDir != _settings->getDataDirectory())
195  _settings->setDataDirectory(dataDir);
196  }
197 
198  if(!ui.chkAuto->isChecked()) {
199  _settings->setControlAddress(controlAddress);
200  _settings->setControlPort(ui.lineControlPort->text().toUShort());
202  }
203  _settings->setSocketPath(ui.lineSocketPath->text());
204 
205  _settings->setAuthenticationMethod(authMethod);
206  _settings->setUseRandomPassword(ui.chkRandomPassword->isChecked());
207  if (authMethod == TorSettings::PasswordAuth
208  && !ui.chkRandomPassword->isChecked())
209  _settings->setControlPassword(ui.linePassword->text());
210 
211 #if 0
212 #if defined(Q_WS_WIN)
213  /* Install or uninstall the Tor service as necessary */
214  setupService(ui.chkUseService->isChecked());
215 #endif
216 #endif
217 
218  return true;
219 }
220 
221 /** Loads previously saved settings. */
222 void
224 {
225  ui.lineControlAddress->setText(_settings->getControlAddress().toString());
226  ui.lineControlPort->setText(QString::number(_settings->getControlPort()));
227  ui.lineTorConfig->setText(_settings->getTorrc());
228  ui.lineTorDataDirectory->setText(_settings->getDataDirectory());
229  ui.chkAuto->setChecked(_settings->autoControlPort());
230 
231  ui.cmbAuthMethod->setCurrentIndex(
233  ui.chkRandomPassword->setChecked(_settings->useRandomPassword());
234  if (!ui.chkRandomPassword->isChecked())
235  ui.linePassword->setText(_settings->getControlPassword());
236  ui.rdoControlPort->setChecked(_settings->getControlMethod() == ControlMethod::Port);
237  ui.rdoControlSocket->setChecked(_settings->getControlMethod() == ControlMethod::Socket);
238  ui.lineSocketPath->setText(_settings->getSocketPath());
239 
240 #if 0
241 #if defined(Q_WS_WIN)
242  TorService s;
243  ui.chkUseService->setChecked(s.isInstalled());
244 #endif
245 #endif
246 
247  if(Vidalia::torControl()->getTorVersion() < 0x2021a) { // 0x2021a == 0.2.2.26
248  ui.chkAuto->setChecked(false);
249  ui.chkAuto->setVisible(false);
250  }
251 }
252 
253 /** Called when the user selects a different authentication method from the
254  * combo box. */
255 void
257 {
258  bool usePassword = (indexToAuthMethod(index) == TorSettings::PasswordAuth);
259  ui.linePassword->setEnabled(usePassword && !ui.chkRandomPassword->isChecked());
260  ui.chkRandomPassword->setEnabled(usePassword);
261 }
262 
263 /** Returns the authentication method for the given <b>index</b>. */
266 {
267  switch (index) {
268  case 0: return TorSettings::NullAuth;
269  case 1: return TorSettings::CookieAuth;
270  case 2: return TorSettings::PasswordAuth;
271  default: break;
272  }
274 }
275 
276 /** Returns the index in the authentication methods combo box for the given
277  * authentication <b>method</b>. */
278 int
280 {
281  switch (method) {
282  case TorSettings::NullAuth: return 0;
283  case TorSettings::CookieAuth: return 1;
284  default: break;
285  }
286  return 2;
287 }
288 
289 /** Open a QFileDialog to browse for Tor config file. */
290 void
292 {
293  /* Prompt the user to select a file or create a new one */
294  QString filename = QFileDialog::getOpenFileName(this,
295  tr("Select Tor Configuration File"),
296  QFileInfo(ui.lineTorConfig->text()).filePath(),
297  tr("Tor Configuration File (torrc);;All Files (*)"));
298 
299  /* Make sure a filename was selected */
300  if (filename.isEmpty()) {
301  return;
302  }
303 
304  /* Check if the file exists */
305  QFile torrcFile(filename);
306  if (!QFileInfo(filename).exists()) {
307  /* The given file does not exist. Should we create it? */
308  int response = VMessageBox::question(this,
309  tr("File Not Found"),
310  tr("%1 does not exist. Would you like to create it?")
311  .arg(filename),
313 
314  if (response == VMessageBox::No) {
315  /* Don't create it. Just bail. */
316  return;
317  }
318  /* Attempt to create the specified file */
319  QString errmsg;
320  if (!touch_file(filename, false, &errmsg)) {
322  tr("Failed to Create File"),
323  tr("Unable to create %1 [%2]").arg(filename)
324  .arg(errmsg),
326  return;
327  }
328  }
329  ui.lineTorConfig->setText(QDir::toNativeSeparators(filename));
330 }
331 
332 /** Opens a QFileDialog for the user to browse to or create a directory for
333  * Tor's DataDirectory. */
334 void
336 {
337  QString dataDir = QFileDialog::getExistingDirectory(this,
338  tr("Select a Directory to Use for Tor Data"),
339  ui.lineTorDataDirectory->text());
340 
341  if (!dataDir.isEmpty())
342  ui.lineTorDataDirectory->setText(QDir::toNativeSeparators(dataDir));
343 }
344 
345 /** Opens a QFileDialog for the user to browse to or create a socket path to
346  * communicate to Tor */
347 void
349 {
350  QString start = QDir::currentPath();
351  if(!ui.lineSocketPath->text().isEmpty())
352  start = ui.lineSocketPath->text();
353  QString socketPath = QFileDialog::getOpenFileName(this,
354  tr("Select a file to use for Tor socket path"),
355  start);
356 
357  if (!socketPath.isEmpty())
358  ui.lineSocketPath->setText(socketPath);
359 }
360 
361 #if 0
362 #if defined(Q_WS_WIN)
363 /** Installs or removes the Tor service as necessary. */
364 void
365 AdvancedPage::setupService(bool useService)
366 {
367  TorService service;
368  bool isInstalled = service.isInstalled();
369 
370  if (!useService && isInstalled) {
371  /* Uninstall if we don't want to use it anymore */
373 
374  if (!service.remove()) {
376  tr("Unable to remove Tor Service"),
377  tr("Vidalia was unable to remove the Tor service.\n\n"
378  "You may need to remove it manually."),
380  }
381  } else if (useService && !isInstalled) {
382  /* Install if we want to start using a service */
383  if (!service.install(_settings->getExecutable(),
384  _settings->getTorrc(),
387  tr("Unable to install Tor Service"),
388  tr("Vidalia was unable to install the Tor service."),
390  }
391  }
392 }
393 #endif
394 #endif
395 
396 /** Called when the user presses the Edit current torrc button */
397 void
399 {
400  TorrcDialog rcdialog(this);
401  rcdialog.exec();
402 }
403 
404 void
406 {
407  if(ui.rdoControlPort->isChecked()) {
408  ui.lblAddress->setEnabled(true);
409  ui.lineControlAddress->setEnabled(true);
410  ui.lineControlPort->setEnabled(true);
411  ui.lblPath->setEnabled(false);
412  ui.lineSocketPath->setEnabled(false);
413  ui.btnBrowseSocketPath->setEnabled(false);
414  ui.chkAuto->setEnabled(true);
415  } else {
416 #if !defined(Q_OS_WIN32)
417  ui.lblAddress->setEnabled(false);
418  ui.lineControlAddress->setEnabled(false);
419  ui.lineControlPort->setEnabled(false);
420  ui.lblPath->setEnabled(true);
421  ui.lineSocketPath->setEnabled(true);
422  ui.btnBrowseSocketPath->setEnabled(true);
423  ui.chkAuto->setEnabled(false);
424 #endif
425  }
426 }
427 
428 void
430 {
431  ui.lblAddress->setVisible(!ui.chkAuto->isChecked());
432  ui.lineControlAddress->setVisible(!ui.chkAuto->isChecked());
433  ui.label->setVisible(!ui.chkAuto->isChecked());
434  ui.lineControlPort->setVisible(!ui.chkAuto->isChecked());
435 }