[tor-commits] [vidalia/alpha] Adds the helperprocess part

chiiph at torproject.org chiiph at torproject.org
Tue May 3 14:21:32 UTC 2011


commit 25950fa9ceeb6ce44924fb607b54691601adb66c
Author: Tomas Touceda <chiiph at gentoo.org>
Date:   Fri Apr 8 20:26:20 2011 -0300

    Adds the helperprocess part
---
 src/vidalia/CMakeLists.txt |    2 +
 src/vidalia/MainWindow.cpp |  236 ++++++++++++++++++++++++++++++++++++++++++++
 src/vidalia/MainWindow.h   |   27 +++++
 3 files changed, 265 insertions(+), 0 deletions(-)

diff --git a/src/vidalia/CMakeLists.txt b/src/vidalia/CMakeLists.txt
index c9803e9..22a869f 100644
--- a/src/vidalia/CMakeLists.txt
+++ b/src/vidalia/CMakeLists.txt
@@ -163,6 +163,7 @@ set(vidalia_SRCS ${vidalia_SRCS}
   ControlPasswordInputDialog.cpp
   VidaliaTab.cpp
   StatusTab.cpp
+  HelperProcess.cpp
 )
 qt4_wrap_cpp(vidalia_SRCS
   Vidalia.h
@@ -173,6 +174,7 @@ qt4_wrap_cpp(vidalia_SRCS
   ControlPasswordInputDialog.h
   VidaliaTab.h
   StatusTab.h
+  HelperProcess.h
 )
 
 if (USE_MINIUPNPC)
diff --git a/src/vidalia/MainWindow.cpp b/src/vidalia/MainWindow.cpp
index ac048e5..d61b5e8 100644
--- a/src/vidalia/MainWindow.cpp
+++ b/src/vidalia/MainWindow.cpp
@@ -383,6 +383,24 @@ MainWindow::createConnections()
   connect(UPNPControl::instance(), SIGNAL(error(UPNPControl::UPNPError)),
           this, SLOT(upnpError(UPNPControl::UPNPError)));
 #endif
+  /* Create a new HelperProcess object, used to start the web browser */
+  _browserProcess = new HelperProcess(this);
+  connect(_browserProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
+           this, SLOT(onSubprocessFinished(int, QProcess::ExitStatus)));
+  connect(_browserProcess, SIGNAL(startFailed(QString)),
+           this, SLOT(onBrowserFailed(QString)));
+
+  /* Create a new HelperProcess object, used to start the IM client */
+  _imProcess = new HelperProcess(this);
+  connect(_imProcess, SIGNAL(finished(int, QProcess::ExitStatus)),
+           this, SLOT(onSubprocessFinished(int, QProcess::ExitStatus)));
+  connect(_imProcess, SIGNAL(startFailed(QString)),
+           this, SLOT(onIMFailed(QString)));
+
+  /* Create a new HelperProcess object, used to start the proxy server */
+  _proxyProcess = new HelperProcess(this);
+  connect(_proxyProcess, SIGNAL(startFailed(QString)),
+           this, SLOT(onProxyFailed(QString)));
 }
 
 /** Called when the application is closing, by selecting "Exit" from the tray
@@ -431,6 +449,10 @@ MainWindow::running()
     start();
   }
 
+  /* Start the proxy server, if configured */
+  if (settings.runProxyAtStart())
+    startProxy();
+
 #if defined(USE_AUTOUPDATE)
   if (settings.isAutoUpdateEnabled()) {
     QDateTime lastCheckedAt = settings.lastCheckedForUpdates();
@@ -476,9 +498,33 @@ MainWindow::aboutToQuit()
   ServerSettings settings(_torControl);
   settings.cleanupPortForwarding();
 
+  if (_proxyProcess->state() != QProcess::NotRunning) {
+    /* Close the proxy server (Polipo ignores the WM_CLOSE event sent by
+     * terminate() so we have to kill() it) */
+    _proxyProcess->kill();
+  }
+
   /* Kill the browser and IM client if using the new launcher */
   VidaliaSettings vidalia_settings;
 
+  if (! vidalia_settings.getBrowserDirectory().isEmpty()) {
+    /* Disconnect the finished signals so that we won't try to exit Vidalia again */
+    QObject::disconnect(_browserProcess, SIGNAL(finished(int, QProcess::ExitStatus)), 0, 0);
+    QObject::disconnect(_imProcess, SIGNAL(finished(int, QProcess::ExitStatus)), 0, 0);
+
+    /* Use QProcess terminate function */
+    if (_browserProcess->state() == QProcess::Running)
+      _browserProcess->terminate();
+
+#if defined(Q_OS_WIN)
+    /* Kill any processes which might have been forked off */
+    win32_end_process_by_filename(vidalia_settings.getBrowserExecutable());
+#endif
+
+    if (_imProcess->state() == QProcess::Running)
+      _imProcess->terminate();    
+  }
+
   /* Disconnect all of the TorControl object's signals */
   QObject::disconnect(_torControl, 0, 0, 0);
 }
