/* 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 "smtpclient.h" #include #include /* [1] Constructors and destructors */ SmtpClient::SmtpClient(const QString & host, int port, ConnectionType ct) : name("localhost"), authMethod(AuthPlain), connectionTimeout(5000), responseTimeout(5000) { if (ct == TcpConnection) this->useSsl = false; else if (ct == SslConnection) this->useSsl = true; if (useSsl == false) socket = new QTcpSocket(this); else socket = new QSslSocket(this); 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() {} /* [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(QString &host) { this->host = host; } void SmtpClient::setPort(int port) { this->port = port; } void SmtpClient::setConnectionType(ConnectionType ct) { if (ct == TcpConnection) this->useSsl = false; else if (ct == SslConnection) this->useSsl = true; if (useSsl == false) socket = new QTcpSocket(this); else 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 { if (useSsl) return SslConnection; else return TcpConnection; } const QString& SmtpClient::getName() const { return this->name; } void SmtpClient::setName(const QString &name) { this->name = name; } /* [2] --- */ /* [3] Public methods */ bool SmtpClient::connectToHost() { if (useSsl) ((QSslSocket*) socket)->connectToHostEncrypted(host, port); else socket->connectToHost(host, port); // 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; } } catch (ResponseTimeoutException) { 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).append((char) 0).append(password).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).toBase64()); // Wait for 334 waitForResponse(); if (responseCode != 334) { emit smtpError(AuthenticationFailedError); return false; } // Send the password in base64 sendMessage(QByteArray().append(password).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 e) { // Responce 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::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; } return true; } void SmtpClient::quit() { sendMessage("QUIT"); } /* [3] --- */ /* [4] Protected methods */ void SmtpClient::waitForResponse() throw (ResponseTimeoutException) { if (!socket->waitForReadyRead(responseTimeout)) { emit smtpError(ResponseTimeoutError); throw ResponseTimeoutException(); } // Save the server's response responseText = socket->readAll(); // 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); } void SmtpClient::sendMessage(const QString &text) { socket->write(text.toUtf8() + "\r\n"); } /* [4] --- */ /* [5] Slots for the socket's signals */ void SmtpClient::socketStateChanged(QAbstractSocket::SocketState state) { } void SmtpClient::socketError(QAbstractSocket::SocketError socketError) { } void SmtpClient::socketReadyRead() { } /* [5] --- */