1 /*
2   SPDX-FileCopyrightText: 2009 Constantin Berzan <exit3219@gmail.com>
3 
4   SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "messagequeuejob.h"
8 
9 #include "kmailtransportakonadi/transportattribute.h"
10 #include "transport.h"
11 #include "transportmanager.h"
12 
13 #include "mailtransportakonadi_debug.h"
14 #include <KLocalizedString>
15 
16 #include <Akonadi/Item>
17 #include <Akonadi/ItemCreateJob>
18 #include <addressattribute.h>
19 #include <messageflags.h>
20 #include <specialmailcollections.h>
21 #include <specialmailcollectionsrequestjob.h>
22 
23 using namespace Akonadi;
24 using namespace KMime;
25 using namespace MailTransport;
26 
27 /**
28   @internal
29 */
30 class MailTransport::MessageQueueJobPrivate
31 {
32 public:
MessageQueueJobPrivate(MessageQueueJob * qq)33     explicit MessageQueueJobPrivate(MessageQueueJob *qq)
34         : q(qq)
35     {
36     }
37 
38     MessageQueueJob *const q;
39 
40     Message::Ptr message;
41     TransportAttribute transportAttribute;
42     DispatchModeAttribute dispatchModeAttribute;
43     SentBehaviourAttribute sentBehaviourAttribute;
44     SentActionAttribute sentActionAttribute;
45     AddressAttribute addressAttribute;
46     bool started = false;
47 
48     /**
49       Returns true if this message has everything it needs and is ready to be
50       sent.
51     */
52     bool validate();
53 
54     // slot
55     void outboxRequestResult(KJob *job);
56 };
57 
validate()58 bool MessageQueueJobPrivate::validate()
59 {
60     if (!message) {
61         q->setError(KJob::UserDefinedError);
62         q->setErrorText(i18n("Empty message."));
63         q->emitResult();
64         return false;
65     }
66 
67     if ((addressAttribute.to().count() + addressAttribute.cc().count() + addressAttribute.bcc().count()) == 0) {
68         q->setError(KJob::UserDefinedError);
69         q->setErrorText(i18n("Message has no recipients."));
70         q->emitResult();
71         return false;
72     }
73 
74     const int transport = transportAttribute.transportId();
75     if (TransportManager::self()->transportById(transport, false) == nullptr) {
76         q->setError(KJob::UserDefinedError);
77         q->setErrorText(i18n("Message has invalid transport."));
78         q->emitResult();
79         return false;
80     }
81 
82     if (sentBehaviourAttribute.sentBehaviour() == SentBehaviourAttribute::MoveToCollection && !(sentBehaviourAttribute.moveToCollection().isValid())) {
83         q->setError(KJob::UserDefinedError);
84         q->setErrorText(i18n("Message has invalid sent-mail folder."));
85         q->emitResult();
86         return false;
87     } else if (sentBehaviourAttribute.sentBehaviour() == SentBehaviourAttribute::MoveToDefaultSentCollection) {
88         // TODO require SpecialMailCollections::SentMail here?
89     }
90 
91     return true; // all ok
92 }
93 
outboxRequestResult(KJob * job)94 void MessageQueueJobPrivate::outboxRequestResult(KJob *job)
95 {
96     Q_ASSERT(!started);
97     started = true;
98 
99     if (job->error()) {
100         qCritical() << "Failed to get the Outbox folder:" << job->error() << job->errorString();
101         q->setError(job->error());
102         q->emitResult();
103         return;
104     }
105 
106     if (!validate()) {
107         // The error has been set; the result has been emitted.
108         return;
109     }
110 
111     auto requestJob = qobject_cast<SpecialMailCollectionsRequestJob *>(job);
112     if (!requestJob) {
113         return;
114     }
115 
116     // Create item.
117     Item item;
118     item.setMimeType(QStringLiteral("message/rfc822"));
119     item.setPayload<Message::Ptr>(message);
120 
121     // Set attributes.
122     item.addAttribute(addressAttribute.clone());
123     item.addAttribute(dispatchModeAttribute.clone());
124     item.addAttribute(sentBehaviourAttribute.clone());
125     item.addAttribute(sentActionAttribute.clone());
126     item.addAttribute(transportAttribute.clone());
127 
128     Akonadi::MessageFlags::copyMessageFlags(*message, item);
129     // Set flags.
130     item.setFlag(Akonadi::MessageFlags::Queued);
131 
132     // Store the item in the outbox.
133     const Collection collection = requestJob->collection();
134     Q_ASSERT(collection.isValid());
135     auto cjob = new ItemCreateJob(item, collection); // job autostarts
136     q->addSubjob(cjob);
137 }
138 
MessageQueueJob(QObject * parent)139 MessageQueueJob::MessageQueueJob(QObject *parent)
140     : KCompositeJob(parent)
141     , d(new MessageQueueJobPrivate(this))
142 {
143 }
144 
145 MessageQueueJob::~MessageQueueJob() = default;
146 
message() const147 Message::Ptr MessageQueueJob::message() const
148 {
149     return d->message;
150 }
151 
dispatchModeAttribute()152 DispatchModeAttribute &MessageQueueJob::dispatchModeAttribute()
153 {
154     return d->dispatchModeAttribute;
155 }
156 
addressAttribute()157 AddressAttribute &MessageQueueJob::addressAttribute()
158 {
159     return d->addressAttribute;
160 }
161 
transportAttribute()162 TransportAttribute &MessageQueueJob::transportAttribute()
163 {
164     return d->transportAttribute;
165 }
166 
sentBehaviourAttribute()167 SentBehaviourAttribute &MessageQueueJob::sentBehaviourAttribute()
168 {
169     return d->sentBehaviourAttribute;
170 }
171 
sentActionAttribute()172 SentActionAttribute &MessageQueueJob::sentActionAttribute()
173 {
174     return d->sentActionAttribute;
175 }
176 
setMessage(const Message::Ptr & message)177 void MessageQueueJob::setMessage(const Message::Ptr &message)
178 {
179     d->message = message;
180 }
181 
start()182 void MessageQueueJob::start()
183 {
184     auto rjob = new SpecialMailCollectionsRequestJob(this);
185     rjob->requestDefaultCollection(SpecialMailCollections::Outbox);
186     connect(rjob, &SpecialMailCollectionsRequestJob::result, this, [this](KJob *job) {
187         d->outboxRequestResult(job);
188     });
189     rjob->start();
190 }
191 
slotResult(KJob * job)192 void MessageQueueJob::slotResult(KJob *job)
193 {
194     // error handling
195     KCompositeJob::slotResult(job);
196 
197     if (!error()) {
198         emitResult();
199     }
200 }
201 
202 #include "moc_messagequeuejob.cpp"
203