@@ -1009,6 +1055,7 @@ MainWindow::circuitEstablished()
   // TODO: fix hardcoded total length
   setStartupProgress(130,
                      tr("Connected to the Tor network!"));
+  startSubprocesses();
 
 #if defined(USE_AUTOUPDATE)
   VidaliaSettings settings;
@@ -1722,3 +1769,192 @@ MainWindow::installUpdatesFailed(const QString &errmsg)
 
 #endif
 
+/** Called when browser or IM client have exited */
+void
+MainWindow::onSubprocessFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+  Q_UNUSED(exitCode)
+  Q_UNUSED(exitStatus)
+
+  /* Get path to browser and IM client */
+  VidaliaSettings settings;
+  QString browserExecutable = settings.getBrowserExecutable();
+  QString browserDirectory = settings.getBrowserDirectory();
+  QString imExecutable = settings.getIMExecutable();
+
+  /* A subprocess is finished if it successfully exited or was never asked to start */
+  bool browserDone = (browserExecutable.isEmpty()
+                        && browserDirectory.isEmpty())
+                        || _browserProcess->isDone();
+  bool imDone = imExecutable.isEmpty() || _imProcess->isDone();
+
+  /* Exit if both subprocesses are finished */
+  if (browserDone && imDone) {
+    if (browserDirectory.isEmpty()) {
+      /* We are using the standard launcher, exit immediately */
+      vApp->quit();
+    } else {
+      /* We are using the alternate launcher, wait until the browser has really died */
+      QTimer *browserWatcher = new QTimer(this);
+      connect(browserWatcher, SIGNAL(timeout()), this, SLOT(onCheckForBrowser()));
+      browserWatcher->start(2000);
+    }
+  }
+}
+
+/** Called periodically to check if the browser is running. If it is not,
+ * exit Vidalia cleanly */
+void
+MainWindow::onCheckForBrowser()
+{
+/* This only works on Windows for now */
+#if defined(Q_OS_WIN)
+
+  VidaliaSettings settings;
+  QString browserDirectoryFilename = settings.getBrowserExecutable();
+
+  /* Get list of running processes */
+  QHash<qint64, QString> procList = win32_process_list();
+
+  /* On old versions of Windows win32_process_list() will return
+     an empty list. In this case, just keep Vidalia open */
+  if (procList.isEmpty()) {
+    return;
+  }
+
+  /* Loop over all processes or until we find <browserDirectoryFilename> */
+  QHashIterator<qint64, QString> i(procList);
+  while (i.hasNext()) {
+    i.next();
+    if (i.value().toLower() == browserDirectoryFilename) {
+      /* The browser is still running, so Vidalia should keep running too */
+      return;
+    }
+  }
+
+  /* The browser isn't running, exit Vidalia */
+  vApp->quit();
+#endif  
+}
+
+/** Called when the web browser failed to start, for example, because the path
+ * specified to the web browser executable didn't lead to an executable. */
+void
+MainWindow::onBrowserFailed(QString errmsg)
+{
+  Q_UNUSED(errmsg);
+ 
+  /* Display an error message and see if the user wants some help */
+  VMessageBox::warning(this, tr("Error starting web browser"),
+              tr("Vidalia was unable to start the configured web browser"),
+              VMessageBox::Ok|VMessageBox::Default|VMessageBox::Escape);
+}
+
+/** Called when the IM client failed to start, for example, because the path
+ * specified to the IM client executable didn't lead to an executable. */
+void
+MainWindow::onIMFailed(QString errmsg)
+{
+  Q_UNUSED(errmsg);
+ 
+  /* Display an error message and see if the user wants some help */
+  VMessageBox::warning(this, tr("Error starting IM client"),
+              tr("Vidalia was unable to start the configured IM client"),
+              VMessageBox::Ok|VMessageBox::Default|VMessageBox::Escape);
+}
+
+/** Starts the proxy server, if appropriately configured */
+void
+MainWindow::startProxy()
+{
+  VidaliaSettings settings;
+  QString executable = settings.getProxyExecutable();
+  _proxyProcess->start(executable, settings.getProxyExecutableArguments());
+}
+
+/** Called when the proxy server fails to start, for example, because
+ * the path specified didn't lead to an executable. */
+void
+MainWindow::onProxyFailed(QString errmsg)
+{
+  Q_UNUSED(errmsg);
+ 
+  /* Display an error message and see if the user wants some help */
+  VMessageBox::warning(this, tr("Error starting proxy server"),
+              tr("Vidalia was unable to start the configured proxy server"),
+              VMessageBox::Ok|VMessageBox::Default|VMessageBox::Escape);
+}
+
+/** Start a web browser when given the directory containing the executable and profile */
+void
+MainWindow::launchBrowserFromDirectory()
+{
+  VidaliaSettings settings;
+
+  QString browserDirectory = settings.getBrowserDirectory();
+  QString browserDirectoryFilename = settings.getBrowserExecutable();
+
+  /* Set TZ=UTC (to stop leaking timezone information) and
+   * MOZ_NO_REMOTE=1 (to allow multiple instances of Firefox */
+  QStringList env = QProcess::systemEnvironment();
+  env << "TZ=UTC";
+  env << "MOZ_NO_REMOTE=1";
+  _browserProcess->setEnvironment(env);
+
+  /* The browser is in <browserDirectory>/App/Firefox/<browserDirectoryFilename> */
+  QString browserExecutable =
+    QDir::toNativeSeparators(browserDirectory + "/App/Firefox/" + browserDirectoryFilename);
+  /* The profile is in <browserDirectory>/Data/profile */
+  QString profileDir =
+    QDir::toNativeSeparators(browserDirectory + "/Data/profile");
+
+  /* Copy the profile directory if it's not already there */
+  QDir browserDirObj = QDir(browserDirectory);
+
+  /* Copy the profile directory if it's not already there */
+  if (!browserDirObj.exists("Data/profile")) {
+    browserDirObj.mkdir("Data/profile");
+    copy_dir(browserDirectory + "/App/DefaultData/profile", browserDirectory + "/Data/profile");
+  }
+
+  /* Copy the plugins directory if it's not already there */
+  if (!browserDirObj.exists("Data/plugins")) {
+    browserDirObj.mkdir("Data/plugins");
+    copy_dir(browserDirectory + "/App/DefaultData/plugins", browserDirectory + "/Data/plugins");
+  }
+
+  /* Build the command line arguments */
+  QStringList commandLine;
+  // Is this better or worse than MOZ_NO_REMOTE?
+  //commandLine << "-no-remote";
+  commandLine << "-profile";
+  commandLine << profileDir;
+
+  /* Launch the browser */
+  _browserProcess->start(browserExecutable, commandLine);
+}
+
+/** Starts the web browser and IM client, if appropriately configured */
+void
+MainWindow::startSubprocesses()
+{
+  VidaliaSettings settings;
+  QString subprocess;
+
+  /* Launch the web browser */
+  if (!(subprocess = settings.getBrowserDirectory()).isEmpty()) {
+    /* The user has set BrowserDirectory; use this */
+    launchBrowserFromDirectory();
+  } else if (!(subprocess = settings.getBrowserExecutable()).isEmpty()) {
+    /* BrowserDirectory is not set, but BrowserExecutable is; use this */
+    _browserProcess->setEnvironment(QProcess::systemEnvironment() << "TZ=UTC");
+    _browserProcess->start(subprocess, QStringList());
+  }
+
+  /* Launch the IM client */
+  subprocess = settings.getIMExecutable();
+
+  if (!subprocess.isEmpty())
+    _imProcess->start(subprocess, QStringList());
+}
+
diff --git a/src/vidalia/MainWindow.h b/src/vidalia/MainWindow.h
index 20f5ef1..51722cb 100644
--- a/src/vidalia/MainWindow.h
+++ b/src/vidalia/MainWindow.h
@@ -24,6 +24,7 @@
 #include "ConfigDialog.h"
 #include "MessageLog.h"
 #include "NetViewer.h"
