File indexing completed on 2025-01-19 04:46:49
0001 /* 0002 SPDX-FileCopyrightText: 2016 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "gnupgwksformatter.h" 0008 #include "gnupgwks_debug.h" 0009 #include "gnupgwksmessagepart.h" 0010 0011 #include <QObject> 0012 #include <QPalette> 0013 #include <QUrl> 0014 #include <QUrlQuery> 0015 #include <QVariant> 0016 0017 #include <MessageCore/ColorUtil> 0018 #include <MessageViewer/HtmlWriter> 0019 #include <MessageViewer/Viewer> 0020 #include <MimeTreeParser/BodyPart> 0021 #include <MimeTreeParser/MessagePart> 0022 #include <MimeTreeParser/NodeHelper> 0023 0024 #include <GrantleeTheme/GrantleeKi18nLocalizer> 0025 #include <GrantleeTheme/GrantleeThemeEngine> 0026 #include <KTextTemplate/Context> 0027 #include <KTextTemplate/Template> 0028 0029 #include <QGpgME/DecryptJob> 0030 #include <QGpgME/Protocol> 0031 0032 using namespace MimeTreeParser; 0033 using namespace MimeTreeParser::Interface; 0034 0035 namespace 0036 { 0037 bool partHasMimeType(KMime::Content *part, const char *mt) 0038 { 0039 const auto ct = part->contentType(false); 0040 return ct && ct->isMimeType(mt); 0041 } 0042 } 0043 0044 MessagePart::Ptr ApplicationGnuPGWKSFormatter::process(BodyPart &part) const 0045 { 0046 const auto ct = part.content()->contentType(false); 0047 if (ct) { 0048 if (ct->isMimeType("multipart/mixed")) { 0049 const auto subParts = part.content()->contents(); 0050 if (subParts.size() == 2 && partHasMimeType(subParts[0], "text/plain") && partHasMimeType(subParts[1], "application/vnd.gnupg.wks")) { 0051 return MimeMessagePart::Ptr(new MimeMessagePart(part.objectTreeParser(), subParts.at(1), false)); 0052 } else { 0053 return MimeMessagePart::Ptr(new MimeMessagePart(part.objectTreeParser(), subParts.at(0), false)); 0054 } 0055 } 0056 0057 if (ct->isMimeType("application/vnd.gnupg.wks")) { 0058 const auto content = part.content()->decodedContent(); 0059 if (content.startsWith("-----BEGIN PGP MESSAGE")) { 0060 auto decrypt = QGpgME::openpgp()->decryptJob(); 0061 QByteArray plainText; 0062 auto result = decrypt->exec(part.content()->decodedContent(), plainText); 0063 if (result.error()) { 0064 qCWarning(GNUPGWKS_LOG) << "Decryption failed!" << result.error().asString(); 0065 return {}; 0066 } 0067 part.content()->setBody(plainText); 0068 } 0069 return MessagePart::Ptr(new GnuPGWKSMessagePart(&part)); 0070 } 0071 } 0072 0073 return {}; 0074 } 0075 0076 bool ApplicationGnuPGWKSFormatter::render(const MimeTreeParser::MessagePartPtr &msgPart, 0077 MessageViewer::HtmlWriter *htmlWriter, 0078 MessageViewer::RenderContext *context) const 0079 { 0080 Q_UNUSED(context) 0081 auto mp = msgPart.dynamicCast<GnuPGWKSMessagePart>(); 0082 if (!mp) { 0083 return false; 0084 } 0085 0086 const QByteArray propertyName = "_GnuPGWKS" + mp->fingerprint().toLatin1(); 0087 const bool hasError = (mp->nodeHelper()->property(propertyName.constData()).toString() == QLatin1StringView("error")); 0088 if (hasError) { 0089 mp->nodeHelper()->setProperty(propertyName.constData(), QVariant()); 0090 } 0091 GrantleeTheme::Engine engine; 0092 engine.localizer()->setApplicationDomain(QByteArrayLiteral("messageviewer_application_gnupgwks_plugin")); 0093 auto loader = QSharedPointer<KTextTemplate::FileSystemTemplateLoader>::create(); 0094 loader->setTemplateDirs({QStringLiteral(":/")}); 0095 engine.addTemplateLoader(loader); 0096 KTextTemplate::Template tpl = engine.loadByName(QStringLiteral("gnupgwksmessagepart.html")); 0097 if (tpl->error()) { 0098 qCWarning(GNUPGWKS_LOG) << tpl->errorString(); 0099 } 0100 KTextTemplate::Context ctx; 0101 ctx.setLocalizer(engine.localizer()); 0102 0103 QObject block; 0104 0105 const auto baseUrl = QStringLiteral("gnupgwks?%1"); 0106 block.setProperty("isRequest", mp->confirmationType() == GnuPGWKSMessagePart::ConfirmationRequest); 0107 block.setProperty("isResponse", mp->confirmationType() == GnuPGWKSMessagePart::ConfirmationResponse); 0108 QUrlQuery confirmQuery; 0109 confirmQuery.addQueryItem(QStringLiteral("action"), QStringLiteral("confirm")); 0110 confirmQuery.addQueryItem(QStringLiteral("fpr"), mp->fingerprint()); 0111 block.setProperty("confirmUrl", mp->makeLink(baseUrl.arg(confirmQuery.toString(QUrl::FullyDecoded)))); 0112 QUrlQuery keyQuery; 0113 keyQuery.addQueryItem(QStringLiteral("action"), QStringLiteral("show")); 0114 keyQuery.addQueryItem(QStringLiteral("fpr"), mp->fingerprint()); 0115 block.setProperty("keyUrl", mp->makeLink(baseUrl.arg(keyQuery.toString(QUrl::FullyDecoded)))); 0116 block.setProperty("hasError", hasError); 0117 ctx.insert(QStringLiteral("block"), &block); 0118 0119 QObject style; 0120 QPalette p; 0121 p.setCurrentColorGroup(QPalette::Normal); 0122 style.setProperty("buttonBg", p.color(QPalette::Button).name()); 0123 style.setProperty("buttonBorder", p.shadow().color().name()); 0124 p.setCurrentColorGroup(QPalette::Active); 0125 style.setProperty("buttonBorderHl", p.shadow().color().name()); 0126 p.setCurrentColorGroup(QPalette::Normal); 0127 style.setProperty("buttonFg", p.color(QPalette::ButtonText).name()); 0128 style.setProperty("errorFg", MessageCore::ColorUtil::self()->pgpSignedBadTextColor().name()); 0129 ctx.insert(QStringLiteral("style"), &style); 0130 KTextTemplate::OutputStream s(htmlWriter->stream()); 0131 tpl->render(&s, &ctx); 0132 return true; 0133 }