Vidalia 0.2.12
|
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 }