7#include "sessionthread_p.h"
9#include <KSslErrorUiData>
11#include "kimap_debug.h"
13#include <QNetworkProxy>
17#include "imapstreamparser.h"
18#include "response_p.h"
26static const int _kimap_abstractSocketError = qRegisterMetaType<QAbstractSocket::SocketError>();
27static const int _kimap_sslErrorUiData = qRegisterMetaType<KSslErrorUiData>();
30SessionThread::SessionThread(
const QString &hostName, quint16 port)
32 , m_hostName(hostName)
43SessionThread::~SessionThread()
46 if (!thread()->wait(10 * 1000)) {
47 qCWarning(KIMAP_LOG) <<
"Session thread refuses to die, killing harder...";
48 thread()->terminate();
56void SessionThread::setUseNetworkProxy(
bool useProxy)
61 setUseProxyInternal(useProxy);
67void SessionThread::sendData(
const QByteArray &payload)
71 m_dataQueue.enqueue(payload);
76void SessionThread::writeDataQueue()
84 while (!m_dataQueue.isEmpty()) {
85 m_socket->write(m_dataQueue.dequeue());
90void SessionThread::readMessage()
93 if (!m_stream || m_stream->availableDataSize() == 0) {
101 while (!m_stream->atCommandEnd()) {
102 if (m_stream->hasString()) {
104 if (
string ==
"NIL") {
105 *payload << Response::Part(QList<QByteArray>());
107 *payload << Response::Part(
string);
109 }
else if (m_stream->hasList()) {
110 *payload << Response::Part(m_stream->readParenthesizedList());
111 }
else if (m_stream->hasResponseCode()) {
112 payload = &message.responseCode;
113 }
else if (m_stream->atResponseCodeEnd()) {
114 payload = &message.content;
115 }
else if (m_stream->hasLiteral()) {
117 while (!m_stream->atLiteralEnd()) {
118 literal += m_stream->readLiteralPart();
120 *payload << Response::Part(literal);
124 qWarning(
"Inconsistent state, probably due to some packet loss");
130 Q_EMIT responseReceived(message);
132 }
catch (
const KIMAP::ImapParserException &e) {
133 qCWarning(KIMAP_LOG) <<
"The stream parser raised an exception:" << e.what();
136 if (m_stream->availableDataSize() > 1) {
142void SessionThread::closeSocket()
148void SessionThread::doCloseSocket()
154 m_encryptedMode =
false;
155 qCDebug(KIMAP_LOG) <<
"close";
160void SessionThread::reconnect()
163 if (m_socket ==
nullptr) {
166 if (m_socket->state() != QSslSocket::ConnectedState && m_socket->state() != QSslSocket::ConnectingState) {
169 qCDebug(KIMAP_LOG) <<
"Connecting to IMAP server with no proxy";
172 qCDebug(KIMAP_LOG) <<
"Connecting to IMAP server using default system proxy";
175 m_socket->setProxy(proxy);
177 if (m_encryptedMode) {
178 qCDebug(KIMAP_LOG) <<
"connectToHostEncrypted" << m_hostName << m_port;
179 m_socket->connectToHostEncrypted(m_hostName, m_port);
181 qCDebug(KIMAP_LOG) <<
"connectToHost" << m_hostName << m_port;
182 m_socket->connectToHost(m_hostName, m_port);
188void SessionThread::threadInit()
191 m_socket = std::make_unique<QSslSocket>();
192 m_stream = std::make_unique<ImapStreamParser>(m_socket.get());
197 connect(m_socket.get(), &QSslSocket::connected,
this, &SessionThread::socketConnected);
201 connect(m_socket.get(), &QSslSocket::encryptedBytesWritten,
this, &SessionThread::socketActivity);
207void SessionThread::threadQuit()
216void SessionThread::setUseProxyInternal(
bool useProxy)
218 m_useProxy = useProxy;
219 if (m_socket !=
nullptr) {
220 if (m_socket->state() != QSslSocket::UnconnectedState) {
221 m_socket->disconnectFromHost();
231 doStartSsl(protocol);
243 m_socket->setProtocol(protocol);
244 m_socket->ignoreSslErrors();
245 connect(m_socket.get(), &QSslSocket::encrypted,
this, &SessionThread::sslConnected);
246 m_socket->startClientEncryption();
250void SessionThread::slotSocketDisconnected()
253 Q_EMIT socketDisconnected();
263 Q_EMIT socketError(error);
267void SessionThread::sslConnected()
273 QSslCipher cipher = m_socket->sessionCipher();
274 if (!m_socket->sslHandshakeErrors().isEmpty() || !m_socket->isEncrypted() || cipher.isNull() || cipher.usedBits() == 0) {
275 qCDebug(KIMAP_LOG) <<
"Initial SSL handshake failed. cipher.isNull() is" << cipher.isNull() <<
", cipher.usedBits() is" << cipher.usedBits()
276 <<
", the socket says:" << m_socket->errorString() <<
"and the list of SSL errors contains" << m_socket->sslHandshakeErrors().count()
279 Q_EMIT sslError(errorData);
281 qCDebug(KIMAP_LOG) <<
"TLS negotiation done, the negotiated protocol is" << cipher.protocolString();
282 m_encryptedMode =
true;
283 Q_EMIT encryptionNegotiationResult(
true, m_socket->sessionProtocol());
287void SessionThread::sslErrorHandlerResponse(
bool response)
290 doSslErrorHandlerResponse(response);
295void SessionThread::doSslErrorHandlerResponse(
bool response)
302 m_encryptedMode =
true;
303 Q_EMIT encryptionNegotiationResult(
true, m_socket->sessionProtocol());
305 m_encryptedMode =
false;
307 m_socket->disconnectFromHost();
311#include "moc_sessionthread_p.cpp"
void errorOccurred(QAbstractSocket::SocketError socketError)
void bytesWritten(qint64 bytes)
void setType(QNetworkProxy::ProxyType type)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QThread * currentThread()