Fix coding style (Issue #2192).

This commit is contained in:
Vladimir Golovnev (Glassez) 2015-05-13 18:39:48 +03:00
parent 191cdc2849
commit 5f288d228d
12 changed files with 820 additions and 784 deletions

View file

@ -42,7 +42,6 @@ QT_END_NAMESPACE
namespace Http namespace Http
{ {
class IRequestHandler; class IRequestHandler;
class Connection : public QObject class Connection : public QObject
@ -65,7 +64,6 @@ private:
IRequestHandler *m_requestHandler; IRequestHandler *m_requestHandler;
QByteArray m_receivedData; QByteArray m_receivedData;
}; };
} }
#endif // HTTP_CONNECTION_H #endif // HTTP_CONNECTION_H

View file

@ -33,14 +33,12 @@
namespace Http namespace Http
{ {
class IRequestHandler class IRequestHandler
{ {
public: public:
virtual ~IRequestHandler() {} virtual ~IRequestHandler() {}
virtual Response processRequest(const Request &request, const Environment &env) = 0; virtual Response processRequest(const Request &request, const Environment &env) = 0;
}; };
} }
#endif // HTTP_IREQUESTHANDLER_H #endif // HTTP_IREQUESTHANDLER_H

View file

@ -36,7 +36,6 @@
namespace Http namespace Http
{ {
class RequestParser class RequestParser
{ {
public: public:
@ -68,7 +67,6 @@ private:
const uint m_maxContentLength; const uint m_maxContentLength;
Request m_request; Request m_request;
}; };
} }
#endif // HTTP_REQUESTPARSER_H #endif // HTTP_REQUESTPARSER_H

View file

@ -34,7 +34,6 @@
namespace Http namespace Http
{ {
class ResponseBuilder : public QObject class ResponseBuilder : public QObject
{ {
public: public:
@ -54,7 +53,6 @@ private:
Response m_response; Response m_response;
}; };
} }
#endif // HTTP_RESPONSEBUILDER_H #endif // HTTP_RESPONSEBUILDER_H

View file

@ -37,13 +37,11 @@
namespace Http namespace Http
{ {
class ResponseGenerator class ResponseGenerator
{ {
public: public:
static QByteArray generate(Response response); static QByteArray generate(Response response);
}; };
} }
#endif // HTTP_RESPONSEGENERATOR_H #endif // HTTP_RESPONSEGENERATOR_H

View file

@ -41,7 +41,6 @@
namespace Http namespace Http
{ {
class IRequestHandler; class IRequestHandler;
class Connection; class Connection;
@ -74,7 +73,6 @@ private:
QSslKey m_key; QSslKey m_key;
#endif #endif
}; };
} }
#endif // HTTP_SERVER_H #endif // HTTP_SERVER_H

View file

@ -37,7 +37,6 @@ typedef QMap<QString, QString> QStringMap;
namespace Http namespace Http
{ {
const QString HEADER_SET_COOKIE = "Set-Cookie"; const QString HEADER_SET_COOKIE = "Set-Cookie";
const QString HEADER_CONTENT_TYPE = "Content-Type"; const QString HEADER_CONTENT_TYPE = "Content-Type";
const QString HEADER_CONTENT_ENCODING = "Content-Encoding"; const QString HEADER_CONTENT_ENCODING = "Content-Encoding";
@ -89,7 +88,6 @@ struct Response
Response(uint code = 200, const QString& text = "OK"): status(code, text) {} Response(uint code = 200, const QString& text = "OK"): status(code, text) {}
}; };
} }
#endif // HTTP_TYPES_H #endif // HTTP_TYPES_H

View file

