Version 1.1 beta

This commit is contained in:
Attila Tőkés 2012-07-23 21:01:08 +03:00 committed by Attila
parent 560eb49344
commit 538c068278
10 changed files with 338 additions and 46 deletions

View File

@ -19,7 +19,11 @@ SOURCES += \
src/mimemessage.cpp \ src/mimemessage.cpp \
src/mimepart.cpp \ src/mimepart.cpp \
src/mimetext.cpp \ src/mimetext.cpp \
src/smtpclient.cpp src/smtpclient.cpp \
src/quotedprintable.cpp \
src/mimemultipart.cpp \
test.cpp \
src/mimecontentformatter.cpp
HEADERS += \ HEADERS += \
src/emailaddress.h \ src/emailaddress.h \
@ -31,7 +35,10 @@ HEADERS += \
src/mimepart.h \ src/mimepart.h \
src/mimetext.h \ src/mimetext.h \
src/smtpclient.h \ src/smtpclient.h \
src/SmtpMime src/SmtpMime \
src/quotedprintable.h \
src/mimemultipart.h \
src/mimecontentformatter.h
OTHER_FILES += \ OTHER_FILES += \
LICENSE \ LICENSE \

View File

@ -0,0 +1,44 @@
#include "mimecontentformatter.h"
MimeContentFormatter::MimeContentFormatter(int max_length) :
max_length(max_length)
{}
QString MimeContentFormatter::format(const QString &content, bool quotedPrintable) {
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;
}
void MimeContentFormatter::setMaxLength(int l) {
max_length = l;
}

View File

@ -0,0 +1,22 @@
#ifndef MIMECONTENTFORMATTER_H
#define MIMECONTENTFORMATTER_H
#include <QObject>
#include <QByteArray>
class MimeContentFormatter : public QObject
{
Q_OBJECT
public:
MimeContentFormatter (int max_length = 76);
void setMaxLength(int l);
QString format(const QString &content, bool quotedPrintable = false);
protected:
int max_length;
};
#endif // MIMECONTENTFORMATTER_H

View File

