Vidalia
0.2.15
|
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 } 00202 _settings->setSocketPath(ui.lineSocketPath->text()); 00203 00204 _settings->setAuthenticationMethod(authMethod); 00205 _settings->setUseRandomPassword(ui.chkRandomPassword->isChecked()); 00206 if (authMethod == TorSettings::PasswordAuth 00207 && !ui.chkRandomPassword->isChecked()) 00208 _settings->setControlPassword(ui.linePassword->text()); 00209 00210 #if 0 00211 #if defined(Q_WS_WIN) 00212 /* Install or uninstall the Tor service as necessary */ 00213 setupService(ui.chkUseService->isChecked()); 00214 #endif 00215 #endif 00216 00217 return true; 00218 } 00219 00220 /** Loads previously saved settings. */ 00221 void 00222 AdvancedPage::load() 00223 { 00224 ui.lineControlAddress->setText(_settings->getControlAddress().toString()); 00225 ui.lineControlPort->setText(QString::number(_settings->getControlPort())); 00226 ui.lineTorConfig->setText(_settings->getTorrc()); 00227 ui.lineTorDataDirectory->setText(_settings->getDataDirectory()); 00228 ui.chkAuto->setChecked(_settings->autoControlPort()); 00229 00230 ui.cmbAuthMethod->setCurrentIndex( 00231 authMethodToIndex(_settings->getAuthenticationMethod())); 00232 ui.chkRandomPassword->setChecked(_settings->useRandomPassword()); 00233 if (!ui.chkRandomPassword->isChecked()) 00234 ui.linePassword->setText(_settings->getControlPassword()); 00235 ui.rdoControlPort->setChecked(_settings->getControlMethod() == ControlMethod::Port); 00236 ui.rdoControlSocket->setChecked(_settings->getControlMethod() == ControlMethod::Socket); 00237 ui.lineSocketPath->setText(_settings->getSocketPath()); 00238 00239 #if 0 00240 #if defined(Q_WS_WIN) 00241 TorService s; 00242 ui.chkUseService->setChecked(s.isInstalled()); 00243 #endif 00244 #endif 00245 00246 if(Vidalia::torControl()->getTorVersion() < 0x2021a) { // 0x2021a == 0.2.2.26 00247 ui.chkAuto->setChecked(false); 00248 ui.chkAuto->setVisible(false); 00249 } 00250 } 00251 00252 /** Called when the user selects a different authentication method from the 00253 * combo box. */ 00254 void 00255 AdvancedPage::authMethodChanged(int index) 00256 { 00257 bool usePassword = (indexToAuthMethod(index) == TorSettings::PasswordAuth); 00258 ui.linePassword->setEnabled(usePassword && !ui.chkRandomPassword->isChecked()); 00259 ui.chkRandomPassword->setEnabled(usePassword); 00260 } 00261 00262 /** Returns the authentication method for the given <b>index</b>. */ 00263 TorSettings::AuthenticationMethod 00264 AdvancedPage::indexToAuthMethod(int index) 00265 { 00266 switch (index) { 00267 case 0: return TorSettings::NullAuth; 00268 case 1: return TorSettings::CookieAuth; 00269 case 2: return TorSettings::PasswordAuth; 00270 default: break; 00271 } 00272 return TorSettings::UnknownAuth; 00273 } 00274 00275 /** Returns the index in the authentication methods combo box for the given 00276 * authentication <b>method</b>. */ 00277 int 00278 AdvancedPage::authMethodToIndex(TorSettings::AuthenticationMethod method) 00279 { 00280 switch (method) { 00281 case TorSettings::NullAuth: return 0; 00282 case TorSettings::CookieAuth: return 1; 00283 default: break; 00284 } 00285 return 2; 00286 } 00287 00288 /** Open a QFileDialog to browse for Tor config file. */ 00289 void 00290 AdvancedPage::browseTorConfig() 00291 { 00292 /* Prompt the user to select a file or create a new one */ 00293 QString filename = QFileDialog::getOpenFileName(this, 00294 tr("Select Tor Configuration File"), 00295 QFileInfo(ui.lineTorConfig->text()).filePath(), 00296 tr("Tor Configuration File (torrc);;All Files (*)")); 00297 00298 /* Make sure a filename was selected */ 00299 if (filename.isEmpty()) { 00300 return; 00301 } 00302 00303 /* Check if the file exists */ 00304 QFile torrcFile(filename); 00305 if (!QFileInfo(filename).exists()) { 00306 /* The given file does not exist. Should we create it? */ 00307 int response = VMessageBox::question(this, 00308 tr("File Not Found"), 00309 tr("%1 does not exist. Would you like to create it?") 00310 .arg(filename), 00311 VMessageBox::Yes, VMessageBox::No); 00312 00313 if (response == VMessageBox::No) { 00314 /* Don't create it. Just bail. */ 00315 return; 00316 } 00317 /* Attempt to create the specified file */ 00318 QString errmsg; 00319 if (!touch_file(filename, false, &errmsg)) { 00320 VMessageBox::warning(this, 00321 tr("Failed to Create File"), 00322 tr("Unable to create %1 [%2]").arg(filename) 00323 .arg(errmsg), 00324 VMessageBox::Ok); 00325 return; 00326 } 00327 } 00328 ui.lineTorConfig->setText(filename); 00329 } 00330 00331 /** Opens a QFileDialog for the user to browse to or create a directory for 00332 * Tor's DataDirectory. */ 00333 void 00334 AdvancedPage::browseTorDataDirectory() 00335 { 00336 QString dataDir = QFileDialog::getExistingDirectory(this, 00337 tr("Select a Directory to Use for Tor Data"), 00338 ui.lineTorDataDirectory->text()); 00339 00340 if (!dataDir.isEmpty()) 00341 ui.lineTorDataDirectory->setText(dataDir); 00342 } 00343 00344 /** Opens a QFileDialog for the user to browse to or create a socket path to 00345 * communicate to Tor */ 00346 void 00347 AdvancedPage::browseSocketPath() 00348 { 00349 QString start = QDir::currentPath(); 00350 if(!ui.lineSocketPath->text().isEmpty()) 00351 start = ui.lineSocketPath->text(); 00352 QString socketPath = QFileDialog::getOpenFileName(this, 00353 tr("Select a file to use for Tor socket path"), 00354 start); 00355 00356 if (!socketPath.isEmpty()) 00357 ui.lineSocketPath->setText(socketPath); 00358 } 00359 00360 #if 0 00361 #if defined(Q_WS_WIN) 00362 /** Installs or removes the Tor service as necessary. */ 00363 void 00364 AdvancedPage::setupService(bool useService) 00365 { 00366 TorService service; 00367 bool isInstalled = service.isInstalled(); 00368 00369 if (!useService && isInstalled) { 00370 /* Uninstall if we don't want to use it anymore */ 00371 Vidalia::torControl()->stop(); 00372 00373 if (!service.remove()) { 00374 VMessageBox::critical(this, 00375 tr("Unable to remove Tor Service"), 00376 tr("Vidalia was unable to remove the Tor service.\n\n" 00377 "You may need to remove it manually."), 00378 VMessageBox::Ok, VMessageBox::Cancel); 00379 } 00380 } else if (useService && !isInstalled) { 00381 /* Install if we want to start using a service */ 00382 if (!service.install(_settings->getExecutable(), 00383 _settings->getTorrc(), 00384 _settings->getControlPort())) { 00385 VMessageBox::critical(this, 00386 tr("Unable to install Tor Service"), 00387 tr("Vidalia was unable to install the Tor service."), 00388 VMessageBox::Ok, VMessageBox::Cancel); 00389 } 00390 } 00391 } 00392 #endif 00393 #endif 00394 00395 /** Called when the user presses the Edit current torrc button */ 00396 void 00397 AdvancedPage::displayTorrcDialog() 00398 { 00399 TorrcDialog rcdialog(this); 00400 rcdialog.exec(); 00401 } 00402 00403 void 00404 AdvancedPage::toggleControl(bool) 00405 { 00406 if(ui.rdoControlPort->isChecked()) { 00407 ui.lblAddress->setEnabled(true); 00408 ui.lineControlAddress->setEnabled(true); 00409 ui.lineControlPort->setEnabled(true); 00410 ui.lblPath->setEnabled(false); 00411 ui.lineSocketPath->setEnabled(false); 00412 ui.btnBrowseSocketPath->setEnabled(false); 00413 ui.chkAuto->setEnabled(true); 00414 } else { 00415 #if !defined(Q_OS_WIN32) 00416 ui.lblAddress->setEnabled(false); 00417 ui.lineControlAddress->setEnabled(false); 00418 ui.lineControlPort->setEnabled(false); 00419 ui.lblPath->setEnabled(true); 00420 ui.lineSocketPath->setEnabled(true); 00421 ui.btnBrowseSocketPath->setEnabled(true); 00422 ui.chkAuto->setEnabled(false); 00423 #endif 00424 } 00425 } 00426 00427 void 00428 AdvancedPage::toggleAuto(bool) 00429 { 00430 ui.lblAddress->setVisible(!ui.chkAuto->isChecked()); 00431 ui.lineControlAddress->setVisible(!ui.chkAuto->isChecked()); 00432 ui.label->setVisible(!ui.chkAuto->isChecked()); 00433 ui.lineControlPort->setVisible(!ui.chkAuto->isChecked()); 00434 }