File indexing completed on 2024-06-23 05:15:11

0001 /*
0002   SPDX-FileCopyrightText: 2006-2007 KovoKs <info@kovoks.nl>
0003 
0004   SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 // Uncomment the next line for full comm debug
0008 // #define comm_debug
0009 
0010 // Own
0011 #include "socket.h"
0012 
0013 // Qt
0014 #include <QByteArray>
0015 #include <QNetworkProxy>
0016 // KDE
0017 #include "mailtransport_debug.h"
0018 
0019 using namespace MailTransport;
0020 
0021 namespace MailTransport
0022 {
0023 class SocketPrivate
0024 {
0025 public:
0026     SocketPrivate(Socket *s);
0027     Socket *const q;
0028     QSslSocket *socket = nullptr;
0029     QString server;
0030     QString protocol;
0031     int port = 0;
0032     bool secure = false;
0033 
0034     // slots
0035     void slotConnected();
0036     void slotStateChanged(QAbstractSocket::SocketState state);
0037     void slotModeChanged(QSslSocket::SslMode state);
0038     void slotSocketRead();
0039     void slotSslErrors(const QList<QSslError> &errors);
0040 
0041 private:
0042     QString m_msg;
0043 };
0044 }
0045 
0046 SocketPrivate::SocketPrivate(Socket *s)
0047     : q(s)
0048 {
0049 }
0050 
0051 void SocketPrivate::slotConnected()
0052 {
0053     qCDebug(MAILTRANSPORT_LOG);
0054 
0055     if (!secure) {
0056         qCDebug(MAILTRANSPORT_LOG) << "normal connect";
0057         Q_EMIT q->connected();
0058     } else {
0059         qCDebug(MAILTRANSPORT_LOG) << "encrypted connect";
0060         socket->startClientEncryption();
0061     }
0062 }
0063 
0064 void SocketPrivate::slotStateChanged(QAbstractSocket::SocketState state)
0065 {
0066 #ifdef comm_debug
0067     qCDebug(MAILTRANSPORT_LOG) << "State is now:" << (int)state;
0068 #endif
0069     if (state == QAbstractSocket::UnconnectedState) {
0070         Q_EMIT q->failed();
0071     }
0072 }
0073 
0074 void SocketPrivate::slotModeChanged(QSslSocket::SslMode state)
0075 {
0076 #ifdef comm_debug
0077     qCDebug(MAILTRANSPORT_LOG) << "Mode is now:" << state;
0078 #endif
0079     if (state == QSslSocket::SslClientMode) {
0080         Q_EMIT q->tlsDone();
0081     }
0082 }
0083 
0084 void SocketPrivate::slotSocketRead()
0085 {
0086     qCDebug(MAILTRANSPORT_LOG);
0087 
0088     if (!socket) {
0089         return;
0090     }
0091 
0092     m_msg += QLatin1StringView(socket->readAll());
0093 
0094     if (!m_msg.endsWith(QLatin1Char('\n'))) {
0095         return;
0096     }
0097 
0098 #ifdef comm_debug
0099     qCDebug(MAILTRANSPORT_LOG) << socket->isEncrypted() << m_msg.trimmed();
0100 #endif
0101 
0102     Q_EMIT q->data(m_msg);
0103     m_msg.clear();
0104 }
0105 
0106 void SocketPrivate::slotSslErrors(const QList<QSslError> &)
0107 {
0108     qCDebug(MAILTRANSPORT_LOG);
0109     /* We can safely ignore the errors, we are only interested in the
0110     capabilities. We're not sending auth info. */
0111     socket->ignoreSslErrors();
0112     Q_EMIT q->connected();
0113 }
0114 
0115 // ------------------ end private ---------------------------//
0116 
0117 Socket::Socket(QObject *parent)
0118     : QObject(parent)
0119     , d(new SocketPrivate(this))
0120 {
0121     qCDebug(MAILTRANSPORT_LOG);
0122 }
0123 
0124 Socket::~Socket()
0125 {
0126     qCDebug(MAILTRANSPORT_LOG);
0127 }
0128 
0129 void Socket::reconnect()
0130 {
0131     qCDebug(MAILTRANSPORT_LOG) << "Connecting to:" << d->server << ":" << d->port;
0132 
0133 #ifdef comm_debug
0134     // qCDebug(MAILTRANSPORT_LOG) << d->protocol;
0135 #endif
0136 
0137     if (d->socket) {
0138         return;
0139     }
0140 
0141     d->socket = new QSslSocket(this);
0142     d->socket->setProxy(QNetworkProxy::DefaultProxy);
0143     d->socket->connectToHost(d->server, d->port);
0144 
0145     d->socket->setProtocol(QSsl::AnyProtocol);
0146 
0147     connect(d->socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), SLOT(slotStateChanged(QAbstractSocket::SocketState)));
0148     connect(d->socket, SIGNAL(modeChanged(QSslSocket::SslMode)), SLOT(slotModeChanged(QSslSocket::SslMode)));
0149     connect(d->socket, SIGNAL(connected()), SLOT(slotConnected()));
0150     connect(d->socket, SIGNAL(readyRead()), SLOT(slotSocketRead()));
0151     connect(d->socket, &QSslSocket::encrypted, this, &Socket::connected);
0152     connect(d->socket, SIGNAL(sslErrors(QList<QSslError>)), SLOT(slotSslErrors(QList<QSslError>)));
0153 }
0154 
0155 void Socket::write(const QString &text)
0156 {
0157     // qCDebug(MAILTRANSPORT_LOG);
0158     // Eat things in the queue when there is no connection. We need
0159     // to get a connection first don't we...
0160     if (!d->socket || !available()) {
0161         return;
0162     }
0163 
0164     QByteArray cs = (text + QLatin1StringView("\r\n")).toLatin1();
0165 
0166 #ifdef comm_debug
0167     qCDebug(MAILTRANSPORT_LOG) << "C   :" << cs;
0168 #endif
0169 
0170     d->socket->write(cs.data(), cs.size());
0171 }
0172 
0173 bool Socket::available()
0174 {
0175     // qCDebug(MAILTRANSPORT_LOG);
0176     bool ok = d->socket && d->socket->state() == QAbstractSocket::ConnectedState;
0177     return ok;
0178 }
0179 
0180 void Socket::startTLS()
0181 {
0182     qCDebug(MAILTRANSPORT_LOG) << objectName();
0183     d->socket->setProtocol(QSsl::TlsV1_2OrLater);
0184     d->socket->startClientEncryption();
0185 }
0186 
0187 void Socket::setProtocol(const QString &proto)
0188 {
0189     d->protocol = proto;
0190 }
0191 
0192 void Socket::setServer(const QString &server)
0193 {
0194     d->server = server;
0195 }
0196 
0197 void Socket::setPort(int port)
0198 {
0199     d->port = port;
0200 }
0201 
0202 int Socket::port() const
0203 {
0204     return d->port;
0205 }
0206 
0207 void Socket::setSecure(bool what)
0208 {
0209     d->secure = what;
0210 }
0211 
0212 #include "moc_socket.cpp"