24 #include "session_p.h"
25 #include "sessionuiproxy.h"
27 #include <QtCore/QDebug>
28 #include <QtCore/QTimer>
31 #include <KDE/KLocalizedString>
35 #include "message_p.h"
36 #include "sessionlogger_p.h"
37 #include "sessionthread_p.h"
40 Q_DECLARE_METATYPE( KTcpSocket::SslVersion )
42 static const
int _kimap_sslVersionId = qRegisterMetaType<KTcpSocket::SslVersion>();
44 using namespace KIMAP;
46 Session::Session( const
QString &hostName, quint16 port,
QObject *parent)
47 :
QObject( parent ), d( new SessionPrivate( this ) )
49 if ( !qgetenv(
"KIMAP_LOGFILE" ).isEmpty() ) {
50 d->logger =
new SessionLogger;
53 d->isSocketConnected =
false;
54 d->state = Disconnected;
55 d->jobRunning =
false;
57 d->
thread =
new SessionThread( hostName, port );
58 connect( d->thread, SIGNAL(encryptionNegotiationResult(
bool,KTcpSocket::SslVersion)),
59 d, SLOT(onEncryptionNegotiationResult(
bool,KTcpSocket::SslVersion)) );
60 connect( d->thread, SIGNAL(sslError(KSslErrorUiData)),
61 d, SLOT(handleSslError(KSslErrorUiData)) );
62 connect( d->thread, SIGNAL(socketDisconnected()),
63 d, SLOT(socketDisconnected()) );
64 connect( d->thread, SIGNAL(responseReceived(KIMAP::Message)),
65 d, SLOT(responseReceived(KIMAP::Message)) );
66 connect( d->thread, SIGNAL(socketConnected()),
67 d, SLOT(socketConnected()) );
68 connect( d->thread, SIGNAL(socketActivity()),
69 d, SLOT(socketActivity()) );
70 connect( d->thread, SIGNAL(socketError(KTcpSocket::Error)),
71 d, SLOT(socketError(KTcpSocket::Error)) );
73 d->socketTimer.setSingleShot(
true );
74 connect( &d->socketTimer, SIGNAL(timeout()),
75 d, SLOT(onSocketTimeout()) );
77 d->startSocketTimer();
86 void Session::setUiProxy(SessionUiProxy::Ptr proxy)
93 setUiProxy( SessionUiProxy::Ptr( proxy ) );
96 QString Session::hostName()
const
98 return d->thread->hostName();
101 quint16 Session::port()
const
103 return d->thread->port();
106 Session::State Session::state()
const
111 QString Session::userName()
const
121 int Session::jobQueueSize()
const
123 return d->queue.
size() + ( d->jobRunning ? 1 : 0 );
126 void KIMAP::Session::close()
128 d->thread->closeSocket();
131 void SessionPrivate::handleSslError(
const KSslErrorUiData& errorData)
133 const bool ignoreSslError = uiProxy && uiProxy->ignoreSslError( errorData );
136 thread->sslErrorHandlerResponse(ignoreSslError);
140 SessionPrivate::SessionPrivate( Session *session )
143 state( Session::Disconnected ),
147 sslVersion( KTcpSocket::UnknownSslVersion ),
148 socketTimerInterval( 30000 )
152 SessionPrivate::~SessionPrivate()
157 void SessionPrivate::addJob(Job *job)
160 emit q->jobQueueSizeChanged( q->jobQueueSize() );
165 if ( state != Session::Disconnected ) {
170 void SessionPrivate::startNext()
175 void SessionPrivate::doStartNext()
177 if ( queue.isEmpty() || jobRunning || !isSocketConnected ) {
181 restartSocketTimer();
184 currentJob = queue.dequeue();
185 currentJob->doStart();
188 void SessionPrivate::jobDone( KJob *job )
191 Q_ASSERT( job == currentJob );
197 emit q->jobQueueSizeChanged( q->jobQueueSize() );
201 void SessionPrivate::jobDestroyed(
QObject *job )
203 queue.removeAll( static_cast<KIMAP::Job*>( job ) );
204 if ( currentJob == job ) {
209 void SessionPrivate::responseReceived(
const Message &response )
211 if ( logger && ( state == Session::Authenticated || state == Session::Selected ) ) {
212 logger->dataReceived( response.toString() );
218 if ( response.content.size()>=1 ) {
219 tag = response.content[0].toString();
222 if ( response.content.size()>=2 ) {
223 code = response.content[1].toString();
228 if ( code ==
"BYE" ) {
229 Message simplified = response;
230 if ( simplified.content.size() >= 2 ) {
231 simplified.content.removeFirst();
232 simplified.content.removeFirst();
234 kDebug() <<
"Received BYE: " << simplified.toString();
239 case Session::Disconnected:
240 if ( socketTimer.isActive() ) {
243 if ( code ==
"OK" ) {
244 setState( Session::NotAuthenticated );
246 Message simplified = response;
247 simplified.content.removeFirst();
248 simplified.content.removeFirst();
249 greeting = simplified.toString().trimmed();
252 }
else if ( code ==
"PREAUTH" ) {
253 setState( Session::Authenticated );
255 Message simplified = response;
256 simplified.content.removeFirst();
257 simplified.content.removeFirst();
258 greeting = simplified.toString().trimmed();
262 thread->closeSocket();
265 case Session::NotAuthenticated:
266 if ( code ==
"OK" && tag == authTag ) {
267 setState( Session::Authenticated );
270 case Session::Authenticated:
271 if ( code ==
"OK" && tag == selectTag ) {
272 setState( Session::Selected );
273 currentMailBox = upcomingMailBox;
276 case Session::Selected:
277 if ( ( code ==
"OK" && tag == closeTag ) ||
278 ( code !=
"OK" && tag == selectTag ) ) {
279 setState( Session::Authenticated );
281 }
else if ( code ==
"OK" && tag == selectTag ) {
282 currentMailBox = upcomingMailBox;
287 if ( tag == authTag ) {
290 if ( tag == selectTag ) {
293 if ( tag == closeTag ) {
298 if ( currentJob != 0 ) {
299 restartSocketTimer();
300 currentJob->handleResponse( response );
302 qWarning() <<
"A message was received from the server with no job to handle it:"
303 << response.toString()
304 <<
'(' + response.toString().toHex() +
')';
308 void SessionPrivate::setState(Session::State s)
311 Session::State oldState = state;
313 emit q->stateChanged( state, oldState );
323 payload +=
' ' + args;
328 if ( command ==
"LOGIN" || command ==
"AUTHENTICATE" ) {
330 }
else if ( command ==
"SELECT" || command ==
"EXAMINE" ) {
332 upcomingMailBox = args;
333 upcomingMailBox.
remove( 0, 1 );
334 upcomingMailBox = upcomingMailBox.
left( upcomingMailBox.indexOf(
'\"') );
335 upcomingMailBox = KIMAP::decodeImapFolderName( upcomingMailBox );
336 }
else if ( command ==
"CLOSE" ) {
342 void SessionPrivate::sendData(
const QByteArray &data )
344 restartSocketTimer();
346 if ( logger && ( state == Session::Authenticated || state == Session::Selected ) ) {
347 logger->dataSent( data );
350 thread->sendData( data +
"\r\n" );
353 void SessionPrivate::socketConnected()
356 isSocketConnected =
true;
358 bool willUseSsl =
false;
359 if ( !queue.isEmpty() ) {
360 KIMAP::LoginJob *login = qobject_cast<KIMAP::LoginJob*>( queue.first() );
362 willUseSsl = ( login->encryptionMode() == KIMAP::LoginJob::SslV2 ) ||
363 ( login->encryptionMode() == KIMAP::LoginJob::SslV3 ) ||
364 ( login->encryptionMode() == KIMAP::LoginJob::SslV3_1 ) ||
365 ( login->encryptionMode() == KIMAP::LoginJob::AnySslVersion );
367 userName = login->userName();
371 if ( state == Session::Disconnected && willUseSsl ) {
378 void SessionPrivate::socketDisconnected()
380 if ( socketTimer.isActive() ) {
384 if ( logger && ( state == Session::Authenticated || state == Session::Selected ) ) {
385 logger->disconnectionOccured();
388 if ( state != Session::Disconnected ) {
389 setState( Session::Disconnected );
390 emit q->connectionLost();
392 emit q->connectionFailed();
395 isSocketConnected =
false;
400 void SessionPrivate::socketActivity()
402 restartSocketTimer();
405 void SessionPrivate::socketError(KTcpSocket::Error error)
407 if ( socketTimer.isActive() ) {
412 currentJob->setSocketError(error);
413 }
else if ( !queue.isEmpty() ) {
414 currentJob = queue.takeFirst();
415 currentJob->setSocketError(error);
418 if ( isSocketConnected ) {
419 thread->closeSocket();
421 emit q->connectionFailed();
422 emit q->connectionLost();
427 void SessionPrivate::clearJobQueue()
430 currentJob->connectionLost();
431 }
else if ( !queue.isEmpty() ) {
432 currentJob = queue.takeFirst();
433 currentJob->connectionLost();
437 qDeleteAll(queueCopy);
439 emit q->jobQueueSizeChanged( 0 );
442 void SessionPrivate::startSsl(
const KTcpSocket::SslVersion &version)
444 thread->startSsl( version );
447 QString Session::selectedMailBox()
const
452 void SessionPrivate::onEncryptionNegotiationResult(
bool isEncrypted, KTcpSocket::SslVersion version)
455 sslVersion = version;
457 sslVersion = KTcpSocket::UnknownSslVersion;
459 emit encryptionNegotiationResult( isEncrypted );
462 KTcpSocket::SslVersion SessionPrivate::negotiatedEncryption()
const
467 void SessionPrivate::setSocketTimeout(
int ms )
469 bool timerActive = socketTimer.isActive();
475 socketTimerInterval = ms;
482 int SessionPrivate::socketTimeout()
const
484 return socketTimerInterval;
487 void SessionPrivate::startSocketTimer()
489 if ( socketTimerInterval < 0 ) {
492 Q_ASSERT( !socketTimer.isActive() );
494 socketTimer.start( socketTimerInterval );
497 void SessionPrivate::stopSocketTimer()
499 if ( socketTimerInterval < 0 ) {
506 void SessionPrivate::restartSocketTimer()
508 if ( socketTimer.isActive() ) {
514 void SessionPrivate::onSocketTimeout()
516 kDebug() <<
"Socket timeout!";
517 thread->closeSocket();
520 void Session::setTimeout(
int timeout )
522 d->setSocketTimeout( timeout * 1000 );
525 int Session::timeout()
const
527 return d->socketTimeout() / 1000;
530 #include "moc_session.cpp"
531 #include "moc_session_p.cpp"
This file is part of the IMAP support library and defines the RfcCodecs class.
QString fromUtf8(const char *str, int size)
QByteArray number(int n, int base)
QByteArray left(int len) const
Interface to display communication errors and wait for user feedback.
QByteArray rightJustified(int width, char fill, bool truncate) const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QByteArray & remove(int pos, int len)