@ -35,13 +35,16 @@
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
#include <QUrlQuery> #include <QUrlQuery>
#endif #endif
#include "dnsupdater.h"
#include "core/logger.h" #include "core/logger.h"
#include "dnsupdater.h"
using namespace Net; using namespace Net;
DNSUpdater::DNSUpdater(QObject *parent) : DNSUpdater::DNSUpdater(QObject *parent)
QObject(parent), m_state(OK), m_service(DNS::NONE) : QObject(parent)
, m_state(OK)
, m_service(DNS::NONE)
{ {
updateCredentials(); updateCredentials();
@ -56,13 +59,14 @@ DNSUpdater::DNSUpdater(QObject *parent) :
m_ipCheckTimer.start(); m_ipCheckTimer.start();
// Check lastUpdate to avoid flooding // Check lastUpdate to avoid flooding
if (!m_lastIPCheckTime.isValid() || if (!m_lastIPCheckTime.isValid()
m_lastIPCheckTime.secsTo(QDateTime::currentDateTime())*1000 > IP_CHECK_INTERVAL_MS) { || (m_lastIPCheckTime.secsTo(QDateTime::currentDateTime()) * 1000 > IP_CHECK_INTERVAL_MS)) {
checkPublicIP(); checkPublicIP();
} }
} }
DNSUpdater::~DNSUpdater() { DNSUpdater::~DNSUpdater()
{
// Save lastupdate time and last ip // Save lastupdate time and last ip
Preferences *const pref = Preferences::instance(); Preferences *const pref = Preferences::instance();
pref->setDNSLastUpd(m_lastIPCheckTime); pref->setDNSLastUpd(m_lastIPCheckTime);
@ -73,8 +77,7 @@ void DNSUpdater::checkPublicIP()
{ {
Q_ASSERT(m_state == OK); Q_ASSERT(m_state == OK);
QNetworkAccessManager *manager = new QNetworkAccessManager(this); QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), connect(manager, SIGNAL(finished(QNetworkReply *)), SLOT(ipRequestFinished(QNetworkReply *)));
SLOT(ipRequestFinished(QNetworkReply*)));
m_lastIPCheckTime = QDateTime::currentDateTime(); m_lastIPCheckTime = QDateTime::currentDateTime();
QNetworkRequest request; QNetworkRequest request;
request.setUrl(QUrl("http://checkip.dyndns.org")); request.setUrl(QUrl("http://checkip.dyndns.org"));
@ -88,7 +91,8 @@ void DNSUpdater::ipRequestFinished(QNetworkReply *reply)
if (reply->error()) { if (reply->error()) {
// Error // Error
qWarning() << Q_FUNC_INFO << "Error:" << reply->errorString(); qWarning() << Q_FUNC_INFO << "Error:" << reply->errorString();
} else { }
else {
// Parse response // Parse response
QRegExp ipregex("Current IP Address:\\s+([^<]+)</body>"); QRegExp ipregex("Current IP Address:\\s+([^<]+)</body>");
QString ret = reply->readAll(); QString ret = reply->readAll();
@ -103,10 +107,12 @@ void DNSUpdater::ipRequestFinished(QNetworkReply *reply)
m_lastIP = new_ip; m_lastIP = new_ip;
updateDNSService(); updateDNSService();
} }
} else { }
else {
qWarning() << Q_FUNC_INFO << "Failed to construct a QHostAddress from the IP string"; qWarning() << Q_FUNC_INFO << "Failed to construct a QHostAddress from the IP string";
} }
} else { }
else {
qWarning() << Q_FUNC_INFO << "Regular expression failed ot capture the IP address"; qWarning() << Q_FUNC_INFO << "Regular expression failed ot capture the IP address";
} }
} }
@ -120,8 +126,7 @@ void DNSUpdater::updateDNSService()
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
// Prepare request // Prepare request
QNetworkAccessManager *manager = new QNetworkAccessManager(this); QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), connect(manager, SIGNAL(finished(QNetworkReply *)), SLOT(ipUpdateFinished(QNetworkReply *)));
SLOT(ipUpdateFinished(QNetworkReply*)));
m_lastIPCheckTime = QDateTime::currentDateTime(); m_lastIPCheckTime = QDateTime::currentDateTime();
QNetworkRequest request; QNetworkRequest request;
request.setUrl(getUpdateUrl()); request.setUrl(getUpdateUrl());
@ -175,7 +180,8 @@ void DNSUpdater::ipUpdateFinished(QNetworkReply *reply)
if (reply->error()) { if (reply->error()) {
// Error // Error
qWarning() << Q_FUNC_INFO << "Error:" << reply->errorString(); qWarning() << Q_FUNC_INFO << "Error:" << reply->errorString();
} else { }
else {
// Pase reply // Pase reply
processIPUpdateReply(reply->readAll()); processIPUpdateReply(reply->readAll());
} }
@ -194,7 +200,7 @@ void DNSUpdater::processIPUpdateReply(const QString &reply)
logger->addMessage(tr("Your dynamic DNS was successfully updated."), Log::INFO); logger->addMessage(tr("Your dynamic DNS was successfully updated."), Log::INFO);
return; return;
} }
if (code == "911" || code == "dnserr") { if ((code == "911") || (code == "dnserr")) {
logger->addMessage(tr("Dynamic DNS error: The service is temporarily unavailable, it will be retried in 30 minutes."), Log::CRITICAL); logger->addMessage(tr("Dynamic DNS error: The service is temporarily unavailable, it will be retried in 30 minutes."), Log::CRITICAL);
m_lastIP.clear(); m_lastIP.clear();
// It will retry in 30 minutes because the timer was not stopped // It will retry in 30 minutes because the timer was not stopped
@ -278,7 +284,7 @@ void DNSUpdater::updateCredentials()
change = true; change = true;
} }
if (m_state == INVALID_CREDS && change) { if ((m_state == INVALID_CREDS) && change) {
m_state = OK; // Try again m_state = OK; // Try again
m_ipCheckTimer.start(); m_ipCheckTimer.start();
checkPublicIP(); checkPublicIP();

View file

@ -40,16 +40,15 @@
namespace Net namespace Net
{ {
// Based on http://www.dyndns.com/developers/specs/
/*!
* Based on http://www.dyndns.com/developers/specs/
*/
class DNSUpdater : public QObject class DNSUpdater : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit DNSUpdater(QObject *parent = 0); explicit DNSUpdater(QObject *parent = 0);
~DNSUpdater(); ~DNSUpdater();
static QUrl getRegistrationUrl(int service); static QUrl getRegistrationUrl(int service);
public slots: public slots:
@ -78,9 +77,14 @@ private:
private: private:
static const int IP_CHECK_INTERVAL_MS = 1800000; // 30 min static const int IP_CHECK_INTERVAL_MS = 1800000; // 30 min
enum State { OK, INVALID_CREDS, FATAL };
};
enum State
{
OK,
INVALID_CREDS,
FATAL
};
};
} }
#endif // DNSUPDATER_H #endif // DNSUPDATER_H

