diff --git a/src/gpgcardgui/gpgcardgui-options.h b/src/gpgcardgui/gpgcardgui-options.h index 24482c7..c65a01b 100644 --- a/src/gpgcardgui/gpgcardgui-options.h +++ b/src/gpgcardgui/gpgcardgui-options.h @@ -1,29 +1,29 @@ /* Copyright (C) 2020 by g10 Code GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #pragma once #include #include /** @file Commandline options*/ static void options(QCommandLineParser &parser) { QList options; options << QCommandLineOption(QStringList() << QStringLiteral("debug"), QStringLiteral("Print debug output.")) << QCommandLineOption(QStringLiteral("lang"), QStringLiteral("Language"), QStringLiteral("Language to be used e.g. de_DE")) ; for (const auto &opt: options) { parser.addOption(opt); } parser.addVersionOption(); parser.addHelpOption(); } diff --git a/src/gpgcardgui/gpgcardgui.cpp b/src/gpgcardgui/gpgcardgui.cpp index 8cf96bd..41b2208 100644 --- a/src/gpgcardgui/gpgcardgui.cpp +++ b/src/gpgcardgui/gpgcardgui.cpp @@ -1,24 +1,24 @@ /* Copyright (C) 2020 by g10 Code GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "gpgcardgui.h" #include "mainwindow.h" GpgCardGUI::GpgCardGUI(int &argc, char *argv[]): QApplication(argc, argv) { mMainWin = new MainWindow(); } GpgCardGUI::~GpgCardGUI() { delete mMainWin; } void GpgCardGUI::showWindow() { mMainWin->show(); } diff --git a/src/gpgcardgui/gpgcardgui.h b/src/gpgcardgui/gpgcardgui.h index d64fa2d..41a630e 100644 --- a/src/gpgcardgui/gpgcardgui.h +++ b/src/gpgcardgui/gpgcardgui.h @@ -1,34 +1,34 @@ /* Copyright (C) 2020 by g10 Code GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #pragma once #include #include class MainWindow; /** @brief Resolver Application entry point. * * The GpgCardGUI exists to serve as a frontend * for gpgcard. It is written in a way that the * widgets are reusable in other applications. With * the goal to move most of the code to libkleo. * * This is the global qApp singleton. */ class GpgCardGUI: public QApplication { Q_OBJECT public: explicit GpgCardGUI(int &argc, char *argv[]); ~GpgCardGUI(); void showWindow(); private: MainWindow *mMainWin; }; diff --git a/src/gpgcardgui/main.cpp b/src/gpgcardgui/main.cpp index 626ea0e..409bb84 100644 --- a/src/gpgcardgui/main.cpp +++ b/src/gpgcardgui/main.cpp @@ -1,81 +1,81 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ /** @file Main entry point for the application. */ #include "strhelp.h" #include "gpgcardgui.h" #include #include #include #include #include #include #include #include #ifndef APPNAME #define APPNAME "GpgCardGUI" #endif #ifndef VERSION #define VERSION "0.0" #endif #include "gpgcardgui-options.h" bool g_debug = false; QtMessageHandler g_default_msg_handler = NULL; void filterDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { if (!g_debug && type == QtDebugMsg) { return; } if (g_default_msg_handler) { (*g_default_msg_handler)(type, context, msg); } } /** @brief The real entry point to the application. * * @param [in] argc the count of the arguments. * @param [in] argv On GNU/Linux this function expects argv to be in the * native system encoding. On Windows the arguments * shall be UTF-8 * * @returns 0 on success an error code otherwise. */ int main(int argc, char **argv) { /* QApplication setup */ GpgCardGUI app(argc, argv); QApplication::setOrganizationName(QStringLiteral(APPNAME)); QApplication::setApplicationName(QStringLiteral(APPNAME)); QApplication::setApplicationVersion(QStringLiteral(VERSION)); /* Parse the command line */ QCommandLineParser parser; options(parser); parser.process (app); const auto lang = parser.value("lang"); g_debug = parser.isSet("debug"); g_default_msg_handler = qInstallMessageHandler(filterDebugOutput); if (!lang.isEmpty()) { qputenv("LANG", lang.toUtf8()); } app.showWindow(); /* Start the main event loop */ return app.exec(); } diff --git a/src/gpgcardgui/mainwindow.cpp b/src/gpgcardgui/mainwindow.cpp index c7071f8..fd5ef4a 100644 --- a/src/gpgcardgui/mainwindow.cpp +++ b/src/gpgcardgui/mainwindow.cpp @@ -1,39 +1,39 @@ /* Copyright (C) 2020 by g10 Code GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "mainwindow.h" #include #include #include #include #include #include "w32-gettext.h" MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags): QMainWindow(parent, flags) { mEdit = new QTextEdit (this); mEdit->setReadOnly(true); setCentralWidget(mEdit); connect (&mManager, &Kleo::SmartCard::CardManager::cardsMayHaveChanged, this, [this] () { const auto cards = mManager.cards(); for (const auto card: cards) { if (card) { mEdit->setText(mEdit->toPlainText() + "\nFound smartcard" + QString::fromStdString(card->serialNumber()) + "\nIn Reader: " + card->reader()); } } }); mManager.startCardList(); } diff --git a/src/gpgcardgui/mainwindow.h b/src/gpgcardgui/mainwindow.h index 1659c0f..ff5ecbd 100644 --- a/src/gpgcardgui/mainwindow.h +++ b/src/gpgcardgui/mainwindow.h @@ -1,26 +1,26 @@ /* Copyright (C) 2020 by g10 Code GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #pragma once #include #include class QTextEdit; /** MainWindow of the application. */ class MainWindow: public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags()); private: QTextEdit *mEdit; Kleo::SmartCard::CardManager mManager; }; diff --git a/src/gpgolconfig/cryptoconfigpage.cpp b/src/gpgolconfig/cryptoconfigpage.cpp index e6beac7..992da60 100644 --- a/src/gpgolconfig/cryptoconfigpage.cpp +++ b/src/gpgolconfig/cryptoconfigpage.cpp @@ -1,134 +1,134 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "cryptoconfigpage.h" #include #include #include #include #include #include #include #include void clearLayout(QLayout* layout, bool deleteWidgets = true) { while (QLayoutItem* item = layout->takeAt(0)) { if (deleteWidgets) { if (QWidget* widget = item->widget()) widget->deleteLater(); } if (QLayout* childLayout = item->layout()) clearLayout(childLayout, deleteWidgets); delete item; } } class DelayLoader: public QThread { Q_OBJECT void run() override { QGpgME::CryptoConfig *config = QGpgME::cryptoConfig(); /* Grab an entry to force the load */ auto entry = config->entry(QStringLiteral("gpg"), QStringLiteral("Keyserver"), QStringLiteral("keyserver")); Q_UNUSED(entry); emit resultReady(config); deleteLater(); } signals: void resultReady(QGpgME::CryptoConfig *config); }; void CryptoConfigPage::delayLoadFinished(QGpgME::CryptoConfig *config) { mConfigWidget = new Kleo::CryptoConfigModule(config, Kleo::CryptoConfigModule::TabbedLayout); auto lay = layout(); clearLayout(lay, true); delete lay; auto newLay = new QVBoxLayout(this); newLay->addWidget(mConfigWidget); connect(mConfigWidget, &Kleo::CryptoConfigModule::changed, this, [this] () { mCryptoConfigChanged = true; }); } CryptoConfigPage::CryptoConfigPage(QWidget *parent): QWidget(parent), mConfigWidget(nullptr), mCryptoConfigChanged(false) { auto loader = new DelayLoader; auto vLay = new QVBoxLayout(this); auto bar = new QProgressBar; auto label = new QLabel; label->setText(QStringLiteral("

Loading module...

