KIMAP Library
session.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "session.h"
00021 #include "session_p.h"
00022 #include "sessionuiproxy.h"
00023
00024 #include <QtCore/QDebug>
00025 #include <QtCore/QTimer>
00026
00027 #include <KDE/KMessageBox>
00028 #include <KDE/KLocale>
00029
00030 #include "job.h"
00031 #include "message_p.h"
00032 #include "sessionthread_p.h"
00033 #include "rfccodecs.h"
00034
00035 Q_DECLARE_METATYPE(KTcpSocket::SslVersion)
00036 Q_DECLARE_METATYPE(QSslSocket::SslMode)
00037 static const int _kimap_sslVersionId = qRegisterMetaType<KTcpSocket::SslVersion>();
00038
00039 using namespace KIMAP;
00040
00041 Session::Session( const QString &hostName, quint16 port, QObject *parent)
00042 : QObject(parent), d(new SessionPrivate(this))
00043 {
00044 d->state = Disconnected;
00045 d->jobRunning = false;
00046
00047 d->thread = new SessionThread(hostName, port, this);
00048 connect(d->thread, SIGNAL(encryptionNegotiationResult(bool)), d, SIGNAL(encryptionNegotiationResult(bool)));
00049 connect(d->thread, SIGNAL(sslError(const KSslErrorUiData&)), this, SLOT(handleSslError(const KSslErrorUiData&)));
00050
00051 d->thread->start();
00052 }
00053
00054 Session::~Session()
00055 {
00056 delete d->thread;
00057 }
00058
00059 void Session::setUiProxy(SessionUiProxy *proxy)
00060 {
00061 d->uiProxy = proxy;
00062 }
00063
00064 QString Session::hostName() const
00065 {
00066 return d->thread->hostName();
00067 }
00068
00069 quint16 Session::port() const
00070 {
00071 return d->thread->port();
00072 }
00073
00074 Session::State Session::state() const
00075 {
00076 return d->state;
00077 }
00078
00079 void SessionPrivate::handleSslError(const KSslErrorUiData& errorData)
00080 {
00081 if (uiProxy && uiProxy->ignoreSslError(errorData)) {
00082 QMetaObject::invokeMethod( thread, "sslErrorHandlerResponse", Q_ARG(bool, true) );
00083 } else {
00084 QMetaObject::invokeMethod( thread, "sslErrorHandlerResponse", Q_ARG(bool, false) );
00085 }
00086 }
00087
00088 SessionPrivate::SessionPrivate( Session *session )
00089 : q(session),
00090 uiProxy(0),
00091 currentJob(0),
00092 tagCount(0)
00093 {
00094 }
00095
00096 void SessionPrivate::addJob(Job *job)
00097 {
00098 queue.append(job);
00099
00100 QObject::connect( job, SIGNAL(result(KJob*)), q, SLOT(jobDone(KJob*)) );
00101 QObject::connect( job, SIGNAL(destroyed(QObject*)), q, SLOT(jobDestroyed(QObject*)) );
00102
00103 startNext();
00104 }
00105
00106 void SessionPrivate::startNext()
00107 {
00108 QTimer::singleShot( 0, q, SLOT(doStartNext()) );
00109 }
00110
00111 void SessionPrivate::doStartNext()
00112 {
00113 if ( queue.isEmpty() || jobRunning || state==Session::Disconnected ) {
00114 return;
00115 }
00116
00117 jobRunning = true;
00118
00119 currentJob = queue.dequeue();
00120 currentJob->doStart();
00121 }
00122
00123 void SessionPrivate::jobDone( KJob *job )
00124 {
00125 Q_ASSERT( job == currentJob );
00126
00127 jobRunning = false;
00128 currentJob = 0;
00129 startNext();
00130 }
00131
00132 void SessionPrivate::jobDestroyed( QObject *job )
00133 {
00134 queue.removeAll( static_cast<KIMAP::Job*>( job ) );
00135 if ( currentJob == job )
00136 currentJob = 0;
00137 }
00138
00139 void SessionPrivate::responseReceived( const Message &response )
00140 {
00141 QByteArray tag;
00142 QByteArray code;
00143
00144 if ( response.content.size()>=1 ) {
00145 tag = response.content[0].toString();
00146 }
00147
00148 if ( response.content.size()>=2 ) {
00149 code = response.content[1].toString();
00150 }
00151
00152 switch ( state ) {
00153 case Session::Disconnected:
00154 if ( code=="OK" ) {
00155 state = Session::NotAuthenticated;
00156 startNext();
00157 } else if ( code=="PREAUTH" ) {
00158 state = Session::Authenticated;
00159 startNext();
00160 } else {
00161 thread->closeSocket();
00162 QTimer::singleShot( 1000, thread, SLOT( reconnect() ) );
00163 }
00164 return;
00165 case Session::NotAuthenticated:
00166 if ( code=="OK" && tag==authTag ) {
00167 state = Session::Authenticated;
00168 }
00169 break;
00170 case Session::Authenticated:
00171 if ( code=="OK" && tag==selectTag ) {
00172 state = Session::Selected;
00173 currentMailBox = upcomingMailBox;
00174 }
00175 break;
00176 case Session::Selected:
00177 if ( ( code=="OK" && tag==closeTag )
00178 || ( code!="OK" && tag==selectTag) ) {
00179 state = Session::Authenticated;
00180 currentMailBox = QByteArray();
00181 } else if ( code=="OK" && tag==selectTag ) {
00182 currentMailBox = upcomingMailBox;
00183 }
00184 break;
00185 }
00186
00187 if (tag==authTag) authTag.clear();
00188 if (tag==selectTag) selectTag.clear();
00189 if (tag==closeTag) closeTag.clear();
00190
00191
00192 if ( currentJob!=0 ) {
00193 currentJob->handleResponse( response );
00194 } else {
00195 qWarning() << "A message was received from the server with no job to handle it";
00196 }
00197 }
00198
00199 QByteArray SessionPrivate::sendCommand( const QByteArray &command, const QByteArray &args )
00200 {
00201 QByteArray tag = "A" + QByteArray::number(++tagCount).rightJustified(6, '0');
00202
00203 QByteArray payload = tag+' '+command;
00204 if ( !args.isEmpty() ) {
00205 payload+= ' '+args;
00206 }
00207 payload+="\r\n";
00208
00209 thread->sendData(payload);
00210
00211 if ( command=="LOGIN" || command=="AUTHENTICATE" ) {
00212 authTag = tag;
00213 } else if ( command=="SELECT" || command=="EXAMINE" ) {
00214 selectTag = tag;
00215 upcomingMailBox = args;
00216 upcomingMailBox.remove( 0, 1 );
00217 upcomingMailBox.chop( 1 );
00218 upcomingMailBox = KIMAP::decodeImapFolderName( upcomingMailBox );
00219 } else if ( command=="CLOSE" ) {
00220 closeTag = tag;
00221 }
00222
00223 return tag;
00224 }
00225
00226 void SessionPrivate::sendData( const QByteArray &data )
00227 {
00228 thread->sendData(data+"\r\n");
00229 }
00230
00231 void SessionPrivate::socketConnected()
00232 {
00233 state = Session::NotAuthenticated;
00234 startNext();
00235 }
00236
00237 void SessionPrivate::socketDisconnected()
00238 {
00239 state = Session::Disconnected;
00240 thread->closeSocket();
00241
00242 if ( currentJob ) {
00243 currentJob->connectionLost();
00244 }
00245 }
00246
00247 void SessionPrivate::socketError()
00248 {
00249
00250 socketDisconnected();
00251 }
00252
00253 void SessionPrivate::startSsl(const KTcpSocket::SslVersion &version)
00254 {
00255 QMetaObject::invokeMethod( thread, "startSsl", Qt::QueuedConnection, Q_ARG(KTcpSocket::SslVersion, version) );
00256 }
00257
00258 QString SessionPrivate::selectedMailBox() const
00259 {
00260 return QString::fromUtf8( currentMailBox );
00261 }
00262
00263 #include "session.moc"
00264 #include "session_p.moc"