gnupgwksformatter.cpp 5.76 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/*
  Copyright (c) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>

   This library is free software; you can redistribute it and/or modify it
   under the terms of the GNU Library General Public License as published by
   the Free Software Foundation; either version 2 of the License, or (at your
   option) any later version.

   This library 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 Library General Public
   License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to the
   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   02110-1301, USA.
*/

#include "gnupgwksformatter.h"
#include "gnupgwksmessagepart.h"

#include <QObject>
#include <QVariant>
#include <QPalette>
#include <QUrl>

#include <MimeTreeParser/BodyPart>
#include <MimeTreeParser/HtmlWriter>
#include <MimeTreeParser/NodeHelper>
31 32
#include <MimeTreeParser/MessagePart>
#include <MimeTreeParser/BodyPartFormatterBaseFactory>
33 34 35 36 37 38 39 40 41
#include <MessageCore/MessageCoreUtil>
#include <MessageViewer/Viewer>

#include <GrantleeTheme/GrantleeThemeEngine>
#include <GrantleeTheme/GrantleeKi18nLocalizer>
#include <GrantleeTheme/QtResourceTemplateLoader>
#include <grantlee/context.h>
#include <grantlee/template.h>

42 43 44 45
#include <QGpgME/Protocol>
#include <QGpgME/DecryptJob>

using namespace MimeTreeParser;
46 47
using namespace MimeTreeParser::Interface;

48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
namespace {
bool partHasMimeType(KMime::Content *part, const char *mt)
{
    const auto ct = part->contentType(false);
    return ct && ct->isMimeType(mt);
}
}

Interface::MessagePart::Ptr ApplicationGnuPGWKSFormatter::process(BodyPart &part) const
{
    const auto ct = part.content()->contentType(false);
    if (ct && ct->isMimeType("multipart/mixed")) {
        const auto subParts = part.content()->contents();
        if (subParts.size() == 2
            && partHasMimeType(subParts[0], "text/plain")
            && partHasMimeType(subParts[1], "application/vnd.gnupg.wks")) {
Laurent Montel's avatar
Laurent Montel committed
64
            return MimeMessagePart::Ptr(new MimeMessagePart(part.objectTreeParser(), subParts.at(1), false));
65
        } else {
Laurent Montel's avatar
Laurent Montel committed
66
            return MimeMessagePart::Ptr(new MimeMessagePart(part.objectTreeParser(), subParts.at(0), false));
67 68 69 70 71 72
        }
    }

    return BodyPartFormatter::process(part);
}

Laurent Montel's avatar
Laurent Montel committed
73
BodyPartFormatter::Result ApplicationGnuPGWKSFormatter::format(BodyPart *part, MimeTreeParser::HtmlWriter *writer) const
74 75 76 77 78
{
    if (!writer) {
        return Ok;
    }

79 80 81 82 83
    if (part->content()->contentType(false) && part->content()->contentType()->isMimeType("multipart/mixed")) {
        const auto registry = part->source()->bodyPartFormatterFactory()->subtypeRegistry("multipart");
        const auto mixed = registry.find("mixed");
        Q_ASSERT(mixed != registry.end()); // there *must* be a multipart/mixed handler

84
        return mixed->second->format(part, writer);
85 86 87 88 89 90 91 92 93 94 95 96 97 98
    }

    const auto content = part->content()->decodedContent();
    if (content.startsWith("-----BEGIN PGP MESSAGE")) {
        auto decrypt = QGpgME::openpgp()->decryptJob();
        QByteArray plainText;
        auto result = decrypt->exec(part->content()->decodedContent(), plainText);
        if (result.error()) {
            qWarning() << "Decryption failed!" << result.error().asString();
            return Failed;
        }
        part->content()->setBody(plainText);
    }

99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
    GnuPGWKSMessagePart mp(part);

    const QByteArray propertyName = "_GnuPGWKS" + mp.fingerprint().toLatin1();
    const bool hasError = (part->nodeHelper()->property(propertyName).toString() == QLatin1String("error"));
    if (hasError) {
        part->nodeHelper()->setProperty(propertyName, QVariant());
    }

    GrantleeTheme::Engine engine;
    engine.localizer()->setApplicationDomain(QByteArrayLiteral("messageviewer_application_gnupgwks_plugin"));
    engine.addTemplateLoader(QSharedPointer<GrantleeTheme::QtResourceTemplateLoader>::create());

    Grantlee::Template tpl = engine.loadByName(QStringLiteral(":/gnupgwksmessagepart.html"));
    Grantlee::Context ctx;
    ctx.setLocalizer(engine.localizer());

    QObject block;

    const auto baseUrl = QStringLiteral("gnupgwks?%1");
    block.setProperty("isRequest", mp.confirmationType() == GnuPGWKSMessagePart::ConfirmationRequest);
    block.setProperty("isResponse", mp.confirmationType() == GnuPGWKSMessagePart::ConfirmationResponse);
    QUrlQuery confirmQuery;
    confirmQuery.addQueryItem(QStringLiteral("action"), QStringLiteral("confirm"));
    confirmQuery.addQueryItem(QStringLiteral("fpr"), mp.fingerprint());
    block.setProperty("confirmUrl", mp.part()->makeLink(baseUrl.arg(confirmQuery.toString(QUrl::FullyDecoded))));
    QUrlQuery keyQuery;
    keyQuery.addQueryItem(QStringLiteral("action"), QStringLiteral("show"));
    keyQuery.addQueryItem(QStringLiteral("fpr"), mp.fingerprint());
    block.setProperty("keyUrl", mp.part()->makeLink(baseUrl.arg(keyQuery.toString(QUrl::FullyDecoded))));
    block.setProperty("hasError", hasError);
    ctx.insert(QStringLiteral("block"), &block);

    QObject style;
    QPalette p;
    p.setCurrentColorGroup(QPalette::Normal);
    style.setProperty("buttonBg", p.color(QPalette::Button).name());
    style.setProperty("buttonBorder", p.shadow().color().name());
    p.setCurrentColorGroup(QPalette::Active);
    style.setProperty("buttonBorderHl", p.shadow().color().name());
    p.setCurrentColorGroup(QPalette::Normal);
    style.setProperty("buttonFg", p.color(QPalette::ButtonText).name());
    style.setProperty("errorFg", MessageCore::ColorUtil::self()->pgpSignedBadTextColor().name());
    ctx.insert(QStringLiteral("style"), &style);

    writer->queue(tpl->render(&ctx));
    return Ok;
}