Page MenuHome GnuPG

No OneTemporary

diff --git a/src/ui/cryptoconfigmodule.cpp b/src/ui/cryptoconfigmodule.cpp
index bb8132ec..c84bebd2 100644
--- a/src/ui/cryptoconfigmodule.cpp
+++ b/src/ui/cryptoconfigmodule.cpp
@@ -1,978 +1,978 @@
/*
cryptoconfigmodule.cpp
This file is part of kgpgcertmanager
Copyright (c) 2004 Klar�vdalens Datakonsult AB
Libkleopatra is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
Libkleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include "cryptoconfigmodule.h"
#include "cryptoconfigmodule_p.h"
#include "directoryserviceswidget.h"
#include "kdhorizontalline.h"
#include "filenamerequester.h"
#include <qgpgme/cryptoconfig.h>
#include <klineedit.h>
#include <KLocalizedString>
#include "kleo_ui_debug.h"
#include <utils/formatting.h>
#include <qicon.h>
#include <QDialogButtonBox>
#include <QSpinBox>
#include <QApplication>
#include <QLabel>
#include <QLayout>
#include <QPushButton>
#include <QRegExp>
#include <QVBoxLayout>
#include <QList>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QScrollArea>
#include <QDesktopWidget>
#include <QCheckBox>
#include <QStyle>
#include <QComboBox>
#include <QGroupBox>
#include <memory>
#include <limits>
using namespace Kleo;
namespace
{
class ScrollArea : public QScrollArea
{
public:
explicit ScrollArea(QWidget *p) : QScrollArea(p) {}
QSize sizeHint() const override
{
const QSize wsz = widget() ? widget()->sizeHint() : QSize();
return QSize(wsz.width() + style()->pixelMetric(QStyle::PM_ScrollBarExtent), QScrollArea::sizeHint().height());
}
};
}
inline QIcon loadIcon(const QString &s)
{
QString ss = s;
return QIcon::fromTheme(ss.replace(QRegExp(QLatin1String("[^a-zA-Z0-9_]")), QStringLiteral("-")));
}
static unsigned int num_components_with_options(const QGpgME::CryptoConfig *config)
{
if (!config) {
return 0;
}
const QStringList components = config->componentList();
unsigned int result = 0;
for (QStringList::const_iterator it = components.begin(); it != components.end(); ++it)
if (const QGpgME::CryptoConfigComponent *const comp = config->component(*it))
if (!comp->groupList().empty()) {
++result;
}
return result;
}
static KPageView::FaceType determineJanusFace(const QGpgME::CryptoConfig *config, Kleo::CryptoConfigModule::Layout layout, bool &ok)
{
ok = true;
if (num_components_with_options(config) < 2) {
ok = false;
return KPageView::Plain;
}
return
layout == CryptoConfigModule::LinearizedLayout ? KPageView::Plain :
layout == CryptoConfigModule::TabbedLayout ? KPageView::Tabbed :
/* else */ KPageView::List;
}
Kleo::CryptoConfigModule::CryptoConfigModule(QGpgME::CryptoConfig *config, QWidget *parent)
: KPageWidget(parent), mConfig(config)
{
init(IconListLayout);
}
Kleo::CryptoConfigModule::CryptoConfigModule(QGpgME::CryptoConfig *config, Layout layout, QWidget *parent)
: KPageWidget(parent), mConfig(config)
{
init(layout);
}
void Kleo::CryptoConfigModule::init(Layout layout)
{
if (QLayout *l = this->layout()) {
- l->setMargin(0);
+ l->setContentsMargins(0, 0, 0, 0);
}
QGpgME::CryptoConfig *const config = mConfig;
bool configOK = false;
const KPageView::FaceType type = determineJanusFace(config, layout, configOK);
setFaceType(type);
QVBoxLayout *vlay = nullptr;
QWidget *vbox = nullptr;
if (type == Plain) {
QWidget *w = new QWidget(this);
QVBoxLayout *l = new QVBoxLayout(w);
- l->setMargin(0);
+ l->setContentsMargins(0, 0, 0, 0);
QScrollArea *s = new QScrollArea(w);
s->setFrameStyle(QFrame::NoFrame);
s->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
s->setWidgetResizable(true);
l->addWidget(s);
vbox = new QWidget(s->viewport());
vlay = new QVBoxLayout(vbox);
- vlay->setMargin(0);
+ vlay->setContentsMargins(0, 0, 0, 0);
s->setWidget(vbox);
addPage(w, configOK ? QString() : i18n("GpgConf Error"));
}
const QStringList components = config->componentList();
for (QStringList::const_iterator it = components.begin(); it != components.end(); ++it) {
//qCDebug(KLEO_UI_LOG) <<"Component" << (*it).toLocal8Bit() <<":";
QGpgME::CryptoConfigComponent *comp = config->component(*it);
Q_ASSERT(comp);
if (comp->groupList().empty()) {
continue;
}
std::unique_ptr<CryptoConfigComponentGUI> compGUI(new CryptoConfigComponentGUI(this, comp));
compGUI->setObjectName(*it);
// KJanusWidget doesn't seem to have iterators, so we store a copy...
mComponentGUIs.append(compGUI.get());
if (type == Plain) {
QGroupBox *gb = new QGroupBox(comp->description(), vbox);
(new QVBoxLayout(gb))->addWidget(compGUI.release());
vlay->addWidget(gb);
} else {
vbox = new QWidget(this);
vlay = new QVBoxLayout(vbox);
- vlay->setMargin(0);
+ vlay->setContentsMargins(0, 0, 0, 0);
KPageWidgetItem *pageItem = new KPageWidgetItem(vbox, comp->description());
if (type != Tabbed) {
pageItem->setIcon(loadIcon(comp->iconName()));
}
addPage(pageItem);
QScrollArea *scrollArea = type == Tabbed ? new QScrollArea(vbox) : new ScrollArea(vbox);
scrollArea->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
scrollArea->setWidgetResizable(true);
vlay->addWidget(scrollArea);
const QSize compGUISize = compGUI->sizeHint();
scrollArea->setWidget(compGUI.release());
// Set a nice startup size
const int deskHeight = QApplication::desktop()->height();
int dialogHeight;
if (deskHeight > 1000) { // very big desktop ?
dialogHeight = 800;
} else if (deskHeight > 650) { // big desktop ?
dialogHeight = 500;
} else { // small (800x600, 640x480) desktop
dialogHeight = 400;
}
Q_ASSERT(scrollArea->widget());
if (type != Tabbed) {
scrollArea->setMinimumHeight(qMin(compGUISize.height(), dialogHeight));
}
}
}
if (mComponentGUIs.empty()) {
const QString msg = i18n("The gpgconf tool used to provide the information "
"for this dialog does not seem to be installed "
"properly. It did not return any components. "
"Try running \"%1\" on the command line for more "
"information.",
components.empty() ? QLatin1String("gpgconf --list-components") : QLatin1String("gpgconf --list-options gpg"));
QLabel *label = new QLabel(msg, vbox);
label->setWordWrap(true);
label->setMinimumHeight(fontMetrics().lineSpacing() * 5);
vlay->addWidget(label);
}
}
bool Kleo::CryptoConfigModule::hasError() const
{
return mComponentGUIs.empty();
}
void Kleo::CryptoConfigModule::save()
{
bool changed = false;
QList<CryptoConfigComponentGUI *>::Iterator it = mComponentGUIs.begin();
for (; it != mComponentGUIs.end(); ++it) {
if ((*it)->save()) {
changed = true;
}
}
if (changed) {
mConfig->sync(true /*runtime*/);
}
}
void Kleo::CryptoConfigModule::reset()
{
QList<CryptoConfigComponentGUI *>::Iterator it = mComponentGUIs.begin();
for (; it != mComponentGUIs.end(); ++it) {
(*it)->load();
}
}
void Kleo::CryptoConfigModule::defaults()
{
QList<CryptoConfigComponentGUI *>::Iterator it = mComponentGUIs.begin();
for (; it != mComponentGUIs.end(); ++it) {
(*it)->defaults();
}
}
void Kleo::CryptoConfigModule::cancel()
{
mConfig->clear();
}
////
Kleo::CryptoConfigComponentGUI::CryptoConfigComponentGUI(
CryptoConfigModule *module, QGpgME::CryptoConfigComponent *component,
QWidget *parent)
: QWidget(parent),
mComponent(component)
{
QGridLayout *glay = new QGridLayout(this);
const QStringList groups = mComponent->groupList();
if (groups.size() > 1) {
glay->setColumnMinimumWidth(0, KDHorizontalLine::indentHint());
for (QStringList::const_iterator it = groups.begin(), end = groups.end(); it != end; ++it) {
QGpgME::CryptoConfigGroup *group = mComponent->group(*it);
Q_ASSERT(group);
if (!group) {
continue;
}
const QString title = group->description();
KDHorizontalLine *hl = new KDHorizontalLine(title.isEmpty() ? *it : title, this);
const int row = glay->rowCount();
glay->addWidget(hl, row, 0, 1, 3);
mGroupGUIs.append(new CryptoConfigGroupGUI(module, group, glay, this));
}
} else if (!groups.empty()) {
mGroupGUIs.append(new CryptoConfigGroupGUI(module, mComponent->group(groups.front()), glay, this));
}
glay->setRowStretch(glay->rowCount(), 1);
}
bool Kleo::CryptoConfigComponentGUI::save()
{
bool changed = false;
QList<CryptoConfigGroupGUI *>::Iterator it = mGroupGUIs.begin();
for (; it != mGroupGUIs.end(); ++it) {
if ((*it)->save()) {
changed = true;
}
}
return changed;
}
void Kleo::CryptoConfigComponentGUI::load()
{
QList<CryptoConfigGroupGUI *>::Iterator it = mGroupGUIs.begin();
for (; it != mGroupGUIs.end(); ++it) {
(*it)->load();
}
}
void Kleo::CryptoConfigComponentGUI::defaults()
{
QList<CryptoConfigGroupGUI *>::Iterator it = mGroupGUIs.begin();
for (; it != mGroupGUIs.end(); ++it) {
(*it)->defaults();
}
}
////
Kleo::CryptoConfigGroupGUI::CryptoConfigGroupGUI(
CryptoConfigModule *module, QGpgME::CryptoConfigGroup *group,
QGridLayout *glay, QWidget *widget)
: QObject(module), mGroup(group)
{
const bool de_vs = Kleo::Formatting::complianceMode() == QStringLiteral("de-vs");
const int startRow = glay->rowCount();
const QStringList entries = mGroup->entryList();
for (QStringList::const_iterator it = entries.begin(), end = entries.end(); it != end; ++it) {
QGpgME::CryptoConfigEntry *entry = group->entry(*it);
Q_ASSERT(entry);
/* Skip "dangerous" options if we are running in CO_DE_VS. */
if (de_vs && entry->level() > QGpgME::CryptoConfigEntry::Level_Advanced) {
qCDebug(KLEO_UI_LOG) << "entry" << *it << "too advanced, skipping";
continue;
}
CryptoConfigEntryGUI *entryGUI =
CryptoConfigEntryGUIFactory::createEntryGUI(module, entry, *it, glay, widget);
if (entryGUI) {
mEntryGUIs.append(entryGUI);
entryGUI->load();
}
}
const int endRow = glay->rowCount() - 1;
if (endRow < startRow) {
return;
}
const QString iconName = group->iconName();
if (iconName.isEmpty()) {
return;
}
QLabel *l = new QLabel(widget);
l->setPixmap(loadIcon(iconName).pixmap(32, 32));
glay->addWidget(l, startRow, 0, endRow - startRow + 1, 1, Qt::AlignTop);
}
bool Kleo::CryptoConfigGroupGUI::save()
{
bool changed = false;
QList<CryptoConfigEntryGUI *>::Iterator it = mEntryGUIs.begin();
for (; it != mEntryGUIs.end(); ++it) {
if ((*it)->isChanged()) {
(*it)->save();
changed = true;
}
}
return changed;
}
void Kleo::CryptoConfigGroupGUI::load()
{
QList<CryptoConfigEntryGUI *>::Iterator it = mEntryGUIs.begin();
for (; it != mEntryGUIs.end(); ++it) {
(*it)->load();
}
}
void Kleo::CryptoConfigGroupGUI::defaults()
{
QList<CryptoConfigEntryGUI *>::Iterator it = mEntryGUIs.begin();
for (; it != mEntryGUIs.end(); ++it) {
(*it)->resetToDefault();
}
}
////
typedef CryptoConfigEntryGUI *(*constructor)(CryptoConfigModule *, QGpgME::CryptoConfigEntry *, const QString &, QGridLayout *, QWidget *);
namespace
{
template <typename T_Widget>
CryptoConfigEntryGUI *_create(CryptoConfigModule *m, QGpgME::CryptoConfigEntry *e, const QString &n, QGridLayout *l, QWidget *p)
{
return new T_Widget(m, e, n, l, p);
}
}
static const struct WidgetsByEntryName {
const char *entryGlob;
constructor create;
} widgetsByEntryName[] = {
{ "*/*/debug-level", &_create<CryptoConfigEntryDebugLevel> },
{ "gpg/*/keyserver", &_create<CryptoConfigEntryKeyserver> }
};
static const unsigned int numWidgetsByEntryName = sizeof widgetsByEntryName / sizeof * widgetsByEntryName;
static const constructor listWidgets[QGpgME::CryptoConfigEntry::NumArgType] = {
// None: A list of options with no arguments (e.g. -v -v -v) is shown as a spinbox
&_create<CryptoConfigEntrySpinBox>,
nullptr, // String
// Int/UInt: Let people type list of numbers (1,2,3....). Untested.
&_create<CryptoConfigEntryLineEdit>,
&_create<CryptoConfigEntryLineEdit>,
nullptr, // Path
nullptr, // Formerly URL
&_create<CryptoConfigEntryLDAPURL>,
nullptr, // DirPath
};
static const constructor scalarWidgets[QGpgME::CryptoConfigEntry::NumArgType] = {
&_create<CryptoConfigEntryCheckBox>, // None
&_create<CryptoConfigEntryLineEdit>, // String
&_create<CryptoConfigEntrySpinBox>, // Int
&_create<CryptoConfigEntrySpinBox>, // UInt
&_create<CryptoConfigEntryPath>, // Path
nullptr, // Formerly URL
nullptr, // LDAPURL
&_create<CryptoConfigEntryDirPath>, // DirPath
};
CryptoConfigEntryGUI *Kleo::CryptoConfigEntryGUIFactory::createEntryGUI(CryptoConfigModule *module, QGpgME::CryptoConfigEntry *entry, const QString &entryName, QGridLayout *glay, QWidget *widget)
{
Q_ASSERT(entry);
// try to lookup by path:
const QString path = entry->path();
for (unsigned int i = 0; i < numWidgetsByEntryName; ++i)
if (QRegExp(QLatin1String(widgetsByEntryName[i].entryGlob), Qt::CaseSensitive, QRegExp::Wildcard).exactMatch(path)) {
return widgetsByEntryName[i].create(module, entry, entryName, glay, widget);
}
// none found, so look up by type:
const unsigned int argType = entry->argType();
Q_ASSERT(argType < QGpgME::CryptoConfigEntry::NumArgType);
if (entry->isList())
if (const constructor create = listWidgets[argType]) {
return create(module, entry, entryName, glay, widget);
} else {
qCWarning(KLEO_UI_LOG) << "No widget implemented for list of type" << entry->argType();
}
else if (const constructor create = scalarWidgets[argType]) {
return create(module, entry, entryName, glay, widget);
} else {
qCWarning(KLEO_UI_LOG) << "No widget implemented for type" << entry->argType();
}
return nullptr;
}
////
Kleo::CryptoConfigEntryGUI::CryptoConfigEntryGUI(
CryptoConfigModule *module,
QGpgME::CryptoConfigEntry *entry,
const QString &entryName)
: QObject(module), mEntry(entry), mName(entryName), mChanged(false)
{
connect(this, &CryptoConfigEntryGUI::changed, module, &CryptoConfigModule::changed);
}
QString Kleo::CryptoConfigEntryGUI::description() const
{
QString descr = mEntry->description();
if (descr.isEmpty()) { // happens for expert options
// String does not need to be translated because the options itself
// are also not translated
return QStringLiteral("\"%1\"").arg(mName);
}
if (i18nc("Translate this to 'yes' or 'no' (use the English words!) "
"depending on whether your language uses "
"Sentence style capitalisation in GUI labels (yes) or not (no). "
"Context: We get some backend strings in that have the wrong "
"capitalizaion (in English, at least) so we need to force the "
"first character to upper-case. It is this behaviour you can "
"control for your language with this translation.", "yes") == QLatin1String("yes")) {
descr[0] = descr[0].toUpper();
}
return descr;
}
void Kleo::CryptoConfigEntryGUI::resetToDefault()
{
mEntry->resetToDefault();
load();
}
////
Kleo::CryptoConfigEntryLineEdit::CryptoConfigEntryLineEdit(
CryptoConfigModule *module,
QGpgME::CryptoConfigEntry *entry, const QString &entryName,
QGridLayout *glay, QWidget *widget)
: CryptoConfigEntryGUI(module, entry, entryName)
{
const int row = glay->rowCount();
mLineEdit = new KLineEdit(widget);
QLabel *label = new QLabel(description(), widget);
label->setBuddy(mLineEdit);
glay->addWidget(label, row, 1);
glay->addWidget(mLineEdit, row, 2);
if (entry->isReadOnly()) {
label->setEnabled(false);
mLineEdit->setEnabled(false);
} else {
connect(mLineEdit, &KLineEdit::textChanged, this, &CryptoConfigEntryLineEdit::slotChanged);
}
}
void Kleo::CryptoConfigEntryLineEdit::doSave()
{
mEntry->setStringValue(mLineEdit->text());
}
void Kleo::CryptoConfigEntryLineEdit::doLoad()
{
mLineEdit->setText(mEntry->stringValue());
}
////
static const struct {
const char *label;
const char *name;
} debugLevels[] = {
{ I18N_NOOP("0 - None"), "none"},
{ I18N_NOOP("1 - Basic"), "basic"},
{ I18N_NOOP("2 - Verbose"), "advanced"},
{ I18N_NOOP("3 - More Verbose"), "expert"},
{ I18N_NOOP("4 - All"), "guru"},
};
static const unsigned int numDebugLevels = sizeof debugLevels / sizeof * debugLevels;
Kleo::CryptoConfigEntryDebugLevel::CryptoConfigEntryDebugLevel(CryptoConfigModule *module, QGpgME::CryptoConfigEntry *entry,
const QString &entryName, QGridLayout *glay, QWidget *widget)
: CryptoConfigEntryGUI(module, entry, entryName),
mComboBox(new QComboBox(widget))
{
QLabel *label = new QLabel(i18n("Set the debugging level to"), widget);
label->setBuddy(mComboBox);
for (unsigned int i = 0; i < numDebugLevels; ++i) {
mComboBox->addItem(i18n(debugLevels[i].label));
}
if (entry->isReadOnly()) {
label->setEnabled(false);
mComboBox->setEnabled(false);
} else {
connect(mComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &CryptoConfigEntryDebugLevel::slotChanged);
}
const int row = glay->rowCount();
glay->addWidget(label, row, 1);
glay->addWidget(mComboBox, row, 2);
}
void Kleo::CryptoConfigEntryDebugLevel::doSave()
{
const unsigned int idx = mComboBox->currentIndex();
if (idx < numDebugLevels) {
mEntry->setStringValue(QLatin1String(debugLevels[idx].name));
} else {
mEntry->setStringValue(QString());
}
}
void Kleo::CryptoConfigEntryDebugLevel::doLoad()
{
const QString str = mEntry->stringValue();
for (unsigned int i = 0; i < numDebugLevels; ++i)
if (str == QLatin1String(debugLevels[i].name)) {
mComboBox->setCurrentIndex(i);
return;
}
mComboBox->setCurrentIndex(0);
}
////
Kleo::CryptoConfigEntryPath::CryptoConfigEntryPath(
CryptoConfigModule *module,
QGpgME::CryptoConfigEntry *entry, const QString &entryName,
QGridLayout *glay, QWidget *widget)
: CryptoConfigEntryGUI(module, entry, entryName),
mFileNameRequester(nullptr)
{
const int row = glay->rowCount();
mFileNameRequester = new FileNameRequester(widget);
mFileNameRequester->setExistingOnly(false);
mFileNameRequester->setFilter(QDir::Files);
QLabel *label = new QLabel(description(), widget);
label->setBuddy(mFileNameRequester);
glay->addWidget(label, row, 1);
glay->addWidget(mFileNameRequester, row, 2);
if (entry->isReadOnly()) {
label->setEnabled(false);
mFileNameRequester->setEnabled(false);
} else {
connect(mFileNameRequester, &FileNameRequester::fileNameChanged, this, &CryptoConfigEntryPath::slotChanged);
}
}
void Kleo::CryptoConfigEntryPath::doSave()
{
mEntry->setURLValue(QUrl::fromLocalFile(mFileNameRequester->fileName()));
}
void Kleo::CryptoConfigEntryPath::doLoad()
{
if (mEntry->urlValue().isLocalFile()) {
mFileNameRequester->setFileName(mEntry->urlValue().toLocalFile());
} else {
mFileNameRequester->setFileName(mEntry->urlValue().toString());
}
}
////
Kleo::CryptoConfigEntryDirPath::CryptoConfigEntryDirPath(
CryptoConfigModule *module,
QGpgME::CryptoConfigEntry *entry, const QString &entryName,
QGridLayout *glay, QWidget *widget)
: CryptoConfigEntryGUI(module, entry, entryName),
mFileNameRequester(nullptr)
{
const int row = glay->rowCount();
mFileNameRequester = new FileNameRequester(widget);
mFileNameRequester->setExistingOnly(false);
mFileNameRequester->setFilter(QDir::Dirs);
QLabel *label = new QLabel(description(), widget);
label->setBuddy(mFileNameRequester);
glay->addWidget(label, row, 1);
glay->addWidget(mFileNameRequester, row, 2);
if (entry->isReadOnly()) {
label->setEnabled(false);
mFileNameRequester->setEnabled(false);
} else {
connect(mFileNameRequester, &FileNameRequester::fileNameChanged, this, &CryptoConfigEntryDirPath::slotChanged);
}
}
void Kleo::CryptoConfigEntryDirPath::doSave()
{
mEntry->setURLValue(QUrl::fromLocalFile(mFileNameRequester->fileName()));
}
void Kleo::CryptoConfigEntryDirPath::doLoad()
{
mFileNameRequester->setFileName(mEntry->urlValue().toLocalFile());
}
////
Kleo::CryptoConfigEntrySpinBox::CryptoConfigEntrySpinBox(
CryptoConfigModule *module,
QGpgME::CryptoConfigEntry *entry, const QString &entryName,
QGridLayout *glay, QWidget *widget)
: CryptoConfigEntryGUI(module, entry, entryName)
{
if (entry->argType() == QGpgME::CryptoConfigEntry::ArgType_None && entry->isList()) {
mKind = ListOfNone;
} else if (entry->argType() == QGpgME::CryptoConfigEntry::ArgType_UInt) {
mKind = UInt;
} else {
Q_ASSERT(entry->argType() == QGpgME::CryptoConfigEntry::ArgType_Int);
mKind = Int;
}
const int row = glay->rowCount();
mNumInput = new QSpinBox(widget);
QLabel *label = new QLabel(description(), widget);
label->setBuddy(mNumInput);
glay->addWidget(label, row, 1);
glay->addWidget(mNumInput, row, 2);
if (entry->isReadOnly()) {
label->setEnabled(false);
mNumInput->setEnabled(false);
} else {
mNumInput->setMinimum(mKind == Int ? std::numeric_limits<int>::min() : 0);
mNumInput->setMaximum(std::numeric_limits<int>::max());
connect(mNumInput, QOverload<int>::of(&QSpinBox::valueChanged), this, &CryptoConfigEntrySpinBox::slotChanged);
}
}
void Kleo::CryptoConfigEntrySpinBox::doSave()
{
int value = mNumInput->value();
switch (mKind) {
case ListOfNone:
mEntry->setNumberOfTimesSet(value);
break;
case UInt:
mEntry->setUIntValue(value);
break;
case Int:
mEntry->setIntValue(value);
break;
}
}
void Kleo::CryptoConfigEntrySpinBox::doLoad()
{
int value = 0;
switch (mKind) {
case ListOfNone:
value = mEntry->numberOfTimesSet();
break;
case UInt:
value = mEntry->uintValue();
break;
case Int:
value = mEntry->intValue();
break;
}
mNumInput->setValue(value);
}
////
Kleo::CryptoConfigEntryCheckBox::CryptoConfigEntryCheckBox(
CryptoConfigModule *module,
QGpgME::CryptoConfigEntry *entry, const QString &entryName,
QGridLayout *glay, QWidget *widget)
: CryptoConfigEntryGUI(module, entry, entryName)
{
const int row = glay->rowCount();
mCheckBox = new QCheckBox(widget);
glay->addWidget(mCheckBox, row, 1, 1, 2);
mCheckBox->setText(description());
if (entry->isReadOnly()) {
mCheckBox->setEnabled(false);
} else {
connect(mCheckBox, &QCheckBox::toggled, this, &CryptoConfigEntryCheckBox::slotChanged);
}
}
void Kleo::CryptoConfigEntryCheckBox::doSave()
{
mEntry->setBoolValue(mCheckBox->isChecked());
}
void Kleo::CryptoConfigEntryCheckBox::doLoad()
{
mCheckBox->setChecked(mEntry->boolValue());
}
Kleo::CryptoConfigEntryLDAPURL::CryptoConfigEntryLDAPURL(
CryptoConfigModule *module,
QGpgME::CryptoConfigEntry *entry,
const QString &entryName,
QGridLayout *glay, QWidget *widget)
: CryptoConfigEntryGUI(module, entry, entryName)
{
mLabel = new QLabel(widget);
mPushButton = new QPushButton(entry->isReadOnly() ? i18n("Show...") : i18n("Edit..."), widget);
const int row = glay->rowCount();
QLabel *label = new QLabel(description(), widget);
label->setBuddy(mPushButton);
glay->addWidget(label, row, 1);
QHBoxLayout *hlay = new QHBoxLayout;
glay->addLayout(hlay, row, 2);
hlay->addWidget(mLabel, 1);
hlay->addWidget(mPushButton);
if (entry->isReadOnly()) {
mLabel->setEnabled(false);
}
connect(mPushButton, &QPushButton::clicked, this, &CryptoConfigEntryLDAPURL::slotOpenDialog);
}
void Kleo::CryptoConfigEntryLDAPURL::doLoad()
{
setURLList(mEntry->urlValueList());
}
void Kleo::CryptoConfigEntryLDAPURL::doSave()
{
mEntry->setURLValueList(mURLList);
}
void prepareURLCfgDialog(QDialog *dialog, DirectoryServicesWidget *dirserv, bool readOnly)
{
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok, dialog);
if (!readOnly) {
buttonBox->addButton(QDialogButtonBox::Cancel);
buttonBox->addButton(QDialogButtonBox::RestoreDefaults);
QPushButton *defaultsBtn = buttonBox->button(QDialogButtonBox::RestoreDefaults);
QObject::connect(defaultsBtn, &QPushButton::clicked, dirserv, &DirectoryServicesWidget::clear);
QObject::connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject);
}
QObject::connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(dirserv);
layout->addWidget(buttonBox);
dialog->setLayout(layout);
}
void Kleo::CryptoConfigEntryLDAPURL::slotOpenDialog()
{
// I'm a bad boy and I do it all on the stack. Enough classes already :)
// This is just a simple dialog around the directory-services-widget
QDialog dialog(mPushButton->parentWidget());
dialog.setWindowTitle(i18n("Configure LDAP Servers"));
DirectoryServicesWidget *dirserv = new DirectoryServicesWidget(&dialog);
prepareURLCfgDialog(&dialog, dirserv, mEntry->isReadOnly());
dirserv->setX509ReadOnly(mEntry->isReadOnly());
dirserv->setAllowedSchemes(DirectoryServicesWidget::LDAP);
dirserv->setAllowedProtocols(DirectoryServicesWidget::X509Protocol);
dirserv->addX509Services(mURLList);
if (dialog.exec()) {
setURLList(dirserv->x509Services());
slotChanged();
}
}
void Kleo::CryptoConfigEntryLDAPURL::setURLList(const QList<QUrl> &urlList)
{
mURLList = urlList;
if (mURLList.isEmpty()) {
mLabel->setText(i18n("None configured"));
} else {
mLabel->setText(i18np("1 server configured", "%1 servers configured", mURLList.count()));
}
}
Kleo::CryptoConfigEntryKeyserver::CryptoConfigEntryKeyserver(
CryptoConfigModule *module,
QGpgME::CryptoConfigEntry *entry,
const QString &entryName,
QGridLayout *glay, QWidget *widget)
: CryptoConfigEntryGUI(module, entry, entryName)
{
mLabel = new QLabel(widget);
mPushButton = new QPushButton(i18n("Edit..."), widget);
const int row = glay->rowCount();
QLabel *label = new QLabel(i18n("Use keyserver at"), widget);
label->setBuddy(mPushButton);
glay->addWidget(label, row, 1);
QHBoxLayout *hlay = new QHBoxLayout;
glay->addLayout(hlay, row, 2);
hlay->addWidget(mLabel, 1);
hlay->addWidget(mPushButton);
if (entry->isReadOnly()) {
mLabel->setEnabled(false);
mPushButton->hide();
} else {
connect(mPushButton, &QPushButton::clicked, this, &CryptoConfigEntryKeyserver::slotOpenDialog);
}
}
Kleo::ParsedKeyserver Kleo::parseKeyserver(const QString &str)
{
const QStringList list = str.split(QRegExp(QLatin1String("[\\s,]")), QString::SkipEmptyParts);
if (list.empty()) {
return Kleo::ParsedKeyserver();
}
Kleo::ParsedKeyserver result;
result.url = list.front();
Q_FOREACH (const QString &kvpair, list.mid(1)) {
const int idx = kvpair.indexOf(QLatin1Char('='));
if (idx < 0) {
result.options.push_back(qMakePair(kvpair, QString())); // null QString
} else {
const QString key = kvpair.left(idx);
const QString value = kvpair.mid(idx + 1);
if (value.isEmpty()) {
result.options.push_back(qMakePair(key, QStringLiteral(""))); // make sure it's not a null QString, only an empty one
} else {
result.options.push_back(qMakePair(key, value));
}
}
}
return result;
}
QString Kleo::assembleKeyserver(const ParsedKeyserver &keyserver)
{
if (keyserver.options.empty()) {
return keyserver.url;
}
QString result = keyserver.url;
typedef QPair<QString, QString> Pair;
for (const Pair &pair : qAsConst(keyserver.options))
if (pair.second.isNull()) {
result += QLatin1Char(' ') + pair.first;
} else {
result += QLatin1Char(' ') + pair.first + QLatin1Char('=') + pair.second;
}
return result;
}
void Kleo::CryptoConfigEntryKeyserver::doLoad()
{
mParsedKeyserver = parseKeyserver(mEntry->stringValue());
mLabel->setText(mParsedKeyserver.url);
}
void Kleo::CryptoConfigEntryKeyserver::doSave()
{
mParsedKeyserver.url = mLabel->text();
mEntry->setStringValue(assembleKeyserver(mParsedKeyserver));
}
static QList<QUrl> string2urls(const QString &str)
{
QList<QUrl> ret;
if (str.isEmpty()) {
return ret;
}
ret << QUrl::fromUserInput(str);
return ret;
}
static QString urls2string(const QList<QUrl> &urls)
{
return urls.empty() ? QString() : urls.front().url();
}
void Kleo::CryptoConfigEntryKeyserver::slotOpenDialog()
{
// I'm a bad boy and I do it all on the stack. Enough classes already :)
// This is just a simple dialog around the directory-services-widget
QDialog dialog(mPushButton->parentWidget());
dialog.setWindowTitle(i18n("Configure Keyservers"));
DirectoryServicesWidget *dirserv = new DirectoryServicesWidget(&dialog);
prepareURLCfgDialog(&dialog, dirserv, mEntry->isReadOnly());
dirserv->setOpenPGPReadOnly(mEntry->isReadOnly());
dirserv->setAllowedSchemes(DirectoryServicesWidget::AllSchemes);
dirserv->setAllowedProtocols(DirectoryServicesWidget::OpenPGPProtocol);
dirserv->addOpenPGPServices(string2urls(mLabel->text()));
if (dialog.exec()) {
mLabel->setText(urls2string(dirserv->openPGPServices()));
slotChanged();
}
}
#include "moc_cryptoconfigmodule_p.cpp"
diff --git a/src/ui/dnattributeorderconfigwidget.cpp b/src/ui/dnattributeorderconfigwidget.cpp
index b17ee8a3..75e2209d 100644
--- a/src/ui/dnattributeorderconfigwidget.cpp
+++ b/src/ui/dnattributeorderconfigwidget.cpp
@@ -1,378 +1,378 @@
/* -*- c++ -*-
dnattributeorderconfigwidget.cpp
This file is part of libkleopatra, the KDE keymanagement library
Copyright (c) 2004 Klarävdalens Datakonsult AB
Libkleopatra is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
Libkleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include "dnattributeorderconfigwidget.h"
#include "libkleo_debug.h"
#include "libkleo/dn.h"
#include <KLocalizedString>
#include <qdebug.h>
#include <kconfig.h>
#include <QIcon>
#include <QToolButton>
#include <QGridLayout>
#include <QLabel>
#include <QTreeWidget>
#include <QHeaderView>
class Kleo::DNAttributeOrderConfigWidget::Private
{
public:
enum { UUp = 0, Up = 1, Left = 2, Right = 3, Down = 4, DDown = 5 };
#ifndef QT_NO_TREEWIDGET
QTreeWidget *availableLV = nullptr;
QTreeWidget *currentLV = nullptr;
#endif
QToolButton *navTB[6];
#ifndef QT_NO_TREEWIDGET
QTreeWidgetItem *placeHolderItem = nullptr;
#endif
Kleo::DNAttributeMapper *mapper = nullptr;
};
#ifndef QT_NO_TREEWIDGET
static void prepare(QTreeWidget *lv)
{
lv->setAllColumnsShowFocus(true);
lv->header()->setStretchLastSection(true);
lv->setHeaderLabels(QStringList() << QString() << i18n("Description"));
}
#endif
Kleo::DNAttributeOrderConfigWidget::DNAttributeOrderConfigWidget(DNAttributeMapper *mapper, QWidget *parent, Qt::WindowFlags f)
: QWidget(parent, f), d(new Private)
{
Q_ASSERT(mapper);
d->mapper = mapper;
QGridLayout *glay = new QGridLayout(this);
- glay->setMargin(0);
+ glay->setContentsMargins(0, 0, 0, 0);
glay->setColumnStretch(0, 1);
glay->setColumnStretch(2, 1);
int row = -1;
++row;
glay->addWidget(new QLabel(i18n("Available attributes:"), this), row, 0);
glay->addWidget(new QLabel(i18n("Current attribute order:"), this), row, 2);
++row;
glay->setRowStretch(row, 1);
#ifndef QT_NO_TREEWIDGET
d->availableLV = new QTreeWidget(this);
prepare(d->availableLV);
d->availableLV->sortItems(0, Qt::AscendingOrder);
glay->addWidget(d->availableLV, row, 0);
d->currentLV = new QTreeWidget(this);
prepare(d->currentLV);
glay->addWidget(d->currentLV, row, 2);
connect(d->availableLV, &QTreeWidget::itemClicked, this, &DNAttributeOrderConfigWidget::slotAvailableSelectionChanged);
connect(d->currentLV, &QTreeWidget::itemClicked, this, &DNAttributeOrderConfigWidget::slotCurrentOrderSelectionChanged);
d->placeHolderItem = new QTreeWidgetItem(d->availableLV);
d->placeHolderItem->setText(0, QStringLiteral("_X_"));
d->placeHolderItem->setText(1, i18n("All others"));
#endif
// the up/down/left/right arrow cross:
QGridLayout *xlay = new QGridLayout();
xlay->setSpacing(0);
xlay->setObjectName(QStringLiteral("xlay"));
xlay->setAlignment(Qt::AlignCenter);
static const struct {
const char *icon;
int row, col;
const char *tooltip;
void(DNAttributeOrderConfigWidget::*slot)();
bool autorepeat;
} navButtons[] = {
{ "go-top", 0, 1, I18N_NOOP("Move to top"), &DNAttributeOrderConfigWidget::slotDoubleUpButtonClicked, false },
{ "go-up", 1, 1, I18N_NOOP("Move one up"), &DNAttributeOrderConfigWidget::slotUpButtonClicked, true },
{ "go-previous", 2, 0, I18N_NOOP("Remove from current attribute order"), &DNAttributeOrderConfigWidget::slotLeftButtonClicked, false },
{ "go-next", 2, 2, I18N_NOOP("Add to current attribute order"), &DNAttributeOrderConfigWidget::slotRightButtonClicked, false },
{ "go-down", 3, 1, I18N_NOOP("Move one down"), &DNAttributeOrderConfigWidget::slotDownButtonClicked, true },
{ "go-bottom", 4, 1, I18N_NOOP("Move to bottom"), &DNAttributeOrderConfigWidget::slotDoubleDownButtonClicked, false }
};
for (unsigned int i = 0; i < sizeof navButtons / sizeof * navButtons; ++i) {
QToolButton *tb = d->navTB[i] = new QToolButton(this);
tb->setIcon(QIcon::fromTheme(QLatin1String(navButtons[i].icon)));
tb->setEnabled(false);
tb->setToolTip(i18n(navButtons[i].tooltip));
xlay->addWidget(tb, navButtons[i].row, navButtons[i].col);
tb->setAutoRepeat(navButtons[i].autorepeat);
connect(tb, &QToolButton::clicked, this, navButtons[i].slot);
}
glay->addLayout(xlay, row, 1);
}
Kleo::DNAttributeOrderConfigWidget::~DNAttributeOrderConfigWidget()
{
delete d;
}
void Kleo::DNAttributeOrderConfigWidget::load()
{
#ifndef QT_NO_TREEWIDGET
// save the _X_ item:
takePlaceHolderItem();
// clear the rest:
d->availableLV->clear();
d->currentLV->clear();
const QStringList order = d->mapper->attributeOrder();
// fill the RHS listview:
QTreeWidgetItem *last = nullptr;
for (QStringList::const_iterator it = order.begin(); it != order.end(); ++it) {
const QString attr = (*it).toUpper();
if (attr == QLatin1String("_X_")) {
takePlaceHolderItem();
d->currentLV->insertTopLevelItem(d->currentLV->topLevelItemCount(), d->placeHolderItem);
last = d->placeHolderItem;
} else {
last = new QTreeWidgetItem(d->currentLV, last);
last->setText(0, attr);
last->setText(1, d->mapper->name2label(attr));
}
}
// fill the LHS listview with what's left:
const QStringList all = Kleo::DNAttributeMapper::instance()->names();
const QStringList::const_iterator end(all.end());
for (QStringList::const_iterator it = all.begin(); it != end; ++it) {
if (!order.contains(*it)) {
QTreeWidgetItem *item = new QTreeWidgetItem(d->availableLV);
item->setText(0, *it);
item->setText(1, d->mapper->name2label(*it));
}
}
if (!d->placeHolderItem->treeWidget()) {
d->availableLV->addTopLevelItem(d->placeHolderItem);
}
#endif
}
void Kleo::DNAttributeOrderConfigWidget::takePlaceHolderItem()
{
#ifndef QT_NO_TREEWIDGET
if (QTreeWidget *lv = d->placeHolderItem->treeWidget()) {
lv->takeTopLevelItem(lv->indexOfTopLevelItem(d->placeHolderItem));
}
#endif
}
void Kleo::DNAttributeOrderConfigWidget::save() const
{
#ifndef QT_NO_TREEWIDGET
QStringList order;
for (QTreeWidgetItemIterator it(d->currentLV); (*it); ++it) {
order.push_back((*it)->text(0));
}
d->mapper->setAttributeOrder(order);
#endif
}
void Kleo::DNAttributeOrderConfigWidget::defaults()
{
qCDebug (LIBKLEO_LOG) << "Sorry, not implemented: Kleo::DNAttributeOrderConfigWidget::defaults()";
}
void Kleo::DNAttributeOrderConfigWidget::slotAvailableSelectionChanged(QTreeWidgetItem *item)
{
d->navTB[Private::Right]->setEnabled(item);
}
void Kleo::DNAttributeOrderConfigWidget::slotCurrentOrderSelectionChanged(QTreeWidgetItem *item)
{
enableDisableButtons(item);
}
void Kleo::DNAttributeOrderConfigWidget::enableDisableButtons(QTreeWidgetItem *item)
{
#ifndef QT_NO_TREEWIDGET
d->navTB[Private::UUp ]->setEnabled(item && d->currentLV->itemAbove(item));
d->navTB[Private::Up ]->setEnabled(item && d->currentLV->itemAbove(item));
d->navTB[Private::Left ]->setEnabled(item);
d->navTB[Private::Down ]->setEnabled(item && d->currentLV->itemBelow(item));
d->navTB[Private::DDown]->setEnabled(item && d->currentLV->itemBelow(item));
#endif
}
void Kleo::DNAttributeOrderConfigWidget::slotUpButtonClicked()
{
#ifndef QT_NO_TREEWIDGET
if (d->currentLV->selectedItems().isEmpty()) {
return;
}
QTreeWidgetItem *item = d->currentLV->selectedItems().first();
int itemIndex = d->currentLV->indexOfTopLevelItem(item);
if (itemIndex <= 0) {
return;
}
d->currentLV->takeTopLevelItem(itemIndex);
d->currentLV->insertTopLevelItem(itemIndex - 1, item);
d->currentLV->clearSelection();
item->setSelected(true);
enableDisableButtons(item);
Q_EMIT changed();
#endif
}
void Kleo::DNAttributeOrderConfigWidget::slotDoubleUpButtonClicked()
{
#ifndef QT_NO_TREEWIDGET
if (d->currentLV->selectedItems().isEmpty()) {
return;
}
QTreeWidgetItem *item = d->currentLV->selectedItems().first();
int itemIndex = d->currentLV->indexOfTopLevelItem(item);
if (itemIndex == 0) {
return;
}
d->currentLV->takeTopLevelItem(itemIndex);
d->currentLV->insertTopLevelItem(0, item);
d->currentLV->clearSelection();
item->setSelected(true);
enableDisableButtons(item);
Q_EMIT changed();
#endif
}
void Kleo::DNAttributeOrderConfigWidget::slotDownButtonClicked()
{
#ifndef QT_NO_TREEWIDGET
if (d->currentLV->selectedItems().isEmpty()) {
return;
}
QTreeWidgetItem *item = d->currentLV->selectedItems().first();
int itemIndex = d->currentLV->indexOfTopLevelItem(item);
if (itemIndex + 1 >= d->currentLV->topLevelItemCount()) {
return;
}
d->currentLV->takeTopLevelItem(itemIndex);
d->currentLV->insertTopLevelItem(itemIndex + 1, item);
d->currentLV->clearSelection();
item->setSelected(true);
enableDisableButtons(item);
Q_EMIT changed();
#endif
}
void Kleo::DNAttributeOrderConfigWidget::slotDoubleDownButtonClicked()
{
#ifndef QT_NO_TREEWIDGET
if (d->currentLV->selectedItems().isEmpty()) {
return;
}
QTreeWidgetItem *item = d->currentLV->selectedItems().first();
const int itemIndex = d->currentLV->indexOfTopLevelItem(item);
if (itemIndex + 1 >= d->currentLV->topLevelItemCount()) {
return;
}
d->currentLV->takeTopLevelItem(itemIndex);
d->currentLV->addTopLevelItem(item);
d->currentLV->clearSelection();
item->setSelected(true);
enableDisableButtons(item);
Q_EMIT changed();
#endif
}
void Kleo::DNAttributeOrderConfigWidget::slotLeftButtonClicked()
{
#ifndef QT_NO_TREEWIDGET
if (d->currentLV->selectedItems().isEmpty()) {
return;
}
QTreeWidgetItem *right = d->currentLV->selectedItems().first();
QTreeWidgetItem *next = d->currentLV->itemBelow(right);
if (!next) {
next = d->currentLV->itemAbove(right);
}
d->currentLV->takeTopLevelItem(d->currentLV->indexOfTopLevelItem(right));
d->availableLV->addTopLevelItem(right);
d->availableLV->sortItems(0, Qt::AscendingOrder);
if (next) {
next->setSelected(true);
}
enableDisableButtons(next);
Q_EMIT changed();
#endif
}
void Kleo::DNAttributeOrderConfigWidget::slotRightButtonClicked()
{
#ifndef QT_NO_TREEWIDGET
if (d->availableLV->selectedItems().isEmpty()) {
return;
}
QTreeWidgetItem *left = d->availableLV->selectedItems().first();
QTreeWidgetItem *next = d->availableLV->itemBelow(left);
if (!next) {
next = d->availableLV->itemAbove(left);
}
d->availableLV->takeTopLevelItem(d->availableLV->indexOfTopLevelItem(left));
int newRightIndex = d->currentLV->topLevelItemCount();
if (!d->currentLV->selectedItems().isEmpty()) {
QTreeWidgetItem *right = d->currentLV->selectedItems().first();
newRightIndex = d->currentLV->indexOfTopLevelItem(right);
right->setSelected(false);
}
d->currentLV->insertTopLevelItem(newRightIndex, left);
left->setSelected(true);
enableDisableButtons(left);
d->navTB[Private::Right]->setEnabled(next);
if (next) {
next->setSelected(true);
}
Q_EMIT changed();
#endif
}
void Kleo::DNAttributeOrderConfigWidget::virtual_hook(int, void *) {}
diff --git a/src/ui/filenamerequester.cpp b/src/ui/filenamerequester.cpp
index 6ae04a4f..6b813128 100644
--- a/src/ui/filenamerequester.cpp
+++ b/src/ui/filenamerequester.cpp
@@ -1,203 +1,203 @@
/* -*- mode: c++; c-basic-offset:4 -*-
ui/filenamerequester.cpp
This file is part of Kleopatra, the KDE keymanager
Copyright (c) 2007 Klarälvdalens Datakonsult AB
Kleopatra is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Kleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include "filenamerequester.h"
#include <KLineEdit>
#include <QHBoxLayout>
#include <QToolButton>
#include <QCompleter>
#include <QDirModel>
#include <QString>
#include <QFileDialog>
using namespace Kleo;
class Q_DECL_HIDDEN FileNameRequester::Private
{
friend class ::Kleo::FileNameRequester;
FileNameRequester *const q;
public:
explicit Private(FileNameRequester *qq);
~Private();
private:
void slotButtonClicked();
private:
#ifndef QT_NO_DIRMODEL
QDirModel dirmodel;
QCompleter completer;
#else
QDir::Filters filter;
#endif
KLineEdit lineedit;
QToolButton button;
QHBoxLayout hlay;
QString nameFilter;
bool existingOnly;
};
FileNameRequester::Private::Private(FileNameRequester *qq)
: q(qq),
#ifndef QT_NO_DIRMODEL
dirmodel(),
completer(&dirmodel),
#else
filter(),
#endif
lineedit(q),
button(q),
hlay(q),
nameFilter(),
existingOnly(true)
{
#ifndef QT_NO_DIRMODEL
dirmodel.setObjectName(QStringLiteral("dirmodel"));
completer.setObjectName(QStringLiteral("completer"));
#endif
lineedit.setObjectName(QStringLiteral("lineedit"));
button.setObjectName(QStringLiteral("button"));
hlay.setObjectName(QStringLiteral("hlay"));
button.setIcon(QIcon::fromTheme(QStringLiteral("document-open")));
#ifndef QT_NO_DIRMODEL
lineedit.setCompleter(&completer);
#endif
lineedit.setClearButtonEnabled(true);
- hlay.setMargin(0);
+ hlay.setContentsMargins(0, 0, 0, 0);
hlay.addWidget(&lineedit);
hlay.addWidget(&button);
connect(&button, &QToolButton::clicked, q, [this]() { slotButtonClicked(); });
connect(&lineedit, &KLineEdit::textChanged, q, &FileNameRequester::fileNameChanged);
}
FileNameRequester::Private::~Private() {}
FileNameRequester::FileNameRequester(QWidget *p)
: QWidget(p), d(new Private(this))
{
}
FileNameRequester::FileNameRequester(QDir::Filters f, QWidget *p)
: QWidget(p), d(new Private(this))
{
#ifndef QT_NO_DIRMODEL
d->dirmodel.setFilter(f);
#else
d->filter = f;
#endif
}
FileNameRequester::~FileNameRequester()
{
delete d;
}
void FileNameRequester::setFileName(const QString &file)
{
d->lineedit.setText(file);
}
QString FileNameRequester::fileName() const
{
return d->lineedit.text();
}
void FileNameRequester::setExistingOnly(bool on)
{
d->existingOnly = on;
}
bool FileNameRequester::existingOnly() const
{
return d->existingOnly;
}
void FileNameRequester::setFilter(QDir::Filters f)
{
#ifndef QT_NO_DIRMODEL
d->dirmodel.setFilter(f);
#else
d->filter = f;
#endif
}
QDir::Filters FileNameRequester::filter() const
{
#ifndef QT_NO_DIRMODEL
return d->dirmodel.filter();
#else
return d->filter;
#endif
}
void FileNameRequester::setNameFilter(const QString &nameFilter)
{
d->nameFilter = nameFilter;
}
QString FileNameRequester::nameFilter() const
{
return d->nameFilter;
}
void FileNameRequester::Private::slotButtonClicked()
{
const QString fileName = q->requestFileName();
if (!fileName.isEmpty()) {
q->setFileName(fileName);
}
}
QString FileNameRequester::requestFileName()
{
#ifndef QT_NO_FILEDIALOG
const QDir::Filters filters = filter();
if ((filters & QDir::Dirs) && !(filters & QDir::Files)) {
return QFileDialog::getExistingDirectory(this);
} else if (d->existingOnly) {
return QFileDialog::getOpenFileName(this, QString(), QString(), d->nameFilter);
} else {
return QFileDialog::getSaveFileName(this, QString(), QString(), d->nameFilter);
}
#else
return QString();
#endif
}
#include "moc_filenamerequester.cpp"
diff --git a/src/ui/keyapprovaldialog.cpp b/src/ui/keyapprovaldialog.cpp
index 39b44f3d..7e019ba0 100644
--- a/src/ui/keyapprovaldialog.cpp
+++ b/src/ui/keyapprovaldialog.cpp
@@ -1,222 +1,222 @@
/* -*- c++ -*-
keyapprovaldialog.h
This file is part of libkleopatra, the KDE keymanagement library
Copyright (c) 2004 Klarälvdalens Datakonsult AB
Based on kpgpui.h
Copyright (C) 2001,2002 the KPGP authors
See file libkdenetwork/AUTHORS.kpgp for details
Libkleopatra is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
Libkleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include "keyapprovaldialog.h"
#include "keyrequester.h"
#include <qpushbutton.h>
#include <KLocalizedString>
#include <kseparator.h>
#include <QStringList>
#include <QLabel>
#include <QComboBox>
#include <QScrollArea>
#include <QPushButton>
#include <QVBoxLayout>
#include <QGridLayout>
#include <gpgme++/key.h>
#include <qgpgme/protocol.h>
#include <QApplication>
#include <QDesktopWidget>
#include <QDialogButtonBox>
static Kleo::EncryptionPreference cb2pref(int i)
{
switch (i) {
default:
case 0: return Kleo::UnknownPreference;
case 1: return Kleo::NeverEncrypt;
case 2: return Kleo::AlwaysEncrypt;
case 3: return Kleo::AlwaysEncryptIfPossible;
case 4: return Kleo::AlwaysAskForEncryption;
case 5: return Kleo::AskWheneverPossible;
}
}
static int pref2cb(Kleo::EncryptionPreference p)
{
switch (p) {
default: return 0;
case Kleo::NeverEncrypt: return 1;
case Kleo::AlwaysEncrypt: return 2;
case Kleo::AlwaysEncryptIfPossible: return 3;
case Kleo::AlwaysAskForEncryption: return 4;
case Kleo::AskWheneverPossible: return 5;
}
}
static QStringList preferencesStrings()
{
return QStringList() << xi18n("<placeholder>none</placeholder>")
<< i18n("Never Encrypt with This Key")
<< i18n("Always Encrypt with This Key")
<< i18n("Encrypt Whenever Encryption is Possible")
<< i18n("Always Ask")
<< i18n("Ask Whenever Encryption is Possible");
}
class Q_DECL_HIDDEN Kleo::KeyApprovalDialog::Private
{
public:
Private() {}
Kleo::KeyRequester *selfRequester = nullptr;
QStringList addresses;
std::vector<Kleo::KeyRequester *> requesters;
std::vector<QComboBox *> preferences;
bool prefsChanged = false;
};
Kleo::KeyApprovalDialog::KeyApprovalDialog(const std::vector<Item> &recipients,
const std::vector<GpgME::Key> &sender,
QWidget *parent)
: QDialog(parent),
d(new Private())
{
setWindowTitle(i18n("Encryption Key Approval"));
QVBoxLayout *mainLayout = new QVBoxLayout(this);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
connect(buttonBox, &QDialogButtonBox::accepted, this, &KeyApprovalDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &KeyApprovalDialog::reject);
okButton->setDefault(true);
Q_ASSERT(!recipients.empty());
QFrame *page = new QFrame(this);
mainLayout->addWidget(page);
mainLayout->addWidget(buttonBox);
QVBoxLayout *vlay = new QVBoxLayout(page);
- vlay->setMargin(0);
+ vlay->setContentsMargins(0, 0, 0, 0);
vlay->addWidget(new QLabel(i18n("The following keys will be used for encryption:"), page));
QScrollArea *sv = new QScrollArea(page);
sv->setWidgetResizable(true);
vlay->addWidget(sv);
QWidget *view = new QWidget(sv->viewport());
QGridLayout *glay = new QGridLayout(view);
glay->setColumnStretch(1, 1);
sv->setWidget(view);
int row = -1;
if (!sender.empty()) {
++row;
glay->addWidget(new QLabel(i18n("Your keys:"), view), row, 0);
d->selfRequester = new EncryptionKeyRequester(true, EncryptionKeyRequester::AllProtocols, view);
d->selfRequester->setKeys(sender);
glay->addWidget(d->selfRequester, row, 1);
++row;
glay->addWidget(new KSeparator(Qt::Horizontal, view), row, 0, 1, 2);
}
const QStringList prefs = preferencesStrings();
for (std::vector<Item>::const_iterator it = recipients.begin(); it != recipients.end(); ++it) {
++row;
glay->addWidget(new QLabel(i18n("Recipient:"), view), row, 0);
glay->addWidget(new QLabel(it->address, view), row, 1);
d->addresses.push_back(it->address);
++row;
glay->addWidget(new QLabel(i18n("Encryption keys:"), view), row, 0);
KeyRequester *req = new EncryptionKeyRequester(true, EncryptionKeyRequester::AllProtocols, view);
req->setKeys(it->keys);
glay->addWidget(req, row, 1);
d->requesters.push_back(req);
++row;
glay->addWidget(new QLabel(i18n("Encryption preference:"), view), row, 0);
QComboBox *cb = new QComboBox(view);
cb->setEditable(false);
cb->addItems(prefs);
glay->addWidget(cb, row, 1);
cb->setCurrentIndex(pref2cb(it->pref));
connect(cb, QOverload<int>::of(&QComboBox::activated), this, &KeyApprovalDialog::slotPrefsChanged);
d->preferences.push_back(cb);
}
QSize size = sizeHint();
// don't make the dialog too large
const QRect desk = QApplication::desktop()->screenGeometry(this);
resize(QSize(qMin(size.width(), 3 * desk.width() / 4),
qMin(size.height(), 7 * desk.height() / 8)));
}
Kleo::KeyApprovalDialog::~KeyApprovalDialog()
{
delete d;
}
std::vector<GpgME::Key> Kleo::KeyApprovalDialog::senderKeys() const
{
return d->selfRequester ? d->selfRequester->keys() : std::vector<GpgME::Key>();
}
std::vector<Kleo::KeyApprovalDialog::Item> Kleo::KeyApprovalDialog::items() const
{
Q_ASSERT(d->requesters.size() == static_cast<unsigned int>(d->addresses.size()));
Q_ASSERT(d->requesters.size() == d->preferences.size());
std::vector<Item> result;
result.reserve(d->requesters.size());
QStringList::const_iterator ait = d->addresses.constBegin();
std::vector<KeyRequester *>::iterator rit = d->requesters.begin();
std::vector<QComboBox *>::iterator cit = d->preferences.begin();
while (ait != d->addresses.constEnd()) {
result.push_back(Item(*ait++, (*rit++)->keys(), cb2pref((*cit++)->currentIndex())));
}
return result;
}
bool Kleo::KeyApprovalDialog::preferencesChanged() const
{
return d->prefsChanged;
}
void Kleo::KeyApprovalDialog::slotPrefsChanged()
{
d->prefsChanged = true;
}
diff --git a/src/ui/keyrequester.cpp b/src/ui/keyrequester.cpp
index ee117396..809e3f84 100644
--- a/src/ui/keyrequester.cpp
+++ b/src/ui/keyrequester.cpp
@@ -1,524 +1,524 @@
/* -*- c++ -*-
keyrequester.cpp
This file is part of libkleopatra, the KDE keymanagement library
Copyright (c) 2004 Klar�vdalens Datakonsult AB
Libkleopatra is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
Libkleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
Based on kpgpui.cpp
Copyright (C) 2001,2002 the KPGP authors
See file libkdenetwork/AUTHORS.kpgp for details
This file is part of KPGP, the KDE PGP/GnuPG support library.
KPGP is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "keyrequester.h"
#include "keyselectiondialog.h"
#include "libkleo/dn.h"
// gpgme++
#include <gpgme++/key.h>
#include <gpgme++/keylistresult.h>
#include <qgpgme/protocol.h>
#include <qgpgme/keylistjob.h>
// KDE
#include <KLocalizedString>
#include <QDialog>
#include <kmessagebox.h>
#include <qpushbutton.h>
// Qt
#include <QApplication>
#include <QString>
#include <QStringList>
#include <QLabel>
#include <QHBoxLayout>
using namespace QGpgME;
Kleo::KeyRequester::KeyRequester(unsigned int allowedKeys, bool multipleKeys,
QWidget *parent)
: QWidget(parent),
mOpenPGPBackend(nullptr),
mSMIMEBackend(nullptr),
mMulti(multipleKeys),
mKeyUsage(allowedKeys),
mJobs(0),
d(nullptr)
{
init();
}
Kleo::KeyRequester::KeyRequester(QWidget *parent)
: QWidget(parent),
mOpenPGPBackend(nullptr),
mSMIMEBackend(nullptr),
mMulti(false),
mKeyUsage(0),
mJobs(0),
d(nullptr)
{
init();
}
void Kleo::KeyRequester::init()
{
QHBoxLayout *hlay = new QHBoxLayout(this);
- hlay->setMargin(0);
+ hlay->setContentsMargins(0, 0, 0, 0);
// the label where the key id is to be displayed:
mLabel = new QLabel(this);
mLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
// the button to unset any key:
mEraseButton = new QPushButton(this);
mEraseButton->setAutoDefault(false);
mEraseButton->setSizePolicy(QSizePolicy(QSizePolicy::Minimum,
QSizePolicy::Minimum));
mEraseButton->setIcon(QIcon::fromTheme(QApplication::isRightToLeft() ? QStringLiteral("edit-clear-locationbar-ltr") : QStringLiteral("edit-clear-locationbar-rtl")));
mEraseButton->setToolTip(i18n("Clear"));
// the button to call the KeySelectionDialog:
mDialogButton = new QPushButton(i18n("Change..."), this);
mDialogButton->setAutoDefault(false);
hlay->addWidget(mLabel, 1);
hlay->addWidget(mEraseButton);
hlay->addWidget(mDialogButton);
connect(mEraseButton, &QPushButton::clicked, this, &SigningKeyRequester::slotEraseButtonClicked);
connect(mDialogButton, &QPushButton::clicked, this, &SigningKeyRequester::slotDialogButtonClicked);
setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding,
QSizePolicy::Fixed));
setAllowedKeys(mKeyUsage);
}
Kleo::KeyRequester::~KeyRequester()
{
}
const std::vector<GpgME::Key> &Kleo::KeyRequester::keys() const
{
return mKeys;
}
const GpgME::Key &Kleo::KeyRequester::key() const
{
static const GpgME::Key null = GpgME::Key::null;
if (mKeys.empty()) {
return null;
} else {
return mKeys.front();
}
}
void Kleo::KeyRequester::setKeys(const std::vector<GpgME::Key> &keys)
{
mKeys.clear();
for (std::vector<GpgME::Key>::const_iterator it = keys.begin(); it != keys.end(); ++it)
if (!it->isNull()) {
mKeys.push_back(*it);
}
updateKeys();
}
void Kleo::KeyRequester::setKey(const GpgME::Key &key)
{
mKeys.clear();
if (!key.isNull()) {
mKeys.push_back(key);
}
updateKeys();
}
QString Kleo::KeyRequester::fingerprint() const
{
if (mKeys.empty()) {
return QString();
} else {
return QLatin1String(mKeys.front().primaryFingerprint());
}
}
QStringList Kleo::KeyRequester::fingerprints() const
{
QStringList result;
for (std::vector<GpgME::Key>::const_iterator it = mKeys.begin(); it != mKeys.end(); ++it)
if (!it->isNull())
if (const char *fpr = it->primaryFingerprint()) {
result.push_back(QLatin1String(fpr));
}
return result;
}
void Kleo::KeyRequester::setFingerprint(const QString &fingerprint)
{
startKeyListJob(QStringList(fingerprint));
}
void Kleo::KeyRequester::setFingerprints(const QStringList &fingerprints)
{
startKeyListJob(fingerprints);
}
void Kleo::KeyRequester::updateKeys()
{
if (mKeys.empty()) {
mLabel->clear();
return;
}
if (mKeys.size() > 1) {
setMultipleKeysEnabled(true);
}
QStringList labelTexts;
QString toolTipText;
for (std::vector<GpgME::Key>::const_iterator it = mKeys.begin(); it != mKeys.end(); ++it) {
if (it->isNull()) {
continue;
}
const QString fpr = QLatin1String(it->primaryFingerprint());
labelTexts.push_back(fpr.right(8));
toolTipText += fpr.right(8) + QLatin1String(": ");
if (const char *uid = it->userID(0).id())
if (it->protocol() == GpgME::OpenPGP) {
toolTipText += QString::fromUtf8(uid);
} else {
toolTipText += Kleo::DN(uid).prettyDN();
}
else {
toolTipText += xi18n("<placeholder>unknown</placeholder>");
}
toolTipText += QLatin1Char('\n');
}
mLabel->setText(labelTexts.join(QStringLiteral(", ")));
mLabel->setToolTip(toolTipText);
}
#ifndef __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
#define __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
static void showKeyListError(QWidget *parent, const GpgME::Error &err)
{
Q_ASSERT(err);
const QString msg = i18n("<qt><p>An error occurred while fetching "
"the keys from the backend:</p>"
"<p><b>%1</b></p></qt>",
QString::fromLocal8Bit(err.asString()));
KMessageBox::error(parent, msg, i18n("Key Listing Failed"));
}
#endif // __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
void Kleo::KeyRequester::startKeyListJob(const QStringList &fingerprints)
{
if (!mSMIMEBackend && !mOpenPGPBackend) {
return;
}
mTmpKeys.clear();
mJobs = 0;
unsigned int count = 0;
for (QStringList::const_iterator it = fingerprints.begin(); it != fingerprints.end(); ++it)
if (!(*it).trimmed().isEmpty()) {
++count;
}
if (!count) {
// don't fall into the trap that an empty pattern means
// "return all keys" :)
setKey(GpgME::Key::null);
return;
}
if (mOpenPGPBackend) {
KeyListJob *job = mOpenPGPBackend->keyListJob(false); // local, no sigs
if (!job) {
KMessageBox::error(this,
i18n("The OpenPGP backend does not support listing keys. "
"Check your installation."),
i18n("Key Listing Failed"));
} else {
connect(job, &KeyListJob::result, this, &SigningKeyRequester::slotKeyListResult);
connect(job, &KeyListJob::nextKey, this, &SigningKeyRequester::slotNextKey);
const GpgME::Error err = job->start(fingerprints,
mKeyUsage & Kleo::KeySelectionDialog::SecretKeys &&
!(mKeyUsage & Kleo::KeySelectionDialog::PublicKeys));
if (err) {
showKeyListError(this, err);
} else {
++mJobs;
}
}
}
if (mSMIMEBackend) {
KeyListJob *job = mSMIMEBackend->keyListJob(false); // local, no sigs
if (!job) {
KMessageBox::error(this,
i18n("The S/MIME backend does not support listing keys. "
"Check your installation."),
i18n("Key Listing Failed"));
} else {
connect(job, &KeyListJob::result, this, &SigningKeyRequester::slotKeyListResult);
connect(job, &KeyListJob::nextKey, this, &SigningKeyRequester::slotNextKey);
const GpgME::Error err = job->start(fingerprints,
mKeyUsage & Kleo::KeySelectionDialog::SecretKeys &&
!(mKeyUsage & Kleo::KeySelectionDialog::PublicKeys));
if (err) {
showKeyListError(this, err);
} else {
++mJobs;
}
}
}
if (mJobs > 0) {
mEraseButton->setEnabled(false);
mDialogButton->setEnabled(false);
}
}
void Kleo::KeyRequester::slotNextKey(const GpgME::Key &key)
{
if (!key.isNull()) {
mTmpKeys.push_back(key);
}
}
void Kleo::KeyRequester::slotKeyListResult(const GpgME::KeyListResult &res)
{
if (res.error()) {
showKeyListError(this, res.error());
}
if (--mJobs <= 0) {
mEraseButton->setEnabled(true);
mDialogButton->setEnabled(true);
setKeys(mTmpKeys);
mTmpKeys.clear();
}
}
void Kleo::KeyRequester::slotDialogButtonClicked()
{
KeySelectionDialog *dlg = mKeys.empty()
? new KeySelectionDialog(mDialogCaption, mDialogMessage, mInitialQuery, mKeyUsage, mMulti, false, this)
: new KeySelectionDialog(mDialogCaption, mDialogCaption, mKeys, mKeyUsage, mMulti, false, this);
if (dlg->exec() == QDialog::Accepted) {
if (mMulti) {
setKeys(dlg->selectedKeys());
} else {
setKey(dlg->selectedKey());
}
Q_EMIT changed();
}
delete dlg;
}
void Kleo::KeyRequester::slotEraseButtonClicked()
{
if (!mKeys.empty()) {
Q_EMIT changed();
}
mKeys.clear();
updateKeys();
}
void Kleo::KeyRequester::setDialogCaption(const QString &caption)
{
mDialogCaption = caption;
}
void Kleo::KeyRequester::setDialogMessage(const QString &msg)
{
mDialogMessage = msg;
}
bool Kleo::KeyRequester::isMultipleKeysEnabled() const
{
return mMulti;
}
void Kleo::KeyRequester::setMultipleKeysEnabled(bool multi)
{
if (multi == mMulti) {
return;
}
if (!multi && !mKeys.empty()) {
mKeys.erase(mKeys.begin() + 1, mKeys.end());
}
mMulti = multi;
updateKeys();
}
unsigned int Kleo::KeyRequester::allowedKeys() const
{
return mKeyUsage;
}
void Kleo::KeyRequester::setAllowedKeys(unsigned int keyUsage)
{
mKeyUsage = keyUsage;
mOpenPGPBackend = nullptr;
mSMIMEBackend = nullptr;
if (mKeyUsage & KeySelectionDialog::OpenPGPKeys) {
mOpenPGPBackend = openpgp();
}
if (mKeyUsage & KeySelectionDialog::SMIMEKeys) {
mSMIMEBackend = smime();
}
if (mOpenPGPBackend && !mSMIMEBackend) {
mDialogCaption = i18n("OpenPGP Key Selection");
mDialogMessage = i18n("Please select an OpenPGP key to use.");
} else if (!mOpenPGPBackend && mSMIMEBackend) {
mDialogCaption = i18n("S/MIME Key Selection");
mDialogMessage = i18n("Please select an S/MIME key to use.");
} else {
mDialogCaption = i18n("Key Selection");
mDialogMessage = i18n("Please select an (OpenPGP or S/MIME) key to use.");
}
}
QPushButton *Kleo::KeyRequester::dialogButton()
{
return mDialogButton;
}
QPushButton *Kleo::KeyRequester::eraseButton()
{
return mEraseButton;
}
static inline unsigned int foo(bool openpgp, bool smime, bool trusted, bool valid)
{
unsigned int result = 0;
if (openpgp) {
result |= Kleo::KeySelectionDialog::OpenPGPKeys;
}
if (smime) {
result |= Kleo::KeySelectionDialog::SMIMEKeys;
}
if (trusted) {
result |= Kleo::KeySelectionDialog::TrustedKeys;
}
if (valid) {
result |= Kleo::KeySelectionDialog::ValidKeys;
}
return result;
}
static inline unsigned int encryptionKeyUsage(bool openpgp, bool smime, bool trusted, bool valid)
{
return foo(openpgp, smime, trusted, valid) | Kleo::KeySelectionDialog::EncryptionKeys | Kleo::KeySelectionDialog::PublicKeys;
}
static inline unsigned int signingKeyUsage(bool openpgp, bool smime, bool trusted, bool valid)
{
return foo(openpgp, smime, trusted, valid) | Kleo::KeySelectionDialog::SigningKeys | Kleo::KeySelectionDialog::SecretKeys;
}
Kleo::EncryptionKeyRequester::EncryptionKeyRequester(bool multi, unsigned int proto,
QWidget *parent,
bool onlyTrusted, bool onlyValid)
: KeyRequester(encryptionKeyUsage(proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid), multi,
parent), d(nullptr)
{
}
Kleo::EncryptionKeyRequester::EncryptionKeyRequester(QWidget *parent)
: KeyRequester(0, false, parent), d(nullptr)
{
}
Kleo::EncryptionKeyRequester::~EncryptionKeyRequester() {}
void Kleo::EncryptionKeyRequester::setAllowedKeys(unsigned int proto, bool onlyTrusted, bool onlyValid)
{
KeyRequester::setAllowedKeys(encryptionKeyUsage(proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid));
}
Kleo::SigningKeyRequester::SigningKeyRequester(bool multi, unsigned int proto,
QWidget *parent,
bool onlyTrusted, bool onlyValid)
: KeyRequester(signingKeyUsage(proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid), multi,
parent), d(nullptr)
{
}
Kleo::SigningKeyRequester::SigningKeyRequester(QWidget *parent)
: KeyRequester(0, false, parent), d(nullptr)
{
}
Kleo::SigningKeyRequester::~SigningKeyRequester() {}
void Kleo::SigningKeyRequester::setAllowedKeys(unsigned int proto, bool onlyTrusted, bool onlyValid)
{
KeyRequester::setAllowedKeys(signingKeyUsage(proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid));
}
void Kleo::KeyRequester::virtual_hook(int, void *) {}
void Kleo::EncryptionKeyRequester::virtual_hook(int id, void *data)
{
KeyRequester::virtual_hook(id, data);
}
void Kleo::SigningKeyRequester::virtual_hook(int id, void *data)
{
KeyRequester::virtual_hook(id, data);
}
diff --git a/src/ui/keyselectiondialog.cpp b/src/ui/keyselectiondialog.cpp
index 7a1e8932..36ef3a09 100644
--- a/src/ui/keyselectiondialog.cpp
+++ b/src/ui/keyselectiondialog.cpp
@@ -1,989 +1,989 @@
/* -*- c++ -*-
keyselectiondialog.cpp
This file is part of libkleopatra, the KDE keymanagement library
Copyright (c) 2004 Klar�vdalens Datakonsult AB
Based on kpgpui.cpp
Copyright (C) 2001,2002 the KPGP authors
See file libkdenetwork/AUTHORS.kpgp for details
Libkleopatra is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
Libkleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include "keyselectiondialog.h"
#include "keylistview.h"
#include "progressdialog.h"
#include "libkleo/dn.h"
#include "kleo_ui_debug.h"
// gpgme++
#include <gpgme++/key.h>
#include <gpgme++/keylistresult.h>
#include <qgpgme/keylistjob.h>
#include <qgpgme/protocol.h>
// KDE
#include <KLocalizedString>
#include <kwindowsystem.h>
#include <kconfig.h>
#include <kmessagebox.h>
#include <qpushbutton.h>
#include <kconfiggroup.h>
#include <qmenu.h>
#include <QLineEdit>
// Qt
#include <QCheckBox>
#include <QLabel>
#include <QTimer>
#include <QDateTime>
#include <QProcess>
#include <QRegExp>
#include <QPushButton>
#include <QFrame>
#include <QApplication>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <algorithm>
#include <iterator>
#include <string.h>
#include <qscrollbar.h>
#include <KSharedConfig>
#include <KConfigGroup>
#include <QDialogButtonBox>
static bool checkKeyUsage(const GpgME::Key &key, unsigned int keyUsage, QString *statusString = nullptr)
{
auto setStatusString = [statusString](const QString &status) {
if (statusString) {
*statusString = status;
}
};
if (keyUsage & Kleo::KeySelectionDialog::ValidKeys) {
if (key.isInvalid()) {
if (key.keyListMode() & GpgME::Validate) {
qCDebug(KLEO_UI_LOG) << "key is invalid";
setStatusString(i18n("The key is not valid."));
return false;
} else {
qCDebug(KLEO_UI_LOG) << "key is invalid - ignoring";
}
}
if (key.isExpired()) {
qCDebug(KLEO_UI_LOG) << "key is expired";
setStatusString(i18n("The key is expired."));
return false;
} else if (key.isRevoked()) {
qCDebug(KLEO_UI_LOG) << "key is revoked";
setStatusString(i18n("The key is revoked."));
return false;
} else if (key.isDisabled()) {
qCDebug(KLEO_UI_LOG) << "key is disabled";
setStatusString(i18n("The key is disabled."));
return false;
}
}
if (keyUsage & Kleo::KeySelectionDialog::EncryptionKeys &&
!key.canEncrypt()) {
qCDebug(KLEO_UI_LOG) << "key can't encrypt";
setStatusString(i18n("The key is not designated for encryption."));
return false;
}
if (keyUsage & Kleo::KeySelectionDialog::SigningKeys &&
!key.canSign()) {
qCDebug(KLEO_UI_LOG) << "key can't sign";
setStatusString(i18n("The key is not designated for signing."));
return false;
}
if (keyUsage & Kleo::KeySelectionDialog::CertificationKeys &&
!key.canCertify()) {
qCDebug(KLEO_UI_LOG) << "key can't certify";
setStatusString(i18n("The key is not designated for certifying."));
return false;
}
if (keyUsage & Kleo::KeySelectionDialog::AuthenticationKeys &&
!key.canAuthenticate()) {
qCDebug(KLEO_UI_LOG) << "key can't authenticate";
setStatusString(i18n("The key is not designated for authentication."));
return false;
}
if (keyUsage & Kleo::KeySelectionDialog::SecretKeys &&
!(keyUsage & Kleo::KeySelectionDialog::PublicKeys) &&
!key.hasSecret()) {
qCDebug(KLEO_UI_LOG) << "key isn't secret";
setStatusString(i18n("The key is not secret."));
return false;
}
if (keyUsage & Kleo::KeySelectionDialog::TrustedKeys &&
key.protocol() == GpgME::OpenPGP &&
// only check this for secret keys for now.
// Seems validity isn't checked for secret keylistings...
!key.hasSecret()) {
std::vector<GpgME::UserID> uids = key.userIDs();
for (std::vector<GpgME::UserID>::const_iterator it = uids.begin(); it != uids.end(); ++it)
if (!it->isRevoked() && it->validity() >= GpgME::UserID::Marginal) {
return true;
}
qCDebug(KLEO_UI_LOG) << "key has no UIDs with validity >= Marginal";
setStatusString(i18n("The key is not trusted enough."));
return false;
}
// X.509 keys are always trusted, else they won't be the keybox.
// PENDING(marc) check that this ^ is correct
setStatusString(i18n("The key can be used."));
return true;
}
static bool checkKeyUsage(const std::vector<GpgME::Key> &keys, unsigned int keyUsage)
{
for (std::vector<GpgME::Key>::const_iterator it = keys.begin(); it != keys.end(); ++it)
if (!checkKeyUsage(*it, keyUsage)) {
return false;
}
return true;
}
static inline QString time_t2string(time_t t)
{
QDateTime dt;
dt.setTime_t(t);
return dt.toString();
}
namespace
{
class ColumnStrategy : public Kleo::KeyListView::ColumnStrategy
{
public:
ColumnStrategy(unsigned int keyUsage);
QString title(int col) const override;
int width(int col, const QFontMetrics &fm) const override;
QString text(const GpgME::Key &key, int col) const override;
QString toolTip(const GpgME::Key &key, int col) const override;
QIcon icon(const GpgME::Key &key, int col) const override;
private:
const QIcon mKeyGoodPix, mKeyBadPix, mKeyUnknownPix, mKeyValidPix;
const unsigned int mKeyUsage;
};
static QString iconPath(const QString &name)
{
return QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("libkleopatra/pics/") + name + QStringLiteral(".png"));
}
ColumnStrategy::ColumnStrategy(unsigned int keyUsage)
: Kleo::KeyListView::ColumnStrategy(),
mKeyGoodPix(iconPath(QStringLiteral("key_ok"))),
mKeyBadPix(iconPath(QStringLiteral("key_bad"))),
mKeyUnknownPix(iconPath(QStringLiteral("key_unknown"))),
mKeyValidPix(iconPath(QStringLiteral("key"))),
mKeyUsage(keyUsage)
{
if (keyUsage == 0)
qCWarning(KLEO_UI_LOG)
<< "KeySelectionDialog: keyUsage == 0. You want to use AllKeys instead.";
}
QString ColumnStrategy::title(int col) const
{
switch (col) {
case 0: return i18n("Key ID");
case 1: return i18n("User ID");
default: return QString();
}
}
int ColumnStrategy::width(int col, const QFontMetrics &fm) const
{
if (col == 0) {
static const char hexchars[] = "0123456789ABCDEF";
int maxWidth = 0;
for (unsigned int i = 0; i < 16; ++i) {
maxWidth = qMax(fm.boundingRect(QLatin1Char(hexchars[i])).width(), maxWidth);
}
return 8 * maxWidth + 2 * 16 /* KIconLoader::SizeSmall */;
}
return Kleo::KeyListView::ColumnStrategy::width(col, fm);
}
QString ColumnStrategy::text(const GpgME::Key &key, int col) const
{
switch (col) {
case 0: {
if (key.shortKeyID()) {
return QString::fromUtf8(key.shortKeyID());
} else {
return xi18n("<placeholder>unknown</placeholder>");
}
}
case 1: {
const char *uid = key.userID(0).id();
if (key.protocol() == GpgME::OpenPGP) {
return uid && *uid ? QString::fromUtf8(uid) : QString();
} else { // CMS
return Kleo::DN(uid).prettyDN();
}
}
default: return QString();
}
}
QString ColumnStrategy::toolTip(const GpgME::Key &key, int) const
{
const char *uid = key.userID(0).id();
const char *fpr = key.primaryFingerprint();
const char *issuer = key.issuerName();
const GpgME::Subkey subkey = key.subkey(0);
const QString expiry = subkey.neverExpires() ? i18n("never") : time_t2string(subkey.expirationTime());
const QString creation = time_t2string(subkey.creationTime());
QString keyStatusString;
if (!checkKeyUsage(key, mKeyUsage, &keyStatusString)) {
// Show the status in bold if there is a problem
keyStatusString = QLatin1String("<b>") % keyStatusString % QLatin1String("</b>");
}
QString html = QStringLiteral("<qt><p style=\"style='white-space:pre'\">");
if (key.protocol() == GpgME::OpenPGP) {
html += i18n("OpenPGP key for <b>%1</b>", uid ? QString::fromUtf8(uid) : i18n("unknown"));
} else {
html += i18n("S/MIME key for <b>%1</b>", uid ? Kleo::DN(uid).prettyDN() : i18n("unknown"));
}
html += QStringLiteral("</p><table>");
const auto addRow = [&html](const QString &name, const QString &value) {
html += QStringLiteral("<tr><td align=\"right\"><b>%1: </b></td><td>%2</td></tr>").arg(name, value);
};
addRow(i18nc("Key creation date", "Created"), creation);
addRow(i18nc("Key Expiration date", "Expiry"), expiry);
addRow(i18nc("Key fingerprint", "Fingerprint"), fpr ? QString::fromLatin1(fpr) : i18n("unknown"));
if (key.protocol() != GpgME::OpenPGP) {
addRow(i18nc("Key issuer", "Issuer"), issuer ? Kleo::DN(issuer).prettyDN() : i18n("unknown"));
}
addRow(i18nc("Key status", "Status"), keyStatusString);
html += QStringLiteral("</table></qt>");
return html;
}
QIcon ColumnStrategy::icon(const GpgME::Key &key, int col) const
{
if (col != 0) {
return QIcon();
}
// this key did not undergo a validating keylisting yet:
if (!(key.keyListMode() & GpgME::Validate)) {
return mKeyUnknownPix;
}
if (!checkKeyUsage(key, mKeyUsage)) {
return mKeyBadPix;
}
if (key.protocol() == GpgME::CMS) {
return mKeyGoodPix;
}
switch (key.userID(0).validity()) {
default:
case GpgME::UserID::Unknown:
case GpgME::UserID::Undefined:
return mKeyUnknownPix;
case GpgME::UserID::Never:
return mKeyValidPix;
case GpgME::UserID::Marginal:
case GpgME::UserID::Full:
case GpgME::UserID::Ultimate:
return mKeyGoodPix;
}
}
}
static const int sCheckSelectionDelay = 250;
Kleo::KeySelectionDialog::KeySelectionDialog(const QString &title,
const QString &text,
const std::vector<GpgME::Key> &selectedKeys,
unsigned int keyUsage,
bool extendedSelection,
bool rememberChoice,
QWidget *parent,
bool modal)
: QDialog(parent),
mOpenPGPBackend(nullptr),
mSMIMEBackend(nullptr),
mRememberCB(nullptr),
mSelectedKeys(selectedKeys),
mKeyUsage(keyUsage),
mCurrentContextMenuItem(nullptr)
{
setWindowTitle(title);
setModal(modal);
init(rememberChoice, extendedSelection, text, QString());
}
Kleo::KeySelectionDialog::KeySelectionDialog(const QString &title,
const QString &text,
const QString &initialQuery,
const std::vector<GpgME::Key> &selectedKeys,
unsigned int keyUsage,
bool extendedSelection,
bool rememberChoice,
QWidget *parent,
bool modal)
: QDialog(parent),
mOpenPGPBackend(nullptr),
mSMIMEBackend(nullptr),
mRememberCB(nullptr),
mSelectedKeys(selectedKeys),
mKeyUsage(keyUsage),
mSearchText(initialQuery),
mInitialQuery(initialQuery),
mCurrentContextMenuItem(nullptr)
{
setWindowTitle(title);
setModal(modal);
init(rememberChoice, extendedSelection, text, initialQuery);
}
Kleo::KeySelectionDialog::KeySelectionDialog(const QString &title,
const QString &text,
const QString &initialQuery,
unsigned int keyUsage,
bool extendedSelection,
bool rememberChoice,
QWidget *parent,
bool modal)
: QDialog(parent),
mOpenPGPBackend(nullptr),
mSMIMEBackend(nullptr),
mRememberCB(nullptr),
mKeyUsage(keyUsage),
mSearchText(initialQuery),
mInitialQuery(initialQuery),
mCurrentContextMenuItem(nullptr)
{
setWindowTitle(title);
setModal(modal);
init(rememberChoice, extendedSelection, text, initialQuery);
}
void Kleo::KeySelectionDialog::init(bool rememberChoice, bool extendedSelection,
const QString &text, const QString &initialQuery)
{
QVBoxLayout *mainLayout = new QVBoxLayout(this);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
mOkButton = buttonBox->button(QDialogButtonBox::Ok);
mOkButton->setDefault(true);
mOkButton->setShortcut(Qt::CTRL | Qt::Key_Return);
QPushButton *user1Button = new QPushButton;
buttonBox->addButton(user1Button, QDialogButtonBox::ActionRole);
QPushButton *user2Button = new QPushButton;
buttonBox->addButton(user2Button, QDialogButtonBox::ActionRole);
if (mKeyUsage & OpenPGPKeys) {
mOpenPGPBackend = QGpgME::openpgp();
}
if (mKeyUsage & SMIMEKeys) {
mSMIMEBackend = QGpgME::smime();
}
mCheckSelectionTimer = new QTimer(this);
mStartSearchTimer = new QTimer(this);
QFrame *page = new QFrame(this);
mainLayout->addWidget(page);
mainLayout->addWidget(buttonBox);
mTopLayout = new QVBoxLayout(page);
- mTopLayout->setMargin(0);
+ mTopLayout->setContentsMargins(0, 0, 0, 0);
if (!text.isEmpty()) {
QLabel *textLabel = new QLabel(text, page);
textLabel->setWordWrap(true);
// Setting the size policy is necessary as a workaround for https://issues.kolab.org/issue4429
// and http://bugreports.qt.nokia.com/browse/QTBUG-8740
textLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
connect(textLabel, &QLabel::linkActivated, this, &KeySelectionDialog::slotStartCertificateManager);
mTopLayout->addWidget(textLabel);
}
QPushButton *const searchExternalPB =
new QPushButton(i18n("Search for &External Certificates"), page);
mTopLayout->addWidget(searchExternalPB, 0, Qt::AlignLeft);
connect(searchExternalPB, &QAbstractButton::clicked, this, &KeySelectionDialog::slotStartSearchForExternalCertificates);
if (initialQuery.isEmpty()) {
searchExternalPB->hide();
}
QHBoxLayout *hlay = new QHBoxLayout();
mTopLayout->addLayout(hlay);
QLineEdit *le = new QLineEdit(page);
le->setClearButtonEnabled(true);
le->setText(initialQuery);
QLabel *lbSearchFor = new QLabel(i18n("&Search for:"), page);
lbSearchFor->setBuddy(le);
hlay->addWidget(lbSearchFor);
hlay->addWidget(le, 1);
le->setFocus();
connect(le, &QLineEdit::textChanged,
this, static_cast<void(KeySelectionDialog::*)(const QString &)>(&KeySelectionDialog::slotSearch));
connect(mStartSearchTimer, &QTimer::timeout, this, &KeySelectionDialog::slotFilter);
mKeyListView = new KeyListView(new ColumnStrategy(mKeyUsage), nullptr, page);
mKeyListView->setObjectName(QStringLiteral("mKeyListView"));
mKeyListView->header()->stretchLastSection();
mKeyListView->setRootIsDecorated(true);
mKeyListView->setSortingEnabled(true);
mKeyListView->header()->setSortIndicatorShown(true);
mKeyListView->header()->setSortIndicator(1, Qt::AscendingOrder); // sort by User ID
if (extendedSelection) {
mKeyListView->setSelectionMode(QAbstractItemView::ExtendedSelection);
}
mTopLayout->addWidget(mKeyListView, 10);
if (rememberChoice) {
mRememberCB = new QCheckBox(i18n("&Remember choice"), page);
mTopLayout->addWidget(mRememberCB);
mRememberCB->setWhatsThis(
i18n("<qt><p>If you check this box your choice will "
"be stored and you will not be asked again."
"</p></qt>"));
}
connect(mCheckSelectionTimer, &QTimer::timeout,
this, static_cast<void(KeySelectionDialog::*)()>(&KeySelectionDialog::slotCheckSelection));
connectSignals();
connect(mKeyListView, &Kleo::KeyListView::doubleClicked, this, &KeySelectionDialog::slotTryOk);
connect(mKeyListView, &KeyListView::contextMenu, this, &KeySelectionDialog::slotRMB);
user1Button->setText(i18n("&Reread Keys"));
user2Button->setText(i18n("&Start Certificate Manager"));
connect(user1Button, &QPushButton::clicked, this, &KeySelectionDialog::slotRereadKeys);
connect(user2Button, &QPushButton::clicked, this, [this]() { slotStartCertificateManager(); });
connect(mOkButton, &QPushButton::clicked, this, &KeySelectionDialog::slotOk);
connect(buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &KeySelectionDialog::slotCancel);
slotRereadKeys();
mTopLayout->activate();
if (qApp) {
QSize dialogSize(sizeHint());
KWindowSystem::setIcons(winId(), qApp->windowIcon().pixmap(32, 32),
qApp->windowIcon().pixmap(16, 16));
KConfigGroup dialogConfig(KSharedConfig::openConfig(), "Key Selection Dialog");
dialogSize = dialogConfig.readEntry("Dialog size", dialogSize);
const QByteArray headerState = dialogConfig.readEntry("header", QByteArray());
if (!headerState.isEmpty()) {
mKeyListView->header()->restoreState(headerState);
}
resize(dialogSize);
}
}
Kleo::KeySelectionDialog::~KeySelectionDialog()
{
disconnectSignals();
KConfigGroup dialogConfig(KSharedConfig::openConfig(), "Key Selection Dialog");
dialogConfig.writeEntry("Dialog size", size());
dialogConfig.writeEntry("header", mKeyListView->header()->saveState());
dialogConfig.sync();
}
void Kleo::KeySelectionDialog::connectSignals()
{
if (mKeyListView->isMultiSelection())
connect(mKeyListView, &QTreeWidget::itemSelectionChanged, this, &KeySelectionDialog::slotSelectionChanged);
else
connect(mKeyListView, static_cast<void(KeyListView::*)(KeyListViewItem*)>(&KeyListView::selectionChanged),
this, static_cast<void(KeySelectionDialog::*)(KeyListViewItem*)>(&KeySelectionDialog::slotCheckSelection));
}
void Kleo::KeySelectionDialog::disconnectSignals()
{
if (mKeyListView->isMultiSelection())
disconnect(mKeyListView, &QTreeWidget::itemSelectionChanged,
this, &KeySelectionDialog::slotSelectionChanged);
else
disconnect(mKeyListView, static_cast<void(KeyListView::*)(KeyListViewItem*)>(&KeyListView::selectionChanged),
this, static_cast<void(KeySelectionDialog::*)(KeyListViewItem*)>(&KeySelectionDialog::slotCheckSelection));
}
const GpgME::Key &Kleo::KeySelectionDialog::selectedKey() const
{
static const GpgME::Key null = GpgME::Key::null;
if (mKeyListView->isMultiSelection() || !mKeyListView->selectedItem()) {
return null;
}
return mKeyListView->selectedItem()->key();
}
QString Kleo::KeySelectionDialog::fingerprint() const
{
return QLatin1String(selectedKey().primaryFingerprint());
}
QStringList Kleo::KeySelectionDialog::fingerprints() const
{
QStringList result;
for (std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin(); it != mSelectedKeys.end(); ++it)
if (const char *fpr = it->primaryFingerprint()) {
result.push_back(QLatin1String(fpr));
}
return result;
}
QStringList Kleo::KeySelectionDialog::pgpKeyFingerprints() const
{
QStringList result;
for (std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin(); it != mSelectedKeys.end(); ++it)
if (it->protocol() == GpgME::OpenPGP)
if (const char *fpr = it->primaryFingerprint()) {
result.push_back(QLatin1String(fpr));
}
return result;
}
QStringList Kleo::KeySelectionDialog::smimeFingerprints() const
{
QStringList result;
for (std::vector<GpgME::Key>::const_iterator it = mSelectedKeys.begin(); it != mSelectedKeys.end(); ++it)
if (it->protocol() == GpgME::CMS)
if (const char *fpr = it->primaryFingerprint()) {
result.push_back(QLatin1String(fpr));
}
return result;
}
void Kleo::KeySelectionDialog::slotRereadKeys()
{
mKeyListView->clear();
mListJobCount = 0;
mTruncated = 0;
mSavedOffsetY = mKeyListView->verticalScrollBar()->value();
disconnectSignals();
mKeyListView->setEnabled(false);
// FIXME: save current selection
if (mOpenPGPBackend) {
startKeyListJobForBackend(mOpenPGPBackend, std::vector<GpgME::Key>(), false /*non-validating*/);
}
if (mSMIMEBackend) {
startKeyListJobForBackend(mSMIMEBackend, std::vector<GpgME::Key>(), false /*non-validating*/);
}
if (mListJobCount == 0) {
mKeyListView->setEnabled(true);
KMessageBox::information(this,
i18n("No backends found for listing keys. "
"Check your installation."),
i18n("Key Listing Failed"));
connectSignals();
}
}
void Kleo::KeySelectionDialog::slotStartCertificateManager(const QString &query)
{
QStringList args;
if (!query.isEmpty()) {
args << QStringLiteral("--search") << query;
}
if (!QProcess::startDetached(QStringLiteral("kleopatra"), args))
KMessageBox::error(this,
i18n("Could not start certificate manager; "
"please check your installation."),
i18n("Certificate Manager Error"));
else {
qCDebug(KLEO_UI_LOG) << "\nslotStartCertManager(): certificate manager started.";
}
}
#ifndef __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
#define __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
static void showKeyListError(QWidget *parent, const GpgME::Error &err)
{
Q_ASSERT(err);
const QString msg = i18n("<qt><p>An error occurred while fetching "
"the keys from the backend:</p>"
"<p><b>%1</b></p></qt>",
QString::fromLocal8Bit(err.asString()));
KMessageBox::error(parent, msg, i18n("Key Listing Failed"));
}
#endif // __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
namespace
{
struct ExtractFingerprint {
QString operator()(const GpgME::Key &key)
{
return QLatin1String(key.primaryFingerprint());
}
};
}
void Kleo::KeySelectionDialog::startKeyListJobForBackend(const QGpgME::Protocol *backend, const std::vector<GpgME::Key> &keys, bool validate)
{
Q_ASSERT(backend);
QGpgME::KeyListJob *job = backend->keyListJob(false, false, validate); // local, w/o sigs, validation as givem
if (!job) {
return;
}
connect(job, &QGpgME::KeyListJob::result, this, &KeySelectionDialog::slotKeyListResult);
if (validate)
connect(job, &QGpgME::KeyListJob::nextKey, mKeyListView, &KeyListView::slotRefreshKey);
else
connect(job, &QGpgME::KeyListJob::nextKey, mKeyListView, &KeyListView::slotAddKey);
QStringList fprs;
std::transform(keys.begin(), keys.end(), std::back_inserter(fprs), ExtractFingerprint());
const GpgME::Error err = job->start(fprs, mKeyUsage & SecretKeys && !(mKeyUsage & PublicKeys));
if (err) {
return showKeyListError(this, err);
}
#ifndef LIBKLEO_NO_PROGRESSDIALOG
// FIXME: create a MultiProgressDialog:
(void)new ProgressDialog(job, validate ? i18n("Checking selected keys...") : i18n("Fetching keys..."), this);
#endif
++mListJobCount;
}
static void selectKeys(Kleo::KeyListView *klv, const std::vector<GpgME::Key> &selectedKeys)
{
klv->clearSelection();
if (selectedKeys.empty()) {
return;
}
for (std::vector<GpgME::Key>::const_iterator it = selectedKeys.begin(); it != selectedKeys.end(); ++it)
if (Kleo::KeyListViewItem *item = klv->itemByFingerprint(it->primaryFingerprint())) {
item->setSelected(true);
}
}
void Kleo::KeySelectionDialog::slotKeyListResult(const GpgME::KeyListResult &res)
{
if (res.error()) {
showKeyListError(this, res.error());
} else if (res.isTruncated()) {
++mTruncated;
}
if (--mListJobCount > 0) {
return; // not yet finished...
}
if (mTruncated > 0)
KMessageBox::information(this,
i18np("<qt>One backend returned truncated output.<p>"
"Not all available keys are shown</p></qt>",
"<qt>%1 backends returned truncated output.<p>"
"Not all available keys are shown</p></qt>",
mTruncated),
i18n("Key List Result"));
mKeyListView->flushKeys();
mKeyListView->setEnabled(true);
mListJobCount = mTruncated = 0;
mKeysToCheck.clear();
selectKeys(mKeyListView, mSelectedKeys);
slotFilter();
connectSignals();
slotSelectionChanged();
// restore the saved position of the contents
mKeyListView->verticalScrollBar()->setValue(mSavedOffsetY); mSavedOffsetY = 0;
}
void Kleo::KeySelectionDialog::slotSelectionChanged()
{
qCDebug(KLEO_UI_LOG) << "KeySelectionDialog::slotSelectionChanged()";
// (re)start the check selection timer. Checking the selection is delayed
// because else drag-selection doesn't work very good (checking key trust
// is slow).
mCheckSelectionTimer->start(sCheckSelectionDelay);
}
namespace
{
struct AlreadyChecked {
bool operator()(const GpgME::Key &key) const
{
return key.keyListMode() & GpgME::Validate;
}
};
}
void Kleo::KeySelectionDialog::slotCheckSelection(KeyListViewItem *item)
{
qCDebug(KLEO_UI_LOG) << "KeySelectionDialog::slotCheckSelection()";
mCheckSelectionTimer->stop();
mSelectedKeys.clear();
if (!mKeyListView->isMultiSelection()) {
if (item) {
mSelectedKeys.push_back(item->key());
}
}
for (KeyListViewItem *it = mKeyListView->firstChild(); it; it = it->nextSibling())
if (it->isSelected()) {
mSelectedKeys.push_back(it->key());
}
mKeysToCheck.clear();
std::remove_copy_if(mSelectedKeys.begin(), mSelectedKeys.end(),
std::back_inserter(mKeysToCheck),
AlreadyChecked());
if (mKeysToCheck.empty()) {
mOkButton->setEnabled(!mSelectedKeys.empty() &&
checkKeyUsage(mSelectedKeys, mKeyUsage));
return;
}
// performed all fast checks - now for validating key listing:
startValidatingKeyListing();
}
void Kleo::KeySelectionDialog::startValidatingKeyListing()
{
if (mKeysToCheck.empty()) {
return;
}
mListJobCount = 0;
mTruncated = 0;
mSavedOffsetY = mKeyListView->verticalScrollBar()->value();
disconnectSignals();
mKeyListView->setEnabled(false);
std::vector<GpgME::Key> smime, openpgp;
for (std::vector<GpgME::Key>::const_iterator it = mKeysToCheck.begin(); it != mKeysToCheck.end(); ++it)
if (it->protocol() == GpgME::OpenPGP) {
openpgp.push_back(*it);
} else {
smime.push_back(*it);
}
if (!openpgp.empty()) {
Q_ASSERT(mOpenPGPBackend);
startKeyListJobForBackend(mOpenPGPBackend, openpgp, true /*validate*/);
}
if (!smime.empty()) {
Q_ASSERT(mSMIMEBackend);
startKeyListJobForBackend(mSMIMEBackend, smime, true /*validate*/);
}
Q_ASSERT(mListJobCount > 0);
}
bool Kleo::KeySelectionDialog::rememberSelection() const
{
return mRememberCB && mRememberCB->isChecked();
}
void Kleo::KeySelectionDialog::slotRMB(Kleo::KeyListViewItem *item, const QPoint &p)
{
if (!item) {
return;
}
mCurrentContextMenuItem = item;
QMenu menu;
menu.addAction(i18n("Recheck Key"), this, &KeySelectionDialog::slotRecheckKey);
menu.exec(p);
}
void Kleo::KeySelectionDialog::slotRecheckKey()
{
if (!mCurrentContextMenuItem || mCurrentContextMenuItem->key().isNull()) {
return;
}
mKeysToCheck.clear();
mKeysToCheck.push_back(mCurrentContextMenuItem->key());
}
void Kleo::KeySelectionDialog::slotTryOk()
{
if (!mSelectedKeys.empty() && checkKeyUsage(mSelectedKeys, mKeyUsage)) {
slotOk();
}
}
void Kleo::KeySelectionDialog::slotOk()
{
if (mCheckSelectionTimer->isActive()) {
slotCheckSelection();
}
#if 0 //Laurent I don't understand why we returns here.
// button could be disabled again after checking the selected key1
if (!mSelectedKeys.empty() && checkKeyUsage(mSelectedKeys, mKeyUsage)) {
return;
}
#endif
mStartSearchTimer->stop();
accept();
}
void Kleo::KeySelectionDialog::slotCancel()
{
mCheckSelectionTimer->stop();
mStartSearchTimer->stop();
reject();
}
void Kleo::KeySelectionDialog::slotSearch(const QString &text)
{
mSearchText = text.trimmed().toUpper();
slotSearch();
}
void Kleo::KeySelectionDialog::slotSearch()
{
mStartSearchTimer->setSingleShot(true);
mStartSearchTimer->start(sCheckSelectionDelay);
}
void Kleo::KeySelectionDialog::slotFilter()
{
if (mSearchText.isEmpty()) {
showAllItems();
return;
}
// OK, so we need to filter:
QRegExp keyIdRegExp(QLatin1String("(?:0x)?[A-F0-9]{1,8}"), Qt::CaseInsensitive);
if (keyIdRegExp.exactMatch(mSearchText)) {
if (mSearchText.startsWith(QStringLiteral("0X")))
// search for keyID only:
{
filterByKeyID(mSearchText.mid(2));
} else
// search for UID and keyID:
{
filterByKeyIDOrUID(mSearchText);
}
} else {
// search in UID:
filterByUID(mSearchText);
}
}
void Kleo::KeySelectionDialog::filterByKeyID(const QString &keyID)
{
Q_ASSERT(keyID.length() <= 8);
Q_ASSERT(!keyID.isEmpty()); // regexp in slotFilter should prevent these
if (keyID.isEmpty()) {
showAllItems();
} else
for (KeyListViewItem *item = mKeyListView->firstChild(); item; item = item->nextSibling()) {
item->setHidden(!item->text(0).toUpper().startsWith(keyID));
}
}
static bool anyUIDMatches(const Kleo::KeyListViewItem *item, QRegExp &rx)
{
if (!item) {
return false;
}
const std::vector<GpgME::UserID> uids = item->key().userIDs();
for (std::vector<GpgME::UserID>::const_iterator it = uids.begin(); it != uids.end(); ++it)
if (it->id() && rx.indexIn(QString::fromUtf8(it->id())) >= 0) {
return true;
}
return false;
}
void Kleo::KeySelectionDialog::filterByKeyIDOrUID(const QString &str)
{
Q_ASSERT(!str.isEmpty());
// match beginnings of words:
QRegExp rx(QLatin1String("\\b") + QRegExp::escape(str), Qt::CaseInsensitive);
for (KeyListViewItem *item = mKeyListView->firstChild(); item; item = item->nextSibling()) {
item->setHidden(!item->text(0).toUpper().startsWith(str) && !anyUIDMatches(item, rx));
}
}
void Kleo::KeySelectionDialog::filterByUID(const QString &str)
{
Q_ASSERT(!str.isEmpty());
// match beginnings of words:
QRegExp rx(QLatin1String("\\b") + QRegExp::escape(str), Qt::CaseInsensitive);
for (KeyListViewItem *item = mKeyListView->firstChild(); item; item = item->nextSibling()) {
item->setHidden(!anyUIDMatches(item, rx));
}
}
void Kleo::KeySelectionDialog::showAllItems()
{
for (KeyListViewItem *item = mKeyListView->firstChild(); item; item = item->nextSibling()) {
item->setHidden(false);
}
}
diff --git a/src/ui/newkeyapprovaldialog.cpp b/src/ui/newkeyapprovaldialog.cpp
index 22517b07..41b14a42 100644
--- a/src/ui/newkeyapprovaldialog.cpp
+++ b/src/ui/newkeyapprovaldialog.cpp
@@ -1,634 +1,634 @@
/* -*- c++ -*-
newkeyapprovaldialog.cpp
This file is part of libkleopatra, the KDE keymanagement library
Copyright (c) 2018 Intevation GmbH
Libkleopatra is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
Libkleopatra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
In addition, as a special exception, the copyright holders give
permission to link the code of this program with any edition of
the Qt library by Trolltech AS, Norway (or with modified versions
of Qt that use the same license as Qt), and distribute linked
combinations including the two. You must obey the GNU General
Public License in all respects for all of the code used other than
Qt. If you modify this file, you may extend this exception to
your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from
your version.
*/
#include "newkeyapprovaldialog.h"
#include "kleo/defaultkeyfilter.h"
#include "keyselectioncombo.h"
#include "progressdialog.h"
#include "utils/formatting.h"
#include "libkleo_debug.h"
#include <QApplication>
#include <QButtonGroup>
#include <QDesktopWidget>
#include <QDialogButtonBox>
#include <QGroupBox>
#include <QLabel>
#include <QMap>
#include <QPushButton>
#include <QRadioButton>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QGpgME/DefaultKeyGenerationJob>
#include <QGpgME/CryptoConfig>
#include <QGpgME/Protocol>
#include <gpgme++/keygenerationresult.h>
#include <gpgme++/key.h>
#include <KLocalizedString>
#include <KMessageBox>
using namespace Kleo;
namespace {
class OpenPGPFilter: public DefaultKeyFilter
{
public:
OpenPGPFilter() : DefaultKeyFilter()
{
setIsOpenPGP(DefaultKeyFilter::Set);
}
};
static std::shared_ptr<KeyFilter> s_pgpFilter = std::shared_ptr<KeyFilter> (new OpenPGPFilter);
class OpenPGPSignFilter: public DefaultKeyFilter
{
public:
OpenPGPSignFilter() : DefaultKeyFilter()
{
/* Also list unusable keys to make it transparent why they are unusable */
setHasSecret(DefaultKeyFilter::Set);
setIsOpenPGP(DefaultKeyFilter::Set);
}
};
static std::shared_ptr<KeyFilter> s_pgpSignFilter = std::shared_ptr<KeyFilter> (new OpenPGPSignFilter);
class SMIMEFilter: public DefaultKeyFilter
{
public:
SMIMEFilter(): DefaultKeyFilter()
{
setIsOpenPGP(DefaultKeyFilter::NotSet);
}
};
static std::shared_ptr<KeyFilter> s_smimeFilter = std::shared_ptr<KeyFilter> (new SMIMEFilter);
class SMIMESignFilter: public DefaultKeyFilter
{
public:
SMIMESignFilter(): DefaultKeyFilter()
{
setIsOpenPGP(DefaultKeyFilter::NotSet);
setHasSecret(DefaultKeyFilter::Set);
}
};
static std::shared_ptr<KeyFilter> s_smimeSignFilter = std::shared_ptr<KeyFilter> (new SMIMESignFilter);
static std::shared_ptr<KeyFilter> s_defaultFilter= std::shared_ptr<KeyFilter> (new DefaultKeyFilter);
class SignFilter: public DefaultKeyFilter
{
public:
SignFilter(): DefaultKeyFilter()
{
setHasSecret(DefaultKeyFilter::Set);
}
};
static std::shared_ptr<KeyFilter> s_signFilter = std::shared_ptr<KeyFilter> (new SignFilter);
/* Some decoration and a button to remove the filter for a keyselectioncombo */
class ComboWidget: public QWidget
{
Q_OBJECT
public:
explicit ComboWidget(KeySelectionCombo *combo):
mCombo(combo),
mFilterBtn(new QPushButton)
{
auto hLay = new QHBoxLayout(this);
hLay->addWidget(combo, 1);
hLay->addWidget(mFilterBtn, 0);
// Assume that combos start out with a filter
mFilterBtn->setIcon(QIcon::fromTheme(QStringLiteral("kt-remove-filters")));
mFilterBtn->setToolTip(i18n("Remove Filter"));
// FIXME: This is ugly to enforce but otherwise the
// icon is broken.
combo->setMinimumHeight(22);
mFilterBtn->setMinimumHeight(23);
connect(mFilterBtn, &QPushButton::clicked, this, [this] () {
const QString curFilter = mCombo->idFilter();
if (curFilter.isEmpty()) {
mCombo->setIdFilter(mLastIdFilter);
mLastIdFilter = QString();
mFilterBtn->setIcon(QIcon::fromTheme(QStringLiteral("kt-remove-filters")));
mFilterBtn->setToolTip(i18n("Remove Filter"));
} else {
mLastIdFilter = curFilter;
mFilterBtn->setIcon(QIcon::fromTheme(QStringLiteral("kt-add-filters")));
mFilterBtn->setToolTip(i18n("Add Filter"));
mCombo->setIdFilter(QString());
}
});
}
KeySelectionCombo *combo()
{
return mCombo;
}
private:
KeySelectionCombo *mCombo;
QPushButton *mFilterBtn;
QString mLastIdFilter;
};
static enum GpgME::UserID::Validity keyValidity(const GpgME::Key &key)
{
enum GpgME::UserID::Validity validity = GpgME::UserID::Validity::Unknown;
for (const auto &uid: key.userIDs()) {
if (validity == GpgME::UserID::Validity::Unknown
|| validity > uid.validity()) {
validity = uid.validity();
}
}
return validity;
}
} // namespace
class NewKeyApprovalDialog::Private
{
private:
enum Action {
Unset,
GenerateKey,
IgnoreKey,
};
public:
Private(NewKeyApprovalDialog *pub,
GpgME::Protocol forcedProtocol,
GpgME::Protocol presetProtocol,
const QString &sender, bool allowMixed):
mProto(forcedProtocol),
mSender(sender),
mAllowMixed(allowMixed),
q(pub)
{
mMainLay = new QVBoxLayout;
QDialogButtonBox *btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
mOkButton = btnBox->button(QDialogButtonBox::Ok);
QObject::connect (btnBox, &QDialogButtonBox::accepted, q, [this] () {
accepted();
});
QObject::connect (btnBox, &QDialogButtonBox::rejected, q, &QDialog::reject);
mScrollArea = new QScrollArea;
mScrollArea->setWidget(new QWidget);
mScrollLayout = new QVBoxLayout;
mScrollArea->widget()->setLayout(mScrollLayout);
mScrollArea->setWidgetResizable(true);
mScrollArea->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
mScrollArea->setFrameStyle(QFrame::NoFrame);
- mScrollLayout->setMargin(0);
+ mScrollLayout->setContentsMargins(0, 0, 0, 0);
q->setWindowTitle(i18n("Security approval"));
auto fmtLayout = new QHBoxLayout;
mFormatBtns = new QButtonGroup;
auto pgpBtn = new QRadioButton(i18n("OpenPGP"));
auto smimeBtn = new QRadioButton(i18n("S/MIME"));
mFormatBtns->addButton(pgpBtn, 1);
mFormatBtns->addButton(smimeBtn, 2);
mFormatBtns->setExclusive(true);
fmtLayout->addStretch(-1);
fmtLayout->addWidget(pgpBtn);
fmtLayout->addWidget(smimeBtn);
mMainLay->addLayout(fmtLayout);
// Handle force / preset
if (forcedProtocol == GpgME::OpenPGP) {
pgpBtn->setChecked(true);
pgpBtn->setVisible(false);
smimeBtn->setVisible(false);
} else if (forcedProtocol == GpgME::CMS) {
smimeBtn->setChecked(true);
pgpBtn->setVisible(false);
smimeBtn->setVisible(false);
} else if (presetProtocol == GpgME::CMS) {
smimeBtn->setChecked(true);
} else if (!mAllowMixed) {
pgpBtn->setChecked(true);
} else if (mAllowMixed) {
smimeBtn->setVisible(false);
pgpBtn->setVisible(false);
}
updateFilter();
QObject::connect (mFormatBtns, static_cast<void (QButtonGroup::*)(int, bool)> (&QButtonGroup::buttonToggled),
q, [this](int, bool) {
updateFilter();
});
mMainLay->addWidget(mScrollArea);
mComplianceLbl = new QLabel;
mComplianceLbl->setVisible(false);
auto btnLayout = new QHBoxLayout;
btnLayout->addWidget(mComplianceLbl);
btnLayout->addWidget(btnBox);
mMainLay->addLayout(btnLayout);
q->setLayout(mMainLay);
}
void generateKey(KeySelectionCombo *combo)
{
const auto &addr = combo->property("address").toString();
auto job = new QGpgME::DefaultKeyGenerationJob(q);
auto progress = new Kleo::ProgressDialog(job, i18n("Generating key for '%1'...", addr) + QStringLiteral("\n\n") +
i18n("This can take several minutes."), q);
progress->setWindowFlags(progress->windowFlags() & ~Qt::WindowContextHelpButtonHint);
progress->setWindowTitle(i18n("Key generation"));
progress->setModal(true);
progress->setAutoClose(true);
progress->setMinimumDuration(0);
progress->setValue(0);
mRunningJobs << job;
connect (job, &QGpgME::DefaultKeyGenerationJob::result, q,
[this, job, combo] (const GpgME::KeyGenerationResult &result) {
handleKeyGenResult(result, job, combo);
});
job->start(addr, QString());
return;
}
void handleKeyGenResult(const GpgME::KeyGenerationResult &result, QGpgME::Job *job, KeySelectionCombo *combo)
{
mLastError = result.error();
if (!mLastError || mLastError.isCanceled()) {
combo->setDefaultKey(QString::fromLatin1(result.fingerprint()));
connect (combo, &KeySelectionCombo::keyListingFinished, q, [this, job] () {
mRunningJobs.removeAll(job);
});
combo->refreshKeys();
} else {
mRunningJobs.removeAll(job);
}
}
void checkAccepted()
{
if (mLastError || mLastError.isCanceled()) {
KMessageBox::error(q, QString::fromLocal8Bit(mLastError.asString()), i18n("Operation Failed"));
mRunningJobs.clear();
return;
}
if (mRunningJobs.empty()) {
q->accept();
}
}
void accepted()
{
// We can assume everything was validly resolved, otherwise
// the OK button would have been disabled.
// Handle custom items now.
for (auto combo: mAllCombos) {
auto act = combo->currentData(Qt::UserRole).toInt();
if (act == GenerateKey) {
generateKey(combo);
// Only generate once
return;
}
}
checkAccepted();
}
void updateFilter()
{
bool isPGP = mFormatBtns->checkedId() == 1;
bool isSMIME = mFormatBtns->checkedId() == 2;
if (isSMIME) {
mCurEncFilter = s_smimeFilter;
mCurSigFilter = s_smimeSignFilter;
} else if (isPGP) {
mCurEncFilter = s_pgpFilter;
mCurSigFilter = s_pgpSignFilter;
} else {
mCurEncFilter = s_defaultFilter;
mCurSigFilter = s_signFilter;
}
for (auto combo: mSigningCombos) {
combo->setKeyFilter(mCurSigFilter);
}
for (auto combo: mEncCombos) {
combo->setKeyFilter(mCurEncFilter);
}
}
ComboWidget *createSigningCombo(const QString &addr, const GpgME::Key &key)
{
auto combo = new KeySelectionCombo();
combo->setKeyFilter(mCurSigFilter);
if (!key.isNull()) {
combo->setDefaultKey(QString::fromLatin1(key.primaryFingerprint()));
}
if (key.isNull() && mProto != GpgME::CMS) {
combo->appendCustomItem(QIcon::fromTheme(QStringLiteral("document-new")),
i18n("Generate a new key pair"), GenerateKey);
}
combo->appendCustomItem(QIcon::fromTheme(QStringLiteral("emblem-unavailable")),
i18n("Don't confirm identity and integrity"), IgnoreKey);
mSigningCombos << combo;
mAllCombos << combo;
combo->setProperty("address", addr);
connect(combo, &KeySelectionCombo::currentKeyChanged, q, [this] () {
updateOkButton();
});
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), q, [this] () {
updateOkButton();
});
return new ComboWidget(combo);
}
void addSigningKeys(const QMap<QString, std::vector<GpgME::Key> > &resolved,
const QStringList &unresolved)
{
if (resolved.empty() && unresolved.empty()) {
return;
}
for (const QString &addr: resolved.keys()) {
auto group = new QGroupBox(i18nc("Caption for signing key selection",
"Confirm identity '%1' as:", addr));
group->setAlignment(Qt::AlignLeft);
mScrollLayout->addWidget(group);
auto sigLayout = new QVBoxLayout;
group->setLayout(sigLayout);
for (const auto &key: resolved[addr])
{
auto comboWidget = createSigningCombo(addr, key);
if (resolved[addr].size() == 1) {
comboWidget->combo()->setIdFilter(addr);
}
sigLayout->addWidget(comboWidget);
}
}
for (const QString &addr: unresolved) {
auto group = new QGroupBox(i18nc("Caption for signing key selection, no key found",
"No key found for the address '%1':", addr));
group->setAlignment(Qt::AlignLeft);
mScrollLayout->addWidget(group);
auto sigLayout = new QHBoxLayout;
group->setLayout(sigLayout);
auto comboWidget = createSigningCombo(addr, GpgME::Key());
comboWidget->combo()->setIdFilter(addr);
sigLayout->addWidget(comboWidget);
}
}
void addEncryptionAddr(const QString &addr, const std::vector<GpgME::Key> &keys,
QGridLayout *encGrid)
{
encGrid->addWidget(new QLabel(addr), encGrid->rowCount(), 0);
for (const auto &key: keys)
{
auto combo = new KeySelectionCombo(false);
combo->setKeyFilter(mCurEncFilter);
if (!key.isNull()) {
combo->setDefaultKey(QString::fromLatin1(key.primaryFingerprint()));
}
if (mSender == addr && key.isNull()) {
combo->appendCustomItem(QIcon::fromTheme(QStringLiteral("document-new")),
i18n("Generate a new key pair"), GenerateKey);
}
combo->appendCustomItem(QIcon::fromTheme(QStringLiteral("emblem-unavailable")),
i18n("Ignore recipient"), IgnoreKey);
if (keys.size () == 1) {
combo->setIdFilter(addr);
}
connect(combo, &KeySelectionCombo::currentKeyChanged, q, [this] () {
updateOkButton();
});
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), q, [this] () {
updateOkButton();
});
mEncCombos << combo;
mAllCombos << combo;
combo->setProperty("address", addr);
auto comboWidget = new ComboWidget(combo);
encGrid->addWidget(comboWidget, encGrid->rowCount(), 0, 1, 2);
}
}
void addEncryptionKeys(const QMap<QString, std::vector<GpgME::Key> > &resolved,
const QStringList &unresolved)
{
if (resolved.empty() && unresolved.empty()) {
return;
}
auto group = new QGroupBox(i18n("Encrypt to:"));
group->setAlignment(Qt::AlignLeft);
auto encGrid = new QGridLayout;
group->setLayout(encGrid);
mScrollLayout->addWidget(group);
for (const QString &addr: resolved.keys()) {
addEncryptionAddr(addr, resolved[addr], encGrid);
}
std::vector<GpgME::Key> dummy;
dummy.push_back(GpgME::Key());
for (const QString &addr: unresolved) {
addEncryptionAddr(addr, dummy, encGrid);
}
encGrid->setColumnStretch(1, -1);
mScrollLayout->addStretch(-1);
}
void updateOkButton()
{
static QString origOkText = mOkButton->text();
bool isGenerate = false;
bool isAllIgnored = true;
// Check if generate is selected.
for (auto combo: mAllCombos) {
auto act = combo->currentData(Qt::UserRole).toInt();
if (act == GenerateKey) {
mOkButton->setText(i18n("Generate"));
isGenerate = true;
}
if (act != IgnoreKey) {
isAllIgnored = false;
}
}
mOkButton->setEnabled(!isAllIgnored);
if (!isGenerate) {
mOkButton->setText(origOkText);
}
if (Formatting::complianceMode() != QStringLiteral("de-vs")) {
return;
}
// Handle compliance
bool de_vs = true;
for (const auto &key: q->signingKeys()) {
if (!Formatting::isKeyDeVs(key) || keyValidity(key) < GpgME::UserID::Validity::Full) {
de_vs = false;
break;
}
}
if (de_vs) {
for (const auto &keys: q->encryptionKeys().values()) {
for (const auto &key: keys) {
if (!Formatting::isKeyDeVs(key) || keyValidity(key) < GpgME::UserID::Validity::Full) {
de_vs = false;
break;
}
}
if (!de_vs) {
break;
}
}
}
mOkButton->setIcon(QIcon::fromTheme(de_vs
? QStringLiteral("security-high")
: QStringLiteral("security-medium")));
mOkButton->setStyleSheet(QStringLiteral("background-color: ") + (de_vs
? QStringLiteral("#D5FAE2") // KColorScheme(QPalette::Active, KColorScheme::View).background(KColorScheme::PositiveBackground).color().name()
: QStringLiteral("#FAE9EB"))); //KColorScheme(QPalette::Active, KColorScheme::View).background(KColorScheme::NegativeBackground).color().name()));
mComplianceLbl->setText(de_vs
? i18nc("VS-NfD-conforming is a German standard for restricted documents for which special restrictions about algorithms apply. The string states that all cryptographic operations necessary for the communication are compliant with that.",
"VS-NfD-compliant communication possible.")
: i18nc("VS-NfD-conforming is a German standard for restricted documents for which special restrictions about algorithms apply. The string states that all cryptographic operations necessary for the communication are compliant with that.",
"VS-NfD-compliant communication not possible."));
mComplianceLbl->setVisible(true);
}
void selectionChanged()
{
bool isPGP = false;
bool isCMS = false;
for (const auto combo: mEncCombos) {
isPGP |= combo->currentKey().protocol() == GpgME::OpenPGP;
isCMS |= combo->currentKey().protocol() == GpgME::CMS;
if (isPGP && isCMS) {
break;
}
}
}
~Private() {}
GpgME::Protocol mProto;
QList<KeySelectionCombo *> mSigningCombos;
QList<KeySelectionCombo *> mEncCombos;
QList<KeySelectionCombo *> mAllCombos;
QScrollArea *mScrollArea;
QVBoxLayout *mScrollLayout;
QPushButton *mOkButton;
QVBoxLayout *mMainLay;
QButtonGroup *mFormatBtns;
std::shared_ptr<KeyFilter> mCurSigFilter;
std::shared_ptr<KeyFilter> mCurEncFilter;
QString mSender;
bool mAllowMixed;
NewKeyApprovalDialog *q;
QList <QGpgME::Job *> mRunningJobs;
GpgME::Error mLastError;
QLabel *mComplianceLbl;
};
NewKeyApprovalDialog::NewKeyApprovalDialog(const QMap<QString, std::vector<GpgME::Key> > &resolvedSigningKeys,
const QMap<QString, std::vector<GpgME::Key> > &resolvedRecp,
const QStringList &unresolvedSigKeys,
const QStringList &unresolvedRecp,
const QString &sender,
bool allowMixed,
GpgME::Protocol forcedProtocol,
GpgME::Protocol presetProtocol,
QWidget *parent,
Qt::WindowFlags f): QDialog(parent, f),
d(new Private(this, forcedProtocol, presetProtocol, sender, allowMixed))
{
d->addSigningKeys(resolvedSigningKeys, unresolvedSigKeys);
d->addEncryptionKeys(resolvedRecp, unresolvedRecp);
d->updateOkButton();
const auto size = sizeHint();
const auto desk = QApplication::desktop()->screenGeometry(this);
resize(QSize(desk.width() / 3, qMin(size.height(), desk.height() / 2)));
}
std::vector<GpgME::Key> NewKeyApprovalDialog::signingKeys()
{
std::vector <GpgME::Key> ret;
for (const auto combo: d->mSigningCombos) {
ret.push_back(combo->currentKey());
}
return ret;
}
QMap <QString, std::vector<GpgME::Key> > NewKeyApprovalDialog::encryptionKeys()
{
QMap <QString, std::vector<GpgME::Key> > ret;
for (const auto combo: d->mEncCombos) {
const auto &addr = combo->property("address").toString();
const auto &key = combo->currentKey();
if (ret.contains(addr)) {
ret[addr].push_back(key);
} else {
std::vector<GpgME::Key> vec;
vec.push_back(key);
ret.insert(addr, vec);
}
}
return ret;
}
#include "newkeyapprovaldialog.moc"

File Metadata

Mime Type
text/x-diff
Expires
Thu, Feb 26, 6:51 PM (21 h, 47 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ae/e3/7c562c01a7a7b30377db7b811e99

Event Timeline