00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "smtpjob.h"
00024 #include "transport.h"
00025 #include "mailtransport_defs.h"
00026 #include "precommandjob.h"
00027
00028 #include <klocale.h>
00029 #include <kurl.h>
00030 #include <kio/job.h>
00031 #include <kio/scheduler.h>
00032 #include <kio/passworddialog.h>
00033
00034 #include <QBuffer>
00035 #include <QHash>
00036
00037 using namespace MailTransport;
00038
00039 class SlavePool
00040 {
00041 public:
00042 SlavePool() : ref( 0 ) {}
00043 int ref;
00044 QHash<int,KIO::Slave*> slaves;
00045
00046 void removeSlave( KIO::Slave *slave, bool disconnect = false )
00047 {
00048 kDebug() << "Removing slave" << slave << "from pool";
00049 const int slaveKey = slaves.key( slave );
00050 if ( slaveKey > 0 ) {
00051 slaves.remove( slaveKey );
00052 if ( disconnect ) {
00053 KIO::Scheduler::disconnectSlave( slave );
00054 }
00055 }
00056 }
00057 };
00058
00059 K_GLOBAL_STATIC( SlavePool, s_slavePool )
00060
00061
00065 class SmtpJobPrivate
00066 {
00067 public:
00068 KIO::Slave *slave;
00069 enum State {
00070 Idle, Precommand, Smtp
00071 } currentState;
00072 bool finished;
00073 };
00074
00075 SmtpJob::SmtpJob( Transport *transport, QObject *parent )
00076 : TransportJob( transport, parent ), d( new SmtpJobPrivate )
00077 {
00078 d->currentState = SmtpJobPrivate::Idle;
00079 d->slave = 0;
00080 d->finished = false;
00081 if ( !s_slavePool.isDestroyed() ) {
00082 s_slavePool->ref++;
00083 }
00084 KIO::Scheduler::connect( SIGNAL(slaveError(KIO::Slave*,int,QString)),
00085 this, SLOT(slaveError(KIO::Slave*,int,QString)) );
00086 }
00087
00088 SmtpJob::~SmtpJob()
00089 {
00090 if ( !s_slavePool.isDestroyed() ) {
00091 s_slavePool->ref--;
00092 if ( s_slavePool->ref == 0 ) {
00093 kDebug() << "clearing SMTP slave pool" << s_slavePool->slaves.count();
00094 foreach ( KIO::Slave *slave, s_slavePool->slaves.values() ) {
00095 KIO::Scheduler::disconnectSlave( slave );
00096 }
00097 s_slavePool->slaves.clear();
00098 }
00099 }
00100 delete d;
00101 }
00102
00103 void SmtpJob::doStart()
00104 {
00105 if ( s_slavePool.isDestroyed() ) {
00106 return;
00107 }
00108
00109 if ( s_slavePool->slaves.contains( transport()->id() ) ||
00110 transport()->precommand().isEmpty() ) {
00111 d->currentState = SmtpJobPrivate::Smtp;
00112 startSmtpJob();
00113 } else {
00114 d->currentState = SmtpJobPrivate::Precommand;
00115 PrecommandJob *job = new PrecommandJob( transport()->precommand(), this );
00116 addSubjob( job );
00117 job->start();
00118 }
00119 }
00120
00121 void SmtpJob::startSmtpJob()
00122 {
00123 if ( s_slavePool.isDestroyed() ) {
00124 return;
00125 }
00126
00127 KUrl destination;
00128 destination.setProtocol( ( transport()->encryption() == Transport::EnumEncryption::SSL ) ?
00129 SMTPS_PROTOCOL : SMTP_PROTOCOL );
00130 destination.setHost( transport()->host() );
00131 destination.setPort( transport()->port() );
00132
00133 destination.addQueryItem( QLatin1String( "headers" ), QLatin1String( "0" ) );
00134 destination.addQueryItem( QLatin1String( "from" ), sender() );
00135
00136 foreach ( const QString& str, to() ) {
00137 destination.addQueryItem( QLatin1String( "to" ), str );
00138 }
00139 foreach ( const QString& str, cc() ) {
00140 destination.addQueryItem( QLatin1String( "cc" ), str );
00141 }
00142 foreach ( const QString& str, bcc() ) {
00143 destination.addQueryItem( QLatin1String( "bcc" ), str );
00144 }
00145
00146 if ( transport()->specifyHostname() ) {
00147 destination.addQueryItem( QLatin1String( "hostname" ), transport()->localHostname() );
00148 }
00149
00150 #ifdef __GNUC__
00151 #warning Argh!
00152 #endif
00153
00154
00155
00156 if ( transport()->requiresAuthentication() ) {
00157 if( ( transport()->userName().isEmpty() || transport()->password().isEmpty() ) &&
00158 transport()->authenticationType() != Transport::EnumAuthenticationType::GSSAPI ) {
00159 QString user = transport()->userName();
00160 QString passwd = transport()->password();
00161 int result;
00162
00163 #ifdef __GNUC__
00164 #warning yet another KMail specific thing
00165 #endif
00166
00167 bool keep = true;
00168 result = KIO::PasswordDialog::getNameAndPassword(
00169 user, passwd, &keep,
00170 i18n( "You need to supply a username and a password to use this SMTP server." ),
00171 false, QString(), transport()->name(), QString() );
00172
00173 if ( result != QDialog::Accepted ) {
00174 setError( KilledJobError );
00175 emitResult();
00176 return;
00177 }
00178 transport()->setUserName( user );
00179 transport()->setPassword( passwd );
00180 transport()->setStorePassword( keep );
00181 transport()->writeConfig();
00182 }
00183 destination.setUser( transport()->userName() );
00184 destination.setPass( transport()->password() );
00185 }
00186
00187
00188 if ( !data().isEmpty() ) {
00189
00190
00191 destination.addQueryItem( QLatin1String( "size" ),
00192 QString::number( qRound( data().length() * 1.05 ) ) );
00193 }
00194
00195 destination.setPath( QLatin1String( "/send" ) );
00196
00197 d->slave = s_slavePool->slaves.value( transport()->id() );
00198 if ( !d->slave ) {
00199 KIO::MetaData slaveConfig;
00200 slaveConfig.insert( QLatin1String( "tls" ),
00201 ( transport()->encryption() == Transport::EnumEncryption::TLS ) ?
00202 QLatin1String( "on" ) : QLatin1String( "off" ) );
00203 if ( transport()->requiresAuthentication() ) {
00204 slaveConfig.insert( QLatin1String( "sasl" ), transport()->authenticationTypeString() );
00205 }
00206 d->slave = KIO::Scheduler::getConnectedSlave( destination, slaveConfig );
00207 kDebug() << "Created new SMTP slave" << d->slave;
00208 s_slavePool->slaves.insert( transport()->id(), d->slave );
00209 } else {
00210 kDebug() << "Re-using existing slave" << d->slave;
00211 }
00212
00213 KIO::TransferJob *job = KIO::put( destination, -1, KIO::HideProgressInfo );
00214 if ( !d->slave || !job ) {
00215 setError( UserDefinedError );
00216 setErrorText( i18n( "Unable to create SMTP job." ) );
00217 emitResult();
00218 return;
00219 }
00220
00221 job->addMetaData( QLatin1String( "lf2crlf+dotstuff" ), QLatin1String( "slave" ) );
00222 connect( job, SIGNAL(dataReq(KIO::Job*,QByteArray&)),
00223 SLOT(dataRequest(KIO::Job*,QByteArray&)) );
00224
00225 addSubjob( job );
00226 KIO::Scheduler::assignJobToSlave( d->slave, job );
00227
00228 setTotalAmount( KJob::Bytes, data().length() );
00229 }
00230
00231 bool SmtpJob::doKill()
00232 {
00233 if ( s_slavePool.isDestroyed() ) {
00234 return false;
00235 }
00236
00237 if ( !hasSubjobs() ) {
00238 return true;
00239 }
00240 if ( d->currentState == SmtpJobPrivate::Precommand ) {
00241 return subjobs().first()->kill();
00242 } else if ( d->currentState == SmtpJobPrivate::Smtp ) {
00243 KIO::SimpleJob *job = static_cast<KIO::SimpleJob*>( subjobs().first() );
00244 clearSubjobs();
00245 KIO::Scheduler::cancelJob( job );
00246 s_slavePool->removeSlave( d->slave );
00247 return true;
00248 }
00249 return false;
00250 }
00251
00252 void SmtpJob::slotResult( KJob *job )
00253 {
00254 if ( s_slavePool.isDestroyed() ) {
00255 return;
00256 }
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269 d->finished = true;
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279 int errorCode = error();
00280 if ( !errorCode )
00281 errorCode = job->error();
00282
00283 if ( errorCode && d->currentState == SmtpJobPrivate::Smtp ) {
00284 s_slavePool->removeSlave( d->slave, errorCode != KIO::ERR_SLAVE_DIED );
00285 TransportJob::slotResult( job );
00286 return;
00287 }
00288
00289 TransportJob::slotResult( job );
00290 if ( !error() && d->currentState == SmtpJobPrivate::Precommand ) {
00291 d->currentState = SmtpJobPrivate::Smtp;
00292 startSmtpJob();
00293 return;
00294 }
00295 if ( !error() ) {
00296 emitResult();
00297 }
00298 }
00299
00300 void SmtpJob::dataRequest( KIO::Job *job, QByteArray &data )
00301 {
00302 if ( s_slavePool.isDestroyed() ) {
00303 return;
00304 }
00305
00306 Q_ASSERT( job );
00307 if ( buffer()->atEnd() ) {
00308 data.clear();
00309 } else {
00310 Q_ASSERT( buffer()->isOpen() );
00311 data = buffer()->read( 32 * 1024 );
00312 }
00313 setProcessedAmount( KJob::Bytes, buffer()->pos() );
00314 }
00315
00316 void SmtpJob::slaveError( KIO::Slave *slave, int errorCode, const QString &errorMsg )
00317 {
00318 if ( s_slavePool.isDestroyed() ) {
00319 return;
00320 }
00321
00322 s_slavePool->removeSlave( slave, errorCode != KIO::ERR_SLAVE_DIED );
00323 if ( d->slave == slave && !d->finished ) {
00324 setError( errorCode );
00325 setErrorText( KIO::buildErrorString( errorCode, errorMsg ) );
00326 emitResult();
00327 }
00328 }
00329
00330 #include "smtpjob.moc"