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 folder->
setStatus(index, status);
00751 folder->
close();
00752 }
00753 }
00754 }
00755
00756
00757
00758 KMSendProc::KMSendProc(KMSender* aSender):
QObject()
00759 {
00760 mSender = aSender;
00761 preSendInit();
00762 }
00763
00764
00765
void KMSendProc::preSendInit(
void)
00766 {
00767 mSending = FALSE;
00768 mSendOk = FALSE;
00769 mMsg = QString::null;
00770 }
00771
00772
00773
void KMSendProc::failed(
const QString &aMsg)
00774 {
00775 mSending = FALSE;
00776 mSendOk = FALSE;
00777 mMsg = aMsg;
00778 }
00779
00780
00781
void KMSendProc::start(
void)
00782 {
00783 emit started(
true);
00784 }
00785
00786
00787
bool KMSendProc::finish(
bool destructive)
00788 {
00789
if (destructive) deleteLater();
00790
return TRUE;
00791 }
00792
00793
00794
void KMSendProc::statusMsg(
const QString& aMsg)
00795 {
00796
if (mSender) mSender->setStatusMsg(aMsg);
00797 }
00798
00799
00800
bool KMSendProc::addRecipients(
const AddrSpecList & al )
00801 {
00802
for ( AddrSpecList::const_iterator it = al.begin() ; it != al.end() ; ++it )
00803
if ( !addOneRecipient( (*it).asString() ) )
00804
return false;
00805
return true;
00806 }
00807
00808
00809
00810
00811 KMSendSendmail::KMSendSendmail(KMSender* aSender):
00812 KMSendProc(aSender)
00813 {
00814 mMailerProc = 0;
00815 }
00816
00817
00818 KMSendSendmail::~KMSendSendmail()
00819 {
00820
delete mMailerProc;
00821 }
00822
00823
00824
void KMSendSendmail::start(
void)
00825 {
00826
if (mSender->transportInfo()->host.isEmpty())
00827 {
00828
QString str = i18n(
"Please specify a mailer program in the settings.");
00829
QString msg;
00830 msg = i18n(
"Sending failed:\n%1\n"
00831
"The message will stay in the 'outbox' folder and will be resent.\n"
00832
"Please remove it from there if you do not want the message to "
00833
"be resent.\n"
00834
"The following transport protocol was used:\n %2")
00835 .arg(str +
"\n")
00836 .arg(
"sendmail://");
00837 KMessageBox::information(0,msg);
00838 emit started(
false);
00839
return;
00840 }
00841
00842
if (!mMailerProc)
00843 {
00844 mMailerProc =
new KProcess;
00845 assert(mMailerProc != 0);
00846 connect(mMailerProc,SIGNAL(processExited(KProcess*)),
00847
this, SLOT(sendmailExited(KProcess*)));
00848 connect(mMailerProc,SIGNAL(wroteStdin(KProcess*)),
00849
this, SLOT(wroteStdin(KProcess*)));
00850 connect(mMailerProc,SIGNAL(receivedStderr(KProcess*,
char*,
int)),
00851
this, SLOT(receivedStderr(KProcess*,
char*,
int)));
00852 }
00853 emit started(
true);
00854 }
00855
00856
00857
bool KMSendSendmail::finish(
bool destructive)
00858 {
00859
delete mMailerProc;
00860 mMailerProc = 0;
00861
if (destructive)
00862 deleteLater();
00863
return TRUE;
00864 }
00865
00866
00867
void KMSendSendmail::abort()
00868 {
00869
delete mMailerProc;
00870 mMailerProc = 0;
00871 mSendOk =
false;
00872 mMsgStr = 0;
00873 idle();
00874 }
00875
00876
00877
00878
bool KMSendSendmail::send(KMMessage* aMsg)
00879 {
00880
QString bccStr;
00881
00882 mMailerProc->clearArguments();
00883 *mMailerProc << mSender->transportInfo()->host;
00884 *mMailerProc <<
"-i";
00885 *mMailerProc <<
"-f";
00886 *mMailerProc << aMsg->sender().latin1();
00887
00888
if( !aMsg->headerField(
"X-KMail-Recipients").isEmpty() ) {
00889
00890
00891 addRecipients(aMsg->extractAddrSpecs(
"X-KMail-Recipients"));
00892 aMsg->removeHeaderField(
"X-KMail-Recipients" );
00893 }
else {
00894 addRecipients(aMsg->extractAddrSpecs(
"To"));
00895 addRecipients(aMsg->extractAddrSpecs(
"Cc"));
00896 addRecipients(aMsg->extractAddrSpecs(
"Bcc"));
00897 }
00898
00899 mMsgStr = aMsg->asSendableString();
00900
00901
if (!mMailerProc->start(KProcess::NotifyOnExit,KProcess::All))
00902 {
00903 KMessageBox::information(0,i18n(
"Failed to execute mailer program %1")
00904 .arg(mSender->transportInfo()->host));
00905
return FALSE;
00906 }
00907 mMsgPos = mMsgStr.data();
00908 mMsgRest = mMsgStr.length();
00909 wroteStdin(mMailerProc);
00910
00911
return TRUE;
00912 }
00913
00914
00915
00916
void KMSendSendmail::wroteStdin(KProcess *proc)
00917 {
00918
char* str;
00919
int len;
00920
00921 assert(proc!=0);
00922 Q_UNUSED( proc );
00923
00924 str = mMsgPos;
00925 len = (mMsgRest>1024 ? 1024 : mMsgRest);
00926
00927
if (len <= 0)
00928 {
00929 mMailerProc->closeStdin();
00930 }
00931
else
00932 {
00933 mMsgRest -= len;
00934 mMsgPos += len;
00935 mMailerProc->writeStdin(str,len);
00936
00937
00938 }
00939 }
00940
00941
00942
00943
void KMSendSendmail::receivedStderr(KProcess *proc,
char *buffer,
int buflen)
00944 {
00945 assert(proc!=0);
00946 Q_UNUSED( proc );
00947 mMsg.replace(mMsg.length(), buflen, buffer);
00948 }
00949
00950
00951
00952
void KMSendSendmail::sendmailExited(KProcess *proc)
00953 {
00954 assert(proc!=0);
00955 mSendOk = (proc->normalExit() && proc->exitStatus()==0);
00956
if (!mSendOk) failed(i18n(
"Sendmail exited abnormally."));
00957 mMsgStr = 0;
00958 emit idle();
00959 }
00960
00961
00962
00963
bool KMSendSendmail::addOneRecipient(
const QString& aRcpt)
00964 {
00965 assert(mMailerProc!=0);
00966
if (!aRcpt.isEmpty()) *mMailerProc << aRcpt;
00967
return TRUE;
00968 }
00969
00970
00971
00972
00973
00974
00975 KMSendSMTP::KMSendSMTP(KMSender *sender)
00976 : KMSendProc(sender),
00977 mInProcess(false),
00978 mJob(0),
00979 mSlave(0)
00980 {
00981 KIO::Scheduler::connect(SIGNAL(slaveError(KIO::Slave *,
int,
00982
const QString &)),
this, SLOT(slaveError(KIO::Slave *,
int,
00983
const QString &)));
00984 }
00985
00986 KMSendSMTP::~KMSendSMTP()
00987 {
00988
if (mJob) mJob->kill();
00989 }
00990
00991
bool KMSendSMTP::send(KMMessage *aMsg)
00992 {
00993 KMTransportInfo *ti = mSender->transportInfo();
00994 assert(aMsg != 0);
00995
00996
const QString sender = aMsg->sender();
00997
if ( sender.isEmpty() )
00998
return false;
00999
01000
01001 mQuery =
"headers=0&from=";
01002 mQuery += KURL::encode_string( sender );
01003
01004
01005
if( !aMsg->headerField(
"X-KMail-Recipients").isEmpty() ) {
01006
01007
01008 mQueryField =
"&to=";
01009
if( !addRecipients( aMsg->extractAddrSpecs(
"X-KMail-Recipients")) ) {
01010
return FALSE;
01011 }
01012 aMsg->removeHeaderField(
"X-KMail-Recipients" );
01013 }
else {
01014 mQueryField =
"&to=";
01015
if(!addRecipients(aMsg->extractAddrSpecs(
"To")))
01016 {
01017
return FALSE;
01018 }
01019
01020
if(!aMsg->cc().isEmpty())
01021 {
01022 mQueryField =
"&cc=";
01023
if(!addRecipients(aMsg->extractAddrSpecs(
"Cc")))
return FALSE;
01024 }
01025
01026
QString bccStr = aMsg->bcc();
01027
if(!bccStr.isEmpty())
01028 {
01029 mQueryField =
"&bcc=";
01030
if (!addRecipients(aMsg->extractAddrSpecs(
"Bcc")))
return FALSE;
01031 }
01032 }
01033
01034
if (ti->specifyHostname)
01035 mQuery +=
"&hostname=" + KURL::encode_string(ti->localHostname);
01036
01037
if ( !kmkernel->msgSender()->sendQuotedPrintable() )
01038 mQuery +=
"&body=8bit";
01039
01040 KURL destination;
01041
01042 destination.setProtocol((ti->encryption ==
"SSL") ? SMTPS_PROTOCOL : SMTP_PROTOCOL);
01043 destination.setHost(ti->host);
01044 destination.setPort(ti->port.toUShort());
01045
01046
if (ti->auth)
01047 {
01048
if(ti->user.isEmpty() || ti->pass.isEmpty())
01049 {
01050
bool b = FALSE;
01051
int result;
01052
01053
KCursorSaver idle(KBusyPtr::idle());
01054 result = KIO::PasswordDialog::getNameAndPassword(ti->user, ti->pass,
01055 &b, i18n(
"You need to supply a username and a password to use this "
01056
"SMTP server."), FALSE, QString::null, ti->name, QString::null);
01057
01058
if ( result != QDialog::Accepted )
01059 {
01060 abort();
01061
return FALSE;
01062 }
01063
if (
int id = KMTransportInfo::findTransport(ti->name))
01064 ti->writeConfig(
id);
01065 }
01066 destination.setUser(ti->user);
01067 destination.setPass(ti->pass);
01068 }
01069
01070
if (!mSlave || !mInProcess)
01071 {
01072 KIO::MetaData slaveConfig;
01073 slaveConfig.insert(
"tls", (ti->encryption ==
"TLS") ?
"on" :
"off");
01074
if (ti->auth) slaveConfig.insert(
"sasl", ti->authType);
01075 mSlave = KIO::Scheduler::getConnectedSlave(destination, slaveConfig);
01076 }
01077
01078
if (!mSlave)
01079 {
01080 abort();
01081
return false;
01082 }
01083
01084
01085 mMessage = aMsg->asSendableString();
01086 mMessageLength = mMessage.length();
01087 mMessageOffset = 0;
01088
01089
if ( mMessageLength )
01090
01091
01092 mQuery +=
"&size=" + QString::number( qRound( mMessageLength * 1.05 ) );
01093
01094 destination.setPath(
"/send");
01095 destination.setQuery(mQuery);
01096 mQuery = QString::null;
01097
01098
if ((mJob = KIO::put(destination, -1,
false,
false,
false)))
01099 {
01100 mJob->addMetaData(
"lf2crlf+dotstuff",
"slave" );
01101 KIO::Scheduler::assignJobToSlave(mSlave, mJob);
01102 connect(mJob, SIGNAL(result(KIO::Job *)),
this, SLOT(result(KIO::Job *)));
01103 connect(mJob, SIGNAL(dataReq(KIO::Job *,
QByteArray &)),
01104
this, SLOT(dataReq(KIO::Job *,
QByteArray &)));
01105 mSendOk =
true;
01106 mInProcess =
true;
01107
return mSendOk;
01108 }
01109
else
01110 {
01111 abort();
01112
return false;
01113 }
01114 }
01115
01116
void KMSendSMTP::abort()
01117 {
01118 finish(
false);
01119 emit idle();
01120 }
01121
01122
bool KMSendSMTP::finish(
bool b)
01123 {
01124
if(mJob)
01125 {
01126 mJob->kill(TRUE);
01127 mJob = 0;
01128 mSlave = 0;
01129 }
01130
01131
if (mSlave)
01132 {
01133 KIO::Scheduler::disconnectSlave(mSlave);
01134 mSlave = 0;
01135 }
01136
01137 mInProcess =
false;
01138
return KMSendProc::finish(b);
01139 }
01140
01141
bool KMSendSMTP::addOneRecipient(
const QString& _addr)
01142 {
01143
if(!_addr.isEmpty())
01144 mQuery += mQueryField + KURL::encode_string(_addr);
01145
01146
return true;
01147 }
01148
01149
void KMSendSMTP::dataReq(KIO::Job *,
QByteArray &array)
01150 {
01151
01152
int chunkSize = QMIN( mMessageLength - mMessageOffset, 0x8000 );
01153
if ( chunkSize > 0 ) {
01154 array.duplicate(mMessage.data() + mMessageOffset, chunkSize);
01155 mMessageOffset += chunkSize;
01156 }
else
01157 {
01158 array.resize(0);
01159 mMessage.resize(0);
01160 }
01161 mSender->emitProgressInfo( mMessageOffset );
01162 }
01163
01164
void KMSendSMTP::result(KIO::Job *_job)
01165 {
01166
if (!mJob)
return;
01167 mJob = 0;
01168
01169
if(_job->error())
01170 {
01171 mSendOk =
false;
01172
if (_job->error() == KIO::ERR_SLAVE_DIED) mSlave = 0;
01173 failed(_job->errorString());
01174 abort();
01175 }
else {
01176 emit idle();
01177 }
01178 }
01179
01180
void KMSendSMTP::slaveError(KIO::Slave *aSlave,
int error,
const QString &errorMsg)
01181 {
01182
if (aSlave == mSlave)
01183 {
01184
if (error == KIO::ERR_SLAVE_DIED) mSlave = 0;
01185 mSendOk =
false;
01186 mJob = 0;
01187 failed(KIO::buildErrorString(error, errorMsg));
01188 abort();
01189 }
01190 }
01191
01192
#include "kmsender.moc"