State machine implementation terminated. Added some functions

(waitForReadyConnected, waitForAuthenticated, waitForMailSent)
synchronous waiting.

Added writeToDevice() function to MimeMessage and MimePart (and
subclasses), now these are used in SmtpClient instead of toString().

Added some unit tests.
This commit is contained in:
Tőkés Attila 2012-09-22 20:59:27 +03:00
parent afb66b4fff
commit 9e048495ba
40 changed files with 538 additions and 340 deletions

View File

@ -1,46 +0,0 @@
#-------------------------------------------------
#
# Project created by QtCreator 2011-08-11T20:59:25
#
#-------------------------------------------------
QT += core gui network
TARGET = SMTPEmail
TEMPLATE = app
SOURCES += \
src/emailaddress.cpp \
src/mimeattachment.cpp \
src/mimefile.cpp \
src/mimehtml.cpp \
src/mimeinlinefile.cpp \
src/mimemessage.cpp \
src/mimepart.cpp \
src/mimetext.cpp \
src/smtpclient.cpp \
src/quotedprintable.cpp \
src/mimemultipart.cpp \
src/mimecontentformatter.cpp
HEADERS += \
src/emailaddress.h \
src/mimeattachment.h \
src/mimefile.h \
src/mimehtml.h \
src/mimeinlinefile.h \
src/mimemessage.h \
src/mimepart.h \
src/mimetext.h \
src/smtpclient.h \
src/SmtpMime \
src/quotedprintable.h \
src/mimemultipart.h \
src/mimecontentformatter.h
OTHER_FILES += \
LICENSE \
README.md
FORMS +=

59
src/SMTPEmail.pro Normal file
View File

@ -0,0 +1,59 @@
#-------------------------------------------------
#
# Project created by QtCreator 2011-08-11T20:59:25
#
#-------------------------------------------------
QT += core network
TARGET = SmtpMime
TEMPLATE = lib
DEFINE += SMTP_MIME_LIBRARY
SOURCES += \
emailaddress.cpp \
mimeattachment.cpp \
mimefile.cpp \
mimehtml.cpp \
mimeinlinefile.cpp \
mimemessage.cpp \
mimepart.cpp \
mimetext.cpp \
smtpclient.cpp \
quotedprintable.cpp \
mimemultipart.cpp \
mimecontentencoder.cpp \
mimebase64encoder.cpp \
mimeqpencoder.cpp \
mimeqpformatter.cpp \
mimebase64formatter.cpp \
mimecontentformatter.cpp
HEADERS += \
emailaddress.h \
mimeattachment.h \
mimefile.h \
mimehtml.h \
mimeinlinefile.h \
mimemessage.h \
mimepart.h \
mimetext.h \
smtpclient.h \
SmtpMime \
quotedprintable.h \
mimemultipart.h \
smtpmime_global.h \
mimecontentencoder.h \
mimebase64encoder.h \
mimeqpencoder.h \
mimeqpformatter.h \
mimepart.cpp.autosave \
mimebase64formatter.h \
mimecontentformatter.h
OTHER_FILES += \
LICENSE \
README.md
FORMS +=

View File

