00001
00002
00003
#include <config.h>
00004
00005
#include "kmsender.h"
00006
00007
#include <kmime_header_parsing.h>
00008
using namespace KMime::Types;
00009
00010
#include <kio/passdlg.h>
00011
#include <kio/scheduler.h>
00012
#include <kapplication.h>
00013
#include <kmessagebox.h>
00014
#include <kdeversion.h>
00015
#include <klocale.h>
00016
#include <kdebug.h>
00017
#include <kconfig.h>
00018
00019
#include <assert.h>
00020
#include <stdio.h>
00021
#include <unistd.h>
00022
#include <sys/types.h>
00023
#include <sys/stat.h>
00024
#include <sys/wait.h>
00025
#include "kmfiltermgr.h"
00026
00027
#include "kcursorsaver.h"
00028
#include <libkpimidentities/identity.h>
00029
#include <libkpimidentities/identitymanager.h>
00030
#include "progressmanager.h"
00031
#include "kmaccount.h"
00032
#include "kmtransport.h"
00033
#include "kmfolderindex.h"
00034
#include "kmfoldermgr.h"
00035
#include "kmmsgdict.h"
00036
#include "kmmsgpart.h"
00037
#include "protocols.h"
00038
#include "kmcommands.h"
00039
#include <mimelib/mediatyp.h>
00040
00041
#define SENDER_GROUP "sending mail"
00042
00043
00044 KMSender::KMSender()
00045 : mOutboxFolder( 0 ), mSentFolder( 0 )
00046 {
00047 mPrecommand = 0;
00048 mSendProc = 0;
00049 mSendProcStarted = FALSE;
00050 mSendInProgress = FALSE;
00051 mCurrentMsg = 0;
00052 mTransportInfo =
new KMTransportInfo();
00053 readConfig();
00054 mSendAborted =
false;
00055 mSentMessages = 0;
00056 mTotalMessages = 0;
00057 mFailedMessages = 0;
00058 mSentBytes = 0;
00059 mTotalBytes = 0;
00060 mProgressItem = 0;
00061 }
00062
00063
00064
00065 KMSender::~KMSender()
00066 {
00067 writeConfig(FALSE);
00068
delete mSendProc;
00069
delete mPrecommand;
00070
delete mTransportInfo;
00071 }
00072
00073
00074
void KMSender::setStatusMsg(
const QString &msg)
00075 {
00076
if ( mProgressItem )
00077 mProgressItem->setStatus(msg);
00078 }
00079
00080
00081
void KMSender::readConfig(
void)
00082 {
00083
QString str;
00084 KConfigGroup config(KMKernel::config(), SENDER_GROUP);
00085
00086 mSendImmediate = config.readBoolEntry(
"Immediate", TRUE);
00087 mSendQuotedPrintable = config.readBoolEntry(
"Quoted-Printable", TRUE);
00088 }
00089
00090
00091
00092
void KMSender::writeConfig(
bool aWithSync)
00093 {
00094 KConfigGroup config(KMKernel::config(), SENDER_GROUP);
00095
00096 config.writeEntry(
"Immediate", mSendImmediate);
00097 config.writeEntry(
"Quoted-Printable", mSendQuotedPrintable);
00098
00099
if (aWithSync) config.sync();
00100 }
00101
00102
00103
00104
bool KMSender::settingsOk()
const
00105
{
00106
if (KMTransportInfo::availableTransports().isEmpty())
00107 {
00108 KMessageBox::information(0,i18n(
"Please create an account for sending and try again."));
00109
return false;
00110 }
00111
return true;
00112 }
00113
00114
00115
00116
bool KMSender::send(KMMessage* aMsg,
short sendNow)
00117 {
00118
int rc;
00119
00120
00121
if(!aMsg)
00122 {
00123
return false;
00124 }
00125
if (!settingsOk())
return FALSE;
00126
00127
if (aMsg->to().isEmpty())
00128 {
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 aMsg->setTo(
"Undisclosed.Recipients: ;");
00150 }
00151
00152
00153
00154
QString from = aMsg->headerField(
"X-KMail-Redirect-From");
00155
QString msgId = aMsg->msgId();
00156
if( from.isEmpty() || msgId.isEmpty() ) {
00157 msgId = KMMessage::generateMessageId( aMsg->sender() );
00158
00159 aMsg->setMsgId( msgId );
00160 }
00161
00162
if (sendNow==-1) sendNow = mSendImmediate;
00163
00164 kmkernel->outboxFolder()->open();
00165 aMsg->setStatus(KMMsgStatusQueued);
00166
00167 rc = kmkernel->outboxFolder()->addMsg(aMsg);
00168
if (rc)
00169 {
00170 KMessageBox::information(0,i18n(
"Cannot add message to outbox folder"));
00171
return FALSE;
00172 }
00173
00174
00175 kmkernel->outboxFolder()->unGetMsg( kmkernel->outboxFolder()->count() - 1 );
00176
00177
if (sendNow && !mSendInProgress) rc = sendQueued();
00178
else rc = TRUE;
00179 kmkernel->outboxFolder()->close();
00180
00181
return rc;
00182 }
00183
00184
00185
00186
void KMSender::outboxMsgAdded(
int idx)
00187 {
00188 ++mTotalMessages;
00189 KMMsgBase* msg = kmkernel->outboxFolder()->getMsgBase(idx);
00190 Q_ASSERT(msg);
00191
if ( msg )
00192 mTotalBytes += msg->msgSize();
00193 }
00194
00195
00196
00197
bool KMSender::sendQueued(
void)
00198 {
00199
if (!settingsOk())
return FALSE;
00200
00201
if (mSendInProgress)
00202 {
00203
return FALSE;
00204 }
00205
00206
00207 mOutboxFolder = kmkernel->outboxFolder();
00208 mOutboxFolder->open();
00209 mTotalMessages = mOutboxFolder->count();
00210
if (mTotalMessages == 0) {
00211
00212 mOutboxFolder->close();
00213 mOutboxFolder = 0;
00214
return TRUE;
00215 }
00216 mTotalBytes = 0;
00217
for(
int i = 0 ; i<mTotalMessages ; ++i )
00218 mTotalBytes += mOutboxFolder->getMsgBase(i)->msgSize();
00219
00220 connect( mOutboxFolder, SIGNAL(msgAdded(
int)),
00221
this, SLOT(outboxMsgAdded(
int)) );
00222 mCurrentMsg = 0;
00223
00224 mSentFolder = kmkernel->sentFolder();
00225 mSentFolder->open();
00226 kmkernel->filterMgr()->ref();
00227
00228
00229 doSendMsg();
00230
return TRUE;
00231 }
00232
00233
00234
void KMSender::emitProgressInfo(
int currentFileProgress )
00235 {
00236
int percent = (mTotalBytes) ? ( 100 * (mSentBytes+currentFileProgress) / mTotalBytes ) : 0;
00237
if (percent > 100) percent = 100;
00238 mProgressItem->setProgress(percent);
00239 }
00240
00241
00242
void KMSender::doSendMsg()
00243 {
00244
if (!kmkernel)
00245
return;
00246
00247
KMFolder *sentFolder = 0, *imapSentFolder = 0;
00248
bool someSent = mCurrentMsg;
00249
int rc;
00250
if (someSent) {
00251 mSentMessages++;
00252 mSentBytes += mCurrentMsg->msgSize();
00253 }
00254
00255
00256
if (mCurrentMsg && kmkernel->filterMgr())
00257 {
00258 mCurrentMsg->setTransferInProgress( FALSE );
00259
if( mCurrentMsg->hasUnencryptedMsg() ) {
00260 kdDebug(5006) <<
"KMSender::doSendMsg() post-processing: replace mCurrentMsg body by unencryptedMsg data" << endl;
00261
00262 mCurrentMsg->deleteBodyParts();
00263
00264 KMMessage & newMsg( *mCurrentMsg->unencryptedMsg() );
00265 mCurrentMsg->dwContentType() = newMsg.dwContentType();
00266 mCurrentMsg->setContentTransferEncodingStr( newMsg.contentTransferEncodingStr() );
00267
QCString newDispo = newMsg.headerField(
"Content-Disposition").latin1();
00268
if( newDispo.isEmpty() )
00269 mCurrentMsg->removeHeaderField(
"Content-Disposition" );
00270
else
00271 mCurrentMsg->setHeaderField(
"Content-Disposition", newDispo );
00272
00273 mCurrentMsg->setBody( newMsg.body() );
00274
00275 KMMessagePart msgPart;
00276
for(
int i = 0; i < newMsg.numBodyParts(); ++i ) {
00277 newMsg.bodyPart( i, &msgPart );
00278 mCurrentMsg->addBodyPart( &msgPart );
00279 }
00280 }
00281 mCurrentMsg->setStatus(KMMsgStatusSent);
00282 mCurrentMsg->setStatus(KMMsgStatusRead);
00283
00284
const KPIM::Identity &
id = kmkernel->identityManager()
00285 ->identityForUoidOrDefault( mCurrentMsg->headerField(
"X-KMail-Identity" ).stripWhiteSpace().toUInt() );
00286
if ( !mCurrentMsg->fcc().isEmpty() )
00287 {
00288 sentFolder = kmkernel->folderMgr()->findIdString( mCurrentMsg->fcc() );
00289
if ( sentFolder == 0 )
00290
00291 sentFolder =
00292 kmkernel->dimapFolderMgr()->findIdString( mCurrentMsg->fcc() );
00293
if ( sentFolder == 0 )
00294 imapSentFolder =
00295 kmkernel->imapFolderMgr()->findIdString( mCurrentMsg->fcc() );
00296 }
00297
else if ( !
id.fcc().isEmpty() )
00298 {
00299 sentFolder = kmkernel->folderMgr()->findIdString(
id.fcc() );
00300
if ( sentFolder == 0 )
00301
00302 sentFolder = kmkernel->dimapFolderMgr()->findIdString(
id.fcc() );
00303
if ( sentFolder == 0 )
00304 imapSentFolder = kmkernel->imapFolderMgr()->findIdString(
id.fcc() );
00305 }
00306
if (imapSentFolder && imapSentFolder->
noContent()) imapSentFolder = 0;
00307
00308
if ( sentFolder == 0 )
00309 sentFolder = kmkernel->sentFolder();
00310
00311
if ( sentFolder ) {
00312 rc = sentFolder->
open();
00313
if (rc != 0) {
00314 cleanup();
00315
return;
00316 }
00317 }
00318
00319
00320
00321
00322
if ( mCurrentMsg->parent() ) mCurrentMsg->parent()->quiet(
true );
00323
int processResult = kmkernel->filterMgr()->process(mCurrentMsg,KMFilterMgr::Outbound);
00324
if ( mCurrentMsg->parent() ) mCurrentMsg->parent()->quiet(
false );
00325
00326
00327
switch (processResult) {
00328
case 2:
00329 perror(
"Critical error: Unable to process sent mail (out of space?)");
00330 KMessageBox::information(0, i18n(
"Critical error: "
00331
"Unable to process sent mail (out of space?)"
00332
"Moving failing message to \"sent-mail\" folder."));
00333 sentFolder->
moveMsg(mCurrentMsg);
00334 sentFolder->
close();
00335 cleanup();
00336
return;
00337
case 1:
00338
if (sentFolder->
moveMsg(mCurrentMsg) != 0)
00339 {
00340 KMessageBox::error(0, i18n(
"Moving the sent message \"%1\" from the "
00341
"\"outbox\" to the \"sent-mail\" folder failed.\n"
00342
"Possible reasons are lack of disk space or write permission. "
00343
"Please try to fix the problem and move the message manually.")
00344 .arg(mCurrentMsg->subject()));
00345 cleanup();
00346
return;
00347 }
00348
if (imapSentFolder) {
00349
00350 KMCommand *command =
new KMMoveCommand( imapSentFolder, mCurrentMsg );
00351 command->keepFolderOpen( sentFolder );
00352 command->start();
00353 }
00354
default:
00355
break;
00356 }
00357 setStatusByLink( mCurrentMsg );
00358
if (mCurrentMsg->parent() && !imapSentFolder) {
00359
00360
00361 assert( mCurrentMsg->parent()->find( mCurrentMsg )
00362 == mCurrentMsg->parent()->count() - 1 );
00363
00364 mCurrentMsg->parent()->unGetMsg( mCurrentMsg->parent()->count() -1 );
00365 }
00366
00367 mCurrentMsg = 0;
00368 }
00369
00370
00371 mCurrentMsg = mOutboxFolder->getMsg(mFailedMessages);
00372
if ( mCurrentMsg && !mCurrentMsg->transferInProgress() &&
00373 mCurrentMsg->sender().isEmpty() ) {
00374
00375
00376
00377
const KPIM::Identity &
id = kmkernel->identityManager()
00378 ->identityForUoidOrDefault( mCurrentMsg->headerField(
"X-KMail-Identity" ).stripWhiteSpace().toUInt() );
00379
if ( !
id.emailAddr().isEmpty() ) {
00380 mCurrentMsg->setFrom(
id.fullEmailAddr() );
00381 }
00382
else if ( !kmkernel->identityManager()->defaultIdentity().emailAddr().isEmpty() ) {
00383 mCurrentMsg->setFrom( kmkernel->identityManager()->defaultIdentity().fullEmailAddr() );
00384 }
00385
else {
00386 KMessageBox::sorry( 0, i18n(
"It's not possible to send messages "
00387
"without specifying a sender address.\n"
00388
"Please set the email address of "
00389
"identity '%1' in the Identities "
00390
"section of the configuration dialog "
00391
"and then try again." )
00392 .arg(
id.identityName() ) );
00393 mOutboxFolder->unGetMsg( mFailedMessages );
00394 mCurrentMsg = 0;
00395 }
00396 }
00397
if (!mCurrentMsg || mCurrentMsg->transferInProgress())
00398 {
00399
00400
if (mCurrentMsg && mCurrentMsg->transferInProgress())
00401 mCurrentMsg = 0;
00402
00403
if ( sentFolder != 0 )
00404 sentFolder->
close();
00405
if ( someSent ) {
00406
if ( mSentMessages == mTotalMessages ) {
00407 setStatusMsg(i18n(
"%n queued message successfully sent.",
00408
"%n queued messages successfully sent.",
00409 mSentMessages));
00410 }
else {
00411 setStatusMsg(i18n(
"%1 of %2 queued messages successfully sent.")
00412 .arg(mSentMessages).arg( mTotalMessages ));
00413 }
00414 }
00415 cleanup();
00416
return;
00417 }
00418 mCurrentMsg->setTransferInProgress( TRUE );
00419
00420
00421
if (!mSendInProgress)
00422 {
00423 Q_ASSERT( !mProgressItem );
00424 mProgressItem = KPIM::ProgressManager::createProgressItem(
00425
"Sender",
00426 i18n(
"Sending messages" ),
00427 i18n(
"Initiating sender process..."),
00428
true );
00429 connect( mProgressItem, SIGNAL( progressItemCanceled( ProgressItem* ) ),
00430
this, SLOT( slotAbortSend() ) );
00431 kapp->ref();
00432 mSendInProgress = TRUE;
00433 }
00434
00435
QString msgTransport = mCurrentMsg->headerField(
"X-KMail-Transport");
00436
if (msgTransport.isEmpty())
00437 {
00438
QStringList sl = KMTransportInfo::availableTransports();
00439
if (!sl.isEmpty()) msgTransport = sl[0];
00440 }
00441
if (!mSendProc || msgTransport != mMethodStr) {
00442
if (mSendProcStarted && mSendProc) {
00443 mSendProc->finish(
true);
00444 mSendProcStarted = FALSE;
00445 }
00446
00447 mSendProc = createSendProcFromString(msgTransport);
00448 mMethodStr = msgTransport;
00449
00450
if( mTransportInfo->encryption ==
"TLS" || mTransportInfo->encryption ==
"SSL" )
00451 mProgressItem->setUsesCrypto(
true );
00452
00453
if (!mSendProc)
00454 sendProcStarted(
false);
00455
else {
00456 connect(mSendProc, SIGNAL(idle()), SLOT(slotIdle()));
00457 connect(mSendProc, SIGNAL(started(
bool)), SLOT(sendProcStarted(
bool)));
00458
00459
00460
if (!mTransportInfo->precommand.isEmpty())
00461 {
00462 setStatusMsg(i18n(
"Executing precommand %1")
00463 .arg(mTransportInfo->precommand));
00464 mPrecommand =
new KMPrecommand(mTransportInfo->precommand);
00465 connect(mPrecommand, SIGNAL(finished(
bool)),
00466 SLOT(slotPrecommandFinished(
bool)));
00467
if (!mPrecommand->start())
00468 {
00469
delete mPrecommand;
00470 mPrecommand = 0;
00471 }
00472
return;
00473 }
00474
00475 mSendProc->start();
00476 }
00477 }
00478
else if (!mSendProcStarted)
00479 mSendProc->start();
00480
else
00481 doSendMsgAux();
00482 }
00483
00484
00485
00486
void KMSender::sendProcStarted(
bool success)
00487 {
00488
if (!success) {
00489
if (mSendProc)
00490 mSendProc->finish(
true);
00491
else
00492 setStatusMsg(i18n(
"Unrecognized transport protocol. Unable to send message."));
00493 mSendProc = 0;
00494 mSendProcStarted =
false;
00495 cleanup();
00496
return;
00497 }
00498 doSendMsgAux();
00499 }
00500
00501
00502
00503
void KMSender::doSendMsgAux()
00504 {
00505 mSendProcStarted = TRUE;
00506
00507
00508
00509 mSendProc->preSendInit();
00510 setStatusMsg(i18n(
"%3: subject of message",
"Sending message %1 of %2: %3")
00511 .arg(mSentMessages+mFailedMessages+1).arg(mTotalMessages)
00512 .arg(mCurrentMsg->subject()));
00513
if (!mSendProc->send(mCurrentMsg))
00514 {
00515 cleanup();
00516 setStatusMsg(i18n(
"Failed to send (some) queued messages."));
00517
return;
00518 }
00519
00520
00521 }
00522
00523
00524
00525
void KMSender::cleanup(
void)
00526 {
00527 kdDebug(5006) << k_funcinfo << endl;
00528
if (mSendProc && mSendProcStarted) mSendProc->finish(
true);
00529 mSendProc = 0;
00530 mSendProcStarted = FALSE;
00531
if (mSendInProgress) kapp->deref();
00532 mSendInProgress = FALSE;
00533
if (mCurrentMsg)
00534 {
00535 mCurrentMsg->setTransferInProgress( FALSE );
00536 mCurrentMsg = 0;
00537 }
00538
if ( mSentFolder ) {
00539 mSentFolder->close();
00540 mSentFolder = 0;
00541 }
00542
if ( mOutboxFolder ) {
00543 disconnect( mOutboxFolder, SIGNAL(msgAdded(
int)),
00544
this, SLOT(outboxMsgAdded(
int)) );
00545 mOutboxFolder->close();
00546
if ( mOutboxFolder->count(
true ) == 0 ) {
00547 mOutboxFolder->expunge();
00548 }
00549
else if ( mOutboxFolder->needsCompacting() ) {
00550 mOutboxFolder->compact( KMFolder::CompactSilentlyNow );
00551 }
00552 mOutboxFolder = 0;
00553 }
00554
00555 mSendAborted =
false;
00556 mSentMessages = 0;
00557 mFailedMessages = 0;
00558 mSentBytes = 0;
00559
if ( mProgressItem )
00560 mProgressItem->setComplete();
00561 mProgressItem = 0;
00562 kmkernel->filterMgr()->deref();
00563 }
00564
00565
00566
00567
void KMSender::slotAbortSend()
00568 {
00569 mSendAborted =
true;
00570
delete mPrecommand;
00571 mPrecommand = 0;
00572
if (mSendProc) mSendProc->abort();
00573 }
00574
00575
00576
void KMSender::slotIdle()
00577 {
00578 assert(mSendProc != 0);
00579
00580
QString msg;
00581
QString errString;
00582
if (mSendProc)
00583 errString = mSendProc->message();
00584
00585
if (mSendAborted) {
00586
00587 msg = i18n(
"Sending aborted:\n%1\n"
00588
"The message will stay in the 'outbox' folder until you either "
00589
"fix the problem (e.g. a broken address) or remove the message "
00590
"from the 'outbox' folder.\n"
00591
"The following transport protocol was used:\n %2")
00592 .arg(errString)
00593 .arg(mMethodStr);
00594
if (!errString.isEmpty()) KMessageBox::error(0,msg);
00595 setStatusMsg( i18n(
"Sending aborted." ) );
00596 }
else {
00597
if (!mSendProc->sendOk()) {
00598 mCurrentMsg->setTransferInProgress(
false );
00599 mCurrentMsg = 0;
00600 mFailedMessages++;
00601
00602
if (!errString.isEmpty()) {
00603
int res = KMessageBox::Yes;
00604
if (mSentMessages+mFailedMessages != mTotalMessages) {
00605 msg = i18n(
"<p>Sending failed:</p>"
00606
"<p>%1</p>"
00607
"<p>The message will stay in the 'outbox' folder until you either "
00608
"fix the problem (e.g. a broken address) or remove the message "
00609
"from the 'outbox' folder.</p>"
00610
"<p>The following transport protocol was used: %2</p>"
00611
"<p>Do you want me to continue sending the remaining messages?</p>")
00612 .arg(errString)
00613 .arg(mMethodStr);
00614 res = KMessageBox::warningYesNo( 0 , msg ,
00615 i18n(
"Continue Sending" ), i18n(
"&Continue Sending" ),
00616 i18n(
"&Abort Sending") );
00617 }
else {
00618 msg = i18n(
"Sending failed:\n%1\n"
00619
"The message will stay in the 'outbox' folder until you either "
00620
"fix the problem (e.g. a broken address) or remove the message "
00621
"from the 'outbox' folder.\n"
00622
"The following transport protocol was used:\n %2")
00623 .arg(errString)
00624 .arg(mMethodStr);
00625 KMessageBox::error(0,msg);
00626 }
00627
if (res == KMessageBox::Yes) {
00628
00629 doSendMsg();
00630
return;
00631 }
else {
00632 setStatusMsg( i18n(
"Sending aborted." ) );
00633 }
00634 }
00635 }
else {
00636
00637 doSendMsg();
00638
return;
00639 }
00640 }
00641 mSendProc->finish(
true);
00642 mSendProc = 0;
00643 mSendProcStarted =
false;
00644
00645 cleanup();
00646 }
00647
00648
00649
00650
void KMSender::slotPrecommandFinished(
bool normalExit)
00651 {
00652
delete mPrecommand;
00653 mPrecommand = 0;
00654
if (normalExit) mSendProc->start();
00655
else slotIdle();
00656 }
00657
00658
00659
00660
void KMSender::setSendImmediate(
bool aSendImmediate)
00661 {
00662 mSendImmediate = aSendImmediate;
00663 }
00664
00665
00666
00667
void KMSender::setSendQuotedPrintable(
bool aSendQuotedPrintable)
00668 {
00669 mSendQuotedPrintable = aSendQuotedPrintable;
00670 }
00671
00672
00673
00674 KMSendProc* KMSender::createSendProcFromString(
QString transport)
00675 {
00676 mTransportInfo->type = QString::null;
00677
int nr = KMTransportInfo::findTransport(transport);
00678
if (nr)
00679 {
00680 mTransportInfo->readConfig(nr);
00681 }
else {
00682
if (transport.startsWith(
"smtp://"))
00683 {
00684 mTransportInfo->type =
"smtp";
00685 mTransportInfo->auth = FALSE;
00686 mTransportInfo->encryption =
"NONE";
00687
QString serverport = transport.mid(7);
00688
int colon = serverport.find(
':');
00689
if (colon != -1) {
00690 mTransportInfo->host = serverport.left(colon);
00691 mTransportInfo->port = serverport.mid(colon + 1);
00692 }
else {
00693 mTransportInfo->host = serverport;
00694 mTransportInfo->port =
"25";
00695 }
00696 }
else
00697
if (transport.startsWith(
"smtps://"))
00698 {
00699 mTransportInfo->type =
"smtps";
00700 mTransportInfo->auth = FALSE;
00701 mTransportInfo->encryption =
"ssl";
00702
QString serverport = transport.mid(7);
00703
int colon = serverport.find(
':');
00704
if (colon != -1) {
00705 mTransportInfo->host = serverport.left(colon);
00706 mTransportInfo->port = serverport.mid(colon + 1);
00707 }
else {
00708 mTransportInfo->host = serverport;
00709 mTransportInfo->port =
"465";
00710 }
00711 }
00712
else if (transport.startsWith(
"file://"))
00713 {
00714 mTransportInfo->type =
"sendmail";
00715 mTransportInfo->host = transport.mid(7);
00716 }
00717 }
00718
00719
while (mTransportInfo->host.endsWith(
"/")) {
00720 mTransportInfo->host.truncate(mTransportInfo->host.length()-1);
00721 }
00722
00723
00724
if (mTransportInfo->type ==
"sendmail")
00725
return new KMSendSendmail(
this);
00726
if (mTransportInfo->type ==
"smtp" || mTransportInfo->type ==
"smtps")
00727
return new KMSendSMTP(
this);
00728
00729
return 0L;
00730 }
00731
00732
00733
void KMSender::setStatusByLink(
const KMMessage *aMsg)
00734 {
00735
int n = 0;
00736
while (1) {
00737 ulong msn;
00738 KMMsgStatus status;
00739 aMsg->getLink(n, &msn, &status);
00740
if (!msn || !status)
00741
break;
00742 n++;
00743
00744
KMFolder *folder;
00745
int index;
00746 kmkernel->msgDict()->getLocation(msn, &folder, &index);
00747
00748
if (folder) {
00749 folder->
open();
00750
if ( status == KMMsgStatusDeleted ) {
00751
00752 KMDeleteMsgCommand *cmd =
00753
new KMDeleteMsgCommand( folder, folder->
getMsg( index ) );
00754 cmd->start();
00755 }
else {
00756 folder->
setStatus(index, status);
00757 }
00758 folder->
close();
00759 }
00760 }
00761 }
00762
00763
00764
00765 KMSendProc::KMSendProc(KMSender* aSender):
QObject()
00766 {
00767 mSender = aSender;
00768 preSendInit();
00769 }
00770
00771
00772
void KMSendProc::preSendInit(
void)
00773 {
00774 mSending = FALSE;
00775 mSendOk = FALSE;
00776 mMsg = QString::null;
00777 }
00778
00779
00780
void KMSendProc::failed(
const QString &aMsg)
00781 {
00782 mSending = FALSE;
00783 mSendOk = FALSE;
00784 mMsg = aMsg;
00785 }
00786
00787
00788
void KMSendProc::start(
void)
00789 {
00790 emit started(
true);
00791 }
00792
00793
00794
bool KMSendProc::finish(
bool destructive)
00795 {
00796
if (destructive) deleteLater();
00797
return TRUE;
00798 }
00799
00800
00801
void KMSendProc::statusMsg(
const QString& aMsg)
00802 {
00803
if (mSender) mSender->setStatusMsg(aMsg);
00804 }
00805
00806
00807
bool KMSendProc::addRecipients(
const AddrSpecList & al )
00808 {
00809
for ( AddrSpecList::const_iterator it = al.begin() ; it != al.end() ; ++it )
00810
if ( !addOneRecipient( (*it).asString() ) )
00811
return false;
00812
return true;
00813 }
00814
00815
00816
00817
00818 KMSendSendmail::KMSendSendmail(KMSender* aSender):
00819 KMSendProc(aSender)
00820 {
00821 mMailerProc = 0;
00822 }
00823
00824
00825 KMSendSendmail::~KMSendSendmail()
00826 {
00827
delete mMailerProc;
00828 }
00829
00830
00831
void KMSendSendmail::start(
void)
00832 {
00833
if (mSender->transportInfo()->host.isEmpty())
00834 {
00835
QString str = i18n(
"Please specify a mailer program in the settings.");
00836
QString msg;
00837 msg = i18n(
"Sending failed:\n%1\n"
00838
"The message will stay in the 'outbox' folder and will be resent.\n"
00839
"Please remove it from there if you do not want the message to "
00840
"be resent.\n"
00841
"The following transport protocol was used:\n %2")
00842 .arg(str +
"\n")
00843 .arg(
"sendmail://");
00844 KMessageBox::information(0,msg);
00845 emit started(
false);
00846
return;
00847 }
00848
00849
if (!mMailerProc)
00850 {
00851 mMailerProc =
new KProcess;
00852 assert(mMailerProc != 0);
00853 connect(mMailerProc,SIGNAL(processExited(KProcess*)),
00854
this, SLOT(sendmailExited(KProcess*)));
00855 connect(mMailerProc,SIGNAL(wroteStdin(KProcess*)),
00856
this, SLOT(wroteStdin(KProcess*)));
00857 connect(mMailerProc,SIGNAL(receivedStderr(KProcess*,
char*,
int)),
00858
this, SLOT(receivedStderr(KProcess*,
char*,
int)));
00859 }
00860 emit started(
true);
00861 }
00862
00863
00864
bool KMSendSendmail::finish(
bool destructive)
00865 {
00866
delete mMailerProc;
00867 mMailerProc = 0;
00868
if (destructive)
00869 deleteLater();
00870
return TRUE;
00871 }
00872
00873
00874
void KMSendSendmail::abort()
00875 {
00876
delete mMailerProc;
00877 mMailerProc = 0;
00878 mSendOk =
false;
00879 mMsgStr = 0;
00880 idle();
00881 }
00882
00883
00884
00885
bool KMSendSendmail::send(KMMessage* aMsg)
00886 {
00887
QString bccStr;
00888
00889 mMailerProc->clearArguments();
00890 *mMailerProc << mSender->transportInfo()->host;
00891 *mMailerProc <<
"-i";
00892 *mMailerProc <<
"-f";
00893 *mMailerProc << aMsg->sender().latin1();
00894
00895
if( !aMsg->headerField(
"X-KMail-Recipients").isEmpty() ) {
00896
00897
00898 addRecipients(aMsg->extractAddrSpecs(
"X-KMail-Recipients"));
00899 aMsg->removeHeaderField(
"X-KMail-Recipients" );
00900 }
else {
00901 addRecipients(aMsg->extractAddrSpecs(
"To"));
00902 addRecipients(aMsg->extractAddrSpecs(
"Cc"));
00903 addRecipients(aMsg->extractAddrSpecs(
"Bcc"));
00904 }
00905
00906 mMsgStr = aMsg->asSendableString();
00907
00908
if (!mMailerProc->start(KProcess::NotifyOnExit,KProcess::All))
00909 {
00910 KMessageBox::information(0,i18n(
"Failed to execute mailer program %1")
00911 .arg(mSender->transportInfo()->host));
00912
return FALSE;
00913 }
00914 mMsgPos = mMsgStr.data();
00915 mMsgRest = mMsgStr.length();
00916 wroteStdin(mMailerProc);
00917
00918
return TRUE;
00919 }
00920
00921
00922
00923
void KMSendSendmail::wroteStdin(KProcess *proc)
00924 {
00925
char* str;
00926
int len;
00927
00928 assert(proc!=0);
00929 Q_UNUSED( proc );
00930
00931 str = mMsgPos;
00932 len = (mMsgRest>1024 ? 1024 : mMsgRest);
00933
00934
if (len <= 0)
00935 {
00936 mMailerProc->closeStdin();
00937 }
00938
else
00939 {
00940 mMsgRest -= len;
00941 mMsgPos += len;
00942 mMailerProc->writeStdin(str,len);
00943
00944
00945 }
00946 }
00947
00948
00949
00950
void KMSendSendmail::receivedStderr(KProcess *proc,
char *buffer,
int buflen)
00951 {
00952 assert(proc!=0);
00953 Q_UNUSED( proc );
00954 mMsg.replace(mMsg.length(), buflen, buffer);
00955 }
00956
00957
00958
00959
void KMSendSendmail::sendmailExited(KProcess *proc)
00960 {
00961 assert(proc!=0);
00962 mSendOk = (proc->normalExit() && proc->exitStatus()==0);
00963
if (!mSendOk) failed(i18n(
"Sendmail exited abnormally."));
00964 mMsgStr = 0;
00965 emit idle();
00966 }
00967
00968
00969
00970
bool KMSendSendmail::addOneRecipient(
const QString& aRcpt)
00971 {
00972 assert(mMailerProc!=0);
00973
if (!aRcpt.isEmpty()) *mMailerProc << aRcpt;
00974
return TRUE;
00975 }
00976
00977
00978
00979
00980
00981
00982 KMSendSMTP::KMSendSMTP(KMSender *sender)
00983 : KMSendProc(sender),
00984 mInProcess(false),
00985 mJob(0),
00986 mSlave(0)
00987 {
00988 KIO::Scheduler::connect(SIGNAL(slaveError(KIO::Slave *,
int,
00989
const QString &)),
this, SLOT(slaveError(KIO::Slave *,
int,
00990
const QString &)));
00991 }
00992
00993 KMSendSMTP::~KMSendSMTP()
00994 {
00995
if (mJob) mJob->kill();
00996 }
00997
00998
bool KMSendSMTP::send(KMMessage *aMsg)
00999 {
01000 KMTransportInfo *ti = mSender->transportInfo();
01001 assert(aMsg != 0);
01002
01003
const QString sender = aMsg->sender();
01004
if ( sender.isEmpty() )
01005
return false;
01006
01007
01008 mQuery =
"headers=0&from=";
01009 mQuery += KURL::encode_string( sender );
01010
01011
01012
if( !aMsg->headerField(
"X-KMail-Recipients").isEmpty() ) {
01013
01014
01015 mQueryField =
"&to=";
01016
if( !addRecipients( aMsg->extractAddrSpecs(
"X-KMail-Recipients")) ) {
01017
return FALSE;
01018 }
01019 aMsg->removeHeaderField(
"X-KMail-Recipients" );
01020 }
else {
01021 mQueryField =
"&to=";
01022
if(!addRecipients(aMsg->extractAddrSpecs(
"To")))
01023 {
01024
return FALSE;
01025 }
01026
01027
if(!aMsg->cc().isEmpty())
01028 {
01029 mQueryField =
"&cc=";
01030
if(!addRecipients(aMsg->extractAddrSpecs(
"Cc")))
return FALSE;
01031 }
01032
01033
QString bccStr = aMsg->bcc();
01034
if(!bccStr.isEmpty())
01035 {
01036 mQueryField =
"&bcc=";
01037
if (!addRecipients(aMsg->extractAddrSpecs(
"Bcc")))
return FALSE;
01038 }
01039 }
01040
01041
if (ti->specifyHostname)
01042 mQuery +=
"&hostname=" + KURL::encode_string(ti->localHostname);
01043
01044
if ( !kmkernel->msgSender()->sendQuotedPrintable() )
01045 mQuery +=
"&body=8bit";
01046
01047 KURL destination;
01048
01049 destination.setProtocol((ti->encryption ==
"SSL") ? SMTPS_PROTOCOL : SMTP_PROTOCOL);
01050 destination.setHost(ti->host);
01051 destination.setPort(ti->port.toUShort());
01052
01053
if (ti->auth)
01054 {
01055
if(ti->user.isEmpty() || ti->pass.isEmpty())
01056 {
01057
bool b = FALSE;
01058
int result;
01059
01060
KCursorSaver idle(KBusyPtr::idle());
01061 result = KIO::PasswordDialog::getNameAndPassword(ti->user, ti->pass,
01062 &b, i18n(
"You need to supply a username and a password to use this "
01063
"SMTP server."), FALSE, QString::null, ti->name, QString::null);
01064
01065
if ( result != QDialog::Accepted )
01066 {
01067 abort();
01068
return FALSE;
01069 }
01070
if (
int id = KMTransportInfo::findTransport(ti->name))
01071 ti->writeConfig(
id);
01072 }
01073 destination.setUser(ti->user);
01074 destination.setPass(ti->pass);
01075 }
01076
01077
if (!mSlave || !mInProcess)
01078 {
01079 KIO::MetaData slaveConfig;
01080 slaveConfig.insert(
"tls", (ti->encryption ==
"TLS") ?
"on" :
"off");
01081
if (ti->auth) slaveConfig.insert(
"sasl", ti->authType);
01082 mSlave = KIO::Scheduler::getConnectedSlave(destination, slaveConfig);
01083 }
01084
01085
if (!mSlave)
01086 {
01087 abort();
01088
return false;
01089 }
01090
01091
01092 mMessage = aMsg->asSendableString();
01093 mMessageLength = mMessage.length();
01094 mMessageOffset = 0;
01095
01096
if ( mMessageLength )
01097
01098
01099 mQuery +=
"&size=" + QString::number( qRound( mMessageLength * 1.05 ) );
01100
01101 destination.setPath(
"/send");
01102 destination.setQuery(mQuery);
01103 mQuery = QString::null;
01104
01105
if ((mJob = KIO::put(destination, -1,
false,
false,
false)))
01106 {
01107 mJob->addMetaData(
"lf2crlf+dotstuff",
"slave" );
01108 KIO::Scheduler::assignJobToSlave(mSlave, mJob);
01109 connect(mJob, SIGNAL(result(KIO::Job *)),
this, SLOT(result(KIO::Job *)));
01110 connect(mJob, SIGNAL(dataReq(KIO::Job *,
QByteArray &)),
01111
this, SLOT(dataReq(KIO::Job *,
QByteArray &)));
01112 mSendOk =
true;
01113 mInProcess =
true;
01114
return mSendOk;
01115 }
01116
else
01117 {
01118 abort();
01119
return false;
01120 }
01121 }
01122
01123
void KMSendSMTP::abort()
01124 {
01125 finish(
false);
01126 emit idle();
01127 }
01128
01129
bool KMSendSMTP::finish(
bool b)
01130 {
01131
if(mJob)
01132 {
01133 mJob->kill(TRUE);
01134 mJob = 0;
01135 mSlave = 0;
01136 }
01137
01138
if (mSlave)
01139 {
01140 KIO::Scheduler::disconnectSlave(mSlave);
01141 mSlave = 0;
01142 }
01143
01144 mInProcess =
false;
01145
return KMSendProc::finish(b);
01146 }
01147
01148
bool KMSendSMTP::addOneRecipient(
const QString& _addr)
01149 {
01150
if(!_addr.isEmpty())
01151 mQuery += mQueryField + KURL::encode_string(_addr);
01152
01153
return true;
01154 }
01155
01156
void KMSendSMTP::dataReq(KIO::Job *,
QByteArray &array)
01157 {
01158
01159
int chunkSize = QMIN( mMessageLength - mMessageOffset, 0x8000 );
01160
if ( chunkSize > 0 ) {
01161 array.duplicate(mMessage.data() + mMessageOffset, chunkSize);
01162 mMessageOffset += chunkSize;
01163 }
else
01164 {
01165 array.resize(0);
01166 mMessage.resize(0);
01167 }
01168 mSender->emitProgressInfo( mMessageOffset );
01169 }
01170
01171
void KMSendSMTP::result(KIO::Job *_job)
01172 {
01173
if (!mJob)
return;
01174 mJob = 0;
01175
01176
if(_job->error())
01177 {
01178 mSendOk =
false;
01179
if (_job->error() == KIO::ERR_SLAVE_DIED) mSlave = 0;
01180 failed(_job->errorString());
01181 abort();
01182 }
else {
01183 emit idle();
01184 }
01185 }
01186
01187
void KMSendSMTP::slaveError(KIO::Slave *aSlave,
int error,
const QString &errorMsg)
01188 {
01189
if (aSlave == mSlave)
01190 {
01191
if (error == KIO::ERR_SLAVE_DIED) mSlave = 0;
01192 mSendOk =
false;
01193 mJob = 0;
01194 failed(KIO::buildErrorString(error, errorMsg));
01195 abort();
01196 }
01197 }
01198
01199
#include "kmsender.moc"