1/*
2 Copyright (c) 2009 Constantin Berzan <exit3219@gmail.com>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#include "messagequeuejob.h"
21
22#include "transport.h"
23#include "transportattribute.h"
24#include "transportmanager.h"
25
26#include <KDebug>
27#include <KLocalizedString>
28
29#include <akonadi/collection.h>
30#include <akonadi/item.h>
31#include <akonadi/itemcreatejob.h>
32#include <akonadi/kmime/addressattribute.h>
33#include <akonadi/kmime/messageflags.h>
34#include <akonadi/kmime/specialmailcollections.h>
35#include <akonadi/kmime/specialmailcollectionsrequestjob.h>
36
37using namespace Akonadi;
38using namespace KMime;
39using namespace MailTransport;
40
41/**
42 @internal
43*/
44class MailTransport::MessageQueueJob::Private
45{
46 public:
47 Private( MessageQueueJob *qq )
48 : q( qq )
49 {
50 started = false;
51 }
52
53 MessageQueueJob *const q;
54
55 Message::Ptr message;
56 TransportAttribute transportAttribute;
57 DispatchModeAttribute dispatchModeAttribute;
58 SentBehaviourAttribute sentBehaviourAttribute;
59 SentActionAttribute sentActionAttribute;
60 AddressAttribute addressAttribute;
61 bool started;
62
63 /**
64 Returns true if this message has everything it needs and is ready to be
65 sent.
66 */
67 bool validate();
68
69 // slot
70 void outboxRequestResult( KJob *job );
71
72};
73
74bool MessageQueueJob::Private::validate()
75{
76 if ( !message ) {
77 q->setError( UserDefinedError );
78 q->setErrorText( i18n( "Empty message." ) );
79 q->emitResult();
80 return false;
81 }
82
83 if ( addressAttribute.to().count() + addressAttribute.cc().count() +
84 addressAttribute.bcc().count() == 0 ) {
85 q->setError( UserDefinedError );
86 q->setErrorText( i18n( "Message has no recipients." ) );
87 q->emitResult();
88 return false;
89 }
90
91 const int transport = transportAttribute.transportId();
92 if ( TransportManager::self()->transportById( transport, false ) == 0 ) {
93 q->setError( UserDefinedError );
94 q->setErrorText( i18n( "Message has invalid transport." ) );
95 q->emitResult();
96 return false;
97 }
98
99 if ( sentBehaviourAttribute.sentBehaviour() == SentBehaviourAttribute::MoveToCollection &&
100 !( sentBehaviourAttribute.moveToCollection().isValid() ) ) {
101 q->setError( UserDefinedError );
102 q->setErrorText( i18n( "Message has invalid sent-mail folder." ) );
103 q->emitResult();
104 return false;
105 } else if ( sentBehaviourAttribute.sentBehaviour() ==
106 SentBehaviourAttribute::MoveToDefaultSentCollection ) {
107 // TODO require SpecialMailCollections::SentMail here?
108 }
109
110 return true; // all ok
111}
112
113void MessageQueueJob::Private::outboxRequestResult( KJob *job )
114{
115 Q_ASSERT( !started );
116 started = true;
117
118 if ( job->error() ) {
119 kError() << "Failed to get the Outbox folder:" << job->error() << job->errorString();
120 q->setError( job->error() );
121 q->emitResult();
122 return;
123 }
124
125 if ( !validate() ) {
126 // The error has been set; the result has been emitted.
127 return;
128 }
129
130 SpecialMailCollectionsRequestJob *requestJob =
131 qobject_cast<SpecialMailCollectionsRequestJob*>( job );
132 if ( !requestJob ) {
133 return;
134 }
135
136 // Create item.
137 Item item;
138 item.setMimeType( QLatin1String( "message/rfc822" ) );
139 item.setPayload<Message::Ptr>( message );
140
141 // Set attributes.
142 item.addAttribute( addressAttribute.clone() );
143 item.addAttribute( dispatchModeAttribute.clone() );
144 item.addAttribute( sentBehaviourAttribute.clone() );
145 item.addAttribute( sentActionAttribute.clone() );
146 item.addAttribute( transportAttribute.clone() );
147
148 // Update status flags
149 if ( KMime::isSigned( message.get() ) ) {
150 item.setFlag( Akonadi::MessageFlags::Signed );
151 }
152
153 if ( KMime::isEncrypted( message.get() ) ) {
154 item.setFlag( Akonadi::MessageFlags::Encrypted );
155 }
156
157 if ( KMime::isInvitation( message.get() ) ) {
158 item.setFlag( Akonadi::MessageFlags::HasInvitation );
159 }
160
161 if ( KMime::hasAttachment( message.get() ) ) {
162 item.setFlag( Akonadi::MessageFlags::HasAttachment );
163 }
164
165 // Set flags.
166 item.setFlag( Akonadi::MessageFlags::Queued );
167
168 // Store the item in the outbox.
169 const Collection collection = requestJob->collection();
170 Q_ASSERT( collection.isValid() );
171 ItemCreateJob *cjob = new ItemCreateJob( item, collection ); // job autostarts
172 q->addSubjob( cjob );
173}
174
175MessageQueueJob::MessageQueueJob( QObject *parent )
176 : KCompositeJob( parent ), d( new Private( this ) )
177{
178}
179
180MessageQueueJob::~MessageQueueJob()
181{
182 delete d;
183}
184
185Message::Ptr MessageQueueJob::message() const
186{
187 return d->message;
188}
189
190DispatchModeAttribute &MessageQueueJob::dispatchModeAttribute()
191{
192 return d->dispatchModeAttribute;
193}
194
195AddressAttribute &MessageQueueJob::addressAttribute()
196{
197 return d->addressAttribute;
198}
199
200TransportAttribute &MessageQueueJob::transportAttribute()
201{
202 return d->transportAttribute;
203}
204
205SentBehaviourAttribute &MessageQueueJob::sentBehaviourAttribute()
206{
207 return d->sentBehaviourAttribute;
208}
209
210SentActionAttribute &MessageQueueJob::sentActionAttribute()
211{
212 return d->sentActionAttribute;
213}
214
215void MessageQueueJob::setMessage( Message::Ptr message )
216{
217 d->message = message;
218}
219
220void MessageQueueJob::start()
221{
222 SpecialMailCollectionsRequestJob *rjob = new SpecialMailCollectionsRequestJob( this );
223 rjob->requestDefaultCollection( SpecialMailCollections::Outbox );
224 connect( rjob, SIGNAL(result(KJob*)), this, SLOT(outboxRequestResult(KJob*)) );
225 rjob->start();
226}
227
228void MessageQueueJob::slotResult( KJob *job )
229{
230 // error handling
231 KCompositeJob::slotResult( job );
232
233 if ( !error() ) {
234 emitResult();
235 }
236}
237
238#include "moc_messagequeuejob.cpp"
239