View file

@ -50,7 +50,8 @@
#include <QCryptographicHash> #include <QCryptographicHash>
#include <QStringList> #include <QStringList>
namespace { namespace
{
const short DEFAULT_PORT = 25; const short DEFAULT_PORT = 25;
const short DEFAULT_PORT_SSL = 465; const short DEFAULT_PORT_SSL = 465;
@ -91,66 +92,69 @@ QByteArray determineFQDN()
using namespace Net; using namespace Net;
Smtp::Smtp(QObject *parent): QObject(parent), Smtp::Smtp(QObject *parent)
state(Init), use_ssl(false) { : QObject(parent)
, m_state(Init)
, m_useSsl(false)
{
#ifndef QT_NO_OPENSSL #ifndef QT_NO_OPENSSL
socket = new QSslSocket(this); m_socket = new QSslSocket(this);
#else #else
socket = new QTcpSocket(this); m_socket = new QTcpSocket(this);
#endif #endif
connect(socket, SIGNAL(readyRead()), SLOT(readyRead())); connect(m_socket, SIGNAL(readyRead()), SLOT(readyRead()));
connect(socket, SIGNAL(disconnected()), SLOT(deleteLater())); connect(m_socket, SIGNAL(disconnected()), SLOT(deleteLater()));
// Test hmacMD5 function (http://www.faqs.org/rfcs/rfc2202.html) // Test hmacMD5 function (http://www.faqs.org/rfcs/rfc2202.html)
Q_ASSERT(hmacMD5("Jefe", "what do ya want for nothing?").toHex() Q_ASSERT(hmacMD5("Jefe", "what do ya want for nothing?").toHex()
== "750c783e6ab0b503eaa86e310a5db738"); == "750c783e6ab0b503eaa86e310a5db738");
Q_ASSERT(hmacMD5(QByteArray::fromHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), Q_ASSERT(hmacMD5(QByteArray::fromHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), "Hi There").toHex()
"Hi There").toHex()
== "9294727a3638bb1c13f48ef8158bfc9d"); == "9294727a3638bb1c13f48ef8158bfc9d");
} }
Smtp::~Smtp() { Smtp::~Smtp()
{
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
} }
void Smtp::sendMail(const QString &from, const QString &to, const QString &subject, const QString &body) { void Smtp::sendMail(const QString &from, const QString &to, const QString &subject, const QString &body)
{
const Preferences* const pref = Preferences::instance(); const Preferences* const pref = Preferences::instance();
QTextCodec* latin1 = QTextCodec::codecForName("latin1"); QTextCodec* latin1 = QTextCodec::codecForName("latin1");
message = ""; m_message = "";
message += encode_mime_header("Date", QDateTime::currentDateTime().toUTC().toString("ddd, d MMM yyyy hh:mm:ss UT"), latin1); m_message += encodeMimeHeader("Date", QDateTime::currentDateTime().toUTC().toString("ddd, d MMM yyyy hh:mm:ss UT"), latin1);
message += encode_mime_header("From", from, latin1); m_message += encodeMimeHeader("From", from, latin1);
message += encode_mime_header("Subject", subject, latin1); m_message += encodeMimeHeader("Subject", subject, latin1);
message += encode_mime_header("To", to, latin1); m_message += encodeMimeHeader("To", to, latin1);
message += "MIME-Version: 1.0\r\n"; m_message += "MIME-Version: 1.0\r\n";
message += "Content-Type: text/plain; charset=UTF-8\r\n"; m_message += "Content-Type: text/plain; charset=UTF-8\r\n";
message += "Content-Transfer-Encoding: base64\r\n"; m_message += "Content-Transfer-Encoding: base64\r\n";
message += "\r\n"; m_message += "\r\n";
// Encode the body in base64 // Encode the body in base64
QString crlf_body = body; QString crlf_body = body;
QByteArray b = crlf_body.replace("\n","\r\n").toUtf8().toBase64(); QByteArray b = crlf_body.replace("\n","\r\n").toUtf8().toBase64();
int ct = b.length(); int ct = b.length();
for (int i = 0; i < ct; i += 78) for (int i = 0; i < ct; i += 78)
{ m_message += b.mid(i, 78);
message += b.mid(i, 78); m_from = from;
} m_rcpt = to;
this->from = from;
rcpt = to;
// Authentication // Authentication
if (pref->getMailNotificationSMTPAuth()) { if (pref->getMailNotificationSMTPAuth()) {
username = pref->getMailNotificationSMTPUsername(); m_username = pref->getMailNotificationSMTPUsername();
password = pref->getMailNotificationSMTPPassword(); m_password = pref->getMailNotificationSMTPPassword();
} }
// Connect to SMTP server // Connect to SMTP server
#ifndef QT_NO_OPENSSL #ifndef QT_NO_OPENSSL
if (pref->getMailNotificationSMTPSSL()) { if (pref->getMailNotificationSMTPSSL()) {
socket->connectToHostEncrypted(pref->getMailNotificationSMTP(), DEFAULT_PORT_SSL); m_socket->connectToHostEncrypted(pref->getMailNotificationSMTP(), DEFAULT_PORT_SSL);
use_ssl = true; m_useSsl = true;
} else { }
else {
#endif #endif
socket->connectToHost(pref->getMailNotificationSMTP(), DEFAULT_PORT); m_socket->connectToHost(pref->getMailNotificationSMTP(), DEFAULT_PORT);
use_ssl = false; m_useSsl = false;
#ifndef QT_NO_OPENSSL #ifndef QT_NO_OPENSSL
} }
#endif #endif
@ -160,18 +164,17 @@ void Smtp::readyRead()
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
// SMTP is line-oriented // SMTP is line-oriented
buffer += socket->readAll(); m_buffer += m_socket->readAll();
while (true) while (true) {
{ int pos = m_buffer.indexOf("\r\n");
int pos = buffer.indexOf("\r\n");
if (pos < 0) return; // Loop exit condition if (pos < 0) return; // Loop exit condition
QByteArray line = buffer.left(pos); QByteArray line = m_buffer.left(pos);
buffer = buffer.mid(pos + 2); m_buffer = m_buffer.mid(pos + 2);
qDebug() << "Response line:" << line; qDebug() << "Response line:" << line;
// Extract reponse code // Extract reponse code
QByteArray code = line.left(3); QByteArray code = line.left(3);
switch(state) { switch (m_state) {
case Init: { case Init: {
if (code[0] == '2') { if (code[0] == '2') {
// The server may send a multiline greeting/INIT/220 response. // The server may send a multiline greeting/INIT/220 response.
@ -180,9 +183,10 @@ void Smtp::readyRead()
break; break;
// Connection was successful // Connection was successful
ehlo(); ehlo();
} else { }
else {
logError("Connection failed, unrecognized reply: "+line); logError("Connection failed, unrecognized reply: "+line);
state = Close; m_state = Close;
} }
break; break;
} }
@ -194,82 +198,88 @@ void Smtp::readyRead()
#ifndef QT_NO_OPENSSL #ifndef QT_NO_OPENSSL
case StartTLSSent: case StartTLSSent:
if (code == "220") { if (code == "220") {
socket->startClientEncryption(); m_socket->startClientEncryption();
ehlo(); ehlo();
} else { }
else {
authenticate(); authenticate();
} }
break; break;
#endif #endif
case AuthRequestSent: case AuthRequestSent:
case AuthUsernameSent: case AuthUsernameSent:
if (authType == AuthPlain) authPlain(); if (m_authType == AuthPlain) authPlain();
else if (authType == AuthLogin) authLogin(); else if (m_authType == AuthLogin) authLogin();
else authCramMD5(line.mid(4)); else authCramMD5(line.mid(4));
break; break;
case AuthSent: case AuthSent:
case Authenticated: case Authenticated:
if (code[0] == '2') { if (code[0] == '2') {
qDebug() << "Sending <mail from>..."; qDebug() << "Sending <mail from>...";
socket->write("mail from:<" + from.toLatin1() + ">\r\n"); m_socket->write("mail from:<" + m_from.toLatin1() + ">\r\n");
socket->flush(); m_socket->flush();
state = Rcpt; m_state = Rcpt;
} else { }
else {
// Authentication failed! // Authentication failed!
logError("Authentication failed, msg: "+line); logError("Authentication failed, msg: "+line);
state = Close; m_state = Close;
} }
break; break;
case Rcpt: case Rcpt:
if (code[0] == '2') { if (code[0] == '2') {
socket->write("rcpt to:<" + rcpt.toLatin1() + ">\r\n"); m_socket->write("rcpt to:<" + m_rcpt.toLatin1() + ">\r\n");
socket->flush(); m_socket->flush();
state = Data; m_state = Data;
} else { }
else {
logError("<mail from> was rejected by server, msg: "+line); logError("<mail from> was rejected by server, msg: "+line);
state = Close; m_state = Close;
} }
break; break;
case Data: case Data:
if (code[0] == '2') { if (code[0] == '2') {
socket->write("data\r\n"); m_socket->write("data\r\n");
socket->flush(); m_socket->flush();
state = Body; m_state = Body;
} else { }
else {
logError("<Rcpt to> was rejected by server, msg: "+line); logError("<Rcpt to> was rejected by server, msg: "+line);
state = Close; m_state = Close;
} }
break; break;
case Body: case Body:
if (code[0] == '3') { if (code[0] == '3') {
socket->write(message + "\r\n.\r\n"); m_socket->write(m_message + "\r\n.\r\n");
socket->flush(); m_socket->flush();
state = Quit; m_state = Quit;
} else { }
else {
logError("<data> was rejected by server, msg: "+line); logError("<data> was rejected by server, msg: "+line);
state = Close; m_state = Close;
} }
break; break;
case Quit: case Quit:
if (code[0] == '2') { if (code[0] == '2') {
socket->write("QUIT\r\n"); m_socket->write("QUIT\r\n");
socket->flush(); m_socket->flush();
// here, we just close. // here, we just close.
state = Close; m_state = Close;
} else { }
else {
logError("Message was rejected by the server, error: "+line); logError("Message was rejected by the server, error: "+line);
state = Close; m_state = Close;
} }
break; break;
default: default:
qDebug() << "Disconnecting from host"; qDebug() << "Disconnecting from host";
socket->disconnectFromHost(); m_socket->disconnectFromHost();
return; return;
} }
} }
} }
QByteArray Smtp::encode_mime_header(const QString& key, const QString& value, QTextCodec* latin1, const QByteArray& prefix) QByteArray Smtp::encodeMimeHeader(const QString &key, const QString &value, QTextCodec *latin1, const QByteArray &prefix)
{ {
QByteArray rv = ""; QByteArray rv = "";
QByteArray line = key.toLatin1() + ": "; QByteArray line = key.toLatin1() + ": ";
@ -287,7 +297,8 @@ QByteArray Smtp::encode_mime_header(const QString& key, const QString& value, QT
line += " " + word; line += " " + word;
firstWord = false; firstWord = false;
} }
} else { }
else {
// The text cannot be losslessly encoded as Latin-1. Therefore, we // The text cannot be losslessly encoded as Latin-1. Therefore, we
// must use base64 encoding. // must use base64 encoding.
QByteArray utf8 = value.toUtf8(); QByteArray utf8 = value.toUtf8();
@ -310,58 +321,65 @@ QByteArray Smtp::encode_mime_header(const QString& key, const QString& value, QT
void Smtp::ehlo() void Smtp::ehlo()
{ {
QByteArray address = determineFQDN(); QByteArray address = determineFQDN();
socket->write("ehlo " + address + "\r\n"); m_socket->write("ehlo " + address + "\r\n");
socket->flush(); m_socket->flush();
state = EhloSent; m_state = EhloSent;
} }
void Smtp::helo() void Smtp::helo()
{ {
QByteArray address = determineFQDN(); QByteArray address = determineFQDN();
socket->write("helo " + address + "\r\n"); m_socket->write("helo " + address + "\r\n");
socket->flush(); m_socket->flush();
state = HeloSent; m_state = HeloSent;
} }
void Smtp::parseEhloResponse(const QByteArray &code, bool continued, const QString &line) void Smtp::parseEhloResponse(const QByteArray &code, bool continued, const QString &line)
{ {
if (code != "250") { if (code != "250") {
// Error // Error
if (state == EhloSent) { if (m_state == EhloSent) {
// try to send HELO instead of EHLO // try to send HELO instead of EHLO
qDebug() << "EHLO failed, trying HELO instead..."; qDebug() << "EHLO failed, trying HELO instead...";
helo(); helo();
} else { }
else {
// Both EHLO and HELO failed, chances are this is NOT // Both EHLO and HELO failed, chances are this is NOT
// a SMTP server // a SMTP server
logError("Both EHLO and HELO failed, msg: "+line); logError("Both EHLO and HELO failed, msg: "+line);
state = Close; m_state = Close;
} }
return; return;
} }
if (state != EhloGreetReceived) {
if (m_state != EhloGreetReceived) {
if (!continued) { if (!continued) {
// greeting only, no extensions // greeting only, no extensions
qDebug() << "No extension"; qDebug() << "No extension";
state = EhloDone; m_state = EhloDone;
} else { }
else {
// greeting followed by extensions // greeting followed by extensions
state = EhloGreetReceived; m_state = EhloGreetReceived;
qDebug () << "EHLO greet received"; qDebug () << "EHLO greet received";
return; return;
} }
} else { }
else {
qDebug() << Q_FUNC_INFO << "Supported extension: " << line.section(' ', 0, 0).toUpper() qDebug() << Q_FUNC_INFO << "Supported extension: " << line.section(' ', 0, 0).toUpper()
<< line.section(' ', 1); << line.section(' ', 1);
extensions[line.section(' ', 0, 0).toUpper()] = line.section(' ', 1); m_extensions[line.section(' ', 0, 0).toUpper()] = line.section(' ', 1);
if (!continued) if (!continued)
state = EhloDone; m_state = EhloDone;
} }
if (state != EhloDone) return;
if (extensions.contains("STARTTLS") && use_ssl) { if (m_state != EhloDone) return;
if (m_extensions.contains("STARTTLS") && m_useSsl) {
qDebug() << "STARTTLS"; qDebug() << "STARTTLS";
startTLS(); startTLS();
} else { }
else {
authenticate(); authenticate();
} }
} }
@ -369,21 +387,21 @@ void Smtp::parseEhloResponse(const QByteArray& code, bool continued, const QStri
void Smtp::authenticate() void Smtp::authenticate()
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
if (!extensions.contains("AUTH") || if (!m_extensions.contains("AUTH") ||
username.isEmpty() || password.isEmpty()) { m_username.isEmpty() || m_password.isEmpty()) {
// Skip authentication // Skip authentication
qDebug() << "Skipping authentication..."; qDebug() << "Skipping authentication...";
state = Authenticated; m_state = Authenticated;
// At this point the server will not send any response // At this point the server will not send any response
// So fill the buffer with a fake one to pass the tests // So fill the buffer with a fake one to pass the tests
// in readyRead() // in readyRead()
buffer.push_front("250 QBT FAKE RESPONSE\r\n"); m_buffer.push_front("250 QBT FAKE RESPONSE\r\n");
return; return;
} }
// AUTH extension is supported, check which // AUTH extension is supported, check which
// authentication modes are supported by // authentication modes are supported by
// the server // the server
QStringList auth = extensions["AUTH"].toUpper().split(' ', QString::SkipEmptyParts); QStringList auth = m_extensions["AUTH"].toUpper().split(' ', QString::SkipEmptyParts);
if (auth.contains("CRAM-MD5")) { if (auth.contains("CRAM-MD5")) {
qDebug() << "Using CRAM-MD5 authentication..."; qDebug() << "Using CRAM-MD5 authentication...";
authCramMD5(); authCramMD5();
@ -395,16 +413,17 @@ void Smtp::authenticate()
else if (auth.contains("LOGIN")) { else if (auth.contains("LOGIN")) {
qDebug() << "Using LOGIN authentication..."; qDebug() << "Using LOGIN authentication...";
authLogin(); authLogin();
} else { }
else {
// Skip authentication // Skip authentication
logError("The SMTP server does not seem to support any of the authentications modes " logError("The SMTP server does not seem to support any of the authentications modes "
"we support [CRAM-MD5|PLAIN|LOGIN], skipping authentication, " "we support [CRAM-MD5|PLAIN|LOGIN], skipping authentication, "
"knowing it is likely to fail... Server Auth Modes: "+auth.join("|")); "knowing it is likely to fail... Server Auth Modes: "+auth.join("|"));
state = Authenticated; m_state = Authenticated;
// At this point the server will not send any response // At this point the server will not send any response
// So fill the buffer with a fake one to pass the tests // So fill the buffer with a fake one to pass the tests
// in readyRead() // in readyRead()
buffer.push_front("250 QBT FAKE RESPONSE\r\n"); m_buffer.push_front("250 QBT FAKE RESPONSE\r\n");
} }
} }
@ -412,9 +431,9 @@ void Smtp::startTLS()
{ {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
#ifndef QT_NO_OPENSSL #ifndef QT_NO_OPENSSL
socket->write("starttls\r\n"); m_socket->write("starttls\r\n");
socket->flush(); m_socket->flush();
state = StartTLSSent; m_state = StartTLSSent;
#else #else
authenticate(); authenticate();
#endif #endif
@ -422,56 +441,57 @@ void Smtp::startTLS()
void Smtp::authCramMD5(const QByteArray& challenge) void Smtp::authCramMD5(const QByteArray& challenge)
{ {
if (state != AuthRequestSent) { if (m_state != AuthRequestSent) {
socket->write("auth cram-md5\r\n"); m_socket->write("auth cram-md5\r\n");
socket->flush(); m_socket->flush();
authType = AuthCramMD5; m_authType = AuthCramMD5;
state = AuthRequestSent; m_state = AuthRequestSent;
} else { }
QByteArray response = username.toLatin1() + ' ' else {
+ hmacMD5(password.toLatin1(), QByteArray::fromBase64(challenge)).toHex(); QByteArray response = m_username.toLatin1() + ' '
socket->write(response.toBase64() + "\r\n"); + hmacMD5(m_password.toLatin1(), QByteArray::fromBase64(challenge)).toHex();
socket->flush(); m_socket->write(response.toBase64() + "\r\n");
state = AuthSent; m_socket->flush();
m_state = AuthSent;
} }
} }
void Smtp::authPlain() void Smtp::authPlain()
{ {
if (state != AuthRequestSent) { if (m_state != AuthRequestSent) {
authType = AuthPlain; m_authType = AuthPlain;
// Prepare Auth string // Prepare Auth string
QByteArray auth; QByteArray auth;
auth += '\0'; auth += '\0';
auth += username.toLatin1(); auth += m_username.toLatin1();
qDebug() << "username: " << username.toLatin1(); qDebug() << "username: " << m_username.toLatin1();
auth += '\0'; auth += '\0';
auth += password.toLatin1(); auth += m_password.toLatin1();
qDebug() << "password: " << password.toLatin1(); qDebug() << "password: " << m_password.toLatin1();
// Send it // Send it
socket->write("auth plain "+ auth.toBase64() + "\r\n"); m_socket->write("auth plain "+ auth.toBase64() + "\r\n");
socket->flush(); m_socket->flush();
state = AuthSent; m_state = AuthSent;
} }
} }
void Smtp::authLogin() void Smtp::authLogin()
{ {
if (state != AuthRequestSent && state != AuthUsernameSent) { if ((m_state != AuthRequestSent) && (m_state != AuthUsernameSent)) {
socket->write("auth login\r\n"); m_socket->write("auth login\r\n");
socket->flush(); m_socket->flush();
authType = AuthLogin; m_authType = AuthLogin;
state = AuthRequestSent; m_state = AuthRequestSent;
} }
else if (state == AuthRequestSent) { else if (m_state == AuthRequestSent) {
socket->write(username.toLatin1().toBase64() + "\r\n"); m_socket->write(m_username.toLatin1().toBase64() + "\r\n");
socket->flush(); m_socket->flush();
state = AuthUsernameSent; m_state = AuthUsernameSent;
} }
else { else {
socket->write(password.toLatin1().toBase64() + "\r\n"); m_socket->write(m_password.toLatin1().toBase64() + "\r\n");
socket->flush(); m_socket->flush();
state = AuthSent; m_state = AuthSent;
} }
} }

View file

@ -52,20 +52,47 @@ QT_END_NAMESPACE
namespace Net namespace Net
{ {
class Smtp : public QObject
class Smtp : public QObject { {
Q_OBJECT Q_OBJECT
public: public:
Smtp(QObject *parent = 0); Smtp(QObject *parent = 0);
~Smtp(); ~Smtp();
void sendMail(const QString &from, const QString &to, const QString &subject, const QString &body);
void sendMail(const QString &m_from, const QString &to, const QString &subject, const QString &body);
private slots: private slots:
void readyRead(); void readyRead();
private: private:
QByteArray encode_mime_header(const QString& key, const QString& value, QTextCodec* latin1, const QByteArray& prefix=QByteArray()); enum States
{
Rcpt,
EhloSent,
HeloSent,
EhloDone,
EhloGreetReceived,
AuthRequestSent,
AuthSent,
AuthUsernameSent,
Authenticated,
StartTLSSent,
Data,
Init,
Body,
Quit,
Close
};
enum AuthType
{
AuthPlain,
AuthLogin,
AuthCramMD5
};
QByteArray encodeMimeHeader(const QString &key, const QString &value, QTextCodec *latin1, const QByteArray &prefix = QByteArray());
void ehlo(); void ehlo();
void helo(); void helo();
void parseEhloResponse(const QByteArray &code, bool continued, const QString &line); void parseEhloResponse(const QByteArray &code, bool continued, const QString &line);
@ -76,30 +103,23 @@ private:
void authLogin(); void authLogin();
void logError(const QString &msg); void logError(const QString &msg);
private: QByteArray m_message;
enum states { Rcpt, EhloSent, HeloSent, EhloDone, EhloGreetReceived, AuthRequestSent, AuthSent,
AuthUsernameSent, Authenticated, StartTLSSent, Data, Init, Body, Quit, Close };
enum AuthType { AuthPlain, AuthLogin, AuthCramMD5 };
private:
QByteArray message;
#ifndef QT_NO_OPENSSL #ifndef QT_NO_OPENSSL
QSslSocket *socket; QSslSocket *m_socket;
#else #else
QTcpSocket *socket; QTcpSocket *m_socket;
#endif #endif
QString from; QString m_from;
QString rcpt; QString m_rcpt;
QString response; QString m_response;
int state; int m_state;
QHash<QString, QString> extensions; QHash<QString, QString> m_extensions;
QByteArray buffer; QByteArray m_buffer;
bool use_ssl; bool m_useSsl;
AuthType authType; AuthType m_authType;
QString username; QString m_username;
QString password; QString m_password;
}; };
} }
#endif #endif