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
23 #undef REALLY_WANT_KMSENDER
25 #include <kmime/kmime_header_parsing.h>
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>
42 #include <kconfiggroup.h>
47 #include <sys/types.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 //-----------------------------------------------------------------------------
74 : mTransportJob( 0 ), mOutboxFolder( 0 ), mSentFolder( 0 )
76 mSendProcStarted
= false;
77 mSendInProgress
= false;
90 //-----------------------------------------------------------------------------
96 //-----------------------------------------------------------------------------
97 void KMSender::setStatusMsg(const QString
&msg
)
100 mProgressItem
->setStatus(msg
);
103 //-----------------------------------------------------------------------------
104 void KMSender::readConfig(void)
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
)
141 if ( !TransportManager::self()->promptCreateTransportIfNoneExists( 0 ) ) {
145 if ( aMsg
->to().isEmpty() ) {
147 // Note that the "Bcc" field may be empty, while the "To" field is
148 // required to have at least one address.
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."
158 // "group + display-name ":" [mailbox-list / 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
) ) {
182 KMessageBox::information( 0, i18n("Cannot add message to outbox folder") );
186 //Ensure the message is correctly and fully parsed
187 openOutbox
.folder()->unGetMsg( openOutbox
.folder()->count() - 1 );
189 if ( !sendNow
|| mSendInProgress
) {
196 //-----------------------------------------------------------------------------
197 void KMSender::outboxMsgAdded( int idx
)
200 KMMsgBase
* msg
= kmkernel
->outboxFolder()->getMsgBase( idx
);
203 mTotalBytes
+= msg
->msgSize();
207 //-----------------------------------------------------------------------------
208 bool KMSender::doSendQueued( const QString
&customTransport
)
210 if ( !TransportManager::self()->promptCreateTransportIfNoneExists( 0 ) ) {
214 if ( mSendInProgress
) {
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" );
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 ) ) );
237 mSentFolder
= kmkernel
->sentFolder();
238 mSentFolder
->open( "dosendsent" );
239 kmkernel
->filterMgr()->ref();
241 // start sending the messages
242 mCustomTransport
= customTransport
;
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
)
261 if ( msg
->type() != DwMime::kTypeMultipart
||
262 msg
->subtype() != DwMime::kSubtypeReport
)
265 DwMediaType
& ct
= msg
->dwContentType();
266 DwParameter
*param
= ct
.FirstParameter();
268 if ( !qstricmp( param
->Attribute().c_str(), "report-type")
269 && !qstricmp( param
->Value().c_str(), "disposition-notification" ) )
272 param
= param
->Next();
278 static QStringList
addrSpecListToStringList( const AddrSpecList
& l
, bool allowEmpty
=false ) {
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
);
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" );
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
;
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" );
333 mCurrentMsg
->setHeaderField( "Content-Disposition", newDispo
);
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!
357 kmkernel
->dimapFolderMgr()->findIdString( mCurrentMsg
->fcc() );
359 if ( sentFolder
== 0 ) {
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() ) ) {
383 if ( sentFolder
== 0 || sentFolder
->isReadOnly() ) {
384 sentFolder
= kmkernel
->sentFolder();
387 if ( const int err
= sentFolder
->open( "sentFolder" ) ) {
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
) {
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.") );
415 sentFolder
->moveMsg( mCurrentMsg
);
416 sentFolder
->close( "sentFolder" );
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() ) );
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
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 );
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
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() );
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
);
479 if ( !mCurrentMsg
|| mCurrentMsg
->transferInProgress() ) {
480 // a message is locked finish the send
481 if ( mCurrentMsg
&& mCurrentMsg
->transferInProgress() ) {
484 // no more message: cleanup and done
485 if ( sentFolder
!= 0 ) {
486 sentFolder
->close( "sentFolder" );
489 if ( mSentMessages
== mTotalMessages
) {
490 setStatusMsg(i18np("%1 queued message successfully sent.",
491 "%1 queued messages successfully sent.",
494 setStatusMsg(i18n("%1 of %2 queued messages successfully sent.",
495 mSentMessages
, mTotalMessages
));
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
);
523 KPIM::ProgressManager::createProgressItem(
525 i18n( "Sending messages" ),
526 i18n("Initiating sender process..."),
528 connect( mProgressItem
, SIGNAL(progressItemCanceled(KPIM::ProgressItem
*)),
529 this, SLOT( slotAbortSend() ) );
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();
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();
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
;
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() )
585 const QByteArray message
= mCurrentMsg
->asSendableString();
586 if ( sender
.isEmpty() ) {
588 mCurrentMsg
->setTransferInProgress( false );
590 mOutboxFolder
->unGetMsg( mFailedMessages
);
593 setStatusMsg(i18n("Failed to send (some) queued messages."));
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 )
616 if ( mTransportJob
&& mSendProcStarted
) {
617 mTransportJob
->kill();
620 mSendProcStarted
= false;
621 if ( mSendInProgress
) {
624 mSendInProgress
= false;
626 mCurrentMsg
->setTransferInProgress( false );
630 mSentFolder
->close( "dosendsent" );
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
);
645 mSendAborted
= false;
649 if ( mProgressItem
) {
650 mProgressItem
->setComplete();
653 kmkernel
->filterMgr()->deref();
656 //-----------------------------------------------------------------------------
657 void KMSender::slotAbortSend()
660 if ( mTransportJob
) {
661 mTransportJob
->kill( KJob::EmitResult
);
665 //-----------------------------------------------------------------------------
666 void KMSender::slotResult( KJob
*job
)
668 assert( mTransportJob
== job
);
670 mSendProcStarted
= false;
673 QString errString
= job
->errorString();
675 if ( mSendAborted
) {
676 // sending of message aborted
678 mCurrentMsg
->setTransferInProgress( false );
679 if ( mOutboxFolder
) {
680 mOutboxFolder
->unGetMsg( mFailedMessages
);
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",
691 if (!errString
.isEmpty()) KMessageBox::error(0,msg
);
692 setStatusMsg( i18n( "Sending aborted." ) );
694 if ( job
->error() ) {
696 mCurrentMsg
->setTransferInProgress( false );
698 if ( mOutboxFolder
) {
699 mOutboxFolder
->unGetMsg( 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>"
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>",
717 res
= KMessageBox::warningYesNo( 0, msg
,
718 i18n( "Continue Sending" ), KGuiItem(i18n( "&Continue Sending" )),
719 KGuiItem(i18n("&Abort Sending")) );
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",
728 KMessageBox::error(0,msg
);
730 if (res
== KMessageBox::Yes
) {
735 setStatusMsg( i18n( "Sending aborted." ) );
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
)
767 MessageStatus status
;
768 aMsg
->getLink( n
, &msn
, status
);
769 if ( !msn
|| status
.isOfUnknownStatus() ) {
774 KMFolder
*folder
= 0;
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
) );
785 folder
->setStatus( index
, status
);
788 kWarning() <<"Cannot update linked message, it could not be found!";
793 #include "kmsender.moc"