[tor-commits] [vidalia/alpha] Improve the bootstrap procedure to play better with the async TorControl

chiiph at torproject.org chiiph at torproject.org
Thu Mar 15 14:15:55 UTC 2012


commit decef1ded8096ecdf15c3e2c140b315e09b4cc61
Author: Tomás Touceda <chiiph at torproject.org>
Date:   Thu Mar 15 11:10:46 2012 -0300

    Improve the bootstrap procedure to play better with the async TorControl
---
 src/torcontrol/ControlConnection.cpp |   42 +++---
 src/torcontrol/TorControl.cpp        |   89 ++++++++++-
 src/torcontrol/TorControl.h          |   45 ++++--
 src/torcontrol/TorProcess.cpp        |   28 ++--
 src/vidalia/MainWindow.cpp           |  295 +++++++++++++++++++++-------------
 src/vidalia/MainWindow.h             |   16 +-
 6 files changed, 345 insertions(+), 170 deletions(-)

diff --git a/src/torcontrol/ControlConnection.cpp b/src/torcontrol/ControlConnection.cpp
index 21cb527..af3d2d3 100644
--- a/src/torcontrol/ControlConnection.cpp
+++ b/src/torcontrol/ControlConnection.cpp
@@ -1,10 +1,10 @@
 /*
 **  This file is part of Vidalia, and is subject to the license terms in the
-**  LICENSE file, found in the top level directory of this distribution. If 
+**  LICENSE file, found in the top level directory of this distribution. If
 **  you did not receive the LICENSE file with this file, you may obtain it
 **  from the Vidalia source package distributed by the Vidalia Project at
-**  http://www.torproject.org/projects/vidalia.html. No part of Vidalia, 
-**  including this file, may be copied, modified, propagated, or distributed 
+**  http://www.torproject.org/projects/vidalia.html. No part of Vidalia,
+**  including this file, may be copied, modified, propagated, or distributed
 **  except according to the terms described in the LICENSE file.
 */
 
@@ -44,6 +44,9 @@ ControlConnection::~ControlConnection()
 {
   /* Clean up after the send waiter */
   delete _sendWaiter;
+  delete _sock;
+  delete _connectTimer;
+  _sock = 0;
 }
 
 /** Connect to the specified Tor control interface. */
@@ -75,7 +78,7 @@ ControlConnection::connect(const QString &addr)
               "control thread is already running.");
     return;
   }
-  
+
   _path = addr;
   _connectAttempt = 0;
   setStatus(Connecting);
@@ -92,7 +95,7 @@ ControlConnection::connect()
   _connectAttempt++;
   tc::debug("Connecting to Tor (Attempt %1 of %2)").arg(_connectAttempt)
                                                    .arg(MAX_CONNECT_ATTEMPTS);
