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