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("&nbsp;") + i18n("(resent from %1)", StringUtil::emailAddrAsAnchor(resentFrom.data(), StringUtil::DisplayFullAddress))
0096                    : QString())
0097             + (!vCardName().isEmpty()
0098                    ? QStringLiteral("&nbsp;&nbsp;<a href=\"") + vCardName() + QStringLiteral("\">") + i18n("[vCard]") + QStringLiteral("</a>")
0099                    : QString())
0100             + (!message->organization(false)
0101                    ? QString()
0102                    : QStringLiteral("&nbsp;&nbsp;(") + 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>&nbsp;<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 }