Commit 4cd90762 authored by Daniel Vrátil's avatar Daniel Vrátil 🤖
Browse files

Port away from KTcpSocket to QSslSocket

Test Plan:
Tested TLS and plain connection against my Cyrus IMAP server and SSL
connection against Gmail.

Reviewers: vkrause

Reviewed By: vkrause

Subscribers: kde-pim

Tags: #kde_pim

Differential Revision: https://phabricator.kde.org/D24438
parent c4609178
......@@ -3,6 +3,8 @@ set(PIM_VERSION "5.12.40")
project(KIMAP VERSION ${PIM_VERSION})
set(CMAKE_CXX_STANDARD 14)
# ECM setup
set(KF5_MIN_VERSION "5.62.0")
......
......@@ -21,7 +21,7 @@
#define KIMAP_JOB_P_H
#include "session.h"
#include <ktcpsocket.h>
#include <QAbstractSocket>
namespace KIMAP
{
......@@ -31,7 +31,7 @@ class SessionPrivate;
class JobPrivate
{
public:
JobPrivate(Session *session, const QString &name) : m_session(session), m_socketError(KTcpSocket::UnknownError)
JobPrivate(Session *session, const QString &name) : m_session(session)
{
m_name = name;
}
......@@ -47,7 +47,7 @@ public:
return m_session->d;
}
void setSocketError(KTcpSocket::Error error)
void setSocketError(QAbstractSocket::SocketError error)
{
m_socketError = error;
}
......@@ -55,7 +55,7 @@ public:
QList<QByteArray> tags;
Session *m_session = nullptr;
QString m_name;
KTcpSocket::Error m_socketError;
QAbstractSocket::SocketError m_socketError = QAbstractSocket::UnknownSocketError;
};
}
......
......@@ -21,8 +21,9 @@
#include "loginjob.h"
#include <KLocalizedString>
#include <QSslSocket>
#include "kimap_debug.h"
#include <ktcpsocket.h>
#include "job_p.h"
#include "response_p.h"
......@@ -207,14 +208,14 @@ void LoginJob::doStart()
EncryptionMode encryptionMode = d->encryptionMode;
const auto negotiatedEncryption = d->sessionInternal()->negotiatedEncryption();
if (negotiatedEncryption != KTcpSocket::UnknownSslVersion) {
if (negotiatedEncryption != QSsl::UnknownProtocol) {
// If the socket is already encrypted, pretend we did not want any
// encryption
encryptionMode = Unencrypted;
}
if (encryptionMode == SSLorTLS) {
d->sessionInternal()->startSsl(KTcpSocket::SecureProtocols);
d->sessionInternal()->startSsl(QSsl::SecureProtocols);
} else if (encryptionMode == STARTTLS) {
// Check if STARTTLS is supported
d->authState = LoginJobPrivate::PreStartTlsCapability;
......@@ -363,7 +364,7 @@ void LoginJob::handleResponse(const Response &response)
break;
case LoginJobPrivate::StartTls:
d->sessionInternal()->startSsl(KTcpSocket::SecureProtocols);
d->sessionInternal()->startSsl(QSsl::SecureProtocols);
break;
case LoginJobPrivate::Capability:
......@@ -573,7 +574,7 @@ void LoginJob::connectionLost()
//the TLS handshake failed and the socket was reconnected in normal mode
if (d->authState != LoginJobPrivate::StartTls) {
qCWarning(KIMAP_LOG) << "Connection to server lost " << d->m_socketError;
if (d->m_socketError == KTcpSocket::SslHandshakeFailedError) {
if (d->m_socketError == QAbstractSocket::SslHandshakeFailedError) {
setError(KJob::UserDefinedError);
setErrorText(i18n("SSL handshake failed."));
emitResult();
......
......@@ -37,9 +37,9 @@
#include "sessionthread_p.h"
#include "rfccodecs.h"
Q_DECLARE_METATYPE(KTcpSocket::SslVersion)
Q_DECLARE_METATYPE(QSsl::SslProtocol)
Q_DECLARE_METATYPE(QSslSocket::SslMode)
static const int _kimap_sslVersionId = qRegisterMetaType<KTcpSocket::SslVersion>();
static const int _kimap_sslVersionId = qRegisterMetaType<QSsl::SslProtocol>();
using namespace KIMAP;
......@@ -148,7 +148,7 @@ SessionPrivate::SessionPrivate(Session *session)
jobRunning(false),
currentJob(nullptr),
tagCount(0),
sslVersion(KTcpSocket::UnknownSslVersion),
sslVersion(QSsl::UnknownProtocol),
socketTimerInterval(30000) // By default timeouts on 30s
{
}
......@@ -407,7 +407,7 @@ void SessionPrivate::socketActivity()
restartSocketTimer();
}
void SessionPrivate::socketError(KTcpSocket::Error error)
void SessionPrivate::socketError(QAbstractSocket::SocketError error)
{
if (socketTimer.isActive()) {
stopSocketTimer();
......@@ -443,9 +443,9 @@ void SessionPrivate::clearJobQueue()
emit q->jobQueueSizeChanged(0);
}
void SessionPrivate::startSsl(KTcpSocket::SslVersion version)
void SessionPrivate::startSsl(QSsl::SslProtocol protocol)
{
thread->startSsl(version);
thread->startSsl(protocol);
}
QString Session::selectedMailBox() const
......@@ -453,17 +453,17 @@ QString Session::selectedMailBox() const
return QString::fromUtf8(d->currentMailBox);
}
void SessionPrivate::onEncryptionNegotiationResult(bool isEncrypted, KTcpSocket::SslVersion version)
void SessionPrivate::onEncryptionNegotiationResult(bool isEncrypted, QSsl::SslProtocol protocol)
{
if (isEncrypted) {
sslVersion = version;
sslVersion = protocol;
} else {
sslVersion = KTcpSocket::UnknownSslVersion;
sslVersion = QSsl::UnknownProtocol;
}
emit encryptionNegotiationResult(isEncrypted);
}
KTcpSocket::SslVersion SessionPrivate::negotiatedEncryption() const
QSsl::SslProtocol SessionPrivate::negotiatedEncryption() const
{
return sslVersion;
}
......
......@@ -23,12 +23,11 @@
#include "session.h"
#include "sessionuiproxy.h"
#include <ktcpsocket.h>
#include <QObject>
#include <QQueue>
#include <QString>
#include <QTimer>
#include <QSslSocket>
class KJob;
......@@ -52,10 +51,10 @@ public:
void addJob(Job *job);
QByteArray sendCommand(const QByteArray &command, const QByteArray &args = QByteArray());
void startSsl(KTcpSocket::SslVersion version);
void startSsl(QSsl::SslProtocol protocol);
void sendData(const QByteArray &data);
KTcpSocket::SslVersion negotiatedEncryption() const;
QSsl::SslProtocol negotiatedEncryption() const;
void setSocketTimeout(int ms);
int socketTimeout() const;
......@@ -64,7 +63,7 @@ Q_SIGNALS:
void encryptionNegotiationResult(bool);
private Q_SLOTS:
void onEncryptionNegotiationResult(bool isEncrypted, KTcpSocket::SslVersion sslVersion);
void onEncryptionNegotiationResult(bool isEncrypted, QSsl::SslProtocol sslVersion);
void onSocketTimeout();
void doStartNext();
......@@ -74,7 +73,7 @@ private Q_SLOTS:
void socketConnected();
void socketDisconnected();
void socketError(KTcpSocket::Error);
void socketError(QAbstractSocket::SocketError error);
void socketActivity();
void handleSslError(const KSslErrorUiData &errorData);
......@@ -112,7 +111,7 @@ private:
QByteArray upcomingMailBox;
quint16 tagCount;
KTcpSocket::SslVersion sslVersion;
QSsl::SslProtocol sslVersion;
int socketTimerInterval = 0;
QTimer socketTimer;
......
......@@ -19,10 +19,12 @@
#include "sessionthread_p.h"
#include <KSslErrorUiData>
#include <QDebug>
#include <QThread>
#include <QNetworkProxy>
#include <QSslCipher>
#include "kimap_debug.h"
#include "imapstreamparser.h"
......@@ -30,14 +32,15 @@
using namespace KIMAP;
Q_DECLARE_METATYPE(KTcpSocket::Error)
Q_DECLARE_METATYPE(KSslErrorUiData)
static const int _kimap_socketErrorTypeId = qRegisterMetaType<KTcpSocket::Error>();
namespace {
static const int _kimap_abstractSocketError = qRegisterMetaType<QAbstractSocket::SocketError>();
static const int _kimap_sslErrorUiData = qRegisterMetaType<KSslErrorUiData>();
}
SessionThread::SessionThread(const QString &hostName, quint16 port)
: QObject(), m_hostName(hostName), m_port(port),
m_socket(nullptr), m_stream(nullptr), m_mutex(),
m_encryptedMode(false),
m_useProxy(false)
{
......@@ -168,8 +171,8 @@ void SessionThread::reconnect()
if (m_socket == nullptr) { // threadQuit already called
return;
}
if (m_socket->state() != SessionSocket::ConnectedState &&
m_socket->state() != SessionSocket::ConnectingState) {
if (m_socket->state() != QSslSocket::ConnectedState &&
m_socket->state() != QSslSocket::ConnectingState) {
QNetworkProxy proxy;
if (!m_useProxy) {
......@@ -195,25 +198,23 @@ void SessionThread::reconnect()
void SessionThread::threadInit()
{
Q_ASSERT(QThread::currentThread() == thread());
m_socket = new SessionSocket;
m_stream = new ImapStreamParser(m_socket);
connect(m_socket, &QIODevice::readyRead,
m_socket = std::make_unique<QSslSocket>();
m_stream = std::make_unique<ImapStreamParser>(m_socket.get());
connect(m_socket.get(), &QIODevice::readyRead,
this, &SessionThread::readMessage, Qt::QueuedConnection);
// Delay the call to slotSocketDisconnected so that it finishes disconnecting before we call reconnect()
connect(m_socket, &KTcpSocket::disconnected,
connect(m_socket.get(), &QSslSocket::disconnected,
this, &SessionThread::slotSocketDisconnected, Qt::QueuedConnection);
connect(m_socket, &KTcpSocket::connected,
connect(m_socket.get(), &QSslSocket::connected,
this, &SessionThread::socketConnected);
connect(m_socket, SIGNAL(error(KTcpSocket::Error)),
this, SLOT(slotSocketError(KTcpSocket::Error)));
connect(m_socket, &QIODevice::bytesWritten,
connect(m_socket.get(), QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error),
this, &SessionThread::slotSocketError);
connect(m_socket.get(), &QIODevice::bytesWritten,
this, &SessionThread::socketActivity);
if (m_socket->metaObject()->indexOfSignal("encryptedBytesWritten(qint64)") > -1) {
connect(m_socket, &KTcpSocket::encryptedBytesWritten, // needs kdelibs > 4.8
this, &SessionThread::socketActivity);
}
connect(m_socket, &QIODevice::readyRead,
connect(m_socket.get(), &QSslSocket::encryptedBytesWritten,
this, &SessionThread::socketActivity);
connect(m_socket.get(), &QIODevice::readyRead,
this, &SessionThread::socketActivity);
QMetaObject::invokeMethod(this, &SessionThread::reconnect, Qt::QueuedConnection);
}
......@@ -222,10 +223,8 @@ void SessionThread::threadInit()
void SessionThread::threadQuit()
{
Q_ASSERT(QThread::currentThread() == thread());
delete m_stream;
m_stream = nullptr;
delete m_socket;
m_socket = nullptr;
m_stream.reset();
m_socket.reset();
thread()->quit();
}
......@@ -234,7 +233,7 @@ void SessionThread::setUseProxyInternal(bool useProxy)
{
m_useProxy = useProxy;
if (m_socket != nullptr) {
if (m_socket->state() != SessionSocket::UnconnectedState) {
if (m_socket->state() != QSslSocket::UnconnectedState) {
m_socket->disconnectFromHost();
QMetaObject::invokeMethod(this, &SessionThread::reconnect, Qt::QueuedConnection);
}
......@@ -242,22 +241,22 @@ void SessionThread::setUseProxyInternal(bool useProxy)
}
// Called in primary thread
void SessionThread::startSsl(KTcpSocket::SslVersion version)
void SessionThread::startSsl(QSsl::SslProtocol protocol)
{
QMetaObject::invokeMethod(this, [this, version]() { doStartSsl(version); });
QMetaObject::invokeMethod(this, [this, protocol]() { doStartSsl(protocol); });
}
// Called in secondary thread (via invokeMethod)
void SessionThread::doStartSsl(KTcpSocket::SslVersion version)
void SessionThread::doStartSsl(QSsl::SslProtocol protocol)
{
Q_ASSERT(QThread::currentThread() == thread());
if (!m_socket) {
return;
}
m_socket->setAdvertisedSslVersion(version);
m_socket->ignoreSslErrors();
connect(m_socket, &KTcpSocket::encrypted, this, &SessionThread::sslConnected);
m_socket->setProtocol(protocol);
m_socket->ignoreSslErrors(); // Don't worry, errors are handled manually below
connect(m_socket.get(), &QSslSocket::encrypted, this, &SessionThread::sslConnected);
m_socket->startClientEncryption();
}
......@@ -269,13 +268,12 @@ void SessionThread::slotSocketDisconnected()
}
// Called in secondary thread
void SessionThread::slotSocketError(KTcpSocket::Error error)
void SessionThread::slotSocketError(QAbstractSocket::SocketError error)
{
Q_ASSERT(QThread::currentThread() == thread());
if (!m_socket) {
return;
}
Q_UNUSED(error); // can be used for debugging
emit socketError(error);
}
......@@ -286,22 +284,21 @@ void SessionThread::sslConnected()
if (!m_socket) {
return;
}
KSslCipher cipher = m_socket->sessionCipher();
QSslCipher cipher = m_socket->sessionCipher();
if (!m_socket->sslErrors().isEmpty() ||
m_socket->encryptionMode() != KTcpSocket::SslClientMode ||
cipher.isNull() || cipher.usedBits() == 0) {
if (!m_socket->sslErrors().isEmpty() || !m_socket->isEncrypted()
|| cipher.isNull() || cipher.usedBits() == 0) {
qCDebug(KIMAP_LOG) << "Initial SSL handshake failed. cipher.isNull() is" << cipher.isNull()
<< ", cipher.usedBits() is" << cipher.usedBits()
<< ", the socket says:" << m_socket->errorString()
<< "and the list of SSL errors contains"
<< m_socket->sslErrors().count() << "items.";
KSslErrorUiData errorData(m_socket);
KSslErrorUiData errorData(m_socket.get());
emit sslError(errorData);
} else {
qCDebug(KIMAP_LOG) << "TLS negotiation done.";
qCDebug(KIMAP_LOG) << "TLS negotiation done, the negotiated protocol is" << cipher.protocolString();
m_encryptedMode = true;
emit encryptionNegotiationResult(true, m_socket->negotiatedSslVersion());
emit encryptionNegotiationResult(true, m_socket->sessionProtocol());
}
}
......@@ -319,14 +316,14 @@ void SessionThread::doSslErrorHandlerResponse(bool response)
}
if (response) {
m_encryptedMode = true;
emit encryptionNegotiationResult(true, m_socket->negotiatedSslVersion());
emit encryptionNegotiationResult(true, m_socket->sessionProtocol());
} else {
m_encryptedMode = false;
//reconnect in unencrypted mode, so new commands can be issued
m_socket->disconnectFromHost();
m_socket->waitForDisconnected();
m_socket->connectToHost(m_hostName, m_port);
emit encryptionNegotiationResult(false, KTcpSocket::UnknownSslVersion);
emit encryptionNegotiationResult(false, QSsl::UnknownProtocol);
}
}
......
......@@ -23,9 +23,11 @@
#include <QMutex>
#include <QQueue>
#include <ktcpsocket.h>
#include <QSslSocket>
typedef KTcpSocket SessionSocket;
#include <memory>
class KSslErrorUiData;
namespace KIMAP
{
......@@ -56,16 +58,16 @@ public:
public Q_SLOTS:
void closeSocket();
void startSsl(KTcpSocket::SslVersion version);
void startSsl(QSsl::SslProtocol protocol);
void sslErrorHandlerResponse(bool result);
Q_SIGNALS:
void socketConnected();
void socketDisconnected();
void socketActivity();
void socketError(KTcpSocket::Error);
void socketError(QAbstractSocket::SocketError);
void responseReceived(const KIMAP::Response &response);
void encryptionNegotiationResult(bool, KTcpSocket::SslVersion);
void encryptionNegotiationResult(bool, QSsl::SslProtocol);
void sslError(const KSslErrorUiData &);
private Q_SLOTS:
......@@ -76,9 +78,9 @@ private Q_SLOTS:
void writeDataQueue();
void sslConnected();
void doCloseSocket();
void slotSocketError(KTcpSocket::Error);
void slotSocketError(QAbstractSocket::SocketError);
void slotSocketDisconnected();
void doStartSsl(KTcpSocket::SslVersion);
void doStartSsl(QSsl::SslProtocol);
void doSslErrorHandlerResponse(bool result);
void setUseProxyInternal(bool useProxy);
......@@ -86,8 +88,8 @@ private:
QString m_hostName;
quint16 m_port;
SessionSocket *m_socket = nullptr;
ImapStreamParser *m_stream = nullptr;
std::unique_ptr<QSslSocket> m_socket;
std::unique_ptr<ImapStreamParser> m_stream;
QQueue<QByteArray> m_dataQueue;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment