diff --git a/src/gpgolconfig/gpgolconfig.cpp b/src/gpgolconfig/gpgolconfig.cpp index f0dc683..5ccef1f 100644 --- a/src/gpgolconfig/gpgolconfig.cpp +++ b/src/gpgolconfig/gpgolconfig.cpp @@ -1,117 +1,124 @@ /* Copyright (C) 2018 by Intevation GmbH * * 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); - auto cryptoConfWidget = new CryptoConfigPage; + 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] () { - cryptoConfWidget->save(); + 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); - 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); + 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/gpgolconfigpage.cpp b/src/gpgolconfig/gpgolconfigpage.cpp index b4e300f..cb3338d 100644 --- a/src/gpgolconfig/gpgolconfigpage.cpp +++ b/src/gpgolconfig/gpgolconfigpage.cpp @@ -1,356 +1,339 @@ /* Copyright (C) 2018 by Intevation GmbH * * 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.")); generalLay->addWidget(mAlwaysSigChk); generalLay->addWidget(mAlwaysEncChk); generalLay->addWidget(mReplyCryptChk); generalLay->addWidget(mInlinePGPChk); // 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 strToBool(const std::string &str, bool defaultVal = false) -{ - if (str.empty()) { - return defaultVal; - } - - if (str == "1") { - return true; - } - if (str == "0") { - return false; - } - - qDebug() << "Unknown bool val" << str.c_str(); - return defaultVal; -} - 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 }, }; 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"]); 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("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/gpgoldebugpage.cpp b/src/gpgolconfig/gpgoldebugpage.cpp index 02f2fa9..15a5f58 100644 --- a/src/gpgolconfig/gpgoldebugpage.cpp +++ b/src/gpgolconfig/gpgoldebugpage.cpp @@ -1,254 +1,237 @@ /* Copyright (C) 2018 by Intevation GmbH * * 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 strToBool(const std::string &str, bool defaultVal = false) -{ - if (str.empty()) { - return defaultVal; - } - - if (str == "1") { - return true; - } - if (str == "0") { - return false; - } - - qDebug() << "Unknown bool val" << str.c_str(); - return defaultVal; -} - 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/util/w32-util.cpp b/src/util/w32-util.cpp index cdb962a..281cabc 100644 --- a/src/util/w32-util.cpp +++ b/src/util/w32-util.cpp @@ -1,288 +1,305 @@ /* Copyright (C) 2018 by Intevation GmbH * * 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; +} -}// namespace diff --git a/src/util/w32-util.h b/src/util/w32-util.h index 998ae95..e2fde25 100644 --- a/src/util/w32-util.h +++ b/src/util/w32-util.h @@ -1,56 +1,59 @@ /* Copyright (C) 2018 by Intevation GmbH * * 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);