File indexing completed on 2024-06-23 05:18:30

0001 /*
0002   SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
0003   SPDX-FileCopyrightText: 2010 Leo Franchi <lfranchi@kde.org>
0004   SPDX-FileCopyrightText: 2017-2024 Laurent Montel <montel@kde.org>
0005 
0006   SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #pragma once
0010 
0011 #include "messagecomposer_export.h"
0012 #include <KMime/KMimeMessage>
0013 #include <KMime/MDN>
0014 
0015 #include <Akonadi/Collection>
0016 #include <Akonadi/Item>
0017 #include <Akonadi/MessageStatus>
0018 #include <QList>
0019 
0020 namespace KIdentityManagementCore
0021 {
0022 class IdentityManager;
0023 }
0024 
0025 namespace MessageComposer
0026 {
0027 /**
0028  * Enumeration that defines the available reply "modes"
0029  */
0030 enum ReplyStrategy {
0031     ReplySmart = 0, //< Attempt to automatically guess the best recipient for the reply
0032     ReplyAuthor, //< Reply to the author of the message (possibly NOT the mailing list, if any)
0033     ReplyList, //< Reply to the mailing list (and not the author of the message)
0034     ReplyAll, //< Reply to author and all the recipients in CC
0035     ReplyNone, //< Don't set reply addresses: they will be set manually
0036 };
0037 
0038 enum MDNAdvice {
0039     MDNIgnore,
0040     MDNSendDenied,
0041     MDNSend,
0042 };
0043 /**
0044  * Contains various factory methods for creating new messages such as replies, MDNs, forwards, etc.
0045  */
0046 class MESSAGECOMPOSER_EXPORT MessageFactoryNG : public QObject
0047 {
0048     Q_OBJECT
0049 public:
0050     /// Small helper structure which encapsulates the KMime::Message created when creating a reply, and
0051     /// the reply mode
0052     struct MessageReply {
0053         KMime::Message::Ptr msg = nullptr; ///< The actual reply message
0054         bool replyAll = false; ///< If true, the "reply all" template was used, otherwise the normal reply
0055         ///  template
0056     };
0057 
0058     explicit MessageFactoryNG(const KMime::Message::Ptr &origMsg,
0059                               Akonadi::Item::Id id,
0060                               const Akonadi::Collection &col = Akonadi::Collection(),
0061                               QObject *parent = nullptr);
0062     ~MessageFactoryNG() override;
0063 
0064     /**
0065      * Create a new message that is a reply to this message, filling all
0066      * required header fields with the proper values. The returned message
0067      * is not stored in any folder. Marks this message as replied.
0068      *
0069      */
0070     void createReplyAsync();
0071 
0072     /** Create a new message that is a forward of this message, filling all
0073     required header fields with the proper values. The returned message
0074     is not stored in any folder. Marks this message as forwarded. */
0075     void createForwardAsync();
0076 
0077     /**
0078      * Create a forward from the given list of messages, attaching each
0079      *  message to be forwarded to the new forwarded message.
0080      *
0081      * If no list is passed, use the original message passed in the MessageFactoryNG
0082      *  constructor.
0083      */
0084     [[nodiscard]] QPair<KMime::Message::Ptr, QList<KMime::Content *>> createAttachedForward(const Akonadi::Item::List &items = Akonadi::Item::List());
0085 
0086     /** Create a new message that is a redirect to this message, filling all
0087     required header fields with the proper values. The returned message
0088     is not stored in any folder. Marks this message as replied.
0089     Redirects differ from forwards so they are forwarded to some other
0090     user, mail is not changed and the reply-to field is set to
0091     the email address of the original sender.
0092     */
0093     [[nodiscard]] KMime::Message::Ptr createRedirect(const QString &toStr,
0094                                                      const QString &ccStr = QString(),
0095                                                      const QString &bccStr = QString(),
0096                                                      int transportId = -1,
0097                                                      const QString &fcc = QString(),
0098                                                      int identity = -1);
0099 
0100     [[nodiscard]] KMime::Message::Ptr createResend();
0101 
0102     /** Create a new message that is a delivery receipt of this message,
0103       filling required header fields with the proper values. The
0104       returned message is not stored in any folder. */
0105     [[nodiscard]] KMime::Message::Ptr createDeliveryReceipt();
0106 
0107     /** Create a new message that is a MDN for this message, filling all
0108       required fields with proper values. The returned message is not
0109       stored in any folder.
0110 
0111       @param a Use AutomaticAction for filtering and ManualAction for
0112                user-induced events.
0113       @param d See docs for KMime::MDN::DispositionType
0114       @param s See docs for KMime::MDN::SendingMode (in KMail, use MDNAdvideDialog to ask the user for this parameter)
0115       @param m See docs for KMime::MDN::DispositionModifier
0116 
0117       @return The notification message or 0, if none should be sent, as well as the state of the MDN operation.
0118     **/
0119     [[nodiscard]] KMime::Message::Ptr createMDN(KMime::MDN::ActionMode a,
0120                                                 KMime::MDN::DispositionType d,
0121                                                 KMime::MDN::SendingMode s,
0122                                                 int mdnQuoteOriginal = 0,
0123                                                 const QList<KMime::MDN::DispositionModifier> &m = QList<KMime::MDN::DispositionModifier>());
0124 
0125     /**
0126      * Create a new forwarded MIME digest. If the user is trying to forward multiple messages
0127      *  at once all inline, they can choose to have them be compiled into a single digest
0128      *  message.
0129      *
0130      * This will return a header message and individual message parts to be set as
0131      *  attachments.
0132      *
0133      * @param msgs List of messages to be composed into a digest
0134      */
0135     [[nodiscard]] QPair<KMime::Message::Ptr, KMime::Content *> createForwardDigestMIME(const Akonadi::Item::List &items);
0136 
0137     /**
0138      * Set the identity manager to be used when creating messages.
0139      * Required to be set before create* is called, otherwise the created messages
0140      *  might have the wrong identity data.
0141      */
0142     void setIdentityManager(KIdentityManagementCore::IdentityManager *ident);
0143 
0144     /**
0145      * Set the reply strategy to use. Default is ReplySmart.
0146      */
0147     void setReplyStrategy(MessageComposer::ReplyStrategy replyStrategy);
0148 
0149     /**
0150      * Set the selection to be used to  base the reply on.
0151      */
0152     void setSelection(const QString &selection);
0153 
0154     /**
0155      * Whether to quote the original message in the reply.
0156      *  Default is to quote.
0157      */
0158     void setQuote(bool quote);
0159 
0160     /**
0161      * Set the template to be used when creating the reply. Default is to not
0162      *  use any template at all.
0163      */
0164     void setTemplate(const QString &templ);
0165 
0166     /**
0167      * Set extra mailinglist addresses to send the created message to.
0168      * Any mailing-list addresses specified in the original message
0169      * itself will be added by MessageFactoryNG, so no need to add those manually.
0170      */
0171     void setMailingListAddresses(const KMime::Types::Mailbox::List &listAddresses);
0172 
0173     /**
0174      *  Set the identity that is set for the folder in which the given message is.
0175      *   It is used as a fallback when finding the identity if it can't be found in
0176      *   any other way.
0177      *   @param folderIdentityId an uoid of KIdentityManagementCore::Identity
0178      */
0179     void setFolderIdentity(uint folderIdentityId);
0180 
0181     /**
0182      * Whether or not to put the reply to a message in the same folder as the message itself.
0183      *  If so, specify the folder id in which to put them. Default is -1, which means to not put
0184      *  replies in the same folder at all.
0185      */
0186     void putRepliesInSameFolder(Akonadi::Item::Id parentColId = -1);
0187 
0188     /**
0189      * When creating MDNs, the user needs to be asked for confirmation in specific
0190      *  cases according to RFC 2298.
0191      */
0192     [[nodiscard]] static bool MDNRequested(const KMime::Message::Ptr &msg);
0193 
0194     /**
0195      * If sending an MDN requires confirmation due to multiple addresses.
0196      *
0197      * RFC 2298: [ Confirmation from the user SHOULD be obtained (or no
0198      * MDN sent) ] if there is more than one distinct address in the
0199      * Disposition-Notification-To header.
0200      */
0201     [[nodiscard]] static bool MDNConfirmMultipleRecipients(const KMime::Message::Ptr &msg);
0202 
0203     /**
0204      *
0205      * If sending an MDN requires confirmation due to discrepancy between MDN
0206      *  header and Return-Path header.
0207      *
0208      * RFC 2298: MDNs SHOULD NOT be sent automatically if the address in
0209      * the Disposition-Notification-To header differs from the address
0210      * in the Return-Path header. [...] Confirmation from the user
0211      * SHOULD be obtained (or no MDN sent) if there is no Return-Path
0212      * header in the message [...]
0213      */
0214     [[nodiscard]] static bool MDNReturnPathEmpty(const KMime::Message::Ptr &msg);
0215     [[nodiscard]] static bool MDNReturnPathNotInRecieptTo(const KMime::Message::Ptr &msg);
0216 
0217     /**
0218      * If the MDN headers contain options that KMail can't parse
0219      */
0220     [[nodiscard]] static bool MDNMDNUnknownOption(const KMime::Message::Ptr &msg);
0221 
0222     [[nodiscard]] bool replyAsHtml() const;
0223     void setReplyAsHtml(bool replyAsHtml);
0224 
0225 Q_SIGNALS:
0226     void createReplyDone(const MessageComposer::MessageFactoryNG::MessageReply &reply);
0227     void createForwardDone(const KMime::Message::Ptr &msg);
0228 
0229 private Q_SLOTS:
0230     MESSAGECOMPOSER_NO_EXPORT void slotCreateReplyDone(const KMime::Message::Ptr &msg, bool replyAll);
0231     MESSAGECOMPOSER_NO_EXPORT void slotCreateForwardDone(const KMime::Message::Ptr &msg);
0232 
0233 private:
0234     /** @return the UOID of the identity for this message.
0235       Searches the "x-kmail-identity" header and if that fails,
0236       searches with KIdentityManagementCore::IdentityManager::identityForAddress()
0237     **/
0238     [[nodiscard]] MESSAGECOMPOSER_NO_EXPORT uint identityUoid(const KMime::Message::Ptr &msg);
0239 
0240     [[nodiscard]] MESSAGECOMPOSER_NO_EXPORT QString replaceHeadersInString(const KMime::Message::Ptr &msg, const QString &s);
0241 
0242     [[nodiscard]] MESSAGECOMPOSER_NO_EXPORT QByteArray getRefStr(const KMime::Message::Ptr &msg);
0243     MESSAGECOMPOSER_NO_EXPORT KMime::Content *createForwardAttachmentMessage(const KMime::Message::Ptr &fwdMsg);
0244 
0245     KIdentityManagementCore::IdentityManager *mIdentityManager = nullptr;
0246     // Required parts to create messages
0247     KMime::Message::Ptr mOrigMsg;
0248     uint mFolderId;
0249     Akonadi::Item::Id mParentFolderId;
0250 
0251     Akonadi::Collection mCollection;
0252 
0253     // Optional settings the calling class may set
0254     MessageComposer::ReplyStrategy mReplyStrategy;
0255     QString mSelection;
0256     QString mTemplate;
0257     bool mQuote = true;
0258     bool mReplyAsHtml = false;
0259     KMime::Types::Mailbox::List mMailingListAddresses;
0260     Akonadi::Item::Id mId;
0261 };
0262 }
0263 
0264 Q_DECLARE_METATYPE(MessageComposer::ReplyStrategy)
0265 Q_DECLARE_METATYPE(MessageComposer::MessageFactoryNG::MessageReply)