vidalia.cpp

Go to the documentation of this file.
00001 /****************************************************************
00002  *  Vidalia is distributed under the following license:
00003  *
00004  *  Copyright (C) 2006-2007,  Matt Edman, Justin Hipple
00005  *
00006  *  This program is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU General Public License
00008  *  as published by the Free Software Foundation; either version 2
00009  *  of the License, or (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  *  Boston, MA  02110-1301, USA.
00020  ****************************************************************/
00021 
00022 /**
00023  * \file vidalia.cpp
00024  * \version $Id: vidalia.cpp 1801 2007-07-13 02:31:02Z edmanm $
00025  * \brief Main Vidalia QApplication object
00026  */
00027 
00028 #include <QDir>
00029 #include <QTextStream>
00030 #include <QStyleFactory>
00031 #include <util/string.h>
00032 #include <lang/languagesupport.h>
00033 #include <gui/common/vmessagebox.h>
00034 #include <util/html.h>
00035 #include <stdlib.h>
00036 
00037 #include "vidalia.h"
00038 
00039 /* Available command-line arguments. */
00040 #define ARG_LANGUAGE   "lang"     /**< Argument specifying language.    */
00041 #define ARG_GUISTYLE   "style"    /**< Argument specfying GUI style.    */
00042 #define ARG_RESET      "reset"    /**< Reset Vidalia's saved settings.  */
00043 #define ARG_HELP       "help"     /**< Display usage informatino.       */
00044 #define ARG_DATADIR    "datadir"  /**< Directory to use for data files. */
00045 #define ARG_PIDFILE    "pidfile"  /**< Location and name of our pidfile.*/
00046 #define ARG_LOGFILE    "logfile"  /**< Location of our logfile.         */
00047 #define ARG_LOGLEVEL   "loglevel" /**< Log verbosity.                   */
00048 
00049 
00050 /* Static member variables */
00051 QMap<QString, QString> Vidalia::_args; /**< List of command-line arguments.  */
00052 QString Vidalia::_style;               /**< The current GUI style.           */
00053 QString Vidalia::_language;            /**< The current language.            */
00054 HelpBrowser*  Vidalia::_help = 0;      /**< Vidalia's help system.           */
00055 TorControl* Vidalia::_torControl = 0;  /**< Main TorControl object.          */
00056 Log Vidalia::_log;
00057 
00058 /** Catches debugging messages from Qt and sends them to Vidalia's logs. If Qt
00059  * emits a QtFatalMsg, we will write the message to the log and then abort().
00060  */
00061 void
00062 Vidalia::qt_msg_handler(QtMsgType type, const char *s)
00063 {
00064   QString msg(s);
00065   switch (type) {
00066     case QtDebugMsg:
00067       vDebug("QtDebugMsg: %1").arg(msg);
00068       break;
00069     case QtWarningMsg:
00070       vNotice("QtWarningMsg: %1").arg(msg);
00071       break;
00072     case QtCriticalMsg:
00073       vWarn("QtCriticalMsg: %1").arg(msg);
00074       break;
00075     case QtFatalMsg:
00076       vError("QtFatalMsg: %1").arg(msg);
00077       break;
00078   }
00079   if (type == QtFatalMsg) {
00080     vError("Fatal Qt error. Aborting.");
00081     abort();
00082   }
00083 }
00084 
00085 /** Constructor. Parses the command-line arguments, resets Vidalia's
00086  * configuration (if requested), and sets up the GUI style and language
00087  * translation. */
00088 Vidalia::Vidalia(QStringList args, int &argc, char **argv)
00089 : QApplication(argc, argv)
00090 {
00091   qInstallMsgHandler(qt_msg_handler);
00092 
00093   /* Read in all our command-line arguments. */
00094   parseArguments(args);
00095 
00096   /* Check if we're supposed to reset our config before proceeding. */
00097   if (_args.contains(ARG_RESET))
00098     VidaliaSettings::reset();
00099 
00100   /* Handle the -loglevel and -logfile options. */
00101   if (_args.contains(ARG_LOGFILE))
00102     _log.open(_args.value(ARG_LOGFILE));
00103   if (_args.contains(ARG_LOGLEVEL)) {
00104     _log.setLogLevel(Log::stringToLogLevel(
00105                       _args.value(ARG_LOGLEVEL)));
00106     if (!_args.contains(ARG_LOGFILE))
00107       _log.open(stdout);
00108   }
00109   if (!_args.contains(ARG_LOGLEVEL) && 
00110       !_args.contains(ARG_LOGFILE))
00111     _log.setLogLevel(Log::Off);
00112 
00113   /* Translate the GUI to the appropriate language. */
00114   setLanguage(_args.value(ARG_LANGUAGE));
00115   /* Set the GUI style appropriately. */
00116   setStyle(_args.value(ARG_GUISTYLE));
00117 
00118   /* Creates a TorControl object, used to talk to Tor. */
00119   _torControl = new TorControl();
00120 }
00121 
00122 /** Destructor */
00123 Vidalia::~Vidalia()
00124 {
00125   if (_help)
00126     delete _help;
00127   delete _torControl;
00128 }
00129 
00130 #if defined(Q_OS_WIN)
00131 /** On Windows, we need to catch the WM_QUERYENDSESSION message
00132  * so we know that it is time to shutdown. */
00133 bool
00134 Vidalia::winEventFilter(MSG *msg, long *result)
00135 {
00136   if (msg->message == WM_QUERYENDSESSION) {
00137     emit shutdown();
00138   }
00139   return QApplication::winEventFilter(msg, result);
00140 }
00141 #endif
00142 
00143 /** Returns true if the user wants to see usage information. */
00144 bool
00145 Vidalia::showUsage()
00146 {
00147   return _args.contains(ARG_HELP);
00148 }
00149 
00150 /** Displays usage information for command-line args. */
00151 void
00152 Vidalia::showUsageMessageBox()
00153 {
00154   QString usage;
00155   QTextStream out(&usage);
00156 
00157   out << "Available Options:" << endl;
00158   out << "<table>";
00159   out << trow(tcol("-"ARG_HELP) + 
00160               tcol(tr("Displays this usage message and exits.")));
00161   out << trow(tcol("-"ARG_RESET) +
00162               tcol(tr("Resets ALL stored Vidalia settings.")));
00163   out << trow(tcol("-"ARG_DATADIR" &lt;dir&gt;") +
00164               tcol(tr("Sets the directory Vidalia uses for data files.")));
00165   out << trow(tcol("-"ARG_PIDFILE" &lt;file&gt;") +
00166               tcol(tr("Sets the name and location of Vidalia's pidfile.")));
00167   out << trow(tcol("-"ARG_LOGFILE" &lt;file&gt;") +
00168               tcol(tr("Sets the name and location of Vidalia's logfile.")));
00169   out << trow(tcol("-"ARG_LOGLEVEL" &lt;level&gt;") +
00170               tcol(tr("Sets the verbosity of Vidalia's logging.") +
00171                    "<br>[" + Log::logLevels().join("|") +"]"));
00172   out << trow(tcol("-"ARG_GUISTYLE" &lt;style&gt;") +
00173               tcol(tr("Sets Vidalia's interface style.") +
00174                    "<br>[" + QStyleFactory::keys().join("|") + "]"));
00175   out << trow(tcol("-"ARG_LANGUAGE" &lt;language&gt;") + 
00176               tcol(tr("Sets Vidalia's language.") +
00177                    "<br>[" + LanguageSupport::languageCodes().join("|") + "]"));
00178   out << "</table>";
00179 
00180   VMessageBox::information(0, 
00181     tr("Vidalia Usage Information"), usage, VMessageBox::Ok);
00182 }
00183 
00184 /** Returns true if the specified argument expects a value. */
00185 bool
00186 Vidalia::argNeedsValue(QString argName)
00187 {
00188   return (argName == ARG_GUISTYLE ||
00189           argName == ARG_LANGUAGE ||
00190           argName == ARG_DATADIR  ||
00191           argName == ARG_PIDFILE  ||
00192           argName == ARG_LOGFILE  ||
00193           argName == ARG_LOGLEVEL);
00194 }
00195 
00196 /** Parses the list of command-line arguments for their argument names and
00197  * values. */
00198 void
00199 Vidalia::parseArguments(QStringList args)
00200 {
00201   QString arg, value;
00202 
00203   /* Loop through all command-line args/values and put them in a map */
00204   for (int i = 0; i < args.size(); i++) {
00205     /* Get the argument name and set a blank value */
00206     arg   = args.at(i).toLower();
00207     value = "";
00208 
00209     /* Check if it starts with a - or -- */
00210     if (arg.startsWith("-")) {
00211       arg = arg.mid((arg.startsWith("--") ? 2 : 1));
00212     }
00213     /* Check if it takes a value and there is one on the command-line */
00214     if (i < args.size()-1 && argNeedsValue(arg)) {
00215       value = args.at(++i);
00216     }
00217     /* Place this arg/value in the map */
00218     _args.insert(arg, value);
00219   }
00220 }
00221 
00222 /** Verifies that all specified arguments were valid. */
00223 bool
00224 Vidalia::validateArguments(QString &errmsg)
00225 {
00226   /* Check for a language that Vidalia recognizes. */
00227   if (_args.contains(ARG_LANGUAGE) &&
00228       !LanguageSupport::isValidLanguageCode(_args.value(ARG_LANGUAGE))) {
00229     errmsg = tr("Invalid language code specified: ") + _args.value(ARG_LANGUAGE);
00230     return false;
00231   }
00232   /* Check for a valid GUI style */
00233   if (_args.contains(ARG_GUISTYLE) &&
00234       !QStyleFactory::keys().contains(_args.value(ARG_GUISTYLE),
00235                                       Qt::CaseInsensitive)) {
00236     errmsg = tr("Invalid GUI style specified: ") + _args.value(ARG_GUISTYLE);
00237     return false;
00238   }
00239   /* Check for a valid log level */
00240   if (_args.contains(ARG_LOGLEVEL) &&
00241       !Log::logLevels().contains(_args.value(ARG_LOGLEVEL))) {
00242     errmsg = tr("Invalid log level specified: ") + _args.value(ARG_LOGLEVEL);
00243     return false;
00244   }
00245   /* Check for a writable log file */
00246   if (_args.contains(ARG_LOGFILE) && !_log.isOpen()) {
00247     errmsg = tr("Unable to open log file '%1': %2")
00248                            .arg(_args.value(ARG_LOGFILE))
00249                            .arg(_log.errorString());
00250     return false;
00251   }
00252   return true;
00253 }
00254 
00255 /** Sets the translation Vidalia will use. If one was specified on the
00256  * command-line, we will use that. Otherwise, we'll check to see if one was
00257  * saved previously. If not, we'll default to one appropriate for the system
00258  * locale. */
00259 bool
00260 Vidalia::setLanguage(QString languageCode)
00261 {
00262   /* If the language code is empty, use the previously-saved setting */
00263   if (languageCode.isEmpty()) {
00264     VidaliaSettings settings;
00265     languageCode = settings.getLanguageCode();
00266   }
00267   /* Translate into the desired langauge */
00268   if (LanguageSupport::translate(languageCode)) {
00269     _language = languageCode;
00270     return true;
00271   }
00272   return false;
00273 }
00274 
00275 /** Sets the GUI style Vidalia will use. If one was specified on the
00276  * command-line, we will use that. Otherwise, we'll check to see if one was
00277  * saved previously. If not, we'll default to one appropriate for the
00278  * operating system. */
00279 bool
00280 Vidalia::setStyle(QString styleKey)
00281 {
00282   /* If no style was specified, use the previously-saved setting */
00283   if (styleKey.isEmpty()) {
00284     VidaliaSettings settings;
00285     styleKey = settings.getInterfaceStyle();
00286   }
00287   /* Apply the specified GUI style */
00288   if (QApplication::setStyle(styleKey)) {
00289     _style = styleKey;
00290     return true;
00291   }
00292   return false;
00293 }
00294 
00295 /** Displays the help page associated with the specified topic. If no topic is
00296  * specified, then the default help page will be displayed. */
00297 void
00298 Vidalia::help(QString topic)
00299 {
00300   if (!_help)
00301     _help = new HelpBrowser();
00302   _help->showWindow(topic);
00303 }
00304 
00305 /** Returns the directory Vidalia uses for its data files. */
00306 QString
00307 Vidalia::dataDirectory()
00308 {
00309   if (_args.contains(ARG_DATADIR)) {
00310     return _args.value(ARG_DATADIR);
00311   }
00312   return defaultDataDirectory();
00313 }
00314 
00315 /** Returns the default location of Vidalia's data directory. */
00316 QString
00317 Vidalia::defaultDataDirectory()
00318 {
00319 #if defined(Q_OS_WIN32)
00320   return (win32_app_data_folder() + "\\Vidalia");
00321 #else
00322   return (QDir::homePath() + "/.vidalia");
00323 #endif
00324 }
00325 
00326 /** Returns the location of Vidalia's pid file. */
00327 QString
00328 Vidalia::pidFile()
00329 {
00330   if (_args.contains(ARG_PIDFILE)) {
00331     return _args.value(ARG_PIDFILE);
00332   }
00333   return QDir::convertSeparators("/var/run/tor/tor.pid");
00334 }
00335 
00336 Log::LogMessage
00337 Vidalia::log(Log::LogLevel level, QString msg)
00338 {
00339   return _log.log(level, msg);
00340 }
00341 

Generated on Wed Sep 5 15:49:28 2007 for Vidalia by  doxygen 1.5.3