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