")); bar->setRange(0, 0); vLay->addStretch(1); auto subLay1 = new QVBoxLayout; auto subLay3 = new QHBoxLayout; subLay3->addStretch(0.5); subLay3->addWidget(label); subLay3->addStretch(1); subLay1->addLayout(subLay3); subLay1->addWidget(bar); auto subLay2 = new QHBoxLayout; subLay2->addStretch(0.1); subLay2->addLayout(subLay1); subLay2->addStretch(0.1); vLay->addLayout(subLay2); vLay->addStretch(1); connect(loader, SIGNAL(resultReady(QGpgME::CryptoConfig *)), this, SLOT(delayLoadFinished(QGpgME::CryptoConfig *))); /* connect(loader, &DelayLoader::resultReady, [this] (QGpgME::CryptoConfig *config) { qDebug() << "Creating config widget"; mConfigWidget = new Kleo::CryptoConfigModule(config, Kleo::CryptoConfigModule::TabbedLayout); delete layout(); auto newLay = new QVBoxLayout(this); newLay->addWidget(mConfigWidget); connect(mConfigWidget, &Kleo::CryptoConfigModule::changed, this, [this] () { mCryptoConfigChanged = true; }); }); */ loader->start(); } void CryptoConfigPage::save() { if (mConfigWidget && mCryptoConfigChanged) { mConfigWidget->save(); } } void CryptoConfigPage::defaults() { if (mConfigWidget) { mConfigWidget->defaults(); } } #include "cryptoconfigpage.moc" diff --git a/src/gpgolconfig/cryptoconfigpage.h b/src/gpgolconfig/cryptoconfigpage.h index 405d12a..7e3862e 100644 --- a/src/gpgolconfig/cryptoconfigpage.h +++ b/src/gpgolconfig/cryptoconfigpage.h @@ -1,41 +1,41 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #ifndef CRYPTOCONFIGPAGE_H #define CRYPTOCONFIGPAGE_H #include namespace Kleo { class CryptoConfigModule; } // namespace Kleo namespace QGpgME { class CryptoConfig; } class CryptoConfigPage: public QWidget { Q_OBJECT public: explicit CryptoConfigPage(QWidget *parent = nullptr); void save(); void load(); void defaults(); private Q_SLOTS: void delayLoadFinished(QGpgME::CryptoConfig *config); private: Kleo::CryptoConfigModule *mConfigWidget; bool mCryptoConfigChanged; }; #endif diff --git a/src/gpgolconfig/gpgolconfig-options.h b/src/gpgolconfig/gpgolconfig-options.h index 6cf371f..79250c7 100644 --- a/src/gpgolconfig/gpgolconfig-options.h +++ b/src/gpgolconfig/gpgolconfig-options.h @@ -1,41 +1,41 @@ #ifndef GPGOLCONFIG_OPTIONS #define GPGOLCONFIG_OPTIONS /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include /** @file Commandline options*/ static void options(QCommandLineParser &parser) { QList options; options << QCommandLineOption(QStringList() << QStringLiteral("debug"), QStringLiteral("Print debug output.")) << QCommandLineOption(QStringList() << QStringLiteral("w64"), QStringLiteral("GpgOL is a 64bit application.")) << QCommandLineOption(QStringLiteral("hwnd"), QStringLiteral("Parent Window"), QStringLiteral("windows window handle")) << QCommandLineOption(QStringLiteral("lang"), QStringLiteral("Language"), QStringLiteral("Language to be used e.g. de_DE")) << QCommandLineOption(QStringLiteral("gpgol-version"), QStringLiteral("Version string"), QStringLiteral("GpgOL's Version")) << QCommandLineOption(QStringLiteral("alwaysShow"), QStringLiteral("Should always be shown")); for (const auto &opt: options) { parser.addOption(opt); } parser.addVersionOption(); parser.addHelpOption(); } #endif diff --git a/src/gpgolconfig/gpgolconfig.cpp b/src/gpgolconfig/gpgolconfig.cpp index 5ccef1f..756d364 100644 --- a/src/gpgolconfig/gpgolconfig.cpp +++ b/src/gpgolconfig/gpgolconfig.cpp @@ -1,124 +1,124 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "gpgolconfig.h" #include "w32-gettext.h" #include "w32-util.h" #include "w32-qt-util.h" #include "gpgolconfigpage.h" #include "gpgoldebugpage.h" #include "cryptoconfigpage.h" #include #include #include #include #include #include #include #include #include #include GpgOLConfig::GpgOLConfig(const QCommandLineParser &parser): KPageDialog(nullptr) { setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint)); setWindowTitle(_("Configure GpgOL")); setWindowIcon(QIcon(":/gpgol-icon.svg")); const auto hwnd = parser.value(QStringLiteral("hwnd")); if (!hwnd.isEmpty()) { bool ok; WId id = (WId) hwnd.toInt(&ok); if (!ok) { qDebug() << "invalid hwnd value"; } else { W32::setupForeignParent(id, this, true); setModal(true); } } if (parser.isSet("gpgol-version")) { mVersion = parser.value("gpgol-version"); } else { mVersion = QStringLiteral("unknown version"); } setupGUI(); resize(800, 500); } void GpgOLConfig::setupGUI() { setFaceType(KPageDialog::List); QDialogButtonBox *buttonBox = new QDialogButtonBox(); buttonBox->setStandardButtons(QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Cancel | QDialogButtonBox::Ok); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Ok), KStandardGuiItem::ok()); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel()); KGuiItem::assign(buttonBox->button(QDialogButtonBox::RestoreDefaults), KStandardGuiItem::defaults()); setButtonBox(buttonBox); bool hideCryptoConf = strToBool(W32::readRegStr(nullptr, GPGOL_REG_PATH, "hideCryptoConfig"), false); auto cryptoConfWidget = hideCryptoConf ? nullptr : new CryptoConfigPage; auto gpgolConfWidget = new GpgOLConfigPage; auto gpgolDbgWidget = new GpgOLDebugPage; connect(buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, this, [this, cryptoConfWidget, gpgolConfWidget, gpgolDbgWidget] () { if (cryptoConfWidget) { cryptoConfWidget->save(); } gpgolConfWidget->save(); gpgolDbgWidget->save(); close(); }); connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, this, [this, cryptoConfWidget, gpgolConfWidget, gpgolDbgWidget] () { if (currentPage()->widget() == cryptoConfWidget) { cryptoConfWidget->defaults(); } else if (currentPage()->widget() == gpgolConfWidget){ gpgolConfWidget->defaults(); } else if (currentPage()->widget() == gpgolDbgWidget){ gpgolDbgWidget->defaults(); } }); connect(buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, this, [this] () { close(); }); KPageWidgetItem *page = new KPageWidgetItem(gpgolConfWidget, _("GpgOL")); page->setHeader(QStringLiteral("%1 - %2%3").arg(_("Configure GpgOL")).arg( _("Version ")).arg(mVersion)); page->setIcon(QIcon(":/gpgol-icon.svg")); addPage(page); if (cryptoConfWidget) { page = new KPageWidgetItem(cryptoConfWidget, QStringLiteral("%1\n%2").arg(_("GnuPG System")).arg(_("(Technical)"))); page->setHeader(_("Configuration of GnuPG System options")); page->setIcon(QIcon::fromTheme("document-encrypt")); addPage(page); } page = new KPageWidgetItem(gpgolDbgWidget, _("Debug")); page->setHeader(_("Configuration of debug options")); page->setIcon(QIcon::fromTheme("tools-report-bug")); addPage(page); } diff --git a/src/gpgolconfig/gpgolconfig.h b/src/gpgolconfig/gpgolconfig.h index c40d1a4..aca33ff 100644 --- a/src/gpgolconfig/gpgolconfig.h +++ b/src/gpgolconfig/gpgolconfig.h @@ -1,30 +1,30 @@ #ifndef GPGOLCONFIG_H #define GPGOLCONFIG_H /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include class QCommandLineParser; class GpgOLConfig: public KPageDialog { Q_OBJECT public: GpgOLConfig(const QCommandLineParser &parser); protected: /** @brief UI setup */ void setupGUI(); private: bool mCryptoConfigChanged; QString mVersion; }; #endif // GPGOLCONFIG_H diff --git a/src/gpgolconfig/gpgolconfigpage.cpp b/src/gpgolconfig/gpgolconfigpage.cpp index df8ecf3..b50c59c 100644 --- a/src/gpgolconfig/gpgolconfigpage.cpp +++ b/src/gpgolconfig/gpgolconfigpage.cpp @@ -1,347 +1,347 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "gpgolconfigpage.h" #include "w32-gettext.h" #include "w32-util.h" #include #include #include #include #include #include #include #include #include #include class SecretKeyFilter: public Kleo::DefaultKeyFilter { public: SecretKeyFilter(): Kleo::DefaultKeyFilter() { setHasSecret(Kleo::DefaultKeyFilter::Set); setRevoked(Kleo::DefaultKeyFilter::NotSet); setDisabled(Kleo::DefaultKeyFilter::NotSet); setExpired(Kleo::DefaultKeyFilter::NotSet); setCanEncrypt(Kleo::DefaultKeyFilter::Set); } }; static auto s_secretKeyFilter = std::shared_ptr (new SecretKeyFilter); /* class ExplainingChkBox: public QWidget { Q_OBJECT public: explicit ExplainingChkBox(const QString &text, const QString &explanation): mChkBox(new QCheckBox(text)), mExplanation(explanation) { auto hBox = new QHBoxLayout(this); hBox->addWidget(mChkBox); auto infoBtn = new QPushButton; infoBtn->setIcon(QIcon::fromTheme("help-contextual")); hBox->addWidget(infoBtn); hBox->addStretch(1); connect(infoBtn, &QPushButton::clicked, this, [this, infoBtn] () { QToolTip::showText(infoBtn->mapToGlobal(QPoint()), mExplanation, infoBtn); }); } void setChecked(bool value) { mChkBox->setChecked(value); } private: QCheckBox *mChkBox; QString mExplanation; }; */ GpgOLConfigPage::GpgOLConfigPage(QWidget *parent): QWidget(parent) { setupGUI(); load(); } /* Helper to build an "About" style layout. static QLayout *buildAboutLayout(const QString &version) { auto hLay = new QHBoxLayout; auto vLay = new QVBoxLayout; hLay->addLayout(vLay); hLay->addStretch(1); auto iconLbl = new QLabel; iconLbl->setPixmap(QIcon(":/gpgol-logo.png").pixmap(128, 80)); auto versionLbl = new QLabel(QStringLiteral(" ") + QString::fromUtf8(_("Version ")) + version); vLay->addWidget(iconLbl); vLay->addWidget(versionLbl); return hLay; } */ void GpgOLConfigPage::setupGUI() { auto baseLay = new QVBoxLayout(this); mSMIMEGrp = new QGroupBox(_("Enable the S/MIME support")); mSMIMEGrp->setCheckable(true); mSMIMEGrp->setAlignment(Qt::AlignLeft); auto smimeLay = new QVBoxLayout(mSMIMEGrp); mPreferSMIMEChk = new QCheckBox(_("&Prefer S/MIME")); mPreferSMIMEChk->setToolTip(_("Prefer S/MIME over OpenPGP if both are possible.")); smimeLay->addWidget(mPreferSMIMEChk); mSearchSMIMEChk = new QCheckBox(_("Search and import &X509 certificates in the configured directory services")); mSearchSMIMEChk->setToolTip(_("Searches for X509 certificates automatically and imports them. This option searches in all configured services.")); mSearchSMIMEWarning = new QLabel(_("Warning: The configured services will receive information about whom you send Emails!")); smimeLay->addWidget(mSearchSMIMEChk); smimeLay->addWidget(mSearchSMIMEWarning); connect(mSearchSMIMEChk, &QCheckBox::toggled, [this] (bool on) { mSearchSMIMEWarning->setVisible(on); }); baseLay->addWidget(mSMIMEGrp); // The general group auto generalGrp = new QGroupBox(_("General")); auto generalLay = new QVBoxLayout(generalGrp); generalGrp->setAlignment(Qt::AlignLeft); mAlwaysSigChk = new QCheckBox(_("&Sign new messages by default")); mAlwaysSigChk->setToolTip(_("Toggles the sign option for all new mails.")); mAlwaysEncChk = new QCheckBox(_("&Encrypt new messages by default")); mAlwaysEncChk->setToolTip(_("Toggles the encrypt option for all new mails.")); mReplyCryptChk = new QCheckBox(_("S&elect crypto settings automatically " "for reply and forward")); mReplyCryptChk->setToolTip(_("Toggles sign, encrypt options if the original mail was signed or encrypted.")); mInlinePGPChk = new QCheckBox(_("&Send OpenPGP mails without attachments as PGP/Inline")); mInlinePGPChk->setToolTip(_("Instead of using the PGP/MIME format, " "which properly handles attachments and encoding, " "the deprecated PGP/Inline is used.\n" "This can be useful for compatibility but should generally not " "be used.")); mAlwaysShowApprovalChk = new QCheckBox(QString::fromUtf8(_("&Always show security approval dialog."))); mAlwaysShowApprovalChk->setToolTip(_("Always show the security approval and certificate selection dialog. " "This slows down the encryption / signing process, especially with large keyrings.")); generalLay->addWidget(mAlwaysSigChk); generalLay->addWidget(mAlwaysEncChk); generalLay->addWidget(mReplyCryptChk); generalLay->addWidget(mInlinePGPChk); generalLay->addWidget(mAlwaysShowApprovalChk); // The draft encryption part mDraftEncChk = new QCheckBox(QStringLiteral("(%1) ").arg(QString::fromUtf8(_("experimental"))) + QString::fromUtf8(_("Encrypt &drafts of secure mails to this key:"))); mDraftEncChk->setToolTip(_("Encrypt drafts and autosaved mails if the secure button is toggled.")); mDraftKey = new Kleo::KeySelectionCombo (false); mDraftKey->setKeyFilter(s_secretKeyFilter); auto draftLay = new QHBoxLayout; draftLay->addWidget(mDraftEncChk); draftLay->addWidget(mDraftKey); generalLay->addLayout(draftLay); baseLay->addWidget(generalGrp); // The automation checkboxes mAutomationGrp = new QGroupBox(_("Automation")); mAutomationGrp->setToolTip(_("Enable or disable any automated key handling.")); auto autoLayout = new QVBoxLayout(mAutomationGrp); mAutomationGrp->setCheckable(true); mAutoImportChk = new QCheckBox(_("&Import any keys included in mails")); mAutoImportChk->setToolTip(_("Import OpenPGP keys from mail attachments or from mail headers.")); autoLayout->addWidget(mAutoImportChk); mAutoResolveChk = new QCheckBox(_("&Resolve recipient keys automatically")); autoLayout->addWidget(mAutoResolveChk); mAutoSecureChk = new QCheckBox(_("Automatically secure &messages")); mAutoSecureChk->setToolTip(_("Automatically toggles secure if keys with at least level 1 trust were found for all recipients.")); mAutoEncryptUntrustedChk = new QCheckBox(_("Also &with untrusted keys")); mAutoEncryptUntrustedChk->setToolTip(_("Also automatically toggles secure if keys with level 0 trust were found.")); auto subLay = new QHBoxLayout; subLay->addSpacing(20); subLay->addWidget(mAutoSecureChk); subLay->addWidget(mAutoEncryptUntrustedChk); autoLayout->addLayout(subLay); mAutoTrustChk = new QCheckBox(QStringLiteral("%1 (%2)").arg(_("Include OpenPGP &trust based on communication history")).arg(_("experimental"))); mAutoTrustChk->setToolTip(_("This changes the trust model to \"tofu+pgp\" which tracks the history of key usage. " "Automated trust can never exceed level 2.")); /* Dsiabled for now */ mAutoTrustChk->setVisible(false); autoLayout->addWidget(mAutoTrustChk); baseLay->addWidget(mAutomationGrp); // baseLay->addLayout(buildAboutLayout(mVersion)); baseLay->addStretch(1); connect(mAutoResolveChk, &QCheckBox::toggled, [this] (bool on) { mAutoSecureChk->setEnabled(on); mAutoEncryptUntrustedChk->setEnabled(mAutoSecureChk->isChecked()); mSearchSMIMEChk->setEnabled(mSMIMEGrp->isChecked() && on); }); connect(mAutoSecureChk, &QCheckBox::toggled, [this] (bool on) { mAutoEncryptUntrustedChk->setEnabled(on); }); connect(mSMIMEGrp, &QGroupBox::toggled, [this] (bool on) { mSearchSMIMEChk->setEnabled(mAutoResolveChk->isChecked() && on); }); connect (mDraftEncChk, &QCheckBox::toggled, [this] (bool on) { mDraftKey->setEnabled(on); }); } static bool loadBool(const char *name, bool defaultVal) { return strToBool(W32::readRegStr(nullptr, GPGOL_REG_PATH, name), defaultVal); } /* Bump this if you remove a config value */ #define CONFIG_VERSION "1" static const QMap defaultMap { { QStringLiteral("enableSmime"), false }, { QStringLiteral("encryptDefault"), false }, { QStringLiteral("signDefault"), false }, { QStringLiteral("inlinePGP"), false }, { QStringLiteral("replyCrypt"), true }, { QStringLiteral("preferSmime"), false }, { QStringLiteral("debugGPGME"), false }, { QStringLiteral("automation"), true }, { QStringLiteral("autoresolve"), true }, { QStringLiteral("autosecure"), true }, { QStringLiteral("autotrust"), false }, { QStringLiteral("automation"), true }, { QStringLiteral("syncEnc"), false }, { QStringLiteral("searchSmimeServers"), false }, { QStringLiteral("autoimport"), false }, { QStringLiteral("autoencryptUntrusted"), false }, { QStringLiteral("draftEnc"), false }, { QStringLiteral("alwaysShowApproval"), false }, }; void GpgOLConfigPage::updateGUI(const QMap &values) { bool smimeEnabled = values["enableSmime"]; mSMIMEGrp->setChecked(smimeEnabled); mPreferSMIMEChk->setChecked(values["preferSmime"]); mSearchSMIMEChk->setChecked(values["searchSmimeServers"]); mSearchSMIMEWarning->setVisible(mSearchSMIMEChk->isChecked()); mAlwaysEncChk->setChecked(values["encryptDefault"]); mAlwaysSigChk->setChecked(values["signDefault"]); mInlinePGPChk->setChecked(values["inlinePGP"]); mReplyCryptChk->setChecked(values["replyCrypt"]); mDraftEncChk->setChecked(values["draftEnc"]); mAlwaysShowApprovalChk->setChecked(values["alwaysShowApproval"]); mAutomationGrp->setChecked(values["automation"]); mAutoSecureChk->setChecked(values["autosecure"]); mAutoTrustChk->setChecked(values["autotrust"]); mAutoResolveChk->setChecked(values["autoresolve"]); mAutoImportChk->setChecked(values["autoimport"]); mAutoEncryptUntrustedChk->setChecked(values["autoencryptUntrusted"]); mAutoSecureChk->setEnabled(mAutoResolveChk->isChecked() && mAutomationGrp->isChecked()); mAutoEncryptUntrustedChk->setEnabled(mAutoSecureChk->isChecked() && mAutomationGrp->isChecked()); mSearchSMIMEChk->setEnabled(mAutoResolveChk->isChecked() && smimeEnabled); } void GpgOLConfigPage::load() { QMap confValues; for (const auto &key: defaultMap.keys()) { confValues[key] = loadBool(key.toLocal8Bit().constData(), defaultMap[key]); } updateGUI(confValues); const std::string version = W32::readRegStr(nullptr, GPGOL_REG_PATH, "config-version"); if (version != CONFIG_VERSION) { qDebug() << "Config update. Cleaning old values"; } const std::string draftKeyFpr = W32::readRegStr(nullptr, GPGOL_REG_PATH, "draftKey"); if (!draftKeyFpr.empty()) { mDraftKey->setDefaultKey(QString::fromStdString(draftKeyFpr)); } } void GpgOLConfigPage::defaults() { updateGUI(defaultMap); } static void saveBool(const char *name, bool value) { const char *val = value ? "1" : "0"; if (!W32::writeRegStr(nullptr, GPGOL_REG_PATH, name, val)) { qWarning() << "Failed to write registry value for" << name; } } void GpgOLConfigPage::save() const { saveBool("enableSmime", mSMIMEGrp->isChecked()); saveBool("preferSmime", mPreferSMIMEChk->isChecked()); saveBool("searchSmimeServers", mSearchSMIMEChk->isChecked()); saveBool("encryptDefault", mAlwaysEncChk->isChecked()); saveBool("signDefault", mAlwaysSigChk->isChecked()); saveBool("inlinePGP", mInlinePGPChk->isChecked()); saveBool("replyCrypt", mReplyCryptChk->isChecked()); saveBool("draftEnc", mDraftEncChk->isChecked()); saveBool("alwaysShowApproval", mAlwaysShowApprovalChk->isChecked()); saveBool("automation", mAutomationGrp->isChecked()); saveBool("autosecure", mAutoSecureChk->isChecked()); saveBool("autotrust", mAutoTrustChk->isChecked()); saveBool("autoresolve", mAutoResolveChk->isChecked()); saveBool("autoencryptUntrusted", mAutoEncryptUntrustedChk->isChecked()); saveBool("autoimport", mAutoImportChk->isChecked()); W32::writeRegStr(nullptr, GPGOL_REG_PATH, "config-version", CONFIG_VERSION); const auto key = mDraftKey->currentKey(); if (!key.isNull()) { W32::writeRegStr(nullptr, GPGOL_REG_PATH, "draftKey", key.primaryFingerprint()); } } #include "gpgolconfigpage.moc" diff --git a/src/gpgolconfig/gpgolconfigpage.h b/src/gpgolconfig/gpgolconfigpage.h index 6a6ad64..9416295 100644 --- a/src/gpgolconfig/gpgolconfigpage.h +++ b/src/gpgolconfig/gpgolconfigpage.h @@ -1,58 +1,58 @@ #ifndef GPGOLCONFIGPAGE_H #define GPGOLCONFIGPAGE_H /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include #include class QGroupBox; class QCheckBox; class QLabel; class ExplainingChkBox; namespace Kleo { class KeySelectionCombo; } // namespace Kleo class GpgOLConfigPage: public QWidget { Q_OBJECT public: explicit GpgOLConfigPage(QWidget *parent = nullptr); void save() const; void load(); void defaults(); protected: void setupGUI(); void updateGUI(const QMap &values); private: QGroupBox *mSMIMEGrp, *mAutomationGrp; QLabel *mSearchSMIMEWarning; QCheckBox *mPreferSMIMEChk, *mAutoSecureChk, *mAlwaysEncChk, *mAlwaysSigChk, *mInlinePGPChk, *mAutoTrustChk, *mAutoResolveChk, *mReplyCryptChk, *mSearchSMIMEChk, *mAutoEncryptUntrustedChk, *mAutoImportChk, *mDraftEncChk, *mAlwaysShowApprovalChk; Kleo::KeySelectionCombo *mDraftKey; }; #endif diff --git a/src/gpgolconfig/gpgoldebugpage.cpp b/src/gpgolconfig/gpgoldebugpage.cpp index 15a5f58..cfc90e4 100644 --- a/src/gpgolconfig/gpgoldebugpage.cpp +++ b/src/gpgolconfig/gpgoldebugpage.cpp @@ -1,237 +1,237 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "gpgoldebugpage.h" #include "w32-gettext.h" #include "w32-util.h" #include #include #include #include #include #include #include #include #include #include #include #include #include /* See gpgol/src/debug.h */ #define DBG_OOM (1<<1) #define DBG_MEMORY (1<<2) #define DBG_TRACE (1<<3) #define DBG_DATA (1<<4) GpgOLDebugPage::GpgOLDebugPage(QWidget *parent): QWidget(parent) { setupGUI(); load(); } void GpgOLDebugPage::setupGUI() { auto baseLay = new QVBoxLayout(this); // The debugging group mDbgGrp = new QGroupBox(_("Enable Logging")); mDbgGrp->setCheckable(true); mDbgCombo = new QComboBox; mDbgCombo->addItem(_("Default"), 1); mDbgCombo->addItem(_("+Outlook API calls"), (DBG_OOM)); mDbgCombo->addItem(_("+Memory analysis"), (DBG_OOM | DBG_MEMORY)); mDbgCombo->addItem(_("+Call tracing"), (DBG_OOM | DBG_MEMORY | DBG_TRACE)); mDbgVerboseWarningLabel = new QLabel(_("Warning: Decreased performance. Huge logs!")); mDbgComboLabel = new QLabel(_("Log level:")); mDbgLogFileLabel = new QLabel(_("Log File (required):")); mDbgDataChk = new QCheckBox(_("Include Mail contents (decrypted!) and meta information.")); mDbgLogFileName = new QLineEdit; auto dbgLay = new QVBoxLayout(mDbgGrp); auto logFileLay = new QHBoxLayout; mDbgLogFileBtn = new QPushButton; mDbgLogFileBtn->setIcon(style()->standardIcon(QStyle::SP_FileDialogStart)); logFileLay->addWidget(mDbgLogFileLabel, 0); logFileLay->addWidget(mDbgLogFileName, 1); logFileLay->addWidget(mDbgLogFileBtn, 0); dbgLay->addLayout(logFileLay); auto dbgComboLay = new QHBoxLayout; dbgLay->addLayout(dbgComboLay); dbgComboLay->addWidget(mDbgComboLabel); dbgComboLay->addWidget(mDbgCombo); dbgComboLay->addWidget(mDbgVerboseWarningLabel); dbgComboLay->addStretch(1); dbgLay->addWidget(mDbgDataChk); baseLay->addWidget(mDbgGrp); connect(mDbgGrp, &QGroupBox::toggled, [this] (bool) { enableDisableDbgWidgets(); }); connect(mDbgCombo, &QComboBox::currentTextChanged, [this] (QString) { mDbgVerboseWarningLabel->setVisible((mDbgCombo->currentData().toInt() & DBG_TRACE)); }); connect(mDbgLogFileBtn, &QPushButton::clicked, [this] () { const auto fileName = QFileDialog::getSaveFileName(this, _("Select log file"), mDbgLogFileName->text(), "(*.txt)"); if (!fileName.isEmpty()) { mDbgLogFileName->setText(QDir::toNativeSeparators(fileName)); } }); enableDisableDbgWidgets(); // End debugging group auto othersGrp = new QGroupBox(_("Potential workarounds")); mSyncEncChk = new QCheckBox (_("Block Outlook during encrypt / sign")); mSyncDecChk = new QCheckBox (_("Block Outlook during decrypt / verify")); auto othersLay = new QVBoxLayout(othersGrp); othersLay->addWidget(mSyncDecChk); othersLay->addWidget(mSyncEncChk); baseLay->addWidget(othersGrp); auto bugReportLabel = new QLabel(QStringLiteral("%1").arg(_("How to report a problem?"))); bugReportLabel->setOpenExternalLinks(true); baseLay->addWidget(bugReportLabel); baseLay->addStretch(1); } static bool loadBool(const char *name, bool defaultVal) { return strToBool(W32::readRegStr(nullptr, GPGOL_REG_PATH, name), defaultVal); } static const QMap defaultMap { { QStringLiteral("syncEnc"), false }, { QStringLiteral("syncDec"), false }, }; void GpgOLDebugPage::updateGUI(const QMap &values) { mSyncDecChk->setChecked(values["syncDec"]); mSyncEncChk->setChecked(values["syncEnc"]); } void GpgOLDebugPage::load() { QMap confValues; for (const auto &key: defaultMap.keys()) { confValues[key] = loadBool(key.toLocal8Bit().constData(), defaultMap[key]); } updateGUI(confValues); const auto logFile = W32::readRegStr(nullptr, GPGOL_REG_PATH, "logFile"); mDbgLogFileName->setText(logFile.empty() ? QDir::toNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/gpgol.txt") : QString::fromStdString(logFile)); const auto logLevelS = W32::readRegStr(nullptr, GPGOL_REG_PATH, "enableDebug"); bool ok; int logLevel = QString::fromStdString(logLevelS).toInt(&ok); if (!ok) { logLevel = 0; } mDbgGrp->setChecked(logLevel > 0); int idx = 0; if ((logLevel & DBG_OOM)) { idx++; } if ((logLevel & DBG_MEMORY)) { idx++; } if ((logLevel & DBG_TRACE)) { idx++; } mDbgCombo->setCurrentIndex(idx); mDbgDataChk->setChecked((logLevel & DBG_DATA)); } void GpgOLDebugPage::defaults() { updateGUI(defaultMap); mDbgGrp->setChecked(false); } static void saveBool(const char *name, bool value) { const char *val = value ? "1" : "0"; if (!W32::writeRegStr(nullptr, GPGOL_REG_PATH, name, val)) { qWarning() << "Failed to write registry value for" << name; } } static void saveInt(const char *name, int value) { const std::string val = std::to_string(value); if (!W32::writeRegStr(nullptr, GPGOL_REG_PATH, name, val.c_str())) { qWarning() << "Failed to write registry value for" << name; } } void GpgOLDebugPage::save() const { saveBool("syncEnc", mSyncEncChk->isChecked()); saveBool("syncDec", mSyncDecChk->isChecked()); int logLevel = 0; if (mDbgGrp->isChecked()) { logLevel = mDbgCombo->currentData().toInt(); logLevel |= mDbgDataChk->isChecked() ? DBG_DATA : 0; } saveInt("enableDebug", logLevel); W32::writeRegStr(nullptr, GPGOL_REG_PATH, "logFile", QDir::toNativeSeparators( mDbgLogFileName->text()).toLocal8Bit().constData()); } void GpgOLDebugPage::enableDisableDbgWidgets() { bool vis = mDbgGrp->isChecked(); mDbgDataChk->setVisible(vis); mDbgCombo->setVisible(vis); mDbgComboLabel->setVisible(vis); mDbgLogFileName->setVisible(vis); mDbgLogFileLabel->setVisible(vis); mDbgLogFileBtn->setVisible(vis); mDbgVerboseWarningLabel->setVisible(vis && (mDbgCombo->currentData().toInt() & DBG_TRACE)); } #include "gpgoldebugpage.moc" diff --git a/src/gpgolconfig/gpgoldebugpage.h b/src/gpgolconfig/gpgoldebugpage.h index 5885309..48cf625 100644 --- a/src/gpgolconfig/gpgoldebugpage.h +++ b/src/gpgolconfig/gpgoldebugpage.h @@ -1,49 +1,49 @@ #ifndef GPGOLDEBUGPAGE_H #define GPGOLDEBUGPAGE_H /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include #include class QGroupBox; class QCheckBox; class QLabel; class QLineEdit; class QComboBox; class QPushButton; class GpgOLDebugPage: public QWidget { Q_OBJECT public: explicit GpgOLDebugPage(QWidget *parent = nullptr); void save() const; void load(); void defaults(); protected: void setupGUI(); void updateGUI(const QMap &values); void enableDisableDbgWidgets(); private: QGroupBox *mDbgGrp; QCheckBox *mSyncEncChk, *mSyncDecChk, *mDbgDataChk; QLineEdit *mDbgLogFileName; QLabel *mDbgLogFileLabel, *mDbgComboLabel, *mDbgVerboseWarningLabel; QComboBox *mDbgCombo; QPushButton *mDbgLogFileBtn; }; #endif diff --git a/src/gpgolconfig/main.cpp b/src/gpgolconfig/main.cpp index 549ae95..43e8e51 100644 --- a/src/gpgolconfig/main.cpp +++ b/src/gpgolconfig/main.cpp @@ -1,163 +1,163 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ /** @file Main entry point for the application. */ #include "strhelp.h" #include "gpgolconfig-options.h" #include "w32-gettext.h" #include "w32-util.h" #include "gpgolconfig.h" #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN #include #include #endif #ifndef APPNAME #define APPNAME "GpgOL" #endif #ifndef VERSION #define VERSION "0.0" #endif bool g_debug = false; QtMessageHandler g_default_msg_handler = NULL; void filterDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { if (!g_debug && type == QtDebugMsg) { return; } if (g_default_msg_handler) { (*g_default_msg_handler)(type, context, msg); } } int realMain(int argc, char **argv); #if defined(WIN32) && defined(UNICODE) /** @brief Unicode entry point. * * Converts arguments to UTF-8 and executes the real * entry point realMain. */ int wmain(int argc, wchar_t **argv, wchar_t **envp) { char **utf8args = NULL; utf8args = (char**) xmalloc0 ((argc + 1) * sizeof(char*)); for (int i = 0; i < argc; i++) { utf8args[i] = wchar_to_utf8(argv[i], wcslen(argv[i])); if (utf8args[i] == NULL) { printf ("Fatal: could not convert arguments to UTF-8.\n"); exit(-1); } } int ret = realMain(argc, utf8args); strv_free(utf8args); return ret; } #else int main(int argc, char **argv) { return realMain(argc, argv); } #endif /** @brief The real entry point to the application. * * @param [in] argc the count of the arguments. * @param [in] argv On GNU/Linux this function expects argv to be in the * native system encoding. On Windows the arguments * shall be UTF-8 * * @returns 0 on success an error code otherwise. */ int realMain(int argc, char **argv) { /* QApplication setup */ QApplication app(argc, argv); QApplication::setOrganizationName(QStringLiteral(APPNAME)); QApplication::setApplicationName(QStringLiteral(APPNAME)); QApplication::setApplicationVersion(QStringLiteral(VERSION)); #if 0 /* Setup translations */ QTranslator translator; if (QLocale::system().name() == "C") { /* Useful for testing / development as the primary target is german */ translator.load(":/l10n/main_de_DE"); } else { translator.load(":/l10n/main_" + QLocale::system().name()); } app.installTranslator(&translator); #endif /* Parse the command line */ QCommandLineParser parser; options(parser); #ifdef Q_OS_WIN auto oldCodec = QTextCodec::codecForLocale(); QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); #endif parser.process(app); #ifdef Q_OS_WIN QTextCodec::setCodecForLocale(oldCodec); #endif g_debug = parser.isSet("debug"); g_default_msg_handler = qInstallMessageHandler(filterDebugOutput); const auto lang = parser.value("lang"); if (!lang.isEmpty()) { qputenv("LANG", lang.toUtf8()); } // Initialize GpgME const GpgME::Error gpgmeInitError = GpgME::initializeLibrary(0); if (gpgmeInitError) { QMessageBox::critical(nullptr, QObject::tr("Installation Error"), QObject::tr("Could not initialize GPGME.") + "
" + QObject::tr("Please reinstall") + " " APPNAME "."); return EXIT_FAILURE; } // Initialize w32-gettext const auto localeDir = W32::getGpg4winLocaleDir(); if (!localeDir.empty()) { i18n_init("gpgol", localeDir.c_str()); } else { qDebug() << "No locale dir."; } GpgOLConfig mainWin(parser); mainWin.show(); app.exec(); return EXIT_SUCCESS; } diff --git a/src/gpgolkeyadder/gpgolkeyadder-options.h b/src/gpgolkeyadder/gpgolkeyadder-options.h index f4de06d..c6080d9 100644 --- a/src/gpgolkeyadder/gpgolkeyadder-options.h +++ b/src/gpgolkeyadder/gpgolkeyadder-options.h @@ -1,43 +1,43 @@ #ifndef GPGOLKEYADDER_OPTIONS #define GPGOLKEYADDER_OPTIONS /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include /** @file Commandline options*/ static void options(QCommandLineParser &parser) { QList options; options << QCommandLineOption(QStringList() << QStringLiteral("debug"), QStringLiteral("Print debug output.")) << QCommandLineOption(QStringList() << QStringLiteral("cms"), QStringLiteral("Add S/MIME settings")) << QCommandLineOption(QStringLiteral("hwnd"), QStringLiteral("Parent Window"), QStringLiteral("windows window handle")) << QCommandLineOption(QStringList() << QStringLiteral("sign"), QStringLiteral("Always sign")) << QCommandLineOption(QStringList() << QStringLiteral("encrypt"), QStringLiteral("Always enccrypt")) << QCommandLineOption(QStringLiteral("username"), QStringLiteral("Name"), QStringLiteral("username")) << QCommandLineOption(QStringLiteral("lang"), QStringLiteral("Language"), QStringLiteral("Language to be used e.g. de_DE")); for (const auto &opt: options) { parser.addOption(opt); } parser.addVersionOption(); parser.addHelpOption(); } #endif diff --git a/src/gpgolkeyadder/gpgolkeyadder.cpp b/src/gpgolkeyadder/gpgolkeyadder.cpp index 6b39824..f07aae5 100644 --- a/src/gpgolkeyadder/gpgolkeyadder.cpp +++ b/src/gpgolkeyadder/gpgolkeyadder.cpp @@ -1,565 +1,565 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "gpgolkeyadder.h" #include "w32-gettext.h" #include "w32-util.h" #include "w32-qt-util.h" #include "stdinreader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { static char **vector_to_cArray(const std::vector &vec) { char ** ret = (char**) malloc (sizeof (char*) * (vec.size() + 1)); for (size_t i = 0; i < vec.size(); i++) { ret[i] = strdup (vec[i].c_str()); } ret[vec.size()] = NULL; return ret; } static void release_cArray (char **carray) { if (carray) { for (int idx = 0; carray[idx]; idx++) { free (carray[idx]); } free (carray); } } class CMSImportThread: public QThread { Q_OBJECT public: explicit CMSImportThread(const GpgME::Data &data): mData(data) { } std::vector certs() { return mCerts; } std::string error() { return mError.asString(); } protected: void run() override { auto ctx = GpgME::Context::create(GpgME::CMS); if (!ctx) { qDebug () << "No ctx"; return; } const auto result = ctx->importKeys(mData); mError = result.error (); if (result.error ()) { qDebug() << "Import failed: " << result.error().asString(); } std::vector fingerprints; for (const auto import: result.imports()) { if (import.error()){ qDebug() << "Error importing:" << import.error().asString(); continue; } const char *fpr = import.fingerprint (); if (!fpr) { qDebug() << "Import with no fpr."; continue; } fingerprints.push_back (fpr); qDebug () << "imported: " << fpr; } if (!fingerprints.size()) { qDebug () << "Nothing imported"; return; } ctx = GpgME::Context::create(GpgME::CMS); ctx->setKeyListMode (GpgME::KeyListMode::Local | GpgME::KeyListMode::Validate); char **patterns = vector_to_cArray(fingerprints); mError = ctx->startKeyListing((const char**)patterns, false); release_cArray(patterns); if (mError) { qDebug() << "Failed to start keylisting err:" << mError.asString(); return; } GpgME::Error err; while (!err) { const auto key = ctx->nextKey(err); if (err || key.isNull()) { break; } mCerts.push_back(key); } return; } private: GpgME::Error mError; GpgME::Data mData; std::vector mCerts; }; } // Namespace GpgOLKeyAdder::GpgOLKeyAdder(const QCommandLineParser &parser): QDialog(nullptr), mEdit(new QTextEdit), mCMSEdit(new QTextEdit), mAlwaysSec(new QCheckBox) { setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint)); mName = parser.value(QStringLiteral("username")); mShowCMS = parser.isSet(QStringLiteral("cms")); setWindowTitle(_("GpgOL") + QStringLiteral(" - ") + _("Settings for:") + QStringLiteral(" ") + mName); setWindowIcon(QIcon(":/gpgol-icon.svg")); const auto hwnd = parser.value(QStringLiteral("hwnd")); if (!hwnd.isEmpty()) { bool ok; WId id = (WId) hwnd.toInt(&ok); if (!ok) { qDebug() << "invalid hwnd value"; } else { W32::setupForeignParent(id, this, true); setModal(true); } } mAlwaysSec->setChecked(parser.isSet("encrypt") && parser.isSet("sign")); /* FIXME: This should be implemented in GpgOL */ mAlwaysSec->setVisible(false); setupGUI(); // Deletes itself auto reader = new StdinReader; connect (reader, &StdinReader::stdinRead, this, [this] (const QByteArray &data) { if (data.size() > 1) { handleInput(data); } }); reader->start(); } void GpgOLKeyAdder::handleInput(const QByteArray &data) { const auto stringData = QString::fromUtf8(data); const auto splitData = stringData.split("BEGIN CMS DATA\n"); if (splitData.size() != 2) { qDebug() << "Failed to split data. Old GpgOL Version?"; mEdit->setPlainText(stringData); } else { mEdit->setPlainText(splitData[0].trimmed()); mCMSEdit->setPlainText(splitData[1].trimmed()); } } void GpgOLKeyAdder::setupGUI() { /* Setup Edits */ auto fixedFont = QFont("Monospace", 10); fixedFont.setStyleHint(QFont::TypeWriter); resize(QFontMetrics(fixedFont).averageCharWidth() * 80, QFontMetrics(fixedFont).height() * 30); mEdit->setFont(fixedFont); mEdit->setPlaceholderText(QString::fromUtf8(_("Paste a public key export here. It should look like:")) + QStringLiteral("\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n\n" "mQENBEzJavsBCADG/guWL6AxGgngUxp/DcmoitJjaJMqcJkBtD3uKrW81Pbnm3LI\n" "...\n" "dCl8hHggB9x2\n" "=oShe\n" "-----END PGP PUBLIC KEY BLOCK-----")); mEdit->setUndoRedoEnabled(true); mCMSEdit->setFont(fixedFont); mCMSEdit->setPlaceholderText(QString::fromUtf8(_("Paste certificates here. They should look like:")) + QStringLiteral("\n\n-----BEGIN CERTIFICATE-----\n\n" "MIICeDCCAeGgAwIBAgIJANNFIDoYY4XJMA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNV\n" "...\n" "dCl8hHggB9x2\n" "-----END CERTIFICATE-----")); mCMSEdit->setUndoRedoEnabled(true); /* Setup buttons */ QDialogButtonBox *buttonBox = new QDialogButtonBox(); buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); connect(buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, this, [this] () { checkAccept(); }); connect(buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, this, [this] () { qApp->quit(); }); auto okBtn = buttonBox->button(QDialogButtonBox::Ok); okBtn->setEnabled(false); connect(mEdit, &QTextEdit::textChanged, this, [this, okBtn] () { const auto text = mEdit->toPlainText().trimmed().toUtf8(); if (!text.size()) { okBtn->setEnabled(true); return; } GpgME::Data data(text.constData(), text.size(), false); okBtn->setEnabled(data.type() == GpgME::Data::PGPKey); }); connect(mCMSEdit, &QTextEdit::textChanged, this, [this, okBtn] () { const auto text = mCMSEdit->toPlainText().trimmed().toUtf8(); if (!text.size()) { okBtn->setEnabled(true); return; } GpgME::Data data(text.constData(), text.size(), false); okBtn->setEnabled(data.type() == GpgME::Data::X509Cert); }); /* The always secure box */ mAlwaysSec->setText(QString::fromUtf8(_("Always secure mails"))); /* Setup layout */ auto layout = new QVBoxLayout; setLayout(layout); layout->addWidget(mAlwaysSec); auto hBox = new QHBoxLayout; hBox->addWidget(new QLabel( _("Use these keys for this contact:"))); auto infoBtn = new QPushButton; infoBtn->setIcon(QIcon::fromTheme("help-contextual")); infoBtn->setFlat(true); hBox->addWidget(infoBtn); hBox->addStretch(1); connect(infoBtn, &QPushButton::clicked, this, [this, infoBtn] () { const QString generalMsg = QString::fromUtf8(_("You can use this to override the keys " "for this contact. The keys will be imported and used " "regardless of their trust level.")); const QString smimeMsg = QString::fromUtf8(_("For S/MIME the root certificate has to be trusted.")); const QString multiMsg = QString::fromUtf8(_("Place multiple keys in here to encrypt to all of them.")); QToolTip::showText(infoBtn->mapToGlobal(QPoint()) + QPoint(infoBtn->width(), 0), QStringLiteral("%1

