20#include "sessionthread_p.h"
22#include <QtCore/QDebug>
23#include <QtCore/QThread>
27#include "imapstreamparser.h"
32Q_DECLARE_METATYPE( KTcpSocket::Error )
33Q_DECLARE_METATYPE( KSslErrorUiData )
34static const int _kimap_socketErrorTypeId = qRegisterMetaType<KTcpSocket::Error>();
35static const int _kimap_sslErrorUiData = qRegisterMetaType<KSslErrorUiData>();
37SessionThread::SessionThread(
const QString &hostName, quint16 port )
38 : QObject(), m_hostName( hostName ), m_port( port ),
39 m_socket( 0 ), m_stream( 0 ), m_mutex(),
40 m_encryptedMode( false )
44 QThread* thread =
new QThread();
45 moveToThread( thread );
47 QMetaObject::invokeMethod(
this,
"threadInit" );
50SessionThread::~SessionThread()
52 QMetaObject::invokeMethod(
this,
"threadQuit" );
53 if ( !thread()->wait( 10 * 1000 ) ) {
54 kWarning() <<
"Session thread refuses to die, killing harder...";
55 thread()->terminate();
63void SessionThread::sendData(
const QByteArray &payload )
65 QMutexLocker locker( &m_mutex );
67 m_dataQueue.enqueue( payload );
68 QMetaObject::invokeMethod(
this,
"writeDataQueue" );
72void SessionThread::writeDataQueue()
74 Q_ASSERT( QThread::currentThread() == thread() );
77 QMutexLocker locker( &m_mutex );
79 while ( !m_dataQueue.isEmpty() ) {
80 m_socket->write( m_dataQueue.dequeue() );
85void SessionThread::readMessage()
87 Q_ASSERT( QThread::currentThread() == thread() );
88 if ( !m_stream || m_stream->availableDataSize() == 0 ) {
93 QList<Message::Part> *payload = &message.content;
99 if (
string ==
"NIL" ) {
100 *payload << Message::Part( QList<QByteArray>() );
102 *payload << Message::Part(
string );
104 }
else if ( m_stream->
hasList() ) {
107 payload = &message.responseCode;
109 payload = &message.content;
115 *payload << Message::Part( literal );
119 qWarning(
"Inconsistent state, probably due to some packet loss" );
125 emit responseReceived( message );
127 }
catch ( KIMAP::ImapParserException e ) {
128 qWarning() <<
"The stream parser raised an exception:" << e.what();
131 if ( m_stream->availableDataSize() > 1 ) {
132 QMetaObject::invokeMethod(
this,
"readMessage", Qt::QueuedConnection );
138void SessionThread::closeSocket()
140 QMetaObject::invokeMethod(
this,
"doCloseSocket", Qt::QueuedConnection );
144void SessionThread::doCloseSocket()
146 Q_ASSERT( QThread::currentThread() == thread() );
149 m_encryptedMode =
false;
155void SessionThread::reconnect()
157 Q_ASSERT( QThread::currentThread() == thread() );
160 if ( m_socket->state() != SessionSocket::ConnectedState &&
161 m_socket->state() != SessionSocket::ConnectingState ) {
162 if ( m_encryptedMode ) {
163 kDebug() <<
"connectToHostEncrypted" << m_hostName << m_port;
164 m_socket->connectToHostEncrypted( m_hostName, m_port );
166 kDebug() <<
"connectToHost" << m_hostName << m_port;
167 m_socket->connectToHost( m_hostName, m_port );
173void SessionThread::threadInit()
175 Q_ASSERT( QThread::currentThread() == thread() );
176 m_socket =
new SessionSocket;
178 connect( m_socket, SIGNAL(readyRead()),
179 this, SLOT(readMessage()), Qt::QueuedConnection );
182 connect( m_socket, SIGNAL(disconnected()),
183 this, SLOT(slotSocketDisconnected()), Qt::QueuedConnection );
184 connect( m_socket, SIGNAL(connected()),
185 this, SIGNAL(socketConnected()) );
186 connect( m_socket, SIGNAL(error(KTcpSocket::Error)),
187 this, SLOT(slotSocketError(KTcpSocket::Error)) );
188 connect( m_socket, SIGNAL(bytesWritten(qint64)),
189 this, SIGNAL(socketActivity()) );
190 if ( m_socket->metaObject()->indexOfSignal(
"encryptedBytesWritten(qint64)" ) > -1 ) {
191 connect( m_socket, SIGNAL(encryptedBytesWritten(qint64)),
192 this, SIGNAL(socketActivity()) );
194 connect( m_socket, SIGNAL(readyRead()),
195 this, SIGNAL(socketActivity()) );
197 QMetaObject::invokeMethod(
this,
"reconnect", Qt::QueuedConnection);
201void SessionThread::threadQuit()
203 Q_ASSERT( QThread::currentThread() == thread() );
212void SessionThread::startSsl( KTcpSocket::SslVersion version )
214 QMetaObject::invokeMethod(
this,
"doStartSsl", Q_ARG(KTcpSocket::SslVersion, version) );
218void SessionThread::doStartSsl( KTcpSocket::SslVersion version )
220 Q_ASSERT( QThread::currentThread() == thread() );
224 m_socket->setAdvertisedSslVersion( version );
225 m_socket->ignoreSslErrors();
226 connect( m_socket, SIGNAL(encrypted()),
this, SLOT(sslConnected()) );
227 m_socket->startClientEncryption();
231void SessionThread::slotSocketDisconnected()
233 Q_ASSERT( QThread::currentThread() == thread() );
234 emit socketDisconnected();
238void SessionThread::slotSocketError(KTcpSocket::Error error)
240 Q_ASSERT( QThread::currentThread() == thread() );
244 emit socketError(error);
248void SessionThread::sslConnected()
250 Q_ASSERT( QThread::currentThread() == thread() );
253 KSslCipher cipher = m_socket->sessionCipher();
255 if ( m_socket->sslErrors().count() > 0 ||
256 m_socket->encryptionMode() != KTcpSocket::SslClientMode ||
257 cipher.isNull() || cipher.usedBits() == 0 ) {
258 kDebug() <<
"Initial SSL handshake failed. cipher.isNull() is" << cipher.isNull()
259 <<
", cipher.usedBits() is" << cipher.usedBits()
260 <<
", the socket says:" << m_socket->errorString()
261 <<
"and the list of SSL errors contains"
262 << m_socket->sslErrors().count() <<
"items.";
263 KSslErrorUiData errorData( m_socket );
264 emit sslError( errorData );
266 kDebug() <<
"TLS negotiation done.";
267 m_encryptedMode =
true;
268 emit encryptionNegotiationResult(
true, m_socket->negotiatedSslVersion() );
272void SessionThread::sslErrorHandlerResponse(
bool response)
274 QMetaObject::invokeMethod(
this,
"doSslErrorHandlerResponse", Q_ARG(
bool, response));
278void SessionThread::doSslErrorHandlerResponse(
bool response)
280 Q_ASSERT( QThread::currentThread() == thread() );
284 m_encryptedMode =
true;
285 emit encryptionNegotiationResult(
true, m_socket->negotiatedSslVersion() );
287 m_encryptedMode =
false;
289 m_socket->disconnectFromHost();
290 m_socket->waitForDisconnected();
291 m_socket->connectToHost( m_hostName, m_port );
292 emit encryptionNegotiationResult(
false, KTcpSocket::UnknownSslVersion );
296#include "moc_sessionthread_p.cpp"
Parser for IMAP messages that operates on a local socket stream.
QList< QByteArray > readParenthesizedList()
Get he next parenthesized list.
bool hasList()
Check if the next data is a parenthesized list.
bool atResponseCodeEnd()
Check if the next data is a response code end.
bool atCommandEnd()
Check if the command end was reached.
bool atLiteralEnd() const
Check if the literal data end was reached.
bool hasLiteral()
Check if the next data is a literal data or not.
QByteArray readString()
Same as above, but without decoding it to utf8.
bool hasString()
Check if the next data is a string or not.
bool hasResponseCode()
Check if the next data is a response code.
QByteArray readLiteralPart()
Read the next literal sequence.