File indexing completed on 2025-03-09 04:54:32

0001 /*
0002    SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "grantleeheaderformatter.h"
0008 #include "headerstyle_util.h"
0009 #include "settings/messageviewersettings.h"
0010 #include "utils/iconnamecache.h"
0011 
0012 #include <MessageCore/StringUtil>
0013 #include <MimeTreeParser/NodeHelper>
0014 
0015 #include <KMime/DateFormatter>
0016 #include <KMime/KMimeMessage>
0017 
0018 #include <KColorScheme>
0019 #include <KIconLoader>
0020 #include <KLocalizedString>
0021 #include <KTextTemplate/Engine>
0022 #include <KTextTemplate/MetaType>
0023 
0024 using namespace MessageCore;
0025 
0026 using namespace MessageViewer;
0027 
0028 Q_DECLARE_METATYPE(const KMime::Headers::Generics::AddressList *)
0029 Q_DECLARE_METATYPE(QSharedPointer<KMime::Headers::Generics::AddressList>)
0030 Q_DECLARE_METATYPE(const KMime::Headers::Generics::MailboxList *)
0031 Q_DECLARE_METATYPE(QSharedPointer<KMime::Headers::Generics::MailboxList>)
0032 Q_DECLARE_METATYPE(QDateTime)
0033 
0034 // Read-only introspection of KMime::Headers::Generics::AddressList object.
0035 namespace KTextTemplate
0036 {
0037 template<>
0038 inline QVariant TypeAccessor<const KMime::Headers::Generics::AddressList *>::lookUp(const KMime::Headers::Generics::AddressList *const object,
0039                                                                                     const QString &property)
0040 {
0041     if (property == QLatin1StringView("nameOnly")) {
0042         return StringUtil::emailAddrAsAnchor(object, StringUtil::DisplayNameOnly);
0043     } else if (property == QLatin1StringView("isSet")) {
0044         return !object->asUnicodeString().isEmpty();
0045     } else if (property == QLatin1StringView("fullAddress")) {
0046         return StringUtil::emailAddrAsAnchor(object, StringUtil::DisplayFullAddress);
0047     } else if (property == QLatin1StringView("str")) {
0048         return object->asUnicodeString();
0049     } else if (property.startsWith(QLatin1StringView("expandable"))) {
0050         const auto &name = property.mid(10);
0051         const QString val = MessageCore::StringUtil::emailAddrAsAnchor(object,
0052                                                                        MessageCore::StringUtil::DisplayFullAddress,
0053                                                                        QString(),
0054                                                                        MessageCore::StringUtil::ShowLink,
0055                                                                        MessageCore::StringUtil::ExpandableAddresses,
0056                                                                        QStringLiteral("Full") + name + QStringLiteral("AddressList"));
0057         return val;
0058     }
0059     return {};
0060 }
0061 
0062 template<>
0063 inline QVariant TypeAccessor<QByteArray &>::lookUp(const QByteArray &object, const QString &property)
0064 {
0065     return object;
0066 }
0067 }
0068 KTEXTTEMPLATE_BEGIN_LOOKUP(QSharedPointer<KMime::Headers::Generics::MailboxList>)
0069 if (property == QLatin1StringView("nameOnly")) {
0070     return StringUtil::emailAddrAsAnchor(object.data(), StringUtil::DisplayNameOnly);
0071 } else if (property == QLatin1StringView("isSet")) {
0072     return !object->asUnicodeString().isEmpty();
0073 } else if (property == QLatin1StringView("fullAddress")) {
0074     return StringUtil::emailAddrAsAnchor(object.data(), StringUtil::DisplayFullAddress);
0075 } else if (property == QLatin1StringView("str")) {
0076     return object->asUnicodeString();
0077 } else if (property.startsWith(QLatin1StringView("expandable"))) {
0078     const auto &name = property.mid(10);
0079     const QString val = MessageCore::StringUtil::emailAddrAsAnchor(object.data(),
0080                                                                    MessageCore::StringUtil::DisplayFullAddress,
0081                                                                    QString(),
0082                                                                    MessageCore::StringUtil::ShowLink,
0083                                                                    MessageCore::StringUtil::ExpandableAddresses,
0084                                                                    QStringLiteral("Full") + name + QStringLiteral("AddressList"));
0085     return val;
0086 }
0087 KTEXTTEMPLATE_END_LOOKUP
0088 
0089 // Read-only introspection of KMime::Headers::Generics::MailboxList object.
0090 namespace KTextTemplate
0091 {
0092 template<>
0093 inline QVariant TypeAccessor<const KMime::Headers::Generics::MailboxList *>::lookUp(const KMime::Headers::Generics::MailboxList *const object,
0094                                                                                     const QString &property)
0095 {
0096     if (property == QLatin1StringView("nameOnly")) {
0097         return StringUtil::emailAddrAsAnchor(object, StringUtil::DisplayNameOnly);
0098     } else if (property == QLatin1StringView("isSet")) {
0099         return !object->asUnicodeString().isEmpty();
0100     } else if (property == QLatin1StringView("fullAddress")) {
0101         return StringUtil::emailAddrAsAnchor(object, StringUtil::DisplayFullAddress);
0102     } else if (property == QLatin1StringView("str")) {
0103         return object->asUnicodeString();
0104     } else if (property.startsWith(QLatin1StringView("expandable"))) {
0105         const auto &name = property.mid(10);
0106         const QString val = MessageCore::StringUtil::emailAddrAsAnchor(object,
0107                                                                        MessageCore::StringUtil::DisplayFullAddress,
0108                                                                        QString(),
0109                                                                        MessageCore::StringUtil::ShowLink,
0110                                                                        MessageCore::StringUtil::ExpandableAddresses,
0111                                                                        QStringLiteral("Full") + name + QStringLiteral("AddressList"));
0112         return val;
0113     }
0114     return {};
0115 }
0116 }
0117 KTEXTTEMPLATE_BEGIN_LOOKUP(QSharedPointer<KMime::Headers::Generics::AddressList>)
0118 if (property == QLatin1StringView("nameOnly")) {
0119     return StringUtil::emailAddrAsAnchor(object.data(), StringUtil::DisplayNameOnly);
0120 } else if (property == QLatin1StringView("isSet")) {
0121     return !object->asUnicodeString().isEmpty();
0122 } else if (property == QLatin1StringView("fullAddress")) {
0123     return StringUtil::emailAddrAsAnchor(object.data(), StringUtil::DisplayFullAddress);
0124 } else if (property == QLatin1StringView("str")) {
0125     return object->asUnicodeString();
0126 } else if (property.startsWith(QLatin1StringView("expandable"))) {
0127     const auto &name = property.mid(10);
0128     const QString val = MessageCore::StringUtil::emailAddrAsAnchor(object.data(),
0129                                                                    MessageCore::StringUtil::DisplayFullAddress,
0130                                                                    QString(),
0131                                                                    MessageCore::StringUtil::ShowLink,
0132                                                                    MessageCore::StringUtil::ExpandableAddresses,
0133                                                                    QStringLiteral("Full") + name + QStringLiteral("AddressList"));
0134     return val;
0135 }
0136 KTEXTTEMPLATE_END_LOOKUP
0137 namespace KTextTemplate
0138 {
0139 template<>
0140 inline QVariant TypeAccessor<QDateTime &>::lookUp(const QDateTime &object, const QString &property)
0141 {
0142     MessageViewer::HeaderStyleUtil::HeaderStyleUtilDateFormat dateFormat;
0143     if (property == QLatin1StringView("str")) {
0144         return HeaderStyleUtil::dateStr(object);
0145     } else if (property == QLatin1StringView("short")) {
0146         dateFormat = MessageViewer::HeaderStyleUtil::ShortDate;
0147     } else if (property == QLatin1StringView("long")) {
0148         dateFormat = MessageViewer::HeaderStyleUtil::LongDate;
0149     } else if (property == QLatin1StringView("fancylong")) {
0150         dateFormat = MessageViewer::HeaderStyleUtil::FancyLongDate;
0151     } else if (property == QLatin1StringView("fancyshort")) {
0152         dateFormat = MessageViewer::HeaderStyleUtil::FancyShortDate;
0153     } else if (property == QLatin1StringView("localelong")) {
0154         dateFormat = MessageViewer::HeaderStyleUtil::LongDate;
0155     } else {
0156         return {};
0157     }
0158 
0159     return HeaderStyleUtil::strToHtml(HeaderStyleUtil::dateString(object, dateFormat));
0160 }
0161 }
0162 
0163 class Q_DECL_HIDDEN HeaderFormatter
0164 {
0165 public:
0166     virtual ~HeaderFormatter() = default;
0167 
0168     virtual QVariant format(KMime::Message *message, MimeTreeParser::NodeHelper *nodeHelper, bool showEmoticons) = 0;
0169     virtual QString i18nName() = 0;
0170 };
0171 
0172 class DefaultHeaderFormatter : public HeaderFormatter
0173 {
0174 public:
0175     DefaultHeaderFormatter(const QByteArray &h)
0176         : header(h)
0177     {
0178     }
0179 
0180     QString i18nName() override
0181     {
0182         if (header == "list-id") {
0183             return i18n("List-Id:");
0184         } else {
0185             return {};
0186         }
0187     }
0188 
0189     QVariant format(KMime::Message *message, MimeTreeParser::NodeHelper *nodeHelper, bool showEmoticons) override
0190     {
0191         Q_UNUSED(showEmoticons);
0192         return nodeHelper->mailHeaderAsBase(header.constData(), message)->asUnicodeString();
0193     }
0194 
0195 private:
0196     QByteArray header;
0197 };
0198 
0199 class SubjectFormatter : public HeaderFormatter
0200 {
0201 public:
0202     QString i18nName() override
0203     {
0204         return i18n("Subject:");
0205     }
0206 
0207     QVariant format(KMime::Message *message, MimeTreeParser::NodeHelper *nodeHelper, bool showEmoticons) override
0208     {
0209         KTextToHTML::Options flags = KTextToHTML::PreserveSpaces;
0210         if (showEmoticons) {
0211             flags |= KTextToHTML::ReplaceSmileys;
0212         }
0213         const auto subjectStr = nodeHelper->mailHeaderAsBase("subject", message)->asUnicodeString();
0214 
0215         return HeaderStyleUtil::strToHtml(subjectStr, flags);
0216     }
0217 };
0218 
0219 class DateFormatter : public HeaderFormatter
0220 {
0221 public:
0222     QString i18nName() override
0223     {
0224         return i18n("Date:");
0225     }
0226 
0227     QVariant format(KMime::Message *message, MimeTreeParser::NodeHelper *nodeHelper, bool showEmoticons) override
0228     {
0229         Q_UNUSED(showEmoticons);
0230         const auto value = nodeHelper->dateHeader(message);
0231         return value;
0232     }
0233 };
0234 
0235 class MessageIdFormatter : public HeaderFormatter
0236 {
0237 public:
0238     QString i18nName() override
0239     {
0240         return i18n("Message-Id:");
0241     }
0242 
0243     QVariant format(KMime::Message *message, MimeTreeParser::NodeHelper *nodeHelper, bool showEmoticons) override
0244     {
0245         const auto messageIdHeader = nodeHelper->mailHeaderAsBase("Message-Id", message);
0246         if (messageIdHeader != nullptr) {
0247             return static_cast<const KMime::Headers::MessageID *>(messageIdHeader)->identifier();
0248         }
0249         return {};
0250     }
0251 };
0252 
0253 class AddressHeaderFormatter : public HeaderFormatter
0254 {
0255 public:
0256     AddressHeaderFormatter(const QByteArray &h)
0257         : header(h)
0258     {
0259     }
0260 
0261     QString i18nName() override
0262     {
0263         if (header == "to") {
0264             return i18n("To:");
0265         } else if (header == "reply-To") {
0266             return i18n("Reply To:");
0267         } else if (header == "cc") {
0268             return i18n("CC:");
0269         } else if (header == "bcc") {
0270             return i18n("BCC:");
0271         } else if (header == "from") {
0272             return i18n("From:");
0273         } else if (header == "sender") {
0274             return i18n("Sender:");
0275         } else if (header == "resent-From") {
0276             return i18n("resent from:");
0277         } else if (header == "resent-To") {
0278             return i18n("resent to:");
0279         } else {
0280             return {};
0281         }
0282     }
0283 
0284     QVariant format(KMime::Message *message, MimeTreeParser::NodeHelper *nodeHelper, bool showEmoticons) override
0285     {
0286         Q_UNUSED(showEmoticons);
0287         const auto value = nodeHelper->mailHeaderAsAddressList(header.constData(), message);
0288         return QVariant::fromValue(value);
0289     }
0290 
0291 protected:
0292     QByteArray header;
0293 };
0294 
0295 class MessageViewer::GrantleeHeaderFormatter::GrantleeHeaderFormatterPrivate
0296 {
0297 public:
0298     GrantleeHeaderFormatterPrivate()
0299         : engine(new KTextTemplate::Engine)
0300     {
0301         KTextTemplate::registerMetaType<const KMime::Headers::Generics::AddressList *>();
0302         KTextTemplate::registerMetaType<const KMime::Headers::Generics::MailboxList *>();
0303         KTextTemplate::registerMetaType<QSharedPointer<KMime::Headers::Generics::MailboxList>>();
0304         KTextTemplate::registerMetaType<QSharedPointer<KMime::Headers::Generics::AddressList>>();
0305         KTextTemplate::registerMetaType<QDateTime>();
0306         KTextTemplate::registerMetaType<QByteArray>();
0307         iconSize = KIconLoader::global()->currentSize(KIconLoader::Toolbar);
0308         templateLoader = QSharedPointer<KTextTemplate::FileSystemTemplateLoader>(new KTextTemplate::FileSystemTemplateLoader);
0309         engine->addTemplateLoader(templateLoader);
0310 
0311         QList<QByteArray> addressHeaders;
0312         addressHeaders << "to"
0313                        << "reply-To"
0314                        << "cc"
0315                        << "bcc"
0316                        << "from"
0317                        << "sender"
0318                        << "resent-From"
0319                        << "resent-To";
0320 
0321         for (const auto &header : std::as_const(addressHeaders)) {
0322             registerHeaderFormatter(header, QSharedPointer<HeaderFormatter>(new AddressHeaderFormatter(header)));
0323         }
0324 
0325         registerHeaderFormatter("subject", QSharedPointer<HeaderFormatter>(new SubjectFormatter()));
0326         registerHeaderFormatter("date", QSharedPointer<HeaderFormatter>(new DateFormatter()));
0327         registerHeaderFormatter("Message-Id", QSharedPointer<HeaderFormatter>(new MessageIdFormatter()));
0328     }
0329 
0330     ~GrantleeHeaderFormatterPrivate()
0331     {
0332         delete engine;
0333     }
0334 
0335     void registerHeaderFormatter(const QByteArray &header, QSharedPointer<HeaderFormatter> formatter)
0336     {
0337         headerFormatter[header] = formatter;
0338     }
0339     QSharedPointer<KTextTemplate::FileSystemTemplateLoader> templateLoader;
0340     KTextTemplate::Engine *const engine;
0341     QMap<QByteArray, QSharedPointer<HeaderFormatter>> headerFormatter;
0342     MessageViewer::HeaderStyleUtil headerStyleUtil;
0343     QColor activeColor;
0344 
0345     int iconSize;
0346 };
0347 
0348 GrantleeHeaderFormatter::GrantleeHeaderFormatter()
0349     : d(new GrantleeHeaderFormatter::GrantleeHeaderFormatterPrivate)
0350 {
0351 }
0352 
0353 GrantleeHeaderFormatter::~GrantleeHeaderFormatter() = default;
0354 
0355 QString GrantleeHeaderFormatter::toHtml(const GrantleeHeaderFormatter::GrantleeHeaderFormatterSettings &settings) const
0356 {
0357     QString errorMessage;
0358     if (!settings.theme.isValid()) {
0359         errorMessage = i18n("Grantlee theme \"%1\" is not valid.", settings.theme.name());
0360         return errorMessage;
0361     }
0362     d->templateLoader->setTemplateDirs(QStringList() << settings.theme.absolutePath());
0363     KTextTemplate::Template headerTemplate = d->engine->loadByName(settings.theme.themeFilename());
0364     if (headerTemplate->error()) {
0365         errorMessage = headerTemplate->errorString();
0366         return errorMessage;
0367     }
0368     return format(settings.theme.absolutePath(),
0369                   headerTemplate,
0370                   settings.theme.displayExtraVariables(),
0371                   settings.isPrinting,
0372                   settings.style,
0373                   settings.message,
0374                   settings.showEmoticons);
0375 }
0376 
0377 QString GrantleeHeaderFormatter::toHtml(const QStringList &displayExtraHeaders,
0378                                         const QString &absolutPath,
0379                                         const QString &filename,
0380                                         const MessageViewer::HeaderStyle *style,
0381                                         KMime::Message *message,
0382                                         bool isPrinting) const
0383 {
0384     d->templateLoader->setTemplateDirs(QStringList() << absolutPath);
0385     KTextTemplate::Template headerTemplate = d->engine->loadByName(filename);
0386     if (headerTemplate->error()) {
0387         return headerTemplate->errorString();
0388     }
0389     return format(absolutPath, headerTemplate, displayExtraHeaders, isPrinting, style, message);
0390 }
0391 
0392 QString GrantleeHeaderFormatter::format(const QString &absolutePath,
0393                                         const KTextTemplate::Template &headerTemplate,
0394                                         const QStringList &displayExtraHeaders,
0395                                         bool isPrinting,
0396                                         const MessageViewer::HeaderStyle *style,
0397                                         KMime::Message *message,
0398                                         bool showEmoticons) const
0399 {
0400     QVariantHash headerObject;
0401     const auto nodeHelper = style->nodeHelper();
0402 
0403     // However, the direction of the message subject within the header is
0404     // determined according to the contents of the subject itself. Since
0405     // the "Re:" and "Fwd:" prefixes would always cause the subject to be
0406     // considered left-to-right, they are ignored when determining its
0407     // direction.
0408     const QString absoluteThemePath = QUrl::fromLocalFile(absolutePath + QLatin1Char('/')).url();
0409     headerObject.insert(QStringLiteral("absoluteThemePath"), absoluteThemePath);
0410     headerObject.insert(QStringLiteral("applicationDir"), QApplication::isRightToLeft() ? QStringLiteral("rtl") : QStringLiteral("ltr"));
0411 
0412     // TODO: use correct subject from nodeHelper->mailHeader
0413     headerObject.insert(QStringLiteral("subjectDir"), d->headerStyleUtil.subjectDirectionString(message));
0414 
0415     QList<QByteArray> defaultHeaders;
0416     defaultHeaders << "to"
0417                    << "reply-To"
0418                    << "cc"
0419                    << "bcc"
0420                    << "from"
0421                    << "sender"
0422                    << "resent-From"
0423                    << "resent-To"
0424                    << "subject"
0425                    << "organization"
0426                    << "list-id"
0427                    << "date"
0428                    << "Message-Id";
0429 
0430     for (const auto &header : std::as_const(defaultHeaders)) {
0431         QSharedPointer<HeaderFormatter> formatter;
0432         if (d->headerFormatter.contains(header)) {
0433             formatter = d->headerFormatter.value(header);
0434         } else {
0435             formatter = QSharedPointer<HeaderFormatter>(new DefaultHeaderFormatter(header));
0436         }
0437         const auto i18nName = formatter->i18nName();
0438         const auto objectName = QString::fromUtf8(header).remove(QLatin1Char('-'));
0439         if (nodeHelper->hasMailHeader(header.constData(), message)) {
0440             const auto value = formatter->format(message, nodeHelper, showEmoticons);
0441             headerObject.insert(objectName, value);
0442         }
0443         if (!i18nName.isEmpty()) {
0444             headerObject.insert(objectName + QStringLiteral("i18n"), i18nName);
0445         }
0446     }
0447 
0448     if (!nodeHelper->hasMailHeader("subject", message)) {
0449         headerObject.insert(QStringLiteral("subject"), i18n("No Subject"));
0450     }
0451 
0452     const QString spamHtml = d->headerStyleUtil.spamStatus(message);
0453     if (!spamHtml.isEmpty()) {
0454         headerObject.insert(QStringLiteral("spamstatusi18n"), i18n("Spam Status:"));
0455         headerObject.insert(QStringLiteral("spamHTML"), spamHtml);
0456     }
0457 
0458     if (!style->vCardName().isEmpty()) {
0459         headerObject.insert(QStringLiteral("vcardname"), style->vCardName());
0460     }
0461 
0462     if (isPrinting) {
0463         // provide a bit more left padding when printing
0464         // kolab/issue3254 (printed mail cut at the left side)
0465         // Use it just for testing if we are in printing mode
0466         headerObject.insert(QStringLiteral("isprinting"), i18n("Printing mode"));
0467         headerObject.insert(QStringLiteral("printmode"), QStringLiteral("printmode"));
0468     } else {
0469         headerObject.insert(QStringLiteral("screenmode"), QStringLiteral("screenmode"));
0470     }
0471 
0472     // colors depend on if it is encapsulated or not
0473     QColor fontColor(Qt::white);
0474     QString linkColor = QStringLiteral("white");
0475 
0476     if (!d->activeColor.isValid()) {
0477         d->activeColor = KColorScheme(QPalette::Active, KColorScheme::Selection).background().color();
0478     }
0479     QColor activeColorDark = d->activeColor.darker(130);
0480     // reverse colors for encapsulated
0481     if (!style->isTopLevel()) {
0482         activeColorDark = d->activeColor.darker(50);
0483         fontColor = QColor(Qt::black);
0484         linkColor = QStringLiteral("black");
0485     }
0486 
0487     // 3D borders
0488     headerObject.insert(QStringLiteral("activecolordark"), activeColorDark.name());
0489     headerObject.insert(QStringLiteral("fontcolor"), fontColor.name());
0490     headerObject.insert(QStringLiteral("linkcolor"), linkColor);
0491 
0492     MessageViewer::HeaderStyleUtil::xfaceSettings xface = d->headerStyleUtil.xface(style, message);
0493     if (!xface.photoURL.isEmpty()) {
0494         headerObject.insert(QStringLiteral("photowidth"), xface.photoWidth);
0495         headerObject.insert(QStringLiteral("photoheight"), xface.photoHeight);
0496         headerObject.insert(QStringLiteral("photourl"), xface.photoURL);
0497     }
0498 
0499     for (QString header : std::as_const(displayExtraHeaders)) {
0500         const QByteArray baHeader = header.toLocal8Bit();
0501         if (auto hrd = message->headerByType(baHeader.constData())) {
0502             // Grantlee doesn't support '-' in variable name => remove it.
0503             header.remove(QLatin1Char('-'));
0504             headerObject.insert(header, hrd->asUnicodeString());
0505         }
0506     }
0507 
0508     headerObject.insert(QStringLiteral("vcardi18n"), i18n("[vcard]"));
0509     headerObject.insert(QStringLiteral("readOnlyMessage"), style->readOnlyMessage());
0510 
0511     const QString attachmentHtml = style->attachmentHtml();
0512     const bool messageHasAttachment = !attachmentHtml.isEmpty();
0513     headerObject.insert(QStringLiteral("hasAttachment"), messageHasAttachment);
0514     headerObject.insert(QStringLiteral("attachmentHtml"), attachmentHtml);
0515     headerObject.insert(QStringLiteral("attachmentI18n"), i18n("Attachments:"));
0516 
0517     if (messageHasAttachment) {
0518         const QString iconPath = MessageViewer::IconNameCache::instance()->iconPath(QStringLiteral("mail-attachment"), KIconLoader::Toolbar);
0519         const QString html =
0520             QStringLiteral("<img height=\"%2\" width=\"%2\" src=\"%1\"></a>").arg(QUrl::fromLocalFile(iconPath).url(), QString::number(d->iconSize));
0521         headerObject.insert(QStringLiteral("attachmentIcon"), html);
0522     }
0523 
0524     const bool messageIsSigned = KMime::isSigned(message);
0525     headerObject.insert(QStringLiteral("messageIsSigned"), messageIsSigned);
0526     if (messageIsSigned) {
0527         const QString iconPath = MessageViewer::IconNameCache::instance()->iconPath(QStringLiteral("mail-signed"), KIconLoader::Toolbar);
0528         const QString html =
0529             QStringLiteral("<img height=\"%2\" width=\"%2\" src=\"%1\"></a>").arg(QUrl::fromLocalFile(iconPath).url(), QString::number(d->iconSize));
0530         headerObject.insert(QStringLiteral("signedIcon"), html);
0531     }
0532 
0533     const bool messageIsEncrypted = KMime::isEncrypted(message);
0534     headerObject.insert(QStringLiteral("messageIsEncrypted"), messageIsEncrypted);
0535     if (messageIsEncrypted) {
0536         const QString iconPath = MessageViewer::IconNameCache::instance()->iconPath(QStringLiteral("mail-encrypted"), KIconLoader::Toolbar);
0537         const QString html =
0538             QStringLiteral("<img height=\"%2\" width=\"%2\" src=\"%1\"></a>").arg(QUrl::fromLocalFile(iconPath).url(), QString::number(d->iconSize));
0539         headerObject.insert(QStringLiteral("encryptedIcon"), html);
0540     }
0541 
0542     const bool messageHasSecurityInfo = messageIsEncrypted || messageIsSigned;
0543     headerObject.insert(QStringLiteral("messageHasSecurityInfo"), messageHasSecurityInfo);
0544     headerObject.insert(QStringLiteral("messageHasSecurityInfoI18n"), i18n("Security:"));
0545 
0546     QVariantHash mapping;
0547     mapping.insert(QStringLiteral("header"), headerObject);
0548     KTextTemplate::Context context(mapping);
0549 
0550     return headerTemplate->render(&context);
0551 }