File indexing completed on 2025-03-09 04:46:56
0001 /* 0002 SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "fancyheaderstyle.h" 0008 0009 #include <KTextToHTML> 0010 #include <MessageViewer/HeaderStrategy> 0011 #include <MessageViewer/MessageViewerSettings> 0012 #include <MimeTreeParser/NodeHelper> 0013 0014 #include <MessageCore/StringUtil> 0015 0016 #include <KLocalizedString> 0017 0018 #include <QApplication> 0019 0020 using namespace MessageCore; 0021 0022 using namespace MessageViewer; 0023 // 0024 // FancyHeaderStyle: 0025 // Like PlainHeaderStyle, but with slick frames and background colours. 0026 // 0027 0028 FancyHeaderStyle::FancyHeaderStyle() 0029 : HeaderStyle() 0030 { 0031 } 0032 0033 FancyHeaderStyle::~FancyHeaderStyle() = default; 0034 0035 const char *FancyHeaderStyle::name() const 0036 { 0037 return "fancy"; 0038 } 0039 0040 QString FancyHeaderStyle::format(KMime::Message *message) const 0041 { 0042 if (!message) { 0043 return {}; 0044 } 0045 const HeaderStrategy *strategy = headerStrategy(); 0046 // ### from kmreaderwin begin 0047 // The direction of the header is determined according to the direction 0048 // of the application layout. 0049 0050 const QString dir = QApplication::isRightToLeft() ? QStringLiteral("rtl") : QStringLiteral("ltr"); 0051 QString headerStr = QStringLiteral("<div class=\"fancy header\" dir=\"%1\">\n").arg(dir); 0052 0053 // However, the direction of the message subject within the header is 0054 // determined according to the contents of the subject itself. Since 0055 // the "Re:" and "Fwd:" prefixes would always cause the subject to be 0056 // considered left-to-right, they are ignored when determining its 0057 // direction. 0058 0059 const QString subjectDir = mHeaderStyleUtil.subjectDirectionString(message); 0060 0061 // Spam header display. 0062 // If the spamSpamStatus config value is true then we look for headers 0063 // from a few spam filters and try to create visually meaningful graphics 0064 // out of the spam scores. 0065 0066 const QString spamHTML = mHeaderStyleUtil.spamStatus(message); 0067 0068 QString userHTML; 0069 MessageViewer::HeaderStyleUtil::xfaceSettings xface = mHeaderStyleUtil.xface(this, message); 0070 if (!xface.photoURL.isEmpty()) { 0071 // qCDebug(MESSAGEVIEWER_LOG) << "Got a photo:" << xface.photoURL; 0072 userHTML = QStringLiteral("<img src=\"%1\" width=\"%2\" height=\"%3\"/>").arg(xface.photoURL).arg(xface.photoWidth).arg(xface.photoHeight); 0073 userHTML = QLatin1StringView("<div class=\"senderpic\">") + userHTML + QLatin1StringView("</div>"); 0074 } 0075 0076 // the subject line and box below for details 0077 if (strategy->showHeader(QStringLiteral("subject"))) { 0078 const KTextToHTML::Options flags = KTextToHTML::PreserveSpaces | KTextToHTML::ReplaceSmileys; 0079 0080 headerStr += QStringLiteral("<div dir=\"%1\">%2</div>\n").arg(subjectDir, mHeaderStyleUtil.subjectString(message, flags)); 0081 } 0082 headerStr += QLatin1StringView("<table class=\"outer\"><tr><td width=\"100%\"><table>\n"); 0083 // headerStr += "<table>\n"; 0084 // from line 0085 // the mailto: URLs can contain %3 etc., therefore usage of multiple 0086 // QString::arg is not possible 0087 if (strategy->showHeader(QStringLiteral("from"))) { 0088 const auto resentFrom = mHeaderStyleUtil.resentFromList(message); 0089 headerStr += QStringLiteral( 0090 "<tr><th>%1</th>\n" 0091 "<td>") 0092 .arg(i18n("From: ")) 0093 + StringUtil::emailAddrAsAnchor(message->from(), StringUtil::DisplayFullAddress) 0094 + (message->headerByType("Resent-From") 0095 ? QStringLiteral(" ") + i18n("(resent from %1)", StringUtil::emailAddrAsAnchor(resentFrom.data(), StringUtil::DisplayFullAddress)) 0096 : QString()) 0097 + (!vCardName().isEmpty() 0098 ? QStringLiteral(" <a href=\"") + vCardName() + QStringLiteral("\">") + i18n("[vCard]") + QStringLiteral("</a>") 0099 : QString()) 0100 + (!message->organization(false) 0101 ? QString() 0102 : QStringLiteral(" (") + mHeaderStyleUtil.strToHtml(message->organization()->asUnicodeString()) + QLatin1Char(')')) 0103 + QStringLiteral("</td></tr>\n"); 0104 } 0105 // to line 0106 if (strategy->showHeader(QStringLiteral("to"))) { 0107 const auto resentTo = mHeaderStyleUtil.resentToList(message); 0108 0109 QString to; 0110 if (resentTo.data()) { 0111 to = StringUtil::emailAddrAsAnchor(resentTo.data(), StringUtil::DisplayFullAddress) + QLatin1Char(' ') 0112 + i18n("(receiver was %1)", 0113 StringUtil::emailAddrAsAnchor(message->to(), 0114 StringUtil::DisplayFullAddress, 0115 QString(), 0116 StringUtil::ShowLink, 0117 StringUtil::ExpandableAddresses, 0118 QStringLiteral("FullToAddressList"))); 0119 } else { 0120 to = StringUtil::emailAddrAsAnchor(message->to(), 0121 StringUtil::DisplayFullAddress, 0122 QString(), 0123 StringUtil::ShowLink, 0124 StringUtil::ExpandableAddresses, 0125 QStringLiteral("FullToAddressList")); 0126 } 0127 0128 headerStr.append(QStringLiteral("<tr><th>%1</th>\n" 0129 "<td>%2</td></tr>\n") 0130 .arg(i18nc("To-field of the mail header.", "To: "), to)); 0131 } 0132 0133 // cc line, if an 0134 if (strategy->showHeader(QStringLiteral("cc")) && message->cc(false)) { 0135 const QString str = StringUtil::emailAddrAsAnchor(message->cc(), 0136 StringUtil::DisplayFullAddress, 0137 QString(), 0138 StringUtil::ShowLink, 0139 StringUtil::ExpandableAddresses, 0140 QStringLiteral("FullCcAddressList")); 0141 if (!str.isEmpty()) { 0142 headerStr.append(QStringLiteral("<tr><th>%1</th>\n" 0143 "<td>%2</td></tr>\n") 0144 .arg(i18n("CC: "), str)); 0145 } 0146 } 0147 0148 // Bcc line, if any 0149 if (strategy->showHeader(QStringLiteral("bcc")) && message->bcc(false)) { 0150 const QString str = StringUtil::emailAddrAsAnchor(message->bcc(), StringUtil::DisplayFullAddress); 0151 if (!str.isEmpty()) { 0152 headerStr.append(QStringLiteral("<tr><th>%1</th>\n" 0153 "<td>%2</td></tr>\n") 0154 .arg(i18n("BCC: "), str)); 0155 } 0156 } 0157 0158 if (strategy->showHeader(QStringLiteral("date"))) { 0159 headerStr.append(QStringLiteral("<tr><th>%1</th>\n" 0160 "<td dir=\"%2\">%3</td></tr>\n") 0161 .arg(i18n("Date: "), 0162 mHeaderStyleUtil.directionOf(HeaderStyleUtil::dateStr(message->date()->dateTime())), 0163 mHeaderStyleUtil.strToHtml(HeaderStyleUtil::dateString(message, /* short = */ MessageViewer::HeaderStyleUtil::CustomDate)))); 0164 } 0165 0166 if (strategy->showHeader(QStringLiteral("x-bugzilla-url"))) { 0167 if (message->hasHeader("X-Bugzilla-URL")) { 0168 QString product; 0169 if (auto hrd = message->headerByType("X-Bugzilla-Product")) { 0170 product = hrd->asUnicodeString(); 0171 } 0172 QString component; 0173 if (auto hrd = message->headerByType("X-Bugzilla-Component")) { 0174 component = hrd->asUnicodeString(); 0175 } 0176 QString status; 0177 if (auto hrd = message->headerByType("X-Bugzilla-Status")) { 0178 status = hrd->asUnicodeString(); 0179 } 0180 headerStr.append( 0181 QStringLiteral("<tr><th>%1</th>\n" 0182 "<td>%2/%3, <strong>%4</strong></td></tr>\n") 0183 .arg(i18n("Bugzilla: "), mHeaderStyleUtil.strToHtml(product), mHeaderStyleUtil.strToHtml(component), mHeaderStyleUtil.strToHtml(status))); 0184 } 0185 } 0186 0187 if (strategy->showHeader(QStringLiteral("disposition-notification-to"))) { 0188 if (auto hrd = message->headerByType("Disposition-Notification-To")) { 0189 const QString to = hrd->asUnicodeString(); 0190 headerStr.append(QStringLiteral("<tr><th>%1</th>\n" 0191 "<td>%2</tr>\n") 0192 .arg(i18n("MDN To: "), mHeaderStyleUtil.strToHtml(to))); 0193 } 0194 } 0195 0196 if (!spamHTML.isEmpty()) { 0197 headerStr.append( 0198 QStringLiteral( 0199 "<tr><td colspan=\"2\"><div class=\"spamheader\" dir=\"%1\"><b>%2</b> <span style=\"padding-left: 20px;\">%3</span></div></td></tr>\n") 0200 .arg(subjectDir, i18n("Spam Status:"), spamHTML)); 0201 } 0202 0203 headerStr.append(QStringLiteral("<tr><td colspan=\"2\"><div>%1</div></td></tr>").arg(attachmentHtml())); 0204 0205 headerStr.append(QStringLiteral("</table></td><td align=\"center\">%1</td></tr></table>\n").arg(userHTML)); 0206 0207 headerStr += QLatin1StringView("</div>\n\n"); 0208 return headerStr; 0209 }