-  
+
   switch(_method) {
     case ControlMethod::Socket:
       _sock->connectToServer(_path);
@@ -115,7 +118,7 @@ ControlConnection::disconnect()
 
   while (!_recvQueue.isEmpty()) {
     ReceiveWaiter *w = _recvQueue.dequeue();
-    w->setResult(false, ControlReply(), 
+    w->setResult(false, ControlReply(),
                  tr("Control socket is not connected."));
 
     QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
@@ -135,9 +138,6 @@ ControlConnection::disconnect()
   }
 
   _sock->disconnect(this);
-  delete _sock;
-  delete _connectTimer;
-  _sock = 0;
 }
 
 /** Called when the control socket is connected. This method checks that the
@@ -278,10 +278,10 @@ bool
 ControlConnection::send(const ControlCommand &cmd, QString *errmsg)
 {
   if (!_sock || !_sock->isConnected()) {
-    return err(errmsg, tr("Control socket is not connected.")); 
+    return err(errmsg, tr("Control socket is not connected."));
   }
   QCoreApplication::postEvent(_sock, new SendCommandEvent(cmd, _sendWaiter));
-  
+
   return _sendWaiter->getResult(errmsg);
 }
 
@@ -291,21 +291,21 @@ ControlConnection::onReadyRead()
 {
   ReceiveWaiter *waiter;
   QString errmsg;
- 
+
   while (_sock->canReadLine()) {
     ControlReply reply;
     if (_sock->readReply(reply, &errmsg)) {
       if (reply.getStatus() == "650") {
         /* Asynchronous event message */
         tc::debug("Control Event: %1").arg(reply.toString());
-        
+
         if (_events) {
           _events->handleEvent(reply);
         }
       } else {
         /* Response to a previous command */
         tc::debug("Control Reply: %1").arg(reply.toString());
-        
+
         if (!_recvQueue.isEmpty()) {
           waiter = _recvQueue.dequeue();
           waiter->setResult(true, reply);
@@ -327,14 +327,14 @@ ControlConnection::run()
 
   _connectTimer = new QTimer();
   _connectTimer->setSingleShot(true);
-  
+
   QObject::connect(_sock, SIGNAL(readyRead()), this, SLOT(onReadyRead()),
                    Qt::DirectConnection);
   QObject::connect(_sock, SIGNAL(disconnected()), this, SLOT(onDisconnected()),
                    Qt::DirectConnection);
   QObject::connect(_sock, SIGNAL(connected()), this, SLOT(onConnected()),
                    Qt::DirectConnection);
-  QObject::connect(_sock, SIGNAL(error(QAbstractSocket::SocketError)), 
+  QObject::connect(_sock, SIGNAL(error(QAbstractSocket::SocketError)),
                    this, SLOT(onError(QAbstractSocket::SocketError)),
                    Qt::DirectConnection);
   QObject::connect(_connectTimer, SIGNAL(timeout()), this, SLOT(connect()),
@@ -349,8 +349,8 @@ ControlConnection::run()
  * ControlConnection::ReceiveWaiter
  */
 /** Waits for and gets the reply from a control command. */
-bool 
-ControlConnection::ReceiveWaiter::getResult(ControlReply *reply, 
+bool
+ControlConnection::ReceiveWaiter::getResult(ControlReply *reply,
                                             QString *errmsg)
 {
   while(_status == Waiting)
@@ -364,9 +364,9 @@ ControlConnection::ReceiveWaiter::getResult(ControlReply *reply,
 }
 
 /** Sets the result and reply from a control command. */
-void 
-ControlConnection::ReceiveWaiter::setResult(bool success, 
-                                            const ControlReply &reply, 
+void
+ControlConnection::ReceiveWaiter::setResult(bool success,
+                                            const ControlReply &reply,
                                             const QString &errmsg)
 {
   _status = (success ? Success : Failed);
diff --git a/src/torcontrol/TorControl.cpp b/src/torcontrol/TorControl.cpp
index 9cdf6ad..0ad9db6 100644
--- a/src/torcontrol/TorControl.cpp
+++ b/src/torcontrol/TorControl.cpp
@@ -3,8 +3,8 @@
 **  LICENSE file, found in the top level directory of this distribution. If
 **  you did not receive the LICENSE file with this file, you may obtain it
 **  from the Vidalia source package distributed by the Vidalia Project at
-**  http://www.torproject.org/projects/vidalia.html. No part of Vidalia, 
-**  including this file, may be copied, modified, propagated, or distributed 
+**  http://www.torproject.org/projects/vidalia.html. No part of Vidalia,
+**  including this file, may be copied, modified, propagated, or distributed
 **  except according to the terms described in the LICENSE file.
 */
 
@@ -26,7 +26,7 @@
 
 /** Default constructor */
 TorControl::TorControl(ControlMethod::Method method)
-{
+  : QObject(), _shouldContinue(true), _reason("") {
 #define RELAY_SIGNAL(src, sig) \
   QObject::connect((src), (sig), this, (sig))
 
@@ -83,6 +83,12 @@ TorControl::TorControl(ControlMethod::Method method)
   QObject::connect(_torProcess, SIGNAL(log(QString, QString)),
                    this, SLOT(onLogStdout(QString, QString)));
 
+  QObject::connect(_torProcess, SIGNAL(startFailed(QString)),
+                   this, SLOT(torStartFailed(QString)));
+  QObject::connect(_controlConn, SIGNAL(connectFailed(QString)),
+                   this, SLOT(torConnectFailed(QString)));
+
+
 #if defined(Q_OS_WIN32)
   _torService = new TorService(this);
   RELAY_SIGNAL(_torService, SIGNAL(started()));
@@ -127,6 +133,33 @@ TorControl::start(const QString &tor, const QStringList &args)
   }
 }
 
+/** Returns true if the process is running */
+bool
+TorControl::torStarted()
+{
+  return _torProcess->state() == QProcess::Running;
+}
+
+/** Called when starting the tor process failed */
+void
+TorControl::torStartFailed(QString errmsg)
+{
+  _shouldContinue = false;
+  _reason = tr("Start failed: %1").arg(errmsg);
+}
+
+/** Returns true if the bootstrap should continue. If it returns
+ * false, it also sets the errmsg to the last error */
+bool
+TorControl::shouldContinue(QString *errmsg)
+{
+  if(not errmsg)
+    errmsg = new QString();
+
+  *errmsg = _reason;
+  return _shouldContinue;
+}
+
 /** Stop the Tor process. */
 bool
 TorControl::stop(QString *errmsg)
@@ -157,10 +190,26 @@ TorControl::onStopped(int exitCode, QProcess::ExitStatus exitStatus)
   if (_controlConn->status() == ControlConnection::Connecting)
     _controlConn->cancelConnect();
 
+  if (exitStatus == QProcess::CrashExit || exitCode != 0) {
+    _shouldContinue = false;
+    _reason = tr("Process finished: ExitCode=%1").arg(exitCode);
+  }
+
   emit stopped();
+  disconnect();
   emit stopped(exitCode, exitStatus);
 }
 
+/** Returns true if the tor process has finished, along with its exit
+ * code and status */
+bool
+TorControl::finished(int *exitCode, QProcess::ExitStatus *exitStatus)
+{
+  *exitCode = _torProcess->exitCode();
+  *exitStatus = _torProcess->exitStatus();
+  return _torProcess->state() == QProcess::NotRunning;
+}
+
 /** Detects if the Tor process is running under Vidalia. Returns true if
  * Vidalia owns the Tor process, or false if it was an independent Tor. */
 bool
@@ -209,6 +258,14 @@ TorControl::connect(const QString &path)
   _controlConn->connect(path);
 }
 
+/** Called when the connection to tor has failed */
+void
+TorControl::torConnectFailed(QString errmsg)
+{
+  _shouldContinue = false;
+  _reason = tr("Connection failed: %1").arg(errmsg);
+}
+
 /** Disconnect from Tor's control port */
 void
 TorControl::disconnect()
@@ -217,6 +274,7 @@ TorControl::disconnect()
     _controlConn->disconnect();
 }
 
+/** Emits the proper bootstrapStatusChanged */
 void
 TorControl::getBootstrapPhase()
 {
@@ -257,6 +315,9 @@ TorControl::onDisconnected()
   /* Tor isn't running, so it has no version */
   _torVersion = QString();
 
+  _shouldContinue = false;
+  _reason = tr("Disconnected");
+
   /* Let interested parties know we lost our control connection */
   emit disconnected();
 }
@@ -307,6 +368,9 @@ TorControl::authenticate(const QByteArray cookie, QString *errmsg)
 
   if (!send(cmd, reply, &str)) {
     emit authenticationFailed(str);
+    _shouldContinue = false;
+    _reason = str;
+
     return err(errmsg, str);
   }
   onAuthenticated();
@@ -326,6 +390,9 @@ TorControl::authenticate(const QString &password, QString *errmsg)
 
   if (!send(cmd, reply, &str)) {
     emit authenticationFailed(str);
+    _shouldContinue = false;
+    _reason = str;
+
     return err(errmsg, str);
   }
   onAuthenticated();
@@ -403,6 +470,7 @@ TorControl::useFeature(const QString &feature, QString *errmsg)
   return send(cmd, errmsg);
 }
 
+/** Returns the current BootstrapStatus */
 BootstrapStatus
 TorControl::bootstrapStatus(QString *errmsg)
 {
@@ -906,7 +974,7 @@ TorControl::loadConf(const QString &contents, QString *errmsg)
 {
   ControlCommand cmd("+LOADCONF");
   ControlReply reply;
-  
+
   cmd.addArgument(contents + ".");
   return send(cmd, reply, errmsg);
 }
@@ -963,6 +1031,7 @@ TorControl::resetConf(QString key, QString *errmsg)
   return resetConf(QStringList() << key, errmsg);
 }
 
+/** Returns true if microdescriptors are used */
 bool
 TorControl::useMicrodescriptors(QString *errmsg)
 {
@@ -1131,8 +1200,8 @@ TorControl::closeStream(const StreamId &streamId, QString *errmsg)
   return send(cmd, errmsg);
 }
 
- /** Gets a list of address mappings of the type specified by <b>type</b>
-  * (defaults to <i>AddressMapAll</i>. */
+/** Gets a list of address mappings of the type specified by <b>type</b>
+ * (defaults to <i>AddressMapAll</i>. */
 AddressMap
 TorControl::getAddressMap(AddressMap::AddressMapType type, QString *errmsg)
 {
@@ -1180,3 +1249,11 @@ TorControl::takeOwnership(QString *errmsg)
   ControlCommand cmd("TAKEOWNERSHIP");
   return send(cmd, errmsg);
 }
+
+/** Clear the error state for shouldContinue(errmsg) */
+void
+TorControl::clearErrState()
+{
+  _shouldContinue = true;
+  _reason = "";
+}
diff --git a/src/torcontrol/TorControl.h b/src/torcontrol/TorControl.h
index 96c7bd2..6432c83 100644
--- a/src/torcontrol/TorControl.h
+++ b/src/torcontrol/TorControl.h
@@ -1,14 +1,14 @@
 /*
 **  This file is part of Vidalia, and is subject to the license terms in the
-**  LICENSE file, found in the top level directory of this distribution. If 
+**  LICENSE file, found in the top level directory of this distribution. If
 **  you did not receive the LICENSE file with this file, you may obtain it
 **  from the Vidalia source package distributed by the Vidalia Project at
-**  http://www.torproject.org/projects/vidalia.html. No part of Vidalia, 
-**  including this file, may be copied, modified, propagated, or distributed 
+**  http://www.torproject.org/projects/vidalia.html. No part of Vidalia,
+**  including this file, may be copied, modified, propagated, or distributed
 **  except according to the terms described in the LICENSE file.
 */
 
-/* 
+/*
 ** \file TorControl.h
 ** \brief Object for interacting with the Tor process and control interface
 */
@@ -49,7 +49,7 @@ typedef QHash<QString,QString> DescriptorAnnotations;
 class TorControl : public QObject
 {
   Q_OBJECT
-  
+
 public:
   /** Default constructor */
   TorControl(ControlMethod::Method method = ControlMethod::Port);
@@ -58,6 +58,9 @@ public:
 
   /** Start the Tor process */
   void start(const QString &tor, const QStringList &args);
+  /** Returns true if the process is running */
+  bool torStarted();
+
   /** Stop the Tor process */
   bool stop(QString *errmsg = 0);
   /** Detect if the Tor process is running */
@@ -71,6 +74,7 @@ public:
   /** Connect to Tor's control socket */
   void connect(const QHostAddress &address, quint16 port);
   void connect(const QString &path);
+
   /** Disconnect from Tor's control socket */
   void disconnect();
   /** Check if we're connected to Tor's control socket */
@@ -79,14 +83,14 @@ public:
   bool authenticate(const QByteArray cookie, QString *errmsg = 0);
   /** Sends an authentication password to Tor. */
   bool authenticate(const QString &password = QString(), QString *errmsg = 0);
-  
+
   /** Sends a PROTOCOLINFO command to Tor and parses the response. */
   ProtocolInfo protocolInfo(QString *errmsg = 0);
 
   /** Returns the Tor software's current bootstrap phase and status. */
   BootstrapStatus bootstrapStatus(QString *errmsg = 0);
 
-  /** Returns true if Tor either has an open circuit or (on Tor >= 
+  /** Returns true if Tor either has an open circuit or (on Tor >=
    * 0.2.0.1-alpha) has previously decided it's able to establish a circuit. */
   bool isCircuitEstablished();
 
@@ -106,11 +110,11 @@ public:
 
   /** Sends a signal to Tor */
   bool signal(TorSignal::Signal sig, QString *errmsg = 0);
- 
+
   /** Returns an address on which Tor is listening for application
    * requests. If none are available, a null QHostAddress is returned. */
   QHostAddress getSocksAddress(QString *errmsg = 0);
-  /** Returns a (possibly empty) list of all currently configured 
+  /** Returns a (possibly empty) list of all currently configured
    * SocksListenAddress entries. */
   QStringList getSocksAddressList(QString *errmsg = 0);
   /** Returns a valid SOCKS port for Tor, or 0 if Tor is not accepting
@@ -162,7 +166,7 @@ public:
   /** Sends a GETCONF message to Tor with the single key and returns a QString
    * containing the value returned by Tor */
   QString getHiddenServiceConf(const QString &key, QString *errmsg = 0);
-  
+
   /** Asks Tor to save the current configuration to its torrc */
   bool saveConf(QString *errmsg = 0);
   /** Tells Tor to reset the given configuration keys back to defaults. */
@@ -200,7 +204,7 @@ public:
   CircuitList getCircuits(QString *errmsg = 0);
   /** Gets a list of current streams. */
   StreamList getStreams(QString *errmsg = 0);
-  
+
   /** Gets a list of address mappings of the type specified by <b>type</b>
    * (defaults to <i>AddressMapAll</i>. */
   AddressMap getAddressMap(
@@ -216,6 +220,15 @@ public:
   /** Takes ownership of the tor process it's communicating to */
   bool takeOwnership(QString *errmsg);
 
+  /** Clear the error state for shouldContinue(errmsg) */
+  void clearErrState();
+  /** Returns true if the bootstrap should continue. If it returns
+   * false, it also sets the errmsg to the last error */
+  bool shouldContinue(QString *errmsg = 0);
+  /** Returns true if the tor process has finished, along with its exit
+   * code and status */
+  bool finished(int *exitCode, QProcess::ExitStatus *exitStatus);
+
 public slots:
   /** Closes the circuit specified by <b>circId</b>. If <b>ifUnused</b> is
    * true, then the circuit will not be closed unless it is unused. */
@@ -313,7 +326,7 @@ signals:
 
   /** Emitted when Tor decides the client's external IP address has changed
    * to <b>ip</b>. If <b>hostname</b> is non-empty, Tor obtained the new
-   * value for <b>ip</b> by resolving <b>hostname</b>. 
+   * value for <b>ip</b> by resolving <b>hostname</b>.
    */
   void externalAddressChanged(const QHostAddress &ip, const QString &hostname);
 
@@ -338,7 +351,7 @@ signals:
    */
   void dnsUseless();
 
-  /** Indicates Tor has started testing the reachability of its OR port 
+  /** Indicates Tor has started testing the reachability of its OR port
    * using the IP address <b>ip</b> and port <b>port</b>.
    */
   void checkingOrPortReachability(const QHostAddress &ip, quint16 port);
@@ -396,6 +409,9 @@ private:
   TorService* _torService;
 #endif
 
+  bool _shouldContinue;
+  QString _reason;
+
   /** Send a message to Tor and read the response */
   bool send(ControlCommand cmd, ControlReply &reply, QString *errmsg = 0);
   /** Send a message to Tor and discard the response */
@@ -412,6 +428,9 @@ private slots:
   void onDisconnected();
   void onLogStdout(const QString &severity, const QString &message);
   void onAuthenticated();
+
+  void torStartFailed(QString errmsg);
+  void torConnectFailed(QString errmsg);
 };
 
 #endif
diff --git a/src/torcontrol/TorProcess.cpp b/src/torcontrol/TorProcess.cpp
index 7275f7a..84dfcb3 100644
--- a/src/torcontrol/TorProcess.cpp
+++ b/src/torcontrol/TorProcess.cpp
@@ -1,14 +1,14 @@
 /*
 **  This file is part of Vidalia, and is subject to the license terms in the
-**  LICENSE file, found in the top level directory of this distribution. If 
+**  LICENSE file, found in the top level directory of this distribution. If
 **  you did not receive the LICENSE file with this file, you may obtain it
 **  from the Vidalia source package distributed by the Vidalia Project at
-**  http://www.torproject.org/projects/vidalia.html. No part of Vidalia, 
-**  including this file, may be copied, modified, propagated, or distributed 
+**  http://www.torproject.org/projects/vidalia.html. No part of Vidalia,
+**  including this file, may be copied, modified, propagated, or distributed
 **  except according to the terms described in the LICENSE file.
 */
 
-/* 
+/*
 ** \file TorProcess.cpp
 ** \brief Starts and stops a Tor process
 */
@@ -31,9 +31,9 @@ TorProcess::TorProcess(QObject *parent)
 : QProcess(parent)
 {
   openStdout();
-  connect(this, SIGNAL(readyReadStandardOutput()), 
+  connect(this, SIGNAL(readyReadStandardOutput()),
           this,   SLOT(onReadyRead()));
-  connect(this, SIGNAL(error(QProcess::ProcessError)), 
+  connect(this, SIGNAL(error(QProcess::ProcessError)),
           this,   SLOT(onError(QProcess::ProcessError)));
 }
 
@@ -53,7 +53,7 @@ TorProcess::formatArguments(const QStringList &args)
  * signal started() will be emitted. If Tor fails to start,
  * startFailed(errmsg) will be emitted, with an appropriate error message. */
 void
-TorProcess::start(const QString &app, const QStringList &args) 
+TorProcess::start(const QString &app, const QStringList &args)
 {
   QString exe = app;
 #if defined(Q_OS_WIN32)
@@ -61,12 +61,12 @@ TorProcess::start(const QString &app, const QStringList &args)
    * quoted before being passed to it. */
   exe = "\"" + exe + "\"";
 #endif
-  
+
   /* Attempt to start Tor with the given command-line arguments */
   QStringList env = QProcess::systemEnvironment();
 #if !defined(Q_OS_WIN32)
   /* Add "/usr/sbin" to an existing $PATH
-   * XXX What if they have no path? Would always just making one with 
+   * XXX What if they have no path? Would always just making one with
    *     "/usr/sbin" smart? Should we add anything else? */
   for (int i = 0; i < env.size(); i++) {
     QString envVar = env.at(i);
@@ -93,7 +93,7 @@ TorProcess::stop(QString *errmsg)
   tc::debug("Stopping the Tor process.");
   /* Tell the process to stop */
 #if defined(Q_OS_WIN32)
-  /* Tor on Windows doesn't understand a WM_CLOSE message (which is what 
+  /* Tor on Windows doesn't understand a WM_CLOSE message (which is what
    * QProcess::terminate() sends it), so we have to kill it harshly. */
   kill();
 #else
@@ -103,7 +103,7 @@ TorProcess::stop(QString *errmsg)
   if (!waitForFinished(5000)) {
     tc::error("Tor failed to stop: %1").arg(errorString());
     if (errmsg) {
-      *errmsg = 
+      *errmsg =
         tr("Process %1 failed to stop. [%2]").arg(pid()).arg(errorString());
     }
     return false;
@@ -149,7 +149,7 @@ TorProcess::onReadyRead()
 {
   int i, j;
   QString line;
-  
+
   while (canReadLine()) {
     line = readLine();
     if (!line.isEmpty()) {
@@ -171,11 +171,11 @@ TorProcess::onError(QProcess::ProcessError error)
 {
   if (error == QProcess::FailedToStart) {
     tc::error("The Tor process failed to start: %1").arg(errorString());
-    /* Tor didn't start, so let everyone know why. */
-    emit startFailed(errorString());
   } else {
     tc::error("Tor process error: %1").arg(errorString());
   }
+  /* Tor didn't start, so let everyone know why. */
+  emit startFailed(errorString());
 }
 
 /** Returns the version reported by the Tor executable specified in
diff --git a/src/vidalia/MainWindow.cpp b/src/vidalia/MainWindow.cpp
index 4307f05..0861b0c 100644
--- a/src/vidalia/MainWindow.cpp
+++ b/src/vidalia/MainWindow.cpp
@@ -3,8 +3,8 @@
 **  LICENSE file, found in the top level directory of this distribution. If you
 **  did not receive the LICENSE file with this file, you may obtain it from the
 **  Vidalia source package distributed by the Vidalia Project at
-**  http://www.torproject.org/projects/vidalia.html. No part of Vidalia, 
-**  including this file, may be copied, modified, propagated, or distributed 
+**  http://www.torproject.org/projects/vidalia.html. No part of Vidalia,
+**  including this file, may be copied, modified, propagated, or distributed
 **  except according to the terms described in the LICENSE file.
 */
 
@@ -105,10 +105,12 @@ void qt_mac_set_dock_menu(QMenu *menu);
 MainWindow::MainWindow()
 : VidaliaWindow("MainWindow")
 {
+  _pressedStop = false;
+
   _startedWithPrevious = false;
 
   /* Create a new TorControl object, used to communicate with Tor */
-  _torControl = Vidalia::torControl(); 
+  _torControl = Vidalia::torControl();
 
   _engine = new PluginEngine();
 
@@ -239,9 +241,9 @@ MainWindow::createToolBar()
   tool->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
 }
 
-/** Creates a QMenu object that contains QActions which compose the system 
+/** Creates a QMenu object that contains QActions which compose the system
  * tray menu. */
-QMenu* 
+QMenu*
 MainWindow::createTrayMenu()
 {
   QMenu *menu = new QMenu(this);
@@ -255,7 +257,7 @@ MainWindow::createTrayMenu()
   menu->addAction(_actionShowControlPanel);
 
   menu->addMenu(&_reattachMenu);
-  
+
 #if !defined(Q_WS_MAC)
   /* These aren't added to the dock menu on Mac, since they are in the
    * standard Mac locations in the menu bar. */
@@ -398,18 +400,6 @@ MainWindow::createConnections()
   connect(vApp, SIGNAL(running()), this, SLOT(running()));
   connect(vApp, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit()));
 
-  connect(_torControl, SIGNAL(started()), this, SLOT(started()));
-  connect(_torControl, SIGNAL(startFailed(QString)),
-          this, SLOT(startFailed(QString)));
-  connect(_torControl, SIGNAL(stopped(int, QProcess::ExitStatus)),
-          this, SLOT(stopped(int, QProcess::ExitStatus)));
-  connect(_torControl, SIGNAL(connected()), this, SLOT(connected()));
-  connect(_torControl, SIGNAL(disconnected()), this, SLOT(disconnected()));
-  connect(_torControl, SIGNAL(connectFailed(QString)), 
-          this, SLOT(connectFailed(QString)));
-  connect(_torControl, SIGNAL(authenticated()), this, SLOT(authenticated()));
-  connect(_torControl, SIGNAL(authenticationFailed(QString)),
-          this, SLOT(authenticationFailed(QString)));
   connect(_torControl, SIGNAL(clockSkewed(int, QString)),
           this, SLOT(clockSkewed(int, QString)));
 
@@ -422,8 +412,6 @@ MainWindow::createConnections()
   _torControl->setEvent(TorEvents::ClientStatus);
   connect(_torControl, SIGNAL(bootstrapStatusChanged(BootstrapStatus)),
           this, SLOT(bootstrapStatusChanged(BootstrapStatus)));
-  connect(_torControl, SIGNAL(circuitEstablished()),
-          this, SLOT(circuitEstablished()));
   connect(_torControl, SIGNAL(dangerousPort(quint16, bool)),
           this, SLOT(warnDangerousPort(quint16, bool)));
 
@@ -458,7 +446,7 @@ MainWindow::createConnections()
           this, SLOT(upnpError(UPNPControl::UPNPError)));
 #endif
 
-  connect(_engine, SIGNAL(pluginTab(VidaliaTab *)), 
+  connect(_engine, SIGNAL(pluginTab(VidaliaTab *)),
           this, SLOT(addTab(VidaliaTab *)));
 }
 
@@ -468,16 +456,17 @@ MainWindow::createConnections()
 void
 MainWindow::close()
 {
+  _pressedStop = true;
+  QCoreApplication::processEvents();
+
   if (_torControl->isVidaliaRunningTor()) {
     /* If we're running a server currently, ask if we want to do a delayed
      * shutdown. If we do, then close Vidalia only when Tor stops. Otherwise,
      * kill Tor and bail now. */
     ServerSettings settings(_torControl);
     if (_torControl->isConnected() && settings.isServerEnabled()) {
-      connect(_torControl, SIGNAL(stopped()), vApp, SLOT(quit()));
-      if (!stop())
-        QObject::disconnect(_torControl, SIGNAL(stopped()), vApp, SLOT(quit()));
-      return;
+      if(!stop())
+        return;
     }
   }
   vApp->quit();
@@ -545,7 +534,7 @@ MainWindow::aboutToQuit()
   vNotice("Cleaning up before exiting.");
 
   if (_torControl->isVidaliaRunningTor()) {
-    /* Kill our Tor process now */ 
+    /* Kill our Tor process now */
     _torControl->stop();
   }
 
@@ -559,12 +548,14 @@ MainWindow::aboutToQuit()
 
 /** Attempts to start Tor. If Tor fails to start, then startFailed() will be
  * called with an error message containing the reason. */
-void 
+void
 MainWindow::start()
 {
   TorSettings settings;
   QStringList args;
 
+  _torControl->clearErrState();
+
   updateTorStatus(Starting);
 
   // Disable autoconfiguration if there are missing config data
@@ -579,12 +570,12 @@ MainWindow::start()
   if(settings.getControlMethod() == ControlMethod::Port) {
     if(!settings.autoControlPort() && net_test_connect(settings.getControlAddress(),
                                                        settings.getControlPort())) {
-      started();
+      connectToTor();
       return;
     }
   } else {
     if (socket_test_connect(settings.getSocketPath())) {
-      started();
+      connectToTor();
       return;
     }
   }
@@ -602,7 +593,7 @@ MainWindow::start()
       }
     }
   }
-  
+
   if(_torControl->getTorVersion() >= 0x020309) {
     if (!torrc_defaults.isEmpty()) {
       args << "--defaults-torrc" << torrc_defaults;
@@ -619,7 +610,7 @@ MainWindow::start()
   /* Specify Tor's data directory, if different from the default */
   QString dataDirectory = settings.getDataDirectory();
   QString expDataDirectory = expand_filename(dataDirectory);
-  
+
   if(settings.getControlMethod() == ControlMethod::Port) {
     if(settings.autoControlPort()) {
       QString portconf = QString("%1/port.conf").arg(expDataDirectory);
@@ -637,8 +628,9 @@ MainWindow::start()
     }
   }
 
-  args << "__OwningControllerProcess" << QString::number(QCoreApplication::applicationPid());
-  
+  if (_torControl->getTorVersion() < 0x02021c)
+    args << "__OwningControllerProcess" << QString::number(QCoreApplication::applicationPid());
+
   /* Add the control port authentication arguments */
   switch (settings.getAuthenticationMethod()) {
     case TorSettings::PasswordAuth:
@@ -664,15 +656,36 @@ MainWindow::start()
   _isIntentionalExit = true;
   /* Kick off the Tor process */
   _torControl->start(settings.getExecutable(), args);
+
+  QString errmsg;
+  while(not _torControl->torStarted()) {
+    QCoreApplication::processEvents();
+    if(not _torControl->shouldContinue(&errmsg) and not _pressedStop) {
+      startFailed(errmsg);
+
+      int exitCode;
+      QProcess::ExitStatus exitStatus;
+
+      if(_torControl->finished(&exitCode, &exitStatus))
+         stopped(exitCode, exitStatus);
+
+      return;
+    } else if(_pressedStop) {
+      return;
+    }
+  }
+  connectToTor();
 }
 
 /** Slot: Called when the Tor process is started. It will connect the control
  * socket and set the icons and tooltips accordingly. */
-void 
-MainWindow::started()
+void
+MainWindow::connectToTor()
 {
   TorSettings settings;
 
+  _torControl->clearErrState();
+
   updateTorStatus(Started);
 
   /* Now that Tor is running, we want to know if it dies when we didn't want
@@ -741,6 +754,26 @@ MainWindow::started()
     Vidalia::torrc()->apply(Vidalia::torControl());
   }
   setStartupProgress(STARTUP_PROGRESS_CONNECTING, tr("Connecting to Tor"));
+
+  QString errmsg;
+  while(not _torControl->isConnected()) {
+    QCoreApplication::processEvents();
+    if(not _torControl->shouldContinue(&errmsg) and not _pressedStop) {
+      connectFailed(errmsg);
+
+      int exitCode;
+      QProcess::ExitStatus exitStatus;
+
+      if(_torControl->finished(&exitCode, &exitStatus))
+         stopped(exitCode, exitStatus);
+
+      return;
+    } else if(_pressedStop) {
+      return;
+    }
+  }
+
+  authenticate();
 }
 
 /** Disconnects the control socket and stops the Tor process. */
@@ -753,6 +786,9 @@ MainWindow::stop()
   bool rc;
   VidaliaSettings settings;
 
+  _pressedStop = true;
+  QCoreApplication::processEvents();
+
   /* If we're running a server, give users the option of terminating
    * gracefully so clients have time to find new servers. */
   if (server.isServerEnabled() && !_delayedShutdownStarted) {
@@ -765,8 +801,8 @@ MainWindow::stop()
                         "open connections from clients.\n\n"
                         "Would you like to shutdown gracefully and "
                         "give clients time to find a new relay?"),
-                        VMessageBox::Yes|VMessageBox::Default, 
-                        VMessageBox::No, 
+                        VMessageBox::Yes|VMessageBox::Default,
+                        VMessageBox::No,
                         VMessageBox::Cancel|VMessageBox::Escape,
                         "Remember this answer", &settings, SETTING_REMEMBER_SHUTDOWN);
     }
@@ -775,8 +811,8 @@ MainWindow::stop()
     else if (response == VMessageBox::Cancel)
       return false;
   }
-  
-  prevStatus = updateTorStatus(Stopping);  
+
+  prevStatus = updateTorStatus(Stopping);
   if (_delayedShutdownStarted) {
     /* Start a delayed shutdown */
     rc = _torControl->signal(TorSignal::Shutdown, &errmsg);
@@ -785,15 +821,22 @@ MainWindow::stop()
     _isIntentionalExit = true;
     rc = _torControl->stop(&errmsg);
   }
-  
+
+  int exitCode;
+  QProcess::ExitStatus exitStatus;
+
+  while(not _torControl->finished(&exitCode, &exitStatus)) {
+    QCoreApplication::processEvents();
+  }
+
   if (!rc) {
     /* We couldn't tell Tor to stop, for some reason. */
     int response = VMessageBox::warning(this, tr("Error Shutting Down"),
-                     p(tr("Vidalia was unable to stop the Tor software.")) 
+                     p(tr("Vidalia was unable to stop the Tor software."))
                        + p(errmsg),
-                     VMessageBox::Ok|VMessageBox::Default|VMessageBox::Escape, 
+                     VMessageBox::Ok|VMessageBox::Default|VMessageBox::Escape,
                      VMessageBox::Help);
-      
+
     if (response == VMessageBox::Help) {
       /* Show some troubleshooting help */
       showHelpDialog("troubleshooting.stop");
@@ -803,12 +846,17 @@ MainWindow::stop()
     _delayedShutdownStarted = false;
     updateTorStatus(prevStatus);
   }
+
+  stopped(exitCode, exitStatus);
+
+  _pressedStop = false;
+
   return rc;
 }
 
 /** Slot: Called when the Tor process has exited. It will adjust the tray
  * icons and tooltips accordingly. */
-void 
+void
 MainWindow::stopped(int exitCode, QProcess::ExitStatus exitStatus)
 {
   updateTorStatus(Stopped);
@@ -825,7 +873,7 @@ MainWindow::stopped(int exitCode, QProcess::ExitStatus exitStatus)
                      "unexpectedly.\n\n"
                      "Please check the message log for recent "
                      "warning or error messages."),
-                  VMessageBox::Ok|VMessageBox::Escape, 
+                  VMessageBox::Ok|VMessageBox::Escape,
                   VMessageBox::ShowLog|VMessageBox::Default,
                   VMessageBox::Help);
       if (ret == VMessageBox::ShowLog)
@@ -834,6 +882,9 @@ MainWindow::stopped(int exitCode, QProcess::ExitStatus exitStatus)
         showHelpDialog("troubleshooting.torexited");
     }
   }
+  QObject::disconnect(_torControl, SIGNAL(stopped(int, QProcess::ExitStatus)),
+          this, SLOT(stopped(int, QProcess::ExitStatus)));
+  QObject::disconnect(_torControl, SIGNAL(disconnected()), this, SLOT(disconnected()));
 }
 
 /** Called when the Tor process fails to start, for example, because the path
@@ -857,7 +908,7 @@ MainWindow::startFailed(QString errmsg)
     start();
     return;
   }
- 
+
   updateTorStatus(Stopped);
 
   /* Display an error message and see if the user wants some help */
@@ -879,22 +930,15 @@ MainWindow::startFailed(QString errmsg)
   }
 }
 
-/** Called when the control socket has successfully connected to Tor. */
-void
-MainWindow::connected()
-{
-  authenticate();
-}
-
 /** Called when the connection to the control socket fails. The reason will be
  * given in the errmsg parameter. */
 void
 MainWindow::connectFailed(QString errmsg)
 {
   /* Ok, ok. It really isn't going to connect. I give up. */
-  int response = VMessageBox::warning(this, 
+  int response = VMessageBox::warning(this,
                    tr("Connection Error"), p(errmsg),
-                   VMessageBox::Ok|VMessageBox::Default|VMessageBox::Escape, 
+                   VMessageBox::Ok|VMessageBox::Default|VMessageBox::Escape,
                    VMessageBox::Retry, VMessageBox::Help);
 
 
@@ -917,6 +961,9 @@ void
 MainWindow::authenticated()
 {
   TorSettings settings;
+
+  _torControl->clearErrState();
+
   if(settings.autoControlPort()) {
     // We want to remember the ports if it's on auto
     QString control_str = "", socks_str = "";
@@ -930,7 +977,7 @@ MainWindow::authenticated()
       if(socks_parts.size() > 1)
         socks_str = socks_parts[1];
     }
-    
+
     _previousControlPort = control_str;
     _previousSocksPort = socks_str;
   } else {
@@ -943,14 +990,14 @@ MainWindow::authenticated()
   QString errmsg;
 
   updateTorStatus(Authenticated);
-  
+
   /* If Tor doesn't have bootstrapping events, then update the current
    * status string and bump the progress bar along a bit. */
   if (_torControl->getTorVersion() < 0x020101) {
     setStartupProgress(STARTUP_PROGRESS_CIRCUITBUILD,
                        tr("Connecting to the Tor network"));
   }
-  
+
   /* Let people click on their beloved "New Circuit" button */
   _actionNewIdentity->setEnabled(true);
 
@@ -970,10 +1017,6 @@ MainWindow::authenticated()
   /* Configure UPnP port forwarding if needed */
   serverSettings.configurePortForwarding();
 
-  /* Check if Tor has a circuit established */
-  if (_torControl->isCircuitEstablished()) {
-    circuitEstablished();
-  }
   /* Check the status of Tor's version */
   if (_torControl->getTorVersion() >= 0x020001)
     checkTorVersion();
@@ -982,6 +1025,25 @@ MainWindow::authenticated()
     if (status.isValid())
       bootstrapStatusChanged(status);
   }
+
+  /* Check if Tor has a circuit established */
+  while(not _torControl->isCircuitEstablished()) {
+    QCoreApplication::processEvents();
+    if(not _torControl->shouldContinue(&errmsg) and not _pressedStop) {
+      startFailed(errmsg);
+
+      int exitCode;
+      QProcess::ExitStatus exitStatus;
+
+      if(_torControl->finished(&exitCode, &exitStatus))
+         stopped(exitCode, exitStatus);
+      return;
+    } else if(_pressedStop) {
+      return;
+    }
+  }
+
+  circuitEstablished();
 }
 
 /** Called when Vidalia fails to authenticate to Tor. The failure reason is
@@ -990,7 +1052,7 @@ void
 MainWindow::authenticationFailed(QString errmsg)
 {
   bool retry = false;
-  
+
   vWarn("Authentication failed: %1").arg(errmsg);
 
   /* Parsing log messages is evil, but we're left with little option */
@@ -1009,7 +1071,7 @@ MainWindow::authenticationFailed(QString errmsg)
         break;
       }
     }
-    
+
     dlg.setResetEnabled(torPid > 0);
 
     int ret = dlg.exec();
@@ -1026,9 +1088,9 @@ MainWindow::authenticationFailed(QString errmsg)
       }
     }
   }
-  
+
   if (_torControl->isRunning())
-    if (_isVidaliaRunningTor) 
+    if (_isVidaliaRunningTor)
       stop();
     else
       disconnect();
@@ -1093,7 +1155,7 @@ void
 MainWindow::bootstrapStatusChanged(const BootstrapStatus &bs)
 {
   int percentComplete = STARTUP_PROGRESS_BOOTSTRAPPING + bs.percentComplete();
-  bool warn = (bs.severity() == tc::WarnSeverity && 
+  bool warn = (bs.severity() == tc::WarnSeverity &&
                bs.recommendedAction() != BootstrapStatus::RecommendIgnore);
 
   QString description;
@@ -1190,6 +1252,9 @@ MainWindow::circuitEstablished()
     }
   }
 #endif
+  connect(_torControl, SIGNAL(stopped(int, QProcess::ExitStatus)),
+          this, SLOT(stopped(int, QProcess::ExitStatus)));
+  connect(_torControl, SIGNAL(disconnected()), this, SLOT(disconnected()));
 }
 
 /** Called when Tor thinks the user has tried to connect to a port that
@@ -1217,7 +1282,7 @@ MainWindow::warnDangerousPort(quint16 port, bool rejected)
     case 109:
     case 110:
     case 143:
-      application = tr("(probably an email client)"); 
+      application = tr("(probably an email client)");
       break;
 
     default:
@@ -1284,18 +1349,20 @@ MainWindow::warnDangerousPort(quint16 port, bool rejected)
 /** Attempts to authenticate to Tor's control port, depending on the
  * authentication method specified in TorSettings::getAuthenticationMethod().
  */
