Vidalia 0.2.12

AdvancedPage.cpp

Go to the documentation of this file.
00001 /*
00002 **  This file is part of Vidalia, and is subject to the license terms in the
00003 **  LICENSE file, found in the top level directory of this distribution. If you
00004 **  did not receive the LICENSE file with this file, you may obtain it from the
00005 **  Vidalia source package distributed by the Vidalia Project at
00006 **  http://www.vidalia-project.net/. No part of Vidalia, including this file,
00007 **  may be copied, modified, propagated, or distributed except according to the
00008 **  terms described in the LICENSE file.
00009 */
00010 
00011 /*
00012 ** \file AdvancedPage.cpp
00013 ** \brief Advanced Tor and Vidalia configuration options
00014 */
00015 
00016 #include "AdvancedPage.h"
00017 #include "TorrcDialog.h"
00018 #include "Vidalia.h"
00019 #include "VMessageBox.h"
00020 #include "IpValidator.h"
00021 #include "Local8BitStringValidator.h"
00022 
00023 #include "file.h"
00024 
00025 #if defined(Q_WS_WIN)
00026 #include "TorService.h"
00027 #endif
00028 
00029 #include <QFile>
00030 #include <QFileInfo>
00031 #include <QHostAddress>
00032 #include <QTextCodec>
00033 
00034 
00035 /** Constructor */
00036 AdvancedPage::AdvancedPage(QWidget *parent)
00037   : ConfigPage(parent, "Advanced")
00038 {
00039   /* Invoke the Qt Designer generated object setup routine */
00040   ui.setupUi(this);
00041 
00042   /* Create TorSettings object */
00043   _settings = new TorSettings(Vidalia::torControl());
00044 
00045   /* Set validators for the control port and IP address fields */
00046   ui.lineControlAddress->setValidator(new IpValidator(this));
00047   ui.lineControlPort->setValidator(new QIntValidator(1, 65535, this));
00048 
00049   /* Set encoding validators for text boxes containing values that may be
00050    * passed to Tor via the control port. */
00051   ui.lineTorConfig->setValidator(new Local8BitStringValidator(this));
00052   ui.lineTorDataDirectory->setValidator(new Local8BitStringValidator(this));
00053   ui.linePassword->setValidator(new Local8BitStringValidator(this));
00054 
00055   /* Bind event to actions */
00056   connect(ui.btnBrowseTorConfig, SIGNAL(clicked()), this, SLOT(browseTorConfig()));
00057   connect(ui.btnBrowseTorDataDirectory, SIGNAL(clicked()),
00058           this, SLOT(browseTorDataDirectory()));
00059   connect(ui.cmbAuthMethod, SIGNAL(currentIndexChanged(int)),
00060           this, SLOT(authMethodChanged(int)));
00061   connect(ui.chkRandomPassword, SIGNAL(toggled(bool)),
00062           ui.linePassword, SLOT(setDisabled(bool)));
00063   connect(ui.btnEditTorConfig, SIGNAL(clicked()),
00064           this, SLOT(displayTorrcDialog()));
00065   connect(ui.rdoControlPort, SIGNAL(toggled(bool)), this, SLOT(toggleControl(bool)));
00066   connect(ui.btnBrowseSocketPath, SIGNAL(clicked()), this, SLOT(browseSocketPath()));
00067 
00068   /* Hide platform specific features */
00069 #if defined(Q_WS_WIN)
00070 #if 0
00071   ui.grpService->setVisible(TorService::isSupported());
00072 #endif
00073   /* Disable ControlSocket */
00074   ui.rdoControlSocket->setEnabled(false);
00075 #endif
00076 }
00077 
00078 /** Destructor */
00079 AdvancedPage::~AdvancedPage()
00080 {
00081   delete _settings;
00082 }
00083 
00084 /** Called when the user changes the UI translation. */
00085 void
00086 AdvancedPage::retranslateUi()
00087 {
00088   ui.retranslateUi(this);
00089 }
00090 
00091 /** Applies the network configuration settings to Tor. Returns true if the
00092  * settings were applied successfully. Otherwise, <b>errmsg</b> is set
00093  * and false is returned. */
00094 bool
00095 AdvancedPage::apply(QString &errmsg)
00096 {
00097   return _settings->apply(&errmsg);
00098 }
00099 
00100 /** Reverts the Tor configuration settings to their values at the last
00101  * time they were successfully applied to Tor. */
00102 bool
00103 AdvancedPage::changedSinceLastApply()
00104 {
00105   return _settings->changedSinceLastApply();
00106 }
00107 
00108 /** Returns true if the user has changed their advanced Tor settings since
00109  * the last time they were applied to Tor. */
00110 void
00111 AdvancedPage::revert()
00112 {
00113   return _settings->revert();
00114 }
00115 
00116 /** Saves all settings for this page. */
00117 bool
00118 AdvancedPage::save(QString &errmsg)
00119 {
00120   QHostAddress controlAddress(ui.lineControlAddress->text());
00121   QString path(ui.lineSocketPath->text());
00122 
00123   /* Validate the control settings */
00124   if(ui.rdoControlPort->isChecked()) {
00125     if (controlAddress.isNull()) {
00126       errmsg = tr("'%1' is not a valid IP address.")
00127                 .arg(ui.lineControlAddress->text());
00128       return false; 
00129     }
00130     _settings->setControlMethod(ControlMethod::Port);
00131   } else {
00132     QFileInfo finfo(path);
00133     if(!finfo.exists()) {
00134       errmsg = tr("ControlSocket path doesn't exist.");
00135       return false;
00136     }
00137     _settings->setControlMethod(ControlMethod::Socket);
00138   }
00139   
00140   /* Validate the selected authentication options */
00141   TorSettings::AuthenticationMethod authMethod = 
00142     indexToAuthMethod(ui.cmbAuthMethod->currentIndex());
00143   if (authMethod == TorSettings::PasswordAuth
00144         && ui.linePassword->text().isEmpty()
00145         && !ui.chkRandomPassword->isChecked()) {
00146     errmsg = tr("You selected 'Password' authentication, but did not "
00147                 "specify a password.");
00148     return false;
00149   }
00150 
00151   /* Ensure that the DataDirectory and torrc options only contain characters
00152    * that are valid in the local 8-bit encoding. */
00153   if (! Local8BitStringValidator::canEncode(ui.lineTorConfig->text())) {
00154     errmsg = tr("The specified Tor configuration file location contains "
00155                 "characters that cannot be represented in your system's "
00156                 "current 8-bit character encoding.");
00157     return false;
00158   }
00159   if (! Local8BitStringValidator::canEncode(ui.lineTorDataDirectory->text())) {
00160     errmsg = tr("The specified Tor data directory location contains "
00161                 "characters that cannot be represented in your system's "
00162                 "current 8-bit character encoding.");
00163     return false;
00164   }
00165 
00166   /* Only remember the torrc and datadir values if Vidalia started Tor, or
00167    * if the user changed the displayed values. */
00168   if (Vidalia::torControl()->isVidaliaRunningTor()) {
00169     QString torrc = ui.lineTorConfig->text();
00170     if (torrc != _settings->getTorrc()) {
00171       _settings->setTorrc(torrc);
00172       QMessageBox::StandardButtons res = QMessageBox::question(this, tr("Warning"), 
00173           tr("You changed torrc path, would you like to restart Tor?"),
00174           QMessageBox::Yes | QMessageBox::No);
00175       if(res == QMessageBox::Yes)
00176         emit restartTor();
00177     }
00178 
00179     QString dataDir = ui.lineTorDataDirectory->text();
00180     if (dataDir != _settings->getDataDirectory())
00181       _settings->setDataDirectory(dataDir);
00182   }
00183 
00184   _settings->setControlAddress(controlAddress);
00185   _settings->setControlPort(ui.lineControlPort->text().toUShort());
00186   _settings->setSocketPath(ui.lineSocketPath->text());
00187 
00188   _settings->setAuthenticationMethod(authMethod);
00189   _settings->setUseRandomPassword(ui.chkRandomPassword->isChecked());
00190   if (authMethod == TorSettings::PasswordAuth
00191         && !ui.chkRandomPassword->isChecked())
00192     _settings->setControlPassword(ui.linePassword->text());
00193 
00194 #if 0
00195 #if defined(Q_WS_WIN)
00196   /* Install or uninstall the Tor service as necessary */
00197   setupService(ui.chkUseService->isChecked());
00198 #endif
00199 #endif
00200 
00201   return true;
00202 }
00203 
00204 /** Loads previously saved settings. */
00205 void
00206 AdvancedPage::load()
00207 {
00208   ui.lineControlAddress->setText(_settings->getControlAddress().toString());
00209   ui.lineControlPort->setText(QString::number(_settings->getControlPort()));
00210   ui.lineTorConfig->setText(_settings->getTorrc());
00211   ui.lineTorDataDirectory->setText(_settings->getDataDirectory());
00212 
00213   ui.cmbAuthMethod->setCurrentIndex(
00214     authMethodToIndex(_settings->getAuthenticationMethod()));
00215   ui.chkRandomPassword->setChecked(_settings->useRandomPassword());
00216   if (!ui.chkRandomPassword->isChecked())
00217     ui.linePassword->setText(_settings->getControlPassword());
00218   ui.rdoControlPort->setChecked(_settings->getControlMethod() == ControlMethod::Port);
00219   ui.rdoControlSocket->setChecked(_settings->getControlMethod() == ControlMethod::Socket);
00220   ui.lineSocketPath->setText(_settings->getSocketPath());
00221 
00222 #if 0
00223 #if defined(Q_WS_WIN)
00224   TorService s;
00225   ui.chkUseService->setChecked(s.isInstalled());
00226 #endif
00227 #endif
00228 }
00229 
00230 /** Called when the user selects a different authentication method from the
00231  * combo box. */
00232 void
00233 AdvancedPage::authMethodChanged(int index)
00234 {
00235   bool usePassword = (indexToAuthMethod(index) == TorSettings::PasswordAuth);
00236   ui.linePassword->setEnabled(usePassword && !ui.chkRandomPassword->isChecked());
00237   ui.chkRandomPassword->setEnabled(usePassword);
00238 }
00239 
00240 /** Returns the authentication method for the given <b>index</b>. */
00241 TorSettings::AuthenticationMethod
00242 AdvancedPage::indexToAuthMethod(int index)
00243 {
00244   switch (index) {
00245     case 0: return TorSettings::NullAuth;
00246     case 1: return TorSettings::CookieAuth;
00247     case 2: return TorSettings::PasswordAuth;
00248     default: break;
00249   }
00250   return TorSettings::UnknownAuth;
00251 }
00252 
00253 /** Returns the index in the authentication methods combo box for the given
00254  * authentication <b>method</b>. */
00255 int
00256 AdvancedPage::authMethodToIndex(TorSettings::AuthenticationMethod method)
00257 {
00258   switch (method) {
00259     case TorSettings::NullAuth: return 0;
00260     case TorSettings::CookieAuth: return 1;
00261     default: break;
00262   }
00263   return 2;
00264 }
00265 
00266 /** Open a QFileDialog to browse for Tor config file. */
00267 void
00268 AdvancedPage::browseTorConfig()
00269 {
00270   /* Prompt the user to select a file or create a new one */
00271   QString filename = QFileDialog::getOpenFileName(this, 
00272                        tr("Select Tor Configuration File"),
00273                        QFileInfo(ui.lineTorConfig->text()).filePath(),
00274                        tr("Tor Configuration File (torrc);;All Files (*)"));
00275 
00276   /* Make sure a filename was selected */
00277   if (filename.isEmpty()) {
00278     return;
00279   }
00280 
00281   /* Check if the file exists */
00282   QFile torrcFile(filename);
00283   if (!QFileInfo(filename).exists()) {
00284     /* The given file does not exist. Should we create it? */
00285     int response = VMessageBox::question(this,
00286                      tr("File Not Found"),
00287                      tr("%1 does not exist. Would you like to create it?")
00288                                                             .arg(filename),
00289                      VMessageBox::Yes, VMessageBox::No);
00290     
00291     if (response == VMessageBox::No) {
00292       /* Don't create it. Just bail. */
00293       return;
00294     }
00295     /* Attempt to create the specified file */
00296     QString errmsg;
00297     if (!touch_file(filename, false, &errmsg)) {
00298       VMessageBox::warning(this,
00299         tr("Failed to Create File"),
00300         tr("Unable to create %1 [%2]").arg(filename)
00301                                       .arg(errmsg),
00302         VMessageBox::Ok);
00303       return;
00304     }
00305   }
00306   ui.lineTorConfig->setText(filename);
00307 }
00308 
00309 /** Opens a QFileDialog for the user to browse to or create a directory for
00310  * Tor's DataDirectory. */
00311 void
00312 AdvancedPage::browseTorDataDirectory()
00313 {
00314   QString dataDir = QFileDialog::getExistingDirectory(this,
00315                       tr("Select a Directory to Use for Tor Data"),
00316                       ui.lineTorDataDirectory->text());
00317 
00318   if (!dataDir.isEmpty()) 
00319     ui.lineTorDataDirectory->setText(dataDir);
00320 }
00321 
00322 /** Opens a QFileDialog for the user to browse to or create a socket path to
00323  * communicate to Tor */
00324 void
00325 AdvancedPage::browseSocketPath()
00326 {
00327   QString start = QDir::currentPath();
00328   if(!ui.lineSocketPath->text().isEmpty())
00329     start = ui.lineSocketPath->text();
00330   QString socketPath = QFileDialog::getOpenFileName(this,
00331                       tr("Select a file to use for Tor socket path"),
00332                       start);
00333 
00334   if (!socketPath.isEmpty()) 
00335     ui.lineSocketPath->setText(socketPath);
00336 }
00337 
00338 #if 0
00339 #if defined(Q_WS_WIN)
00340 /** Installs or removes the Tor service as necessary. */
00341 void
00342 AdvancedPage::setupService(bool useService)
00343 {
00344   TorService service;
00345   bool isInstalled = service.isInstalled();
00346 
00347   if (!useService && isInstalled) {
00348     /* Uninstall if we don't want to use it anymore */
00349     Vidalia::torControl()->stop();
00350     
00351     if (!service.remove()) {
00352       VMessageBox::critical(this,
00353                             tr("Unable to remove Tor Service"),
00354                             tr("Vidalia was unable to remove the Tor service.\n\n"
00355                                "You may need to remove it manually."), 
00356                             VMessageBox::Ok, VMessageBox::Cancel);
00357     }
00358   } else if (useService && !isInstalled) {
00359     /* Install if we want to start using a service */
00360     if (!service.install(_settings->getExecutable(),
00361                          _settings->getTorrc(),
00362                          _settings->getControlPort())) {
00363       VMessageBox::critical(this,
00364                             tr("Unable to install Tor Service"),
00365                             tr("Vidalia was unable to install the Tor service."),
00366                             VMessageBox::Ok, VMessageBox::Cancel);
00367     }
00368   }
00369 }
00370 #endif
00371 #endif
00372 
00373 /** Called when the user presses the Edit current torrc button */
00374 void 
00375 AdvancedPage::displayTorrcDialog()
00376 {
00377   TorrcDialog rcdialog(this);
00378   rcdialog.exec();
00379 }
00380 
00381 void 
00382 AdvancedPage::toggleControl(bool)
00383 {
00384   if(ui.rdoControlPort->isChecked()) {
00385     ui.lblAddress->setEnabled(true);
00386     ui.lineControlAddress->setEnabled(true);
00387     ui.lineControlPort->setEnabled(true);
00388     ui.lblPath->setEnabled(false);
00389     ui.lineSocketPath->setEnabled(false);
00390     ui.btnBrowseSocketPath->setEnabled(false);
00391   } else {
00392 #if !defined(Q_OS_WIN32)
00393     ui.lblAddress->setEnabled(false);
00394     ui.lineControlAddress->setEnabled(false);
00395     ui.lineControlPort->setEnabled(false);
00396     ui.lblPath->setEnabled(true);
00397     ui.lineSocketPath->setEnabled(true);
00398     ui.btnBrowseSocketPath->setEnabled(true);
00399 #endif
00400   }
00401 }