• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

mailtransport

smtpjob.cpp

00001 /*
00002     Copyright (c) 2007 Volker Krause <vkrause@kde.org>
00003 
00004     Based on KMail code by:
00005     Copyright (c) 1996-1998 Stefan Taferner <taferner@kde.org>
00006 
00007     This library is free software; you can redistribute it and/or modify it
00008     under the terms of the GNU Library General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or (at your
00010     option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful, but WITHOUT
00013     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00015     License for more details.
00016 
00017     You should have received a copy of the GNU Library General Public License
00018     along with this library; see the file COPYING.LIB.  If not, write to the
00019     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00020     02110-1301, USA.
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 //   if ( !kmkernel->msgSender()->sendQuotedPrintable() )
00130 //     query += "&body=8bit";
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 //       KCursorSaver idle( KBusyPtr::idle() );
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   // dotstuffing is now done by the slave (see setting of metadata)
00167   if ( !data().isEmpty() )
00168     // allow +5% for subsequent LF->CRLF and dotstuffing (an average
00169     // over 2G-lines gives an average line length of 42-43):
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   // The job has finished, so we don't care about any further errors. Set
00228   // d->finished to true, so slaveError() knows about this and doesn't call
00229   // emitResult() anymore.
00230   // Sometimes, the SMTP slave emits more than one error
00231   //
00232   // The first error causes slotResult() to be called, but not slaveError(), since
00233   // the scheduler doesn't emit errors for connected slaves.
00234   //
00235   // The second error then causes slaveError() to be called (as the slave is no
00236   // longer connected), which does emitResult() a second time, which is invalid
00237   // (and triggers an assert in KMail).
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"

mailtransport

Skip menu "mailtransport"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • kabc
  • kblog
  • kcal
  • kimap
  • kioslave
  •   imap4
  •   mbox
  • kldap
  • kmime
  • kpimidentities
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.5.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal