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.h>
00035 #include <qhash.h>
00036
00037 using namespace MailTransport;
00038
00039 static int slavePoolRef = 0;
00040 static QHash<int,KIO::Slave*> slavePool;
00041
00042 static void removeSlaveFromPool( KIO::Slave *slave, bool disconnect = false )
00043 {
00044 const int slaveKey = slavePool.key( slave );
00045 if (slaveKey > 0)
00046 {
00047 slavePool.remove( slaveKey );
00048 if ( disconnect )
00049 KIO::Scheduler::disconnectSlave( slave );
00050 }
00051 }
00052
00057 class SmtpJobPrivate
00058 {
00059 public:
00060 KIO::Slave* slave;
00061 enum State {
00062 Idle, Precommand, Smtp
00063 } currentState;
00064 bool finished;
00065 };
00066
00067 SmtpJob::SmtpJob(Transport * transport, QObject * parent) :
00068 TransportJob( transport, parent ), d( new SmtpJobPrivate )
00069 {
00070 d->currentState = SmtpJobPrivate::Idle;
00071 d->slave = 0;
00072 d->finished = false;
00073 slavePoolRef++;
00074 KIO::Scheduler::connect( SIGNAL(slaveError(KIO::Slave*,int,QString)),
00075 this, SLOT(slaveError(KIO::Slave*,int,QString)) );
00076 }
00077
00078 SmtpJob::~SmtpJob()
00079 {
00080 slavePoolRef--;
00081 if ( slavePoolRef == 0 ) {
00082 kDebug(5324) << "clearing SMTP slave pool" << slavePool.count();
00083 foreach ( KIO::Slave *slave, slavePool.values() )
00084 KIO::Scheduler::disconnectSlave( slave );
00085 slavePool.clear();
00086 }
00087 delete d;
00088 }
00089
00090 void SmtpJob::doStart()
00091 {
00092 if ( slavePool.contains( transport()->id() ) ||
00093 transport()->precommand().isEmpty() ) {
00094 d->currentState = SmtpJobPrivate::Smtp;
00095 startSmtpJob();
00096 } else {
00097 d->currentState = SmtpJobPrivate::Precommand;
00098 PrecommandJob *job = new PrecommandJob( transport()->precommand(), this );
00099 addSubjob( job );
00100 job->start();
00101 }
00102 }
00103
00104 void SmtpJob::startSmtpJob()
00105 {
00106 KUrl destination;
00107 destination.setProtocol( (transport()->encryption() ==
00108 Transport::EnumEncryption::SSL) ? SMTPS_PROTOCOL : SMTP_PROTOCOL );
00109 destination.setHost( transport()->host() );
00110 destination.setPort( transport()->port() );
00111
00112 destination.addQueryItem( QLatin1String("headers"), QLatin1String("0") );
00113 destination.addQueryItem( QLatin1String("from"), sender() );
00114
00115 foreach ( QString str, to() )
00116 destination.addQueryItem( QLatin1String("to"), str );
00117 foreach ( QString str, cc() )
00118 destination.addQueryItem( QLatin1String("cc"), str );
00119 foreach ( QString str, bcc() )
00120 destination.addQueryItem( QLatin1String("bcc"), str );
00121
00122 if ( transport()->specifyHostname() )
00123 destination.addQueryItem( QLatin1String("hostname"),
00124 transport()->localHostname() );
00125
00126 #ifdef __GNUC__
00127 #warning Argh!
00128 #endif
00129
00130
00131
00132 if ( transport()->requiresAuthentication() ) {
00133 if( (transport()->userName().isEmpty() || transport()->password().isEmpty())
00134 && transport()->authenticationType() !=
00135 Transport::EnumAuthenticationType::GSSAPI )
00136 {
00137 QString user = transport()->userName();
00138 QString passwd = transport()->password();
00139 int result;
00140
00141 #ifdef __GNUC__
00142 #warning yet another KMail specific thing
00143 #endif
00144
00145 bool keep = true;
00146 result = KIO::PasswordDialog::getNameAndPassword(
00147 user, passwd, &keep,
00148 i18n("You need to supply a username and a password to use this "
00149 "SMTP server."),
00150 false, QString(), transport()->name(), QString() );
00151
00152 if ( result != QDialog::Accepted ) {
00153 setError( KilledJobError );
00154 emitResult();
00155 return;
00156 }
00157 transport()->setUserName( user );
00158 transport()->setPassword( passwd );
00159 transport()->setStorePassword( keep );
00160 transport()->writeConfig();
00161 }
00162 destination.setUser( transport()->userName() );
00163 destination.setPass( transport()->password() );
00164 }
00165
00166
00167 if ( !data().isEmpty() )
00168
00169
00170 destination.addQueryItem( QLatin1String("size"),
00171 QString::number( qRound( data().length() * 1.05 ) ) );
00172
00173 destination.setPath( QLatin1String("/send") );
00174
00175 d->slave = slavePool.value( transport()->id() );
00176 if ( !d->slave ) {
00177 kDebug(5324) << "creating new SMTP slave";
00178 KIO::MetaData slaveConfig;
00179 slaveConfig.insert( QLatin1String("tls"),
00180 (transport()->encryption() == Transport::EnumEncryption::TLS)
00181 ? QLatin1String("on") : QLatin1String("off") );
00182 if ( transport()->requiresAuthentication() )
00183 slaveConfig.insert( QLatin1String("sasl"),
00184 transport()->authenticationTypeString() );
00185 d->slave = KIO::Scheduler::getConnectedSlave( destination, slaveConfig );
00186 slavePool.insert( transport()->id(), d->slave );
00187 } else {
00188 kDebug(5324) << "re-using existing slave";
00189 }
00190
00191 KIO::TransferJob *job = KIO::put( destination, -1, KIO::HideProgressInfo );
00192 if ( !d->slave || !job ) {
00193 setError( UserDefinedError );
00194 setErrorText( i18n("Unable to create SMTP job.") );
00195 emitResult();
00196 return;
00197 }
00198
00199 job->addMetaData( QLatin1String("lf2crlf+dotstuff"), QLatin1String("slave") );
00200 connect( job, SIGNAL(dataReq(KIO::Job*,QByteArray&)),
00201 SLOT(dataRequest(KIO::Job*,QByteArray&)) );
00202
00203 addSubjob( job );
00204 KIO::Scheduler::assignJobToSlave( d->slave, job );
00205
00206 setTotalAmount( KJob::Bytes, data().length() );
00207 }
00208
00209 bool SmtpJob::doKill()
00210 {
00211 if ( !hasSubjobs() )
00212 return true;
00213 if ( d->currentState == SmtpJobPrivate::Precommand )
00214 return subjobs().first()->kill();
00215 else if ( d->currentState == SmtpJobPrivate::Smtp ) {
00216 KIO::SimpleJob *job = static_cast<KIO::SimpleJob*>( subjobs().first() );
00217 clearSubjobs();
00218 KIO::Scheduler::cancelJob( job );
00219 removeSlaveFromPool( d->slave );
00220 return true;
00221 }
00222 return false;
00223 }
00224
00225 void SmtpJob::slotResult(KJob * job)
00226 {
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 d->finished = true;
00239
00240 TransportJob::slotResult( job );
00241 if ( error() && d->currentState == SmtpJobPrivate::Smtp ) {
00242 removeSlaveFromPool( d->slave, error() != KIO::ERR_SLAVE_DIED );
00243 return;
00244 }
00245 if ( !error() && d->currentState == SmtpJobPrivate::Precommand ) {
00246 d->currentState = SmtpJobPrivate::Smtp;
00247 startSmtpJob();
00248 return;
00249 }
00250 if ( !error() )
00251 emitResult();
00252 }
00253
00254 void SmtpJob::dataRequest(KIO::Job * job, QByteArray & data)
00255 {
00256 Q_ASSERT( job );
00257 if ( buffer()->atEnd() )
00258 data.clear();
00259 else {
00260 Q_ASSERT( buffer()->isOpen() );
00261 data = buffer()->read( 32*1024 );
00262 }
00263 setProcessedAmount( KJob::Bytes, buffer()->pos() );
00264 }
00265
00266 void SmtpJob::slaveError(KIO::Slave * slave, int errorCode,
00267 const QString & errorMsg)
00268 {
00269 removeSlaveFromPool( slave, errorCode != KIO::ERR_SLAVE_DIED );
00270 if ( d->slave == slave && !d->finished ) {
00271 setError( errorCode );
00272 setErrorText( KIO::buildErrorString( errorCode, errorMsg ) );
00273 emitResult();
00274 }
00275 }
00276
00277 #include "smtpjob.moc"