diff --git a/CMakeLists.txt b/CMakeLists.txt index e48961d..b50efda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,57 +1,49 @@ # Copyright (C) 2018 by Intevation GmbH # # This file is Free Software under the GNU GPL (v>=2) # and comes with ABSOLUTELY NO WARRANTY! # See LICENSE.txt for details. cmake_minimum_required(VERSION 2.8.8) project(gpg4win-tools) set(PRETTY_NAME cryp.do) ### Generic Setup set(GPGME_REQUIRED_VERSION "1.8.0") set(QT_REQUIRED_VERSION "5.6.0") set(LIBKLEO_VERSION "5.7.20") #Old qtmain linking behavior to be compatible with cmake versions < 2.8.11 if(POLICY CMP0020) cmake_policy(SET CMP0020 OLD) endif() find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED Widgets) find_package(Gpgmepp ${GPGME_REQUIRED_VERSION} CONFIG REQUIRED) find_package(QGpgme ${GPGME_REQUIRED_VERSION} CONFIG REQUIRED) find_package(KF5Libkleo ${LIBKLEO_VERSION} CONFIG REQUIRED) set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) -### Hardening flags - -if(NOT APPLE) - set(HARDENING_FLAGS " -Wall -s -fstack-protector-all -fno-exceptions") - set(HARDENING_FLAGS " ${HARDENING_FLAGS} -Wstack-protector") - set(HARDENING_FLAGS " ${HARDENING_FLAGS} --param ssp-buffer-size=4") - set(HARDENING_FLAGS " ${HARDENING_FLAGS} -D_FORTIFY_SOURCE=2 -O0") -endif(NOT APPLE) if(WIN32) add_definitions(-D_WIN32_WINNT=0x0600) # Windows vista add_definitions(-DWINVER=0x0600) add_definitions(-DUNICODE -D_UNICODE) add_definitions(-DMINGW_HAS_SECURE_API) # for _s functions endif(WIN32) -set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS} ${HARDENING_FLAGS}") +set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") # Cmake does not correctly identify gcc windres when cross compiling # making this line neccessary to set the correct flags for it. # See: http://public.kitware.com/Bug/view.php?id=11773 SET(CMAKE_RC_COMPILE_OBJECT " -Ocoff ") #add_subdirectory(img) ### Include the actual source directories add_subdirectory(src) diff --git a/src/resolver/CMakeLists.txt b/src/resolver/CMakeLists.txt index e8ff3d4..6f43cc8 100644 --- a/src/resolver/CMakeLists.txt +++ b/src/resolver/CMakeLists.txt @@ -1,29 +1,31 @@ # Copyright (C) 2018 Intevation GmbH # # This file is Free Software under the GNU GPL (v>=2) # and comes with ABSOLUTELY NO WARRANTY! # See LICENSE.txt for details. set(EXECUTABLE_NAME "resolver") set(EXECUTABLE_SRC main.cpp resolver.cpp + overlay.cpp + img/icon.rc ${CMAKE_SOURCE_DIR}/src//util/strhelp.c ) add_executable(${EXECUTABLE_NAME} ${_add_executable_params} ${EXECUTABLE_SRC} ) target_link_libraries(${EXECUTABLE_NAME} Qt5::Widgets KF5::Libkleo Gpgmepp QGpgme ) if (WIN32) - set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-municode") + set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINK_FLAGS "-municode") endif(WIN32) diff --git a/src/resolver/overlay.cpp b/src/resolver/overlay.cpp new file mode 100644 index 0000000..643f0bb --- /dev/null +++ b/src/resolver/overlay.cpp @@ -0,0 +1,113 @@ +/* Copyright (C) 2018 by Intevation GmbH + * + * This file is Free Software under the GNU GPL (v>=2) + * and comes with ABSOLUTELY NO WARRANTY! + * See LICENSE.txt for details. + */ + +#include "overlay.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef Q_OS_WIN + +#include + +class Overlay::Private +{ +public: + Private(Overlay *qq, WId id, const QString &text): + q(qq) + { + auto window = QWindow::fromWinId(id); + m_target = (HWND) id; + + auto parentHandle = q->windowHandle(); + if (parentHandle) { + parentHandle->setTransientParent(window); + } + + q->setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog | Qt::Tool | Qt::CustomizeWindowHint); + q->setAttribute(Qt::WA_TransparentForMouseEvents); + q->setAttribute(Qt::WA_TranslucentBackground); + + auto vLay = new QVBoxLayout(q); + auto bar = new QProgressBar; + auto label = new QLabel; + label->setText(QStringLiteral("