%2").arg(generalMsg).arg( (mShowCMS ? smimeMsg + QStringLiteral("

") + multiMsg : multiMsg)), infoBtn, QRect(), 30000); }); layout->addLayout(hBox); if (mShowCMS) { auto tab = new QTabWidget; tab->addTab(mEdit, QStringLiteral("OpenPGP")); tab->addTab(mCMSEdit, QString::fromUtf8(_("S/MIME (X509 Certificates)"))); layout->addWidget(tab); } else { layout->addWidget(mEdit); } layout->addWidget(buttonBox); } void GpgOLKeyAdder::save() { std::cout << "BEGIN KEYADDER PGP DATA" << std::endl; const QByteArray &pgpData = mEdit->toPlainText().trimmed().toUtf8(); if (!pgpData.size()) { /* Empty is a special case which can mean that an * existing key should be removed. */ std::cout << "empty" << std::endl; } else { std::cout << pgpData.constData() << std::endl; } std::cout << "END KEYADDER PGP DATA" << std::endl; std::cout << "BEGIN KEYADDER CMS DATA" << std::endl; const QByteArray &cmsData = mCMSEdit->toPlainText().trimmed().toUtf8(); if (!cmsData.size()) { /* Empty is a special case which can mean that an * existing key should be removed. */ std::cout << "empty" << std::endl; } else { std::cout << cmsData.constData() << std::endl; } std::cout << "END KEYADDER CMS DATA" << std::endl; std::cout << "BEGIN KEYADDER OPTIONS" << std::endl; std::cout << "secure=" << (mAlwaysSec->isChecked() ? "3" : "0") << std::endl; std::cout << "END KEYADDER OPTIONS" << std::endl; qApp->quit(); } static QString prettyNameAndEMail(const QString &id, const QString &name, const QString &email, const QString &comment) { if (name.isEmpty()) { if (email.isEmpty()) { return QString(); } else if (comment.isEmpty()) { return QStringLiteral("<%1>").arg(email); } else { return QStringLiteral("(%2) <%1>").arg(email, comment); } } if (email.isEmpty()) { if (comment.isEmpty()) { return name; } else { return QStringLiteral("%1 (%2)").arg(name, comment); } } if (comment.isEmpty()) { return QStringLiteral("%1 <%2>").arg(name, email); } else { return QStringLiteral("%1 (%3) <%2>").arg(name, email, comment); } return QString(); } static QString prettyNameAndEMail(const char *id, const char *name_, const std::string &email_, const char *comment_) { return prettyNameAndEMail(QString::fromUtf8(id), QString::fromUtf8(name_), QString::fromStdString(email_), QString::fromUtf8(comment_)); } static QString prettyNameAndEMail(const GpgME::UserID &uid) { return prettyNameAndEMail(uid.id(), uid.name(), uid.addrSpec(), uid.comment()); } static QString time_t2string(time_t t) { QDateTime dt; dt.setTime_t(t); return QLocale().toString(dt, QLocale::ShortFormat); } static QStringList buildKeyInfos(const std::vector keys, QWidget *parent, bool *bOk) { QStringList keyInfos; if (!bOk) { qDebug() << "Invalid call"; return keyInfos; } *bOk = false; for (const auto &key: keys) { if (key.isNull() || !key.numSubkeys()) { qDebug() << "Null key?"; continue; } if (key.hasSecret() && key.protocol() == GpgME::OpenPGP) { QMessageBox::warning(parent, QString::fromUtf8 (_("Error")), QStringLiteral("%1