@ -18,12 +18,15 @@
#include <QDateTime> #include <QDateTime>
#include "quotedprintable.h" #include "quotedprintable.h"
#include <typeinfo>
/* [1] Constructors and Destructors */ /* [1] Constructors and Destructors */
MimeMessage::MimeMessage() : MimeMessage::MimeMessage(bool createAutoMimeContent) :
hEncoding(MimePart::_8Bit) hEncoding(MimePart::_8Bit)
{ {
if (createAutoMimeContent)
this->content = new MimeMultiPart();
} }
MimeMessage::~MimeMessage() MimeMessage::~MimeMessage()
@ -41,9 +44,32 @@ void MimeMessage::setSender(EmailAddress* e)
this->sender = e; this->sender = e;
} }
void MimeMessage::addRecipient(EmailAddress* rcpt) void MimeMessage::addRecipient(EmailAddress* rcpt, RecipientType type)
{ {
this->recipients << rcpt; switch (type)
{
case To:
recipientsTo << rcpt;
break;
case Cc:
recipientsCc << rcpt;
break;
case Bcc:
recipientsBcc << rcpt;
break;
}
}
void MimeMessage::addTo(EmailAddress* rcpt) {
this->recipientsTo << rcpt;
}
void MimeMessage::addCc(EmailAddress* rcpt) {
this->recipientsCc << rcpt;
}
void MimeMessage::addBcc(EmailAddress* rcpt) {
this->recipientsBcc << rcpt;
} }
void MimeMessage::setSubject(const QString & subject) void MimeMessage::setSubject(const QString & subject)
@ -53,7 +79,9 @@ void MimeMessage::setSubject(const QString & subject)
void MimeMessage::addPart(MimePart *part) void MimeMessage::addPart(MimePart *part)
{ {
this->parts << part; if (typeid(*content) == typeid(MimeMultiPart)) {
((MimeMultiPart*) content)->addPart(part);
};
} }
void MimeMessage::setHeaderEncoding(MimePart::Encoding hEnc) void MimeMessage::setHeaderEncoding(MimePart::Encoding hEnc)
@ -66,9 +94,18 @@ const EmailAddress & MimeMessage::getSender() const
return *sender; return *sender;
} }
const QList<EmailAddress*> & MimeMessage::getRecipients() const const QList<EmailAddress*> & MimeMessage::getRecipients(RecipientType type) const
{ {
return recipients; switch (type)
{
default:
case To:
return recipientsTo;
case Cc:
return recipientsCc;
case Bcc:
return recipientsBcc;
}
} }
const QString & MimeMessage::getSubject() const const QString & MimeMessage::getSubject() const
@ -78,7 +115,15 @@ const QString & MimeMessage::getSubject() const
const QList<MimePart*> & MimeMessage::getParts() const const QList<MimePart*> & MimeMessage::getParts() const
{ {
return parts; if (typeid(content) == typeid(MimeMultiPart)) {
return static_cast<MimeMultiPart*>(content)->getParts();
}
else {
QList<MimePart*> *res = new QList<MimePart*>();
res->append(content);
return *res;
}
} }
/* [2] --- */ /* [2] --- */
@ -112,11 +157,12 @@ QString MimeMessage::toString()
/* ---------------------------------- */ /* ---------------------------------- */
/* ------- Recipients / To ---------- */ /* ------- Recipients / To ---------- */
QList<EmailAddress*>::iterator it; mime += "To:";
for (it = recipients.begin(); it != recipients.end(); ++it) QList<EmailAddress*>::iterator it; int i;
for (i = 0, it = recipientsTo.begin(); it != recipientsTo.end(); ++it, ++i)
{ {
mime += "To:"; if (i != 0) { mime += ","; }
if ((*it)->getName() != "") if ((*it)->getName() != "")
{ {
@ -132,13 +178,40 @@ QString MimeMessage::toString()
mime += " " + (*it)->getName(); mime += " " + (*it)->getName();
} }
} }
mime += " <" + (*it)->getAddress() + ">\r\n"; mime += " <" + (*it)->getAddress() + ">";
} }
mime += "\r\n";
/* ---------------------------------- */
/* ------- Recipients / Cc ---------- */
mime += "Cc:";
for (i = 0, it = recipientsCc.begin(); it != recipientsCc.end(); ++it, ++i)
{
if (i != 0) { mime += ","; }
if ((*it)->getName() != "")
{
switch (hEncoding)
{
case MimePart::Base64:
mime += " =?utf-8?B?" + QByteArray().append((*it)->getName()).toBase64() + "?=";
break;
case MimePart::QuotedPrintable:
mime += " =?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append((*it)->getName())).replace(' ', "_").replace(':',"=3A") + "?=";
break;
default:
mime += " " + (*it)->getName();
}
}
mime += " <" + (*it)->getAddress() + ">";
}
mime += "\r\n";
/* ---------------------------------- */ /* ---------------------------------- */
/* ------------ Subject ------------- */ /* ------------ Subject ------------- */
mime += "Subject: "; mime += "Subject: ";
switch (hEncoding) switch (hEncoding)
{ {
case MimePart::Base64: case MimePart::Base64:
@ -153,26 +226,9 @@ QString MimeMessage::toString()
/* ---------------------------------- */ /* ---------------------------------- */
mime += "\r\n"; mime += "\r\n";
QString boundary = "----MIME-part-boundary=" + QByteArray().append(QDateTime::currentDateTime().toString()).toBase64() + "-end";
mime += "MIME-Version: 1.0\r\n"; mime += "MIME-Version: 1.0\r\n";
mime += "Content-type: multipart/mixed; boundary=\"" + boundary + "\"\r\n\r\n";
/* ====== END OF MIME HEADER ======== */
boundary = "--" + boundary;
/* ========== MIME BODY ============= */
QList<MimePart*>::iterator i;
for (i = parts.begin(); i != parts.end(); ++i)
mime += boundary + "\r\n" + (*i)->toString();
mime += boundary + "--\r\n";
/* ====== END OF MIME BODY ========= */
mime += content->toString();
return mime; return mime;
} }

View File