-bool
+void
 MainWindow::authenticate()
 {
   TorSettings::AuthenticationMethod authMethod;
   TorSettings settings;
   ProtocolInfo pi;
-  
+
+  _torControl->clearErrState();
+
   updateTorStatus(Authenticating);
   setStartupProgress(STARTUP_PROGRESS_AUTHENTICATING,
                      tr("Authenticating to Tor"));
 
-  authMethod = settings.getAuthenticationMethod(); 
+  authMethod = settings.getAuthenticationMethod();
   pi = _torControl->protocolInfo();
   QStringList authMethods;
   if (!pi.isEmpty()) {
@@ -1308,30 +1375,40 @@ MainWindow::authenticate()
       authMethod = TorSettings::NullAuth;
   }
 
+  QString errmsg;
+
   if (authMethod == TorSettings::CookieAuth) {
-    if(!tryCookie(pi)) {
-      if(authMethods.contains("HASHEDPASSWORD") and !tryHashed()) {
-        goto cancel;
-      } else {
-        return true;
-      }
+    if(tryCookie(pi)) {
+      authenticated();
+      return;
     } else {
-      return true;
+      if(authMethods.contains("HASHEDPASSWORD")) {
+        if(tryHashed()) {
+          authenticated();
+          return;
+        }
+      }
+      _torControl->shouldContinue(&errmsg);
+      authenticationFailed(errmsg);
+      return;
     }
   } else if (authMethod == TorSettings::PasswordAuth) {
-    return tryHashed();
+    if(tryHashed()) {
+      authenticated();
+      return;
+    }
+    _torControl->shouldContinue(&errmsg);
+    authenticationFailed(errmsg);
+    return;
   }
   /* No authentication. Send an empty password. */
   vNotice("Authenticating using 'null' authentication.");
-  return _torControl->authenticate(QString(""));
-
-cancel:
-  vWarn("Cancelling control authentication attempt.");
-  if (_isVidaliaRunningTor)
-    stop();
-  else
-    disconnect();
-  return false;
+  if(_torControl->authenticate(QString("")))
+    authenticated();
+  else {
+    _torControl->shouldContinue(&errmsg);
+    authenticationFailed(errmsg);
+  }
 }
 
 bool
@@ -1351,7 +1428,7 @@ MainWindow::tryCookie(const ProtocolInfo &pi)
                                            "'control_auth_cookie' yourself?")),
                                     VMessageBox::Browse|VMessageBox::Default,
                                     VMessageBox::Cancel|VMessageBox::Escape);
