11#include "ksmtp_debug.h"
14#include "serverresponse_p.h"
16#include "sessionthread_p.h"
18#include <QHostAddress>
28SessionPrivate::SessionPrivate(
Session *session)
32 qRegisterMetaType<QSsl::SslProtocol>();
33 qRegisterMetaType<KSslErrorUiData>();
36SessionPrivate::~SessionPrivate()
39 m_thread->wait(10000);
46 const bool ignore = m_uiProxy && m_uiProxy->ignoreSslError(data);
48 _t->handleSslErrorResponse(ignore);
52void SessionPrivate::setAuthenticationMethods(
const QList<QByteArray> &authMethods)
56 if (!m_authModes.contains(m)) {
57 m_authModes.append(m);
62void SessionPrivate::startHandshake()
70 hostname = QStringLiteral(
"localhost.invalid");
72 hostname += QStringLiteral(
".localnet");
77 if (!m_ehloRejected) {
82 setState(Session::Handshake);
88 , d(new SessionPrivate(this))
90 qRegisterMetaType<KSmtp::ServerResponse>(
"KSmtp::ServerResponse");
98 d->m_thread =
new SessionThread(saneHostName,
port,
this);
101 connect(d->m_thread, &SessionThread::sslError, d, &SessionPrivate::handleSslError);
104Session::~Session() =
default;
108 d->m_thread->setUseNetworkProxy(useProxy);
113 d->m_uiProxy = uiProxy;
123 return d->m_thread->hostName();
128 return d->m_thread->port();
138 return d->m_encryptionMode;
143 d->m_encryptionMode = mode;
148 return d->m_allowsTls;
153 return d->m_allowsDsn;
158 return d->m_authModes;
166void Session::setSocketTimeout(
int ms)
168 bool timerActive = d->m_socketTimer.isActive();
171 d->stopSocketTimer();
174 d->m_socketTimerInterval = ms;
177 d->startSocketTimer();
181int Session::socketTimeout()
const
183 return d->m_socketTimerInterval;
188 d->m_customHostname = hostname;
191QString Session::customHostname()
const
193 return d->m_customHostname;
199 d->m_thread->setConnectWithTls(d->m_encryptionMode ==
Session::TLS);
201 d->startSocketTimer();
221 Q_EMIT q->stateChanged(m_state);
224void SessionPrivate::sendData(
const QByteArray &data)
229 m_thread->sendData(data);
234void SessionPrivate::responseReceived(
const ServerResponse &r)
236 qCDebug(KSMTP_LOG) <<
"S:: [" << r.code() <<
"]" << (r.isMultiline() ?
"-" :
" ") << r.text();
239 m_thread->closeSocket();
244 if (r.isCode(500) || r.isCode(502)) {
245 if (!m_ehloRejected) {
247 m_ehloRejected =
true;
249 qCWarning(KSMTP_LOG) <<
"KSmtp::Session: Handshake failed with both EHLO and HELO";
253 }
else if (r.isCode(25)) {
254 if (r.text().startsWith(
"SIZE ")) {
255 m_size = r.text().remove(0,
QByteArray(
"SIZE ").size()).toInt();
256 }
else if (r.text() ==
"STARTTLS") {
258 }
else if (r.text().startsWith(
"AUTH ")) {
259 setAuthenticationMethods(r.text().remove(0,
QByteArray(
"AUTH ").size()).split(
' '));
260 }
else if (r.text() ==
"DSN") {
264 if (!r.isMultiline()) {
267 m_starttlsSent =
true;
268 sendData(QByteArrayLiteral(
"STARTTLS"));
270 qCWarning(KSMTP_LOG) <<
"STARTTLS not supported by the server!";
278 }
else if (r.isCode(220) && m_starttlsSent) {
279 m_starttlsSent =
false;
285 if (r.isCode(22) || m_ehloRejected) {
292 m_currentJob->handleResponse(r);
296void SessionPrivate::socketConnected()
303void SessionPrivate::socketDisconnected()
305 qCDebug(KSMTP_LOG) <<
"Socket disconnected";
307 m_thread->closeSocket();
310 m_currentJob->connectionLost();
311 }
else if (!m_queue.isEmpty()) {
312 m_currentJob = m_queue.takeFirst();
313 m_currentJob->connectionLost();
321void SessionPrivate::startSsl()
331void SessionPrivate::encryptionNegotiationResult(
bool encrypted,
QSsl::SslProtocol version)
341void SessionPrivate::addJob(
Job *job)
352 m_thread->reconnect();
356void SessionPrivate::startNext()
363void SessionPrivate::doStartNext()
372 m_currentJob = m_queue.dequeue();
373 m_currentJob->doStart();
377 if (qobject_cast<const KSmtp::SendJob *>(m_currentJob)) {
382void SessionPrivate::jobDone(
KJob *job)
385 Q_ASSERT(job == m_currentJob);
391 if (!qobject_cast<const KSmtp::SendJob *>(m_currentJob)) {
396 m_jobRunning =
false;
397 m_currentJob =
nullptr;
402void SessionPrivate::jobDestroyed(
QObject *job)
404 m_queue.removeAll(
static_cast<Job *
>(job));
405 if (m_currentJob == job) {
406 m_currentJob =
nullptr;
410void SessionPrivate::startSocketTimer()
412 if (m_socketTimerInterval < 0) {
415 Q_ASSERT(!m_socketTimer.isActive());
419 m_socketTimer.setSingleShot(
true);
420 m_socketTimer.start(m_socketTimerInterval);
423void SessionPrivate::stopSocketTimer()
425 if (m_socketTimerInterval < 0) {
428 Q_ASSERT(m_socketTimer.isActive());
430 m_socketTimer.stop();
431 disconnect(&m_socketTimer, &
QTimer::timeout,
this, &SessionPrivate::onSocketTimeout);
434void SessionPrivate::onSocketTimeout()
436 socketDisconnected();
439ServerResponse::ServerResponse(
int code,
const QByteArray &text,
bool multiline)
442 , m_multiline(multiline)
446bool ServerResponse::isMultiline()
const
451int ServerResponse::code()
const
461bool ServerResponse::isCode(
int other)
const
463 int otherCpy = other;
469 while (otherCpy > 0) {
476 for (
int i = 0; i < 3 - codeLength; i++) {
480 return m_code / div == other;
483#include "moc_session_p.cpp"
485#include "moc_session.cpp"
@ Disconnected
The Session is not connected to the server.
@ NotAuthenticated
The Session is ready for login.
void quit()
Requests the server to quit the connection.
void setCustomHostname(const QString &hostname)
Custom hostname to send in EHLO/HELO command.
void setEncryptionMode(EncryptionMode mode)
Sets the encryption mode for this session.
bool allowsTls() const
Returns true if the SMTP server has indicated that it allows TLS connections, false otherwise.
QString hostName() const
Returns the host name that has been provided in the Session's constructor.
EncryptionMode encryptionMode() const
Returns the requested encryption mode for this session.
void setUseNetworkProxy(bool useProxy)
Sets whether the SMTP network connection should use the system proxy settings.
EncryptionMode
Transport encryption for a session.
@ TLS
Use TLS encryption on the socket.
@ STARTTLS
Use STARTTLS to upgrade an unencrypted connection to encrypted after the initial handshake.
void open()
Opens the connection to the server.
QStringList availableAuthModes() const
int sizeLimit() const
Returns the maximum message size in bytes that the server accepts.
quint16 port() const
Returns the port number that has been provided in the Session's constructor.
bool allowsDsn() const
Returns true if the SMTP server has indicated that it allows Delivery Status Notification (DSN) suppo...
KDB_EXPORT KDbVersionInfo version()
KIOCORE_EXPORT CopyJob * copy(const QList< QUrl > &src, const QUrl &dest, JobFlags flags=DefaultFlags)
NETWORKMANAGERQT_EXPORT QString hostname()
bool setAddress(const QString &address)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void destroyed(QObject *obj)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString fromLatin1(QByteArrayView str)
bool isEmpty() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QByteArray toAce(const QString &domain, AceProcessingOptions options)