summaryrefslogtreecommitdiffstats
path: root/debian/pinentry-tqt/pinentry-tqt-1.2.1/qt/pinentrydialog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'debian/pinentry-tqt/pinentry-tqt-1.2.1/qt/pinentrydialog.cpp')
-rw-r--r--debian/pinentry-tqt/pinentry-tqt-1.2.1/qt/pinentrydialog.cpp793
1 files changed, 793 insertions, 0 deletions
diff --git a/debian/pinentry-tqt/pinentry-tqt-1.2.1/qt/pinentrydialog.cpp b/debian/pinentry-tqt/pinentry-tqt-1.2.1/qt/pinentrydialog.cpp
new file mode 100644
index 00000000..17e87e6c
--- /dev/null
+++ b/debian/pinentry-tqt/pinentry-tqt-1.2.1/qt/pinentrydialog.cpp
@@ -0,0 +1,793 @@
+/* pinentrydialog.cpp - A (not yet) secure Qt 4 dialog for PIN entry.
+ * Copyright (C) 2002, 2008 Klarälvdalens Datakonsult AB (KDAB)
+ * Copyright 2007 Ingo Klöcker
+ * Copyright 2016 Intevation GmbH
+ * Copyright (C) 2021, 2022 g10 Code GmbH
+ *
+ * Written by Steffen Hansen <steffen@klaralvdalens-datakonsult.se>.
+ * Modified by Andre Heinecke <aheinecke@intevation.de>
+ * Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
+ *
+ * This program 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.
+ *
+ * This program 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, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "pinentrydialog.h"
+
+#include "accessibility.h"
+#include "capslock.h"
+#include "pinlineedit.h"
+#include "util.h"
+
+#include <QGridLayout>
+#include <QProgressBar>
+#include <QApplication>
+#include <QFontMetrics>
+#include <QStyle>
+#include <QPainter>
+#include <QPushButton>
+#include <QDialogButtonBox>
+#include <QKeyEvent>
+#include <QLabel>
+#include <QPalette>
+#include <QLineEdit>
+#include <QAction>
+#include <QCheckBox>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QMessageBox>
+#include <QRegularExpression>
+#include <QAccessible>
+
+#include <QDebug>
+
+#ifdef Q_OS_WIN
+#include <windows.h>
+#if QT_VERSION >= 0x050700
+#include <QtPlatformHeaders/QWindowsWindowFunctions>
+#endif
+#endif
+
+void raiseWindow(QWidget *w)
+{
+#ifdef Q_OS_WIN
+#if QT_VERSION >= 0x050700
+ QWindowsWindowFunctions::setWindowActivationBehavior(
+ QWindowsWindowFunctions::AlwaysActivateWindow);
+#endif
+#endif
+ w->setWindowState((w->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
+ w->activateWindow();
+ w->raise();
+}
+
+QPixmap applicationIconPixmap(const QIcon &overlayIcon)
+{
+ QPixmap pm = qApp->windowIcon().pixmap(48, 48);
+
+ if (!overlayIcon.isNull()) {
+ QPainter painter(&pm);
+ const int emblemSize = 22;
+ painter.drawPixmap(pm.width() - emblemSize, 0,
+ overlayIcon.pixmap(emblemSize, emblemSize));
+ }
+
+ return pm;
+}
+
+namespace
+{
+
+class TextLabel : public QLabel
+{
+public:
+ using QLabel::QLabel;
+
+protected:
+ void focusInEvent(QFocusEvent *ev) override;
+};
+
+void TextLabel::focusInEvent(QFocusEvent *ev)
+{
+ QLabel::focusInEvent(ev);
+
+ // if the text label gets focus, then select its text; this is a workaround
+ // for missing focus indicators for labels in many Qt styles
+ const Qt::FocusReason reason = ev->reason();
+ const auto isKeyboardFocusEvent = reason == Qt::TabFocusReason
+ || reason == Qt::BacktabFocusReason
+ || reason == Qt::ShortcutFocusReason;
+ if (!text().isEmpty() && isKeyboardFocusEvent) {
+ Accessibility::selectLabelText(this);
+ }
+}
+
+}
+
+void PinEntryDialog::slotTimeout()
+{
+ _timed_out = true;
+ reject();
+}
+
+PinEntryDialog::PinEntryDialog(QWidget *parent, const char *name,
+ int timeout, bool modal, bool enable_quality_bar,
+ const QString &repeatString,
+ const QString &visibilityTT,
+ const QString &hideTT)
+ : QDialog{parent}
+ , _have_quality_bar{enable_quality_bar}
+ , mVisibilityTT{visibilityTT}
+ , mHideTT{hideTT}
+{
+ Q_UNUSED(name)
+
+ if (modal) {
+ setWindowModality(Qt::ApplicationModal);
+ }
+
+ QPalette redTextPalette;
+ redTextPalette.setColor(QPalette::WindowText, Qt::red);
+
+ auto *const mainLayout = new QVBoxLayout{this};
+
+ auto *const hbox = new QHBoxLayout;
+
+ _icon = new QLabel(this);
+ _icon->setPixmap(applicationIconPixmap());
+ hbox->addWidget(_icon, 0, Qt::AlignVCenter | Qt::AlignLeft);
+
+ auto *const grid = new QGridLayout;
+ int row = 1;
+
+ _error = new TextLabel{this};
+ _error->setTextFormat(Qt::PlainText);
+ _error->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ _error->setPalette(redTextPalette);
+ _error->hide();
+ grid->addWidget(_error, row, 1, 1, 2);
+
+ row++;
+ _desc = new TextLabel{this};
+ _desc->setTextFormat(Qt::PlainText);
+ _desc->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ _desc->hide();
+ grid->addWidget(_desc, row, 1, 1, 2);
+
+ row++;
+ mCapsLockHint = new TextLabel{this};
+ mCapsLockHint->setTextFormat(Qt::PlainText);
+ mCapsLockHint->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ mCapsLockHint->setPalette(redTextPalette);
+ mCapsLockHint->setAlignment(Qt::AlignCenter);
+ mCapsLockHint->setVisible(false);
+ grid->addWidget(mCapsLockHint, row, 1, 1, 2);
+
+ row++;
+ {
+ _prompt = new QLabel(this);
+ _prompt->setTextFormat(Qt::PlainText);
+ _prompt->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ _prompt->hide();
+ grid->addWidget(_prompt, row, 1);
+
+ const auto l = new QHBoxLayout;
+ _edit = new PinLineEdit(this);
+ _edit->setMaxLength(256);
+ _edit->setMinimumWidth(_edit->fontMetrics().averageCharWidth()*20 + 48);
+ _edit->setEchoMode(QLineEdit::Password);
+ _prompt->setBuddy(_edit);
+ l->addWidget(_edit, 1);
+
+ if (!repeatString.isNull()) {
+ mGenerateButton = new QPushButton{this};
+ mGenerateButton->setIcon(QIcon(QLatin1String(":/icons/password-generate")));
+ mGenerateButton->setVisible(false);
+ l->addWidget(mGenerateButton);
+ }
+ grid->addLayout(l, row, 2);
+ }
+
+ /* Set up the show password action */
+ const QIcon visibilityIcon = QIcon(QLatin1String(":/icons/visibility.svg"));
+ const QIcon hideIcon = QIcon(QLatin1String(":/icons/hint.svg"));
+#if QT_VERSION >= 0x050200
+ if (!visibilityIcon.isNull() && !hideIcon.isNull()) {
+ mVisiActionEdit = _edit->addAction(visibilityIcon, QLineEdit::TrailingPosition);
+ mVisiActionEdit->setVisible(false);
+ mVisiActionEdit->setToolTip(mVisibilityTT);
+ } else
+#endif
+ {
+ if (!mVisibilityTT.isNull()) {
+ row++;
+ mVisiCB = new QCheckBox{mVisibilityTT, this};
+ grid->addWidget(mVisiCB, row, 1, 1, 2, Qt::AlignLeft);
+ }
+ }
+
+ row++;
+ mConstraintsHint = new TextLabel{this};
+ mConstraintsHint->setTextFormat(Qt::PlainText);
+ mConstraintsHint->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ mConstraintsHint->setVisible(false);
+ grid->addWidget(mConstraintsHint, row, 2);
+
+ row++;
+ mFormattedPassphraseHintSpacer = new QLabel{this};
+ mFormattedPassphraseHintSpacer->setVisible(false);
+ mFormattedPassphraseHint = new TextLabel{this};
+ mFormattedPassphraseHint->setTextFormat(Qt::PlainText);
+ mFormattedPassphraseHint->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ mFormattedPassphraseHint->setVisible(false);
+ grid->addWidget(mFormattedPassphraseHintSpacer, row, 1);
+ grid->addWidget(mFormattedPassphraseHint, row, 2);
+
+ if (!repeatString.isNull()) {
+ row++;
+ auto repeatLabel = new QLabel{this};
+ repeatLabel->setTextFormat(Qt::PlainText);
+ repeatLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ repeatLabel->setText(repeatString);
+ grid->addWidget(repeatLabel, row, 1);
+
+ mRepeat = new PinLineEdit(this);
+ mRepeat->setMaxLength(256);
+ mRepeat->setEchoMode(QLineEdit::Password);
+ repeatLabel->setBuddy(mRepeat);
+ grid->addWidget(mRepeat, row, 2);
+
+ row++;
+ mRepeatError = new TextLabel{this};
+ mRepeatError->setTextFormat(Qt::PlainText);
+ mRepeatError->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ mRepeatError->setPalette(redTextPalette);
+ mRepeatError->hide();
+ grid->addWidget(mRepeatError, row, 2);
+ }
+
+ if (enable_quality_bar) {
+ row++;
+ _quality_bar_label = new QLabel(this);
+ _quality_bar_label->setTextFormat(Qt::PlainText);
+ _quality_bar_label->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ _quality_bar_label->setAlignment(Qt::AlignVCenter);
+ grid->addWidget(_quality_bar_label, row, 1);
+
+ _quality_bar = new QProgressBar(this);
+ _quality_bar->setAlignment(Qt::AlignCenter);
+ _quality_bar_label->setBuddy(_quality_bar);
+ grid->addWidget(_quality_bar, row, 2);
+ }
+
+ hbox->addLayout(grid, 1);
+ mainLayout->addLayout(hbox);
+
+ QDialogButtonBox *const buttons = new QDialogButtonBox(this);
+ buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ _ok = buttons->button(QDialogButtonBox::Ok);
+ _cancel = buttons->button(QDialogButtonBox::Cancel);
+
+ if (style()->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons)) {
+ _ok->setIcon(style()->standardIcon(QStyle::SP_DialogOkButton));
+ _cancel->setIcon(style()->standardIcon(QStyle::SP_DialogCancelButton));
+ }
+
+ mainLayout->addStretch(1);
+ mainLayout->addWidget(buttons);
+ mainLayout->setSizeConstraint(QLayout::SetFixedSize);
+
+ if (timeout > 0) {
+ _timer = new QTimer(this);
+ connect(_timer, &QTimer::timeout, this, &PinEntryDialog::slotTimeout);
+ _timer->start(timeout * 1000);
+ }
+
+ connect(buttons, &QDialogButtonBox::accepted,
+ this, &PinEntryDialog::onAccept);
+ connect(buttons, &QDialogButtonBox::rejected,
+ this, &QDialog::reject);
+ connect(_edit, &QLineEdit::textChanged,
+ this, &PinEntryDialog::updateQuality);
+ connect(_edit, &QLineEdit::textChanged,
+ this, &PinEntryDialog::textChanged);
+ connect(_edit, &PinLineEdit::backspacePressed,
+ this, &PinEntryDialog::onBackspace);
+ if (mGenerateButton) {
+ connect(mGenerateButton, &QPushButton::clicked,
+ this, &PinEntryDialog::generatePin);
+ }
+ if (mVisiActionEdit) {
+ connect(mVisiActionEdit, &QAction::triggered,
+ this, &PinEntryDialog::toggleVisibility);
+ }
+ if (mVisiCB) {
+ connect(mVisiCB, &QCheckBox::toggled,
+ this, &PinEntryDialog::toggleVisibility);
+ }
+ if (mRepeat) {
+ connect(mRepeat, &QLineEdit::textChanged,
+ this, &PinEntryDialog::textChanged);
+ }
+
+ auto capsLockWatcher = new CapsLockWatcher{this};
+ connect(capsLockWatcher, &CapsLockWatcher::stateChanged,
+ this, [this] (bool locked) {
+ mCapsLockHint->setVisible(locked);
+ });
+
+ connect(qApp, &QApplication::focusChanged,
+ this, &PinEntryDialog::focusChanged);
+ connect(qApp, &QApplication::applicationStateChanged,
+ this, &PinEntryDialog::checkCapsLock);
+ checkCapsLock();
+
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::installActivationObserver(this);
+ accessibilityActiveChanged(QAccessible::isActive());
+#endif
+
+#if QT_VERSION >= 0x050000
+ /* This is mostly an issue on Windows where this results
+ in the pinentry popping up nicely with an animation and
+ comes to front. It is not ifdefed for Windows only since
+ window managers on Linux like KWin can also have this
+ result in an animation when the pinentry is shown and
+ not just popping it up.
+ */
+ if (qApp->platformName() != QLatin1String("wayland")) {
+ setWindowState(Qt::WindowMinimized);
+ QTimer::singleShot(0, this, [this] () {
+ raiseWindow(this);
+ });
+ }
+#else
+ activateWindow();
+ raise();
+#endif
+}
+
+PinEntryDialog::~PinEntryDialog()
+{
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::removeActivationObserver(this);
+#endif
+}
+
+void PinEntryDialog::keyPressEvent(QKeyEvent *e)
+{
+ const auto returnPressed =
+ (!e->modifiers() && (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return))
+ || (e->modifiers() & Qt::KeypadModifier && e->key() == Qt::Key_Enter);
+ if (returnPressed && _edit->hasFocus() && mRepeat) {
+ // if the user pressed Return in the first input field, then move the
+ // focus to the repeat input field and prevent further event processing
+ // by QDialog (which would trigger the default button)
+ mRepeat->setFocus();
+ e->ignore();
+ return;
+ }
+
+ QDialog::keyPressEvent(e);
+}
+
+void PinEntryDialog::keyReleaseEvent(QKeyEvent *event)
+{
+ QDialog::keyReleaseEvent(event);
+ checkCapsLock();
+}
+
+void PinEntryDialog::showEvent(QShowEvent *event)
+{
+ QDialog::showEvent(event);
+ _edit->setFocus();
+}
+
+void PinEntryDialog::setDescription(const QString &txt)
+{
+ _desc->setVisible(!txt.isEmpty());
+ _desc->setText(txt);
+ Accessibility::setDescription(_desc, txt);
+ _icon->setPixmap(applicationIconPixmap());
+ setError(QString());
+}
+
+QString PinEntryDialog::description() const
+{
+ return _desc->text();
+}
+
+void PinEntryDialog::setError(const QString &txt)
+{
+ if (!txt.isNull()) {
+ _icon->setPixmap(applicationIconPixmap(QIcon{QStringLiteral(":/icons/data-error.svg")}));
+ }
+ _error->setText(txt);
+ Accessibility::setDescription(_error, txt);
+ _error->setVisible(!txt.isEmpty());
+}
+
+QString PinEntryDialog::error() const
+{
+ return _error->text();
+}
+
+void PinEntryDialog::setPin(const QString &txt)
+{
+ _edit->setPin(txt);
+}
+
+QString PinEntryDialog::pin() const
+{
+ return _edit->pin();
+}
+
+void PinEntryDialog::setPrompt(const QString &txt)
+{
+ _prompt->setText(txt);
+ _prompt->setVisible(!txt.isEmpty());
+ if (txt.contains("PIN"))
+ _disable_echo_allowed = false;
+}
+
+QString PinEntryDialog::prompt() const
+{
+ return _prompt->text();
+}
+
+void PinEntryDialog::setOkText(const QString &txt)
+{
+ _ok->setText(txt);
+ Accessibility::setDescription(_ok, txt);
+ _ok->setVisible(!txt.isEmpty());
+}
+
+void PinEntryDialog::setCancelText(const QString &txt)
+{
+ _cancel->setText(txt);
+ Accessibility::setDescription(_cancel, txt);
+ _cancel->setVisible(!txt.isEmpty());
+}
+
+void PinEntryDialog::setQualityBar(const QString &txt)
+{
+ if (_have_quality_bar) {
+ _quality_bar_label->setText(txt);
+ Accessibility::setDescription(_quality_bar_label, txt);
+ }
+}
+
+void PinEntryDialog::setQualityBarTT(const QString &txt)
+{
+ if (_have_quality_bar) {
+ _quality_bar->setToolTip(txt);
+ }
+}
+
+void PinEntryDialog::setGenpinLabel(const QString &txt)
+{
+ if (!mGenerateButton) {
+ return;
+ }
+ mGenerateButton->setVisible(!txt.isEmpty());
+ if (!txt.isEmpty()) {
+ Accessibility::setName(mGenerateButton, txt);
+ }
+}
+
+void PinEntryDialog::setGenpinTT(const QString &txt)
+{
+ if (mGenerateButton) {
+ mGenerateButton->setToolTip(txt);
+ }
+}
+
+void PinEntryDialog::setCapsLockHint(const QString &txt)
+{
+ mCapsLockHint->setText(txt);
+}
+
+void PinEntryDialog::setFormattedPassphrase(const PinEntryDialog::FormattedPassphraseOptions &options)
+{
+ mFormatPassphrase = options.formatPassphrase;
+ mFormattedPassphraseHint->setTextFormat(Qt::RichText);
+ mFormattedPassphraseHint->setText(QLatin1String("<html>") + options.hint.toHtmlEscaped() + QLatin1String("</html>"));
+ Accessibility::setName(mFormattedPassphraseHint, options.hint);
+ toggleFormattedPassphrase();
+}
+
+void PinEntryDialog::setConstraintsOptions(const ConstraintsOptions &options)
+{
+ mEnforceConstraints = options.enforce;
+ mConstraintsHint->setText(options.shortHint);
+ if (!options.longHint.isEmpty()) {
+ mConstraintsHint->setToolTip(QLatin1String("<html>") +
+ options.longHint.toHtmlEscaped().replace(QLatin1String("\n\n"), QLatin1String("<br>")) +
+ QLatin1String("</html>"));
+ Accessibility::setDescription(mConstraintsHint, options.longHint);
+ }
+ mConstraintsErrorTitle = options.errorTitle;
+
+ mConstraintsHint->setVisible(mEnforceConstraints && !options.shortHint.isEmpty());
+}
+
+void PinEntryDialog::toggleFormattedPassphrase()
+{
+ const bool enableFormatting = mFormatPassphrase && _edit->echoMode() == QLineEdit::Normal;
+ _edit->setFormattedPassphrase(enableFormatting);
+ if (mRepeat) {
+ mRepeat->setFormattedPassphrase(enableFormatting);
+ const bool hintAboutToBeHidden = mFormattedPassphraseHint->isVisible() && !enableFormatting;
+ if (hintAboutToBeHidden) {
+ // set hint spacer to current height of hint label before hiding the hint
+ mFormattedPassphraseHintSpacer->setMinimumHeight(mFormattedPassphraseHint->height());
+ mFormattedPassphraseHintSpacer->setVisible(true);
+ } else if (enableFormatting) {
+ mFormattedPassphraseHintSpacer->setVisible(false);
+ }
+ mFormattedPassphraseHint->setVisible(enableFormatting);
+ }
+}
+
+void PinEntryDialog::onBackspace()
+{
+ cancelTimeout();
+
+ if (_disable_echo_allowed) {
+ _edit->setEchoMode(QLineEdit::NoEcho);
+ if (mRepeat) {
+ mRepeat->setEchoMode(QLineEdit::NoEcho);
+ }
+ }
+}
+
+void PinEntryDialog::updateQuality(const QString &txt)
+{
+ int length;
+ int percent;
+ QPalette pal;
+
+ _disable_echo_allowed = false;
+
+ if (!_have_quality_bar || !_pinentry_info) {
+ return;
+ }
+ const QByteArray utf8_pin = txt.toUtf8();
+ const char *pin = utf8_pin.constData();
+ length = strlen(pin);
+ percent = length ? pinentry_inq_quality(_pinentry_info, pin, length) : 0;
+ if (!length) {
+ _quality_bar->reset();
+ } else {
+ pal = _quality_bar->palette();
+ if (percent < 0) {
+ pal.setColor(QPalette::Highlight, QColor("red"));
+ percent = -percent;
+ } else {
+ pal.setColor(QPalette::Highlight, QColor("green"));
+ }
+ _quality_bar->setPalette(pal);
+ _quality_bar->setValue(percent);
+ }
+}
+
+void PinEntryDialog::setPinentryInfo(pinentry_t peinfo)
+{
+ _pinentry_info = peinfo;
+}
+
+void PinEntryDialog::focusChanged(QWidget *old, QWidget *now)
+{
+ // Grab keyboard. It might be a little weird to do it here, but it works!
+ // Previously this code was in showEvent, but that did not work in Qt4.
+ if (!_pinentry_info || _pinentry_info->grab) {
+ if (_grabbed && old && (old == _edit || old == mRepeat)) {
+ old->releaseKeyboard();
+ _grabbed = false;
+ }
+ if (!_grabbed && now && (now == _edit || now == mRepeat)) {
+ now->grabKeyboard();
+ _grabbed = true;
+ }
+ }
+}
+
+void PinEntryDialog::textChanged(const QString &text)
+{
+ Q_UNUSED(text);
+
+ cancelTimeout();
+
+ if (mVisiActionEdit && sender() == _edit) {
+ mVisiActionEdit->setVisible(!_edit->pin().isEmpty());
+ }
+ if (mGenerateButton) {
+ mGenerateButton->setVisible(
+ _edit->pin().isEmpty()
+#ifndef QT_NO_ACCESSIBILITY
+ && !mGenerateButton->accessibleName().isEmpty()
+#endif
+ );
+ }
+}
+
+void PinEntryDialog::generatePin()
+{
+ unique_malloced_ptr<char> pin{pinentry_inq_genpin(_pinentry_info)};
+ if (pin) {
+ if (_edit->echoMode() == QLineEdit::Password) {
+ if (mVisiActionEdit) {
+ mVisiActionEdit->trigger();
+ }
+ if (mVisiCB) {
+ mVisiCB->setChecked(true);
+ }
+ }
+ const auto pinStr = QString::fromUtf8(pin.get());
+ _edit->setPin(pinStr);
+ mRepeat->setPin(pinStr);
+ // explicitly focus the first input field and select the generated password
+ _edit->setFocus();
+ _edit->selectAll();
+ }
+}
+
+void PinEntryDialog::toggleVisibility()
+{
+ if (sender() != mVisiCB) {
+ if (_edit->echoMode() == QLineEdit::Password) {
+ if (mVisiActionEdit) {
+ mVisiActionEdit->setIcon(QIcon(QLatin1String(":/icons/hint.svg")));
+ mVisiActionEdit->setToolTip(mHideTT);
+ }
+ _edit->setEchoMode(QLineEdit::Normal);
+ if (mRepeat) {
+ mRepeat->setEchoMode(QLineEdit::Normal);
+ }
+ } else {
+ if (mVisiActionEdit) {
+ mVisiActionEdit->setIcon(QIcon(QLatin1String(":/icons/visibility.svg")));
+ mVisiActionEdit->setToolTip(mVisibilityTT);
+ }
+ _edit->setEchoMode(QLineEdit::Password);
+ if (mRepeat) {
+ mRepeat->setEchoMode(QLineEdit::Password);
+ }
+ }
+ } else {
+ if (mVisiCB->isChecked()) {
+ if (mRepeat) {
+ mRepeat->setEchoMode(QLineEdit::Normal);
+ }
+ _edit->setEchoMode(QLineEdit::Normal);
+ } else {
+ if (mRepeat) {
+ mRepeat->setEchoMode(QLineEdit::Password);
+ }
+ _edit->setEchoMode(QLineEdit::Password);
+ }
+ }
+ toggleFormattedPassphrase();
+}
+
+QString PinEntryDialog::repeatedPin() const
+{
+ if (mRepeat) {
+ return mRepeat->pin();
+ }
+ return QString();
+}
+
+bool PinEntryDialog::timedOut() const
+{
+ return _timed_out;
+}
+
+void PinEntryDialog::setRepeatErrorText(const QString &err)
+{
+ if (mRepeatError) {
+ mRepeatError->setText(err);
+ }
+}
+
+void PinEntryDialog::cancelTimeout()
+{
+ if (_timer) {
+ _timer->stop();
+ }
+}
+
+void PinEntryDialog::checkCapsLock()
+{
+ const auto state = capsLockState();
+ if (state != LockState::Unknown) {
+ mCapsLockHint->setVisible(state == LockState::On);
+ }
+}
+
+void PinEntryDialog::onAccept()
+{
+ cancelTimeout();
+
+ if (mRepeat && mRepeat->pin() != _edit->pin()) {
+#ifndef QT_NO_ACCESSIBILITY
+ if (QAccessible::isActive()) {
+ QMessageBox::information(this, mRepeatError->text(), mRepeatError->text());
+ } else
+#endif
+ {
+ mRepeatError->setVisible(true);
+ }
+ return;
+ }
+
+ const auto result = checkConstraints();
+ if (result != PassphraseNotOk) {
+ accept();
+ }
+}
+
+#ifndef QT_NO_ACCESSIBILITY
+void PinEntryDialog::accessibilityActiveChanged(bool active)
+{
+ // Allow text labels to get focus if accessibility is active
+ const auto focusPolicy = active ? Qt::StrongFocus : Qt::ClickFocus;
+ _error->setFocusPolicy(focusPolicy);
+ _desc->setFocusPolicy(focusPolicy);
+ mCapsLockHint->setFocusPolicy(focusPolicy);
+ mConstraintsHint->setFocusPolicy(focusPolicy);
+ mFormattedPassphraseHint->setFocusPolicy(focusPolicy);
+ if (mRepeatError) {
+ mRepeatError->setFocusPolicy(focusPolicy);
+ }
+}
+#endif
+
+PinEntryDialog::PassphraseCheckResult PinEntryDialog::checkConstraints()
+{
+ if (!mEnforceConstraints) {
+ return PassphraseNotChecked;
+ }
+
+ const auto passphrase = _edit->pin().toUtf8();
+ unique_malloced_ptr<char> error{pinentry_inq_checkpin(
+ _pinentry_info, passphrase.constData(), passphrase.size())};
+
+ if (!error) {
+ return PassphraseOk;
+ }
+
+ const auto messageLines = QString::fromUtf8(QByteArray::fromPercentEncoding(error.get())).split(QChar{'\n'});
+ if (messageLines.isEmpty()) {
+ // shouldn't happen because pinentry_inq_checkpin() either returns NULL or a non-empty string
+ return PassphraseOk;
+ }
+ const auto firstLine = messageLines.first();
+ const auto indexOfFirstNonEmptyAdditionalLine = messageLines.indexOf(QRegularExpression{QStringLiteral(".*\\S.*")}, 1);
+ const auto additionalLines = indexOfFirstNonEmptyAdditionalLine > 0 ? messageLines.mid(indexOfFirstNonEmptyAdditionalLine).join(QChar{'\n'}) : QString{};
+ QMessageBox messageBox{this};
+ messageBox.setIcon(QMessageBox::Information);
+ messageBox.setWindowTitle(mConstraintsErrorTitle);
+ messageBox.setText(firstLine);
+ messageBox.setInformativeText(additionalLines);
+ messageBox.setStandardButtons(QMessageBox::Ok);
+ messageBox.exec();
+ return PassphraseNotOk;
+}
+
+#include "pinentrydialog.moc"