").arg(QString::fromUtf8(_("Secret key detected."))) + QString::fromUtf8(_("You can only configure public keys in Outlook." " Import secret keys with Kleopatra."))); return QStringList(); } if (key.isBad() || !key.canEncrypt()) { QMessageBox::warning(parent, QString::fromUtf8 (_("Error")), QStringLiteral("%1

%2

").arg(QString::fromUtf8(_("Invalid key detected."))).arg( key.primaryFingerprint()) + QString::fromUtf8(_("The key is unusable for Outlook." " Please check Kleopatra for more information."))); return QStringList(); } const auto subkey = key.subkey(0); QString info = QString::fromLatin1(key.primaryFingerprint()) + "
" + QString::fromUtf8(_("Created:")) + " " + time_t2string(subkey.creationTime()) + "
" + QString::fromUtf8(_("User Ids:")) + "
"; for (const auto &uid: key.userIDs()) { if (uid.isNull() || uid.isRevoked() || uid.isInvalid()) { continue; } info += "  " + prettyNameAndEMail(uid).toHtmlEscaped() + "
"; } keyInfos << info; } *bOk = true; return keyInfos; } void GpgOLKeyAdder::checkAcceptBottom(const std::vector &pgpKeys, const std::vector &cmsCerts, const std::string &errString) { bool ok; QString msg; if (!pgpKeys.size() && (mShowCMS && !pgpKeys.size() && !cmsCerts.size())) { QMessageBox::warning(this, QString::fromUtf8 (_("Error")), QStringLiteral("%1

