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