@ -19,9 +19,10 @@
#ifndef EMAILADDRESS_H
#define EMAILADDRESS_H
#include "smtpmime_global.h"
#include <QObject>
class EmailAddress : public QObject
class SMTP_MIME_EXPORT EmailAddress : public QObject
{
Q_OBJECT
public:

View File

@ -24,6 +24,7 @@
MimeAttachment::MimeAttachment(QFile *file)
: MimeFile(file)
{
this->headerLines += "Content-disposition: attachment\r\n";
}
MimeAttachment::~MimeAttachment()
@ -35,12 +36,4 @@ MimeAttachment::~MimeAttachment()
/* [2] Protected methods */
void MimeAttachment::prepare()
{
this->header += "Content-disposition: attachment\r\n";
/* !!! IMPORTANT !!! */
MimeFile::prepare();
}
/* [2] --- */

View File

@ -19,11 +19,13 @@
#ifndef MIMEATTACHMENT_H
#define MIMEATTACHMENT_H
#include <QFile>
#include "smtpmime_global.h"
#include "mimepart.h"
#include "mimefile.h"
class MimeAttachment : public MimeFile
class SMTP_MIME_EXPORT MimeAttachment : public MimeFile
{
Q_OBJECT
public:
@ -38,9 +40,6 @@ public:
protected:
/* [2] Protected methods */
virtual void prepare();
/* [2] --- */
};

View File

@ -0,0 +1,7 @@
#include "mimebase64encoder.h"
MimeBase64Encoder::MimeBase64Encoder() {}
QByteArray MimeBase64Encoder::encode(const QByteArray &data) {
return data.toBase64();
}

14
src/mimebase64encoder.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef MIMEBASE64ENCODER_H
#define MIMEBASE64ENCODER_H
#include "mimecontentencoder.h"
class MimeBase64Encoder : public MimeContentEncoder
{
public:
MimeBase64Encoder();
QByteArray encode(const QByteArray &data);
};
#endif // MIMEBASE64ENCODER_H

View File

@ -0,0 +1,17 @@
#include "mimebase64formatter.h"
MimeBase64Formatter::MimeBase64Formatter(QIODevice *out) :
MimeContentFormatter(out) {}
qint64 MimeBase64Formatter::writeData(const char *data, qint64 maxLength) {
qDebug("called");
int lines = (maxLength - 1) / lineLength + 1;
for (int i = 1; i < lines; ++i) {
output->write(data, lineLength);
output->write("\r\n");
data += lineLength;
}
output->write(data, maxLength - (lines - 1) * lineLength);
output->write("\r\n");
return maxLength;
}

15
src/mimebase64formatter.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef MIMEBASE64FORMATTER_H
#define MIMEBASE64FORMATTER_H
#include "mimecontentformatter.h"
class MimeBase64Formatter : public MimeContentFormatter
{
public:
MimeBase64Formatter(QIODevice*);
protected:
virtual qint64 writeData(const char *data, qint64 len);
};
#endif // MIMEBASE64FORMATTER_H

View File

@ -0,0 +1,3 @@
#include "mimecontentencoder.h"
MimeContentEncoder::MimeContentEncoder() {}

16
src/mimecontentencoder.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef MIMEENCODER_H
#define MIMEENCODER_H
#include <QObject>
#include <QByteArray>
class MimeContentEncoder : public QObject
{
public:
virtual QByteArray encode(const QByteArray &data) =0;
protected:
MimeContentEncoder();
};
#endif // MIMEENCODER_H

View File

@ -1,66 +1,20 @@
/*
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 "mimecontentformatter.h"
MimeContentFormatter::MimeContentFormatter(int max_length) :
max_length(max_length)
{}
QString MimeContentFormatter::format(const QString &content, bool quotedPrintable) const {
QString out;
int chars = 0;
for (int i = 0; i < content.length() ; ++i) {
chars++;
if (!quotedPrintable) {
if (chars > max_length) {
out.append("\r\n");
chars = 1;
}
}
else {
if (content[i] == '\n') { // new line
out.append(content[i]);
chars = 0;
continue;
}
if ((chars > max_length - 1)
|| ((content[i] == '=') && (chars > max_length - 3) )) {
out.append('=');
out.append("\r\n");
chars = 1;
}
}
out.append(content[i]);
}
return out;
MimeContentFormatter::MimeContentFormatter(QIODevice *out, int length) :
output(out),
lineLength(length)
{
QIODevice::open(WriteOnly);
}
void MimeContentFormatter::setMaxLength(int l) {
max_length = l;
int MimeContentFormatter::getLineLength() const {
return lineLength;
}
int MimeContentFormatter::getMaxLength() const {
return max_length;
void MimeContentFormatter::setLineLength(int l) {
lineLength = l;
}
qint64 MimeContentFormatter::readData(char*, qint64) {
return -1;
}

View File

@ -1,41 +1,24 @@
/*
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.
*/
#ifndef MIMECONTENTFORMATTER_H
#define MIMECONTENTFORMATTER_H
#include <QObject>
#include <QByteArray>
#include <QIODevice>
class MimeContentFormatter : public QObject
class MimeContentFormatter : public QIODevice
{
Q_OBJECT
public:
MimeContentFormatter (int max_length = 76);
MimeContentFormatter(QIODevice *device, int lineLength = 76);
void setMaxLength(int l);
int getMaxLength() const;
QString format(const QString &content, bool quotedPrintable = false) const;
int getLineLength() const;
void setLineLength(int l);
protected:
int max_length;
qint64 readData(char *data, qint64 maxlen);
qint64 writeData(const char *data, qint64 len) = 0;
QIODevice *output;
int lineLength;
};
#endif // MIMECONTENTFORMATTER_H

View File

@ -44,14 +44,15 @@ MimeFile::~MimeFile()
/* [3] Protected methods */
void MimeFile::prepare()
{
void MimeFile::writeContent(QIODevice &device) {
file->open(QIODevice::ReadOnly);
this->content = file->readAll();
file->close();
/* !!! IMPORTANT !!!! */
MimePart::prepare();
MimePart::writeContent(device);
this->content.clear();
}
/* [3] --- */

View File

@ -19,10 +19,11 @@
#ifndef MIMEFILE_H
#define MIMEFILE_H
#include "mimepart.h"
#include <QFile>
#include "mimepart.h"
#include "smtpmime_global.h"
class MimeFile : public MimePart
class SMTP_MIME_EXPORT MimeFile : public MimePart
{
Q_OBJECT
public:
@ -50,7 +51,8 @@ protected:
/* [4] Protected methods */
virtual void prepare();
void writeContent(QIODevice &device);
/* [4] --- */

View File

@ -48,10 +48,4 @@ const QString & MimeHtml::getHtml() const
/* [3] Protected methods */
void MimeHtml::prepare()
{
/* !!! IMPORTANT !!! */
MimeText::prepare();
}
/* [3] --- */

View File

@ -19,9 +19,10 @@
#ifndef MIMEHTML_H
#define MIMEHTML_H
#include "smtpmime_global.h"
#include "mimetext.h"
class MimeHtml : public MimeText
class SMTP_MIME_EXPORT MimeHtml : public MimeText
{
Q_OBJECT
public:
@ -51,8 +52,6 @@ protected:
/* [4] Protected methods */
virtual void prepare();
/* [4] --- */
};

View File

@ -23,6 +23,7 @@
MimeInlineFile::MimeInlineFile(QFile *f)
: MimeFile(f)
{
this->headerLines += "Content-Disposition: inline\r\n";
}
MimeInlineFile::~MimeInlineFile()
@ -38,14 +39,6 @@ MimeInlineFile::~MimeInlineFile()
/* [3] Protected methods */
void MimeInlineFile::prepare()
{
this->header += "Content-Disposition: inline\r\n";
/* !!! IMPORTANT !!! */
MimeFile::prepare();
}
/* [3] --- */

View File

@ -19,9 +19,10 @@
#ifndef MIMEINLINEFILE_H
#define MIMEINLINEFILE_H
#include "smtpmime_global.h"
#include "mimefile.h"
class MimeInlineFile : public MimeFile
class SMTP_MIME_EXPORT MimeInlineFile : public MimeFile
{
public:
@ -46,8 +47,6 @@ protected:
/* [4] Protected methods */
virtual void prepare();
/* [4] --- */
};

View File

@ -18,7 +18,9 @@
#include "mimemessage.h"
#include <QDebug>
#include <QDateTime>
#include <QBuffer>
#include "quotedprintable.h"
#include <typeinfo>
@ -140,117 +142,87 @@ const QList<MimePart*> & MimeMessage::getParts() const
QString MimeMessage::toString()
{
QString mimeString;
QTextStream out(&mimeString);
writeToStream(out);
return mimeString;
QBuffer out;
out.open(QIODevice::WriteOnly);
writeToDevice(out);
return QString(out.buffer());
}
void MimeMessage::writeToStream(QTextStream &out) {
QString MimeMessage::formatAddress(EmailAddress *address, MimePart::Encoding encoding) {
QString result;
if (address->getName() != "")
{
switch (encoding)
{
case MimePart::Base64:
result.append(" =?utf-8?B?" + QByteArray().append(address->getName()).toBase64() + "?=");
break;
case MimePart::QuotedPrintable:
result.append(" =?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append(address->getName())).replace(' ', "_").replace(':',"=3A") + "?=");
break;
default:
result.append(" " + address->getName());
}
}
result.append(" <" + address->getAddress() + ">");
return result;
}
void MimeMessage::writeToDevice(QIODevice &out) {
/* =========== MIME HEADER ============ */
/* ---------- Sender / From ----------- */
out << "From:";
if (sender->getName() != "")
{
switch (hEncoding)
{
case MimePart::Base64:
out << " =?utf-8?B?" + QByteArray().append(sender->getName()).toBase64() + "?=";
break;
case MimePart::QuotedPrintable:
out << " =?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append(sender->getName())).replace(' ', "_").replace(':',"=3A") + "?=";
break;
default:
out << " " + sender->getName();
}
}
out << " <" + sender->getAddress() + ">\r\n";
QString header;
header.append("From:" + formatAddress(sender, hEncoding) + "\r\n");
/* ---------------------------------- */
/* ------- Recipients / To ---------- */
out << "To:";
header.append("To:");
QList<EmailAddress*>::iterator it; int i;
for (i = 0, it = recipientsTo.begin(); it != recipientsTo.end(); ++it, ++i)
{
if (i != 0) { out << ","; }
if ((*it)->getName() != "")
{
switch (hEncoding)
{
case MimePart::Base64:
out << " =?utf-8?B?" + QByteArray().append((*it)->getName()).toBase64() + "?=";
break;
case MimePart::QuotedPrintable:
out << " =?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append((*it)->getName())).replace(' ', "_").replace(':',"=3A") + "?=";
break;
default:
out << " " + (*it)->getName();
}
}
out << " <" + (*it)->getAddress() + ">";
if (i != 0) { header.append(","); }
header.append(formatAddress(*it, hEncoding));
}
out << "\r\n";
header.append("\r\n");
/* ---------------------------------- */
/* ------- Recipients / Cc ---------- */
if (recipientsCc.size() != 0) {
out << "Cc:";
header.append("Cc:");
}
for (i = 0, it = recipientsCc.begin(); it != recipientsCc.end(); ++it, ++i)
{
if (i != 0) { out << ","; }
if ((*it)->getName() != "")
{
switch (hEncoding)
{
case MimePart::Base64:
out << " =?utf-8?B?" + QByteArray().append((*it)->getName()).toBase64() + "?=";
break;
case MimePart::QuotedPrintable:
out << " =?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append((*it)->getName())).replace(' ', "_").replace(':',"=3A") + "?=";
break;
default:
out << " " + (*it)->getName();
}
}
out << " <" + (*it)->getAddress() + ">";
if (i != 0) { header.append(","); }
header.append(formatAddress(*it, hEncoding));
}
if (recipientsCc.size() != 0) {
out << "\r\n";
header.append("\r\n");
}
/* ---------------------------------- */
/* ------------ Subject ------------- */
out << "Subject: ";
header.append("Subject: ");
switch (hEncoding)
{
case MimePart::Base64:
out << "=?utf-8?B?" + QByteArray().append(subject).toBase64() + "?=";
header.append("=?utf-8?B?" + QByteArray().append(subject).toBase64() + "?=");
break;
case MimePart::QuotedPrintable:
out << "=?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append(subject)).replace(' ', "_").replace(':',"=3A") + "?=";
header.append("=?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append(subject)).replace(' ', "_").replace(':',"=3A") + "?=");
break;
default:
out << subject;
header.append(subject);
}
/* ---------------------------------- */
out << "\r\n";
out << "MIME-Version: 1.0\r\n";
header.append("\r\n");
header.append("MIME-Version: 1.0\r\n");
out << content->toString();
out.write(header.toAscii());
content->writeToDevice(out);
}
void MimeMessage::writeToDevice(QIODevice &device) {
QTextStream out (&device);
writeToStream(out);
out.flush();
}
/* [3] --- */

View File

@ -19,13 +19,15 @@
#ifndef MIMEMESSAGE_H
#define MIMEMESSAGE_H
#include "mimepart.h"
#include "mimemultipart.h"
#include "emailaddress.h"
#include <QList>
#include <QTextStream>
class MimeMessage : public QObject
#include "smtpmime_global.h"
#include "mimepart.h"
#include "mimemultipart.h"
#include "emailaddress.h"
class SMTP_MIME_EXPORT MimeMessage : public QObject
{
public:
@ -68,8 +70,7 @@ public:
/* [3] Public methods */
virtual QString toString();
virtual void writeToStream(QTextStream &stream);
virtual void writeToDevice(QIODevice &device);
void writeToDevice(QIODevice &device);
/* [3] --- */
@ -84,6 +85,8 @@ protected:
MimePart::Encoding hEncoding;
static QString formatAddress(EmailAddress*, MimePart::Encoding);
/* [4] --- */

View File

@ -53,21 +53,23 @@ const QList<MimePart*> & MimeMultiPart::getParts() const {
return parts;
}
void MimeMultiPart::prepare() {
void MimeMultiPart::writeContent(QIODevice &device) {
QList<MimePart*>::iterator it;
content = "";
for (it = parts.begin(); it != parts.end(); it++) {
content += "--" + cBoundary + "\r\n";
(*it)->prepare();
content += (*it)->toString();
device.write("--" );
device.write(cBoundary.toAscii());
device.write("\r\n");
(*it)->writeToDevice(device);
};
content += "--" + cBoundary + "--\r\n";
MimePart::prepare();
device.write("--");
device.write(cBoundary.toAscii());
device.write("--\r\n");
}
void MimeMultiPart::setMimeType(const MultiPartType type) {
this->type = type;
this->cType = MULTI_PART_NAMES[type];

View File

@ -19,9 +19,12 @@
#ifndef MIMEMULTIPART_H
#define MIMEMULTIPART_H
#include <QList>
#include <QTextStream>
#include "smtpmime_global.h"
#include "mimepart.h"
class MimeMultiPart : public MimePart
class SMTP_MIME_EXPORT MimeMultiPart : public MimePart
{
Q_OBJECT
public:
@ -59,7 +62,7 @@ public:
void addPart(MimePart *part);
virtual void prepare();
void writeContent(QIODevice &device);
/* [3] --- */

View File

@ -16,8 +16,13 @@
See the LICENSE file for more details.
*/
#include <QBuffer>
#include "mimepart.h"
#include "quotedprintable.h"
#include "mimebase64formatter.h"
#include "mimeqpformatter.h"
#include "mimebase64encoder.h"
#include "mimeqpencoder.h"
/* [1] Constructors and Destructors */
@ -45,17 +50,17 @@ void MimePart::setContent(const QByteArray & content)
void MimePart::setHeader(const QString & header)
{
this->header = header;
this->headerLines = header;
}
void MimePart::addHeaderLine(const QString & line)
{
this->header += line + "\r\n";
this->headerLines += line + "\r\n";
}
const QString& MimePart::getHeader() const
{
return header;
return headerLines;
}
const QByteArray& MimePart::getContent() const
@ -113,9 +118,12 @@ MimePart::Encoding MimePart::getEncoding() const
return this->cEncoding;
}
MimeContentFormatter& MimePart::getContentFormatter()
{
return this->formatter;
void MimePart::setMaxLineLength(const int length) {
maxLineLength = length;
}
int MimePart::getMaxLineLength() const {
return maxLineLength;
}
/* [2] --- */
@ -125,90 +133,91 @@ MimeContentFormatter& MimePart::getContentFormatter()
QString MimePart::toString()
{
if (!prepared)
prepare();
return mimeString;
QBuffer out;
out.open(QIODevice::WriteOnly);
writeToDevice(out);
return QString(out.buffer());
}
/* [3] --- */
/* [4] Protected methods */
void MimePart::prepare()
{
mimeString = QString();
void MimePart::writeToDevice(QIODevice &device) {
QString header;
/* === Header Prepare === */
/* Content-Type */
mimeString.append("Content-Type: ").append(cType);
header.append("Content-Type: ").append(cType);
if (cName != "")
mimeString.append("; name=\"").append(cName).append("\"");
header.append("; name=\"").append(cName).append("\"");
if (cCharset != "")
mimeString.append("; charset=").append(cCharset);
header.append("; charset=").append(cCharset);
if (cBoundary != "")
mimeString.append("; boundary=").append(cBoundary);
header.append("; boundary=").append(cBoundary);
mimeString.append("\r\n");
header.append("\r\n");
/* ------------ */
/* Content-Transfer-Encoding */
mimeString.append("Content-Transfer-Encoding: ");
header.append("Content-Transfer-Encoding: ");
switch (cEncoding)
{
case _7Bit:
mimeString.append("7bit\r\n");
header.append("7bit\r\n");
break;
case _8Bit:
mimeString.append("8bit\r\n");
header.append("8bit\r\n");
break;
case Base64:
mimeString.append("base64\r\n");
header.append("base64\r\n");
break;
case QuotedPrintable:
mimeString.append("quoted-printable\r\n");
header.append("quoted-printable\r\n");
break;
}
/* ------------------------ */
/* Content-Id */
if (cId != NULL)
mimeString.append("Content-ID: <").append(cId).append(">\r\n");
header.append("Content-ID: <").append(cId).append(">\r\n");
/* ---------- */
/* Addition header lines */
/* Additional header lines */
mimeString.append(header).append("\r\n");
header.append(headerLines).append("\r\n");
/* ------------------------- */
/* === End of Header Prepare === */
/* === Content === */
device.write(header.toAscii());
writeContent(device);
}
/* [3] --- */
/* [4] Protected methods */
void MimePart::writeContent(QIODevice &device) {
switch (cEncoding)
{
case _7Bit:
mimeString.append(QString(content).toAscii());
break;
case _8Bit:
mimeString.append(content);
device.write(content);
break;
case Base64:
mimeString.append(formatter.format(content.toBase64()));
MimeBase64Formatter(&device).write(MimeBase64Encoder().encode(content));
break;
case QuotedPrintable:
mimeString.append(formatter.format(QuotedPrintable::encode(content), true));
MimeQPFormatter(&device).write(MimeQpEncoder().encode(content));
break;
}
mimeString.append("\r\n");
/* === End of Content === */
prepared = true;
device.write("\r\n");
}
/* [4] --- */

View File

@ -20,9 +20,10 @@
#define MIMEPART_H
#include <QObject>
#include "mimecontentformatter.h"
#include <QTextStream>
#include "smtpmime_global.h"
class MimePart : public QObject
class SMTP_MIME_EXPORT MimePart : public QObject
{
Q_OBJECT
public:
@ -53,7 +54,7 @@ public:
const QByteArray& getContent() const;
void setContent(const QByteArray & content);
void setHeader(const QString & header);
void setHeader(const QString & headerLines);
void addHeaderLine(const QString & line);
@ -72,7 +73,8 @@ public:
void setEncoding(Encoding enc);
Encoding getEncoding() const;
MimeContentFormatter& getContentFormatter();
void setMaxLineLength(const int length);
int getMaxLineLength() const;
/* [2] --- */
@ -80,18 +82,15 @@ public:
/* [3] Public methods */
virtual QString toString();
virtual void prepare();
void writeToDevice(QIODevice &device);
/* [3] --- */
protected:
/* [4] Protected members */
QString header;
QString headerLines;
QByteArray content;
QString cId;
@ -101,12 +100,14 @@ protected:
QString cBoundary;
Encoding cEncoding;
int maxLineLength;
QString mimeString;
bool prepared;
MimeContentFormatter formatter;
/* [4] --- */
virtual void writeContent(QIODevice &device);
};
#endif // MIMEPART_H

8
src/mimeqpencoder.cpp Normal file
View File

@ -0,0 +1,8 @@
#include "mimeqpencoder.h"
#include "quotedprintable.h"
MimeQpEncoder::MimeQpEncoder() {}
QByteArray MimeQpEncoder::encode(const QByteArray &data) {
return QuotedPrintable::encode(data).toAscii();
}

14
src/mimeqpencoder.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef MIMEQPENCODER_H
#define MIMEQPENCODER_H
#include "mimecontentencoder.h"
class MimeQpEncoder : public MimeContentEncoder
{
public:
MimeQpEncoder();
QByteArray encode(const QByteArray &data);
};
#endif // MIMEQPENCODER_H

29
src/mimeqpformatter.cpp Normal file
View File

@ -0,0 +1,29 @@
#include "mimeqpformatter.h"
MimeQPFormatter::MimeQPFormatter(QIODevice *output) :
MimeContentFormatter(output) {}
qint64 MimeQPFormatter::writeData(const char *data, qint64 maxLength) {
int chars = 0;
const char *start = data;
for (int i = 0; i < maxLength; ++i) {
chars++;
if (data[i] == '\n') {
output->write(start, chars);
start += chars;
chars = 0;
} else if ((chars > lineLength - 3) && (data[i] == '=')) {
output->write(start, chars - 1);
output->write("=\r\n=");
start += chars;
chars = 0;
} else if (chars == lineLength - 1) {
output->write(start, chars);
output->write("=\r\n");
start += chars;
chars = 0;
}
}
output->write(start, chars);
return maxLength;
}

15
src/mimeqpformatter.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef MIMEQPFORMATTER_H
#define MIMEQPFORMATTER_H
#include "mimecontentformatter.h"
class MimeQPFormatter : public MimeContentFormatter
{
public:
MimeQPFormatter(QIODevice*);
protected:
virtual qint64 writeData(const char *data, qint64 len);
};
#endif // MIMEQPFORMATTER_H

View File

@ -50,13 +50,9 @@ const QString & MimeText::getText() const
/* [3] Protected Methods */
void MimeText::prepare()
{
this->content.clear();
this->content.append(text);
/* !!! IMPORTANT !!! */
MimePart::prepare();
void MimeText::writeContent(QIODevice &device) {
this->content = text.toAscii();
MimePart::writeContent(device);
}
/* [3] --- */

View File

@ -19,9 +19,10 @@
#ifndef MIMETEXT_H
#define MIMETEXT_H
#include "smtpmime_global.h"
#include "mimepart.h"
class MimeText : public MimePart
class SMTP_MIME_EXPORT MimeText : public MimePart
{
public:
@ -51,7 +52,7 @@ protected:
/* [4] Protected methods */
void prepare();
void writeContent(QIODevice &device);
/* [4] --- */

View File

@ -29,12 +29,10 @@ QString& QuotedPrintable::encode(const QByteArray &input)
{
byte = input[i];
if ((byte == 0x20) || (byte >= 33) && (byte <= 126) && (byte != 61))
{
if ((byte == 0x20) || (byte >= 33) && (byte <= 126) && (byte != 61)) {
output->append(byte);
}
else
{
else {
output->append('=');
output->append(hex[((byte >> 4) & 0x0F)]);
output->append(hex[(byte & 0x0F)]);

View File

@ -21,8 +21,9 @@
#include <QObject>
#include <QByteArray>
#include "smtpmime_global.h"
class QuotedPrintable : public QObject
class SMTP_MIME_EXPORT QuotedPrintable : public QObject
{
Q_OBJECT
public:

View File

@ -182,6 +182,7 @@ bool SmtpClient::login(const QString &user, const QString &password, AuthMethod
bool SmtpClient::sendMail(MimeMessage& email)
{
this->email = &email;
this->rcptType = 0;
changeState(MailSendingState);
return true;
@ -238,10 +239,10 @@ void SmtpClient::changeState(ClientState state) {
}
#else
// emit all in debug mode
qDebug() << "State:" << state;
emit stateChanged(state);
#endif
switch (state)
{
case ConnectingState:
@ -373,8 +374,8 @@ void SmtpClient::changeState(ClientState state) {
break;
case _MAIL_4_SEND_DATA:
sendMessage(email->toString());
sendMessage(".");
email->writeToDevice(*socket);
sendMessage("\r\n.");
break;
case _READY_MailSent:
@ -528,6 +529,9 @@ void SmtpClient::socketStateChanged(QAbstractSocket::SocketState state) {
}
void SmtpClient::socketError(QAbstractSocket::SocketError socketError) {
#ifndef QT_NO_DEBUG
qDebug() << "SocketError:" << socketError << socket->error();
#endif
emit error(SocketError);
}
@ -539,6 +543,12 @@ void SmtpClient::socketReadyRead()
// Save the server's response
responseLine = socket->readLine();
tempResponse += responseLine;
}
// Is this the last line of the response
if (responseLine[3] == ' ') {
responseText = tempResponse;
tempResponse = "";
// Extract the respose code from the server's responce (first 3 digits)
responseCode = responseLine.left(3).toInt();
@ -554,13 +564,8 @@ void SmtpClient::socketReadyRead()
emit error(ClientError);
return;
}
}
// Is this the last line of the response
if (responseLine[3] == ' ') {
responseText = tempResponse;
processResponse();
}
}

View File

@ -22,11 +22,11 @@
#include <QObject>
#include <QtNetwork/QSslSocket>
#include <QEventLoop>
#include "smtpmime_global.h"
#include "mimemessage.h"
class SmtpClient : public QObject
class SMTP_MIME_EXPORT SmtpClient : public QObject
{
Q_OBJECT
public:
@ -52,9 +52,9 @@ public:
enum ConnectionType
{
TcpConnection,
SslConnection,
TlsConnection // STARTTLS
TcpConnection = 0,
SslConnection = 1,
TlsConnection = 2 // STARTTLS
};
enum ClientState {
@ -136,7 +136,6 @@ public:
QTcpSocket* getSocket();
/* [2] --- */

10
src/smtpmime_global.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef SMTPMIME_GLOBAL_H
#define SMTPMIME_GLOBAL_H
#ifdef SMTP_MIME_LIBRARY
#define SMTP_MIME_EXPORT Q_DECL_EXPORT
#else
#define SMTP_MIME_EXPORT Q_DECL_IMPORT
#endif
#endif // SMTPMIME_GLOBAL_H

55
test/connectiontest.cpp Normal file
View File

@ -0,0 +1,55 @@
#include "connectiontest.h"
#include <QDebug>
#include <QtTest/QtTest>
#include "../src/smtpclient.h"
ConnectionTest::ConnectionTest(QObject *parent) :
QObject(parent) {}
void ConnectionTest::init() {
//qDebug() << "Init...";
}
void ConnectionTest::testConnect() {
QFETCH(QString, host);
QFETCH(int, port);
QFETCH(int, connectionType);
const SmtpClient::ConnectionType cTypes[] = {
SmtpClient::TcpConnection,
SmtpClient::SslConnection,
SmtpClient::TcpConnection
};
SmtpClient::ConnectionType cType = cTypes[--connectionType];
SmtpClient smtp(host, port, cType);
smtp.connectToHost();
QCOMPARE(smtp.waitForReadyConnected(5000), true);
}
void ConnectionTest::testConnect_data() {
QTest::addColumn<QString>("host");
QTest::addColumn<int>("port");
QTest::addColumn<int>("connectionType");
QFile file("../connect_data.txt");
file.open(QIODevice::ReadOnly);
QTextStream in(&file);
while (!in.atEnd()) {
QString host;
int port;
int connectionType;
in >> host >> port >> connectionType;
if (!host.isEmpty()) {
QTest::newRow(QString("%1:%2").arg(host).arg(port).toLocal8Bit().data()) << host << port << connectionType;
}
}
file.close();
}
void ConnectionTest::cleanup() {
}

21
test/connectiontest.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef CONNECTIONTEST_H
#define CONNECTIONTEST_H
#include <QObject>
class ConnectionTest : public QObject
{
Q_OBJECT
public:
ConnectionTest(QObject *parent = 0);
private slots:
void init();
void cleanup();
void testConnect();
void testConnect_data();
};
#endif // CONNECTIONTEST_H

26
test/main.cpp Normal file
View File

@ -0,0 +1,26 @@
#include <QtGui/QApplication>
#include <QCoreApplication>
#include <QtTest/QTest>
#include <QDebug>
#include "connectiontest.h"
bool success = true;
void runTest(QObject *test) {
int retVal = QTest::qExec(test);
success &= retVal == 0;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
runTest(new ConnectionTest());
if (success)
qDebug() << "SUCCESS";
else
qDebug() << "FAIL";
return success;
}

27
test/test.pro Normal file
View File

@ -0,0 +1,27 @@
#-------------------------------------------------
#
# Project created by QtCreator 2012-09-22T16:39:45
#
#-------------------------------------------------
QT += testlib gui
TARGET = test
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp \
connectiontest.cpp
HEADERS += \
connectiontest.h
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../bin/lib/release/ -lSmtpMime
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../bin/lib/debug/ -lSmtpMime
else:unix:!symbian: LIBS += -L$$PWD/../bin/lib/release/ -lSmtpMime
INCLUDEPATH += $$PWD/../bin/lib/release
DEPENDPATH += $$PWD/../bin/lib/release