+#include "HelperProcess.h"
 #if defined(USE_AUTOUPDATE)
 #include "UpdateProcess.h"
 #include "UpdateProgressDialog.h"
@@ -138,6 +139,18 @@ private slots:
   /** Deletes the tab at index if it exists and it isn't the Status tab */
   void delTab(int index = -1);
 
+  /** Called when the web browser or IM client have stopped */
+  void onSubprocessFinished(int exitCode, QProcess::ExitStatus exitStatus);
+  /** Called periodically to check if the browser is running. If it is not,
+   * exit Vidalia cleanly */
+  void onCheckForBrowser();
+  /** Called web the web browser failed to start */
+  void onBrowserFailed(QString errmsg);
+  /** Called web the IM client failed to start */
+  void onIMFailed(QString errmsg);
+  /** Called when the proxy server fails to start */
+  void onProxyFailed(QString errmsg);
+
 #if defined(USE_AUTOUPDATE)
   /** Called when the user clicks the 'Check Now' button in the General
    * settings page. */
@@ -240,6 +253,20 @@ private:
   /** The Vidalia icon that sits in the tray. */
   QSystemTrayIcon _trayIcon;
 
+  /** Start a web browser when given the directory containing the executable and profile */
+  void launchBrowserFromDirectory();
+  /** Starts the web browser, if appropriately configured */
+  void startSubprocesses();
+  /** Starts the proxy server, if appropriately configured */
+  void startProxy();
+
+  /** A HelperProcess object that manages the web browser */
+  HelperProcess* _browserProcess;
+  /** A HelperProcess object that manages the IM client */
+  HelperProcess* _imProcess;
+  /** A HelperProcess object that manages the proxy server */
+  HelperProcess* _proxyProcess;
+
 #if defined(USE_AUTOUPDATE)
   /** Timer used to remind us to check for software updates. */
   QTimer _updateTimer;





More information about the tor-commits mailing list