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 <QBuffer>
00029 #include <QHash>
00030
00031 #include <KLocalizedString>
00032 #include <KUrl>
00033 #include <KIO/Job>
00034 #include <KIO/Scheduler>
00035 #include <KIO/PasswordDialog>
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 ) {
00095 if ( slave ) {
00096 KIO::Scheduler::disconnectSlave( slave );
00097 }
00098 }
00099 s_slavePool->slaves.clear();
00100 }
00101 }
00102 delete d;
00103 }
00104
00105 void SmtpJob::doStart()
00106 {
00107 if ( s_slavePool.isDestroyed() ) {
00108 return;
00109 }
00110
00111 if ( s_slavePool->slaves.contains( transport()->id() ) ||
00112 transport()->precommand().isEmpty() ) {
00113 d->currentState = SmtpJobPrivate::Smtp;
00114 startSmtpJob();
00115 } else {
00116 d->currentState = SmtpJobPrivate::Precommand;
00117 PrecommandJob *job = new PrecommandJob( transport()->precommand(), this );
00118 addSubjob( job );
00119 job->start();
00120 }
00121 }
00122
00123 void SmtpJob::startSmtpJob()
00124 {
00125 if ( s_slavePool.isDestroyed() ) {
00126 return;
00127 }
00128
00129 KUrl destination;
00130 destination.setProtocol( ( transport()->encryption() == Transport::EnumEncryption::SSL ) ?
00131 SMTPS_PROTOCOL : SMTP_PROTOCOL );
00132 destination.setHost( transport()->host().trimmed() );
00133 destination.setPort( transport()->port() );
00134
00135 destination.addQueryItem( QLatin1String( "headers" ), QLatin1String( "0" ) );
00136 destination.addQueryItem( QLatin1String( "from" ), sender() );
00137
00138 foreach ( const QString &str, to() ) {
00139 destination.addQueryItem( QLatin1String( "to" ), str );
00140 }
00141 foreach ( const QString &str, cc() ) {
00142 destination.addQueryItem( QLatin1String( "cc" ), str );
00143 }
00144 foreach ( const QString &str, bcc() ) {
00145 destination.addQueryItem( QLatin1String( "bcc" ), str );
00146 }
00147
00148 if ( transport()->specifyHostname() ) {
00149 destination.addQueryItem( QLatin1String( "hostname" ), transport()->localHostname() );
00150 }
00151
00152 if ( transport()->requiresAuthentication() ) {
00153 if( ( transport()->userName().isEmpty() || transport()->password().isEmpty() ) &&
00154 transport()->authenticationType() != Transport::EnumAuthenticationType::GSSAPI ) {
00155 QString user = transport()->userName();
00156 QString passwd = transport()->password();
00157 int result;
00158
00159 bool keep = transport()->storePassword();
00160 result = KIO::PasswordDialog::getNameAndPassword(
00161 user, passwd, &keep,
00162 i18n( "You need to supply a username and a password to use this SMTP server." ),
00163 false, QString(), transport()->name(), QString() );
00164
00165 if ( result != QDialog::Accepted ) {
00166 setError( KilledJobError );
00167 emitResult();
00168 return;
00169 }
00170 transport()->setUserName( user );
00171 transport()->setPassword( passwd );
00172 transport()->setStorePassword( keep );
00173 transport()->writeConfig();
00174 }
00175 destination.setUser( transport()->userName() );
00176 destination.setPass( transport()->password() );
00177 }
00178
00179
00180 if ( !data().isEmpty() ) {
00181
00182
00183 destination.addQueryItem( QLatin1String( "size" ),
00184 QString::number( qRound( data().length() * 1.05 ) ) );
00185 }
00186
00187 destination.setPath( QLatin1String( "/send" ) );
00188
00189 d->slave = s_slavePool->slaves.value( transport()->id() );
00190 if ( !d->slave ) {
00191 KIO::MetaData slaveConfig;
00192 slaveConfig.insert( QLatin1String( "tls" ),
00193 ( transport()->encryption() == Transport::EnumEncryption::TLS ) ?
00194 QLatin1String( "on" ) : QLatin1String( "off" ) );
00195 if ( transport()->requiresAuthentication() ) {
00196 slaveConfig.insert( QLatin1String( "sasl" ), transport()->authenticationTypeString() );
00197 }
00198 d->slave = KIO::Scheduler::getConnectedSlave( destination, slaveConfig );
00199 kDebug() << "Created new SMTP slave" << d->slave;
00200 s_slavePool->slaves.insert( transport()->id(), d->slave );
00201 } else {
00202 kDebug() << "Re-using existing slave" << d->slave;
00203 }
00204
00205 KIO::TransferJob *job = KIO::put( destination, -1, KIO::HideProgressInfo );
00206 if ( !d->slave || !job ) {
00207 setError( UserDefinedError );
00208 setErrorText( i18n( "Unable to create SMTP job." ) );
00209 emitResult();
00210 return;
00211 }
00212
00213 job->addMetaData( QLatin1String( "lf2crlf+dotstuff" ), QLatin1String( "slave" ) );
00214 connect( job, SIGNAL(dataReq(KIO::Job*,QByteArray&)),
00215 SLOT(dataRequest(KIO::Job*,QByteArray&)) );
00216
00217 addSubjob( job );
00218 KIO::Scheduler::assignJobToSlave( d->slave, job );
00219
00220 setTotalAmount( KJob::Bytes, data().length() );
00221 }
00222
00223 bool SmtpJob::doKill()
00224 {
00225 if ( s_slavePool.isDestroyed() ) {
00226 return false;
00227 }
00228
00229 if ( !hasSubjobs() ) {
00230 return true;
00231 }
00232 if ( d->currentState == SmtpJobPrivate::Precommand ) {
00233 return subjobs().first()->kill();
00234 } else if ( d->currentState == SmtpJobPrivate::Smtp ) {
00235 KIO::SimpleJob *job = static_cast<KIO::SimpleJob*>( subjobs().first() );
00236 clearSubjobs();
00237 KIO::Scheduler::cancelJob( job );
00238 s_slavePool->removeSlave( d->slave );
00239 return true;
00240 }
00241 return false;
00242 }
00243
00244 void SmtpJob::slotResult( KJob *job )
00245 {
00246 if ( s_slavePool.isDestroyed() ) {
00247 return;
00248 }
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261 d->finished = true;
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271 int errorCode = error();
00272 if ( !errorCode ) {
00273 errorCode = job->error();
00274 }
00275
00276 if ( errorCode && d->currentState == SmtpJobPrivate::Smtp ) {
00277 s_slavePool->removeSlave( d->slave, errorCode != KIO::ERR_SLAVE_DIED );
00278 TransportJob::slotResult( job );
00279 return;
00280 }
00281
00282 TransportJob::slotResult( job );
00283 if ( !error() && d->currentState == SmtpJobPrivate::Precommand ) {
00284 d->currentState = SmtpJobPrivate::Smtp;
00285 startSmtpJob();
00286 return;
00287 }
00288 if ( !error() ) {
00289 emitResult();
00290 }
00291 }
00292
00293 void SmtpJob::dataRequest( KIO::Job *job, QByteArray &data )
00294 {
00295 if ( s_slavePool.isDestroyed() ) {
00296 return;
00297 }
00298
00299 Q_UNUSED( job );
00300 Q_ASSERT( job );
00301 if ( buffer()->atEnd() ) {
00302 data.clear();
00303 } else {
00304 Q_ASSERT( buffer()->isOpen() );
00305 data = buffer()->read( 32 * 1024 );
00306 }
00307 setProcessedAmount( KJob::Bytes, buffer()->pos() );
00308 }
00309
00310 void SmtpJob::slaveError( KIO::Slave *slave, int errorCode, const QString &errorMsg )
00311 {
00312 if ( s_slavePool.isDestroyed() ) {
00313 return;
00314 }
00315
00316 s_slavePool->removeSlave( slave, errorCode != KIO::ERR_SLAVE_DIED );
00317 if ( d->slave == slave && !d->finished ) {
00318 setError( errorCode );
00319 setErrorText( KIO::buildErrorString( errorCode, errorMsg ) );
00320 emitResult();
00321 }
00322 }
00323
00324 #include "smtpjob.moc"