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()58bool 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)94void 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)139MessageQueueJob::MessageQueueJob(QObject *parent) 140 : KCompositeJob(parent) 141 , d(new MessageQueueJobPrivate(this)) 142 { 143 } 144 145 MessageQueueJob::~MessageQueueJob() = default; 146 message() const147Message::Ptr MessageQueueJob::message() const 148 { 149 return d->message; 150 } 151 dispatchModeAttribute()152DispatchModeAttribute &MessageQueueJob::dispatchModeAttribute() 153 { 154 return d->dispatchModeAttribute; 155 } 156 addressAttribute()157AddressAttribute &MessageQueueJob::addressAttribute() 158 { 159 return d->addressAttribute; 160 } 161 transportAttribute()162TransportAttribute &MessageQueueJob::transportAttribute() 163 { 164 return d->transportAttribute; 165 } 166 sentBehaviourAttribute()167SentBehaviourAttribute &MessageQueueJob::sentBehaviourAttribute() 168 { 169 return d->sentBehaviourAttribute; 170 } 171 sentActionAttribute()172SentActionAttribute &MessageQueueJob::sentActionAttribute() 173 { 174 return d->sentActionAttribute; 175 } 176 setMessage(const Message::Ptr & message)177void MessageQueueJob::setMessage(const Message::Ptr &message) 178 { 179 d->message = message; 180 } 181 start()182void 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)192void 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