File indexing completed on 2024-06-16 05:00:15

0001 /*
0002   SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
0003   SPDX-FileCopyrightText: 2009 Andras Mantia <andras@kdab.net>
0004 
0005   SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #pragma once
0009 
0010 #include "mimetreeparser_export.h"
0011 
0012 #include "mimetreeparser/enums.h"
0013 #include "mimetreeparser/partmetadata.h"
0014 
0015 #include <KMime/Headers>
0016 #include <KMime/Message>
0017 
0018 #include <QList>
0019 #include <QMap>
0020 #include <QPointer>
0021 #include <QSet>
0022 
0023 class QUrl;
0024 
0025 namespace MimeTreeParser
0026 {
0027 class AttachmentTemporaryFilesDirs;
0028 class MessagePart;
0029 using MessagePartPtr = QSharedPointer<MessagePart>;
0030 namespace Interface
0031 {
0032 class BodyPartMemento;
0033 }
0034 }
0035 
0036 namespace MimeTreeParser
0037 {
0038 /**
0039  * @author Andras Mantia <andras@kdab.net>
0040  */
0041 class MIMETREEPARSER_EXPORT NodeHelper : public QObject
0042 {
0043     Q_OBJECT
0044 public:
0045     NodeHelper();
0046 
0047     ~NodeHelper() override;
0048 
0049     void setNodeProcessed(KMime::Content *node, bool recurse);
0050     void setNodeUnprocessed(KMime::Content *node, bool recurse);
0051     [[nodiscard]] bool nodeProcessed(KMime::Content *node) const;
0052     void clear();
0053     void forceCleanTempFiles();
0054 
0055     void setEncryptionState(const KMime::Content *node, const KMMsgEncryptionState state);
0056     [[nodiscard]] KMMsgEncryptionState encryptionState(const KMime::Content *node) const;
0057 
0058     void setSignatureState(const KMime::Content *node, const KMMsgSignatureState state);
0059     [[nodiscard]] KMMsgSignatureState signatureState(const KMime::Content *node) const;
0060 
0061     [[nodiscard]] KMMsgSignatureState overallSignatureState(KMime::Content *node) const;
0062     [[nodiscard]] KMMsgEncryptionState overallEncryptionState(KMime::Content *node) const;
0063 
0064     void setPartMetaData(KMime::Content *node, const PartMetaData &metaData);
0065     [[nodiscard]] PartMetaData partMetaData(KMime::Content *node);
0066 
0067     /**
0068      *  Set the 'Content-Type' by mime-magic from the contents of the body.
0069      *  If autoDecode is true the decoded body will be used for mime type
0070      *  determination (this does not change the body itself).
0071      */
0072     static void magicSetType(KMime::Content *node, bool autoDecode = true);
0073 
0074     void clearOverrideHeaders();
0075     void registerOverrideHeader(KMime::Content *message, MessagePartPtr);
0076     [[nodiscard]] bool hasMailHeader(const char *header, const KMime::Content *message) const;
0077     QList<MessagePartPtr> messagePartsOfMailHeader(const char *header, const KMime::Content *message) const;
0078     KMime::Headers::Base const *mailHeaderAsBase(const char *header, const KMime::Content *message) const;
0079     QSharedPointer<KMime::Headers::Generics::AddressList> mailHeaderAsAddressList(const char *header, const KMime::Content *message) const;
0080     QList<KMime::Headers::Base *> headers(const char *header, const KMime::Content *message);
0081     [[nodiscard]] QDateTime dateHeader(KMime::Content *message) const;
0082 
0083     /** Attach an extra node to an existing node */
0084     void attachExtraContent(KMime::Content *topLevelNode, KMime::Content *content);
0085 
0086     void cleanExtraContent(KMime::Content *topLevelNode);
0087 
0088     /** Get the extra nodes attached to the @param topLevelNode and all sub-nodes of @param topLevelNode */
0089     [[nodiscard]] QList<KMime::Content *> extraContents(KMime::Content *topLevelNode) const;
0090 
0091     /** Return a modified message (node tree) starting from @param topLevelNode that has the original nodes and the extra nodes.
0092         The caller has the responsibility to delete the new message.
0093      */
0094     [[nodiscard]] KMime::Message *messageWithExtraContent(KMime::Content *topLevelNode);
0095 
0096     /** Get a codec suitable for this message part */
0097     QByteArray codecName(KMime::Content *node) const;
0098 
0099     /** Set the charset the user selected for the message to display */
0100     void setOverrideCodec(KMime::Content *node, const QByteArray &codec);
0101 
0102     Interface::BodyPartMemento *bodyPartMemento(KMime::Content *node, const QByteArray &which) const;
0103 
0104     void setBodyPartMemento(KMime::Content *node, const QByteArray &which, Interface::BodyPartMemento *memento);
0105 
0106     // A flag to remember if the node was embedded. This is useful for attachment nodes, the reader
0107     // needs to know if they were displayed inline or not.
0108     [[nodiscard]] bool isNodeDisplayedEmbedded(KMime::Content *node) const;
0109     void setNodeDisplayedEmbedded(KMime::Content *node, bool displayedEmbedded);
0110 
0111     // Same as above, but this time determines if the node was hidden or not
0112     [[nodiscard]] bool isNodeDisplayedHidden(KMime::Content *node) const;
0113     void setNodeDisplayedHidden(KMime::Content *node, bool displayedHidden);
0114 
0115     /**
0116      * Writes the given message part to a temporary file and returns the
0117      * name of this file or QString() if writing failed.
0118      */
0119     QString writeNodeToTempFile(KMime::Content *node);
0120 
0121     [[nodiscard]] QString writeFileToTempFile(KMime::Content *node, const QString &filename);
0122 
0123     /**
0124      * Returns the temporary file path and name where this node was saved, or an empty url
0125      * if it wasn't saved yet with writeNodeToTempFile()
0126      */
0127     [[nodiscard]] QUrl tempFileUrlFromNode(const KMime::Content *node);
0128 
0129     /**
0130      * Creates a temporary dir for saving attachments, etc.
0131      * Will be automatically deleted when another message is viewed.
0132      * @param param Optional part of the directory name.
0133      */
0134     [[nodiscard]] QString createTempDir(const QString &param = QString());
0135 
0136     /**
0137      * Cleanup the attachment temp files
0138      */
0139     void removeTempFiles();
0140 
0141     /**
0142      * Add a file to the list of managed temporary files
0143      */
0144     void addTempFile(const QString &file);
0145 
0146     // Get a href in the form attachment:<nodeId>?place=<place>, used by ObjectTreeParser and
0147     // UrlHandlerManager.
0148     [[nodiscard]] QString asHREF(const KMime::Content *node, const QString &place) const;
0149     KMime::Content *fromHREF(const KMime::Message::Ptr &mMessage, const QUrl &href) const;
0150 
0151     // Overload which creates a URL without the query part. Used by MessagePart::makeLink.
0152     [[nodiscard]] QString asHREF(const KMime::Content *node) const;
0153 
0154     /**
0155      * @return true if this node is a child or an encapsulated message
0156      */
0157     [[nodiscard]] static bool isInEncapsulatedMessage(KMime::Content *node);
0158 
0159     /**
0160      * Returns the charset for the given node. If no charset is specified
0161      * for the node, the defaultCharset() is returned.
0162      */
0163     [[nodiscard]] static QByteArray charset(KMime::Content *node);
0164 
0165     /**
0166      * Returns a usable filename for a node, that can be the filename from the
0167      * content disposition header, or if that one is empty, the name from the
0168      * content type header.
0169      */
0170     [[nodiscard]] static QString fileName(const KMime::Content *node);
0171 
0172     /**
0173      * Fixes an encoding received by a KDE function and returns the proper,
0174      * MIME-compliant encoding name instead.
0175      * @see encodingForName
0176      */
0177     [[nodiscard]] static QString fixEncoding(const QString &encoding); // TODO(Andras) move to a utility class?
0178 
0179     /**
0180      * Drop-in replacement for KCharsets::encodingForName(). The problem with
0181      * the KCharsets function is that it returns "human-readable" encoding names
0182      * like "ISO 8859-15" instead of valid encoding names like "ISO-8859-15".
0183      * This function fixes this by replacing whitespace with a hyphen.
0184      */
0185     [[nodiscard]] static QString encodingForName(const QString &descriptiveName); // TODO(Andras) move to a utility class?
0186 
0187     /**
0188      * Return a list of the supported encodings
0189      * @param usAscii if true, US-Ascii encoding will be prepended to the list.
0190      */
0191     [[nodiscard]] static QStringList supportedEncodings(bool usAscii); // TODO(Andras) move to a utility class?
0192 
0193     [[nodiscard]] QString fromAsString(KMime::Content *node) const;
0194 
0195     KMime::Content *decryptedNodeForContent(KMime::Content *content) const;
0196 
0197     /**
0198      * This function returns the unencrypted message that is based on @p originalMessage.
0199      * All encrypted MIME parts are removed and replaced by their decrypted plain-text versions.
0200      * Encrypted parts that are within signed parts are not replaced, since that would invalidate
0201      * the signature.
0202      *
0203      * This only works if the message was run through ObjectTreeParser::parseObjectTree() with the
0204      * current NodeHelper before, because parseObjectTree() actually decrypts the message and stores
0205      * the decrypted nodes by calling attachExtraContent().
0206      *
0207      * @return the unencrypted message or an invalid pointer if the original message didn't contain
0208      *         a part that needed to be modified.
0209      */
0210     KMime::Message::Ptr unencryptedMessage(const KMime::Message::Ptr &originalMessage);
0211 
0212     /**
0213      * Returns a list of attachments of attached extra content nodes.
0214      * This is mainly useful is order to get attachments of encrypted messages.
0215      * Note that this does not include attachments from the primary node tree.
0216      * @see KMime::Content::attachments().
0217      */
0218     [[nodiscard]] QList<KMime::Content *> attachmentsOfExtraContents() const;
0219 
0220     [[nodiscard]] QString extractAttachmentIndex(const QString &path) const;
0221 Q_SIGNALS:
0222     void update(MimeTreeParser::UpdateMode);
0223 
0224 private:
0225     Q_DISABLE_COPY(NodeHelper)
0226     bool unencryptedMessage_helper(KMime::Content *node, QByteArray &resultingData, bool addHeaders, int recursionLevel = 1);
0227 
0228     MIMETREEPARSER_NO_EXPORT void mergeExtraNodes(KMime::Content *node);
0229     MIMETREEPARSER_NO_EXPORT void cleanFromExtraNodes(KMime::Content *node);
0230 
0231     /** Creates a persistent index string that bridges the gap between the
0232         permanent nodes and the temporary ones.
0233 
0234         Used internally for robust indexing.
0235     **/
0236     [[nodiscard]] QString persistentIndex(const KMime::Content *node) const;
0237 
0238     /** Translates the persistentIndex into a node back
0239 
0240         node: any node of the actually message to what the persistentIndex is interpreded
0241     **/
0242     KMime::Content *contentFromIndex(KMime::Content *node, const QString &persistentIndex) const;
0243 
0244 private:
0245     QList<KMime::Content *> mProcessedNodes;
0246     QList<KMime::Content *> mNodesUnderProcess;
0247     QMap<const KMime::Content *, KMMsgEncryptionState> mEncryptionState;
0248     QMap<const KMime::Content *, KMMsgSignatureState> mSignatureState;
0249     QSet<KMime::Content *> mDisplayEmbeddedNodes;
0250     QSet<KMime::Content *> mDisplayHiddenNodes;
0251     QMap<KMime::Content *, QByteArray> mOverrideCodecs;
0252     QMap<QString, QMap<QByteArray, Interface::BodyPartMemento *>> mBodyPartMementoMap;
0253     QMap<KMime::Content *, PartMetaData> mPartMetaDatas;
0254     QMap<KMime::Message::Content *, QList<KMime::Content *>> mExtraContents;
0255     QPointer<AttachmentTemporaryFilesDirs> mAttachmentFilesDir;
0256     QMap<const KMime::Content *, QList<MessagePartPtr>> mHeaderOverwrite;
0257     QList<QPointer<AttachmentTemporaryFilesDirs>> mListAttachmentTemporaryDirs;
0258     friend class NodeHelperTest;
0259 };
0260 }