diff --git a/SMTPEmail.pro b/SMTPEmail.pro deleted file mode 100644 index 2fc74d6..0000000 --- a/SMTPEmail.pro +++ /dev/null @@ -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 += diff --git a/src/SMTPEmail.pro b/src/SMTPEmail.pro new file mode 100644 index 0000000..4abab5f --- /dev/null +++ b/src/SMTPEmail.pro @@ -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 += diff --git a/src/emailaddress.h b/src/emailaddress.h index 957ba2b..44f1a2e 100644 --- a/src/emailaddress.h +++ b/src/emailaddress.h @@ -19,9 +19,10 @@ #ifndef EMAILADDRESS_H #define EMAILADDRESS_H +#include "smtpmime_global.h" #include -class EmailAddress : public QObject +class SMTP_MIME_EXPORT EmailAddress : public QObject { Q_OBJECT public: diff --git a/src/mimeattachment.cpp b/src/mimeattachment.cpp index eac36f7..fd2b46c 100644 --- a/src/mimeattachment.cpp +++ b/src/mimeattachment.cpp @@ -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] --- */ diff --git a/src/mimeattachment.h b/src/mimeattachment.h index 4b79678..90a5780 100644 --- a/src/mimeattachment.h +++ b/src/mimeattachment.h @@ -19,11 +19,13 @@ #ifndef MIMEATTACHMENT_H #define MIMEATTACHMENT_H + #include +#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] --- */ }; diff --git a/src/mimebase64encoder.cpp b/src/mimebase64encoder.cpp new file mode 100644 index 0000000..4ce73ff --- /dev/null +++ b/src/mimebase64encoder.cpp @@ -0,0 +1,7 @@ +#include "mimebase64encoder.h" + +MimeBase64Encoder::MimeBase64Encoder() {} + +QByteArray MimeBase64Encoder::encode(const QByteArray &data) { + return data.toBase64(); +} diff --git a/src/mimebase64encoder.h b/src/mimebase64encoder.h new file mode 100644 index 0000000..826b7d4 --- /dev/null +++ b/src/mimebase64encoder.h @@ -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 diff --git a/src/mimebase64formatter.cpp b/src/mimebase64formatter.cpp new file mode 100644 index 0000000..b9b67c8 --- /dev/null +++ b/src/mimebase64formatter.cpp @@ -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; +} diff --git a/src/mimebase64formatter.h b/src/mimebase64formatter.h new file mode 100644 index 0000000..c1d227b --- /dev/null +++ b/src/mimebase64formatter.h @@ -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 diff --git a/src/mimecontentencoder.cpp b/src/mimecontentencoder.cpp new file mode 100644 index 0000000..b718b7e --- /dev/null +++ b/src/mimecontentencoder.cpp @@ -0,0 +1,3 @@ +#include "mimecontentencoder.h" + +MimeContentEncoder::MimeContentEncoder() {} diff --git a/src/mimecontentencoder.h b/src/mimecontentencoder.h new file mode 100644 index 0000000..2cf577e --- /dev/null +++ b/src/mimecontentencoder.h @@ -0,0 +1,16 @@ +#ifndef MIMEENCODER_H +#define MIMEENCODER_H + +#include +#include + +class MimeContentEncoder : public QObject +{ +public: + virtual QByteArray encode(const QByteArray &data) =0; + +protected: + MimeContentEncoder(); +}; + +#endif // MIMEENCODER_H diff --git a/src/mimecontentformatter.cpp b/src/mimecontentformatter.cpp index 7f5a6e4..c1ab674 100644 --- a/src/mimecontentformatter.cpp +++ b/src/mimecontentformatter.cpp @@ -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; } diff --git a/src/mimecontentformatter.h b/src/mimecontentformatter.h index 8180cb6..5912f11 100644 --- a/src/mimecontentformatter.h +++ b/src/mimecontentformatter.h @@ -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 -#include +#include -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 diff --git a/src/mimefile.cpp b/src/mimefile.cpp index 59fb5bf..d981a4b 100644 --- a/src/mimefile.cpp +++ b/src/mimefile.cpp @@ -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] --- */ diff --git a/src/mimefile.h b/src/mimefile.h index b72e947..8540c77 100644 --- a/src/mimefile.h +++ b/src/mimefile.h @@ -19,10 +19,11 @@ #ifndef MIMEFILE_H #define MIMEFILE_H -#include "mimepart.h" #include +#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] --- */ diff --git a/src/mimehtml.cpp b/src/mimehtml.cpp index 5594d3a..e65adf6 100644 --- a/src/mimehtml.cpp +++ b/src/mimehtml.cpp @@ -48,10 +48,4 @@ const QString & MimeHtml::getHtml() const /* [3] Protected methods */ -void MimeHtml::prepare() -{ - /* !!! IMPORTANT !!! */ - MimeText::prepare(); -} - /* [3] --- */ diff --git a/src/mimehtml.h b/src/mimehtml.h index 037c05f..5d59bc4 100644 --- a/src/mimehtml.h +++ b/src/mimehtml.h @@ -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] --- */ }; diff --git a/src/mimeinlinefile.cpp b/src/mimeinlinefile.cpp index 0823b0d..a275691 100644 --- a/src/mimeinlinefile.cpp +++ b/src/mimeinlinefile.cpp @@ -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] --- */ diff --git a/src/mimeinlinefile.h b/src/mimeinlinefile.h index 6a7444e..8a3187e 100644 --- a/src/mimeinlinefile.h +++ b/src/mimeinlinefile.h @@ -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] --- */ }; diff --git a/src/mimemessage.cpp b/src/mimemessage.cpp index f156363..3eae06e 100644 --- a/src/mimemessage.cpp +++ b/src/mimemessage.cpp @@ -18,7 +18,9 @@ #include "mimemessage.h" +#include #include +#include #include "quotedprintable.h" #include @@ -140,117 +142,87 @@ const QList & 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::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] --- */ diff --git a/src/mimemessage.h b/src/mimemessage.h index d136756..7f7edc6 100644 --- a/src/mimemessage.h +++ b/src/mimemessage.h @@ -19,13 +19,15 @@ #ifndef MIMEMESSAGE_H #define MIMEMESSAGE_H -#include "mimepart.h" -#include "mimemultipart.h" -#include "emailaddress.h" #include #include -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] --- */ diff --git a/src/mimemultipart.cpp b/src/mimemultipart.cpp index 19d4729..b3a70d1 100644 --- a/src/mimemultipart.cpp +++ b/src/mimemultipart.cpp @@ -53,21 +53,23 @@ const QList & MimeMultiPart::getParts() const { return parts; } -void MimeMultiPart::prepare() { +void MimeMultiPart::writeContent(QIODevice &device) { QList::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]; diff --git a/src/mimemultipart.h b/src/mimemultipart.h index 8a85b6f..6355347 100644 --- a/src/mimemultipart.h +++ b/src/mimemultipart.h @@ -19,9 +19,12 @@ #ifndef MIMEMULTIPART_H #define MIMEMULTIPART_H +#include +#include +#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] --- */ diff --git a/src/mimepart.cpp b/src/mimepart.cpp index 07ff662..1e85da9 100644 --- a/src/mimepart.cpp +++ b/src/mimepart.cpp @@ -16,8 +16,13 @@ See the LICENSE file for more details. */ +#include #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] --- */ diff --git a/src/mimepart.h b/src/mimepart.h index 3eda975..49bbb19 100644 --- a/src/mimepart.h +++ b/src/mimepart.h @@ -20,9 +20,10 @@ #define MIMEPART_H #include -#include "mimecontentformatter.h" +#include +#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 diff --git a/src/mimeqpencoder.cpp b/src/mimeqpencoder.cpp new file mode 100644 index 0000000..5d7e89e --- /dev/null +++ b/src/mimeqpencoder.cpp @@ -0,0 +1,8 @@ +#include "mimeqpencoder.h" +#include "quotedprintable.h" + +MimeQpEncoder::MimeQpEncoder() {} + +QByteArray MimeQpEncoder::encode(const QByteArray &data) { + return QuotedPrintable::encode(data).toAscii(); +} diff --git a/src/mimeqpencoder.h b/src/mimeqpencoder.h new file mode 100644 index 0000000..31f9a2c --- /dev/null +++ b/src/mimeqpencoder.h @@ -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 diff --git a/src/mimeqpformatter.cpp b/src/mimeqpformatter.cpp new file mode 100644 index 0000000..5177029 --- /dev/null +++ b/src/mimeqpformatter.cpp @@ -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; +} diff --git a/src/mimeqpformatter.h b/src/mimeqpformatter.h new file mode 100644 index 0000000..eb0356c --- /dev/null +++ b/src/mimeqpformatter.h @@ -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 diff --git a/src/mimetext.cpp b/src/mimetext.cpp index 20b1b0a..338cf1e 100644 --- a/src/mimetext.cpp +++ b/src/mimetext.cpp @@ -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] --- */ diff --git a/src/mimetext.h b/src/mimetext.h index 124ad5b..eb75894 100644 --- a/src/mimetext.h +++ b/src/mimetext.h @@ -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] --- */ diff --git a/src/quotedprintable.cpp b/src/quotedprintable.cpp index 52b5f13..e7e130c 100644 --- a/src/quotedprintable.cpp +++ b/src/quotedprintable.cpp @@ -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)]); diff --git a/src/quotedprintable.h b/src/quotedprintable.h index 9c74946..5a54dc4 100644 --- a/src/quotedprintable.h +++ b/src/quotedprintable.h @@ -21,8 +21,9 @@ #include #include +#include "smtpmime_global.h" -class QuotedPrintable : public QObject +class SMTP_MIME_EXPORT QuotedPrintable : public QObject { Q_OBJECT public: diff --git a/src/smtpclient.cpp b/src/smtpclient.cpp index 7419cb5..27858f2 100644 --- a/src/smtpclient.cpp +++ b/src/smtpclient.cpp @@ -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); } @@ -538,7 +542,13 @@ void SmtpClient::socketReadyRead() while (socket->canReadLine()) { // Save the server's response responseLine = socket->readLine(); - tempResponse += responseLine; + 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(); - } } diff --git a/src/smtpclient.h b/src/smtpclient.h index 2753d2f..74bbcae 100644 --- a/src/smtpclient.h +++ b/src/smtpclient.h @@ -22,11 +22,11 @@ #include #include #include - +#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] --- */ diff --git a/src/smtpmime_global.h b/src/smtpmime_global.h new file mode 100644 index 0000000..d3bc902 --- /dev/null +++ b/src/smtpmime_global.h @@ -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 diff --git a/test/connectiontest.cpp b/test/connectiontest.cpp new file mode 100644 index 0000000..254d6aa --- /dev/null +++ b/test/connectiontest.cpp @@ -0,0 +1,55 @@ +#include "connectiontest.h" +#include +#include +#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("host"); + QTest::addColumn("port"); + QTest::addColumn("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() { +} diff --git a/test/connectiontest.h b/test/connectiontest.h new file mode 100644 index 0000000..d23e7f8 --- /dev/null +++ b/test/connectiontest.h @@ -0,0 +1,21 @@ +#ifndef CONNECTIONTEST_H +#define CONNECTIONTEST_H + +#include + +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 diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 0000000..3d3900b --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#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; +} diff --git a/test/test.pro b/test/test.pro new file mode 100644 index 0000000..499b18e --- /dev/null +++ b/test/test.pro @@ -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