/* Copyright (c) 2011 - Tőkés Attila This file is part of SmtpClient for Qt. SmtpClient for Qt is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. SmtpClient for Qt is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. 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] --- */