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 }