").arg(QString::fromUtf8(_("Failed to parse any public key.")) + (errString.empty() ? QStringLiteral("") : QStringLiteral("

%1").arg(QString::fromStdString(errString))))); return; } if (pgpKeys.size()) { const auto keyInfos = buildKeyInfos (pgpKeys, this, &ok); if (!ok) { return; } msg += QString::fromUtf8(_("You are about to configure the following OpenPGP %1 for:")).arg( (keyInfos.size() > 1 ? QString::fromUtf8(_("keys")) : QString::fromUtf8(_("key")))) + QStringLiteral("
\t\"%1\"

").arg(mName.toHtmlEscaped()) + keyInfos.join("

"); } if (mShowCMS && cmsCerts.size()) { std::vector leaves; std::remove_copy_if(cmsCerts.begin(), cmsCerts.end(), std::back_inserter(leaves), [cmsCerts] (const auto &k) { /* Check if a key has this fingerprint in the * chain ID. Meaning that there is any child of * this certificate. In that case remove it. */ for (const auto &c: cmsCerts) { if (!c.chainID()) { continue; } if (!k.primaryFingerprint() || !c.primaryFingerprint()) { /* WTF? */ continue; } if (!strcmp (c.chainID(), k.primaryFingerprint())) { qDebug() << "Filtering out non leaf cert" << k.primaryFingerprint(); return true; } } return false; }); const auto certInfos = buildKeyInfos (leaves, this, &ok); if (!ok) { return; } msg += QString::fromUtf8(_("You are about to configure the following S/MIME %1 for:")).arg( (certInfos.size() > 1 ? QString::fromUtf8(_("certificates")) : QString::fromUtf8(_("certificate")))) + QStringLiteral("
\t\"%1\"

").arg(mName.toHtmlEscaped()) + certInfos.join("

"); } if (!msg.isEmpty()) { msg += "

