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