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 QTimer::singleShot( 0, this, SLOT( doCloseSocket() ) );
00125 }
00126
00127 void SessionThread::doCloseSocket()
00128 {
00129 QMutexLocker locker(&m_mutex);
00130
00131 m_socket->close();
00132 }
00133
00134 void SessionThread::reconnect()
00135 {
00136 QMutexLocker locker(&m_mutex);
00137
00138 if ( m_socket->state() != SessionSocket::ConnectedState &&
00139 m_socket->state() != SessionSocket::ConnectingState ) {
00140 if (m_encryptedMode) {
00141 m_socket->connectToHostEncrypted(m_hostName, m_port);
00142 } else {
00143 m_socket->connectToHost(m_hostName, m_port);
00144 }
00145 }
00146 }
00147
00148 void SessionThread::run()
00149 {
00150 m_socket = new SessionSocket;
00151 m_stream = new ImapStreamParser( m_socket );
00152 connect( m_socket, SIGNAL(readyRead()),
00153 this, SLOT(readMessage()), Qt::QueuedConnection );
00154
00155 connect( m_socket, SIGNAL(disconnected()),
00156 m_session, SLOT(socketDisconnected()) );
00157 connect( m_socket, SIGNAL(connected()),
00158 m_session, SLOT(socketConnected()) );
00159 connect( m_socket, SIGNAL(error(KTcpSocket::Error)),
00160 m_session, SLOT(socketError()) );
00161
00162
00163 connect( this, SIGNAL(responseReceived(KIMAP::Message)),
00164 m_session, SLOT(responseReceived(KIMAP::Message)) );
00165
00166 QTimer::singleShot( 0, this, SLOT( reconnect() ) );
00167 exec();
00168
00169 delete m_stream;
00170 delete m_socket;
00171 }
00172
00173 void SessionThread::startSsl(const KTcpSocket::SslVersion &version)
00174 {
00175 QMutexLocker locker(&m_mutex);
00176
00177 m_socket->setAdvertisedSslVersion(version);
00178 m_socket->ignoreSslErrors();
00179 connect(m_socket, SIGNAL(encrypted()), this, SLOT(sslConnected()));
00180 m_socket->startClientEncryption();
00181 }
00182
00183 void SessionThread::sslConnected()
00184 {
00185 QMutexLocker locker(&m_mutex);
00186 KSslCipher cipher = m_socket->sessionCipher();
00187
00188 if ( m_socket->sslErrors().count() > 0 || m_socket->encryptionMode() != KTcpSocket::SslClientMode
00189 || cipher.isNull() || cipher.usedBits() == 0) {
00190 kDebug() << "Initial SSL handshake failed. cipher.isNull() is" << cipher.isNull()
00191 << ", cipher.usedBits() is" << cipher.usedBits()
00192 << ", the socket says:" << m_socket->errorString()
00193 << "and the list of SSL errors contains"
00194 << m_socket->sslErrors().count() << "items.";
00195 KSslErrorUiData errorData(m_socket);
00196 emit sslError(errorData);
00197 } else {
00198 kDebug() << "TLS negotiation done.";
00199 m_encryptedMode = true;
00200 emit encryptionNegotiationResult(true, m_socket->negotiatedSslVersion());
00201 }
00202 }
00203
00204 void SessionThread::sslErrorHandlerResponse(bool response)
00205 {
00206 QMutexLocker locker(&m_mutex);
00207 if (response) {
00208 m_encryptedMode = true;
00209 emit encryptionNegotiationResult(true, m_socket->negotiatedSslVersion());
00210 } else {
00211 m_encryptedMode = false;
00212
00213 m_socket->disconnectFromHost();
00214 m_socket->waitForDisconnected();
00215 m_socket->connectToHost(m_hostName, m_port);
00216 emit encryptionNegotiationResult(false, KTcpSocket::UnknownSslVersion);
00217 }
00218 }
00219
00220 #include "sessionthread_p.moc"
00221