" + QString::fromUtf8 (_("Continue?")); const auto ret = QMessageBox::question(this, QString::fromUtf8(_("Confirm")), msg, QMessageBox::Yes | QMessageBox::Abort, QMessageBox::Yes); if (ret == QMessageBox::Yes) { save(); return; } } save(); return; } void GpgOLKeyAdder::checkAccept() { const auto openpgpText = mEdit->toPlainText().trimmed().toUtf8(); auto cmsText = mCMSEdit->toPlainText().trimmed().toUtf8(); if (!openpgpText.size() && !cmsText.size()) { save(); return; } /* Otherwise we get an BER error */ cmsText += '\n'; GpgME::Data pgp(openpgpText.constData(), openpgpText.size(), false); GpgME::Data cms(cmsText.constData(), cmsText.size(), false); const auto keys = pgp.toKeys(GpgME::OpenPGP); if (!mShowCMS || !cmsText.size()) { checkAcceptBottom (keys, std::vector(), std::string()); return; } auto progress = new QProgressDialog(this, Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::Dialog); progress->setAutoClose(true); progress->setMinimumDuration(0); progress->setMaximum(0); progress->setMinimum(0); progress->setModal(true); progress->setCancelButton(nullptr); progress->setWindowTitle(_("Validating S/MIME certificates")); progress->setLabel(new QLabel(_("This may take several minutes..."))); auto workerThread = new CMSImportThread(cms); connect(workerThread, &QThread::finished, this, [this, workerThread, progress, keys] { progress->accept(); progress->deleteLater(); checkAcceptBottom(keys, workerThread->certs(), workerThread->error()); delete workerThread; }); workerThread->start(); progress->exec(); } #include "gpgolkeyadder.moc" diff --git a/src/gpgolkeyadder/gpgolkeyadder.h b/src/gpgolkeyadder/gpgolkeyadder.h index c6fe41a..8db5f88 100644 --- a/src/gpgolkeyadder/gpgolkeyadder.h +++ b/src/gpgolkeyadder/gpgolkeyadder.h @@ -1,46 +1,46 @@ #ifndef GPGOLKEYADDER_H #define GPGOLKEYADDER_H /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include #include #include class QCommandLineParser; class QTextEdit; class QCheckBox; class GpgOLKeyAdder: public QDialog { Q_OBJECT public: GpgOLKeyAdder(const QCommandLineParser &parser); protected: /** @brief UI setup */ void setupGUI(); private: void checkAccept(); void checkAcceptBottom(const std::vector &pgpKeys, const std::vector &cmsKeys, const std::string &error); void save(); void handleInput(const QByteArray &data); QTextEdit *mEdit; QTextEdit *mCMSEdit; QString mName; QCheckBox *mAlwaysSec; bool mShowCMS; }; #endif // GPGOLKEYADDER_H diff --git a/src/gpgolkeyadder/main.cpp b/src/gpgolkeyadder/main.cpp index 715f976..c56809e 100644 --- a/src/gpgolkeyadder/main.cpp +++ b/src/gpgolkeyadder/main.cpp @@ -1,163 +1,163 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ /** @file Main entry point for the application. */ #include "strhelp.h" #include "gpgolkeyadder-options.h" #include "w32-gettext.h" #include "w32-util.h" #include "gpgolkeyadder.h" #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN #include #include #endif #ifndef APPNAME #define APPNAME "GpgOL" #endif #ifndef VERSION #define VERSION "0.0" #endif bool g_debug = false; QtMessageHandler g_default_msg_handler = NULL; void filterDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { if (!g_debug && type == QtDebugMsg) { return; } if (g_default_msg_handler) { (*g_default_msg_handler)(type, context, msg); } } int realMain(int argc, char **argv); #if defined(WIN32) && defined(UNICODE) /** @brief Unicode entry point. * * Converts arguments to UTF-8 and executes the real * entry point realMain. */ int wmain(int argc, wchar_t **argv, wchar_t **envp) { char **utf8args = NULL; utf8args = (char**) xmalloc0 ((argc + 1) * sizeof(char*)); for (int i = 0; i < argc; i++) { utf8args[i] = wchar_to_utf8(argv[i], wcslen(argv[i])); if (utf8args[i] == NULL) { printf ("Fatal: could not convert arguments to UTF-8.\n"); exit(-1); } } int ret = realMain(argc, utf8args); strv_free(utf8args); return ret; } #else int main(int argc, char **argv) { return realMain(argc, argv); } #endif /** @brief The real entry point to the application. * * @param [in] argc the count of the arguments. * @param [in] argv On GNU/Linux this function expects argv to be in the * native system encoding. On Windows the arguments * shall be UTF-8 * * @returns 0 on success an error code otherwise. */ int realMain(int argc, char **argv) { /* QApplication setup */ QApplication app(argc, argv); QApplication::setOrganizationName(QStringLiteral(APPNAME)); QApplication::setApplicationName(QStringLiteral(APPNAME)); QApplication::setApplicationVersion(QStringLiteral(VERSION)); #if 0 /* Setup translations */ QTranslator translator; if (QLocale::system().name() == "C") { /* Useful for testing / development as the primary target is german */ translator.load(":/l10n/main_de_DE"); } else { translator.load(":/l10n/main_" + QLocale::system().name()); } app.installTranslator(&translator); #endif /* Parse the command line */ QCommandLineParser parser; options(parser); #ifdef Q_OS_WIN auto oldCodec = QTextCodec::codecForLocale(); QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); #endif parser.process(app); #ifdef Q_OS_WIN QTextCodec::setCodecForLocale(oldCodec); #endif g_debug = parser.isSet("debug"); g_default_msg_handler = qInstallMessageHandler(filterDebugOutput); const auto lang = parser.value("lang"); if (!lang.isEmpty()) { qputenv("LANG", lang.toUtf8()); } // Initialize GpgME const GpgME::Error gpgmeInitError = GpgME::initializeLibrary(0); if (gpgmeInitError) { QMessageBox::critical(nullptr, QObject::tr("Installation Error"), QObject::tr("Could not initialize GPGME.") + "
" + QObject::tr("Please reinstall") + " " APPNAME "."); return EXIT_FAILURE; } // Initialize w32-gettext const auto localeDir = W32::getGpg4winLocaleDir(); if (!localeDir.empty()) { i18n_init("gpgol", localeDir.c_str()); } else { qDebug() << "No locale dir."; } GpgOLKeyAdder mainWin(parser); mainWin.show(); app.exec(); return EXIT_SUCCESS; } diff --git a/src/gpgolkeyadder/stdinreader.cpp b/src/gpgolkeyadder/stdinreader.cpp index 5faf582..33395d6 100644 --- a/src/gpgolkeyadder/stdinreader.cpp +++ b/src/gpgolkeyadder/stdinreader.cpp @@ -1,35 +1,35 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "stdinreader.h" #include #include static void rtrim(std::string &s) { s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end()); } void StdinReader::run() { std::string line; while (true) { std::getline(std::cin, line); // Normalize line endings rtrim(line); line += "\n"; mData += QByteArray::fromStdString(line); if (std::cin.eof()) { Q_EMIT stdinRead(mData); deleteLater(); return; } } } diff --git a/src/gpgolkeyadder/stdinreader.h b/src/gpgolkeyadder/stdinreader.h index 50fde47..0c89a6c 100644 --- a/src/gpgolkeyadder/stdinreader.h +++ b/src/gpgolkeyadder/stdinreader.h @@ -1,27 +1,27 @@ #ifndef STDINREADER_H #define STDINREADER_H /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include class StdinReader: public QThread { Q_OBJECT; Q_SIGNALS: void stdinRead(const QByteArray &data); protected: virtual void run() override; private: QByteArray mData; }; #endif // STDINREADER_H diff --git a/src/overlayer/main.cpp b/src/overlayer/main.cpp index 0b983b0..e9c0915 100644 --- a/src/overlayer/main.cpp +++ b/src/overlayer/main.cpp @@ -1,152 +1,152 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ /** @file Main entry point for the application. */ #include "strhelp.h" #include "overlayer-options.h" #include "quitter.h" #include "util/overlay.h" #include #include #include #include #include #include #ifdef Q_OS_WIN #include #include #endif #ifndef APPNAME #define APPNAME "Overlayer" #endif #ifndef VERSION #define VERSION "0.0" #endif bool g_debug = false; QtMessageHandler g_default_msg_handler = NULL; void filterDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { if (!g_debug && type == QtDebugMsg) { return; } if (g_default_msg_handler) { (*g_default_msg_handler)(type, context, msg); } } int realMain(int argc, char **argv); #if defined(WIN32) && defined(UNICODE) /** @brief Unicode entry point. * * Converts arguments to UTF-8 and executes the real * entry point realMain. */ int wmain(int argc, wchar_t **argv, wchar_t **envp) { char **utf8args = NULL; utf8args = (char**) xmalloc0 ((argc + 1) * sizeof(char*)); for (int i = 0; i < argc; i++) { utf8args[i] = wchar_to_utf8(argv[i], wcslen(argv[i])); if (utf8args[i] == NULL) { printf ("Fatal: could not convert arguments to UTF-8.\n"); exit(-1); } } int ret = realMain(argc, utf8args); strv_free(utf8args); return ret; } #else int main(int argc, char **argv) { return realMain(argc, argv); } #endif /** @brief The real entry point to the application. * * @param [in] argc the count of the arguments. * @param [in] argv On GNU/Linux this function expects argv to be in the * native system encoding. On Windows the arguments * shall be UTF-8 * * @returns 0 on success an error code otherwise. */ int realMain(int argc, char **argv) { /* QApplication setup */ QApplication app(argc, argv); QApplication::setOrganizationName(QStringLiteral(APPNAME)); QApplication::setApplicationName(QStringLiteral(APPNAME)); QApplication::setApplicationVersion(QStringLiteral(VERSION)); #if 0 /* Setup translations */ QTranslator translator; if (QLocale::system().name() == "C") { /* Useful for testing / development as the primary target is german */ translator.load(":/l10n/main_de_DE"); } else { translator.load(":/l10n/main_" + QLocale::system().name()); } app.installTranslator(&translator); #endif /* Parse the command line */ QCommandLineParser parser; options(parser); #ifdef Q_OS_WIN auto oldCodec = QTextCodec::codecForLocale(); QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); #endif parser.process(app); #ifdef Q_OS_WIN QTextCodec::setCodecForLocale(oldCodec); #endif g_debug = parser.isSet("debug"); g_default_msg_handler = qInstallMessageHandler(filterDebugOutput); // Start quitter in the event loop QTimer::singleShot(0, [&parser, &app]() { Quitter *quitter = new Quitter; quitter->start(); }); Overlay *overlay; const auto hwnd = parser.value(QStringLiteral("hwnd")); if (!hwnd.isEmpty()) { bool ok; WId id = (WId) hwnd.toInt(&ok); if (!ok) { std::cerr << "invalid hwnd value" << std::endl; return EXIT_FAILURE; } overlay = new Overlay(id, parser.value(QStringLiteral("overlayText"))); } else { std::cerr << "no hwnd value" << std::endl; return EXIT_FAILURE; } return app.exec(); } diff --git a/src/overlayer/overlayer-options.h b/src/overlayer/overlayer-options.h index 6cb448d..ab806e8 100644 --- a/src/overlayer/overlayer-options.h +++ b/src/overlayer/overlayer-options.h @@ -1,34 +1,34 @@ #ifndef OVERLAYER_OPTIONS #define OVERLAYER_OPTIONS /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include /** @file Commandline options*/ static void options(QCommandLineParser &parser) { QList options; options << QCommandLineOption(QStringList() << QStringLiteral("debug"), QStringLiteral("Print debug output.")) << QCommandLineOption(QStringLiteral("hwnd"), QStringLiteral("Parent Window"), QStringLiteral("windows window handle")) << QCommandLineOption(QStringLiteral("overlayText"), QStringLiteral("Overlay Text"), QStringLiteral("text to overlay over hwnd")); for (const auto &opt: options) { parser.addOption(opt); } parser.addVersionOption(); parser.addHelpOption(); } #endif // OVERLAYER_OPTIONS diff --git a/src/overlayer/quitter.cpp b/src/overlayer/quitter.cpp index 0e97ceb..d7de04b 100644 --- a/src/overlayer/quitter.cpp +++ b/src/overlayer/quitter.cpp @@ -1,32 +1,32 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include "quitter.h" #include static void rtrim(std::string &s) { s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end()); } void Quitter::run() { std::string line; while (true) { std::getline(std::cin, line); rtrim(line); if (std::cin.eof() || line == "quit") { qApp->quit(); return; } } } diff --git a/src/overlayer/quitter.h b/src/overlayer/quitter.h index 7e31644..91f81fc 100644 --- a/src/overlayer/quitter.h +++ b/src/overlayer/quitter.h @@ -1,21 +1,21 @@ #ifndef QUITTER_H #define QUITTER_H /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include class Quitter: public QThread { Q_OBJECT; protected: virtual void run() override; }; #endif // QUITTER_H diff --git a/src/resolver/main.cpp b/src/resolver/main.cpp index db08ad2..a372440 100644 --- a/src/resolver/main.cpp +++ b/src/resolver/main.cpp @@ -1,158 +1,158 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ /** @file Main entry point for the application. */ #include "strhelp.h" #include "resolver-options.h" #include "resolver.h" #include #include #include #include #include #include #include #ifdef Q_OS_WIN #include #include #endif #ifndef APPNAME #define APPNAME "Resolver" #endif #ifndef VERSION #define VERSION "0.0" #endif bool g_debug = false; QtMessageHandler g_default_msg_handler = NULL; void filterDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { if (!g_debug && type == QtDebugMsg) { return; } if (g_default_msg_handler) { (*g_default_msg_handler)(type, context, msg); } } int realMain(int argc, char **argv); #if defined(WIN32) && defined(UNICODE) /** @brief Unicode entry point. * * Converts arguments to UTF-8 and executes the real * entry point realMain. */ int wmain(int argc, wchar_t **argv, wchar_t **envp) { char **utf8args = NULL; utf8args = (char**) xmalloc0 ((argc + 1) * sizeof(char*)); for (int i = 0; i < argc; i++) { utf8args[i] = wchar_to_utf8(argv[i], wcslen(argv[i])); if (utf8args[i] == NULL) { printf ("Fatal: could not convert arguments to UTF-8.\n"); exit(-1); } } int ret = realMain(argc, utf8args); strv_free(utf8args); return ret; } #else int main(int argc, char **argv) { return realMain(argc, argv); } #endif /** @brief The real entry point to the application. * * @param [in] argc the count of the arguments. * @param [in] argv On GNU/Linux this function expects argv to be in the * native system encoding. On Windows the arguments * shall be UTF-8 * * @returns 0 on success an error code otherwise. */ int realMain(int argc, char **argv) { /* QApplication setup */ Resolver app(argc, argv); QApplication::setOrganizationName(QStringLiteral(APPNAME)); QApplication::setApplicationName(QStringLiteral(APPNAME)); QApplication::setApplicationVersion(QStringLiteral(VERSION)); #if 0 /* Setup translations */ QTranslator translator; if (QLocale::system().name() == "C") { /* Useful for testing / development as the primary target is german */ translator.load(":/l10n/main_de_DE"); } else { translator.load(":/l10n/main_" + QLocale::system().name()); } app.installTranslator(&translator); #endif /* Parse the command line */ QCommandLineParser parser; options(parser); #ifdef Q_OS_WIN auto oldCodec = QTextCodec::codecForLocale(); QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); #endif parser.process(app); #ifdef Q_OS_WIN QTextCodec::setCodecForLocale(oldCodec); #endif g_debug = parser.isSet("debug"); g_default_msg_handler = qInstallMessageHandler(filterDebugOutput); // Initialize GpgME const GpgME::Error gpgmeInitError = GpgME::initializeLibrary(0); if (gpgmeInitError) { QMessageBox::critical(nullptr, QObject::tr("Installation Error"), QObject::tr("Could not initialize GPGME.") + "
" + QObject::tr("Please reinstall") + " " APPNAME "."); return EXIT_FAILURE; } const auto lang = parser.value("lang"); if (!lang.isEmpty()) { qputenv("LANG", lang.toUtf8()); } // Go with the app QTimer::singleShot(0, [&parser, &app]() { const QString err = app.newInstance(parser); if (!err.isEmpty()) { std::cerr << QObject::tr("Invalid arguments: %1").arg(err).toLocal8Bit().constData() << "\n"; exit(EXIT_FAILURE); } }); app.exec(); return EXIT_SUCCESS; } diff --git a/src/resolver/resolver-options.h b/src/resolver/resolver-options.h index 1c3e605..a4bdf5c 100644 --- a/src/resolver/resolver-options.h +++ b/src/resolver/resolver-options.h @@ -1,69 +1,69 @@ #ifndef RESOLVER_OPTIONS #define RESOLVER_OPTIONS /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include /** @file Commandline options*/ static void options(QCommandLineParser &parser) { QList options; options << QCommandLineOption(QStringList() << QStringLiteral("debug"), QStringLiteral("Print debug output.")) << QCommandLineOption(QStringList() << QStringLiteral("allowMixed"), QStringLiteral("Allow a combination of S/MIME and OpenPGP")) << QCommandLineOption(QStringLiteral("protocol"), QStringLiteral("Specify a forced protocol"), QStringLiteral("pgp or cms")) << QCommandLineOption(QStringLiteral("preferred-protocol"), QStringLiteral("Specify a preferred protocol"), QStringLiteral("pgp or cms")) << QCommandLineOption(QStringLiteral("sender"), QStringLiteral("The sender"), QStringLiteral("sender mailbox")) << QCommandLineOption(QStringLiteral("sign"), QStringLiteral("Should be signed")) << QCommandLineOption(QStringLiteral("encrypt"), QStringLiteral("Should be encrypted")) << QCommandLineOption(QStringLiteral("hwnd"), QStringLiteral("Parent Window"), QStringLiteral("windows window handle")) << QCommandLineOption(QStringLiteral("overlayText"), QStringLiteral("Overlay Text"), QStringLiteral("text to overlay over hwnd")) << QCommandLineOption(QStringLiteral("lang"), QStringLiteral("Language"), QStringLiteral("Language to be used e.g. de_DE")) << QCommandLineOption(QStringList() << QStringLiteral("override") << QStringLiteral("o"), QStringLiteral("Override where format can be:\n" "InlineOpenPGP\n" "OpenPGPMIME\n" "SMIME\n" "SMIMEOpaque\n" "AnyOpenPGP\n" "AnySMIME\n" "Auto"), QStringLiteral("mailbox:fpr,fpr,..:format")) << QCommandLineOption(QStringLiteral("alwaysShow"), QStringLiteral("Should always be shown")); for (const auto &opt: options) { parser.addOption(opt); } parser.addVersionOption(); parser.addHelpOption(); parser.addPositionalArgument(QStringLiteral("recipients"), QStringLiteral("Recipient Mailboxes"), QStringLiteral("[recipients]")); } #endif // RESOLVER_OPTIONS diff --git a/src/resolver/resolver.cpp b/src/resolver/resolver.cpp index 00da1d6..8eb8d5c 100644 --- a/src/resolver/resolver.cpp +++ b/src/resolver/resolver.cpp @@ -1,184 +1,184 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "resolver.h" #include "util/overlay.h" #include #include #include #include #include #include class Resolver::Private { public: Private(Resolver *qq): q(qq) { } void printResolvedKeys(const Kleo::KeyResolver *kr) { const auto sigMap = kr->signingKeys(); for (const auto fmt: sigMap.keys()) { for (const auto key: sigMap[fmt]) { std::string fmtStr; if (fmt & Kleo::AnySMIME) { fmtStr = "smime"; } else { fmtStr = "openpgp"; } if (!key.isNull()) { std::cout << "sig:" << fmtStr << ":" << key.primaryFingerprint() << std::endl; } } } const auto encMap = kr->encryptionKeys(); for (const auto fmt: encMap.keys()) { for (const auto mbox: encMap[fmt].keys()) { for (const auto key: encMap[fmt][mbox]) { std::string fmtStr; if (fmt & Kleo::AnySMIME) { fmtStr = "smime"; } else { fmtStr = "openpgp"; } if (!key.isNull()) { std::cout << "enc:" << fmtStr << ":" << key.primaryFingerprint() << ":" << mbox.toUtf8().constData() << std::endl; } } } } } void newOverlay(WId wid, const QString &text) { m_overlay = std::shared_ptr(new Overlay(wid, text)); } void newResolver(const QCommandLineParser &parser) { const auto proto = parser.value(QStringLiteral("protocol")).toLower(); Kleo::CryptoMessageFormat format; if (proto == QStringLiteral("cms")) { format = Kleo::AnySMIME; } else if (proto == QStringLiteral("pgp")) { format = Kleo::AnyOpenPGP; } else { format = Kleo::AutoFormat; } const auto preferredVal = parser.value(QStringLiteral("preferred-protocol")).toLower(); GpgME::Protocol preferred = GpgME::UnknownProtocol; if (preferredVal == QStringLiteral("cms")) { preferred = GpgME::CMS; } else if (preferredVal == QStringLiteral("pgp")) { preferred = GpgME::OpenPGP; } QMap > overrides; for (const QString &oride: parser.values("override")) { const QStringList split = oride.split(QLatin1Char(':')); Kleo::CryptoMessageFormat fmt = Kleo::AutoFormat; if (split.size() < 2 || split.size() > 3) { qDebug() << "Invalid override format"; std::cout << "cancel" << std::endl; qApp->quit(); } if (split.size() == 3) { const QString fmtStr = split[2].toLower(); if (fmtStr == "inlineopenpgp") { fmt = Kleo::InlineOpenPGPFormat; } else if (fmtStr == "openpgpmime") { fmt = Kleo::OpenPGPMIMEFormat; } else if (fmtStr == "smime") { fmt = Kleo::SMIMEFormat; } else if (fmtStr == "smimeopaque") { fmt = Kleo::SMIMEOpaqueFormat; } else if (fmtStr == "anyopenpgp") { fmt = Kleo::AnyOpenPGP; } else if (fmtStr == "anysmime") { fmt = Kleo::AnySMIME; } else if (fmtStr == "auto") { fmt = Kleo::AutoFormat; } else { qDebug() << "Invalid override format string"; std::cout << "cancel" << std::endl; qApp->quit(); } } const QStringList fingerprints = split[1].split(QLatin1Char(',')); auto map = overrides.value(fmt); map.insert(split[0], fingerprints); overrides.insert(fmt, map); qDebug () << "Passing overrides" << fingerprints << split[0]; } const auto recps = parser.positionalArguments(); auto *kr = new Kleo::KeyResolver (!recps.isEmpty() || parser.isSet(QStringLiteral("encrypt")) /* encrypt */, parser.isSet(QStringLiteral("sign")) /*sign*/, format /* CryptoMesssageFormat */, parser.isSet("allowMixed")/* AllowMixed */); kr->setRecipients(recps); kr->setSender(parser.value("sender")); kr->enableNagging(true); kr->setOverrideKeys(overrides); kr->setPreferredProtocol(preferred); connect (kr, &Kleo::KeyResolver::keysResolved, q, [this, kr] (bool success, bool sendUnencrypted) { if (!success) { std::cout << "cancel" << std::endl; } else if (sendUnencrypted) { std::cout << "unencrypted" << std::endl; } else { printResolvedKeys(kr); } delete kr; qApp->quit(); }); kr->setDialogWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); kr->start(parser.isSet(QStringLiteral("alwaysShow")), m_overlay.get()); } Resolver *q; std::shared_ptr m_overlay; }; Resolver::Resolver(int &argc, char *argv[]) : QApplication(argc, argv), d(new Private(this)) { } QString Resolver::newInstance(const QCommandLineParser &parser, const QString &workingDirectry) { const auto hwnd = parser.value(QStringLiteral("hwnd")); if (!hwnd.isEmpty()) { bool ok; WId id = (WId) hwnd.toInt(&ok); if (!ok) { std::cerr << "invalid hwnd value" << std::endl; exit(EXIT_FAILURE); } d->newOverlay(id, parser.value(QStringLiteral("overlayText"))); } d->newResolver(parser); return QString(); } diff --git a/src/resolver/resolver.h b/src/resolver/resolver.h index 3f43ca7..5c59fa9 100644 --- a/src/resolver/resolver.h +++ b/src/resolver/resolver.h @@ -1,62 +1,62 @@ #ifndef RESOLVER_H #define RESOLVER_H /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include class QCommandLineParser; class QStringList; class QString; /** @brief Resolver Application entry point. * * The Resolver application exists to resolve Mailboxes * to key fingerprints. A typical task for a MUA. * * The main user of this app is GpgOL so it is tailored * to GpgOL's needs. * * This is the global qApp singleton. */ class Resolver: public QApplication { Q_OBJECT public: /** Create a new Application obejct. You have to * make sure to call init afterwards to get a valid object. * This is to delay initialisation after the UniqueService * call is done and our init / call might be forwarded to * another instance. */ explicit Resolver(int &argc, char *argv[]); static Resolver *instance() { return static_cast (qApp); } /** Starts a new instance or a command from the command line. * * Handles the parser options and starts the according commands. * The parser should have been initialized with options and * already processed. * * @param parser: The command line parser to use. * @param workingDirectory: Optional working directory for file arguments. * * @returns an empty QString on success. A error message otherwise. * */ QString newInstance(const QCommandLineParser &parser, const QString &workingDirectory = QString()); private: class Private; std::shared_ptr d; }; #endif diff --git a/src/util/overlay.cpp b/src/util/overlay.cpp index 54d3e53..a691dfc 100644 --- a/src/util/overlay.cpp +++ b/src/util/overlay.cpp @@ -1,139 +1,139 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "overlay.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "w32-util.h" #include "w32-qt-util.h" #include #ifdef Q_OS_WIN #include class Overlay::Private { public: Private(Overlay *qq, WId id, const QString &text): q(qq) { m_target = (HWND) id; q->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint); q->setAttribute(Qt::WA_TransparentForMouseEvents); q->setAttribute(Qt::WA_TranslucentBackground); W32::setupForeignParent(id, q, true); auto vLay = new QVBoxLayout(q); auto bar = new QProgressBar; auto label = new QLabel; label->setText(QStringLiteral("