@ -18,6 +18,7 @@
#define MIMEMESSAGE_H #define MIMEMESSAGE_H
#include "mimepart.h" #include "mimepart.h"
#include "mimemultipart.h"
#include "emailaddress.h" #include "emailaddress.h"
#include <QList> #include <QList>
@ -25,9 +26,15 @@ class MimeMessage : public QObject
{ {
public: public:
enum RecipientType {
To, // primary
Cc, // carbon copy
Bcc // blind carbon copy
};
/* [1] Constructors and Destructors */ /* [1] Constructors and Destructors */
MimeMessage(); MimeMessage(bool createAutoMimeConent = true);
~MimeMessage(); ~MimeMessage();
/* [1] --- */ /* [1] --- */
@ -36,14 +43,17 @@ public:
/* [2] Getters and Setters */ /* [2] Getters and Setters */
void setSender(EmailAddress* e); void setSender(EmailAddress* e);
void addRecipient(EmailAddress* rcpt); void addRecipient(EmailAddress* rcpt, RecipientType type = To);
void addTo(EmailAddress* rcpt);
void addCc(EmailAddress* rcpt);
void addBcc(EmailAddress* rcpt);
void setSubject(const QString & subject); void setSubject(const QString & subject);
void addPart(MimePart* part); void addPart(MimePart* part);
void setHeaderEncoding(MimePart::Encoding); void setHeaderEncoding(MimePart::Encoding);
const EmailAddress & getSender() const; const EmailAddress & getSender() const;
const QList<EmailAddress*> & getRecipients() const; const QList<EmailAddress*> & getRecipients(RecipientType type = To) const;
const QString & getSubject() const; const QString & getSubject() const;
const QList<MimePart*> & getParts() const; const QList<MimePart*> & getParts() const;
@ -61,9 +71,9 @@ protected:
/* [4] Protected members */ /* [4] Protected members */
EmailAddress* sender; EmailAddress* sender;
QList<EmailAddress*> recipients; QList<EmailAddress*> recipientsTo, recipientsCc, recipientsBcc;
QString subject; QString subject;
QList<MimePart*> parts; MimePart *content;
MimePart::Encoding hEncoding; MimePart::Encoding hEncoding;

52
src/mimemultipart.cpp Normal file
View File

@ -0,0 +1,52 @@
#include "mimemultipart.h"
#include <QTime>
#include <QCryptographicHash>
const QString MULTI_PART_NAMES[] = {
"multipart/mixed", // Mixed
"multipart/digest", // Digest
"multipart/alternative", // Alternative
"multipart/related", // Related
"multipart/report", // Report
"multipart/signed", // Signed
"multipart/encrypted" // Encrypted
};
MimeMultiPart::MimeMultiPart(MultiPartType type)
{
this->type = type;
this->cType = MULTI_PART_NAMES[this->type];
this->cEncoding = _8Bit;
qsrand(QTime::currentTime().msec());
QCryptographicHash md5(QCryptographicHash::Md5);
md5.addData(QByteArray().append(qrand()));
cBoundary = md5.result().toHex();
}
MimeMultiPart::~MimeMultiPart() {
}
void MimeMultiPart::addPart(MimePart *part) {
parts.append(part);
}
const QList<MimePart*> & MimeMultiPart::getParts() const {
return parts;
}
void MimeMultiPart::prepare() {
QList<MimePart*>::iterator it;
content = "";
for (it = parts.begin(); it != parts.end(); it++) {
content += "--" + cBoundary + "\r\n";
(*it)->prepare();
content += (*it)->toString();
};
content += "--" + cBoundary + "--\r\n";
MimePart::prepare();
}

69
src/mimemultipart.h Normal file
View File

@ -0,0 +1,69 @@
/*
Copyright (c) 2012 - Tőkés Attila (tokes_atti@yahoo.com)
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.
*/
#ifndef MIMEMULTIPART_H
#define MIMEMULTIPART_H
#include "mimepart.h"
class MimeMultiPart : public MimePart
{
Q_OBJECT
public:
/* [0] Enums */
enum MultiPartType {
Mixed = 0, // RFC 2046, section 5.1.3
Digest = 1, // RFC 2046, section 5.1.5
Alternative = 2, // RFC 2046, section 5.1.4
Related = 3, // RFC 2387
Report = 4, // RFC 6522
Signed = 5, // RFC 1847, section 2.1
Encrypted = 6 // RFC 1847, section 2.2
};
/* [0] --- */
/* [1] Constructors and Destructors */
MimeMultiPart(const MultiPartType type = Related);
~MimeMultiPart();
/* [1] --- */
/* [2] Getters and Setters */
const QList<MimePart*> & getParts() const;
/* [2] --- */
/* [3] Public methods */
void addPart(MimePart *part);
virtual void prepare();
/* [3] --- */
protected:
QList< MimePart* > parts;
MultiPartType type;
};
#endif // MIMEMULTIPART_H

View File

@ -23,6 +23,7 @@ MimePart::MimePart()
{ {
cEncoding = _7Bit; cEncoding = _7Bit;
prepared = false; prepared = false;
cBoundary = "";
} }
MimePart::~MimePart() MimePart::~MimePart()
@ -47,7 +48,7 @@ void MimePart::setHeader(const QString & header)
void MimePart::addHeaderLine(const QString & line) void MimePart::addHeaderLine(const QString & line)
{ {
this->header += line; this->header += line + "\r\n";
} }
const QString& MimePart::getHeader() const const QString& MimePart::getHeader() const
@ -143,6 +144,9 @@ void MimePart::prepare()
if (cCharset != "") if (cCharset != "")
mimeString.append("; charset=").append(cCharset); mimeString.append("; charset=").append(cCharset);
if (cBoundary != "")
mimeString.append("; boundary=").append(cBoundary);
mimeString.append("\r\n"); mimeString.append("\r\n");
/* ------------ */ /* ------------ */
@ -170,14 +174,15 @@ void MimePart::prepare()
mimeString.append("Content-ID: <").append(cId).append(">\r\n"); mimeString.append("Content-ID: <").append(cId).append(">\r\n");
/* ---------- */ /* ---------- */
/* Addition header lines */
/* ------------------------- */
mimeString.append(header).append("\r\n"); mimeString.append(header).append("\r\n");
/* ------------------------- */
/* === End of Header Prepare === */ /* === End of Header Prepare === */
/* === Content Encoding === */ /* === Content === */
switch (cEncoding) switch (cEncoding)
{ {
case _7Bit: case _7Bit:
@ -187,14 +192,14 @@ void MimePart::prepare()
mimeString.append(content); mimeString.append(content);
break; break;
case Base64: case Base64:
mimeString.append(content.toBase64()); mimeString.append(formatter.format(content.toBase64()));
break; break;
case QuotedPrintable: case QuotedPrintable:
mimeString.append(QuotedPrintable::encode(content)); mimeString.append(formatter.format(QuotedPrintable::encode(content), true));
break; break;
} }
mimeString.append("\r\n"); mimeString.append("\r\n");
/* === End of Content Encoding === */ /* === End of Content === */
prepared = true; prepared = true;
} }