-      
+
     if (ret == VMessageBox::Cancel)
       return false;
     QString cookieDir = QFileDialog::getOpenFileName(this,
@@ -1425,14 +1502,14 @@ MainWindow::loadControlCookie(QString cookiePath)
     QString dataDir = settings.getDataDirectory();
     if (!dataDir.isEmpty())
       pathList << dataDir;
-      
+
 #if defined(Q_WS_WIN)
     pathList << expand_filename("%APPDATA%\\Tor");
 #else
     pathList << expand_filename("~/.tor");
 #endif
   }
-  
+
   /* Search for the cookie file */
   foreach (QString path, pathList) {
     QString cookieFile = QFileInfo(path).isFile() ?
@@ -1440,7 +1517,7 @@ MainWindow::loadControlCookie(QString cookiePath)
     vDebug("Checking for authentication cookie in '%1'").arg(cookieFile);
     if (!QFileInfo(cookieFile).exists())
       continue;
-    
+
     authCookie.setFileName(cookieFile);
     if (authCookie.open(QIODevice::ReadOnly)) {
       vInfo("Reading authentication cookie from '%1'").arg(cookieFile);
@@ -1462,7 +1539,7 @@ MainWindow::updateTorStatus(TorStatus status)
   QString statusText, actionText;
   QString trayIconFile, statusIconFile;
   TorStatus prevStatus = _status;
- 
+
   vNotice("Tor status changed from '%1' to '%2'.")
     .arg(toString(prevStatus)).arg(toString(status));
   _status = status;
@@ -1488,14 +1565,14 @@ MainWindow::updateTorStatus(TorStatus status)
       _actionRestartTor->setEnabled(false);
       _actionReloadConfig->setEnabled(false);
       if (_delayedShutdownStarted) {
-        statusText = tr("Your relay is shutting down.\n" 
+        statusText = tr("Your relay is shutting down.\n"
                         "Click 'Stop' again to stop your relay now.");
       } else {
         statusText = tr("Tor is shutting down");
       }
       trayIconFile = IMG_TOR_STOPPING;
       statusIconFile = IMG_TOR_STOPPING_48;
-      
+
   } else if (status == Started) {
       actionText = tr("Stop Tor");
       _actionRestartTor->setEnabled(true);
@@ -1503,7 +1580,7 @@ MainWindow::updateTorStatus(TorStatus status)
       _actionStartStopTor->setEnabled(true);
       _actionStartStopTor->setIcon(QIcon(IMG_STOP_TOR_16));
       _actionStartStopTor->setText(actionText);
-            
+
       /* XXX: This might need to be smarter if we ever start connecting other
        * slots to these triggered() and clicked() signals. */
       QObject::disconnect(_actionStartStopTor, SIGNAL(triggered()), this, 0);
@@ -1594,7 +1671,7 @@ MainWindow::sighup()
 
   if (!rc) {
     int response = VMessageBox::warning(this, tr("Error reloading configuration"),
-                     p(tr("Vidalia was unable to reload Tor's configuration.")) 
+                     p(tr("Vidalia was unable to reload Tor's configuration."))
                        + p(errmsg),
                      VMessageBox::Ok);
   }
@@ -1635,7 +1712,7 @@ MainWindow::disconnected()
      * connection as "Tor is stopped". */
     updateTorStatus(Stopped);
   }
-  
+
   /*XXX We should warn here if we get disconnected when we didn't intend to */
   _actionNewIdentity->setEnabled(false);
   _isVidaliaRunningTor = false;
@@ -1659,7 +1736,7 @@ MainWindow::newIdentity()
   QString errmsg;
 
   /* Send the NEWNYM signal. If message balloons are supported and the NEWNYM
-   * is successful, we will show the result as a balloon. Otherwise, we'll 
+   * is successful, we will show the result as a balloon. Otherwise, we'll
    * just use a message box. */
   if (_torControl->signal(TorSignal::NewNym, &errmsg)) {
     /* NEWNYM signal was successful */
@@ -1670,7 +1747,7 @@ MainWindow::newIdentity()
 
     /* Disable the New Identity button for MIN_NEWIDENTITY_INTERVAL */
     _actionNewIdentity->setEnabled(false);
-    QTimer::singleShot(MIN_NEWIDENTITY_INTERVAL, 
+    QTimer::singleShot(MIN_NEWIDENTITY_INTERVAL,
                        this, SLOT(enableNewIdentity()));
 
     if (QSystemTrayIcon::supportsMessages())
@@ -1679,7 +1756,7 @@ MainWindow::newIdentity()
       VMessageBox::information(this, title, message, VMessageBox::Ok);
   } else {
     /* NEWNYM signal failed */
-    VMessageBox::warning(this, 
+    VMessageBox::warning(this,
       tr("Failed to Create New Identity"), errmsg, VMessageBox::Ok);
   }
 }
@@ -1788,8 +1865,8 @@ MainWindow::addTab(VidaliaTab *tab)
       return;
 
     /** Exception for tabs that need to be always created */
-    if (tab != _messageLog && 
-        tab != &_statusTab && 
+    if (tab != _messageLog &&
+        tab != &_statusTab &&
         tab != &_netViewer &&
         tab != _graph)
       tab->deleteLater();
@@ -1832,8 +1909,8 @@ MainWindow::delTab(int index)
 
   VidaliaTab *tab = qobject_cast<VidaliaTab*>(ui.tabWidget->widget(index));
   // if it isn't one of the tabs that's supposed to be open at every moment
-  if (tab != _messageLog && 
-      tab != &_statusTab && 
+  if (tab != _messageLog &&
+      tab != &_statusTab &&
       tab != &_netViewer &&
       tab != _graph) {
     QObject::disconnect(ui.tabWidget->widget(index), 0, 0, 0);
@@ -1850,13 +1927,13 @@ MainWindow::showStatusTab()
   addTab(&_statusTab);
 }
 
-void 
+void
 MainWindow::showMessageLogTab()
 {
   addTab(_messageLog);
 }
 
-void 
+void
 MainWindow::showBandwidthTab()
 {
   addTab(_graph);
@@ -1888,7 +1965,7 @@ MainWindow::showHelpDialog(const QString &topic)
   helpBrowser->showWindow(topic);
 }
 
-void 
+void
 MainWindow::showNetViewerTab()
 {
   addTab(&_netViewer);
@@ -2051,7 +2128,7 @@ MainWindow::installUpdatesFailed(const QString &errmsg)
 
   VMessageBox::warning(this, tr("Installation Failed"),
                        p(tr("Vidalia was unable to install your software updates."))
-                         + p(tr("The following error occurred:")) 
+                         + p(tr("The following error occurred:"))
                          + p(errmsg),
                        VMessageBox::Ok);
 
diff --git a/src/vidalia/MainWindow.h b/src/vidalia/MainWindow.h
index 7cd86d7..6e60bb7 100644
--- a/src/vidalia/MainWindow.h
+++ b/src/vidalia/MainWindow.h
@@ -3,8 +3,8 @@
 **  LICENSE file, found in the top level directory of this distribution. If you
 **  did not receive the LICENSE file with this file, you may obtain it from the
 **  Vidalia source package distributed by the Vidalia Project at
-**  http://www.torproject.org/projects/vidalia.html. No part of Vidalia, 
-**  including this file, may be copied, modified, propagated, or distributed 
+**  http://www.torproject.org/projects/vidalia.html. No part of Vidalia,
+**  including this file, may be copied, modified, propagated, or distributed
 **  except according to the terms described in the LICENSE file.
 */
 
@@ -73,13 +73,13 @@ private slots:
   /** Called when the Tor process fails to start. */
   void startFailed(QString errmsg);
   /** Called when the Tor process has successfully started. */
-  void started();
+  void connectToTor();
   /** Called when the user selects "Stop" form the menu. */
   bool stop();
   /** Called when the Tor process has exited, either expectedly or not. */
   void stopped(int errorCode, QProcess::ExitStatus exitStatus);
   /** Called when the control socket has connected to Tor. */
-  void connected();
+  //void connected();
   /** Called when the control connection fails. */
   void connectFailed(QString errmsg);
   /** Called when Vidalia wants to disconnect from a Tor it did not start. */
@@ -145,7 +145,7 @@ private slots:
 
   /** Displays the debug output dialog for plugins */
   void showDebugDialog();
-  
+
   /** Adds a new tab to the MainWindow */
   void addTab(VidaliaTab *tab);
   /** Deletes the tab at index if it exists and it isn't the Status tab */
@@ -224,7 +224,7 @@ private:
   /** Converts a TorStatus enum value to a string for debug logging purposes. */
   QString toString(TorStatus status);
   /** Authenticates Vidalia to Tor's control port. */
-  bool authenticate();
+  void authenticate();
   /** Searches for and attempts to load the control authentication cookie.
    * This assumes the cookie is named 'control_auth_cookie'. If
    * <b>cookiePath</b> is empty, this method will search some default locations
@@ -305,10 +305,12 @@ private:
   PluginEngine *_engine;
   QStringList _tabMap; /**< Map to handle opened tabs */
   QStringList _detachedTabMap; /**< Map to handle detached tabs */
-  
+
   bool _startedWithPrevious; /**< True if Vidalia tried to start Tor with the previous ports */
   QString _previousControlPort; /**< Holds the previous controlport used */
   QString _previousSocksPort; /**< Holds the previous socksport used */
+
+  bool _pressedStop; /**< True if the user has pressed the Stop Tor button */
 };
 
 #endif





More information about the tor-commits mailing list