Vidalia.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "config.h"
00018 #include "Vidalia.h"
00019 #include "LanguageSupport.h"
00020 #include "VMessageBox.h"
00021
00022 #include "stringutil.h"
00023 #include "html.h"
00024
00025 #ifdef USE_MARBLE
00026 #include <MarbleDirs.h>
00027 #endif
00028
00029 #include <QDir>
00030 #include <QTimer>
00031 #include <QTextStream>
00032 #include <QStyleFactory>
00033 #include <QShortcut>
00034 #include <QTranslator>
00035 #include <QLibraryInfo>
00036 #include <QSslSocket>
00037
00038 #ifdef Q_OS_MACX
00039 #include <Carbon/Carbon.h>
00040 #endif
00041 #include <stdlib.h>
00042
00043
00044 #define ARG_LANGUAGE "lang"
00045 #define ARG_GUISTYLE "style"
00046 #define ARG_RESET "reset"
00047 #define ARG_HELP "help"
00048 #define ARG_DATADIR "datadir"
00049 #define ARG_PIDFILE "pidfile"
00050 #define ARG_LOGFILE "logfile"
00051 #define ARG_LOGLEVEL "loglevel"
00052 #define ARG_READ_PASSWORD_FROM_STDIN \
00053 "read-password-from-stdin"
00054
00055
00056 QMap<QString, QString> Vidalia::_args;
00057 QString Vidalia::_style;
00058 QString Vidalia::_language;
00059 TorControl* Vidalia::_torControl = 0;
00060 Log Vidalia::_log;
00061 QList<QTranslator *> Vidalia::_translators;
00062
00063
00064
00065
00066
00067 void
00068 Vidalia::qt_msg_handler(QtMsgType type, const char *s)
00069 {
00070 QString msg(s);
00071 switch (type) {
00072 case QtDebugMsg:
00073 vDebug("QtDebugMsg: %1").arg(msg);
00074 break;
00075 case QtWarningMsg:
00076 vNotice("QtWarningMsg: %1").arg(msg);
00077 break;
00078 case QtCriticalMsg:
00079 vWarn("QtCriticalMsg: %1").arg(msg);
00080 break;
00081 case QtFatalMsg:
00082 vError("QtFatalMsg: %1").arg(msg);
00083 break;
00084 }
00085 if (type == QtFatalMsg) {
00086 vError("Fatal Qt error. Aborting.");
00087 abort();
00088 }
00089 }
00090
00091
00092
00093
00094 Vidalia::Vidalia(QStringList args, int &argc, char **argv)
00095 : QApplication(argc, argv)
00096 {
00097 qInstallMsgHandler(qt_msg_handler);
00098
00099
00100 parseArguments(args);
00101
00102
00103 if (_args.contains(ARG_RESET))
00104 VidaliaSettings::reset();
00105
00106
00107 if (! VidaliaSettings::settingsFileExists())
00108 copyDefaultSettingsFile();
00109
00110
00111 if (_args.contains(ARG_LOGFILE))
00112 _log.open(_args.value(ARG_LOGFILE));
00113 if (_args.contains(ARG_LOGLEVEL)) {
00114 _log.setLogLevel(Log::stringToLogLevel(
00115 _args.value(ARG_LOGLEVEL)));
00116 if (!_args.contains(ARG_LOGFILE))
00117 _log.open(stdout);
00118 }
00119 if (!_args.contains(ARG_LOGLEVEL) &&
00120 !_args.contains(ARG_LOGFILE))
00121 _log.setLogLevel(Log::Off);
00122
00123
00124 setLanguage(_args.value(ARG_LANGUAGE));
00125
00126 setStyle(_args.value(ARG_GUISTYLE));
00127
00128
00129 _torControl = new TorControl();
00130
00131
00132
00133 loadDefaultCaCertificates();
00134
00135 #ifdef USE_MARBLE
00136
00137 Marble::MarbleDirs::setMarbleDataPath(dataDirectory());
00138
00139 #ifdef Q_OS_WIN32
00140 Marble::MarbleDirs::setMarblePluginPath(vApp->applicationDirPath()
00141 + "/plugins/marble");
00142 #endif
00143 #endif
00144 #ifdef Q_WS_MAC
00145 setStyleSheet("QTreeWidget { font-size: 12pt }");
00146 #endif
00147 }
00148
00149
00150 Vidalia::~Vidalia()
00151 {
00152 delete _torControl;
00153 }
00154
00155
00156
00157 int
00158 Vidalia::run()
00159 {
00160 QTimer::singleShot(0, vApp, SLOT(onEventLoopStarted()));
00161 return vApp->exec();
00162 }
00163
00164
00165
00166
00167 void
00168 Vidalia::onEventLoopStarted()
00169 {
00170 emit running();
00171 }
00172
00173 #if defined(Q_OS_WIN)
00174
00175
00176 bool
00177 Vidalia::winEventFilter(MSG *msg, long *result)
00178 {
00179 if (msg->message == WM_QUERYENDSESSION) {
00180 quit();
00181 }
00182 return QApplication::winEventFilter(msg, result);
00183 }
00184 #endif
00185
00186
00187 bool
00188 Vidalia::showUsage()
00189 {
00190 return _args.contains(ARG_HELP);
00191 }
00192
00193
00194 void
00195 Vidalia::showUsageMessageBox()
00196 {
00197 QString usage;
00198 QTextStream out(&usage);
00199
00200 out << "Available Options:" << endl;
00201 out << "<table>";
00202 out << trow(tcol("-"ARG_HELP) +
00203 tcol(tr("Displays this usage message and exits.")));
00204 out << trow(tcol("-"ARG_RESET) +
00205 tcol(tr("Resets ALL stored Vidalia settings.")));
00206 out << trow(tcol("-"ARG_DATADIR" <dir>") +
00207 tcol(tr("Sets the directory Vidalia uses for data files.")));
00208 out << trow(tcol("-"ARG_PIDFILE" <file>") +
00209 tcol(tr("Sets the name and location of Vidalia's pidfile.")));
00210 out << trow(tcol("-"ARG_LOGFILE" <file>") +
00211 tcol(tr("Sets the name and location of Vidalia's logfile.")));
00212 out << trow(tcol("-"ARG_LOGLEVEL" <level>") +
00213 tcol(tr("Sets the verbosity of Vidalia's logging.") +
00214 "<br>[" + Log::logLevels().join("|") +"]"));
00215 out << trow(tcol("-"ARG_GUISTYLE" <style>") +
00216 tcol(tr("Sets Vidalia's interface style.") +
00217 "<br>[" + QStyleFactory::keys().join("|") + "]"));
00218 out << trow(tcol("-"ARG_LANGUAGE" <language>") +
00219 tcol(tr("Sets Vidalia's language.") +
00220 "<br>[" + LanguageSupport::languageCodes().join("|") + "]"));
00221 out << "</table>";
00222
00223 VMessageBox::information(0,
00224 tr("Vidalia Usage Information"), usage, VMessageBox::Ok);
00225 }
00226
00227
00228 bool
00229 Vidalia::argNeedsValue(QString argName)
00230 {
00231 return (argName == ARG_GUISTYLE ||
00232 argName == ARG_LANGUAGE ||
00233 argName == ARG_DATADIR ||
00234 argName == ARG_PIDFILE ||
00235 argName == ARG_LOGFILE ||
00236 argName == ARG_LOGLEVEL);
00237 }
00238
00239
00240
00241 void
00242 Vidalia::parseArguments(QStringList args)
00243 {
00244 QString arg, value;
00245
00246
00247 for (int i = 0; i < args.size(); i++) {
00248
00249 arg = args.at(i).toLower();
00250 value = "";
00251
00252
00253 if (arg.startsWith("-")) {
00254 arg = arg.mid((arg.startsWith("--") ? 2 : 1));
00255 }
00256
00257 if (i < args.size()-1 && argNeedsValue(arg)) {
00258 value = args.at(++i);
00259 }
00260
00261 _args.insert(arg, value);
00262 }
00263 }
00264
00265
00266 bool
00267 Vidalia::validateArguments(QString &errmsg)
00268 {
00269
00270 if (_args.contains(ARG_LANGUAGE) &&
00271 !LanguageSupport::isValidLanguageCode(_args.value(ARG_LANGUAGE))) {
00272 errmsg = tr("Invalid language code specified: ") + _args.value(ARG_LANGUAGE);
00273 return false;
00274 }
00275
00276 if (_args.contains(ARG_GUISTYLE) &&
00277 !QStyleFactory::keys().contains(_args.value(ARG_GUISTYLE),
00278 Qt::CaseInsensitive)) {
00279 errmsg = tr("Invalid GUI style specified: ") + _args.value(ARG_GUISTYLE);
00280 return false;
00281 }
00282
00283 if (_args.contains(ARG_LOGLEVEL) &&
00284 !Log::logLevels().contains(_args.value(ARG_LOGLEVEL))) {
00285 errmsg = tr("Invalid log level specified: ") + _args.value(ARG_LOGLEVEL);
00286 return false;
00287 }
00288
00289 if (_args.contains(ARG_LOGFILE) && !_log.isOpen()) {
00290 errmsg = tr("Unable to open log file '%1': %2")
00291 .arg(_args.value(ARG_LOGFILE))
00292 .arg(_log.errorString());
00293 return false;
00294 }
00295 return true;
00296 }
00297
00298
00299
00300
00301
00302 bool
00303 Vidalia::setLanguage(QString languageCode)
00304 {
00305
00306 if (languageCode.isEmpty()) {
00307 VidaliaSettings settings;
00308 languageCode = settings.getLanguageCode();
00309 }
00310
00311 if (retranslateUi(languageCode)) {
00312 _language = languageCode;
00313 return true;
00314 }
00315 return false;
00316 }
00317
00318
00319
00320
00321
00322 bool
00323 Vidalia::setStyle(QString styleKey)
00324 {
00325
00326 if (styleKey.isEmpty()) {
00327 VidaliaSettings settings;
00328 styleKey = settings.getInterfaceStyle();
00329 }
00330
00331 if (QApplication::setStyle(styleKey)) {
00332 _style = styleKey;
00333 return true;
00334 }
00335 return false;
00336 }
00337
00338
00339 QString
00340 Vidalia::dataDirectory()
00341 {
00342 if (_args.contains(ARG_DATADIR)) {
00343 return _args.value(ARG_DATADIR);
00344 }
00345 return defaultDataDirectory();
00346 }
00347
00348
00349 QString
00350 Vidalia::defaultDataDirectory()
00351 {
00352 #if defined(Q_OS_WIN32)
00353 return (win32_app_data_folder() + "\\Vidalia");
00354 #elif defined(Q_OS_MAC)
00355 return (QDir::homePath() + "/Library/Vidalia");
00356 #else
00357 return (QDir::homePath() + "/.vidalia");
00358 #endif
00359 }
00360
00361
00362 QString
00363 Vidalia::pidFile()
00364 {
00365 if (_args.contains(ARG_PIDFILE)) {
00366 return _args.value(ARG_PIDFILE);
00367 }
00368 return QDir::convertSeparators(dataDirectory() + "/vidalia.pid");
00369 }
00370
00371 bool
00372 Vidalia::readPasswordFromStdin()
00373 {
00374 return _args.contains(ARG_READ_PASSWORD_FROM_STDIN);
00375 }
00376
00377
00378 Log::LogMessage
00379 Vidalia::log(Log::LogLevel level, QString msg)
00380 {
00381 return _log.log(level, msg);
00382 }
00383
00384
00385
00386 void
00387 Vidalia::createShortcut(const QKeySequence &key, QWidget *sender,
00388 QObject *receiver, const char *slot)
00389 {
00390 QShortcut *s = new QShortcut(key, sender);
00391 connect(s, SIGNAL(activated()), receiver, slot);
00392 }
00393
00394
00395
00396 void
00397 Vidalia::createShortcut(const QString &key, QWidget *sender,
00398 QObject *receiver, const char *slot)
00399 {
00400 createShortcut(QKeySequence(key), sender, receiver, slot);
00401 }
00402
00403 void
00404 Vidalia::removeAllTranslators()
00405 {
00406 foreach (QTranslator *translator, _translators) {
00407 QApplication::removeTranslator(translator);
00408 delete translator;
00409 }
00410 _translators.clear();
00411 }
00412
00413 bool
00414 Vidalia::retranslateUi(const QString &languageCode)
00415 {
00416 QTranslator *systemQtTranslator = 0;
00417 QTranslator *vidaliaQtTranslator = 0;
00418 QTranslator *vidaliaTranslator = 0;
00419
00420 if (! LanguageSupport::isValidLanguageCode(languageCode))
00421 return false;
00422 if (! languageCode.compare("en", Qt::CaseInsensitive)) {
00423 _language = languageCode;
00424 removeAllTranslators();
00425 return true;
00426 }
00427
00428 systemQtTranslator = new QTranslator(vApp);
00429 Q_CHECK_PTR(systemQtTranslator);
00430 QString qtDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
00431 systemQtTranslator->load(qtDir + "/qt_" + languageCode + ".qm");
00432
00433
00434 vidaliaQtTranslator = new QTranslator(vApp);
00435 Q_CHECK_PTR(vidaliaQtTranslator);
00436 vidaliaQtTranslator->load(":/lang/qt_" + languageCode + ".qm");
00437
00438 vidaliaTranslator = new QTranslator(vApp);
00439 Q_CHECK_PTR(vidaliaTranslator);
00440 if (! vidaliaTranslator->load(":/lang/vidalia_" + languageCode + ".qm"))
00441 goto err;
00442
00443 removeAllTranslators();
00444 _language = languageCode;
00445 QApplication::installTranslator(systemQtTranslator);
00446 QApplication::installTranslator(vidaliaQtTranslator);
00447 QApplication::installTranslator(vidaliaTranslator);
00448 _translators << systemQtTranslator
00449 << vidaliaQtTranslator
00450 << vidaliaTranslator;
00451 return true;
00452
00453 err:
00454 if (systemQtTranslator)
00455 delete systemQtTranslator;
00456 if (vidaliaQtTranslator)
00457 delete vidaliaQtTranslator;
00458 if (vidaliaTranslator)
00459 delete vidaliaTranslator;
00460 delete vidaliaTranslator;
00461 return false;
00462 }
00463
00464
00465
00466 void
00467 Vidalia::copyDefaultSettingsFile() const
00468 {
00469 #ifdef Q_OS_MACX
00470 CFURLRef confUrlRef;
00471 CFStringRef pathRef;
00472 const char *path;
00473
00474 confUrlRef = CFBundleCopyResourceURL(CFBundleGetMainBundle(),
00475 CFSTR("vidalia"), CFSTR("conf"), NULL);
00476 if (confUrlRef == NULL)
00477 return;
00478
00479 pathRef = CFURLCopyFileSystemPath(confUrlRef, kCFURLPOSIXPathStyle);
00480 path = CFStringGetCStringPtr(pathRef, CFStringGetSystemEncoding());
00481
00482 if (path) {
00483 QString defaultConfFile = QString::fromLocal8Bit(path);
00484 QFileInfo fi(defaultConfFile);
00485 if (fi.exists()) {
00486 QFileInfo out(VidaliaSettings::settingsFile());
00487 if (! out.dir().exists())
00488 out.dir().mkpath(".");
00489 QFile::copy(defaultConfFile, out.absoluteFilePath());
00490 }
00491 }
00492 CFRelease(confUrlRef);
00493 CFRelease(pathRef);
00494 #endif
00495 }
00496
00497 void
00498 Vidalia::loadDefaultCaCertificates() const
00499 {
00500 QSslSocket::setDefaultCaCertificates(QList<QSslCertificate>());
00501
00502 if (! QSslSocket::addDefaultCaCertificates(":/pki/cacert_root.crt"))
00503 vWarn("Failed to add the GeoIP CA certificate to the default CA "
00504 "certificate database.");
00505
00506 if (! QSslSocket::addDefaultCaCertificates(":/pki/EntrustSecureServerCA.crt"))
00507 vWarn("Failed to add the Entrust Secure Server CA certificate to the "
00508 "default CA certificate database.");
00509
00510 if (! QSslSocket::addDefaultCaCertificates(":/pki/gd-class2-root.crt"))
00511 vWarn("Failed to add the GoDaddy Class 2 CA certificate to the "
00512 "default CA certificate database.");
00513 }
00514