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 if ( !wait( 10 * 1000 ) ) {
00053 kWarning() << "Session thread refuses to die, killing harder...";
00054 terminate();
00055 }
00056 }
00057
00058 void SessionThread::sendData( const QByteArray &payload )
00059 {
00060 QMutexLocker locker(&m_mutex);
00061
00062 m_dataQueue.enqueue( payload );
00063 QTimer::singleShot( 0, this, SLOT( writeDataQueue() ) );
00064 }
00065
00066 void SessionThread::writeDataQueue()
00067 {
00068 QMutexLocker locker(&m_mutex);
00069
00070 while ( !m_dataQueue.isEmpty() ) {
00071 m_socket->write( m_dataQueue.dequeue() );
00072 }
00073 }
00074
00075 void SessionThread::readMessage()
00076 {
00077 QMutexLocker locker(&m_mutex);
00078
00079 if ( m_stream->availableDataSize()==0 ) {
00080 return;
00081 }
00082
00083 Message message;
00084 QList<Message::Part> *payload = &message.content;
00085
00086 try {
00087 while ( !m_stream->atCommandEnd() ) {
00088 if ( m_stream->hasString() ) {
00089 QByteArray string = m_stream->readString();
00090 if ( string == "NIL" ) {
00091 *payload << Message::Part( QList<QByteArray>() );
00092 } else {
00093 *payload << Message::Part(string);
00094 }
00095 } else if ( m_stream->hasList() ) {
00096 *payload << Message::Part(m_stream->readParenthesizedList());
00097 } else if ( m_stream->hasResponseCode() ) {
00098 payload = &message.responseCode;
00099 } else if ( m_stream->atResponseCodeEnd() ) {
00100 payload = &message.content;
00101 } else if ( m_stream->hasLiteral() ) {
00102 QByteArray literal;
00103 while ( !m_stream->atLiteralEnd() ) {
00104 literal+= m_stream->readLiteralPart();
00105 }
00106 *payload << Message::Part(literal);
00107 }
00108 }
00109
00110 emit responseReceived(message);
00111
00112 } catch (KIMAP::ImapParserException e) {
00113 qWarning() << "The stream parser raised an exception:" << e.what();
00114 }
00115
00116 if ( m_stream->availableDataSize()>1 ) {
00117 QTimer::singleShot( 0, this, SLOT( readMessage() ) );
00118 }
00119
00120 }
00121
00122 void SessionThread::closeSocket()
00123 {
00124 QTimer::singleShot( 0, this, SLOT( doCloseSocket() ) );
00125 }
00126
00127 void SessionThread::doCloseSocket()
00128 {
00129 m_encryptedMode = false;
00130 m_socket->close();
00131 }
00132
00133 void SessionThread::reconnect()
00134 {
00135 QMutexLocker locker(&m_mutex);
00136
00137 if ( m_socket->state() != SessionSocket::ConnectedState &&
00138 m_socket->state() != SessionSocket::ConnectingState ) {
00139 if (m_encryptedMode) {
00140 m_socket->connectToHostEncrypted(m_hostName, m_port);
00141 } else {
00142 m_socket->connectToHost(m_hostName, m_port);
00143 }
00144 }
00145 }
00146
00147 void SessionThread::run()
00148 {
00149 m_socket = new SessionSocket;
00150 m_stream = new ImapStreamParser( m_socket );
00151 connect( m_socket, SIGNAL(readyRead()),
00152 this, SLOT(readMessage()), Qt::QueuedConnection );
00153
00154 connect( m_socket, SIGNAL(disconnected()),
00155 m_session, SLOT(socketDisconnected()) );
00156 connect( m_socket, SIGNAL(connected()),
00157 m_session, SLOT(socketConnected()) );
00158 connect( m_socket, SIGNAL(error(KTcpSocket::Error)),
00159 m_session, SLOT(socketError()) );
00160
00161
00162 connect( this, SIGNAL(responseReceived(KIMAP::Message)),
00163 m_session, SLOT(responseReceived(KIMAP::Message)) );
00164
00165 QTimer::singleShot( 0, this, SLOT( reconnect() ) );
00166 exec();
00167
00168 delete m_stream;
00169 delete m_socket;
00170 }
00171
00172 void SessionThread::startSsl(const KTcpSocket::SslVersion &version)
00173 {
00174 QMutexLocker locker(&m_mutex);
00175
00176 m_socket->setAdvertisedSslVersion(version);
00177 m_socket->ignoreSslErrors();
00178 connect(m_socket, SIGNAL(encrypted()), this, SLOT(sslConnected()));
00179 m_socket->startClientEncryption();
00180 }
00181
00182 void SessionThread::sslConnected()
00183 {
00184 QMutexLocker locker(&m_mutex);
00185 KSslCipher cipher = m_socket->sessionCipher();
00186
00187 if ( m_socket->sslErrors().count() > 0 || m_socket->encryptionMode() != KTcpSocket::SslClientMode
00188 || cipher.isNull() || cipher.usedBits() == 0) {
00189 kDebug() << "Initial SSL handshake failed. cipher.isNull() is" << cipher.isNull()
00190 << ", cipher.usedBits() is" << cipher.usedBits()
00191 << ", the socket says:" << m_socket->errorString()
00192 << "and the list of SSL errors contains"
00193 << m_socket->sslErrors().count() << "items.";
00194 KSslErrorUiData errorData(m_socket);
00195 emit sslError(errorData);
00196 } else {
00197 kDebug() << "TLS negotiation done.";
00198 m_encryptedMode = true;
00199 emit encryptionNegotiationResult(true, m_socket->negotiatedSslVersion());
00200 }
00201 }
00202
00203 void SessionThread::sslErrorHandlerResponse(bool response)
00204 {
00205 QMutexLocker locker(&m_mutex);
00206 if (response) {
00207 m_encryptedMode = true;
00208 emit encryptionNegotiationResult(true, m_socket->negotiatedSslVersion());
00209 } else {
00210 m_encryptedMode = false;
00211
00212 m_socket->disconnectFromHost();
00213 m_socket->waitForDisconnected();
00214 m_socket->connectToHost(m_hostName, m_port);
00215 emit encryptionNegotiationResult(false, KTcpSocket::UnknownSslVersion);
00216 }
00217 }
00218
00219 #include "sessionthread_p.moc"
00220