%1

").arg(text)); + bar->setRange(0, 0); + vLay->addStretch(1); + + auto subLay1 = new QVBoxLayout; + auto subLay3 = new QHBoxLayout; + subLay3->addStretch(0.5); + subLay3->addWidget(label); + subLay3->addStretch(1); + subLay1->addLayout(subLay3); + subLay1->addWidget(bar); + + auto subLay2 = new QHBoxLayout; + subLay2->addStretch(0.1); + subLay2->addLayout(subLay1); + subLay2->addStretch(0.1); + + vLay->addLayout(subLay2); + + vLay->addStretch(1); + + auto refreshTimer = new QTimer(q); + connect(refreshTimer, &QTimer::timeout, q, [this] () { + RECT rect; + if (GetWindowRect(m_target, &rect)) { + q->setGeometry(rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top); + } else { + //maybe window was closed + std::cerr << "GetWindowRect failed"; + } + }); + refreshTimer->start(50); // update interval in milliseconds + q->show(); + } + HWND m_target; + + Overlay *q; +}; + +Overlay::Overlay (WId id, const QString &text): + d(new Private(this, id, text)) +{ +} + +void Overlay::paintEvent(QPaintEvent *e) { + QPainter painter(this); + + int width = size().width(); + int height = size().height(); + + QLinearGradient gradient(0, 0, 0, height); + gradient.setColorAt(0, Qt::transparent); + gradient.setColorAt(0.5, Qt::white); + gradient.setColorAt(1, Qt::transparent); + + QBrush brush(gradient); + + painter.fillRect(0, 0, width, height, gradient); + QWidget::paintEvent(e); +} + +#else +Overlay::Overlay (WId id, const QString &text) +{ +} +#endif diff --git a/src/resolver/overlay.h b/src/resolver/overlay.h new file mode 100644 index 0000000..6fb1cae --- /dev/null +++ b/src/resolver/overlay.h @@ -0,0 +1,27 @@ +#ifndef OVERLAY_H +#define OVERLAY_H +/* Copyright (C) 2018 by Intevation GmbH + * + * This file is Free Software under the GNU GPL (v>=2) + * and comes with ABSOLUTELY NO WARRANTY! + * See LICENSE.txt for details. + */ + +#include +#include +class QPaintEvent; + +class Overlay: public QWidget +{ + Q_OBJECT +public: + Overlay (WId id, const QString &text); + +protected: + virtual void paintEvent (QPaintEvent *event) override; + +private: + class Private; + std::shared_ptr d; +}; +#endif diff --git a/src/resolver/resolver-options.h b/src/resolver/resolver-options.h index 5df65f4..50160cb 100644 --- a/src/resolver/resolver-options.h +++ b/src/resolver/resolver-options.h @@ -1,42 +1,50 @@ #ifndef RESOLVER_OPTIONS #define RESOLVER_OPTIONS /* Copyright (C) 2018 by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include #include /** @file Commandline options*/ static void options(QCommandLineParser &parser) { QList options; options << QCommandLineOption(QStringList() << QStringLiteral("debug"), QStringLiteral("Print debug output.")) << QCommandLineOption(QStringLiteral("protocol"), QStringLiteral("Specify a forced protocol"), QStringLiteral("pgp or cms")) << QCommandLineOption(QStringLiteral("sender"), QStringLiteral("The sender"), QStringLiteral("sender mailbox")) << QCommandLineOption(QStringLiteral("sign"), QStringLiteral("Should be signed")) + << QCommandLineOption(QStringLiteral("encrypt"), + QStringLiteral("Should be encrypted")) + << QCommandLineOption(QStringLiteral("hwnd"), + QStringLiteral("Parent Window"), + QStringLiteral("windows window handle")) + << QCommandLineOption(QStringLiteral("overlayText"), + QStringLiteral("Overlay Text"), + QStringLiteral("text to overlay over hwnd")) << QCommandLineOption(QStringLiteral("alwaysShow"), QStringLiteral("Should always be shown")); for (const auto &opt: options) { parser.addOption(opt); } parser.addVersionOption(); parser.addHelpOption(); parser.addPositionalArgument(QStringLiteral("recipients"), QStringLiteral("Recipient Mailboxes"), QStringLiteral("[recipients]")); } #endif // RESOLVER_OPTIONS diff --git a/src/resolver/resolver.cpp b/src/resolver/resolver.cpp index 4a6c176..cea1db2 100644 --- a/src/resolver/resolver.cpp +++ b/src/resolver/resolver.cpp @@ -1,94 +1,114 @@ /* Copyright (C) 2018 by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "resolver.h" +#include "overlay.h" + #include #include #include #include #include #include class Resolver::Private { public: Private(Resolver *qq): q(qq) { } void printResolvedKeys(const Kleo::KeyResolver *kr) { qDebug() << "Printing resolved keys."; const auto sigMap = kr->signingKeys(); for (const auto fmt: sigMap.keys()) { for (const auto key: sigMap[fmt]) { std::cout << "sig:" << Kleo::cryptoMessageFormatToString(fmt) << ":" << key.primaryFingerprint() << std::endl; } } const auto encMap = kr->encryptionKeys(); for (const auto fmt: encMap.keys()) { for (const auto mbox: encMap[fmt].keys()) { for (const auto key: encMap[fmt][mbox]) { std::cout << "enc:" << Kleo::cryptoMessageFormatToString(fmt) << ":" << key.primaryFingerprint() << std::endl; } } } } + void newOverlay(WId wid, const QString &text) + { + m_overlay = std::shared_ptr(new Overlay(wid, text)); + m_overlay->show(); + } + void newResolver(const QCommandLineParser &parser) { const auto proto = parser.value(QStringLiteral("protocol")).toLower(); Kleo::CryptoMessageFormat format; if (proto == QStringLiteral("cms")) { format = Kleo::AnySMIME; } else if (proto == QStringLiteral("pgp")) { format = Kleo::AnyOpenPGP; } else { format = Kleo::AutoFormat; } const auto recps = parser.positionalArguments(); - auto *kr = new Kleo::KeyResolver (!recps.isEmpty() /* encrypt */, + auto *kr = new Kleo::KeyResolver (!recps.isEmpty() || parser.isSet(QStringLiteral("encrypt")) /* encrypt */, parser.isSet(QStringLiteral("sign")) /*sign*/, format /* CryptoMesssageFormat */, false /* AllowMixed */); kr->setRecipients(recps); kr->setSender(parser.value("sender")); kr->enableNagging(true); connect (kr, &Kleo::KeyResolver::keysResolved, q, [this, kr] (bool success, bool sendUnencrypted) { if (!success) { std::cout << "cancel" << std::endl; } else if (sendUnencrypted) { std::cout << "unencrypted" << std::endl; } else { printResolvedKeys(kr); } delete kr; qApp->quit(); }); kr->start(parser.isSet(QStringLiteral("alwaysShow"))); } Resolver *q; + std::shared_ptr m_overlay; }; Resolver::Resolver(int &argc, char *argv[]) : QApplication(argc, argv), d(new Private(this)) { } QString Resolver::newInstance(const QCommandLineParser &parser, const QString &workingDirectry) { + const auto hwnd = parser.value(QStringLiteral("hwnd")); + if (!hwnd.isEmpty()) { + bool ok; + WId id = (WId) hwnd.toInt(&ok); + if (!ok) { + std::cerr << "invalid hwnd value" << std::endl; + qApp->exit(EXIT_FAILURE); + } + d->newOverlay(id, parser.value(QStringLiteral("overlayText"))); + } + d->newResolver(parser); return QString(); }