KIMAP Library
sessionthread.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "sessionthread_p.h"
00021
00022 #include <QtCore/QDebug>
00023 #include <QtCore/QTimer>
00024
00025 #include <KDE/KDebug>
00026
00027 #include "imapstreamparser.h"
00028 #include "message_p.h"
00029 #include "session.h"
00030
00031 using namespace KIMAP;
00032
00033 Q_DECLARE_METATYPE(KTcpSocket::Error)
00034 Q_DECLARE_METATYPE(KSslErrorUiData)
00035 static const int _kimap_socketErrorTypeId = qRegisterMetaType<KTcpSocket::Error>();
00036 static const int _kimap_sslErrorUiData = qRegisterMetaType<KSslErrorUiData>();
00037
00038 SessionThread::SessionThread( const QString &hostName, quint16 port, Session *parent )
00039 : QThread(), m_hostName(hostName), m_port(port),
00040 m_session(parent), m_socket(0), m_stream(0), m_encryptedMode(false)
00041 {
00042
00043
00044
00045 moveToThread(this);
00046 }
00047
00048 SessionThread::~SessionThread()
00049 {
00050
00051 QMetaObject::invokeMethod( this, "quit" );
00052 wait();
00053 }
00054
00055 void SessionThread::sendData( const QByteArray &payload )
00056 {
00057 QMutexLocker locker(&m_mutex);
00058
00059 m_dataQueue.enqueue( payload );
00060 QTimer::singleShot( 0, this, SLOT( writeDataQueue() ) );
00061 }
00062
00063 void SessionThread::writeDataQueue()
00064 {
00065 QMutexLocker locker(&m_mutex);
00066
00067 while ( !m_dataQueue.isEmpty() ) {
00068 m_socket->write( m_dataQueue.dequeue() );
00069 }
00070 }
00071
00072 void SessionThread::readMessage()
00073 {
00074 QMutexLocker locker(&m_mutex);
00075
00076 if ( m_stream->availableDataSize()==0 ) {
00077 return;
00078 }
00079
00080 Message message;
00081 QList<Message::Part> *payload = &message.content;
00082
00083 try {
00084 while ( !m_stream->atCommandEnd() ) {
00085 if ( m_stream->hasString() ) {
00086 QByteArray string = m_stream->readString();
00087 if ( string == "NIL" ) {
00088 *payload << Message::Part( QList<QByteArray>() );
00089 } else {
00090 *payload << Message::Part(string);
00091 }
00092 } else if ( m_stream->hasList() ) {
00093 *payload << Message::Part(m_stream->readParenthesizedList());
00094 } else if ( m_stream->hasResponseCode() ) {
00095 payload = &message.responseCode;
00096 } else if ( m_stream->atResponseCodeEnd() ) {
00097 payload = &message.content;
00098 } else if ( m_stream->hasLiteral() ) {
00099 QByteArray literal;
00100 while ( !m_stream->atLiteralEnd() ) {
00101 literal+= m_stream->readLiteralPart();
00102 }
00103 *payload << Message::Part(literal);
00104 }
00105 }
00106
00107 emit responseReceived(message);
00108
00109 } catch (KIMAP::ImapParserException e) {
00110 qWarning() << "The stream parser raised an exception:" << e.what();
00111 }
00112
00113 if ( m_stream->availableDataSize()>1 ) {
00114 QTimer::singleShot( 0, this, SLOT( readMessage() ) );
00115 }
00116
00117 }
00118
00119 void SessionThread::closeSocket()
00120 {
00121 QMutexLocker locker(&m_mutex);
00122
00123 m_encryptedMode = false;
00124 QMetaObject::invokeMethod( m_socket, "close" );
00125 }
00126
00127 void SessionThread::reconnect()
00128 {
00129 QMutexLocker locker(&m_mutex);
00130
00131 if ( m_socket->state() != SessionSocket::ConnectedState &&
00132 m_socket->state() != SessionSocket::ConnectingState ) {
00133 if (m_encryptedMode) {
00134 m_socket->connectToHostEncrypted(m_hostName, m_port);
00135 } else {
00136 m_socket->connectToHost(m_hostName, m_port);
00137 }
00138 }
00139 }
00140
00141 void SessionThread::run()
00142 {
00143 m_socket = new SessionSocket;
00144 m_stream = new ImapStreamParser( m_socket );
00145 connect( m_socket, SIGNAL(readyRead()),
00146 this, SLOT(readMessage()), Qt::QueuedConnection );
00147
00148 connect( m_socket, SIGNAL(disconnected()),
00149 m_session, SLOT(socketDisconnected()) );
00150 connect( m_socket, SIGNAL(connected()),
00151 m_session, SLOT(socketConnected()) );
00152 connect( m_socket, SIGNAL(error(KTcpSocket::Error)),
00153 m_session, SLOT(socketError()) );
00154
00155
00156 connect( this, SIGNAL(responseReceived(KIMAP::Message)),
00157 m_session, SLOT(responseReceived(KIMAP::Message)) );
00158
00159 QTimer::singleShot( 0, this, SLOT( reconnect() ) );
00160 exec();
00161
00162 delete m_stream;
00163 delete m_socket;
00164 }
00165
00166 void SessionThread::startSsl(const KTcpSocket::SslVersion &version)
00167 {
00168 QMutexLocker locker(&m_mutex);
00169
00170 m_socket->setAdvertisedSslVersion(version);
00171 m_socket->ignoreSslErrors();
00172 connect(m_socket, SIGNAL(encrypted()), this, SLOT(sslConnected()));
00173 m_socket->startClientEncryption();
00174 }
00175
00176 void SessionThread::sslConnected()
00177 {
00178 QMutexLocker locker(&m_mutex);
00179 KSslCipher cipher = m_socket->sessionCipher();
00180
00181 if ( m_socket->sslErrors().count() > 0 || m_socket->encryptionMode() != KTcpSocket::SslClientMode
00182 || cipher.isNull() || cipher.usedBits() == 0) {
00183 kDebug() << "Initial SSL handshake failed. cipher.isNull() is" << cipher.isNull()
00184 << ", cipher.usedBits() is" << cipher.usedBits()
00185 << ", the socket says:" << m_socket->errorString()
00186 << "and the list of SSL errors contains"
00187 << m_socket->sslErrors().count() << "items.";
00188 KSslErrorUiData errorData(m_socket);
00189 emit sslError(errorData);
00190 } else {
00191 kDebug() << "TLS negotiation done.";
00192 m_encryptedMode = true;
00193 emit encryptionNegotiationResult(true);
00194 }
00195 }
00196
00197 void SessionThread::sslErrorHandlerResponse(bool response)
00198 {
00199 QMutexLocker locker(&m_mutex);
00200 if (response) {
00201 m_encryptedMode = true;
00202 emit encryptionNegotiationResult(true);
00203 } else {
00204 m_encryptedMode = false;
00205
00206 m_socket->disconnectFromHost();
00207 m_socket->waitForDisconnected();
00208 m_socket->connectToHost(m_hostName, m_port);
00209 emit encryptionNegotiationResult(false);
00210 }
00211 }
00212
00213 #include "sessionthread_p.moc"
00214