Vidalia
0.2.17
|
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.torproject.org/projects/vidalia.html. No part of Vidalia, 00007 ** including this file, may be copied, modified, propagated, or distributed 00008 ** except according to the 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 connect(ui.chkAuto, SIGNAL(toggled(bool)), this, SLOT(toggleAuto(bool))); 00068 00069 /* Hide platform specific features */ 00070 #if defined(Q_WS_WIN) 00071 #if 0 00072 ui.grpService->setVisible(TorService::isSupported()); 00073 #endif 00074 /* Disable ControlSocket */ 00075 ui.rdoControlSocket->setEnabled(false); 00076 #endif 00077 } 00078 00079 /** Destructor */ 00080 AdvancedPage::~AdvancedPage() 00081 { 00082 delete _settings; 00083 } 00084 00085 /** Called when the user changes the UI translation. */ 00086 void 00087 AdvancedPage::retranslateUi() 00088 { 00089 ui.retranslateUi(this); 00090 } 00091 00092 /** Applies the network configuration settings to Tor. Returns true if the 00093 * settings were applied successfully. Otherwise, <b>errmsg</b> is set 00094 * and false is returned. */ 00095 bool 00096 AdvancedPage::apply(QString &errmsg) 00097 { 00098 return _settings->apply(&errmsg); 00099 } 00100 00101 /** Reverts the Tor configuration settings to their values at the last 00102 * time they were successfully applied to Tor. */ 00103 bool 00104 AdvancedPage::changedSinceLastApply() 00105 { 00106 return _settings->changedSinceLastApply(); 00107 } 00108 00109 /** Returns true if the user has changed their advanced Tor settings since 00110 * the last time they were applied to Tor. */ 00111 void 00112 AdvancedPage::revert() 00113 { 00114 return _settings->revert(); 00115 } 00116 00117 /** Saves all settings for this page. */ 00118 bool 00119 AdvancedPage::save(QString &errmsg) 00120 { 00121 QHostAddress controlAddress(ui.lineControlAddress->text()); 00122 QString path(ui.lineSocketPath->text()); 00123 00124 if(ui.chkAuto->isChecked()) { 00125 if(ui.lineTorDataDirectory->text().isEmpty()) { 00126 errmsg = tr("You've checked the autoconfiguration option for the ControlPort, but" 00127 " provided no Data Directory. Please add one, or uncheck the" 00128 " \"Configure ControlPort automatically\" option."); 00129 return false; 00130 } 00131 _settings->setAutoControlPort(true); 00132 } 00133 00134 /* Validate the control settings */ 00135 if(ui.rdoControlPort->isChecked()) { 00136 if (controlAddress.isNull()) { 00137 errmsg = tr("'%1' is not a valid IP address.") 00138 .arg(ui.lineControlAddress->text()); 00139 return false; 00140 } 00141 _settings->setControlMethod(ControlMethod::Port); 00142 } else { 00143 QFileInfo finfo(path); 00144 if(!finfo.exists()) { 00145 errmsg = tr("ControlSocket path doesn't exist."); 00146 return false; 00147 } 00148 _settings->setControlMethod(ControlMethod::Socket); 00149 } 00150 00151 /* Validate the selected authentication options */ 00152 TorSettings::AuthenticationMethod authMethod = 00153 indexToAuthMethod(ui.cmbAuthMethod->currentIndex()); 00154 if (authMethod == TorSettings::PasswordAuth 00155 && ui.linePassword->text().isEmpty() 00156 && !ui.chkRandomPassword->isChecked()) { 00157 errmsg = tr("You selected 'Password' authentication, but did not " 00158 "specify a password."); 00159 return false; 00160 } 00161 00162 /* Ensure that the DataDirectory and torrc options only contain characters 00163 * that are valid in the local 8-bit encoding. */ 00164 if (! Local8BitStringValidator::canEncode(ui.lineTorConfig->text())) { 00165 errmsg = tr("The specified Tor configuration file location contains " 00166 "characters that cannot be represented in your system's " 00167 "current 8-bit character encoding."); 00168 return false; 00169 } 00170 if (! Local8BitStringValidator::canEncode(ui.lineTorDataDirectory->text())) { 00171 errmsg = tr("The specified Tor data directory location contains " 00172 "characters that cannot be represented in your system's " 00173 "current 8-bit character encoding."); 00174 return false; 00175 } 00176 00177 /* Only remember the torrc and datadir values if Vidalia started Tor, or 00178 * if the user changed the displayed values. */ 00179 if (Vidalia::torControl()->isVidaliaRunningTor() or 00180 !Vidalia::torControl()->isConnected()) { 00181 QString torrc = ui.lineTorConfig->text(); 00182 if (torrc != _settings->getTorrc()) { 00183 _settings->setTorrc(torrc); 00184 if(Vidalia::torControl()->isConnected()) { 00185 QMessageBox::StandardButtons res = QMessageBox::question(this, tr("Warning"), 00186 tr("You changed torrc path, would you like to restart Tor?"), 00187 QMessageBox::Yes | QMessageBox::No); 00188 if(res == QMessageBox::Yes) 00189 emit restartTor(); 00190 } 00191 } 00192 00193 QString dataDir = ui.lineTorDataDirectory->text(); 00194 if (dataDir != _settings->getDataDirectory()) 00195 _settings->setDataDirectory(dataDir); 00196 } 00197 00198 if(!ui.chkAuto->isChecked()) { 00199 _settings->setControlAddress(controlAddress); 00200 _settings->setControlPort(ui.lineControlPort->text().toUShort()); 00201 _settings->setAutoControlPort(false); 00202 } 00203 _settings->setSocketPath(ui.lineSocketPath->text()); 00204 00205 _settings->setAuthenticationMethod(authMethod); 00206 _settings->setUseRandomPassword(ui.chkRandomPassword->isChecked()); 00207 if (authMethod == TorSettings::PasswordAuth 00208 && !ui.chkRandomPassword->isChecked()) 00209 _settings->setControlPassword(ui.linePassword->text()); 00210 00211 #if 0 00212 #if defined(Q_WS_WIN) 00213 /* Install or uninstall the Tor service as necessary */ 00214 setupService(ui.chkUseService->isChecked()); 00215 #endif 00216 #endif 00217 00218 return true; 00219 } 00220 00221 /** Loads previously saved settings. */ 00222 void 00223 AdvancedPage::load() 00224 { 00225 ui.lineControlAddress->setText(_settings->getControlAddress().toString()); 00226 ui.lineControlPort->setText(QString::number(_settings->getControlPort())); 00227 ui.lineTorConfig->setText(_settings->getTorrc()); 00228 ui.lineTorDataDirectory->setText(_settings->getDataDirectory()); 00229 ui.chkAuto->setChecked(_settings->autoControlPort()); 00230 00231 ui.cmbAuthMethod->setCurrentIndex( 00232 authMethodToIndex(_settings->getAuthenticationMethod())); 00233 ui.chkRandomPassword->setChecked(_settings->useRandomPassword()); 00234 if (!ui.chkRandomPassword->isChecked()) 00235 ui.linePassword->setText(_settings->getControlPassword()); 00236 ui.rdoControlPort->setChecked(_settings->getControlMethod() == ControlMethod::Port); 00237 ui.rdoControlSocket->setChecked(_settings->getControlMethod() == ControlMethod::Socket); 00238 ui.lineSocketPath->setText(_settings->getSocketPath()); 00239 00240 #if 0 00241 #if defined(Q_WS_WIN) 00242 TorService s; 00243 ui.chkUseService->setChecked(s.isInstalled()); 00244 #endif 00245 #endif 00246 00247 if(Vidalia::torControl()->getTorVersion() < 0x2021a) { // 0x2021a == 0.2.2.26 00248 ui.chkAuto->setChecked(false); 00249 ui.chkAuto->setVisible(false); 00250 } 00251 } 00252 00253 /** Called when the user selects a different authentication method from the 00254 * combo box. */ 00255 void 00256 AdvancedPage::authMethodChanged(int index) 00257 { 00258 bool usePassword = (indexToAuthMethod(index) == TorSettings::PasswordAuth); 00259 ui.linePassword->setEnabled(usePassword && !ui.chkRandomPassword->isChecked()); 00260 ui.chkRandomPassword->setEnabled(usePassword); 00261 } 00262 00263 /** Returns the authentication method for the given <b>index</b>. */ 00264 TorSettings::AuthenticationMethod 00265 AdvancedPage::indexToAuthMethod(int index) 00266 { 00267 switch (index) { 00268 case 0: return TorSettings::NullAuth; 00269 case 1: return TorSettings::CookieAuth; 00270 case 2: return TorSettings::PasswordAuth; 00271 default: break; 00272 } 00273 return TorSettings::UnknownAuth; 00274 } 00275 00276 /** Returns the index in the authentication methods combo box for the given 00277 * authentication <b>method</b>. */ 00278 int 00279 AdvancedPage::authMethodToIndex(TorSettings::AuthenticationMethod method) 00280 { 00281 switch (method) { 00282 case TorSettings::NullAuth: return 0; 00283 case TorSettings::CookieAuth: return 1; 00284 default: break; 00285 } 00286 return 2; 00287 } 00288 00289 /** Open a QFileDialog to browse for Tor config file. */ 00290 void 00291 AdvancedPage::browseTorConfig() 00292 { 00293 /* Prompt the user to select a file or create a new one */ 00294 QString filename = QFileDialog::getOpenFileName(this, 00295 tr("Select Tor Configuration File"), 00296 QFileInfo(ui.lineTorConfig->text()).filePath(), 00297 tr("Tor Configuration File (torrc);;All Files (*)")); 00298 00299 /* Make sure a filename was selected */ 00300 if (filename.isEmpty()) { 00301 return; 00302 } 00303 00304 /* Check if the file exists */ 00305 QFile torrcFile(filename); 00306 if (!QFileInfo(filename).exists()) { 00307 /* The given file does not exist. Should we create it? */ 00308 int response = VMessageBox::question(this, 00309 tr("File Not Found"), 00310 tr("%1 does not exist. Would you like to create it?") 00311 .arg(filename), 00312 VMessageBox::Yes, VMessageBox::No); 00313 00314 if (response == VMessageBox::No) { 00315 /* Don't create it. Just bail. */ 00316 return; 00317 } 00318 /* Attempt to create the specified file */ 00319 QString errmsg; 00320 if (!touch_file(filename, false, &errmsg)) { 00321 VMessageBox::warning(this, 00322 tr("Failed to Create File"), 00323 tr("Unable to create %1 [%2]").arg(filename) 00324 .arg(errmsg), 00325 VMessageBox::Ok); 00326 return; 00327 } 00328 } 00329 ui.lineTorConfig->setText(filename); 00330 } 00331 00332 /** Opens a QFileDialog for the user to browse to or create a directory for 00333 * Tor's DataDirectory. */ 00334 void 00335 AdvancedPage::browseTorDataDirectory() 00336 { 00337 QString dataDir = QFileDialog::getExistingDirectory(this, 00338 tr("Select a Directory to Use for Tor Data"), 00339 ui.lineTorDataDirectory->text()); 00340 00341 if (!dataDir.isEmpty()) 00342 ui.lineTorDataDirectory->setText(dataDir); 00343 } 00344 00345 /** Opens a QFileDialog for the user to browse to or create a socket path to 00346 * communicate to Tor */ 00347 void 00348 AdvancedPage::browseSocketPath() 00349 { 00350 QString start = QDir::currentPath(); 00351 if(!ui.lineSocketPath->text().isEmpty()) 00352 start = ui.lineSocketPath->text(); 00353 QString socketPath = QFileDialog::getOpenFileName(this, 00354 tr("Select a file to use for Tor socket path"), 00355 start); 00356 00357 if (!socketPath.isEmpty()) 00358 ui.lineSocketPath->setText(socketPath); 00359 } 00360 00361 #if 0 00362 #if defined(Q_WS_WIN) 00363 /** Installs or removes the Tor service as necessary. */ 00364 void 00365 AdvancedPage::setupService(bool useService) 00366 { 00367 TorService service; 00368 bool isInstalled = service.isInstalled(); 00369 00370 if (!useService && isInstalled) { 00371 /* Uninstall if we don't want to use it anymore */ 00372 Vidalia::torControl()->stop(); 00373 00374 if (!service.remove()) { 00375 VMessageBox::critical(this, 00376 tr("Unable to remove Tor Service"), 00377 tr("Vidalia was unable to remove the Tor service.\n\n" 00378 "You may need to remove it manually."), 00379 VMessageBox::Ok, VMessageBox::Cancel); 00380 } 00381 } else if (useService && !isInstalled) { 00382 /* Install if we want to start using a service */ 00383 if (!service.install(_settings->getExecutable(), 00384 _settings->getTorrc(), 00385 _settings->getControlPort())) { 00386 VMessageBox::critical(this, 00387 tr("Unable to install Tor Service"), 00388 tr("Vidalia was unable to install the Tor service."), 00389 VMessageBox::Ok, VMessageBox::Cancel); 00390 } 00391 } 00392 } 00393 #endif 00394 #endif 00395 00396 /** Called when the user presses the Edit current torrc button */ 00397 void 00398 AdvancedPage::displayTorrcDialog() 00399 { 00400 TorrcDialog rcdialog(this); 00401 rcdialog.exec(); 00402 } 00403 00404 void 00405 AdvancedPage::toggleControl(bool) 00406 { 00407 if(ui.rdoControlPort->isChecked()) { 00408 ui.lblAddress->setEnabled(true); 00409 ui.lineControlAddress->setEnabled(true); 00410 ui.lineControlPort->setEnabled(true); 00411 ui.lblPath->setEnabled(false); 00412 ui.lineSocketPath->setEnabled(false); 00413 ui.btnBrowseSocketPath->setEnabled(false); 00414 ui.chkAuto->setEnabled(true); 00415 } else { 00416 #if !defined(Q_OS_WIN32) 00417 ui.lblAddress->setEnabled(false); 00418 ui.lineControlAddress->setEnabled(false); 00419 ui.lineControlPort->setEnabled(false); 00420 ui.lblPath->setEnabled(true); 00421 ui.lineSocketPath->setEnabled(true); 00422 ui.btnBrowseSocketPath->setEnabled(true); 00423 ui.chkAuto->setEnabled(false); 00424 #endif 00425 } 00426 } 00427 00428 void 00429 AdvancedPage::toggleAuto(bool) 00430 { 00431 ui.lblAddress->setVisible(!ui.chkAuto->isChecked()); 00432 ui.lineControlAddress->setVisible(!ui.chkAuto->isChecked()); 00433 ui.label->setVisible(!ui.chkAuto->isChecked()); 00434 ui.lineControlPort->setVisible(!ui.chkAuto->isChecked()); 00435 }