diff options
Diffstat (limited to 'debian/pinentry-tqt/pinentry-tqt-1.2.1/qt/main.cpp')
-rw-r--r-- | debian/pinentry-tqt/pinentry-tqt-1.2.1/qt/main.cpp | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/debian/pinentry-tqt/pinentry-tqt-1.2.1/qt/main.cpp b/debian/pinentry-tqt/pinentry-tqt-1.2.1/qt/main.cpp new file mode 100644 index 00000000..47d15d26 --- /dev/null +++ b/debian/pinentry-tqt/pinentry-tqt-1.2.1/qt/main.cpp @@ -0,0 +1,429 @@ +/* main.cpp - A Qt dialog for PIN entry. + * Copyright (C) 2002, 2008 Klarälvdalens Datakonsult AB (KDAB) + * Copyright (C) 2003, 2021 g10 Code GmbH + * Copyright 2007 Ingo Klöcker + * + * Written by Steffen Hansen <steffen@klaralvdalens-datakonsult.se>. + * Modified by Marcus Brinkmann <marcus@g10code.de>. + * Modified by Marc Mutz <marc@kdab.com> + * 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 "accessibility.h" +#include "pinentryconfirm.h" +#include "pinentrydialog.h" +#include "pinentry.h" +#include "util.h" + +#include <QApplication> +#include <QDebug> +#include <QIcon> +#include <QMessageBox> +#include <QPushButton> +#include <QString> +#include <QWidget> +#if QT_VERSION >= 0x050000 +#include <QWindow> +#endif + +#include <stdio.h> +#include <errno.h> + +#include <stdexcept> +#include <gpg-error.h> + +#ifdef FALLBACK_CURSES +#include <pinentry-curses.h> +#endif + +#if QT_VERSION >= 0x050000 && defined(QT_STATIC) + #include <QtPlugin> + #ifdef Q_OS_WIN + #include <windows.h> + #include <shlobj.h> + Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin) + #elif defined(Q_OS_MAC) + Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin) + #else + Q_IMPORT_PLUGIN(QXcbIntegrationPlugin) + #endif +#endif + +#ifdef Q_OS_WIN +#include <windows.h> +#endif + +#include "pinentry_debug.h" + +static QString escape_accel(const QString &s) +{ + + QString result; + result.reserve(s.size()); + + bool afterUnderscore = false; + + for (unsigned int i = 0, end = s.size() ; i != end ; ++i) { + const QChar ch = s[i]; + if (ch == QLatin1Char('_')) { + if (afterUnderscore) { // escaped _ + result += QLatin1Char('_'); + afterUnderscore = false; + } else { // accel + afterUnderscore = true; + } + } else { + if (afterUnderscore || // accel + ch == QLatin1Char('&')) { // escape & from being interpreted by Qt + result += QLatin1Char('&'); + } + result += ch; + afterUnderscore = false; + } + } + + if (afterUnderscore) + // trailing single underscore: shouldn't happen, but deal with it robustly: + { + result += QLatin1Char('_'); + } + + return result; +} + +namespace +{ +class InvalidUtf8 : public std::invalid_argument +{ +public: + InvalidUtf8() : std::invalid_argument("invalid utf8") {} + ~InvalidUtf8() throw() {} +}; +} + +static const bool GPG_AGENT_IS_PORTED_TO_ONLY_SEND_UTF8 = false; + +static QString from_utf8(const char *s) +{ + const QString result = QString::fromUtf8(s); + if (result.contains(QChar::ReplacementCharacter)) { + if (GPG_AGENT_IS_PORTED_TO_ONLY_SEND_UTF8) { + throw InvalidUtf8(); + } else { + return QString::fromLocal8Bit(s); + } + } + + return result; +} + +static void +setup_foreground_window(QWidget *widget, WId parentWid) +{ +#if QT_VERSION >= 0x050000 + /* For windows set the desktop window as the transient parent */ + QWindow *parentWindow = nullptr; + if (parentWid) { + parentWindow = QWindow::fromWinId(parentWid); + } +#ifdef Q_OS_WIN + if (!parentWindow) { + HWND desktop = GetDesktopWindow(); + if (desktop) { + parentWindow = QWindow::fromWinId((WId) desktop); + } + } +#endif + if (parentWindow) { + // Ensure that we have a native wid + widget->winId(); + QWindow *wndHandle = widget->windowHandle(); + + if (wndHandle) { + wndHandle->setTransientParent(parentWindow); + } + } +#endif + widget->setWindowFlags(Qt::Window | + Qt::CustomizeWindowHint | + Qt::WindowTitleHint | + Qt::WindowCloseButtonHint | + Qt::WindowStaysOnTopHint | + Qt::WindowMinimizeButtonHint); +} + +static int +qt_cmd_handler(pinentry_t pe) +{ + int want_pass = !!pe->pin; + + const QString ok = + pe->ok ? escape_accel(from_utf8(pe->ok)) : + pe->default_ok ? escape_accel(from_utf8(pe->default_ok)) : + /* else */ QLatin1String("&OK") ; + const QString cancel = + pe->cancel ? escape_accel(from_utf8(pe->cancel)) : + pe->default_cancel ? escape_accel(from_utf8(pe->default_cancel)) : + /* else */ QLatin1String("&Cancel") ; + + unique_malloced_ptr<char> str{pinentry_get_title(pe)}; + const QString title = + str ? from_utf8(str.get()) : + /* else */ QLatin1String("pinentry-qt") ; + + const QString repeatError = + pe->repeat_error_string ? from_utf8(pe->repeat_error_string) : + QLatin1String("Passphrases do not match"); + const QString repeatString = + pe->repeat_passphrase ? from_utf8(pe->repeat_passphrase) : + QString(); + const QString visibilityTT = + pe->default_tt_visi ? from_utf8(pe->default_tt_visi) : + QLatin1String("Show passphrase"); + const QString hideTT = + pe->default_tt_hide ? from_utf8(pe->default_tt_hide) : + QLatin1String("Hide passphrase"); + + const QString capsLockHint = + pe->default_capshint ? from_utf8(pe->default_capshint) : + QLatin1String("Caps Lock is on"); + + const QString generateLbl = pe->genpin_label ? from_utf8(pe->genpin_label) : + QString(); + const QString generateTT = pe->genpin_tt ? from_utf8(pe->genpin_tt) : + QString(); + + + if (want_pass) { + PinEntryDialog pinentry(nullptr, 0, pe->timeout, true, !!pe->quality_bar, + repeatString, visibilityTT, hideTT); + setup_foreground_window(&pinentry, pe->parent_wid); + pinentry.setPinentryInfo(pe); + pinentry.setPrompt(escape_accel(from_utf8(pe->prompt))); + pinentry.setDescription(from_utf8(pe->description)); + pinentry.setRepeatErrorText(repeatError); + pinentry.setGenpinLabel(generateLbl); + pinentry.setGenpinTT(generateTT); + pinentry.setCapsLockHint(capsLockHint); + pinentry.setFormattedPassphrase({ + bool(pe->formatted_passphrase), + from_utf8(pe->formatted_passphrase_hint)}); + pinentry.setConstraintsOptions({ + bool(pe->constraints_enforce), + from_utf8(pe->constraints_hint_short), + from_utf8(pe->constraints_hint_long), + from_utf8(pe->constraints_error_title) + }); + + if (!title.isEmpty()) { + pinentry.setWindowTitle(title); + } + + /* If we reuse the same dialog window. */ + pinentry.setPin(QString()); + + pinentry.setOkText(ok); + pinentry.setCancelText(cancel); + if (pe->error) { + pinentry.setError(from_utf8(pe->error)); + } + if (pe->quality_bar) { + pinentry.setQualityBar(from_utf8(pe->quality_bar)); + } + if (pe->quality_bar_tt) { + pinentry.setQualityBarTT(from_utf8(pe->quality_bar_tt)); + } + bool ret = pinentry.exec(); + if (!ret) { + if (pinentry.timedOut()) + pe->specific_err = gpg_error (GPG_ERR_TIMEOUT); + return -1; + } + + const QString pinStr = pinentry.pin(); + QByteArray pin = pinStr.toUtf8(); + + if (!!pe->repeat_passphrase) { + /* Should not have been possible to accept + the dialog in that case but we do a safety + check here */ + pe->repeat_okay = (pinStr == pinentry.repeatedPin()); + } + + int len = strlen(pin.constData()); + if (len >= 0) { + pinentry_setbufferlen(pe, len + 1); + if (pe->pin) { + strcpy(pe->pin, pin.constData()); + return len; + } + } + return -1; + } else { + const QString desc = pe->description ? from_utf8(pe->description) : QString(); + const QString notok = pe->notok ? escape_accel(from_utf8(pe->notok)) : QString(); + + const QMessageBox::StandardButtons buttons = + pe->one_button ? QMessageBox::Ok : + pe->notok ? QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel : + /* else */ QMessageBox::Ok | QMessageBox::Cancel ; + + PinentryConfirm box{QMessageBox::Information, title, desc, buttons}; + box.setTextFormat(Qt::PlainText); + box.setTextInteractionFlags(Qt::TextSelectableByMouse); + box.setTimeout(std::chrono::seconds{pe->timeout}); + setup_foreground_window(&box, pe->parent_wid); + + const struct { + QMessageBox::StandardButton button; + QString label; + } buttonLabels[] = { + { QMessageBox::Ok, ok }, + { QMessageBox::Yes, ok }, + { QMessageBox::No, notok }, + { QMessageBox::Cancel, cancel }, + }; + + for (size_t i = 0 ; i < sizeof buttonLabels / sizeof * buttonLabels ; ++i) + if ((buttons & buttonLabels[i].button) && !buttonLabels[i].label.isEmpty()) { + box.button(buttonLabels[i].button)->setText(buttonLabels[i].label); + Accessibility::setDescription(box.button(buttonLabels[i].button), + buttonLabels[i].label); + } + + box.setIconPixmap(applicationIconPixmap()); + + if (!pe->one_button) { + box.setDefaultButton(QMessageBox::Cancel); + } + + box.show(); + raiseWindow(&box); + + const int rc = box.exec(); + + if (rc == QMessageBox::Cancel) { + pe->canceled = true; + } + if (box.timedOut()) { + pe->specific_err = gpg_error (GPG_ERR_TIMEOUT); + } + + return rc == QMessageBox::Ok || rc == QMessageBox::Yes ; + + } +} + +static int +qt_cmd_handler_ex(pinentry_t pe) +{ + try { + return qt_cmd_handler(pe); + } catch (const InvalidUtf8 &) { + pe->locale_err = true; + return pe->pin ? -1 : false ; + } catch (...) { + pe->canceled = true; + return pe->pin ? -1 : false ; + } +} + +pinentry_cmd_handler_t pinentry_cmd_handler = qt_cmd_handler_ex; + +int +main(int argc, char *argv[]) +{ + pinentry_init("pinentry-qt"); + + QApplication *app = NULL; + int new_argc = 0; + +#ifdef FALLBACK_CURSES +#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) + // check a few environment variables that are usually set on X11 or Wayland sessions + const bool hasWaylandDisplay = qEnvironmentVariableIsSet("WAYLAND_DISPLAY"); + const bool isWaylandSessionType = qgetenv("XDG_SESSION_TYPE") == "wayland"; + const bool hasX11Display = pinentry_have_display(argc, argv); + const bool isX11SessionType = qgetenv("XDG_SESSION_TYPE") == "x11"; + const bool isGUISession = hasWaylandDisplay || isWaylandSessionType || hasX11Display || isX11SessionType; + qCDebug(PINENTRY_LOG) << "hasWaylandDisplay:" << hasWaylandDisplay; + qCDebug(PINENTRY_LOG) << "isWaylandSessionType:" << isWaylandSessionType; + qCDebug(PINENTRY_LOG) << "hasX11Display:" << hasX11Display; + qCDebug(PINENTRY_LOG) << "isX11SessionType:" << isX11SessionType; + qCDebug(PINENTRY_LOG) << "isGUISession:" << isGUISession; +#else + const bool isGUISession = pinentry_have_display(argc, argv); +#endif + if (!isGUISession) { + pinentry_cmd_handler = curses_cmd_handler; + pinentry_set_flavor_flag ("curses"); + } else +#endif + { + /* Qt does only understand -display but not --display; thus we + are fixing that here. The code is pretty simply and may get + confused if an argument is called "--display". */ + char **new_argv, *p; + size_t n; + int i, done; + + for (n = 0, i = 0; i < argc; i++) { + n += strlen(argv[i]) + 1; + } + n++; + new_argv = (char **)calloc(argc + 1, sizeof * new_argv); + if (new_argv) { + *new_argv = (char *)malloc(n); + } + if (!new_argv || !*new_argv) { + fprintf(stderr, "pinentry-qt: can't fixup argument list: %s\n", + strerror(errno)); + exit(EXIT_FAILURE); + + } + for (done = 0, p = *new_argv, i = 0; i < argc; i++) + if (!done && !strcmp(argv[i], "--display")) { + new_argv[i] = strcpy(p, argv[i] + 1); + p += strlen(argv[i] + 1) + 1; + done = 1; + } else { + new_argv[i] = strcpy(p, argv[i]); + p += strlen(argv[i]) + 1; + } + + /* Note: QApplication uses int &argc so argc has to be valid + * for the full lifetime of the application. + * + * As Qt might modify argc / argv we use copies here so that + * we do not loose options that are handled in both. e.g. display. + */ + new_argc = argc; + Q_ASSERT (new_argc); + app = new QApplication(new_argc, new_argv); + app->setWindowIcon(QIcon(QLatin1String(":/icons/document-encrypt.png"))); + } + + pinentry_parse_opts(argc, argv); + + int rc = pinentry_loop(); + delete app; + return rc ? EXIT_FAILURE : EXIT_SUCCESS ; +} |