File indexing completed on 2024-05-12 05:17:13

0001 /*
0002     SPDX-FileCopyrightText: 2009 Kevin Ottens <ervin@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include "kimap_export.h"
0010 
0011 #include "imapset.h"
0012 #include "job.h"
0013 
0014 #include <KMime/Content>
0015 #include <KMime/KMimeMessage>
0016 
0017 #include <tuple>
0018 
0019 namespace KIMAP
0020 {
0021 class Session;
0022 struct Response;
0023 class FetchJobPrivate;
0024 
0025 using ContentPtr = QSharedPointer<KMime::Content>;
0026 using MessageParts = QMap<QByteArray, ContentPtr>;
0027 
0028 using MessagePtr = QSharedPointer<KMime::Message>;
0029 using MessageFlags = QList<QByteArray>;
0030 
0031 using MessageAttribute = QPair<QByteArray, QVariant>;
0032 
0033 struct Message {
0034     inline bool operator==(const Message &other) const
0035     {
0036         return std::tie(uid, size, flags, attributes, parts, message)
0037             == std::tie(other.uid, other.size, other.flags, other.attributes, other.parts, other.message);
0038     }
0039 
0040     qint64 uid = -1;
0041     qint64 size = 0;
0042     MessageFlags flags;
0043     QMap<QByteArray, QVariant> attributes;
0044     MessageParts parts;
0045     MessagePtr message;
0046 };
0047 
0048 /**
0049  * Fetch message data from the server
0050  *
0051  * All data is returned using the signals, so you need to connect to
0052  * the relevant signal (or all of them) before starting the job.
0053  *
0054  * This job will always use BODY.PEEK rather than BODY to fetch message
0055  * content, so it will not set the \Seen flag.
0056  *
0057  * This job can only be run when the session is in the selected state.
0058  */
0059 class KIMAP_EXPORT FetchJob : public Job
0060 {
0061     Q_OBJECT
0062     Q_DECLARE_PRIVATE(FetchJob)
0063 
0064     friend class SessionPrivate;
0065 
0066 public:
0067     /**
0068      * Used to indicate what message data should be fetched.
0069      *
0070      * This doesn't provide the same fine-grained control over
0071      * what is fetched that the IMAP FETCH command normally
0072      * does, but the common cases are catered for.
0073      */
0074     class KIMAP_EXPORT FetchScope
0075     {
0076     public:
0077         FetchScope();
0078 
0079         /**
0080          * Used to indicate what part of the message should be fetched.
0081          */
0082         enum Mode {
0083             /**
0084              * Fetch RFC-2822 or MIME message headers.
0085              *
0086              * To fetch MIME headers for a MIME part, populate the @p parts field.
0087              *
0088              * If the RFC-2822 headers are requested (so @p parts is empty), the
0089              * returned information is:
0090              * - To, From, Message-id, References In-Reply-To, Subject and Date headers
0091              * - The message size (in octets)
0092              * - The internal date of the message
0093              * - The message flags
0094              * - The message UID
0095              */
0096             Headers,
0097             /**
0098              * Fetch the message flags (the UID is also fetched)
0099              */
0100             Flags,
0101             /**
0102              * Fetch the MIME message body structure (the UID is also fetched)
0103              */
0104             Structure,
0105             /**
0106              * Fetch the message content (the UID is also fetched)
0107              *
0108              * To fetch only certain MIME parts (see Structure), populate the
0109              * @p parts field.
0110              */
0111             Content,
0112             /**
0113              * Fetch the complete message.
0114              */
0115             Full,
0116             /**
0117              * Fetch the message MIME headers and the content of parts specified in the @p parts
0118              * field.
0119              *
0120              * If @p parts is empty, this mode will return the full message, just like
0121              * FetchScope::Content
0122              *
0123              * Use case:
0124              * -# Start a FetchJob with the FetchScope::Structure mode to retrieve the structure
0125              *    of the message.
0126              * -# Parse the structure to identify the parts that are interesting (ie: probably
0127              *    everything but attachments).
0128              * -# Start another FetchJob with FetchScope::HeaderAndContent to fetch those parts.
0129              * -# At the request of the user, you can repeat the step above to fetch the attachments.
0130              *
0131              * @since 4.7
0132              */
0133             HeaderAndContent,
0134 
0135             /**
0136              * Fetch message size (in octets), internal date of the message, flags, UID
0137              * and all RFC822 headers.
0138              *
0139              * The @p parts field is ignored when using this scope
0140              *
0141              * @since 4.12
0142              */
0143             FullHeaders
0144         };
0145 
0146         /**
0147          * Specify which message parts to operate on.
0148          *
0149          * This refers to multipart-MIME message parts or MIME-IMB encapsulated
0150          * message parts.
0151          *
0152          * Note that this is ignored unless @p mode is Headers or Content.
0153          *
0154          * If @p mode is Headers, this sets the parts to get the MIME headers
0155          * for.  If this list is empty, the headers for the whole message
0156          * (the RFC-2822 headers) are fetched.
0157          *
0158          * If @p mode is Content, this sets the parts to fetch.  Parts are
0159          * fetched wholesale.  If this list is empty, the whole message body
0160          * is fetched (all MIME parts together).
0161          */
0162         QList<QByteArray> parts;
0163         /**
0164          * Specify what message data should be fetched.
0165          */
0166         Mode mode = Content;
0167 
0168         /**
0169          * Specify to fetch only items with mod-sequence higher then @p changedSince.
0170          *
0171          * The server must have CONDSTORE capability (RFC4551).
0172          *
0173          * Default value is 0 (ignored).
0174          *
0175          * @since 4.12
0176          */
0177         quint64 changedSince = 0;
0178 
0179         /**
0180          * Specify whether QRESYNC is supported and should be used.
0181          *
0182          * When enabled, the @p changedSince parameter must be specified as
0183          * well. The server will then also return list of messages that have
0184          * been deleted from the mailbox since the specified modification sequence.
0185          *
0186          * The server must have QRESYNC capability (RFC5162) and it must have
0187          * explicitly been enabled via ENABLE command (see @EnableJob).
0188          *
0189          * QRESYNC can only be used in UID FETCH (@see setUidBased())
0190          *
0191          * @since 5.16
0192          */
0193         bool qresync = false;
0194     };
0195 
0196     explicit FetchJob(Session *session);
0197     ~FetchJob() override = default;
0198 
0199     /**
0200      * Set which messages to fetch data for.
0201      *
0202      * If sequence numbers are given, isUidBased() should be false.  If UIDs
0203      * are given, isUidBased() should be true.
0204      *
0205      * @param set  the sequence numbers or UIDs of the messages to fetch data for
0206      */
0207     void setSequenceSet(const ImapSet &set);
0208     /**
0209      * The messages that will be fetched.
0210      */
0211     ImapSet sequenceSet() const;
0212 
0213     /**
0214      * Set how the sequence set should be interpreted.
0215      *
0216      * @param uidBased  if @c true the argument to setSequenceSet will be
0217      *                  interpreted as UIDs, if @c false it will be interpreted
0218      *                  as sequence numbers
0219      */
0220     void setUidBased(bool uidBased);
0221     /**
0222      * How to interpret the sequence set.
0223      *
0224      * @return  if @c true the result of sequenceSet() should be
0225      *          interpreted as UIDs, if @c false it should be interpreted
0226      *          as sequence numbers
0227      */
0228     [[nodiscard]] bool isUidBased() const;
0229 
0230     /**
0231      * Sets what data should be fetched.
0232      *
0233      * The default scope is FetchScope::Content (all content parts).
0234      *
0235      * @param scope  a FetchScope object describing what data
0236      *               should be fetched
0237      */
0238     void setScope(const FetchScope &scope);
0239     /**
0240      * Specifies what data will be fetched.
0241      */
0242     [[nodiscard]] FetchScope scope() const;
0243 
0244     // TODO: KF6: Move this to FetchScope
0245     /**
0246      * Enables retrieving of Gmail-specific extensions
0247      *
0248      * The FETCH response will contain X-GM-MSGID, X-GM-THRID and X-GM-LABELS
0249      *
0250      * Do NOT enable this, unless talking to Gmail servers, otherwise the
0251      * request may fail.
0252      *
0253      * @param enabled Whether the Gmail support should be enabled
0254      * @since 4.14
0255      */
0256     void setGmailExtensionsEnabled(bool enabled);
0257 
0258     /**
0259      * Returns whether Gmail support is enabled
0260      *
0261      * @since 4.14
0262      * @see setGmailExtensionsEnabled()
0263      */
0264     bool setGmailExtensionsEnabled() const;
0265 
0266     /**
0267      * Returns the name of the mailbox the fetch job is executed on.
0268      *
0269      * Can only be accessed after the job is actually started, before that
0270      * returns an empty string.
0271      *
0272      * @since 5.6
0273      */
0274     [[nodiscard]] QString mailBox() const;
0275 
0276 Q_SIGNALS:
0277     /**
0278      * Provides header and message results.
0279      *
0280      * This signal will be emitted if the requested scope mode
0281      * was FetchScope::Full, FetchScope::Flags or
0282      * FetchScope::Headers with no parts specified
0283      *
0284      * This signal may be emitted any number of times before
0285      * the result() signal is emitted.  The result() signal will
0286      * only be emitted once all results have been reported via
0287      * one of the signals.
0288      *
0289      * Note that, depending on the scope, some of the parameters
0290      * of this signal may be empty maps.
0291      *
0292      * @param mailBox  the name of the mailbox the fetch job was
0293      *                 executed on
0294      * @param uids     a map from message sequence numbers to message UIDs;
0295      *                 this will always be populated
0296      * @param sizes    a map from message sequence numbers to message sizes
0297      *                 (sizes are in octets and refer to the transfer encoding of
0298      *                 the message); populated if the scope is FetchScope::Full or
0299      *                 FetchScope::Headers
0300      * @param flags    a map from message sequence numbers to message flags;
0301      *                 populated if the scope is FetchScope::Flags, FetchScope::Full
0302      *                 of FetchScope::Headers
0303      * @param messages a map from message sequence numbers to message contents (including
0304      *                 headers); populated if the scope is FetchScope::Full,
0305      *                 FetchScope::Headers or FetchScope::Structure
0306      *
0307      * @deprecated Use messagesAvailable() instead.
0308      */
0309     KIMAP_DEPRECATED
0310     void headersReceived(const QString &mailBox,
0311                          const QMap<qint64, qint64> &uids,
0312                          const QMap<qint64, qint64> &sizes,
0313                          const QMap<qint64, KIMAP::MessageFlags> &flags,
0314                          const QMap<qint64, KIMAP::MessagePtr> &messages);
0315 
0316     /**
0317      * An overloaded version of headersReceived(), which includes additional attribute
0318      * specified in the FETCH response, but that don't belong to actual content of the
0319      * message.
0320      *
0321      * @param mailBox  the name of the mailbox the fetch job was
0322      *                 executed on
0323      * @param uids     a map from message sequence numbers to message UIDs;
0324      *                 this will always be populated
0325      * @param attrs    a map from message sequence numbers to a pair of attribute
0326      *                 name and value
0327      * @param sizes    a map from message sequence numbers to message sizes
0328      *                 (sizes are in octets and refer to the transfer encoding of
0329      *                 the message); populated if the scope is FetchScope::Full or
0330      *                 FetchScope::Headers
0331      * @param flags    a map from message sequence numbers to message flags;
0332      *                 populated if the scope is FetchScope::Flags, FetchScope::Full
0333      *                 of FetchScope::Headers
0334      * @param messages a map from message sequence numbers to message contents (including
0335      *                 headers); populated if the scope is FetchScope::Full,
0336      *                 FetchScope::Headers or FetchScope::Structure
0337      *
0338      * @overload
0339      * @since 4.14
0340      * @deprecated Use messagesAvailable() instead.
0341      */
0342     KIMAP_DEPRECATED
0343     void headersReceived(const QString &mailBox,
0344                          const QMap<qint64, qint64> &uids,
0345                          const QMap<qint64, qint64> &sizes,
0346                          const QMap<qint64, KIMAP::MessageAttribute> &attrs,
0347                          const QMap<qint64, KIMAP::MessageFlags> &flags,
0348                          const QMap<qint64, KIMAP::MessagePtr> &messages);
0349 
0350     /**
0351      * Provides header and message results.
0352      *
0353      * This signal will be emitted if the requested scope mode
0354      * was FetchScope::Content or FetchScope::Headers with no
0355      * parts specified or FetchScope::Structure.
0356      *
0357      * This signal may be emitted any number of times before
0358      * the result() signal is emitted.  The result() signal will
0359      * only be emitted once all results have been reported via
0360      * one of the signals.
0361      *
0362      *
0363      * @param mailBox  the name of the mailbox the fetch job was
0364      *                 executed on
0365      * @param uids     a map from message sequence numbers to message UIDs
0366      * @param messages a map from message sequence numbers to message contents
0367      *
0368      * @deprecated Use messagesAvailable() instead.
0369      */
0370     KIMAP_DEPRECATED
0371     void messagesReceived(const QString &mailBox, const QMap<qint64, qint64> &uids, const QMap<qint64, KIMAP::MessagePtr> &messages);
0372 
0373     /**
0374      * An overloaded version of messagesReceived(), which includes additional attribute
0375      * specified in the FETCH response, but that don't belong to actual content of the
0376      * message.
0377      *
0378      * @param mailBox  the name of the mailbox the fetch job was
0379      *                 executed on
0380      * @param uids     a map from message sequence numbers to message UIDs
0381      * @param attrs    a map from message sequence numbers to pair of attribute
0382      *                 name and it's value
0383      * @param messages a map from message sequence numbers to message contents
0384      *
0385      * @overload
0386      * @since 4.14
0387      *
0388      * @deprecated Use messagesAvailable() instead.
0389      */
0390     KIMAP_DEPRECATED
0391     void messagesReceived(const QString &mailBox,
0392                           const QMap<qint64, qint64> &uids,
0393                           const QMap<qint64, KIMAP::MessageAttribute> &attrs,
0394                           const QMap<qint64, KIMAP::MessagePtr> &messages);
0395     /**
0396      * Provides header and message results.
0397      *
0398      * This signal will be emitted if the requested scope mode
0399      * was FetchScope::Content or FetchScope::Headers with
0400      * specified parts.
0401      *
0402      * This signal may be emitted any number of times before
0403      * the result() signal is emitted.  The result() signal will
0404      * only be emitted once all results have been reported via
0405      * one of the signals.
0406      *
0407      * @param mailBox  the name of the mailbox the fetch job was
0408      *                 executed on
0409      * @param uids     a map from message sequence numbers to message UIDs
0410      * @param parts    a map from message sequence numbers to message part collections
0411      *
0412      * @deprecated Use messagesAvailable() instead.
0413      */
0414     KIMAP_DEPRECATED
0415     void partsReceived(const QString &mailBox, const QMap<qint64, qint64> &uids, const QMap<qint64, KIMAP::MessageParts> &parts);
0416 
0417     /**
0418      * An overloaded version of partsReceived(), which includes additional attribute
0419      * specified in the FETCH response, but that don't belong to actual content of the
0420      * message.
0421      *
0422      * @param mailBox  the name of the mailbox the fetch job was
0423      *                 executed on
0424      * @param uids     a map from message sequence numbers to message UIDs
0425      * @param attrs    a map from message sequence numbers to pair of attribute
0426      * @param parts    a map from message sequence numbers to message part collections
0427      *
0428      * @overload
0429      * @since 4.14
0430      *
0431      * @deprecated Use messagesAvailable() instead.
0432      */
0433     KIMAP_DEPRECATED
0434     void partsReceived(const QString &mailBox,
0435                        const QMap<qint64, qint64> &uids,
0436                        const QMap<qint64, KIMAP::MessageAttribute> &attrs,
0437                        const QMap<qint64, KIMAP::MessageParts> &parts);
0438 
0439     /**
0440      * Provides received messages.
0441      *
0442      * This signal is emitted when some data are received. The signal can be
0443      * emitted multiple times as the messages are being received.
0444      *
0445      * @param messages A map from message sequence number to message. Not all
0446      *                 fields may be populated, depending on the fetch scope.
0447      *
0448      * @since 5.6
0449      */
0450     void messagesAvailable(const QMap<qint64, KIMAP::Message> &messages);
0451 
0452     /**
0453      * Provides vanished messages.
0454      *
0455      * This signal is emitted when QRESYNC capability (RFC5162) is available and has
0456      * bee enabled on the server, and @p FetchScope::qresync has been set to @p true.
0457      * It contains a list of messages that have vanished from the mailbox since the
0458      * last modification sequence specified in @p FetchScope::changedSince.
0459      *
0460      * @param uids UIDs of messages that have been removed from the mailbox since
0461      *             the specified modification sequence.
0462      *
0463      * @since 5.16
0464      */
0465     void messagesVanished(const KIMAP::ImapSet &uids);
0466 
0467 protected:
0468     void doStart() override;
0469     void handleResponse(const Response &response) override;
0470 
0471 private:
0472     Q_PRIVATE_SLOT(d_func(), void emitPendings())
0473 };
0474 
0475 }