krop's commit fixes my problem in a better way, reverting
[kdepim.git] / kmail / kmsender.cpp
blobd2b4a40b8267d1cc9b2ef2880e60d86e04fb1c3c
1 /*
2 * kmail: KDE mail client
3 * Copyright (c) 1996-1998 Stefan Taferner <taferner@kde.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #define REALLY_WANT_KMSENDER
22 #include "kmsender.h"
23 #undef REALLY_WANT_KMSENDER
25 #include <kmime/kmime_header_parsing.h>
26 #include <QByteArray>
27 using namespace KMime::Types;
29 #include <kpimidentities/identity.h>
30 #include <kpimidentities/identitymanager.h>
31 #include <mailtransport/transport.h>
32 #include <mailtransport/transportjob.h>
33 #include <mailtransport/transportmanager.h>
34 using namespace MailTransport;
36 #include <kio/passworddialog.h>
37 #include <kio/scheduler.h>
38 #include <kmessagebox.h>
39 #include <klocale.h>
40 #include <kdebug.h>
41 #include <kconfig.h>
42 #include <kconfiggroup.h>
44 #include <assert.h>
45 #include <stdio.h>
46 #include <unistd.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <sys/wait.h>
50 #include "globalsettings.h"
51 #include "kmfiltermgr.h"
53 #include "kcursorsaver.h"
54 #include "progressmanager.h"
55 #include "kmaccount.h"
56 #include "kmfolderindex.h"
57 #include "kmfoldermgr.h"
58 #include "kmmsgdict.h"
59 #include "kmmsgpart.h"
60 #include "protocols.h"
61 #include "kmcommands.h"
62 #include "stringutil.h"
64 #include <mimelib/mediatyp.h>
65 #include <mimelib/enum.h>
66 #include <mimelib/param.h>
68 static const QString SENDER_GROUP( "sending mail" );
70 using namespace KMail;
72 //-----------------------------------------------------------------------------
73 KMSender::KMSender()
74 : mTransportJob( 0 ), mOutboxFolder( 0 ), mSentFolder( 0 )
76 mSendProcStarted = false;
77 mSendInProgress = false;
78 mCurrentMsg = 0;
79 readConfig();
80 mSendAborted = false;
81 mSentMessages = 0;
82 mTotalMessages = 0;
83 mFailedMessages = 0;
84 mSentBytes = 0;
85 mTotalBytes = 0;
86 mProgressItem = 0;
90 //-----------------------------------------------------------------------------
91 KMSender::~KMSender()
93 writeConfig(false);
96 //-----------------------------------------------------------------------------
97 void KMSender::setStatusMsg(const QString &msg)
99 if ( mProgressItem )
100 mProgressItem->setStatus(msg);
103 //-----------------------------------------------------------------------------
104 void KMSender::readConfig(void)
106 QString str;
107 KConfigGroup config(KMKernel::config(), SENDER_GROUP);
109 mSendImmediate = config.readEntry( "Immediate", true );
110 mSendQuotedPrintable = config.readEntry( "Quoted-Printable", true );
114 //-----------------------------------------------------------------------------
115 void KMSender::writeConfig(bool aWithSync)
117 KConfigGroup config(KMKernel::config(), SENDER_GROUP);
119 config.writeEntry("Immediate", mSendImmediate);
120 config.writeEntry("Quoted-Printable", mSendQuotedPrintable);
122 if (aWithSync) config.sync();
126 static void handleRedirections( KMMessage *m ) {
127 const QString from = m->headerField( "X-KMail-Redirect-From" );
128 const QString msgId = m->msgId();
129 if ( from.isEmpty() || msgId.isEmpty() ) {
130 m->setMsgId( StringUtil::generateMessageId( m->sender() ) );
134 //-----------------------------------------------------------------------------
135 bool KMSender::doSend(KMMessage *aMsg, short sendNow )
137 if ( !aMsg ) {
138 return false;
141 if ( !TransportManager::self()->promptCreateTransportIfNoneExists( 0 ) ) {
142 return false;
145 if ( aMsg->to().isEmpty() ) {
146 // RFC822 says:
147 // Note that the "Bcc" field may be empty, while the "To" field is
148 // required to have at least one address.
150 // however:
152 // The following string is accepted according to RFC 2822,
153 // section 3.4 "Address Specification" where they say:
155 // "An address may either be an individual mailbox,
156 // or a group of mailboxes."
157 // and:
158 // "group + display-name ":" [mailbox-list / CFWS] ";"
159 // [CFWS]"
161 // In this syntax our "undisclosed-recipients: ;"
162 // just specifies an empty group.
164 // In further explanations RFC 2822 states that it *is*
165 // allowed to have a ZERO number of mailboxes in the "mailbox-list".
166 aMsg->setTo( "Undisclosed.Recipients: ;" );
169 handleRedirections( aMsg );
171 if ( sendNow == -1 ) {
172 sendNow = mSendImmediate;
175 KMFolder * const outbox = kmkernel->outboxFolder();
176 const KMFolderOpener openOutbox( outbox, "KMSender" );
178 aMsg->setStatus( MessageStatus::statusQueued() );
180 if ( const int err = openOutbox.folder()->addMsg( aMsg ) ) {
181 Q_UNUSED( err );
182 KMessageBox::information( 0, i18n("Cannot add message to outbox folder") );
183 return false;
186 //Ensure the message is correctly and fully parsed
187 openOutbox.folder()->unGetMsg( openOutbox.folder()->count() - 1 );
189 if ( !sendNow || mSendInProgress ) {
190 return true;
193 return sendQueued();
196 //-----------------------------------------------------------------------------
197 void KMSender::outboxMsgAdded( int idx )
199 ++mTotalMessages;
200 KMMsgBase* msg = kmkernel->outboxFolder()->getMsgBase( idx );
201 Q_ASSERT( msg );
202 if ( msg ) {
203 mTotalBytes += msg->msgSize();
207 //-----------------------------------------------------------------------------
208 bool KMSender::doSendQueued( const QString &customTransport )
210 if ( !TransportManager::self()->promptCreateTransportIfNoneExists( 0 ) ) {
211 return false;
214 if ( mSendInProgress ) {
215 return false;
218 // open necessary folders
219 mOutboxFolder = kmkernel->outboxFolder();
220 mOutboxFolder->open( "dosendoutbox" );
221 mTotalMessages = mOutboxFolder->count();
222 if ( mTotalMessages == 0 ) {
223 // Nothing in the outbox. We are done.
224 mOutboxFolder->close( "dosendoutbox" );
225 mOutboxFolder = 0;
226 return true;
228 mTotalBytes = 0;
229 for( int i = 0 ; i<mTotalMessages ; ++i ) {
230 mTotalBytes += mOutboxFolder->getMsgBase(i)->msgSize();
233 connect( mOutboxFolder, SIGNAL( msgAdded( int ) ),
234 this, SLOT( outboxMsgAdded( int ) ) );
235 mCurrentMsg = 0;
237 mSentFolder = kmkernel->sentFolder();
238 mSentFolder->open( "dosendsent" );
239 kmkernel->filterMgr()->ref();
241 // start sending the messages
242 mCustomTransport = customTransport;
243 doSendMsg();
244 return true;
247 //-----------------------------------------------------------------------------
248 void KMSender::slotProcessedSize( KJob *, qulonglong size )
250 int percent = (mTotalBytes) ? ( 100 * (mSentBytes+size) / mTotalBytes ) : 0;
251 if (percent > 100) percent = 100;
252 mProgressItem->setProgress(percent);
255 static bool messageIsDispositionNotificationReport( KMMessage *msg )
257 if ( msg->type() == DwMime::kTypeMessage &&
258 msg->subtype() == DwMime::kSubtypeDispositionNotification )
259 return true;
261 if ( msg->type() != DwMime::kTypeMultipart ||
262 msg->subtype() != DwMime::kSubtypeReport )
263 return false;
265 DwMediaType& ct = msg->dwContentType();
266 DwParameter *param = ct.FirstParameter();
267 while( param ) {
268 if ( !qstricmp( param->Attribute().c_str(), "report-type")
269 && !qstricmp( param->Value().c_str(), "disposition-notification" ) )
270 return true;
271 else
272 param = param->Next();
274 return false;
278 static QStringList addrSpecListToStringList( const AddrSpecList & l, bool allowEmpty=false ) {
279 QStringList result;
280 for ( AddrSpecList::const_iterator it = l.begin(), end = l.end() ; it != end ; ++it ) {
281 const QString s = (*it).asString();
282 if ( allowEmpty || !s.isEmpty() )
283 result.push_back( s );
285 return result;
288 static void extractSenderToCCAndBcc( KMMessage * aMsg, QString * sender, QStringList * to, QStringList * cc, QStringList * bcc ) {
289 if ( sender ) *sender = aMsg->sender();
290 if( !aMsg->headerField("X-KMail-Recipients").isEmpty() ) {
291 // extended BCC handling to prevent TOs and CCs from seeing
292 // BBC information by looking at source of an OpenPGP encrypted mail
293 if ( to ) *to = addrSpecListToStringList( aMsg->extractAddrSpecs( "X-KMail-Recipients" ) );
294 aMsg->removeHeaderField( "X-KMail-Recipients" );
295 } else {
296 if ( to ) *to = addrSpecListToStringList( aMsg->extractAddrSpecs( "To" ) );
297 if ( cc ) *cc = addrSpecListToStringList( aMsg->extractAddrSpecs( "Cc" ) );
298 if ( bcc ) *bcc = addrSpecListToStringList( aMsg->extractAddrSpecs( "Bcc" ) );
303 //-----------------------------------------------------------------------------
304 void KMSender::doSendMsg()
306 if ( !kmkernel ) { //To handle message sending in progress when exiting
307 return; //TODO: handle this case better
310 const bool someSent = mCurrentMsg;
311 if ( someSent ) {
312 mSentMessages++;
313 mSentBytes += mCurrentMsg->msgSize();
316 // Post-process sent message (filtering)
317 KMFolder *sentFolder = 0, *imapSentFolder = 0;
318 if ( mCurrentMsg && kmkernel->filterMgr() ) {
319 mCurrentMsg->setTransferInProgress( false );
320 if ( mCurrentMsg->hasUnencryptedMsg() ) {
321 kDebug() << "Post-processing: replace mCurrentMsg body by unencryptedMsg data";
322 // delete all current body parts
323 mCurrentMsg->deleteBodyParts();
324 // copy Content-[..] headers from unencrypted message to current one
325 KMMessage & newMsg( *mCurrentMsg->unencryptedMsg() );
326 mCurrentMsg->dwContentType() = newMsg.dwContentType();
327 mCurrentMsg->setContentTransferEncodingStr( newMsg.contentTransferEncodingStr() );
328 QByteArray newDispo =
329 newMsg.headerField( "Content-Disposition" ).toLatin1();
330 if ( newDispo.isEmpty() ) {
331 mCurrentMsg->removeHeaderField( "Content-Disposition" );
332 } else {
333 mCurrentMsg->setHeaderField( "Content-Disposition", newDispo );
335 // copy the body
336 mCurrentMsg->setBody( newMsg.body() );
337 // copy all the body parts
338 KMMessagePart msgPart;
339 for ( int i = 0; i < newMsg.numBodyParts(); ++i ) {
340 newMsg.bodyPart( i, &msgPart );
341 mCurrentMsg->addBodyPart( &msgPart );
344 MessageStatus status = MessageStatus::statusSent();
345 status.setRead(); // otherwise it defaults to new on imap
346 mCurrentMsg->setStatus( status );
347 mCurrentMsg->updateAttachmentState();
349 const KPIMIdentities::Identity & id =
350 kmkernel->identityManager()->identityForUoidOrDefault(
351 mCurrentMsg->headerField( "X-KMail-Identity" ).trimmed().toUInt() );
352 if ( !mCurrentMsg->fcc().isEmpty() ) {
353 sentFolder = kmkernel->folderMgr()->findIdString( mCurrentMsg->fcc() );
354 if ( sentFolder == 0 ) {
355 // This is *NOT* supposed to be imapSentFolder!
356 sentFolder =
357 kmkernel->dimapFolderMgr()->findIdString( mCurrentMsg->fcc() );
359 if ( sentFolder == 0 ) {
360 imapSentFolder =
361 kmkernel->imapFolderMgr()->findIdString( mCurrentMsg->fcc() );
364 // No, or no usable sentFolder, and no, or no usable imapSentFolder,
365 // let's try the on in the identity
366 if ( ( sentFolder == 0 || sentFolder->isReadOnly() )
367 && ( imapSentFolder == 0 || imapSentFolder->isReadOnly() )
368 && !id.fcc().isEmpty() ) {
369 sentFolder = kmkernel->folderMgr()->findIdString( id.fcc() );
370 if ( sentFolder == 0 ) {
371 // This is *NOT* supposed to be imapSentFolder!
372 sentFolder = kmkernel->dimapFolderMgr()->findIdString( id.fcc() );
374 if ( sentFolder == 0 ) {
375 imapSentFolder = kmkernel->imapFolderMgr()->findIdString( id.fcc() );
378 if (imapSentFolder &&
379 ( imapSentFolder->noContent() || imapSentFolder->isReadOnly() ) ) {
380 imapSentFolder = 0;
383 if ( sentFolder == 0 || sentFolder->isReadOnly() ) {
384 sentFolder = kmkernel->sentFolder();
387 if ( const int err = sentFolder->open( "sentFolder" ) ) {
388 Q_UNUSED( err );
389 cleanup();
390 return;
393 // Disable the emitting of msgAdded signal, because the message is
394 // taken out of the current folder (outbox) and re-added, to make
395 // filter actions changing the message work. We don't want that to
396 // screw up message counts.
397 if ( mCurrentMsg->parent() ) {
398 mCurrentMsg->parent()->quiet( true );
400 const int processResult =
401 kmkernel->filterMgr()->process( mCurrentMsg, KMFilterMgr::Outbound );
402 if ( mCurrentMsg->parent() ) {
403 mCurrentMsg->parent()->quiet( false );
406 // 0==processed ok, 1==no filter matched, 2==critical error, abort!
407 switch ( processResult ) {
408 case 2:
409 kError() << "Critical error: Unable to process sent mail (out of space?)";
410 KMessageBox::information( 0,
411 i18n("Critical error: "
412 "Unable to process sent mail (out of space?)"
413 "Moving failing message to \"sent-mail\" folder.") );
414 if ( sentFolder ) {
415 sentFolder->moveMsg( mCurrentMsg );
416 sentFolder->close( "sentFolder" );
418 cleanup();
419 return;
420 case 1:
421 if ( sentFolder->moveMsg( mCurrentMsg ) != 0 ) {
422 KMessageBox::error( 0,
423 i18n("Moving the sent message \"%1\" from the "
424 "\"outbox\" to the \"sent-mail\" folder failed.\n"
425 "Possible reasons are lack of disk space or write permission. "
426 "Please try to fix the problem and move the message manually.",
427 mCurrentMsg->subject() ) );
428 cleanup();
429 return;
431 if ( imapSentFolder ) {
432 // Does proper folder refcounting and message locking
433 KMCommand *command = new KMMoveCommand( imapSentFolder, mCurrentMsg );
434 command->keepFolderOpen( sentFolder ); // will open it, and close when done
435 command->start();
437 default:
438 break;
440 setStatusByLink( mCurrentMsg );
441 if ( mCurrentMsg->parent() && !imapSentFolder ) {
442 // for speed optimization, this code assumes that mCurrentMsg is the
443 // last one in it's parent folder; make sure that's really the case:
444 assert( mCurrentMsg->parent()->find( mCurrentMsg )
445 == mCurrentMsg->parent()->count() - 1 );
446 // unGet this message:
447 mCurrentMsg->parent()->unGetMsg( mCurrentMsg->parent()->count() -1 );
450 mCurrentMsg = 0;
453 // See if there is another queued message
454 mCurrentMsg = mOutboxFolder->getMsg( mFailedMessages );
455 if ( mCurrentMsg && !mCurrentMsg->transferInProgress() &&
456 mCurrentMsg->sender().isEmpty() ) {
457 // if we do not have a sender address then use the email address of the
458 // message's identity or of the default identity unless those two are
459 // also empty
460 const KPIMIdentities::Identity &id =
461 kmkernel->identityManager()->identityForUoidOrDefault(
462 mCurrentMsg->headerField( "X-KMail-Identity" ).trimmed().toUInt() );
463 if ( !id.emailAddr().isEmpty() ) {
464 mCurrentMsg->setFrom( id.fullEmailAddr() );
465 } else if ( !kmkernel->identityManager()->defaultIdentity().emailAddr().isEmpty() ) {
466 mCurrentMsg->setFrom( kmkernel->identityManager()->defaultIdentity().fullEmailAddr() );
467 } else {
468 KMessageBox::sorry( 0, i18n( "It is not possible to send messages "
469 "without specifying a sender address.\n"
470 "Please set the email address of "
471 "identity '%1' in the Identities "
472 "section of the configuration dialog "
473 "and then try again.",
474 id.identityName() ) );
475 mOutboxFolder->unGetMsg( mFailedMessages );
476 mCurrentMsg = 0;
479 if ( !mCurrentMsg || mCurrentMsg->transferInProgress() ) {
480 // a message is locked finish the send
481 if ( mCurrentMsg && mCurrentMsg->transferInProgress() ) {
482 mCurrentMsg = 0;
484 // no more message: cleanup and done
485 if ( sentFolder != 0 ) {
486 sentFolder->close( "sentFolder" );
488 if ( someSent ) {
489 if ( mSentMessages == mTotalMessages ) {
490 setStatusMsg(i18np("%1 queued message successfully sent.",
491 "%1 queued messages successfully sent.",
492 mSentMessages));
493 } else {
494 setStatusMsg(i18n("%1 of %2 queued messages successfully sent.",
495 mSentMessages, mTotalMessages ));
498 cleanup();
499 return;
501 mCurrentMsg->setTransferInProgress( true );
503 // apply filters before sending message
504 // TODO: to support encrypted/signed messages this sould be moved to messagecomposer.cpp
505 // Disable the emitting of msgAdded signal, because the message is taken out of the
506 // current folder (outbox) and re-added, to make filter actions changing the message
507 // work. We don't want that to screw up message counts.
508 if ( kmkernel->filterMgr() ) {
509 if ( mCurrentMsg->parent() ) mCurrentMsg->parent()->quiet( true );
510 const int processResult = kmkernel->filterMgr()->process( mCurrentMsg, KMFilterMgr::BeforeOutbound );
511 if ( mCurrentMsg->parent() ) mCurrentMsg->parent()->quiet( false );
512 if ( processResult == 2 /* critical error */ ) {
513 kError() << "Critical error: Unable to execute filters before sending message (out of space?)";
514 KMessageBox::information( 0, i18n( "Critical error: "
515 "Unable to execute filters before sending message (out of space?)" ) );
519 /// start the sender process or initialize communication
520 if ( !mSendInProgress ) {
521 Q_ASSERT( !mProgressItem );
522 mProgressItem =
523 KPIM::ProgressManager::createProgressItem(
524 "Sender",
525 i18n( "Sending messages" ),
526 i18n("Initiating sender process..."),
527 true );
528 connect( mProgressItem, SIGNAL(progressItemCanceled(KPIM::ProgressItem*)),
529 this, SLOT( slotAbortSend() ) );
530 KGlobal::ref();
531 mSendInProgress = true;
534 QString msgTransport = mCustomTransport;
535 if ( msgTransport.isEmpty() )
536 msgTransport = mCurrentMsg->headerField( "X-KMail-Transport" );
538 if ( msgTransport.isEmpty() )
539 msgTransport = TransportManager::self()->defaultTransportName();
541 if ( !mTransportJob ) {
542 mMethodStr = msgTransport;
543 mTransportJob = TransportManager::self()->createTransportJob( msgTransport );
544 if ( !mTransportJob ) {
545 KMessageBox::error( 0, i18n( "Transport '%1' is invalid.", mMethodStr ),
546 i18n( "Sending failed" ) );
547 mProgressItem->cancel();
548 mProgressItem->setComplete();
549 cleanup();
550 return;
553 if ( mTransportJob->transport()->encryption() == Transport::EnumEncryption::TLS ||
554 mTransportJob->transport()->encryption() == Transport::EnumEncryption::SSL ) {
555 mProgressItem->setUsesCrypto( true );
556 } else if ( !mCustomTransport.isEmpty() ) {
557 int result = KMessageBox::warningContinueCancel(
559 i18n( "You have chosen to send all queued email using an unencrypted transport, do you want to continue? "),
560 i18n( "Security Warning" ),
561 KGuiItem( i18n( "Send Unencrypted" ) ),
562 KStandardGuiItem::cancel(),
563 "useCustomTransportWithoutAsking", false );
565 if ( result == KMessageBox::Cancel ) {
566 mProgressItem->cancel();
567 mProgressItem->setComplete();
568 slotAbortSend();
569 cleanup();
570 return;
574 setStatusMsg( i18nc("%3: subject of message","Sending message %1 of %2: %3",
575 mSentMessages+mFailedMessages+1, mTotalMessages,
576 mCurrentMsg->subject()) );
577 QStringList to, cc, bcc;
578 QString sender;
579 extractSenderToCCAndBcc( mCurrentMsg, &sender, &to, &cc, &bcc );
581 // MDNs are required to have an empty envelope from as per RFC2298.
582 if ( messageIsDispositionNotificationReport( mCurrentMsg ) && GlobalSettings::self()->sendMDNsWithEmptySender() )
583 sender = "<>";
585 const QByteArray message = mCurrentMsg->asSendableString();
586 if ( sender.isEmpty() ) {
587 if ( mCurrentMsg )
588 mCurrentMsg->setTransferInProgress( false );
589 if ( mOutboxFolder )
590 mOutboxFolder->unGetMsg( mFailedMessages );
591 mCurrentMsg = 0;
592 cleanup();
593 setStatusMsg(i18n("Failed to send (some) queued messages."));
594 return;
597 mTransportJob->setSender( sender );
598 mTransportJob->setTo( to );
599 mTransportJob->setCc( cc );
600 mTransportJob->setBcc( bcc );
601 mTransportJob->setData( message );
603 connect( mTransportJob, SIGNAL(result(KJob*)), SLOT(slotResult(KJob*)) );
604 connect( mTransportJob, SIGNAL(processedSize(KJob *, qulonglong)),
605 SLOT( slotProcessedSize(KJob *, qulonglong)) );
606 mSendProcStarted = true;
607 mTransportJob->start();
612 //-----------------------------------------------------------------------------
613 void KMSender::cleanup( void )
615 kDebug() ;
616 if ( mTransportJob && mSendProcStarted ) {
617 mTransportJob->kill();
619 mTransportJob = 0;
620 mSendProcStarted = false;
621 if ( mSendInProgress ) {
622 KGlobal::deref();
624 mSendInProgress = false;
625 if ( mCurrentMsg ) {
626 mCurrentMsg->setTransferInProgress( false );
627 mCurrentMsg = 0;
629 if ( mSentFolder ) {
630 mSentFolder->close( "dosendsent" );
631 mSentFolder = 0;
633 if ( mOutboxFolder ) {
634 disconnect( mOutboxFolder, SIGNAL(msgAdded(int)),
635 this, SLOT(outboxMsgAdded(int)) );
636 mOutboxFolder->close( "dosendoutbox" );
637 if ( mOutboxFolder->count( true ) == 0 ) {
638 mOutboxFolder->expunge();
639 } else if ( mOutboxFolder->needsCompacting() ) {
640 mOutboxFolder->compact( KMFolder::CompactSilentlyNow );
642 mOutboxFolder = 0;
645 mSendAborted = false;
646 mSentMessages = 0;
647 mFailedMessages = 0;
648 mSentBytes = 0;
649 if ( mProgressItem ) {
650 mProgressItem->setComplete();
652 mProgressItem = 0;
653 kmkernel->filterMgr()->deref();
656 //-----------------------------------------------------------------------------
657 void KMSender::slotAbortSend()
659 mSendAborted = true;
660 if ( mTransportJob ) {
661 mTransportJob->kill( KJob::EmitResult );
665 //-----------------------------------------------------------------------------
666 void KMSender::slotResult( KJob *job )
668 assert( mTransportJob == job );
669 mTransportJob = 0;
670 mSendProcStarted = false;
672 QString msg;
673 QString errString = job->errorString();
675 if ( mSendAborted ) {
676 // sending of message aborted
677 if ( mCurrentMsg ) {
678 mCurrentMsg->setTransferInProgress( false );
679 if ( mOutboxFolder ) {
680 mOutboxFolder->unGetMsg( mFailedMessages );
682 mCurrentMsg = 0;
684 msg = i18n("Sending aborted:\n%1\n"
685 "The message will stay in the 'outbox' folder until you either "
686 "fix the problem (e.g. a broken address) or remove the message "
687 "from the 'outbox' folder.\n"
688 "The following transport was used:\n %2",
689 errString,
690 mMethodStr);
691 if (!errString.isEmpty()) KMessageBox::error(0,msg);
692 setStatusMsg( i18n( "Sending aborted." ) );
693 } else {
694 if ( job->error() ) {
695 if ( mCurrentMsg ) {
696 mCurrentMsg->setTransferInProgress( false );
698 if ( mOutboxFolder ) {
699 mOutboxFolder->unGetMsg( mFailedMessages );
701 mCurrentMsg = 0;
702 mFailedMessages++;
704 // Sending of message failed.
705 if ( !errString.isEmpty() ) {
706 int res = KMessageBox::Yes;
707 if ( mSentMessages+mFailedMessages != mTotalMessages ) {
708 msg = i18n("<p>Sending failed:</p>"
709 "<p>%1</p>"
710 "<p>The message will stay in the 'outbox' folder until you either "
711 "fix the problem (e.g. a broken address) or remove the message "
712 "from the 'outbox' folder.</p>"
713 "<p>The following transport was used: %2</p>"
714 "<p>Continue sending the remaining messages?</p>",
715 errString,
716 mMethodStr);
717 res = KMessageBox::warningYesNo( 0, msg,
718 i18n( "Continue Sending" ), KGuiItem(i18n( "&Continue Sending" )),
719 KGuiItem(i18n("&Abort Sending")) );
720 } else {
721 msg = i18n("Sending failed:\n%1\n"
722 "The message will stay in the 'outbox' folder until you either "
723 "fix the problem (e.g. a broken address) or remove the message "
724 "from the 'outbox' folder.\n"
725 "The following transport was used:\n %2",
726 errString,
727 mMethodStr);
728 KMessageBox::error(0,msg);
730 if (res == KMessageBox::Yes) {
731 // Try the next one.
732 doSendMsg();
733 return;
734 } else {
735 setStatusMsg( i18n( "Sending aborted." ) );
738 } else {
739 // Sending suceeded.
740 doSendMsg();
741 return;
744 cleanup();
747 //-----------------------------------------------------------------------------
748 void KMSender::setSendImmediate(bool aSendImmediate)
750 mSendImmediate = aSendImmediate;
754 //-----------------------------------------------------------------------------
755 void KMSender::setSendQuotedPrintable(bool aSendQuotedPrintable)
757 mSendQuotedPrintable = aSendQuotedPrintable;
761 //-----------------------------------------------------------------------------
762 void KMSender::setStatusByLink( const KMMessage *aMsg )
764 int n = 0;
765 while ( 1 ) {
766 ulong msn;
767 MessageStatus status;
768 aMsg->getLink( n, &msn, status );
769 if ( !msn || status.isOfUnknownStatus() ) {
770 break;
772 n++;
774 KMFolder *folder = 0;
775 int index = -1;
776 KMMsgDict::instance()->getLocation( msn, &folder, &index );
777 if ( folder && index != -1 ) {
778 KMFolderOpener openFolder( folder, "setstatus" );
779 if ( status.isDeleted() ) {
780 // Move the message to the trash folder
781 KMTrashMsgCommand *cmd =
782 new KMTrashMsgCommand( folder, folder->getMsg( index ) );
783 cmd->start();
784 } else {
785 folder->setStatus( index, status );
787 } else {
788 kWarning() <<"Cannot update linked message, it could not be found!";
793 #include "kmsender.moc"