00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "MainWindow.h"
00022 #include "Vidalia.h"
00023 #include "VMessageBox.h"
00024 #include "ControlPasswordInputDialog.h"
00025 #include "TorSettings.h"
00026 #include "ServerSettings.h"
00027 #ifdef USE_AUTOUPDATE
00028 #include "UpdatesAvailableDialog.h"
00029 #endif
00030
00031 #include "ProtocolInfo.h"
00032
00033 #include "net.h"
00034 #include "file.h"
00035 #include "html.h"
00036 #include "stringutil.h"
00037 #include "procutil.h"
00038
00039 #include <QMenuBar>
00040 #include <QTimer>
00041 #include <QTextStream>
00042
00043 #define IMG_BWGRAPH ":/images/16x16/utilities-system-monitor.png"
00044 #define IMG_CONTROL_PANEL ":/images/16x16/system-run.png"
00045 #define IMG_MESSAGELOG ":/images/16x16/format-justify-fill.png"
00046 #define IMG_CONFIG ":/images/16x16/preferences-system.png"
00047 #define IMG_IDENTITY ":/images/16x16/view-media-artist.png"
00048 #define IMG_HELP ":/images/16x16/system-help.png"
00049 #define IMG_ABOUT ":/images/16x16/help-about.png"
00050 #define IMG_EXIT ":/images/16x16/application-exit.png"
00051 #define IMG_NETWORK ":/images/16x16/applications-internet.png"
00052
00053 #define IMG_START_TOR_16 ":/images/16x16/media-playback-start.png"
00054 #define IMG_STOP_TOR_16 ":/images/16x16/media-playback-stop.png"
00055 #define IMG_START_TOR_48 ":/images/48x48/media-playback-start.png"
00056 #define IMG_STOP_TOR_48 ":/images/48x48/media-playback-stop.png"
00057 #define IMG_TOR_STOPPED_48 ":/images/48x48/tor-off.png"
00058 #define IMG_TOR_RUNNING_48 ":/images/48x48/tor-on.png"
00059 #define IMG_TOR_STARTING_48 ":/images/48x48/tor-starting.png"
00060 #define IMG_TOR_STOPPING_48 ":/images/48x48/tor-stopping.png"
00061
00062
00063 #if defined(Q_WS_WIN)
00064
00065 #define IMG_TOR_STOPPED ":/images/16x16/tor-off.png"
00066 #define IMG_TOR_RUNNING ":/images/16x16/tor-on.png"
00067 #define IMG_TOR_STARTING ":/images/16x16/tor-starting.png"
00068 #define IMG_TOR_STOPPING ":/images/16x16/tor-stopping.png"
00069 #elif defined(Q_WS_MAC)
00070
00071
00072 #define IMG_TOR_STOPPED ":/images/128x128/tor-off.png"
00073 #define IMG_TOR_RUNNING ":/images/128x128/tor-on.png"
00074 #define IMG_TOR_STARTING ":/images/128x128/tor-starting.png"
00075 #define IMG_TOR_STOPPING ":/images/128x128/tor-stopping.png"
00076 void qt_mac_set_dock_menu(QMenu *menu);
00077 #else
00078
00079 #define IMG_TOR_STOPPED ":/images/22x22/tor-off.png"
00080 #define IMG_TOR_RUNNING ":/images/22x22/tor-on.png"
00081 #define IMG_TOR_STARTING ":/images/22x22/tor-starting.png"
00082 #define IMG_TOR_STOPPING ":/images/22x22/tor-stopping.png"
00083 #endif
00084
00085
00086 #define MIN_NEWIDENTITY_INTERVAL (10*1000)
00087
00088
00089 #define STARTUP_PROGRESS_STARTING 0
00090 #define STARTUP_PROGRESS_CONNECTING 10
00091 #define STARTUP_PROGRESS_AUTHENTICATING 20
00092 #define STARTUP_PROGRESS_BOOTSTRAPPING 30
00093 #define STARTUP_PROGRESS_CIRCUITBUILD 75
00094 #define STARTUP_PROGRESS_MAXIMUM (STARTUP_PROGRESS_BOOTSTRAPPING+100)
00095
00096
00097
00098 MainWindow::MainWindow()
00099 : VidaliaWindow("MainWindow")
00100 {
00101 VidaliaSettings settings;
00102
00103 ui.setupUi(this);
00104
00105
00106 Vidalia::createShortcut("Ctrl+W", this, ui.btnHide, SLOT(click()));
00107 Vidalia::createShortcut("Esc", this, ui.btnHide, SLOT(click()));
00108
00109
00110 _messageLog = new MessageLog();
00111 _bandwidthGraph = new BandwidthGraph();
00112 _netViewer = new NetViewer();
00113 _configDialog = new ConfigDialog();
00114 _menuBar = 0;
00115 connect(_messageLog, SIGNAL(helpRequested(QString)),
00116 this, SLOT(showHelpDialog(QString)));
00117 connect(_netViewer, SIGNAL(helpRequested(QString)),
00118 this, SLOT(showHelpDialog(QString)));
00119 connect(_configDialog, SIGNAL(helpRequested(QString)),
00120 this, SLOT(showHelpDialog(QString)));
00121
00122
00123 createActions();
00124
00125
00126 createTrayIcon();
00127
00128 _status = Unset;
00129 _isVidaliaRunningTor = false;
00130 updateTorStatus(Stopped);
00131
00132
00133 _torControl = Vidalia::torControl();
00134 connect(_torControl, SIGNAL(started()), this, SLOT(started()));
00135 connect(_torControl, SIGNAL(startFailed(QString)),
00136 this, SLOT(startFailed(QString)));
00137 connect(_torControl, SIGNAL(stopped(int, QProcess::ExitStatus)),
00138 this, SLOT(stopped(int, QProcess::ExitStatus)));
00139 connect(_torControl, SIGNAL(connected()), this, SLOT(connected()));
00140 connect(_torControl, SIGNAL(disconnected()), this, SLOT(disconnected()));
00141 connect(_torControl, SIGNAL(connectFailed(QString)),
00142 this, SLOT(connectFailed(QString)));
00143 connect(_torControl, SIGNAL(authenticated()), this, SLOT(authenticated()));
00144 connect(_torControl, SIGNAL(authenticationFailed(QString)),
00145 this, SLOT(authenticationFailed(QString)));
00146
00147 _torControl->setEvent(TorEvents::GeneralStatus);
00148 connect(_torControl, SIGNAL(dangerousTorVersion(tc::TorVersionStatus,
00149 QString, QStringList)),
00150 this, SLOT(dangerousTorVersion(tc::TorVersionStatus,
00151 QString, QStringList)));
00152
00153 _torControl->setEvent(TorEvents::ClientStatus);
00154 connect(_torControl, SIGNAL(bootstrapStatusChanged(BootstrapStatus)),
00155 this, SLOT(bootstrapStatusChanged(BootstrapStatus)));
00156 connect(_torControl, SIGNAL(circuitEstablished()),
00157 this, SLOT(circuitEstablished()));
00158 connect(_torControl, SIGNAL(dangerousPort(quint16, bool)),
00159 this, SLOT(warnDangerousPort(quint16, bool)));
00160
00161
00162 _browserProcess = new HelperProcess(this);
00163 connect(_browserProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
00164 this, SLOT(onSubprocessFinished(int, QProcess::ExitStatus)));
00165 connect(_browserProcess, SIGNAL(startFailed(QString)),
00166 this, SLOT(onBrowserFailed(QString)));
00167
00168
00169 _imProcess = new HelperProcess(this);
00170 connect(_imProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
00171 this, SLOT(onSubprocessFinished(int, QProcess::ExitStatus)));
00172 connect(_imProcess, SIGNAL(startFailed(QString)),
00173 this, SLOT(onIMFailed(QString)));
00174
00175
00176 _proxyProcess = new HelperProcess(this);
00177 connect(_proxyProcess, SIGNAL(startFailed(QString)),
00178 this, SLOT(onProxyFailed(QString)));
00179
00180
00181 connect(vApp, SIGNAL(running()), this, SLOT(running()));
00182 connect(vApp, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit()));
00183
00184 #if defined(USE_AUTOUPDATE)
00185
00186 connect(&_updateTimer, SIGNAL(timeout()), this, SLOT(checkForUpdates()));
00187
00188
00189
00190 connect(_configDialog, SIGNAL(checkForUpdates()),
00191 this, SLOT(checkForUpdatesWithUi()));
00192
00193
00194 connect(&_updateProcess, SIGNAL(downloadProgress(QString,int,int)),
00195 &_updateProgressDialog, SLOT(setDownloadProgress(QString,int,int)));
00196 connect(&_updateProcess, SIGNAL(updatesAvailable(UpdateProcess::BundleInfo,PackageList)),
00197 this, SLOT(updatesAvailable(UpdateProcess::BundleInfo,PackageList)));
00198 connect(&_updateProcess, SIGNAL(updatesInstalled(int)),
00199 this, SLOT(updatesInstalled(int)));
00200 connect(&_updateProcess, SIGNAL(installUpdatesFailed(QString)),
00201 this, SLOT(installUpdatesFailed(QString)));
00202 connect(&_updateProgressDialog, SIGNAL(cancelUpdate()),
00203 &_updateProcess, SLOT(cancel()));
00204 #endif
00205
00206 #if defined(USE_MINIUPNPC)
00207
00208 connect(UPNPControl::instance(), SIGNAL(error(UPNPControl::UPNPError)),
00209 this, SLOT(upnpError(UPNPControl::UPNPError)));
00210 #endif
00211
00212 ui.chkShowOnStartup->setChecked(settings.showMainWindowAtStart());
00213 if (ui.chkShowOnStartup->isChecked())
00214 show();
00215
00216 _trayIcon.show();
00217 }
00218
00219
00220 MainWindow::~MainWindow()
00221 {
00222 _trayIcon.hide();
00223 delete _messageLog;
00224 delete _bandwidthGraph;
00225 delete _netViewer;
00226 delete _configDialog;
00227 }
00228
00229 void
00230 MainWindow::setVisible(bool visible)
00231 {
00232 if (visible) {
00233
00234 if (!QSystemTrayIcon::isSystemTrayAvailable()) {
00235
00236 ui.chkShowOnStartup->hide();
00237 ui.btnHide->hide();
00238
00239
00240
00241 }
00242 }
00243 VidaliaWindow::setVisible(visible);
00244 }
00245
00246 void
00247 MainWindow::retranslateUi()
00248 {
00249 ui.retranslateUi(this);
00250
00251 updateTorStatus(_status);
00252 if (_status == Stopped) {
00253 _actionStartStopTor->setText(tr("Start Tor"));
00254 ui.lblStartStopTor->setText(tr("Start Tor"));
00255 } else if (_status == Starting) {
00256 _actionStartStopTor->setText(tr("Starting Tor"));
00257 ui.lblStartStopTor->setText(tr("Starting Tor"));
00258 } else {
00259 _actionStartStopTor->setText(tr("Stop Tor"));
00260 ui.lblStartStopTor->setText(tr("Stop Tor"));
00261 }
00262
00263 _actionShowBandwidth->setText(tr("Bandwidth Graph"));
00264 _actionShowMessageLog->setText(tr("Message Log"));
00265 _actionShowNetworkMap->setText(tr("Network Map"));
00266 _actionShowControlPanel->setText(tr("Control Panel"));
00267 _actionShowHelp->setText(tr("Help"));
00268 _actionNewIdentity->setText(tr("New Identity"));
00269
00270 #if !defined(Q_WS_MAC)
00271 _actionShowAbout->setText(tr("About"));
00272 _actionShowConfig->setText(tr("Settings"));
00273 _actionExit->setText(tr("Exit"));
00274 #else
00275 createMenuBar();
00276 #endif
00277 }
00278
00279
00280
00281 void
00282 MainWindow::running()
00283 {
00284 VidaliaSettings settings;
00285
00286 if (vApp->readPasswordFromStdin()) {
00287 QTextStream in(stdin);
00288 in >> _controlPassword;
00289 _useSavedPassword = false;
00290 } else {
00291
00292
00293
00294
00295
00296 _useSavedPassword = true;
00297 }
00298
00299 if (settings.runTorAtStart()) {
00300
00301 start();
00302 }
00303
00304
00305 if (settings.runProxyAtStart())
00306 startProxy();
00307
00308 #if defined(USE_AUTOUPDATE)
00309 if (settings.isAutoUpdateEnabled()) {
00310 QDateTime lastCheckedAt = settings.lastCheckedForUpdates();
00311 if (UpdateProcess::shouldCheckForUpdates(lastCheckedAt)) {
00312 if (settings.runTorAtStart() && ! _torControl->isCircuitEstablished()) {
00313
00314
00315
00316
00317
00318 _updateTimer.start(5*60*1000);
00319 } else {
00320
00321 checkForUpdates();
00322 }
00323 } else {
00324
00325 QDateTime nextCheckAt = UpdateProcess::nextCheckForUpdates(lastCheckedAt);
00326 QDateTime now = QDateTime::currentDateTime().toUTC();
00327
00328 vInfo("Last checked for software updates at %1. Will check again at %2.")
00329 .arg(lastCheckedAt.toLocalTime().toString("dd-MM-yyyy hh:mm:ss"))
00330 .arg(nextCheckAt.toLocalTime().toString("dd-MM-yyyy hh:mm:ss"));
00331 _updateTimer.start((nextCheckAt.toTime_t() - now.toTime_t()) * 1000);
00332 }
00333 }
00334 #endif
00335 }
00336
00337
00338
00339 void
00340 MainWindow::aboutToQuit()
00341 {
00342 vNotice("Cleaning up before exiting.");
00343
00344 if (_torControl->isVidaliaRunningTor()) {
00345
00346 _torControl->stop();
00347 }
00348
00349
00350 ServerSettings settings(_torControl);
00351 settings.cleanupPortForwarding();
00352
00353 if (_proxyProcess->state() != QProcess::NotRunning) {
00354
00355
00356 _proxyProcess->kill();
00357 }
00358
00359
00360 VidaliaSettings vidalia_settings;
00361
00362 if (! vidalia_settings.getBrowserDirectory().isEmpty()) {
00363
00364 QObject::disconnect(_browserProcess, SIGNAL(finished(int, QProcess::ExitStatus)), 0, 0);
00365 QObject::disconnect(_imProcess, SIGNAL(finished(int, QProcess::ExitStatus)), 0, 0);
00366
00367
00368 if (_browserProcess->state() == QProcess::Running)
00369 _browserProcess->terminate();
00370
00371 #if defined(Q_OS_WIN)
00372
00373 win32_end_process_by_filename(vidalia_settings.getBrowserExecutable());
00374 #endif
00375
00376 if (_imProcess->state() == QProcess::Running)
00377 _imProcess->terminate();
00378 }
00379
00380
00381 QObject::disconnect(_torControl, 0, 0, 0);
00382 }
00383
00384
00385
00386
00387 void
00388 MainWindow::close()
00389 {
00390 if (_torControl->isVidaliaRunningTor()) {
00391
00392
00393
00394 ServerSettings settings(_torControl);
00395 if (_torControl->isConnected() && settings.isServerEnabled()) {
00396 connect(_torControl, SIGNAL(stopped()), vApp, SLOT(quit()));
00397 if (!stop())
00398 QObject::disconnect(_torControl, SIGNAL(stopped()), vApp, SLOT(quit()));
00399 return;
00400 }
00401 }
00402 vApp->quit();
00403 }
00404
00405
00406
00407 void
00408 MainWindow::createActions()
00409 {
00410 _actionStartStopTor = new QAction(tr("Start Tor"), this);
00411 connect(_actionStartStopTor, SIGNAL(triggered()), this, SLOT(start()));
00412
00413 _actionExit = new QAction(tr("Exit"), this);
00414 connect(_actionExit, SIGNAL(triggered()), this, SLOT(close()));
00415
00416 _actionShowBandwidth = new QAction(tr("Bandwidth Graph"), this);
00417 connect(_actionShowBandwidth, SIGNAL(triggered()),
00418 _bandwidthGraph, SLOT(showWindow()));
00419 connect(ui.lblBandwidthGraph, SIGNAL(clicked()),
00420 _bandwidthGraph, SLOT(showWindow()));
00421
00422 _actionShowMessageLog = new QAction(tr("Message Log"), this);
00423 connect(_actionShowMessageLog, SIGNAL(triggered()),
00424 _messageLog, SLOT(showWindow()));
00425 connect(ui.lblMessageLog, SIGNAL(clicked()),
00426 _messageLog, SLOT(showWindow()));
00427
00428 _actionShowNetworkMap = new QAction(tr("Network Map"), this);
00429 connect(_actionShowNetworkMap, SIGNAL(triggered()),
00430 _netViewer, SLOT(showWindow()));
00431 connect(ui.lblViewNetwork, SIGNAL(clicked()),
00432 _netViewer, SLOT(showWindow()));
00433
00434 _actionShowControlPanel = new QAction(tr("Control Panel"), this);
00435 connect(_actionShowControlPanel, SIGNAL(triggered()), this, SLOT(show()));
00436
00437 _actionShowConfig = new QAction(tr("Settings"), this);
00438 connect(_actionShowConfig, SIGNAL(triggered()), this, SLOT(showConfigDialog()));
00439
00440 _actionShowAbout = new QAction(tr("About"), this);
00441 connect(_actionShowAbout, SIGNAL(triggered()), this, SLOT(showAboutDialog()));
00442
00443 _actionShowHelp = new QAction(tr("Help"), this);
00444 connect(_actionShowHelp, SIGNAL(triggered()), this, SLOT(showHelpDialog()));
00445 connect(ui.lblHelpBrowser, SIGNAL(clicked()), this, SLOT(showHelpDialog()));
00446
00447 _actionNewIdentity = new QAction(tr("New Identity"), this);
00448 _actionNewIdentity->setEnabled(false);
00449 connect(_actionNewIdentity, SIGNAL(triggered()), this, SLOT(newIdentity()));
00450
00451 #if !defined(Q_WS_MAC)
00452
00453
00454
00455 _actionStartStopTor->setIcon(QIcon(IMG_START_TOR_16));
00456 _actionExit->setIcon(QIcon(IMG_EXIT));
00457 _actionShowBandwidth->setIcon(QIcon(IMG_BWGRAPH));
00458 _actionShowMessageLog->setIcon(QIcon(IMG_MESSAGELOG));
00459 _actionShowNetworkMap->setIcon(QIcon(IMG_NETWORK));
00460 _actionShowControlPanel->setIcon(QIcon(IMG_CONTROL_PANEL));
00461 _actionShowConfig->setIcon(QIcon(IMG_CONFIG));
00462 _actionShowAbout->setIcon(QIcon(IMG_ABOUT));
00463 _actionShowHelp->setIcon(QIcon(IMG_HELP));
00464 _actionNewIdentity->setIcon(QIcon(IMG_IDENTITY));
00465 #endif
00466 }
00467
00468
00469
00470 void
00471 MainWindow::createTrayIcon()
00472 {
00473 QMenu *menu = createTrayMenu();
00474
00475
00476 _trayIcon.setContextMenu(menu);
00477
00478 connect(&_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
00479 this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
00480
00481 #if defined(Q_WS_MAC)
00482 createMenuBar();
00483 qt_mac_set_dock_menu(menu);
00484 #endif
00485 }
00486
00487
00488
00489 QMenu*
00490 MainWindow::createTrayMenu()
00491 {
00492 QMenu *menu = new QMenu(this);
00493 menu->addAction(_actionStartStopTor);
00494 menu->addSeparator();
00495 menu->addAction(_actionShowBandwidth);
00496 menu->addAction(_actionShowMessageLog);
00497 menu->addAction(_actionShowNetworkMap);
00498 menu->addAction(_actionNewIdentity);
00499 menu->addSeparator();
00500 menu->addAction(_actionShowControlPanel);
00501
00502 #if !defined(Q_WS_MAC)
00503
00504
00505 menu->addAction(_actionShowConfig);
00506 menu->addAction(_actionShowHelp);
00507 menu->addAction(_actionShowAbout);
00508 menu->addSeparator();
00509 menu->addAction(_actionExit);
00510 #endif
00511 return menu;
00512 }
00513
00514
00515
00516
00517 void
00518 MainWindow::createMenuBar()
00519 {
00520 #if defined(Q_WS_MAC)
00521
00522
00523
00524 _actionStartStopTor->setShortcut(tr("Ctrl+T"));
00525 _actionShowBandwidth->setShortcut(tr("Ctrl+B"));
00526 _actionShowMessageLog->setShortcut(tr("Ctrl+L"));
00527 _actionShowNetworkMap->setShortcut(tr("Ctrl+N"));
00528 _actionShowHelp->setShortcut(tr("Ctrl+?"));
00529 _actionNewIdentity->setShortcut(tr("Ctrl+I"));
00530 _actionShowControlPanel->setShortcut(tr("Ctrl+P"));
00531
00532
00533
00534 _actionShowConfig->setText("config");
00535 _actionShowConfig->setMenuRole(QAction::PreferencesRole);
00536 _actionShowAbout->setText("about");
00537 _actionShowAbout->setMenuRole(QAction::AboutRole);
00538 _actionExit->setText("quit");
00539 _actionExit->setMenuRole(QAction::QuitRole);
00540
00541
00542
00543 if (_menuBar)
00544 delete _menuBar;
00545 _menuBar = new QMenuBar(0);
00546 QMenu *fileMenu = _menuBar->addMenu("File");
00547 fileMenu->addAction(_actionExit);
00548 fileMenu->addAction(_actionShowConfig);
00549
00550 QMenu *torMenu = _menuBar->addMenu(tr("Tor"));
00551 torMenu->addAction(_actionStartStopTor);
00552 torMenu->addSeparator();
00553 torMenu->addAction(_actionNewIdentity);
00554
00555 QMenu *viewMenu = _menuBar->addMenu(tr("View"));
00556 viewMenu->addAction(_actionShowControlPanel);
00557 viewMenu->addSeparator();
00558 viewMenu->addAction(_actionShowBandwidth);
00559 viewMenu->addAction(_actionShowMessageLog);
00560 viewMenu->addAction(_actionShowNetworkMap);
00561
00562 QMenu *helpMenu = _menuBar->addMenu(tr("Help"));
00563 _actionShowHelp->setText(tr("Vidalia Help"));
00564 helpMenu->addAction(_actionShowHelp);
00565 helpMenu->addAction(_actionShowAbout);
00566 #endif
00567 }
00568
00569
00570 void
00571 MainWindow::setTrayIcon(const QString &iconFile)
00572 {
00573 #if defined(Q_WS_MAC)
00574 QApplication::setWindowIcon(QPixmap(iconFile));
00575 #else
00576 _trayIcon.setIcon(QIcon(iconFile));
00577 #endif
00578 }
00579
00580
00581
00582 void
00583 MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
00584 {
00585 if (reason == QSystemTrayIcon::DoubleClick)
00586 setVisible(true);
00587 }
00588
00589
00590 void
00591 MainWindow::launchBrowserFromDirectory()
00592 {
00593 VidaliaSettings settings;
00594
00595 QString browserDirectory = settings.getBrowserDirectory();
00596 QString browserDirectoryFilename = settings.getBrowserExecutable();
00597
00598
00599
00600 QStringList env = QProcess::systemEnvironment();
00601 env << "TZ=UTC";
00602 env << "MOZ_NO_REMOTE=1";
00603 _browserProcess->setEnvironment(env);
00604
00605
00606 QString browserExecutable =
00607 QDir::toNativeSeparators(browserDirectory + "/App/Firefox/" + browserDirectoryFilename);
00608
00609 QString profileDir =
00610 QDir::toNativeSeparators(browserDirectory + "/Data/profile");
00611
00612
00613 QDir browserDirObj = QDir(browserDirectory);
00614
00615
00616 if (!browserDirObj.exists("Data/profile")) {
00617 browserDirObj.mkdir("Data/profile");
00618 copy_dir(browserDirectory + "/App/DefaultData/profile", browserDirectory + "/Data/profile");
00619 }
00620
00621
00622 if (!browserDirObj.exists("Data/plugins")) {
00623 browserDirObj.mkdir("Data/plugins");
00624 copy_dir(browserDirectory + "/App/DefaultData/plugins", browserDirectory + "/Data/plugins");
00625 }
00626
00627
00628 QStringList commandLine;
00629
00630
00631 commandLine << "-profile";
00632 commandLine << profileDir;
00633
00634
00635 _browserProcess->start(browserExecutable, commandLine);
00636 }
00637
00638
00639 void
00640 MainWindow::startSubprocesses()
00641 {
00642 VidaliaSettings settings;
00643 QString subprocess;
00644
00645
00646 if (!(subprocess = settings.getBrowserDirectory()).isEmpty()) {
00647
00648 launchBrowserFromDirectory();
00649 } else if (!(subprocess = settings.getBrowserExecutable()).isEmpty()) {
00650
00651 _browserProcess->setEnvironment(QProcess::systemEnvironment() << "TZ=UTC");
00652 _browserProcess->start(subprocess, QStringList());
00653 }
00654
00655
00656 subprocess = settings.getIMExecutable();
00657
00658 if (!subprocess.isEmpty())
00659 _imProcess->start(subprocess, QStringList());
00660 }
00661
00662
00663 void
00664 MainWindow::onSubprocessFinished(int exitCode, QProcess::ExitStatus exitStatus)
00665 {
00666 Q_UNUSED(exitCode)
00667 Q_UNUSED(exitStatus)
00668
00669
00670 VidaliaSettings settings;
00671 QString browserExecutable = settings.getBrowserExecutable();
00672 QString browserDirectory = settings.getBrowserDirectory();
00673 QString imExecutable = settings.getIMExecutable();
00674
00675
00676 bool browserDone = (browserExecutable.isEmpty()
00677 && browserDirectory.isEmpty())
00678 || _browserProcess->isDone();
00679 bool imDone = imExecutable.isEmpty() || _imProcess->isDone();
00680
00681
00682 if (browserDone && imDone) {
00683 if (browserDirectory.isEmpty()) {
00684
00685 vApp->quit();
00686 } else {
00687
00688 QTimer *browserWatcher = new QTimer(this);
00689 connect(browserWatcher, SIGNAL(timeout()), this, SLOT(onCheckForBrowser()));
00690 browserWatcher->start(2000);
00691 }
00692 }
00693 }
00694
00695
00696
00697 void
00698 MainWindow::onCheckForBrowser()
00699 {
00700
00701 #if defined(Q_OS_WIN)
00702
00703 VidaliaSettings settings;
00704 QString browserDirectoryFilename = settings.getBrowserExecutable();
00705
00706
00707 QHash<qint64, QString> procList = win32_process_list();
00708
00709
00710
00711 if (procList.isEmpty()) {
00712 return;
00713 }
00714
00715
00716 QHashIterator<qint64, QString> i(procList);
00717 while (i.hasNext()) {
00718 i.next();
00719 if (i.value().toLower() == browserDirectoryFilename) {
00720
00721 return;
00722 }
00723 }
00724
00725
00726 vApp->quit();
00727 #endif
00728 }
00729
00730
00731
00732 void
00733 MainWindow::onBrowserFailed(QString errmsg)
00734 {
00735 Q_UNUSED(errmsg);
00736
00737
00738 VMessageBox::warning(this, tr("Error starting web browser"),
00739 tr("Vidalia was unable to start the configured web browser"),
00740 VMessageBox::Ok|VMessageBox::Default|VMessageBox::Escape);
00741 }
00742
00743
00744
00745 void
00746 MainWindow::onIMFailed(QString errmsg)
00747 {
00748 Q_UNUSED(errmsg);
00749
00750
00751 VMessageBox::warning(this, tr("Error starting IM client"),
00752 tr("Vidalia was unable to start the configured IM client"),
00753 VMessageBox::Ok|VMessageBox::Default|VMessageBox::Escape);
00754 }
00755
00756
00757 void
00758 MainWindow::startProxy()
00759 {
00760 VidaliaSettings settings;
00761 QString executable = settings.getProxyExecutable();
00762 _proxyProcess->start(executable, settings.getProxyExecutableArguments());
00763 }
00764
00765
00766
00767 void
00768 MainWindow::onProxyFailed(QString errmsg)
00769 {
00770 Q_UNUSED(errmsg);
00771
00772
00773 VMessageBox::warning(this, tr("Error starting proxy server"),
00774 tr("Vidalia was unable to start the configured proxy server"),
00775 VMessageBox::Ok|VMessageBox::Default|VMessageBox::Escape);
00776 }
00777
00778
00779
00780 void
00781 MainWindow::bootstrapStatusChanged(const BootstrapStatus &bs)
00782 {
00783 int percentComplete = STARTUP_PROGRESS_BOOTSTRAPPING + bs.percentComplete();
00784 bool warn = (bs.severity() == tc::WarnSeverity &&
00785 bs.recommendedAction() != BootstrapStatus::RecommendIgnore);
00786
00787 QString description;
00788 switch (bs.status()) {
00789 case BootstrapStatus::ConnectingToDirMirror:
00790 description = tr("Connecting to a relay directory");
00791 break;
00792 case BootstrapStatus::HandshakingWithDirMirror:
00793 case BootstrapStatus::CreatingOneHopCircuit:
00794 description = tr("Establishing an encrypted directory connection");
00795 break;
00796 case BootstrapStatus::RequestingNetworkStatus:
00797 description = tr("Retrieving network status");
00798 break;
00799 case BootstrapStatus::LoadingNetworkStatus:
00800 description = tr("Loading network status");
00801 break;
00802 case BootstrapStatus::LoadingAuthorityCertificates:
00803 description = tr("Loading authority certificates");
00804 break;
00805 case BootstrapStatus::RequestingDescriptors:
00806 description = tr("Requesting relay information");
00807 break;
00808 case BootstrapStatus::LoadingDescriptors:
00809 description = tr("Loading relay information");
00810 break;
00811 case BootstrapStatus::ConnectingToEntryGuard:
00812 description = tr("Connecting to the Tor network");
00813 break;
00814 case BootstrapStatus::HandshakingWithEntryGuard:
00815 case BootstrapStatus::EstablishingCircuit:
00816 description = tr("Establishing a Tor circuit");
00817 break;
00818 case BootstrapStatus::BootstrappingDone:
00819 description = tr("Connected to the Tor network!");
00820 warn = false;
00821 break;
00822 default:
00823 description = tr("Unrecognized startup status");
00824 }
00825 if (warn) {
00826 QString reason;
00827
00828 switch (bs.reason()) {
00829 case tc::MiscellaneousReason:
00830 reason = tr("miscellaneous");
00831 break;
00832 case tc::IdentityMismatch:
00833 reason = tr("identity mismatch");
00834 break;
00835 case tc::ConnectionDone:
00836 reason = tr("done");
00837 break;
00838 case tc::ConnectionRefused:
00839 reason = tr("connection refused");
00840 break;
00841 case tc::ConnectionTimeout:
00842 reason = tr("connection timeout");
00843 break;
00844 case tc::ConnectionIoError:
00845 reason = tr("read/write error");
00846 break;
00847 case tc::NoRouteToHost:
00848 reason = tr("no route to host");
00849 break;
00850 case tc::ResourceLimitReached:
00851 reason = tr("insufficient resources");
00852 break;
00853 default:
00854 reason = tr("unknown");
00855 }
00856 description += tr(" failed (%1)").arg(reason);
00857 }
00858 setStartupProgress(percentComplete, description);
00859 }
00860
00861
00862
00863 MainWindow::TorStatus
00864 MainWindow::updateTorStatus(TorStatus status)
00865 {
00866 QString statusText, actionText;
00867 QString trayIconFile, statusIconFile;
00868 TorStatus prevStatus = _status;
00869
00870 vNotice("Tor status changed from '%1' to '%2'.")
00871 .arg(toString(prevStatus)).arg(toString(status));
00872 _status = status;
00873
00874 if (status == Stopped) {
00875 statusText = tr("Tor is not running");
00876 actionText = tr("Start Tor");
00877 trayIconFile = IMG_TOR_STOPPED;
00878 statusIconFile = IMG_TOR_STOPPED_48;
00879 _actionStartStopTor->setEnabled(true);
00880 _actionStartStopTor->setText(actionText);
00881 _actionStartStopTor->setIcon(QIcon(IMG_START_TOR_16));
00882 ui.lblStartStopTor->setEnabled(true);
00883 ui.lblStartStopTor->setText(actionText);
00884 ui.lblStartStopTor->setPixmap(QPixmap(IMG_START_TOR_48));
00885 ui.lblStartStopTor->setStatusTip(actionText);
00886
00887
00888
00889 QObject::disconnect(_actionStartStopTor, SIGNAL(triggered()), this, 0);
00890 QObject::disconnect(ui.lblStartStopTor, SIGNAL(clicked()), this, 0);
00891 connect(_actionStartStopTor, SIGNAL(triggered()), this, SLOT(start()));
00892 connect(ui.lblStartStopTor, SIGNAL(clicked()), this, SLOT(start()));
00893 setStartupProgressVisible(false);
00894 } else if (status == Stopping) {
00895 if (_delayedShutdownStarted) {
00896 statusText = tr("Your relay is shutting down.\n"
00897 "Click 'Stop' again to stop your relay now.");
00898 } else {
00899 statusText = tr("Tor is shutting down");
00900 }
00901 trayIconFile = IMG_TOR_STOPPING;
00902 statusIconFile = IMG_TOR_STOPPING_48;
00903
00904 ui.lblStartStopTor->setStatusTip(tr("Stop Tor Now"));
00905 } else if (status == Started) {
00906 actionText = tr("Stop Tor");
00907 _actionStartStopTor->setEnabled(true);
00908 _actionStartStopTor->setText(actionText);
00909 _actionStartStopTor->setIcon(QIcon(IMG_STOP_TOR_16));
00910 ui.lblStartStopTor->setEnabled(true);
00911 ui.lblStartStopTor->setText(actionText);
00912 ui.lblStartStopTor->setPixmap(QPixmap(IMG_STOP_TOR_48));
00913 ui.lblStartStopTor->setStatusTip(actionText);
00914
00915
00916
00917 QObject::disconnect(_actionStartStopTor, SIGNAL(triggered()), this, 0);
00918 QObject::disconnect(ui.lblStartStopTor, SIGNAL(clicked()), this, 0);
00919 connect(_actionStartStopTor, SIGNAL(triggered()), this, SLOT(stop()));
00920 connect(ui.lblStartStopTor, SIGNAL(clicked()), this, SLOT(stop()));
00921 } else if (status == Starting) {
00922 statusText = tr("Starting the Tor software");
00923 trayIconFile = IMG_TOR_STARTING;
00924 statusIconFile = IMG_TOR_STARTING_48;
00925 _actionStartStopTor->setEnabled(false);
00926 ui.lblStartStopTor->setText(tr("Starting Tor"));
00927 ui.lblStartStopTor->setEnabled(false);
00928 ui.lblStartStopTor->setStatusTip(statusText);
00929 setStartupProgressVisible(true);
00930 setStartupProgress(STARTUP_PROGRESS_STARTING, statusText);
00931 } else if (status == CircuitEstablished) {
00932 statusText = tr("Connected to the Tor network!");
00933 trayIconFile = IMG_TOR_RUNNING;
00934 statusIconFile = IMG_TOR_RUNNING_48;
00935 setStartupProgressVisible(false);
00936 }
00937
00938
00939 if (!trayIconFile.isEmpty()) {
00940 setTrayIcon(trayIconFile);
00941 }
00942
00943 if (!statusIconFile.isEmpty())
00944 ui.lblTorStatusImg->setPixmap(QPixmap(statusIconFile));
00945 if (!statusText.isEmpty()) {
00946 _trayIcon.setToolTip(statusText);
00947 ui.lblTorStatus->setText(statusText);
00948 }
00949 return prevStatus;
00950 }
00951
00952
00953 void
00954 MainWindow::toggleShowOnStartup(bool checked)
00955 {
00956 VidaliaSettings settings;
00957 settings.setShowMainWindowAtStart(checked);
00958 }
00959
00960
00961
00962 void
00963 MainWindow::setStartupProgressVisible(bool visible)
00964 {
00965
00966
00967 if (visible) {
00968 ui.lblTorStatus->setVisible(false);
00969 ui.lblTorStatusImg->setVisible(false);
00970 repaint(ui.grpStatus->rect());
00971 ui.lblStartupProgress->setVisible(true);
00972 ui.progressBar->setVisible(true);
00973 } else {
00974 ui.lblStartupProgress->setVisible(false);
00975 ui.progressBar->setVisible(false);
00976 repaint(ui.grpStatus->rect());
00977 ui.lblTorStatus->setVisible(true);
00978 ui.lblTorStatusImg->setVisible(true);
00979 }
00980 }
00981
00982
00983
00984 void
00985 MainWindow::setStartupProgress(int progressValue,
00986 const QString &description)
00987 {
00988 ui.progressBar->setValue(progressValue);
00989 ui.lblStartupProgress->setText(description);
00990 _trayIcon.setToolTip(description);
00991 }
00992
00993
00994
00995 void
00996 MainWindow::start()
00997 {
00998 TorSettings settings;
00999 QStringList args;
01000
01001 updateTorStatus(Starting);
01002
01003
01004 if (net_test_connect(settings.getControlAddress(),
01005 settings.getControlPort())) {
01006 started();
01007 return;
01008 }
01009
01010
01011 QString torrc = settings.getTorrc();
01012 if (!torrc.isEmpty()) {
01013 if (!QFileInfo(torrc).exists())
01014 touch_file(torrc, true);
01015 args << "-f" << torrc;
01016 }
01017
01018
01019 QString dataDirectory = settings.getDataDirectory();
01020 if (!dataDirectory.isEmpty())
01021 args << "DataDirectory" << expand_filename(dataDirectory);
01022
01023
01024 quint16 controlPort = settings.getControlPort();
01025 if (controlPort)
01026 args << "ControlPort" << QString::number(controlPort);
01027
01028
01029 switch (settings.getAuthenticationMethod()) {
01030 case TorSettings::PasswordAuth:
01031 if (! vApp->readPasswordFromStdin()) {
01032 if (settings.useRandomPassword()) {
01033 _controlPassword = TorSettings::randomPassword();
01034 _useSavedPassword = false;
01035 } else {
01036 _controlPassword = settings.getControlPassword();
01037 _useSavedPassword = true;
01038 }
01039 }
01040 args << "HashedControlPassword"
01041 << TorSettings::hashPassword(_controlPassword);
01042 break;
01043 case TorSettings::CookieAuth:
01044 args << "CookieAuthentication" << "1";
01045 break;
01046 default:
01047 args << "CookieAuthentication" << "0";
01048 }
01049
01050
01051
01052
01053
01054 _isIntentionalExit = true;
01055
01056 _torControl->start(settings.getExecutable(), args);
01057 }
01058
01059
01060
01061 void
01062 MainWindow::startFailed(QString errmsg)
01063 {
01064
01065
01066
01067 Q_UNUSED(errmsg);
01068
01069 updateTorStatus(Stopped);
01070
01071
01072 int response = VMessageBox::warning(this, tr("Error Starting Tor"),
01073 tr("Vidalia was unable to start Tor. Check your settings "
01074 "to ensure the correct name and location of your Tor "
01075 "executable is specified."),
01076 VMessageBox::ShowSettings|VMessageBox::Default,
01077 VMessageBox::Cancel|VMessageBox::Escape,
01078 VMessageBox::Help);
01079
01080 if (response == VMessageBox::ShowSettings) {
01081
01082
01083 showConfigDialog();
01084 } else if (response == VMessageBox::Help) {
01085
01086 showHelpDialog("troubleshooting.start");
01087 }
01088 }
01089
01090
01091
01092 void
01093 MainWindow::started()
01094 {
01095 TorSettings settings;
01096
01097 updateTorStatus(Started);
01098
01099
01100
01101 _isIntentionalExit = false;
01102
01103 _delayedShutdownStarted = false;
01104
01105 _isVidaliaRunningTor = _torControl->isVidaliaRunningTor();
01106
01107 _torControl->connect(settings.getControlAddress(),
01108 settings.getControlPort());
01109 setStartupProgress(STARTUP_PROGRESS_CONNECTING, tr("Connecting to Tor"));
01110 }
01111
01112
01113
01114 void
01115 MainWindow::connectFailed(QString errmsg)
01116 {
01117
01118 int response = VMessageBox::warning(this,
01119 tr("Connection Error"), p(errmsg),
01120 VMessageBox::Ok|VMessageBox::Default|VMessageBox::Escape,
01121 VMessageBox::Retry, VMessageBox::Help);
01122
01123
01124 if (response == VMessageBox::Retry) {
01125
01126 TorSettings settings;
01127 _torControl->connect(settings.getControlAddress(),
01128 settings.getControlPort());
01129 } else {
01130
01131 if (response == VMessageBox::Help)
01132 showHelpDialog("troubleshooting.connect");
01133
01134 _torControl->stop();
01135 }
01136 }
01137
01138
01139 bool
01140 MainWindow::stop()
01141 {
01142 ServerSettings server(_torControl);
01143 QString errmsg;
01144 TorStatus prevStatus;
01145 bool rc;
01146
01147
01148
01149 if (server.isServerEnabled() && !_delayedShutdownStarted) {
01150
01151 int response = VMessageBox::question(this, tr("Relaying is Enabled"),
01152 tr("You are currently running a relay. "
01153 "Terminating your relay will interrupt any "
01154 "open connections from clients.\n\n"
01155 "Would you like to shutdown gracefully and "
01156 "give clients time to find a new relay?"),
01157 VMessageBox::Yes|VMessageBox::Default,
01158 VMessageBox::No,
01159 VMessageBox::Cancel|VMessageBox::Escape);
01160 if (response == VMessageBox::Yes)
01161 _delayedShutdownStarted = true;
01162 else if (response == VMessageBox::Cancel)
01163 return false;
01164 }
01165
01166 prevStatus = updateTorStatus(Stopping);
01167 if (_delayedShutdownStarted) {
01168
01169 rc = _torControl->signal(TorSignal::Shutdown, &errmsg);
01170 } else {
01171
01172 _isIntentionalExit = true;
01173 rc = _torControl->stop(&errmsg);
01174 }
01175
01176 if (!rc) {
01177
01178 int response = VMessageBox::warning(this, tr("Error Shutting Down"),
01179 p(tr("Vidalia was unable to stop the Tor software."))
01180 + p(errmsg),
01181 VMessageBox::Ok|VMessageBox::Default|VMessageBox::Escape,
01182 VMessageBox::Help);
01183
01184 if (response == VMessageBox::Help) {
01185
01186 showHelpDialog("troubleshooting.stop");
01187 }
01188
01189 _isIntentionalExit = false;
01190 _delayedShutdownStarted = false;
01191 updateTorStatus(prevStatus);
01192 }
01193 return rc;
01194 }
01195
01196
01197
01198 void
01199 MainWindow::stopped(int exitCode, QProcess::ExitStatus exitStatus)
01200 {
01201 updateTorStatus(Stopped);
01202
01203
01204
01205 if (!_isIntentionalExit) {
01206
01207
01208
01209 if (exitStatus == QProcess::CrashExit || exitCode != 0) {
01210 int ret = VMessageBox::warning(this, tr("Unexpected Error"),
01211 tr("Vidalia detected that the Tor software exited "
01212 "unexpectedly.\n\n"
01213 "Please check the message log for recent "
01214 "warning or error messages."),
01215 VMessageBox::Ok|VMessageBox::Escape,
01216 VMessageBox::ShowLog|VMessageBox::Default,
01217 VMessageBox::Help);
01218 if (ret == VMessageBox::ShowLog)
01219 _messageLog->showWindow();
01220 else if (ret == VMessageBox::Help)
01221 showHelpDialog("troubleshooting.torexited");
01222 }
01223 }
01224 }
01225
01226
01227 void
01228 MainWindow::connected()
01229 {
01230 authenticate();
01231 }
01232
01233
01234 void
01235 MainWindow::disconnect()
01236 {
01237 _torControl->disconnect();
01238 }
01239
01240
01241 void
01242 MainWindow::disconnected()
01243 {
01244 if (!_isVidaliaRunningTor) {
01245
01246
01247 updateTorStatus(Stopped);
01248 }
01249
01250
01251 _actionNewIdentity->setEnabled(false);
01252 ui.lblNewIdentity->setEnabled(false);
01253 _isVidaliaRunningTor = false;
01254 }
01255
01256
01257
01258
01259 bool
01260 MainWindow::authenticate()
01261 {
01262 TorSettings::AuthenticationMethod authMethod;
01263 TorSettings settings;
01264 ProtocolInfo pi;
01265
01266 updateTorStatus(Authenticating);
01267 setStartupProgress(STARTUP_PROGRESS_AUTHENTICATING,
01268 tr("Authenticating to Tor"));
01269
01270 authMethod = settings.getAuthenticationMethod();
01271 pi = _torControl->protocolInfo();
01272 if (!pi.isEmpty()) {
01273 QStringList authMethods = pi.authMethods();
01274 if (authMethods.contains("COOKIE"))
01275 authMethod = TorSettings::CookieAuth;
01276 else if (authMethods.contains("HASHEDPASSWORD"))
01277 authMethod = TorSettings::PasswordAuth;
01278 else if (authMethods.contains("NULL"))
01279 authMethod = TorSettings::NullAuth;
01280 }
01281
01282 if (authMethod == TorSettings::CookieAuth) {
01283
01284 QByteArray cookie = loadControlCookie(pi.cookieAuthFile());
01285 while (cookie.isEmpty()) {
01286
01287 int ret = VMessageBox::question(this,
01288 tr("Cookie Authentication Required"),
01289 p(tr("The Tor software requires Vidalia to send the "
01290 "contents of an authentication cookie, but Vidalia "
01291 "was unable to find one."))
01292 + p(tr("Would you like to browse for the file "
01293 "'control_auth_cookie' yourself?")),
01294 VMessageBox::Browse|VMessageBox::Default,
01295 VMessageBox::Cancel|VMessageBox::Escape);
01296
01297 if (ret == VMessageBox::Cancel)
01298 goto cancel;
01299 QString cookieDir = QFileDialog::getOpenFileName(this,
01300 tr("Data Directory"),
01301 settings.getDataDirectory(),
01302 tr("Control Cookie (control_auth_cookie)"));
01303 if (cookieDir.isEmpty())
01304 goto cancel;
01305 cookieDir = QFileInfo(cookieDir).absolutePath();
01306 cookie = loadControlCookie(cookieDir);
01307 }
01308 vNotice("Authenticating using 'cookie' authentication.");
01309 return _torControl->authenticate(cookie);
01310 } else if (authMethod == TorSettings::PasswordAuth) {
01311
01312 vNotice("Authenticating using 'hashed password' authentication.");
01313 if (_useSavedPassword) {
01314 TorSettings settings;
01315 _controlPassword = settings.getControlPassword();
01316 }
01317 return _torControl->authenticate(_controlPassword);
01318 }
01319
01320 vNotice("Authenticating using 'null' authentication.");
01321 return _torControl->authenticate(QString(""));
01322
01323 cancel:
01324 vWarn("Cancelling control authentication attempt.");
01325 if (_isVidaliaRunningTor)
01326 stop();
01327 else
01328 disconnect();
01329 return false;
01330 }
01331
01332
01333 void
01334 MainWindow::authenticated()
01335 {
01336 ServerSettings serverSettings(_torControl);
01337 QString errmsg;
01338
01339 updateTorStatus(Authenticated);
01340
01341
01342
01343 if (_torControl->getTorVersion() < 0x020101) {
01344 setStartupProgress(STARTUP_PROGRESS_CIRCUITBUILD,
01345 tr("Connecting to the Tor network"));
01346 }
01347
01348
01349 _actionNewIdentity->setEnabled(true);
01350 ui.lblNewIdentity->setEnabled(true);
01351
01352
01353 if (!_torControl->setEvents(&errmsg)) {
01354 VMessageBox::warning(this, tr("Error Registering for Events"),
01355 p(tr("Vidalia was unable to register for some events. "
01356 "Many of Vidalia's features may be unavailable."))
01357 + p(errmsg),
01358 VMessageBox::Ok);
01359 } else {
01360
01361
01362 _torControl->closeTorStdout();
01363 }
01364
01365
01366 serverSettings.configurePortForwarding();
01367
01368
01369 if (_torControl->isCircuitEstablished())
01370 circuitEstablished();
01371
01372 if (_torControl->getTorVersion() >= 0x020001)
01373 checkTorVersion();
01374 if (_torControl->getTorVersion() >= 0x020102) {
01375 BootstrapStatus status = _torControl->bootstrapStatus();
01376 if (status.isValid())
01377 bootstrapStatusChanged(status);
01378 }
01379 }
01380
01381
01382
01383 void
01384 MainWindow::authenticationFailed(QString errmsg)
01385 {
01386 bool retry = false;
01387
01388 vWarn("Authentication failed: %1").arg(errmsg);
01389
01390
01391 if (errmsg.contains("Password did not match")) {
01392 ControlPasswordInputDialog dlg;
01393 connect(&dlg, SIGNAL(helpRequested(QString)),
01394 this, SLOT(showHelpDialog(QString)));
01395
01396 qint64 torPid = 0;
01397
01398 #if defined(Q_OS_WIN32)
01399 QHash<qint64, QString> procs = process_list();
01400 foreach (qint64 pid, procs.keys()) {
01401 if (! procs.value(pid).compare("tor.exe", Qt::CaseInsensitive)) {
01402 torPid = pid;
01403 break;
01404 }
01405 }
01406 dlg.setResetEnabled(torPid > 0);
01407 #else
01408 dlg.setResetEnabled(false);
01409 #endif
01410
01411 int ret = dlg.exec();
01412 if (ret == QDialogButtonBox::Ok) {
01413 if (dlg.isSavePasswordChecked()) {
01414 TorSettings settings;
01415 settings.setAuthenticationMethod(TorSettings::PasswordAuth);
01416 settings.setUseRandomPassword(false);
01417 settings.setControlPassword(dlg.password());
01418 _useSavedPassword = true;
01419 } else {
01420 _controlPassword = dlg.password();
01421 _useSavedPassword = false;
01422 }
01423 retry = true;
01424 } else if (ret == QDialogButtonBox::Reset) {
01425 if (! process_kill(torPid)) {
01426 VMessageBox::warning(this,
01427 tr("Password Reset Failed"),
01428 p(tr("Vidalia tried to reset Tor's control password, but was not "
01429 "able to restart the Tor software. Please check your Task "
01430 "Manager to ensure there are no other Tor processes running.")),
01431 VMessageBox::Ok|VMessageBox::Default);
01432 } else {
01433 retry = true;
01434 }
01435 }
01436 } else {
01437
01438 int ret = VMessageBox::warning(this,
01439 tr("Authentication Error"),
01440 p(tr("Vidalia was unable to authenticate to the Tor software. "
01441 "(%1)").arg(errmsg)) +
01442 p(tr("Please check your control port authentication "
01443 "settings.")),
01444 VMessageBox::ShowSettings|VMessageBox::Default,
01445 VMessageBox::Cancel|VMessageBox::Escape);
01446
01447 if (ret == VMessageBox::ShowSettings)
01448 showConfigDialog(ConfigDialog::Advanced);
01449 }
01450
01451 if (_torControl->isRunning())
01452 if (_isVidaliaRunningTor)
01453 stop();
01454 else
01455 disconnect();
01456 if (retry)
01457 start();
01458 }
01459
01460
01461
01462
01463
01464
01465 QByteArray
01466 MainWindow::loadControlCookie(QString cookiePath)
01467 {
01468 QFile authCookie;
01469 QStringList pathList;
01470
01471 if (!cookiePath.isEmpty()) {
01472 pathList << cookiePath;
01473 } else {
01474
01475 TorSettings settings;
01476 QString dataDir = settings.getDataDirectory();
01477 if (!dataDir.isEmpty())
01478 pathList << dataDir;
01479
01480 #if defined(Q_WS_WIN)
01481 pathList << expand_filename("%APPDATA%\\Tor");
01482 #else
01483 pathList << expand_filename("~/.tor");
01484 #endif
01485 }
01486
01487
01488 foreach (QString path, pathList) {
01489 QString cookieFile = QFileInfo(path).isFile() ?
01490 path : path + "/control_auth_cookie";
01491 vDebug("Checking for authentication cookie in '%1'").arg(cookieFile);
01492 if (!QFileInfo(cookieFile).exists())
01493 continue;
01494
01495 authCookie.setFileName(cookieFile);
01496 if (authCookie.open(QIODevice::ReadOnly)) {
01497 vInfo("Reading authentication cookie from '%1'").arg(cookieFile);
01498 return authCookie.readAll();
01499 } else {
01500 vWarn("Couldn't open cookie file '%1': %2")
01501 .arg(cookieFile).arg(authCookie.errorString());
01502 }
01503 }
01504 vWarn("Couldn't find a readable authentication cookie.");
01505 return QByteArray();
01506 }
01507
01508
01509 void
01510 MainWindow::circuitEstablished()
01511 {
01512 updateTorStatus(CircuitEstablished);
01513 setStartupProgress(ui.progressBar->maximum(),
01514 tr("Connected to the Tor network!"));
01515 startSubprocesses();
01516
01517 #if defined(USE_AUTOUPDATE)
01518 VidaliaSettings settings;
01519 if (settings.isAutoUpdateEnabled()) {
01520 QDateTime lastCheckedAt = settings.lastCheckedForUpdates();
01521 if (UpdateProcess::shouldCheckForUpdates(lastCheckedAt)) {
01522
01523 _updateTimer.stop();
01524 checkForUpdates();
01525 }
01526 }
01527 #endif
01528 }
01529
01530
01531
01532 void
01533 MainWindow::checkTorVersion()
01534 {
01535 QString status;
01536 if (_torControl->getInfo("status/version/current", status)) {
01537 if (!status.compare("old", Qt::CaseInsensitive)
01538 || !status.compare("unrecommended", Qt::CaseInsensitive)
01539 || !status.compare("obsolete", Qt::CaseInsensitive)) {
01540 displayTorVersionWarning();
01541 }
01542 }
01543 }
01544
01545
01546
01547 void
01548 MainWindow::dangerousTorVersion(tc::TorVersionStatus reason,
01549 const QString ¤t,
01550 const QStringList &recommended)
01551 {
01552 Q_UNUSED(current);
01553 Q_UNUSED(recommended);
01554
01555 if (reason == tc::ObsoleteTorVersion
01556 || reason == tc::UnrecommendedTorVersion)
01557 displayTorVersionWarning();
01558 }
01559
01560
01561
01562 void
01563 MainWindow::displayTorVersionWarning()
01564 {
01565 static bool alreadyWarned = false;
01566
01567 if (!alreadyWarned) {
01568 #if !defined(USE_AUTOUPDATE)
01569 QString website = "https://www.torproject.org/";
01570 # if QT_VERSION >= 0x040200
01571 website = QString("<a href=\"%1\">%1</a>").arg(website);
01572 # endif
01573
01574 VMessageBox::information(this, tr("Tor Update Available"),
01575 p(tr("The currently installed version of Tor is out of date or no longer "
01576 "recommended. Please visit the Tor website to download the latest "
01577 "version.")) + p(tr("Tor website: %1").arg(website)),
01578 VMessageBox::Ok);
01579 #else
01580 int ret = VMessageBox::information(this,
01581 tr("Tor Update Available"),
01582 p(tr("The currently installed version of Tor is out of date "
01583 "or no longer recommended."))
01584 + p(tr("Would you like to check if a newer package is "
01585 "available for installation?")),
01586 VMessageBox::Yes|VMessageBox::Default,
01587 VMessageBox::No|VMessageBox::Escape);
01588
01589 if (ret == VMessageBox::Yes)
01590 checkForUpdatesWithUi();
01591 #endif
01592 alreadyWarned = true;
01593 }
01594 }
01595
01596
01597
01598
01599
01600
01601
01602
01603 void
01604 MainWindow::warnDangerousPort(quint16 port, bool rejected)
01605 {
01606 static QMessageBox *dlg = 0;
01607
01608
01609 if (dlg)
01610 return;
01611
01612 QString application;
01613 switch (port) {
01614 case 23:
01615 application = tr(", probably Telnet, ");
01616 break;
01617
01618 case 109:
01619 case 110:
01620 case 143:
01621 application = tr(", probably an email client, ");
01622 break;
01623
01624 default:
01625 application = " ";
01626 }
01627
01628 QString text = tr("One of your applications%1appears to be making a "
01629 "potentially unencrypted and unsafe connection to port %2.")
01630 .arg(application).arg(port);
01631
01632 QString extraText = p(tr("Anything sent over this connection could be "
01633 "monitored. Please check your application's "
01634 "configuration and use only encrypted protocols, "
01635 "such as SSL, if possible."));
01636 if (rejected) {
01637 extraText.append(p(tr("Tor has automatically closed your connection in "
01638 "order to protect your anonymity.")));
01639 }
01640
01641 dlg = new QMessageBox(QMessageBox::Warning,
01642 tr("Potentially Unsafe Connection"), text,
01643 QMessageBox::Ok | QMessageBox::Ignore);
01644 dlg->setInformativeText(extraText);
01645 dlg->setDefaultButton(QMessageBox::Ok);
01646 dlg->setEscapeButton(QMessageBox::Ok);
01647
01648 int ret = dlg->exec();
01649 if (ret == QMessageBox::Ignore) {
01650 TorControl *tc = Vidalia::torControl();
01651 TorSettings settings;
01652 QStringList portList;
01653 QList<quint16> ports;
01654 int idx;
01655
01656 ports = settings.getWarnPlaintextPorts();
01657 idx = ports.indexOf(port);
01658 if (idx >= 0) {
01659 ports.removeAt(idx);
01660 settings.setWarnPlaintextPorts(ports);
01661
01662 foreach (quint16 port, ports) {
01663 portList << QString::number(port);
01664 }
01665 tc->setConf("WarnPlaintextPorts", portList.join(","));
01666 portList.clear();
01667 }
01668
01669 ports = settings.getRejectPlaintextPorts();
01670 idx = ports.indexOf(port);
01671 if (idx >= 0) {
01672 ports.removeAt(idx);
01673 settings.setRejectPlaintextPorts(ports);
01674
01675 foreach (quint16 port, ports) {
01676 portList << QString::number(port);
01677 }
01678 tc->setConf("RejectPlaintextPorts", portList.join(","));
01679 }
01680 }
01681 delete dlg;
01682 dlg = 0;
01683 }
01684
01685
01686 void
01687 MainWindow::showAboutDialog()
01688 {
01689 AboutDialog dlg(this);
01690 dlg.exec();
01691 }
01692
01693
01694
01695 void
01696 MainWindow::showHelpDialog()
01697 {
01698 showHelpDialog(QString());
01699 }
01700
01701
01702 void
01703 MainWindow::showHelpDialog(const QString &topic)
01704 {
01705 static HelpBrowser *helpBrowser = 0;
01706 if (!helpBrowser)
01707 helpBrowser = new HelpBrowser(this);
01708 helpBrowser->showWindow(topic);
01709 }
01710
01711
01712
01713 void
01714 MainWindow::showConfigDialog(ConfigDialog::Page page)
01715 {
01716 _configDialog->showWindow(page);
01717 }
01718
01719
01720 void
01721 MainWindow::showServerConfigDialog()
01722 {
01723 showConfigDialog(ConfigDialog::Server);
01724 }
01725
01726
01727 void
01728 MainWindow::newIdentity()
01729 {
01730 QString errmsg;
01731
01732
01733
01734
01735 if (_torControl->signal(TorSignal::NewNym, &errmsg)) {
01736
01737 QString title = tr("New Identity");
01738 QString message = tr("All subsequent connections will "
01739 "appear to be different than your "
01740 "old connections.");
01741
01742
01743 _actionNewIdentity->setEnabled(false);
01744 ui.lblNewIdentity->setEnabled(false);
01745 QTimer::singleShot(MIN_NEWIDENTITY_INTERVAL,
01746 this, SLOT(enableNewIdentity()));
01747
01748 if (QSystemTrayIcon::supportsMessages())
01749 _trayIcon.showMessage(title, message, QSystemTrayIcon::Information);
01750 else
01751 VMessageBox::information(this, title, message, VMessageBox::Ok);
01752 } else {
01753
01754 VMessageBox::warning(this,
01755 tr("Failed to Create New Identity"), errmsg, VMessageBox::Ok);
01756 }
01757 }
01758
01759
01760
01761 void
01762 MainWindow::enableNewIdentity()
01763 {
01764 if (_torControl->isConnected()) {
01765 _actionNewIdentity->setEnabled(true);
01766 ui.lblNewIdentity->setEnabled(true);
01767 }
01768 }
01769
01770
01771 QString
01772 MainWindow::toString(TorStatus status)
01773 {
01774 switch (status) {
01775
01776
01777 case Unset: return "Unset";
01778 case Stopping: return "Stopping";
01779 case Stopped: return "Stopped";
01780 case Starting: return "Starting";
01781 case Started: return "Started";
01782 case Authenticating: return "Authenticating";
01783 case Authenticated: return "Authenticated";
01784 case CircuitEstablished: return "Circuit Established";
01785 default: break;
01786 }
01787 return "Unknown";
01788 }
01789
01790 #if defined(USE_MINIUPNPC)
01791
01792 void
01793 MainWindow::upnpError(UPNPControl::UPNPError error)
01794 {
01795 Q_UNUSED(error);
01796
01797 #if 0
01798
01799
01800
01801
01802
01803 VMessageBox::warning(this,
01804 tr("Port Forwarding Failed"),
01805 p(tr("Vidalia was unable to configure automatic port forwarding."))
01806 + p(UPNPControl::Instance()->errorString()),
01807 VMessageBox::Ok);
01808 #endif
01809 }
01810 #endif
01811
01812 #if defined(USE_AUTOUPDATE)
01813
01814
01815 void
01816 MainWindow::checkForUpdatesWithUi()
01817 {
01818 checkForUpdates(true);
01819 }
01820
01821
01822
01823 void
01824 MainWindow::checkForUpdates(bool showProgress)
01825 {
01826 VidaliaSettings settings;
01827
01828 if (_updateProcess.isRunning()) {
01829 if (showProgress) {
01830
01831
01832
01833 _updateProgressDialog.show();
01834 }
01835 } else {
01836
01837 if (_torControl->isRunning() && _torControl->circuitEstablished())
01838 _updateProcess.setSocksPort(_torControl->getSocksPort());
01839 else
01840 _updateProcess.setSocksPort(0);
01841
01842
01843 _updateProgressDialog.setStatus(UpdateProgressDialog::CheckingForUpdates);
01844 if (showProgress)
01845 _updateProgressDialog.show();
01846
01847
01848
01849
01850
01851 _updateProcess.checkForUpdates(UpdateProcess::TorBundleInfo);
01852
01853
01854 settings.setLastCheckedForUpdates(QDateTime::currentDateTime().toUTC());
01855
01856
01857 _updateTimer.start(UpdateProcess::checkForUpdatesInterval() * 1000);
01858 }
01859 }
01860
01861
01862 void
01863 MainWindow::checkForUpdatesFailed(const QString &errmsg)
01864 {
01865 if (_updateProgressDialog.isVisible()) {
01866 _updateProgressDialog.hide();
01867 VMessageBox::warning(this, tr("Update Failed"), errmsg,
01868 VMessageBox::Ok);
01869 }
01870 }
01871
01872
01873 void
01874 MainWindow::updatesAvailable(UpdateProcess::BundleInfo bi,
01875 const PackageList &packageList)
01876 {
01877 vInfo("%1 software update(s) available").arg(packageList.size());
01878 if (packageList.size() > 0) {
01879 UpdatesAvailableDialog dlg(packageList, &_updateProgressDialog);
01880
01881 switch (dlg.exec()) {
01882 case UpdatesAvailableDialog::InstallUpdatesNow:
01883 installUpdates(bi);
01884 break;
01885
01886 default:
01887 _updateProgressDialog.hide();
01888 break;
01889 }
01890 } else {
01891 if (_updateProgressDialog.isVisible()) {
01892 _updateProgressDialog.hide();
01893 VMessageBox::information(this, tr("Your software is up to date"),
01894 tr("There are no new Tor software packages "
01895 "available for your computer at this time."),
01896 VMessageBox::Ok);
01897 }
01898 }
01899 }
01900
01901
01902
01903 void
01904 MainWindow::installUpdates(UpdateProcess::BundleInfo bi)
01905 {
01906 _updateProgressDialog.setStatus(UpdateProgressDialog::InstallingUpdates);
01907 _updateProgressDialog.show();
01908
01909 if (_isVidaliaRunningTor) {
01910 _restartTorAfterUpgrade = true;
01911 _isIntentionalExit = true;
01912 _torControl->stop();
01913 } else {
01914 _restartTorAfterUpgrade = false;
01915 }
01916 _updateProcess.installUpdates(bi);
01917 }
01918
01919
01920
01921 void
01922 MainWindow::updatesInstalled(int numUpdates)
01923 {
01924 _updateProgressDialog.setStatus(UpdateProgressDialog::UpdatesInstalled);
01925 _updateProgressDialog.show();
01926
01927 if (_restartTorAfterUpgrade)
01928 start();
01929 }
01930
01931
01932
01933 void
01934 MainWindow::installUpdatesFailed(const QString &errmsg)
01935 {
01936 _updateProgressDialog.hide();
01937
01938 VMessageBox::warning(this, tr("Installation Failed"),
01939 p(tr("Vidalia was unable to install your software updates."))
01940 + p(tr("The following error occurred:"))
01941 + p(errmsg),
01942 VMessageBox::Ok);
01943
01944 if (_restartTorAfterUpgrade)
01945 start();
01946 }
01947
01948 #endif
01949