%1

").arg(text)); bar->setRange(0, 0); vLay->addStretch(1); auto cancelBtn = new QPushButton; cancelBtn->setIcon(q->style()->standardPixmap(QStyle::SP_TitleBarCloseButton)); cancelBtn->setFlat(true); auto subLay1 = new QVBoxLayout; auto subLay3 = new QHBoxLayout; subLay3->addStretch(0.5); subLay3->addWidget(label); subLay3->addStretch(1); subLay3->addWidget(cancelBtn); subLay1->addLayout(subLay3); subLay1->addWidget(bar); auto subLay2 = new QHBoxLayout; subLay2->addStretch(0.1); subLay2->addLayout(subLay1); subLay2->addStretch(0.1); vLay->addLayout(subLay2); vLay->addStretch(1); connect(cancelBtn, &QPushButton::clicked, q, [this] () { std::cout << "cancel" << std::endl; qApp->quit(); }); auto refreshTimer = new QTimer(q); connect(refreshTimer, &QTimer::timeout, q, [this] () { RECT rect; if (GetWindowRect(m_target, &rect)) { #if 0 HWND myself = (HWND) q->winId(); if (!SetWindowPos(myself, HWND_NOTOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_SHOWWINDOW)) { qDebug() << "Set Window pos failed."; UpdateWindow(m_target); } #endif q->setGeometry(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); } else { //maybe window was closed OutputDebugStringA ("Overlay GetWindowRect failed."); std::cout << "cancel" << std::endl; qApp->quit(); } }); refreshTimer->start(50); // update interval in milliseconds q->show(); } HWND m_target; Overlay *q; }; Overlay::Overlay (WId id, const QString &text): d(new Private(this, id, text)) { } #else Overlay::Overlay (WId id, const QString &text) { } #endif void Overlay::paintEvent(QPaintEvent *e) { QPainter painter(this); int width = size().width(); int height = size().height(); QLinearGradient gradient(0, 0, 0, height); gradient.setColorAt(0, Qt::transparent); gradient.setColorAt(0.5, Qt::white); gradient.setColorAt(1, Qt::transparent); QBrush brush(gradient); painter.fillRect(0, 0, width, height, gradient); QWidget::paintEvent(e); } diff --git a/src/util/overlay.h b/src/util/overlay.h index 6fb1cae..0c7cd6b 100644 --- a/src/util/overlay.h +++ b/src/util/overlay.h @@ -1,27 +1,27 @@ #ifndef OVERLAY_H #define OVERLAY_H /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include class QPaintEvent; class Overlay: public QWidget { Q_OBJECT public: Overlay (WId id, const QString &text); protected: virtual void paintEvent (QPaintEvent *event) override; private: class Private; std::shared_ptr d; }; #endif diff --git a/src/util/strhelp.h b/src/util/strhelp.h index ab90958..8110f30 100644 --- a/src/util/strhelp.h +++ b/src/util/strhelp.h @@ -1,173 +1,173 @@ /* Copyright (C) 2015 by ETH Zürich * Software engineering by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #ifndef STRHELP_H #define STRHELP_H #ifdef __cplusplus extern "C" { #endif #include #include /** * @file strhelp.h * @brief Helper functions for c strings and memory management * @details strhelp contains terminating memory allocation functions and * some conveniance functions to work with c strings or arrays of c * strings. */ /** @def To avoid that a compiler optimizes certain memset calls away */ #define wipememory2(_ptr,_set,_len) do { \ volatile char *_vptr=(volatile char *)(_ptr); \ size_t _vlen=(_len); \ while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \ } while(0) /** @def To avoid that a compiler optimizes certain memset calls away */ #define wipememory(_ptr,_len) wipememory2(_ptr,0,_len) void *xmalloc( size_t n ); /** @brief like malloc but initalizes the values with 0 */ void *xmalloc0( size_t n ); void *xrealloc( void *a, size_t n ); void *xcalloc( size_t n, size_t m ); char *xstrndup( const char *string, const size_t len ); void xfree ( void *p ); /** * @brief Terminating variant of asprintf * * This function behaves exactly like asprintf(3) but will terminate * when an error occures (usally that means that memoy allocation * failed). */ int xasprintf (char **strp, const char *fmt, ...); /** * @brief Returns the length of the given %NULL-terminated * string array str_array. * @param[in] str_array a %NULL-terminated array of strings * @returns length of str_array. */ unsigned int strv_length (char **str_array); /** * @brief append a string to a NULL terminated array of strings. * * @param[in,out] pArray pointer to the NULL terminated list of string pointers. * @param[in] string pointer to the string to append to the list. * @param[in] len length of the string to append to the list */ void strv_append (char ***pArray, const char *string, const size_t len); /** * @brief append a string to another string. * * @param[in,out] pDst pointer to the string to be extended. * @param[in,out] dst_len length of the dst string. Will be modified. * @param[in] appendage pointer to the string to append. * @param[in] len length of the string to append. */ void str_append_str (char **pDst, size_t *dst_len, const char *appendage, const size_t len); /** * @brief Frees the given %NULL-terminated string array. * @param[in,out] str_array a %NULL-terminated array of strings */ void strv_free (char **str_array); /** * @brief Checks whether two strings exactly match * @param[in] s1 the first string * @param[in] s2 the second string * @returns true if s1 and s2 are equal */ bool str_equal (char *s1, char *s2); /** * @brief Checks whether s2 exactly matches the beginning of s1. * @param[in] s1 the string who's beginning is searched * @param[in] s2 the string which is searched for * @returns true if s1 starts with s2, false otherwise */ bool str_starts_with (char *s1, char *s2); /** * @brief Trims all white space from the start and end of string. * @details the start of the string is trimmed by setting *s to the * first non white space character. The end is trimmed by setting the * first character after the last non white space character to \0. * @param[in,out] s ponter to the string to strip */ bool str_trim (char **s); /** @brief decode base64 encoded data * * The memory allocated for dest needs to be free'd by the * caller. * * _Input warning:_ * If the input contains invalid base64 characters an error * is returned. * * If the input is invalid base64 but consists of valid * base64 characters _no error_ is returned and dst contains * the valid input up to the error. * * @param [out] dst Pointer to the destination. Needs to be NULL * @param [out] dst_size Size allocated for the destination. * @param [in] src Pointer to the base64 encoded data. * @param [in] src_size Size of the encoded data. * * @returns 0 on success a polarssl error or -1 otherwise */ int str_base64_decode(char **dst, size_t *dst_size, char *src, size_t src_size); #ifdef _WIN32 /** @brief convert a utf8 string to utf16 wchar * * @param[in] string utf8 string. Must be at least len characters long. * @param[in] len number of characters to be converted. * * @returns pointer to a newly allocated wchar array. NULL on error. * **/ wchar_t *utf8_to_wchar (const char *string, size_t len); /** @brief convert a local 8 bit (acp) string to utf16 wchar * * @param[in] string acp string. Must be at least len characters long. * @param[in] len number of characters to be converted. * * @returns pointer to a newly allocated wchar array. NULL on error. * **/ wchar_t *acp_to_wchar (const char *string, size_t len); /** @brief convert a utf16 string to utf8 * * @param[in] string utf16 string. Must be at least len characters long. * @param[in] len number of characters to be converted. * * @returns pointer to a newly allocated char array. NULL on error. * **/ char *wchar_to_utf8 (const wchar_t *string, size_t len); #endif #ifdef __cplusplus } #endif #endif diff --git a/src/util/w32-gettext.h b/src/util/w32-gettext.h index 9561458..d27b319 100644 --- a/src/util/w32-gettext.h +++ b/src/util/w32-gettext.h @@ -1,50 +1,50 @@ #ifndef W32_GETTEXT_H #define W32_GETTEXT_H /* w32-gettext.h - Adoption of a libgpg-errors w32-gettext Copyright (C) 2005 g10 Code GmbH 2018 Intevation GmbH libgpg-error is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License - as published by the Free Software Foundation; either version 2.1 of + as published by the free software Foundation; either version 2.1 of the License, or (at your option) any later version. libgpg-error 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with libgpg-error; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef __cplusplus extern "C" { #if 0 } #endif #endif #ifdef _WIN32 const char *gettext (const char *msgid); const char *utf8_gettext (const char *msgid); /* Init i18n for the pkg and locate dir locale_dir.*/ void i18n_init (const char *pkg_name, const char *locale_dir); #else // _WIN32 const char *gettext (const char *msgid); const char *utf8_gettext (const char *msgid); void i18n_init (const char *pkg_name, const char *locale_dir); #endif //_WIN32 #define _(a) utf8_gettext (a) #endif #ifdef __cplusplus } #endif diff --git a/src/util/w32-qt-util.cpp b/src/util/w32-qt-util.cpp index 822b06a..a2b573c 100644 --- a/src/util/w32-qt-util.cpp +++ b/src/util/w32-qt-util.cpp @@ -1,27 +1,27 @@ /* Copyright (C) 2018 by Andre Heinecke * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include #include "w32-qt-util.h" void W32::setupForeignParent(WId id, QWidget *widget, bool modal) { if (!widget || !id) { return; } auto foreignWindow = QWindow::fromWinId(id); widget->winId(); auto parentHandle = widget->windowHandle(); if (parentHandle && foreignWindow) { parentHandle->setTransientParent(foreignWindow); if (modal) { widget->setWindowModality(Qt::WindowModal); } } } diff --git a/src/util/w32-qt-util.h b/src/util/w32-qt-util.h index 1846549..c8f6e99 100644 --- a/src/util/w32-qt-util.h +++ b/src/util/w32-qt-util.h @@ -1,16 +1,16 @@ #ifndef W32_QT_UTIL_H #define W32_QT_UTIL_H /* Copyright (C) 2018 by Andre Heinecke * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include namespace W32 { void setupForeignParent(WId id, QWidget *widget, bool modal); } // namespace W32 #endif //W32-QT-UTIL_H diff --git a/src/util/w32-util.cpp b/src/util/w32-util.cpp index 281cabc..a1628e0 100644 --- a/src/util/w32-util.cpp +++ b/src/util/w32-util.cpp @@ -1,305 +1,305 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include "w32-util.h" #include #ifdef _WIN32 # include #endif #include #include #define SLDIR "\\share\\locale" namespace W32 { std::string getGpg4winLocaleDir() { const auto instdir = getGpg4winDir(); if (instdir.empty()) { return std::string(); } return instdir + SLDIR; } std::string getGpg4winDir() { const auto tmp = readRegStr(nullptr, GPG4WIN_REGKEY_3, "Install Directory"); if (tmp.empty()) { return std::string(); } if (!access(tmp.c_str(), R_OK)) { return tmp; } else { fprintf (stderr, "Failed to access: %s\n", tmp.c_str()); } return std::string(); } /* Helper for read_w32_registry_string(). */ #ifdef _WIN32 static HKEY get_root_key(const char *root) { HKEY root_key; if( !root ) root_key = HKEY_CURRENT_USER; else if( !strcmp( root, "HKEY_CLASSES_ROOT" ) ) root_key = HKEY_CLASSES_ROOT; else if( !strcmp( root, "HKEY_CURRENT_USER" ) ) root_key = HKEY_CURRENT_USER; else if( !strcmp( root, "HKEY_LOCAL_MACHINE" ) ) root_key = HKEY_LOCAL_MACHINE; else if( !strcmp( root, "HKEY_USERS" ) ) root_key = HKEY_USERS; else if( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) ) root_key = HKEY_PERFORMANCE_DATA; else if( !strcmp( root, "HKEY_CURRENT_CONFIG" ) ) root_key = HKEY_CURRENT_CONFIG; else return nullptr; return root_key; } #endif #if defined(_WIN64) #define CROSS_ACCESS KEY_WOW64_32KEY #else #define CROSS_ACCESS KEY_WOW64_64KEY #endif #ifdef _WIN32 std::string _readRegStr (HKEY root_key, const char *dir, const char *name, bool alternate) { HKEY key_handle; DWORD n1, nbytes, type; std::string ret; DWORD flags = KEY_READ; if (alternate) { flags |= CROSS_ACCESS; } if (RegOpenKeyExA(root_key, dir, 0, flags, &key_handle)) { return ret; } nbytes = 1; if (RegQueryValueExA(key_handle, name, 0, nullptr, nullptr, &nbytes)) { RegCloseKey (key_handle); return ret; } n1 = nbytes+1; char result[n1]; if (RegQueryValueExA(key_handle, name, 0, &type, (LPBYTE)result, &n1)) { RegCloseKey(key_handle); return ret; } RegCloseKey(key_handle); result[nbytes] = 0; /* make sure it is really a string */ ret = result; if (type == REG_EXPAND_SZ && strchr (result, '%')) { n1 += 1000; char tmp[n1 +1]; nbytes = ExpandEnvironmentStringsA(ret.c_str(), tmp, n1); if (nbytes && nbytes > n1) { n1 = nbytes; char tmp2[n1 +1]; nbytes = ExpandEnvironmentStringsA(result, tmp2, n1); if (nbytes && nbytes > n1) { /* oops - truncated, better don't expand at all */ return ret; } tmp2[nbytes] = 0; ret = tmp2; } else if (nbytes) { /* okay, reduce the length */ tmp[nbytes] = 0; ret = tmp; } } return ret; } #endif std::string readRegStr (const char *root, const char *dir, const char *name) { #ifndef _WIN32 (void)root; (void)dir; (void)name; return std::string(); #else HKEY root_key; std::string ret; if (!(root_key = get_root_key(root))) { return ret; } ret = _readRegStr (root_key, dir, name, false); if (ret.empty()) { // Try local machine as fallback. qDebug() << "Fallback to HKLM for" << dir << name; ret = _readRegStr (HKEY_LOCAL_MACHINE, dir, name, false); if (ret.empty()) { // Try alternative registry view as fallback qDebug() << "Fallback to HKLM alternative for" << dir << name; ret = _readRegStr (HKEY_LOCAL_MACHINE, dir, name, true); } } qDebug() << "Returning:" << (ret.empty() ? "empty" : ret.c_str()); return ret; #endif } bool writeRegStr(const char *root, const char *path, const char *key, const char *val) { #ifndef _WIN32 (void) root; (void) path; (void) key; (void) val; return false; #else HKEY h, hk; int type; int ec; hk = get_root_key (root); if (!hk) { fprintf(stderr, "Failed to find root key.\n"); } DWORD flags = KEY_ALL_ACCESS; ec = RegCreateKeyExA(hk, path, 0, NULL, REG_OPTION_NON_VOLATILE, flags, NULL, &h, NULL); if (ec != ERROR_SUCCESS) { fprintf (stderr, "creating/opening registry key `%s' failed\n", path); return false; } type = strchr (val, '%')? REG_EXPAND_SZ : REG_SZ; ec = RegSetValueExA(h, key, 0, type, (const BYTE*)val, strlen (val)); if (ec != ERROR_SUCCESS) { fprintf (stderr, "saving registry key `%s'->`%s' failed\n", path, key); RegCloseKey(h); return false; } RegCloseKey(h); return true; #endif } #ifdef _WIN32 static int has_high_integrity(HANDLE hToken) { PTOKEN_MANDATORY_LABEL integrity_label = NULL; DWORD integrity_level = 0, size = 0; if (hToken == NULL || hToken == INVALID_HANDLE_VALUE) { return 0; } /* Get the required size */ if (!GetTokenInformation (hToken, TokenIntegrityLevel, NULL, 0, &size)) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { return 0; } } integrity_label = (PTOKEN_MANDATORY_LABEL) LocalAlloc(0, size); if (integrity_label == NULL) { return 0; } if (!GetTokenInformation (hToken, TokenIntegrityLevel, integrity_label, size, &size)) { LocalFree(integrity_label); return 0; } /* Get the last integrity level */ integrity_level = *GetSidSubAuthority(integrity_label->Label.Sid, (DWORD)(UCHAR)(*GetSidSubAuthorityCount( integrity_label->Label.Sid) - 1)); LocalFree (integrity_label); return integrity_level >= SECURITY_MANDATORY_HIGH_RID; } #endif bool isElevated() { #ifdef _WIN32 int ret = 0; HANDLE hToken = NULL; if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken)) { DWORD elevation; DWORD cbSize = sizeof (DWORD); if (GetTokenInformation (hToken, TokenElevation, &elevation, sizeof (TokenElevation), &cbSize)) { ret = elevation; } } /* Elevation will be true and ElevationType TokenElevationTypeFull even if the token is a user token created by SAFER so we additionally check the integrity level of the token which will only be high in the real elevated process and medium otherwise. */ ret = ret && has_high_integrity (hToken); if (hToken) CloseHandle (hToken); return ret; #else return false; #endif } }// namespace W32 bool strToBool(const std::string &str, bool defaultVal) { if (str.empty()) { return defaultVal; } if (str == "1") { return true; } if (str == "0") { return false; } qDebug() << "Unknown bool val" << str.c_str(); return defaultVal; } diff --git a/src/util/w32-util.h b/src/util/w32-util.h index e2fde25..1fbfa64 100644 --- a/src/util/w32-util.h +++ b/src/util/w32-util.h @@ -1,59 +1,59 @@ /* Copyright (C) 2018 by Intevation GmbH * - * This file is Free Software under the GNU GPL (v>=2) + * This file is free software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include /* The Registry key used by Gpg4win. */ #ifdef _WIN64 # define GPG4WIN_REGKEY_2 "Software\\Wow6432Node\\GNU\\GnuPG" #else # define GPG4WIN_REGKEY_2 "Software\\GNU\\GnuPG" #endif #ifdef _WIN64 # define GPG4WIN_REGKEY_3 "Software\\Wow6432Node\\Gpg4win" #else # define GPG4WIN_REGKEY_3 "Software\\Gpg4win" #endif #define GPGOL_REG_PATH "Software\\GNU\\GpgOL" namespace W32 { /* Get the locale dir of Gpg4win. */ std::string getGpg4winLocaleDir(); /** Get the Gpg4win Install directory. * * Looks for the Gpg4win 3.x registry key. * And checks that the directory can be read. * * @returns an empty string if no dir could be found. * **/ std::string getGpg4winDir(); /** Read a registry string value. If root is null first * HKEY_CURRENT_USER is searched and then it falls back * to HKEY_LOCAL_MACHINE . */ std::string readRegStr(const char *root, const char *path, const char *key); bool writeRegStr(const char *root, const char *path, const char *key, const char *val); /** Call this to switch to the W64 registry. */ void setW64RegistryMode(bool value); bool isElevated(); } // namespace W32 /** Helper to convert a string 0 / 1 to a bool with a default. */ bool strToBool(const std::string &str, bool defaultVal = false);