aboutsummaryrefslogtreecommitdiffstats
path: root/src/smtp/smtpclient.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/smtp/smtpclient.cpp405
1 files changed, 405 insertions, 0 deletions
diff --git a/src/smtp/smtpclient.cpp b/src/smtp/smtpclient.cpp
new file mode 100644
index 00000000..f1d9fe0d
--- /dev/null
+++ b/src/smtp/smtpclient.cpp
@@ -0,0 +1,405 @@
+/*
+ Copyright (c) 2011-2012 - Tőkés Attila
+
+ This file is part of SmtpClient for Qt.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ See the LICENSE file for more details.
+*/
+
+#include "smtp/smtpclient.h"
+
+#include <QByteArray>
+#include <QFileInfo>
+
+/* [1] Constructors and destructors */
+
+SmtpClient::SmtpClient(const QString &host, int port,
+ ConnectionType connectionType)
+ : socket(NULL), name("localhost"), authMethod(AuthPlain),
+ connectionTimeout(5000), responseTimeout(5000),
+ sendMessageTimeout(60000) {
+ setConnectionType(connectionType);
+
+ this->host = host;
+ this->port = port;
+
+ connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this,
+ SLOT(socketStateChanged(QAbstractSocket::SocketState)));
+ connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this,
+ SLOT(socketError(QAbstractSocket::SocketError)));
+ connect(socket, SIGNAL(readyRead()), this, SLOT(socketReadyRead()));
+}
+
+SmtpClient::~SmtpClient() {
+ if (socket)
+ delete socket;
+}
+
+/* [1] --- */
+
+/* [2] Getters and Setters */
+
+void SmtpClient::setUser(const QString &user) { this->user = user; }
+
+void SmtpClient::setPassword(const QString &password) {
+ this->password = password;
+}
+
+void SmtpClient::setAuthMethod(AuthMethod method) { this->authMethod = method; }
+
+void SmtpClient::setHost(const QString &host) { this->host = host; }
+
+void SmtpClient::setPort(int port) { this->port = port; }
+
+void SmtpClient::setConnectionType(ConnectionType ct) {
+ this->connectionType = ct;
+
+ if (socket)
+ delete socket;
+
+ switch (connectionType) {
+ case TcpConnection:
+ socket = new QTcpSocket(this);
+ break;
+ case SslConnection:
+ case TlsConnection:
+ socket = new QSslSocket(this);
+ }
+}
+
+const QString &SmtpClient::getHost() const { return this->host; }
+
+const QString &SmtpClient::getUser() const { return this->user; }
+
+const QString &SmtpClient::getPassword() const { return this->password; }
+
+SmtpClient::AuthMethod SmtpClient::getAuthMethod() const {
+ return this->authMethod;
+}
+
+int SmtpClient::getPort() const { return this->port; }
+
+SmtpClient::ConnectionType SmtpClient::getConnectionType() const {
+ return connectionType;
+}
+
+const QString &SmtpClient::getName() const { return this->name; }
+
+void SmtpClient::setName(const QString &name) { this->name = name; }
+
+const QString &SmtpClient::getResponseText() const { return responseText; }
+
+int SmtpClient::getResponseCode() const { return responseCode; }
+
+QTcpSocket *SmtpClient::getSocket() { return socket; }
+
+int SmtpClient::getConnectionTimeout() const { return connectionTimeout; }
+
+void SmtpClient::setConnectionTimeout(int msec) { connectionTimeout = msec; }
+
+int SmtpClient::getResponseTimeout() const { return responseTimeout; }
+
+void SmtpClient::setResponseTimeout(int msec) { responseTimeout = msec; }
+int SmtpClient::getSendMessageTimeout() const { return sendMessageTimeout; }
+void SmtpClient::setSendMessageTimeout(int msec) { sendMessageTimeout = msec; }
+
+/* [2] --- */
+
+/* [3] Public methods */
+
+bool SmtpClient::connectToHost() {
+ switch (connectionType) {
+ case TlsConnection:
+ case TcpConnection:
+ socket->connectToHost(host, port);
+ break;
+ case SslConnection:
+ ((QSslSocket *)socket)->connectToHostEncrypted(host, port);
+ break;
+ }
+
+ // Tries to connect to server
+ if (!socket->waitForConnected(connectionTimeout)) {
+ emit smtpError(ConnectionTimeoutError);
+ return false;
+ }
+
+ try {
+ // Wait for the server's response
+ waitForResponse();
+
+ // If the response code is not 220 (Service ready)
+ // means that is something wrong with the server
+ if (responseCode != 220) {
+ emit smtpError(ServerError);
+ return false;
+ }
+
+ // Send a EHLO/HELO message to the server
+ // The client's first command must be EHLO/HELO
+ sendMessage("EHLO " + name);
+
+ // Wait for the server's response
+ waitForResponse();
+
+ // The response code needs to be 250.
+ if (responseCode != 250) {
+ emit smtpError(ServerError);
+ return false;
+ }
+
+ if (connectionType == TlsConnection) {
+ // send a request to start TLS handshake
+ sendMessage("STARTTLS");
+
+ // Wait for the server's response
+ waitForResponse();
+
+ // The response code needs to be 220.
+ if (responseCode != 220) {
+ emit smtpError(ServerError);
+ return false;
+ };
+
+ ((QSslSocket *)socket)->startClientEncryption();
+
+ if (!((QSslSocket *)socket)->waitForEncrypted(connectionTimeout)) {
+ qDebug() << ((QSslSocket *)socket)->errorString();
+ emit smtpError(ConnectionTimeoutError);
+ return false;
+ }
+
+ // Send ELHO one more time
+ sendMessage("EHLO " + name);
+
+ // Wait for the server's response
+ waitForResponse();
+
+ // The response code needs to be 250.
+ if (responseCode != 250) {
+ emit smtpError(ServerError);
+ return false;
+ }
+ }
+ } catch (ResponseTimeoutException) {
+ return false;
+ } catch (SendMessageTimeoutException) {
+ return false;
+ }
+
+ // If no errors occured the function returns true.
+ return true;
+}
+
+bool SmtpClient::login() { return login(user, password, authMethod); }
+
+bool SmtpClient::login(const QString &user, const QString &password,
+ AuthMethod method) {
+ try {
+ if (method == AuthPlain) {
+ // Sending command: AUTH PLAIN base64('\0' + username + '\0' + password)
+ sendMessage("AUTH PLAIN " + QByteArray()
+ .append((char)0)
+ .append(user.toUtf8())
+ .append((char)0)
+ .append(password.toUtf8())
+ .toBase64());
+
+ // Wait for the server's response
+ waitForResponse();
+
+ // If the response is not 235 then the authentication was faild
+ if (responseCode != 235) {
+ emit smtpError(AuthenticationFailedError);
+ return false;
+ }
+ } else if (method == AuthLogin) {
+ // Sending command: AUTH LOGIN
+ sendMessage("AUTH LOGIN");
+
+ // Wait for 334 response code
+ waitForResponse();
+ if (responseCode != 334) {
+ emit smtpError(AuthenticationFailedError);
+ return false;
+ }
+
+ // Send the username in base64
+ sendMessage(QByteArray().append(user.toUtf8()).toBase64());
+
+ // Wait for 334
+ waitForResponse();
+ if (responseCode != 334) {
+ emit smtpError(AuthenticationFailedError);
+ return false;
+ }
+
+ // Send the password in base64
+ sendMessage(QByteArray().append(password.toUtf8()).toBase64());
+
+ // Wait for the server's responce
+ waitForResponse();
+
+ // If the response is not 235 then the authentication was faild
+ if (responseCode != 235) {
+ emit smtpError(AuthenticationFailedError);
+ return false;
+ }
+ }
+ } catch (ResponseTimeoutException) {
+ // Responce Timeout exceeded
+ emit smtpError(AuthenticationFailedError);
+ return false;
+ } catch (SendMessageTimeoutException) {
+ // Send Timeout exceeded
+ emit smtpError(AuthenticationFailedError);
+ return false;
+ }
+
+ return true;
+}
+
+bool SmtpClient::sendMail(MimeMessage &email) {
+ try {
+ // Send the MAIL command with the sender
+ sendMessage("MAIL FROM:<" + email.getSender().getAddress() + ">");
+
+ waitForResponse();
+
+ if (responseCode != 250)
+ return false;
+
+ // Send RCPT command for each recipient
+ QList<EmailAddress *>::const_iterator it, itEnd;
+ // To (primary recipients)
+ for (it = email.getRecipients().begin(),
+ itEnd = email.getRecipients().end();
+ it != itEnd; ++it) {
+
+ sendMessage("RCPT TO:<" + (*it)->getAddress() + ">");
+ waitForResponse();
+
+ if (responseCode != 250)
+ return false;
+ }
+
+ // Cc (carbon copy)
+ for (it = email.getRecipients(MimeMessage::Cc).begin(),
+ itEnd = email.getRecipients(MimeMessage::Cc).end();
+ it != itEnd; ++it) {
+ sendMessage("RCPT TO:<" + (*it)->getAddress() + ">");
+ waitForResponse();
+
+ if (responseCode != 250)
+ return false;
+ }
+
+ // Bcc (blind carbon copy)
+ for (it = email.getRecipients(MimeMessage::Bcc).begin(),
+ itEnd = email.getRecipients(MimeMessage::Bcc).end();
+ it != itEnd; ++it) {
+ sendMessage("RCPT TO:<" + (*it)->getAddress() + ">");
+ waitForResponse();
+
+ if (responseCode != 250)
+ return false;
+ }
+
+ // Send DATA command
+ sendMessage("DATA");
+ waitForResponse();
+
+ if (responseCode != 354)
+ return false;
+
+ sendMessage(email.toString());
+
+ // Send \r\n.\r\n to end the mail data
+ sendMessage(".");
+
+ waitForResponse();
+
+ if (responseCode != 250)
+ return false;
+ } catch (ResponseTimeoutException) {
+ return false;
+ } catch (SendMessageTimeoutException) {
+ return false;
+ }
+
+ return true;
+}
+
+void SmtpClient::quit() {
+ try {
+ sendMessage("QUIT");
+ } catch (SmtpClient::SendMessageTimeoutException) {
+ // Manually close the connection to the smtp server if message "QUIT" wasn't
+ // received by the smtp server
+ if (socket->state() == QAbstractSocket::ConnectedState ||
+ socket->state() == QAbstractSocket::ConnectingState ||
+ socket->state() == QAbstractSocket::HostLookupState)
+ socket->disconnectFromHost();
+ }
+}
+
+/* [3] --- */
+
+/* [4] Protected methods */
+
+void SmtpClient::waitForResponse() {
+ do {
+ if (!socket->waitForReadyRead(responseTimeout)) {
+ emit smtpError(ResponseTimeoutError);
+ throw ResponseTimeoutException();
+ }
+
+ while (socket->canReadLine()) {
+ // Save the server's response
+ responseText = socket->readLine();
+
+ // Extract the respose code from the server's responce (first 3 digits)
+ responseCode = responseText.left(3).toInt();
+
+ if (responseCode / 100 == 4)
+ emit smtpError(ServerError);
+
+ if (responseCode / 100 == 5)
+ emit smtpError(ClientError);
+
+ if (responseText[3] == ' ') {
+ return;
+ }
+ }
+ } while (true);
+}
+
+void SmtpClient::sendMessage(const QString &text) {
+ socket->write(text.toUtf8() + "\r\n");
+ if (!socket->waitForBytesWritten(sendMessageTimeout)) {
+ emit smtpError(SendDataTimeoutError);
+ throw SendMessageTimeoutException();
+ }
+}
+
+/* [4] --- */
+
+/* [5] Slots for the socket's signals */
+
+void SmtpClient::socketStateChanged(QAbstractSocket::SocketState /*state*/) {}
+
+void SmtpClient::socketError(QAbstractSocket::SocketError /*socketError*/) {}
+
+void SmtpClient::socketReadyRead() {}
+
+/* [5] --- */