Простой SMTP-клиент Qt C ++ - PullRequest
       25

Простой SMTP-клиент Qt C ++

0 голосов
/ 22 марта 2019

Я новичок в Qt. Я нашел пример простого SMTP-сервера. Он отправляет мое электронное сообщение, но программа вылетает после отправки.

Пожалуйста, смотрите сообщение об ошибке и вывод:

Скриншот

Мне не разрешено публиковать фото, пожалуйста, помогите мне.

Я не могу решить эту проблему. Пожалуйста, помогите мне исправить это ... Ошибка подтверждения:

Ошибка отладки: _CrtIsValidHeapPointer (block)

EmailClient.h

#ifndef EMAILCLIENT_H
#define EMAILCLIENT_H

#include <QtNetwork/QAbstractSocket>
#include <QtNetwork/QSslSocket>
#include <QString>
#include <QTextStream>
#include <QDebug>
#include <QByteArray>
#include <QFile>
#include <QFileInfo>
#include <QTextCodec>


class EmailClient : public QObject
{
    Q_OBJECT
public:

    EmailClient(const QString &user, const QString &pass,
          const QString &host, quint16 port = 465, int timeout = 30000);
    EmailClient() = default;

    ~EmailClient();

    void sendMail(const QString &to,
                   const QString &subject, const QString &body,
                   QStringList files = QStringList());

    QString getLastResponse() const;

    enum SendResult { Sent, Error, Timeout, CannotOpenAttachedFile, CannotFindAttachedFile };
    SendResult getSendResult() const;

signals:
    void finished(int code);

private slots:
    void errorReceived(QAbstractSocket::SocketError socketError);
    void disconnected();
    void connected();
    void readyRead();

private:
    SendResult sendResult;
    int timeout;
    QString message;
    static QTextCodec *codecx;

    QTextStream t;
    QSslSocket socket;
    QString rcpt;
    QString response;
    QString user;
    QString pass;
    QString host;
    quint16 port;
    enum states { Tls, HandShake, Auth, User, Pass, Rcpt, Mail, Data, Init, Body, Quit, Close };
    int state;

    QString lastResponse;

    void initialize(const QString &user, const QString &pass,
                    const QString &host, quint16 port, int timeout);

};


#endif // EMAILCLIENT_H

EmailClient.cpp

#include "EmailClient.h"

QTextCodec *EmailClient::codecx = QTextCodec::codecForName("UTF-8");

EmailClient::EmailClient(const QString &user, const QString &pass, const QString &host, quint16 port, int timeout )
{
    initialize(user,pass, host, port, timeout);
}


void EmailClient::initialize(const QString &user, const QString &pass, const QString &host, quint16 port, int timeout)
{
    connect(&socket, &QSslSocket::readyRead, this, &EmailClient::readyRead);
    connect(&socket, &QSslSocket::connected, this, &EmailClient::connected);
    connect(&socket, &QSslSocket::disconnected, this, &EmailClient::disconnected);
    connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(errorReceived(QAbstractSocket::SocketError)));

    this->user = user;
    this->pass = pass;

    this->host = host;
    this->port = port;
    this->timeout = timeout;
}

void EmailClient::sendMail(const QString &to, const QString &subject, const QString &body, QStringList files)
{
    message = "To: " + to + "\n";
    message.append("From: " + user + "\n");
    //subject = "=?UTF-8?B?" + QByteArray().append(subject).toBase64() + "?=\r\n";

    //message.append("Subject: " + subject + "\n");
    message.append("Subject: =?UTF-8?B?" + QByteArray().append(subject).toBase64() + "?=\r\n");
    message.append("MIME-Version: 1.0\n");
    message.append("Content-Type: multipart/mixed; boundary=frontier\n\n");

    message.append( "--frontier\n" );
    //message.append( "Content-Type: text/html\n\n" );  //Uncomment this for HTML formating, coment the line below
    message.append( "Content-Type: text/plain\n\n" );
    message.append(body).append("\n\n");

    if (!files.isEmpty()) {
        qDebug() << "Files to be sent: " << files.size();
        for (const auto &filePath : files) {
            QFile file(filePath);
            if (file.exists()) {
                if (!file.open(QIODevice::ReadOnly)) {
                    qDebug() << "Couldn't open file " + filePath;
                    lastResponse = "Couldn't open file " + filePath;
                    sendResult = SendResult::CannotOpenAttachedFile;
                    emit finished(sendResult);
                    return;
                }
                QByteArray bytes = file.readAll();
                message.append("--frontier\n");
                message.append("Content-Type: application/octet-stream\nContent-Disposition: attachment; filename=" + QFileInfo(file.fileName()).fileName() +";\nContent-Transfer-Encoding: base64\n\n");
                message.append(bytes.toBase64()).append("\n");
            }
            else {
                qDebug() << "Couldn't find file " + filePath;
                lastResponse = "Couldn't find file " + filePath;
                sendResult = SendResult::CannotFindAttachedFile;
                emit finished(sendResult);
                return;
            }
        }
    }

    message.append( "--frontier--\n" );

    message.replace( QString::fromLatin1( "\n" ), QString::fromLatin1( "\r\n" ) );
    message.replace( QString::fromLatin1( "\r\n.\r\n" ),QString::fromLatin1( "\r\n..\r\n" ) );


    rcpt = to;
    state = Init;
    socket.connectToHostEncrypted(host, port);
    if (!socket.waitForConnected(timeout)) {
         qDebug() << socket.errorString();
         lastResponse = socket.errorString();
         sendResult = SendResult::Timeout;
     }

    //t = new QTextStream(socket);
    t.setDevice(&socket);

    t.setCodec(codecx);
}

