File indexing completed on 2024-06-23 05:19:21

0001 /*
0002   SPDX-FileCopyrightText: 2016 Sandro Knauß <sknauss@kde.org>
0003 
0004   SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "util.h"
0008 
0009 #include "mimetreeparser_debug.h"
0010 
0011 #include "nodehelper.h"
0012 
0013 #include <KMime/Content>
0014 
0015 #include <QMimeDatabase>
0016 
0017 using namespace MimeTreeParser;
0018 using namespace MimeTreeParser::Util;
0019 
0020 bool MimeTreeParser::Util::isTypeBlacklisted(KMime::Content *node)
0021 {
0022     const auto contentType = node->contentType(); // Create
0023     const QByteArray mediaTypeLower = contentType->mediaType().toLower();
0024     bool typeBlacklisted = mediaTypeLower == QByteArrayLiteral("multipart");
0025     if (!typeBlacklisted) {
0026         typeBlacklisted = KMime::isCryptoPart(node);
0027     }
0028     typeBlacklisted = typeBlacklisted || node == node->topLevel();
0029     const bool firstTextChildOfEncapsulatedMsg = mediaTypeLower == "text" && contentType->subType().toLower() == "plain" && node->parent()
0030         && node->parent()->contentType()->mediaType().toLower() == "message";
0031     return typeBlacklisted || firstTextChildOfEncapsulatedMsg;
0032 }
0033 
0034 QString MimeTreeParser::Util::labelForContent(KMime::Content *node)
0035 {
0036     const QString name = node->contentType()->name();
0037     QString label = name.isEmpty() ? NodeHelper::fileName(node) : name;
0038     if (label.isEmpty()) {
0039         label = node->contentDescription()->asUnicodeString();
0040     }
0041     return label;
0042 }
0043 
0044 QMimeType MimeTreeParser::Util::mimetype(const QString &name)
0045 {
0046     QMimeDatabase db;
0047     // consider the filename if mimetype cannot be found by content-type
0048     const auto mimeTypes = db.mimeTypesForFileName(name);
0049     for (const auto &mt : mimeTypes) {
0050         if (mt.name() != QLatin1StringView("application/octet-stream")) {
0051             return mt;
0052         }
0053     }
0054 
0055     // consider the attachment's contents if neither the Content-Type header
0056     // nor the filename give us a clue
0057     return db.mimeTypeForFile(name);
0058 }
0059 
0060 QString MimeTreeParser::Util::iconNameForMimetype(const QString &mimeType, const QString &fallbackFileName1, const QString &fallbackFileName2)
0061 {
0062     QString fileName;
0063     QString tMimeType = mimeType;
0064 
0065     // convert non-registered types to registered types
0066     if (mimeType == QLatin1StringView("application/x-vnd.kolab.contact")) {
0067         tMimeType = QStringLiteral("text/x-vcard");
0068     } else if (mimeType == QLatin1StringView("application/x-vnd.kolab.event")) {
0069         tMimeType = QStringLiteral("application/x-vnd.akonadi.calendar.event");
0070     } else if (mimeType == QLatin1StringView("application/x-vnd.kolab.task")) {
0071         tMimeType = QStringLiteral("application/x-vnd.akonadi.calendar.todo");
0072     } else if (mimeType == QLatin1StringView("application/x-vnd.kolab.journal")) {
0073         tMimeType = QStringLiteral("application/x-vnd.akonadi.calendar.journal");
0074     } else if (mimeType == QLatin1StringView("application/x-vnd.kolab.note")) {
0075         tMimeType = QStringLiteral("application/x-vnd.akonadi.note");
0076     } else if (mimeType == QLatin1StringView("image/jpg")) {
0077         tMimeType = QStringLiteral("image/jpeg");
0078     } else if (mimeType == QLatin1StringView("application/x-pkcs7-signature")) {
0079         tMimeType = QStringLiteral("application/pkcs7-signature");
0080     } else if (mimeType == QLatin1StringView("message/global")) {
0081         tMimeType = QStringLiteral("message/rfc822");
0082     } else if (mimeType == QLatin1StringView("text/x-moz-deleted")) {
0083         // Avoid debug warning about unknown mimetype
0084         // Bug: 468801
0085         // We need to show unknown icon
0086         tMimeType.clear();
0087         fileName = QStringLiteral("unknown");
0088     }
0089     QMimeDatabase mimeDb;
0090     if (!tMimeType.isEmpty()) {
0091         auto mime = mimeDb.mimeTypeForName(tMimeType);
0092         if (mime.isValid()) {
0093             fileName = mime.iconName();
0094         } else {
0095             fileName = QStringLiteral("unknown");
0096             if (!tMimeType.isEmpty()) {
0097                 qCWarning(MIMETREEPARSER_LOG) << "unknown mimetype" << tMimeType;
0098             }
0099         }
0100     }
0101     // WorkAround for #199083
0102     if (fileName == QLatin1StringView("text-vcard")) {
0103         fileName = QStringLiteral("text-x-vcard");
0104     }
0105 
0106     if (fileName.isEmpty()) {
0107         fileName = fallbackFileName1;
0108         if (fileName.isEmpty()) {
0109             fileName = fallbackFileName2;
0110         }
0111         if (!fileName.isEmpty()) {
0112             fileName = mimeDb.mimeTypeForFile(QLatin1StringView("/tmp/") + fileName).iconName();
0113         }
0114     }
0115 
0116     return fileName;
0117 }
0118 
0119 QString MimeTreeParser::Util::iconNameForContent(KMime::Content *node)
0120 {
0121     if (!node) {
0122         return {};
0123     }
0124 
0125     auto ct = node->contentType(); // Create
0126     QByteArray mimeType = ct->mimeType();
0127     if (mimeType.isNull() || mimeType == "application/octet-stream") {
0128         const QString fileName = node->contentDisposition()->filename();
0129         if (!fileName.isEmpty()) {
0130             const QString mime = MimeTreeParser::Util::mimetype(fileName).name();
0131             mimeType = mime.toLatin1();
0132         }
0133     }
0134     mimeType = mimeType.toLower();
0135     return MimeTreeParser::Util::iconNameForMimetype(QLatin1StringView(mimeType), node->contentDisposition()->filename(), ct->name());
0136 }
0137 
0138 QString MimeTreeParser::Util::htmlModeToString(HtmlMode mode)
0139 {
0140     switch (mode) {
0141     case Normal: ///< A normal plaintext message, non-multipart
0142         return QStringLiteral("Normal PlainText Message, non-multipart");
0143     case Html: ///< A HTML message, non-multipart
0144         return QStringLiteral("A HTML message, non-multipart");
0145     case MultipartPlain: ///< A multipart/alternative message, the plain text part is currently displayed
0146         return QStringLiteral("A multipart/alternative message, the plain text part is currently displayed");
0147     case MultipartHtml: ///< A multipart/alternative message, the HTML part is currently displayed
0148         return QStringLiteral("A multipart/alternative message, the HTML part is currently displayed");
0149     case MultipartIcal: ///< A multipart/alternative message, the ICal part is currently displayed
0150         return QStringLiteral("A multipart/alternative message, the ICal part is currently displayed");
0151     }
0152     return {};
0153 }