Vidalia  0.3.1
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.chkRandomPassword, SIGNAL(toggled(bool)),
64  this, SLOT(displayWarning(bool)));
65  connect(ui.btnEditTorConfig, SIGNAL(clicked()),
66  this, SLOT(displayTorrcDialog()));
67  connect(ui.rdoControlPort, SIGNAL(toggled(bool)), this, SLOT(toggleControl(bool)));
68  connect(ui.btnBrowseSocketPath, SIGNAL(clicked()), this, SLOT(browseSocketPath()));
69  connect(ui.chkAuto, SIGNAL(toggled(bool)), this, SLOT(toggleAuto(bool)));
70 
71  /* Hide platform specific features */
72 #if defined(Q_WS_WIN)
73 #if 0
74  ui.grpService->setVisible(TorService::isSupported());
75 #endif
76  /* Disable ControlSocket */
77  ui.rdoControlSocket->setEnabled(false);
78 #endif
79 }
80 
81 /** Destructor */
83 {
84  delete _settings;
85 }
86 
87 /** Called when the user changes the UI translation. */
88 void
90 {
91  ui.retranslateUi(this);
92 }
93 
94 /** Applies the network configuration settings to Tor. Returns true if the
95  * settings were applied successfully. Otherwise, <b>errmsg</b> is set
96  * and false is returned. */
97 bool
98 AdvancedPage::apply(QString &errmsg)
99 {
100  return _settings->apply(&errmsg);
101 }
102 
103 /** Reverts the Tor configuration settings to their values at the last
104  * time they were successfully applied to Tor. */
105 bool
107 {
109 }
110 
111 /** Returns true if the user has changed their advanced Tor settings since
112  * the last time they were applied to Tor. */
113 void
115 {
116  return _settings->revert();
117 }
118 
119 /** Saves all settings for this page. */
120 bool
121 AdvancedPage::save(QString &errmsg)
122 {
123  QHostAddress controlAddress(ui.lineControlAddress->text());
124  QString path(ui.lineSocketPath->text());
125 
126  if(ui.chkAuto->isChecked()) {
127  if(ui.lineTorDataDirectory->text().isEmpty()) {
128  errmsg = tr("You've checked the autoconfiguration option for the ControlPort, but"
129  " provided no Data Directory. Please add one, or uncheck the"
130  " \"Configure ControlPort automatically\" option.");
131  return false;
132  }
134  }
135 
136  /* Validate the control settings */
137  if(ui.rdoControlPort->isChecked()) {
138  if (controlAddress.isNull()) {
139  errmsg = tr("'%1' is not a valid IP address.")
140  .arg(ui.lineControlAddress->text());
141  return false;
142  }
144  } else {
145  QFileInfo finfo(path);
146  if(!finfo.exists()) {
147  errmsg = tr("ControlSocket path doesn't exist.");
148  return false;
149  }
151  }
152 
153  /* Validate the selected authentication options */
155  indexToAuthMethod(ui.cmbAuthMethod->currentIndex());
156  if (authMethod == TorSettings::PasswordAuth
157  && ui.linePassword->text().isEmpty()
158  && !ui.chkRandomPassword->isChecked()) {
159  errmsg = tr("You selected 'Password' authentication, but did not "
160  "specify a password.");
161  return false;
162  }
163 
164  /* Ensure that the DataDirectory and torrc options only contain characters
165  * that are valid in the local 8-bit encoding. */
166  if (! Local8BitStringValidator::canEncode(ui.lineTorConfig->text())) {
167  errmsg = tr("The specified Tor configuration file location contains "
168  "characters that cannot be represented in your system's "
169  "current 8-bit character encoding.");
170  return false;
171  }
172  if (! Local8BitStringValidator::canEncode(ui.lineTorDataDirectory->text())) {
173  errmsg = tr("The specified Tor data directory location contains "
174  "characters that cannot be represented in your system's "
175  "current 8-bit character encoding.");
176  return false;
177  }
178 
179  /* Only remember the torrc and datadir values if Vidalia started Tor, or
180  * if the user changed the displayed values. */
183  QString torrc = ui.lineTorConfig->text();
184  if (torrc != _settings->getTorrc()) {
185  _settings->setTorrc(torrc);
187  QMessageBox::StandardButtons res = QMessageBox::question(this, tr("Warning"),
188  tr("You changed torrc path, would you like to restart Tor?"),
189  QMessageBox::Yes | QMessageBox::No);
190  if(res == QMessageBox::Yes)
191  emit restartTor();
192  }
193  }
194 
195  QString dataDir = ui.lineTorDataDirectory->text();
196  if (dataDir != _settings->getDataDirectory())
197  _settings->setDataDirectory(dataDir);
198  }
199 
200  if(!ui.chkAuto->isChecked()) {
201  _settings->setControlAddress(controlAddress);
202  _settings->setControlPort(ui.lineControlPort->text().toUShort());
204  }
205  _settings->setSocketPath(ui.lineSocketPath->text());
206 
207  _settings->setAuthenticationMethod(authMethod);
208  _settings->setUseRandomPassword(ui.chkRandomPassword->isChecked());
209  if (authMethod == TorSettings::PasswordAuth
210  && !ui.chkRandomPassword->isChecked())
211  _settings->setControlPassword(ui.linePassword->text());
212 
213 #if 0
214 #if defined(Q_WS_WIN)
215  /* Install or uninstall the Tor service as necessary */
216  setupService(ui.chkUseService->isChecked());
217 #endif
218 #endif
219 
220  return true;
221 }
222 
223 /** Loads previously saved settings. */
224 void
226 {
227  ui.lineControlAddress->setText(_settings->getControlAddress().toString());
228  ui.lineControlPort->setText(QString::number(_settings->getControlPort()));
229  ui.lineTorConfig->setText(_settings->getTorrc());
230  ui.lineTorDataDirectory->setText(_settings->getDataDirectory());
231  ui.chkAuto->setChecked(_settings->autoControlPort());
232 
233  ui.cmbAuthMethod->setCurrentIndex(
235  ui.chkRandomPassword->setChecked(_settings->useRandomPassword());
236  if (!ui.chkRandomPassword->isChecked())
237  ui.linePassword->setText(_settings->getControlPassword());
238  ui.rdoControlPort->setChecked(_settings->getControlMethod() == ControlMethod::Port);
239  ui.rdoControlSocket->setChecked(_settings->getControlMethod() == ControlMethod::Socket);
240  ui.lineSocketPath->setText(_settings->getSocketPath());
241 
242 #if 0
243 #if defined(Q_WS_WIN)
244  TorService s;
245  ui.chkUseService->setChecked(s.isInstalled());
246 #endif
247 #endif
248  if(Vidalia::torControl()->getTorVersion() < 0x2021a) { // 0x2021a == 0.2.2.26
249  ui.chkAuto->setChecked(false);
250  ui.chkAuto->setVisible(false);
251  }
252 }
253 
254 /** Called when the user selects a different authentication method from the
255  * combo box. */
256 void
258 {
259  bool usePassword = (indexToAuthMethod(index) == TorSettings::PasswordAuth);
260  ui.linePassword->setEnabled(usePassword && !ui.chkRandomPassword->isChecked());
261  ui.chkRandomPassword->setEnabled(usePassword);
262  ui.lblWarn->setVisible((ui.chkRandomPassword->checkState() == Qt::Unchecked) and usePassword);
263 }
264 
265 /** Returns the authentication method for the given <b>index</b>. */
268 {
269  switch (index) {
270  case 0: return TorSettings::NullAuth;
271  case 1: return TorSettings::CookieAuth;
272  case 2: return TorSettings::PasswordAuth;
273  default: break;
274  }
276 }
277 
278 /** Returns the index in the authentication methods combo box for the given
279  * authentication <b>method</b>. */
280 int
282 {
283  switch (method) {
284  case TorSettings::NullAuth: return 0;
285  case TorSettings::CookieAuth: return 1;
286  default: break;
287  }
288  return 2;
289 }
290 
291 /** Open a QFileDialog to browse for Tor config file. */
292 void
294 {
295  /* Prompt the user to select a file or create a new one */
296  QString filename = QFileDialog::getOpenFileName(this,
297  tr("Select Tor Configuration File"),
298  QFileInfo(ui.lineTorConfig->text()).filePath(),
299  tr("Tor Configuration File (torrc);;All Files (*)"));
300 
301  /* Make sure a filename was selected */
302  if (filename.isEmpty()) {
303  return;
304  }
305 
306  /* Check if the file exists */
307  QFile torrcFile(filename);
308  if (!QFileInfo(filename).exists()) {
309  /* The given file does not exist. Should we create it? */
310  int response = VMessageBox::question(this,
311  tr("File Not Found"),
312  tr("%1 does not exist. Would you like to create it?")
313  .arg(filename),
315 
316  if (response == VMessageBox::No) {
317  /* Don't create it. Just bail. */
318  return;
319  }
320  /* Attempt to create the specified file */
321  QString errmsg;
322  if (!touch_file(filename, false, &errmsg)) {
324  tr("Failed to Create File"),
325  tr("Unable to create %1 [%2]").arg(filename)
326  .arg(errmsg),
328  return;
329  }
330  }
331  ui.lineTorConfig->setText(filename);
332 }
333 
334 /** Opens a QFileDialog for the user to browse to or create a directory for
335  * Tor's DataDirectory. */
336 void
338 {
339  QString dataDir = QFileDialog::getExistingDirectory(this,
340  tr("Select a Directory to Use for Tor Data"),
341  ui.lineTorDataDirectory->text());
342 
343  if (!dataDir.isEmpty())
344  ui.lineTorDataDirectory->setText(dataDir);
345 }
346 
347 /** Opens a QFileDialog for the user to browse to or create a socket path to
348  * communicate to Tor */
349 void
351 {
352  QString start = QDir::currentPath();
353  if(!ui.lineSocketPath->text().isEmpty())
354  start = ui.lineSocketPath->text();
355  QString socketPath = QFileDialog::getOpenFileName(this,
356  tr("Select a file to use for Tor socket path"),
357  start);
358 
359  if (!socketPath.isEmpty())
360  ui.lineSocketPath->setText(socketPath);
361 }
362 
363 #if 0
364 #if defined(Q_WS_WIN)
365 /** Installs or removes the Tor service as necessary. */
366 void
367 AdvancedPage::setupService(bool useService)
368 {
369  TorService service;
370  bool isInstalled = service.isInstalled();
371 
372  if (!useService && isInstalled) {
373  /* Uninstall if we don't want to use it anymore */
375 
376  if (!service.remove()) {
378  tr("Unable to remove Tor Service"),
379  tr("Vidalia was unable to remove the Tor service.\n\n"
380  "You may need to remove it manually."),
382  }
383  } else if (useService && !isInstalled) {
384  /* Install if we want to start using a service */
385  if (!service.install(_settings->getExecutable(),
386  _settings->getTorrc(),
389  tr("Unable to install Tor Service"),
390  tr("Vidalia was unable to install the Tor service."),
392  }
393  }
394 }
395 #endif
396 #endif
397 
398 /** Called when the user presses the Edit current torrc button */
399 void
401 {
402  TorrcDialog rcdialog(this);
403  rcdialog.exec();
404 }
405 
406 void
408 {
409  if(ui.rdoControlPort->isChecked()) {
410  ui.lblAddress->setEnabled(true);
411  ui.lineControlAddress->setEnabled(true);
412  ui.lineControlPort->setEnabled(true);
413  ui.lblPath->setEnabled(false);
414  ui.lineSocketPath->setEnabled(false);
415  ui.btnBrowseSocketPath->setEnabled(false);
416  ui.chkAuto->setEnabled(true);
417  } else {
418 #if !defined(Q_OS_WIN32)
419  ui.lblAddress->setEnabled(false);
420  ui.lineControlAddress->setEnabled(false);
421  ui.lineControlPort->setEnabled(false);
422  ui.lblPath->setEnabled(true);
423  ui.lineSocketPath->setEnabled(true);
424  ui.btnBrowseSocketPath->setEnabled(true);
425  ui.chkAuto->setEnabled(false);
426 #endif
427  }
428 }
429 
430 void
432 {
433  ui.lblAddress->setVisible(!ui.chkAuto->isChecked());
434  ui.lineControlAddress->setVisible(!ui.chkAuto->isChecked());
435  ui.label->setVisible(!ui.chkAuto->isChecked());
436  ui.lineControlPort->setVisible(!ui.chkAuto->isChecked());
437 }
438 
439 void
441 {
442  ui.lblWarn->setVisible(!checked and
443  indexToAuthMethod(ui.cmbAuthMethod->currentIndex()) ==
445 }
void setControlPort(quint16 port)
bool touch_file(const QString &filename, bool createdir, QString *errmsg)
Definition: file.cpp:31
bool stop(QString *errmsg=0)
Definition: TorControl.cpp:131
void browseTorDataDirectory()
void setControlMethod(ControlMethod::Method method)
TorSettings::AuthenticationMethod indexToAuthMethod(int index)
bool install(const QString &torPath, const QString &torrc, quint16 controlPort)
Definition: TorService.cpp:239
void toggleAuto(bool)
QString getTorrc() const
QString getControlPassword() const
quint32 getTorVersion()
Definition: TorControl.cpp:667
bool useRandomPassword() const
void authMethodChanged(int index)
int authMethodToIndex(TorSettings::AuthenticationMethod method)
bool save(QString &errmsg)
QString getDataDirectory() const
void restartTor()
void setControlPassword(const QString &password)
void displayTorrcDialog()
static bool isSupported()
Definition: TorService.cpp:48
void setControlAddress(const QHostAddress &addr)
static TorControl * torControl()
Definition: Vidalia.h:76
virtual bool changedSinceLastApply() const
bool isInstalled()
Definition: TorService.cpp:119
stop errmsg connect(const QHostAddress &address, quint16 port)
void browseSocketPath()
stop errmsg isVidaliaRunningTor()
AdvancedPage(QWidget *parent=0)
static int critical(QWidget *parent, QString caption, QString text, int button0, int button1=NoButton, int button2=NoButton)
AuthenticationMethod getAuthenticationMethod() const
void setSocketPath(const QString &path)
void setAuthenticationMethod(AuthenticationMethod method)
ControlMethod::Method getControlMethod() const
void setDataDirectory(const QString &dataDir)
static int warning(QWidget *parent, QString caption, QString text, int button0, int button1=NoButton, int button2=NoButton)
void setAutoControlPort(const bool auto)
TorSettings * _settings
Definition: AdvancedPage.h:99
void setUseRandomPassword(bool useRandomPassword)
QString getExecutable() const
void setTorrc(const QString &torrc)
static int question(QWidget *parent, QString caption, QString text, int button0, int button1=NoButton, int button2=NoButton, QString remember=QString(), VSettings *settings=0, QString key=QString())
void displayWarning(bool)
bool apply(QString *errmsg=0)
bool apply(QString &errmsg)
QString getSocketPath() const
bool changedSinceLastApply()
QHostAddress getControlAddress() const
void browseTorConfig()
Ui::AdvancedPage ui
Definition: AdvancedPage.h:101
static bool canEncode(const QString &input)
virtual void retranslateUi()
bool remove()
Definition: TorService.cpp:280
void toggleControl(bool)
quint16 getControlPort() const
bool autoControlPort() const
stop errmsg isConnected()