EmailClient::~EmailClient()
{

}


void EmailClient::errorReceived(QAbstractSocket::SocketError socketError)
{
    qDebug() << "Error: " << socketError;
}

void EmailClient::disconnected()
{
    qDebug() <<"Disconneted.";
    qDebug() << "Error: "  << socket.errorString();
    emit finished(sendResult);
}

void EmailClient::connected()
{
    qDebug() << "Connected to host.";
}

void EmailClient::readyRead()
{
    QString responseLine;
    do {
        responseLine = socket.readLine();
        response += responseLine;
    }
    while (socket.canReadLine() && responseLine[3] != ' ');

    responseLine.truncate(3);

    //qDebug() << "Server response code: " <<  responseLine;
    qDebug() << "Server response: " << response;

    if (state == Init && responseLine == "220") {
        t << "EHLO localhost" <<"\r\n";
        t.flush();
        state = HandShake;
    }
    //No need, because I'm using socket.startClienEncryption() which makes the SSL handshake for you
    /*else if (state == Tls && responseLine == "250")
    {
        // Trying AUTH
        qDebug() << "STarting Tls";
        t << "STARTTLS" << "\r\n";
        t.flush();
        state = HandShake;
    }*/
    else if (state == HandShake && responseLine == "250") {
        socket.startClientEncryption();
        if(!socket.waitForEncrypted(timeout)) {
            qDebug() << socket.errorString();
            state = Close;
        }
        t << "EHLO localhost" << "\r\n";
        t.flush();
        state = Auth;
    }
    else if (state == Auth && responseLine == "250") {
        // Trying AUTH
        t << "AUTH LOGIN" << "\r\n";
        t.flush();
        state = User;
    }
    else if (state == User && responseLine == "334") {
        t << QByteArray().append(user).toBase64()  << "\r\n";
        t.flush();
        state = Pass;
    }
    else if (state == Pass && responseLine == "334") {
        t << QByteArray().append(pass).toBase64() << "\r\n";
        t.flush();

        state = Mail;
    }
    else if (state == Mail && responseLine == "235") {
        t << "MAIL FROM:<" << user << ">\r\n";
        t.flush();
        state = Rcpt;
    }
    else if (state == Rcpt && responseLine == "250") {
        t << "RCPT TO:<" << rcpt << ">\r\n"; //r
        t.flush();
        state = Data;
    }
    else if (state == Data && responseLine == "250") {
        t << "DATA\r\n";
        t.flush();
        state = Body;
    }
    else if (state == Body && responseLine == "354") {
        t << message << "\r\n.\r\n";
        t.flush();
        state = Quit;
    }
    else if (state == Quit && responseLine == "250") {
        t << "QUIT\r\n";
        t.flush();
        state = Close;
        lastResponse = "Message sent!";
        sendResult = SendResult::Sent;
    }
    else if (state == Close) {
        deleteLater();
        return;
    }
    else {
        qDebug() << "Unexpected reply from SMTP server: " << response;
        lastResponse = response;
        state = Close;
        sendResult = SendResult::Error;
    }
    response = "";
}

QString EmailClient::getLastResponse() const
{
    return lastResponse;
}


EmailClient::SendResult EmailClient::getSendResult() const
{
    return sendResult;
}
...