View File

@ -18,6 +18,7 @@
#define MIMEPART_H #define MIMEPART_H
#include <QObject> #include <QObject>
#include "mimecontentformatter.h"
class MimePart : public QObject class MimePart : public QObject
{ {
@ -93,11 +94,14 @@ protected:
QString cName; QString cName;
QString cType; QString cType;
QString cCharset; QString cCharset;
QString cBoundary;
Encoding cEncoding; Encoding cEncoding;
QString mimeString; QString mimeString;
bool prepared; bool prepared;
MimeContentFormatter formatter;
/* [4] --- */ /* [4] --- */
}; };

View File

@ -267,9 +267,32 @@ bool SmtpClient::sendMail(MimeMessage& email)
if (responseCode != 250) return false; if (responseCode != 250) return false;
// Send RCPT command for each recipient // Send RCPT command for each recipient
for (int i = 0; i < email.getRecipients().size(); ++i) QList<EmailAddress*>::const_iterator it, itEnd;
// To (primary recipients)
for (it = email.getRecipients().begin(), itEnd = email.getRecipients().end();
it != itEnd; ++it)
{ {
sendMessage("RCPT TO: <" + email.getRecipients().at(i)->getAddress() + ">"); 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(); waitForResponse();
if (responseCode != 250) return false; if (responseCode != 250) return false;