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 *payload << Message::Part(m_stream->readString());
00087 } else if ( m_stream->hasList() ) {
00088 *payload << Message::Part(m_stream->readParenthesizedList());
00089 } else if ( m_stream->hasResponseCode() ) {
00090 payload = &message.responseCode;
00091 } else if ( m_stream->atResponseCodeEnd() ) {
00092 payload = &message.content;
00093 } else if ( m_stream->hasLiteral() ) {
00094 QByteArray literal;
00095 while ( !m_stream->atLiteralEnd() ) {
00096 literal+= m_stream->readLiteralPart();
00097 }
00098 *payload << Message::Part(literal);
00099 }
00100 }
00101
00102 emit responseReceived(message);
00103
00104 } catch (KIMAP::ImapParserException e) {
00105 qWarning() << "The stream parser raised an exception:" << e.what();
00106 }
00107
00108 if ( m_stream->availableDataSize()>1 ) {
00109 QTimer::singleShot( 0, this, SLOT( readMessage() ) );
00110 }
00111
00112 }
00113
00114 void SessionThread::closeSocket()
00115 {
00116 QMutexLocker locker(&m_mutex);
00117
00118 m_encryptedMode = false;
00119 QMetaObject::invokeMethod( m_socket, "close" );
00120 }
00121
00122 void SessionThread::reconnect()
00123 {
00124 QMutexLocker locker(&m_mutex);
00125
00126 if ( m_socket->state() != SessionSocket::ConnectedState &&
00127 m_socket->state() != SessionSocket::ConnectingState ) {
00128 if (m_encryptedMode) {
00129 m_socket->connectToHostEncrypted(m_hostName, m_port);
00130 } else {
00131 m_socket->connectToHost(m_hostName, m_port);
00132 }
00133 }
00134 }
00135
00136 void SessionThread::run()
00137 {
00138 m_socket = new SessionSocket;
00139 m_stream = new ImapStreamParser( m_socket );
00140 connect( m_socket, SIGNAL(readyRead()),
00141 this, SLOT(readMessage()), Qt::QueuedConnection );
00142
00143 connect( m_socket, SIGNAL(disconnected()),
00144 m_session, SLOT(socketDisconnected()) );
00145 connect( m_socket, SIGNAL(connected()),
00146 m_session, SLOT(socketConnected()) );
00147 connect( m_socket, SIGNAL(error(KTcpSocket::Error)),
00148 m_session, SLOT(socketError()) );
00149
00150
00151 connect( this, SIGNAL(responseReceived(KIMAP::Message)),
00152 m_session, SLOT(responseReceived(KIMAP::Message)) );
00153
00154 QTimer::singleShot( 0, this, SLOT( reconnect() ) );
00155 exec();
00156
00157 delete m_stream;
00158 delete m_socket;
00159 }
00160
00161 void SessionThread::startSsl(const KTcpSocket::SslVersion &version)
00162 {
00163 QMutexLocker locker(&m_mutex);
00164
00165 m_socket->setAdvertisedSslVersion(version);
00166 m_socket->ignoreSslErrors();
00167 connect(m_socket, SIGNAL(encrypted()), this, SLOT(sslConnected()));
00168 m_socket->startClientEncryption();
00169 }
00170
00171 void SessionThread::sslConnected()
00172 {
00173 QMutexLocker locker(&m_mutex);
00174 KSslCipher cipher = m_socket->sessionCipher();
00175
00176 if ( m_socket->sslErrors().count() > 0 || m_socket->encryptionMode() != KTcpSocket::SslClientMode
00177 || cipher.isNull() || cipher.usedBits() == 0) {
00178 kDebug() << "Initial SSL handshake failed. cipher.isNull() is" << cipher.isNull()
00179 << ", cipher.usedBits() is" << cipher.usedBits()
00180 << ", the socket says:" << m_socket->errorString()
00181 << "and the list of SSL errors contains"
00182 << m_socket->sslErrors().count() << "items.";
00183 KSslErrorUiData errorData(m_socket);
00184 emit sslError(errorData);
00185 } else {
00186 kDebug() << "TLS negotiation done.";
00187 m_encryptedMode = true;
00188 emit encryptionNegotiationResult(true);
00189 }
00190 }
00191
00192 void SessionThread::sslErrorHandlerResponse(bool response)
00193 {
00194 QMutexLocker locker(&m_mutex);
00195 if (response) {
00196 m_encryptedMode = true;
00197 emit encryptionNegotiationResult(true);
00198 } else {
00199 m_encryptedMode = false;
00200
00201 m_socket->disconnectFromHost();
00202 m_socket->waitForDisconnected();
00203 m_socket->connectToHost(m_hostName, m_port);
00204 emit encryptionNegotiationResult(false);
00205 }
00206 }
00207
00208 #include "sessionthread_p.moc"
00209