diff --git a/main.cpp b/main.cpp index 61d441c52..64ada2f19 100644 --- a/main.cpp +++ b/main.cpp @@ -1,370 +1,369 @@ /* main.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2001,2002,2004,2008 Klar�vdalens Datakonsult AB Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "aboutdata.h" #include "kleopatraapplication.h" #include "mainwindow.h" #include #include #include #include #include #ifdef HAVE_USABLE_ASSUAN # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include #else namespace Kleo { class UiServer; } #endif #include #include "kleopatra_debug.h" #include "kleopatra_options.h" #include #include #include #include #include #include // for Qt::escape #include #include #include #include #include #include #include #include #include #include #include using namespace boost; static const int SPLASHSCREEN_TIMEOUT = 5000; // 5s namespace { template boost::shared_ptr make_shared_ptr(T *t) { return t ? boost::shared_ptr(t) : boost::shared_ptr(); } } static QPixmap UserIcon_nocached(const char *name) { // KIconLoader insists on caching all pixmaps. Since the splash // screen is a particularly large 'icon' and used only once, // caching is unneccesary and just hurts startup performance. KIconLoader *const il = KIconLoader::global(); assert(il); const QString iconPath = il->iconPath(QLatin1String(name), KIconLoader::User); return iconPath.isEmpty() ? il->unknown() : QPixmap(iconPath); } #ifndef QT_NO_SPLASHSCREEN class SplashScreen : public QSplashScreen { QBasicTimer m_timer; public: SplashScreen() : QSplashScreen(UserIcon_nocached("kleopatra_splashscreen"), Qt::WindowStaysOnTopHint), m_timer() { m_timer.start(SPLASHSCREEN_TIMEOUT, this); } protected: void timerEvent(QTimerEvent *ev) Q_DECL_OVERRIDE { if (ev->timerId() == m_timer.timerId()) { m_timer.stop(); hide(); } else { QSplashScreen::timerEvent(ev); } } }; #else class SplashScreen {}; #endif // QT_NO_SPLASHSCREEN static bool selfCheck(SplashScreen &splash) { #ifndef QT_NO_SPLASHSCREEN splash.showMessage(i18n("Performing Self-Check...")); #endif Kleo::Commands::SelfTestCommand cmd(0); cmd.setAutoDelete(false); cmd.setAutomaticMode(true); #ifndef QT_NO_SPLASHSCREEN cmd.setSplashScreen(&splash); #endif QEventLoop loop; QObject::connect(&cmd, &Kleo::Commands::SelfTestCommand::finished, &loop, &QEventLoop::quit); #ifndef QT_NO_SPLASHSCREEN QObject::connect(&cmd, SIGNAL(info(QString)), &splash, SLOT(showMessage(QString))); #endif QTimer::singleShot(0, &cmd, &Kleo::Command::start); // start() may Q_EMIT finished()... loop.exec(); if (cmd.isCanceled()) { #ifndef QT_NO_SPLASHSCREEN splash.showMessage(i18nc("did not pass", "Self-Check Failed")); #endif return false; } else { #ifndef QT_NO_SPLASHSCREEN splash.showMessage(i18n("Self-Check Passed")); #endif return true; } } static void fillKeyCache(SplashScreen *splash, Kleo::UiServer *server) { QEventLoop loop; Kleo::ReloadKeysCommand *cmd = new Kleo::ReloadKeysCommand(0); QObject::connect(cmd, &Kleo::Commands::SelfTestCommand::finished, &loop, &QEventLoop::quit); #ifdef HAVE_USABLE_ASSUAN QObject::connect(cmd, SIGNAL(finished()), server, SLOT(enableCryptoCommands())); #else Q_UNUSED(server); #endif #ifndef QT_NO_SPLASHSCREEN splash->showMessage(i18n("Loading certificate cache...")); #else Q_UNUSED(splash); #endif cmd->start(); loop.exec(); #ifndef QT_NO_SPLASHSCREEN splash->showMessage(i18n("Certificate cache loaded.")); #endif } int main(int argc, char **argv) { KleopatraApplication app(argc, argv); app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); QTime timer; timer.start(); KLocalizedString::setApplicationDomain("kleopatra"); KDBusService service(KDBusService::Unique); QObject::connect(&service, &KDBusService::activateRequested, &app, &KleopatraApplication::slotActivateRequested); QObject::connect(&app, &KleopatraApplication::setExitValue, &service, [&service](int i) { service.setExitValue(i); }); AboutData aboutData; KAboutData::setApplicationData(aboutData); QCommandLineParser parser; aboutData.setupCommandLine(&parser); kleopatra_options(&parser); parser.process(QApplication::arguments()); aboutData.processCommandLine(&parser); Kdelibs4ConfigMigrator migrate(QStringLiteral("kleopatra")); migrate.setConfigFiles(QStringList() << QStringLiteral("kleopatrarc")); migrate.setUiFiles(QStringList() << QStringLiteral("kleopatra.rc")); migrate.migrate(); qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: Application created"; // Initialize GpgME const GpgME::Error gpgmeInitError = GpgME::initializeLibrary(0); { const unsigned int threads = QThreadPool::globalInstance()->maxThreadCount(); QThreadPool::globalInstance()->setMaxThreadCount(qMax(2U, threads)); } if (gpgmeInitError) { KMessageBox::sorry(0, xi18nc("@info", "The version of the GpgME library you are running against " "is older than the one that the GpgME++ library was built against." "Kleopatra will not function in this setting." "Please ask your administrator for help in resolving this issue."), i18nc("@title", "GpgME Too Old")); return EXIT_FAILURE; } SplashScreen splash; - const QString installPath = Kleo::gpg4winInstallPath(); - Kleo::ChecksumDefinition::setInstallPath(installPath); - Kleo::ArchiveDefinition::setInstallPath(installPath); + Kleo::ChecksumDefinition::setInstallPath(Kleo::gpg4winInstallPath()); + Kleo::ArchiveDefinition::setInstallPath(Kleo::gnupgInstallPath()); int rc; #ifdef HAVE_USABLE_ASSUAN try { Kleo::UiServer server(parser.value(QStringLiteral("uiserver-socket"))); qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: UiServer created"; QObject::connect(&server, &Kleo::UiServer::startKeyManagerRequested, &app, &KleopatraApplication::openOrRaiseMainWindow); QObject::connect(&server, &Kleo::UiServer::startConfigDialogRequested, &app, &KleopatraApplication::openOrRaiseConfigDialog); #define REGISTER( Command ) server.registerCommandFactory( boost::shared_ptr( new Kleo::GenericAssuanCommandFactory ) ) REGISTER(CreateChecksumsCommand); REGISTER(DecryptCommand); REGISTER(DecryptFilesCommand); REGISTER(DecryptVerifyFilesCommand); REGISTER(EchoCommand); REGISTER(EncryptCommand); REGISTER(EncryptFilesCommand); REGISTER(EncryptSignFilesCommand); REGISTER(ImportFilesCommand); REGISTER(PrepEncryptCommand); REGISTER(PrepSignCommand); REGISTER(SelectCertificateCommand); REGISTER(SignCommand); REGISTER(SignEncryptFilesCommand); REGISTER(SignFilesCommand); #ifndef QT_NO_DIRMODEL REGISTER(VerifyChecksumsCommand); #endif // QT_NO_DIRMODEL REGISTER(VerifyCommand); REGISTER(VerifyFilesCommand); #undef REGISTER server.start(); qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: UiServer started"; #endif const bool daemon = parser.isSet(QStringLiteral("daemon")); if (!daemon && app.isSessionRestored()) { app.restoreMainWindow(); } #ifndef QT_NO_SPLASHSCREEN // Don't show splash screen if daemon or session restore if (!(daemon || app.isSessionRestored())) { splash.show(); } #endif if (!selfCheck(splash)) { return 1; } qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: SelfCheck completed"; #ifdef HAVE_USABLE_ASSUAN fillKeyCache(&splash, &server); #else fillKeyCache(&splash, 0); #endif qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: KeyCache loaded"; #ifndef QT_NO_SYSTEMTRAYICON app.startMonitoringSmartCard(); #endif app.setIgnoreNewInstance(false); if (!daemon) { const QString err = app.newInstance(parser); if (!err.isEmpty()) { std::cerr << i18n("Invalid arguments: %1", err).toLocal8Bit().constData() << "\n"; exit(1); } qCDebug(KLEOPATRA_LOG) << "Startup timing:" << timer.elapsed() << "ms elapsed: new instance created"; #ifndef QT_NO_SPLASHSCREEN splash.finish(app.mainWindow()); #endif // QT_NO_SPLASHSCREEN } rc = app.exec(); #ifdef HAVE_USABLE_ASSUAN app.setIgnoreNewInstance(true); QObject::disconnect(&server, &Kleo::UiServer::startKeyManagerRequested, &app, &KleopatraApplication::openOrRaiseMainWindow); QObject::disconnect(&server, &Kleo::UiServer::startConfigDialogRequested, &app, &KleopatraApplication::openOrRaiseConfigDialog); server.stop(); server.waitForStopped(); } catch (const std::exception &e) { QMessageBox::information(0, i18n("GPG UI Server Error"), i18n("The Kleopatra GPG UI Server Module could not be initialized.
" "The error given was: %1
" "You can use Kleopatra as a certificate manager, but cryptographic plugins that " "rely on a GPG UI Server being present might not work correctly, or at all.
", QString::fromUtf8(e.what()).toHtmlEscaped())); #ifndef QT_NO_SYSTEMTRAYICON app.startMonitoringSmartCard(); #endif app.setIgnoreNewInstance(false); rc = app.exec(); app.setIgnoreNewInstance(true); } #endif return rc; } diff --git a/utils/gnupg-helper.cpp b/utils/gnupg-helper.cpp index c7ffdbde6..92261532f 100644 --- a/utils/gnupg-helper.cpp +++ b/utils/gnupg-helper.cpp @@ -1,148 +1,174 @@ /* -*- mode: c++; c-basic-offset:4 -*- utils/gnupg-helper.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "gnupg-helper.h" #include "utils/hex.h" #include #include "kleopatra_debug.h" #include #include #include #include #include #include +#include #include #ifdef Q_OS_WIN #include "gnupg-registry.h" #endif // Q_OS_WIN QString Kleo::gnupgHomeDirectory() { #ifdef Q_OS_WIN return QFile::decodeName(default_homedir()); #else const QByteArray gnupgHome = qgetenv("GNUPGHOME"); if (!gnupgHome.isEmpty()) { return QFile::decodeName(gnupgHome); } else { return QDir::homePath() + QLatin1String("/.gnupg"); } #endif } int Kleo::makeGnuPGError(int code) { return gpg_error(static_cast(code)); } static QString findGpgExe(GpgME::Engine engine, const QString &exe) { const GpgME::EngineInfo info = GpgME::engineInfo(engine); return info.fileName() ? QFile::decodeName(info.fileName()) : QStandardPaths::findExecutable(exe); } QString Kleo::gpgConfPath() { return findGpgExe(GpgME::GpgConfEngine, QStringLiteral("gpgconf")); } QString Kleo::gpgSmPath() { return findGpgExe(GpgME::GpgSMEngine, QStringLiteral("gpgsm")); } QString Kleo::gpgPath() { return findGpgExe(GpgME::GpgEngine, QStringLiteral("gpg")); } QStringList Kleo::gnupgFileBlacklist() { return QStringList() << QStringLiteral("dirmngr-cache.d") << QStringLiteral("S.uiserver") << QStringLiteral("S.gpg-agent") << QStringLiteral("random_seed") << QStringLiteral("*~") << QStringLiteral("*.bak") << QStringLiteral("*.lock") << QStringLiteral("*.tmp") << QStringLiteral("reader_*.status") ; } QString Kleo::gpg4winInstallPath() +{ +#ifdef Q_OS_WIN + // QApplication::applicationDirPath is only used as a fallback + // to support the case where Kleopatra is not installed from + // Gpg4win but Gpg4win is also installed. + char *instDir = read_w32_registry_string("HKEY_LOCAL_MACHINE", + "Software/GPG4Win", + "Install Directory"); + if (!instDir) { + // Fallback to HKCU + instDir = read_w32_registry_string("HKEY_CURRENT_USER", + "Software/GPG4Win", + "Install Directory"); + } + if (instDir) { + QString ret = QString::fromLocal8Bit(instDir) + QStringLiteral("/bin"); + free(instDir); + return ret; + } + qCDebug(KLEOPATRA_LOG) << "Gpg4win not found. Falling back to Kleopatra instdir."; +#endif + return QCoreApplication::applicationDirPath(); +} + +QString Kleo::gnupgInstallPath() { return gpgConfListDir("bindir"); } QString Kleo::gpgConfListDir(const char *which) { if (!which || !*which) { return QString(); } const QString gpgConfPath = Kleo::gpgConfPath(); if (gpgConfPath.isEmpty()) { return QString(); } QProcess gpgConf; qCDebug(KLEOPATRA_LOG) << "gpgConfListDir: starting " << qPrintable(gpgConfPath) << " --list-dirs"; gpgConf.start(gpgConfPath, QStringList() << QStringLiteral("--list-dirs")); if (!gpgConf.waitForFinished()) { qCDebug(KLEOPATRA_LOG) << "gpgConfListDir(): failed to execute gpgconf: " << qPrintable(gpgConf.errorString()); qCDebug(KLEOPATRA_LOG) << "output was:" << endl << gpgConf.readAllStandardError().constData(); return QString(); } const QList lines = gpgConf.readAllStandardOutput().split('\n'); Q_FOREACH (const QByteArray &line, lines) if (line.startsWith(which) && line[qstrlen(which)] == ':') { const int begin = qstrlen(which) + 1; int end = line.size(); while (end && (line[end - 1] == '\n' || line[end - 1] == '\r')) { --end; } const QString result = QDir::fromNativeSeparators(QFile::decodeName(hexdecode(line.mid(begin, end - begin)))); qCDebug(KLEOPATRA_LOG) << "gpgConfListDir: found " << qPrintable(result) << " for '" << which << "'entry"; return result; } qCDebug(KLEOPATRA_LOG) << "gpgConfListDir(): didn't find '" << which << "'" << "entry in output:" << endl << gpgConf.readAllStandardError().constData(); return QString(); } diff --git a/utils/gnupg-helper.h b/utils/gnupg-helper.h index 0238321c8..574003187 100644 --- a/utils/gnupg-helper.h +++ b/utils/gnupg-helper.h @@ -1,56 +1,57 @@ /* -*- mode: c++; c-basic-offset:4 -*- utils/gnupg-helper.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_GNUPGHELPER_H__ #define __KLEOPATRA_GNUPGHELPER_H__ class QString; class QStringList; namespace Kleo { QString gnupgHomeDirectory(); QString gpgConfPath(); QString gpgSmPath(); QString gpgPath(); QString gpgConfListDir(const char *which); QString gpg4winInstallPath(); +QString gnupgInstallPath(); QStringList gnupgFileBlacklist(); int makeGnuPGError(int code); } #endif // __KLEOPATRA_GNUPGHELPER_H__