Compare commits

..

44 Commits
dev ... v1.1

Author SHA1 Message Date
39d6f35ca7
<fix>(project): support static build. 2022-01-15 00:34:10 +08:00
Attila Tőkés
3fa4a0fe57
Merge pull request #101 from emkey08/v1.1
Fix incorrect date header when using Qt4
2021-03-20 18:52:56 +02:00
Mathias Kunter
152a3e7572 Fix incorrect date header when using Qt4
Fix the timezone offset string to comply with RFC 2822.

Use the "C" locale instead of the system locale for obtaining day
and month names. Day and month names must always be in English.
2021-02-25 15:06:33 +01:00
Attila Tőkés
f715bb9916
Merge pull request #73 from mabrand/fix2
remove stray space after colon following MAIL FROM and RCPT TO
2019-01-15 08:58:21 +02:00
Mark Brand
67c73c7c96 remove stray space after colon following MAIL FROM and RCPT TO
Quoth https://www.ietf.org/rfc/rfc5321.txt:

   Since it has been a common source of errors, it is worth noting that
   spaces are not permitted on either side of the colon following FROM
   in the MAIL command or TO in the RCPT command.  The syntax is exactly
   as given above.
2019-01-14 23:59:43 +01:00
Attila Tőkés
1f4f2e208b
Merge pull request #71 from mabrand/fix-date-field
fix Qt version check
2018-06-13 19:41:22 +03:00
Mark Brand
5bdfa6a5dd fix Qt version check
QT_VERSION_MAJOR, not QT_MAJOR_VERSION, and fixed stray #elif
2018-06-13 17:44:42 +02:00
Attila Tőkés
3d87c6306e
Merge pull request #69 from esilvia/v1.1
Fixed Qt4 compilation for version 1.1. Works with MSVC2013. (#62)
2018-04-24 07:28:33 +03:00
Evon Silvia
81c652dc73 Fixed Qt4 compilation for version 1.1. Works with MSVC2013. (#62) 2018-04-23 09:02:34 -07:00
Attila Tőkés
ca43f9d642
Merge pull request #63 from bluetiger9/master
Added Reply-To support
2017-12-22 10:47:43 +02:00
Attila Tőkés
12c810ada9 Merge pull request #43 from altaris/master
Added Reply-To support
2017-06-01 20:14:38 +03:00
Attila Tőkés
7633337dd6 Merge pull request #53 from ymuv/v1.1
Add In-Reply-To field.
2017-06-01 20:10:33 +03:00
Attila Tőkés
5fc59c0863 Issue #50 - fix memory leaks 2017-06-01 19:14:20 +03:00
Attila Tőkés
6b676827fe Issue #41 - remove extra space from MAIL FROM and RCPT TO commands 2017-06-01 18:20:49 +03:00
Attila Tőkés
cb04e35bed Merge pull request #56 from bryant1410/v1.1
Fix broken headings in Markdown files
2017-04-22 09:46:48 +03:00
Santiago Castro
96452106d8 Fix broken Markdown headings 2017-04-17 04:27:42 -03:00
ymuv
8623093e9b Add In-Reply-To field. 2017-01-23 01:56:44 +02:00
Attila Tőkés
800ff9cf69 Merge pull request #52 from kosmaz/v1.1
Caught SmtpClient::SendMessageTimeoutException
2017-01-14 09:16:28 +02:00
Ezenwanne I. Cosmas
ff2eb297c4 Caught SmtpClient::SendMessageTimeoutException
In Smtp::quit, SmtpClient::SendMessageTimeoutException is caught and if still connected to the smtp server, manually close
the connection.
2017-01-13 18:49:02 +01:00
Attila Tőkés
ef6194fb26 Merge pull request #48 from Spiek/v1.1
Add date header field in RFC2822 format to MimeMessage
2016-03-23 19:51:57 +02:00
Spiek
78bf2dac42 Add date header field in RFC2822 format to MimeMessage 2016-03-23 11:07:38 +01:00
Cedric HT
c2a734791a Added Reply-To support 2016-01-13 15:43:26 +01:00
Attila Tőkés
48c080b9ee Merge pull request #39 from ursfassler/v1.1
cleanup compiler errors/warnings
2015-10-26 20:21:14 +02:00
Urs Fässler
6de3493c92 cleanup compiler errors/warnings 2015-10-26 16:31:51 +01:00
Attila Tőkés
9afc349942 Fix typo in default host. 2015-09-05 18:22:58 +03:00
Attila Tőkés
c12f70b721 Fix memory leak 2015-06-03 23:27:54 +03:00
Attila Tőkés
6877ac8148 Small fixes. 2014-11-01 22:50:37 +02:00
Attila Tőkés
f8db82bae5 add demos/demo3/demo3.cpp 2014-10-30 23:09:18 +02:00
Attila Tőkés
7f8d11db2f Set up demo projects. 2014-10-30 23:04:04 +02:00
Attila Tőkés
06db4130d9 Add posibility to build as a shared library. 2014-10-30 22:17:44 +02:00
Tőkés Attila
235a350a34 Merge pull request #27 from DEgITx/patch-1
Update quotedprintable.cpp
2014-10-30 21:31:33 +02:00
Tőkés Attila
75f4bf385a Merge pull request #30 from amuetzel/master
added QT_DECL_EXPORT/QT_DECL_IMPORT to allow building DLLs
2014-10-30 21:30:31 +02:00
Andreas Mützel
a4f4235139 added necessary QT_DECL_EXPORT/QT_DECL_IMPORT to be able to build a DLL on windows 2014-09-01 09:59:57 +02:00
Alexey Kasyanchuk
649ea30336 Update quotedprintable.cpp
Some compilators can interpret this differently (gcc shows warning about this)
2014-07-20 10:27:23 +03:00
Tőkés Attila
076034a612 Merge pull request #17 from LascauxSRL/master
Added support for ByteArray Attachments and removed Memory Leak from MimeMessage class
2014-02-21 17:18:51 +02:00
Attila Tőkés
b1c640c39d Merge branch 'v1.1' 2014-02-21 17:17:42 +02:00
LascauxSRL
4f028793e1 - Added support for SendMessage Timeout (Doesn't rely on Reply Timeout)
- Solved small bug in emitting an error message
2014-02-20 11:41:21 +01:00
Attila Tőkés
f3da3b391c Qt5 compatibility. 2014-02-16 19:10:37 +02:00
LascauxSRL
93873f8b1c - Added support for ByteArray Attachments
- Removed memoryleak from MimeMessage
2013-08-08 10:45:39 +02:00
Tőkés Attila
dac7a04d6f Merge branch 'v1.1' 2012-10-25 18:17:30 +03:00
Tőkés Attila
8f6a67664f Added getters and setters for connection and response timeouts. 2012-10-25 18:06:16 +03:00
Attila Tőkés
3d3f9136af Bug fix (issue 2) 2012-09-05 19:36:52 +03:00
Attila
81e561c91b Merge branch 'v1.1'
Conflicts:
	README.md
2012-08-09 22:40:41 +03:00
bluetiger9
32b11e2351 Readme fixed. 2012-03-20 20:24:54 +02:00
58 changed files with 1089 additions and 1433 deletions

6
.gitignore vendored
View File

@ -1,6 +0,0 @@
*.o
*.so
*.so.*
Makefile
moc_*.cpp
*.pro.user*

View File

@ -1,13 +0,0 @@
sudo: required
dist: trusty
before_install:
- sudo add-apt-repository --yes ppa:ubuntu-sdk-team/ppa
- sudo apt-get update -qq
- sudo apt-get install qtbase5-dev qtdeclarative5-dev libqt5webkit5-dev libsqlite3-dev
- sudo apt-get install qt5-default qttools5-dev-tools
script:
- qmake -project
- qmake src/SMTPEmail.pro
- make

View File

@ -1,18 +1,9 @@
SMTP Client for Qt (C++) - Version 2.0 [![Build Status](https://travis-ci.org/bluetiger9/SmtpClient-for-Qt.svg?branch=dev)](https://travis-ci.org/bluetiger9/SmtpClient-for-Qt) SMTP Client for Qt (C++) - Version 1.1
============================================= =============================================
The SmtpClient for Qt is small library writen for Qt 4 (C++ version) that allows application to send complex emails (plain text, html, attachments, inline files, etc.) using the Simple Mail Transfer Protocol (SMTP). The SmtpClient for Qt is small library writen for Qt 4 (C++ version) that allows application to send complex emails (plain text, html, attachments, inline files, etc.) using the Simple Mail Transfer Protocol (SMTP).
##New in version 2.0: ## New in version 1.1:
- Asynchronous & Synchronous working mode
- Qt5 compatibility
- Building as a shared library
- code of SmtpClient refactored and partially rewrited
##New in version 1.1:
- TLS (STARTTLS) connection is now supported - TLS (STARTTLS) connection is now supported
@ -23,7 +14,7 @@ The SmtpClient for Qt is small library writen for Qt 4 (C++ version) that allows
- output compilant with RFC2045 - output compilant with RFC2045
## SMTP Client for Qt supports ## SMPT Client for Qt supports
- TCP and SSL connections to SMTP servers - TCP and SSL connections to SMTP servers
@ -86,14 +77,8 @@ int main(int argc, char *argv[])
// Now we can send the mail // Now we can send the mail
smtp.connectToHost(); smtp.connectToHost();
smtp.waitForReadyConnected();
smtp.login(); smtp.login();
smtp.waitForAuthenticated();
smtp.sendMail(message); smtp.sendMail(message);
smtp.waitForMailSent();
smtp.quit(); smtp.quit();
} }
@ -106,4 +91,4 @@ For more examples see the [Wiki/Examples](https://github.com/bluetiger9/SmtpClie
This project (all files including the demos/examples) is licensed under the GNU LGPL, version 2.1. This project (all files including the demos/examples) is licensed under the GNU LGPL, version 2.1.
**Copyright (c) 2014 - Tőkés Attila** **Copyright (c) 2011 - Tőkés Attila**

53
SMTPEmail.pro Normal file
View File

@ -0,0 +1,53 @@
#-------------------------------------------------
#
# Project created by QtCreator 2011-08-11T20:59:25
#
#-------------------------------------------------
QT += core network
TARGET = SMTPEmail
# Build as an application
#TEMPLATE = app
# Build as a library
TEMPLATE = lib
DEFINES += SMTP_BUILD
win32:CONFIG += dll
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 \
src/smtpexports.h
OTHER_FILES += \
LICENSE \
README.md
FORMS +=

View File

@ -8,15 +8,27 @@ int main(int argc, char *argv[])
// This is a first demo application of the SmtpClient for Qt project // This is a first demo application of the SmtpClient for Qt project
// First we need to create an SmtpClient object
// We will use the Gmail's smtp server (smtp.gmail.com, port 465, ssl)
SmtpClient smtp("smtp.gmail.com", 465, SmtpClient::SslConnection);
// We need to set the username (your email address) and password
// for smtp authentification.
smtp.setUser("your_email_address@host.com");
smtp.setPassword("your_password");
// Now we create a MimeMessage object. This is the email. // Now we create a MimeMessage object. This is the email.
MimeMessage message; MimeMessage message;
EmailAddress sender("your_email_address@host.com", "Your Name"); EmailAddress sender("your_email_address@host.com", "Your Name");
message.setSender(sender); message.setSender(&sender);
EmailAddress to("recipient@host.com", "Recipient's Name"); EmailAddress to("recipient@host.com", "Recipient's Name");
message.addRecipient(to); message.addRecipient(&to);
message.setSubject("SmtpClient for Qt - Demo"); message.setSubject("SmtpClient for Qt - Demo");
@ -32,22 +44,18 @@ int main(int argc, char *argv[])
message.addPart(&text); message.addPart(&text);
// Now we can send the mail // Now we can send the mail
SmtpClient smtp("smtp.gmail.com", 465, SmtpClient::SslConnection);
smtp.connectToHost(); if (!smtp.connectToHost()) {
if (!smtp.waitForReadyConnected()) {
qDebug() << "Failed to connect to host!" << endl; qDebug() << "Failed to connect to host!" << endl;
return -1; return -1;
} }
smtp.login("your_email_address@host.com", "your_password"); if (!smtp.login()) {
if (!smtp.waitForAuthenticated()) {
qDebug() << "Failed to login!" << endl; qDebug() << "Failed to login!" << endl;
return -2; return -2;
} }
smtp.sendMail(message); if (!smtp.sendMail(message)) {
if (!smtp.waitForMailSent()) {
qDebug() << "Failed to send mail!" << endl; qDebug() << "Failed to send mail!" << endl;
return -3; return -3;
} }

View File

@ -21,9 +21,9 @@ SOURCES += \
# Location of SMTP Library # Location of SMTP Library
SMTP_LIBRARY_LOCATION = $$PWD/../../../build/SMTPEmail-Desktop-Debug SMTP_LIBRARY_LOCATION = $$PWD/../../../build/SMTPEmail-Desktop-Debug
win32:CONFIG(release, debug|release): LIBS += -L$$SMTP_LIBRARY_LOCATION/release/ -lSMTPMime win32:CONFIG(release, debug|release): LIBS += -L$$SMTP_LIBRARY_LOCATION/release/ -lSMTPEmail
else:win32:CONFIG(debug, debug|release): LIBS += -L$$SMTP_LIBRARY_LOCATION/debug/ -lSMTPMime else:win32:CONFIG(debug, debug|release): LIBS += -L$$SMTP_LIBRARY_LOCATION/debug/ -lSMTPEmail
else:unix: LIBS += -L$$SMTP_LIBRARY_LOCATION -lSmtpMime else:unix: LIBS += -L$$SMTP_LIBRARY_LOCATION -lSMTPEmail
INCLUDEPATH += $$SMTP_LIBRARY_LOCATION INCLUDEPATH += $$SMTP_LIBRARY_LOCATION
DEPENDPATH += $$SMTP_LIBRARY_LOCATION DEPENDPATH += $$SMTP_LIBRARY_LOCATION

View File

@ -18,9 +18,9 @@ SOURCES += \
# Location of SMTP Library # Location of SMTP Library
SMTP_LIBRARY_LOCATION = $$PWD/../../../build/SMTPEmail-Desktop-Debug SMTP_LIBRARY_LOCATION = $$PWD/../../../build/SMTPEmail-Desktop-Debug
win32:CONFIG(release, debug|release): LIBS += -L$$SMTP_LIBRARY_LOCATION/release/ -lSMTPMime win32:CONFIG(release, debug|release): LIBS += -L$$SMTP_LIBRARY_LOCATION/release/ -lSMTPEmail
else:win32:CONFIG(debug, debug|release): LIBS += -L$$SMTP_LIBRARY_LOCATION/debug/ -lSMTPMime else:win32:CONFIG(debug, debug|release): LIBS += -L$$SMTP_LIBRARY_LOCATION/debug/ -lSMTPEmail
else:unix: LIBS += -L$$SMTP_LIBRARY_LOCATION -lSmtpMime else:unix: LIBS += -L$$SMTP_LIBRARY_LOCATION -lSMTPEmail
INCLUDEPATH += $$SMTP_LIBRARY_LOCATION INCLUDEPATH += $$SMTP_LIBRARY_LOCATION
DEPENDPATH += $$SMTP_LIBRARY_LOCATION DEPENDPATH += $$SMTP_LIBRARY_LOCATION

View File

@ -37,7 +37,7 @@ SendEmail::~SendEmail()
delete ui; delete ui;
} }
EmailAddress SendEmail::stringToEmail(const QString &str) EmailAddress* SendEmail::stringToEmail(const QString &str)
{ {
int p1 = str.indexOf("<"); int p1 = str.indexOf("<");
int p2 = str.indexOf(">"); int p2 = str.indexOf(">");
@ -45,11 +45,11 @@ EmailAddress SendEmail::stringToEmail(const QString &str)
if (p1 == -1) if (p1 == -1)
{ {
// no name, only email address // no name, only email address
return EmailAddress(str); return new EmailAddress(str);
} }
else else
{ {
return EmailAddress(str.mid(p1 + 1, p2 - p1 - 1), str.left(p1)); return new EmailAddress(str.mid(p1 + 1, p2 - p1 - 1), str.left(p1));
} }
} }
@ -59,8 +59,11 @@ void SendEmail::on_addAttachment_clicked()
QFileDialog dialog(this); QFileDialog dialog(this);
dialog.setFileMode(QFileDialog::ExistingFiles); dialog.setFileMode(QFileDialog::ExistingFiles);
if (dialog.exec()) if (dialog.exec())
ui->attachments->addItems(dialog.selectedFiles()); ui->attachments->addItems(dialog.selectedFiles());
} }
void SendEmail::on_sendEmail_clicked() void SendEmail::on_sendEmail_clicked()
@ -72,7 +75,7 @@ void SendEmail::on_sendEmail_clicked()
QString user = ui->username->text(); QString user = ui->username->text();
QString password = ui->password->text(); QString password = ui->password->text();
EmailAddress sender = stringToEmail(ui->sender->text()); EmailAddress *sender = stringToEmail(ui->sender->text());
QStringList rcptStringList = ui->recipients->text().split(';'); QStringList rcptStringList = ui->recipients->text().split(';');
@ -99,25 +102,20 @@ void SendEmail::on_sendEmail_clicked()
message.addPart(new MimeAttachment(new QFile(ui->attachments->item(i)->text()))); message.addPart(new MimeAttachment(new QFile(ui->attachments->item(i)->text())));
} }
smtp.connectToHost(); if (!smtp.connectToHost())
if (!smtp.waitForReadyConnected())
{ {
errorMessage("Connection Failed"); errorMessage("Connection Failed");
return; return;
} }
if (auth) if (auth)
{ if (!smtp.login(user, password))
smtp.login(user, password);
if (!smtp.waitForAuthenticated())
{ {
errorMessage("Authentification Failed"); errorMessage("Authentification Failed");
return; return;
} }
}
smtp.sendMail(message); if (!smtp.sendMail(message))
if (!smtp.waitForMailSent())
{ {
errorMessage("Mail sending failed"); errorMessage("Mail sending failed");
return; return;

View File

@ -21,6 +21,8 @@
#include "../../src/SmtpMime" #include "../../src/SmtpMime"
namespace Ui { namespace Ui {
class SendEmail; class SendEmail;
} }
@ -33,7 +35,7 @@ public:
explicit SendEmail(QWidget *parent = 0); explicit SendEmail(QWidget *parent = 0);
~SendEmail(); ~SendEmail();
static EmailAddress stringToEmail(const QString & str); static EmailAddress * stringToEmail(const QString & str);
private slots: private slots:
void on_addAttachment_clicked(); void on_addAttachment_clicked();

View File

@ -22,14 +22,22 @@ int main(int argc, char *argv[])
{ {
QCoreApplication a(argc, argv); QCoreApplication a(argc, argv);
// First create the SmtpClient object and set the user and the password.
SmtpClient smtp("smtp.gmail.com", 465, SmtpClient::SslConnection);
smtp.setUser("your_email@host.com");
smtp.setPassword("your_password");
// Create a MimeMessage // Create a MimeMessage
MimeMessage message; MimeMessage message;
EmailAddress sender("your_email_address@host.com", "Your Name"); EmailAddress sender("your_email_address@host.com", "Your Name");
message.setSender(sender); message.setSender(&sender);
EmailAddress to("recipient@host.com", "Recipient's Name"); EmailAddress to("recipient@host.com", "Recipient's Name");
message.addRecipient(to); message.addRecipient(&to);
message.setSubject("SmtpClient for Qt - Demo"); message.setSubject("SmtpClient for Qt - Demo");
@ -52,22 +60,18 @@ int main(int argc, char *argv[])
message.addPart(&document); message.addPart(&document);
// Now we can send the mail // Now we can send the mail
SmtpClient smtp("smtp.gmail.com", 465, SmtpClient::SslConnection);
smtp.connectToHost(); if (!smtp.connectToHost()) {
if (!smtp.waitForReadyConnected()) {
qDebug() << "Failed to connect to host!" << endl; qDebug() << "Failed to connect to host!" << endl;
return -1; return -1;
} }
smtp.login("your_email_address@host.com", "your_password"); if (!smtp.login()) {
if (!smtp.waitForAuthenticated()) {
qDebug() << "Failed to login!" << endl; qDebug() << "Failed to login!" << endl;
return -2; return -2;
} }
smtp.sendMail(message); if (!smtp.sendMail(message)) {
if (!smtp.waitForMailSent()) {
qDebug() << "Failed to send mail!" << endl; qDebug() << "Failed to send mail!" << endl;
return -3; return -3;
} }

View File

@ -20,9 +20,9 @@ SOURCES += \
# Location of SMTP Library # Location of SMTP Library
SMTP_LIBRARY_LOCATION = $$PWD/../../../build/SMTPEmail-Desktop-Debug SMTP_LIBRARY_LOCATION = $$PWD/../../../build/SMTPEmail-Desktop-Debug
win32:CONFIG(release, debug|release): LIBS += -L$$SMTP_LIBRARY_LOCATION/release/ -lSMTPMime win32:CONFIG(release, debug|release): LIBS += -L$$SMTP_LIBRARY_LOCATION/release/ -lSMTPEmail
else:win32:CONFIG(debug, debug|release): LIBS += -L$$SMTP_LIBRARY_LOCATION/debug/ -lSMTPMime else:win32:CONFIG(debug, debug|release): LIBS += -L$$SMTP_LIBRARY_LOCATION/debug/ -lSMTPEmail
else:unix: LIBS += -L$$SMTP_LIBRARY_LOCATION -lSmtpMime else:unix: LIBS += -L$$SMTP_LIBRARY_LOCATION -lSMTPEmail
INCLUDEPATH += $$SMTP_LIBRARY_LOCATION INCLUDEPATH += $$SMTP_LIBRARY_LOCATION
DEPENDPATH += $$SMTP_LIBRARY_LOCATION DEPENDPATH += $$SMTP_LIBRARY_LOCATION

View File

@ -22,15 +22,22 @@ int main(int argc, char *argv[])
{ {
QCoreApplication a(argc, argv); QCoreApplication a(argc, argv);
// First create the SmtpClient object and set the user and the password.
SmtpClient smtp("smtp.gmail.com", 465, SmtpClient::SslConnection);
smtp.setUser("your_email@host.com");
smtp.setPassword("your_password");
// Create a MimeMessage // Create a MimeMessage
MimeMessage message; MimeMessage message;
EmailAddress sender("your_email_address@host.com", "Your Name"); EmailAddress sender("your_email_address@host.com", "Your Name");
message.setSender(sender); message.setSender(&sender);
EmailAddress to("recipient@host.com", "Recipient's Name"); EmailAddress to("recipient@host.com", "Recipient's Name");
message.addRecipient(to); message.addRecipient(&to);
message.setSubject("SmtpClient for Qt - Example 3 - Html email with images"); message.setSubject("SmtpClient for Qt - Example 3 - Html email with images");
@ -59,26 +66,22 @@ int main(int argc, char *argv[])
message.addPart(&image1); message.addPart(&image1);
message.addPart(&image2); message.addPart(&image2);
// Now we can send the mail // Now the email can be sended
SmtpClient smtp("smtp.gmail.com", 465, SmtpClient::SslConnection); if (!smtp.connectToHost()) {
smtp.connectToHost();
if (!smtp.waitForReadyConnected()) {
qDebug() << "Failed to connect to host!" << endl; qDebug() << "Failed to connect to host!" << endl;
return -1; return -1;
} }
smtp.login("your_email_address@host.com", "your_password"); if (!smtp.login()) {
if (!smtp.waitForAuthenticated()) {
qDebug() << "Failed to login!" << endl; qDebug() << "Failed to login!" << endl;
return -2; return -2;
} }
smtp.sendMail(message); if (!smtp.sendMail(message)) {
if (!smtp.waitForMailSent()) {
qDebug() << "Failed to send mail!" << endl; qDebug() << "Failed to send mail!" << endl;
return -3; return -3;
} }
smtp.quit(); smtp.quit();
} }

View File

@ -20,9 +20,9 @@ SOURCES += \
# Location of SMTP Library # Location of SMTP Library
SMTP_LIBRARY_LOCATION = $$PWD/../../../build/SMTPEmail-Desktop-Debug SMTP_LIBRARY_LOCATION = $$PWD/../../../build/SMTPEmail-Desktop-Debug
win32:CONFIG(release, debug|release): LIBS += -L$$SMTP_LIBRARY_LOCATION/release/ -lSMTPMime win32:CONFIG(release, debug|release): LIBS += -L$$SMTP_LIBRARY_LOCATION/release/ -lSMTPEmail
else:win32:CONFIG(debug, debug|release): LIBS += -L$$SMTP_LIBRARY_LOCATION/debug/ -lSMTPMime else:win32:CONFIG(debug, debug|release): LIBS += -L$$SMTP_LIBRARY_LOCATION/debug/ -lSMTPEmail
else:unix: LIBS += -L$$SMTP_LIBRARY_LOCATION -lSmtpMime else:unix: LIBS += -L$$SMTP_LIBRARY_LOCATION -lSMTPEmail
INCLUDEPATH += $$SMTP_LIBRARY_LOCATION INCLUDEPATH += $$SMTP_LIBRARY_LOCATION
DEPENDPATH += $$SMTP_LIBRARY_LOCATION DEPENDPATH += $$SMTP_LIBRARY_LOCATION

View File

@ -1,58 +0,0 @@
#-------------------------------------------------
#
# Project created by QtCreator 2011-08-11T20:59:25
#
#-------------------------------------------------
QT = core network
TARGET = SmtpMime
TEMPLATE = lib
DEFINES += 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 \
mimebase64formatter.h \
mimecontentformatter.h
OTHER_FILES += \
LICENSE \
README.md
FORMS +=

View File

@ -27,6 +27,5 @@
#include "mimetext.h" #include "mimetext.h"
#include "mimeinlinefile.h" #include "mimeinlinefile.h"
#include "mimefile.h" #include "mimefile.h"
#include "mimebytearrayattachment.h"
#endif // SMTPMIME_H #endif // SMTPMIME_H

View File

@ -21,13 +21,9 @@
/* [1] Constructors and Destructors */ /* [1] Constructors and Destructors */
EmailAddress::EmailAddress(const QString & address, const QString & name) EmailAddress::EmailAddress(const QString & address, const QString & name)
: address(address), name(name)
{
}
EmailAddress::EmailAddress(const EmailAddress &other)
: address(other.address), name(other.name)
{ {
this->address = address;
this->name = name;
} }
EmailAddress::~EmailAddress() EmailAddress::~EmailAddress()
@ -39,13 +35,23 @@ EmailAddress::~EmailAddress()
/* [2] Getters and Setters */ /* [2] Getters and Setters */
void EmailAddress::setName(const QString & name)
{
this->name = name;
QString EmailAddress::getName() const }
void EmailAddress::setAddress(const QString & address)
{
this->address = address;
}
const QString & EmailAddress::getName() const
{ {
return name; return name;
} }
QString EmailAddress::getAddress() const const QString & EmailAddress::getAddress() const
{ {
return address; return address;
} }

View File

@ -19,17 +19,19 @@
#ifndef EMAILADDRESS_H #ifndef EMAILADDRESS_H
#define EMAILADDRESS_H #define EMAILADDRESS_H
#include "smtpmime_global.h" #include <QObject>
#include <QString>
class SMTP_MIME_EXPORT EmailAddress #include "smtpexports.h"
class SMTP_EXPORT EmailAddress : public QObject
{ {
Q_OBJECT
public: public:
/* [1] Constructors and Destructors */ /* [1] Constructors and Destructors */
EmailAddress(const QString & address = "", const QString & name = ""); EmailAddress();
EmailAddress(const EmailAddress &other); EmailAddress(const QString & address, const QString & name="");
~EmailAddress(); ~EmailAddress();
@ -37,9 +39,11 @@ public:
/* [2] Getters and Setters */ /* [2] Getters and Setters */
void setName(const QString & name);
void setAddress(const QString & address);
QString getAddress() const; const QString & getName() const;
QString getName() const; const QString & getAddress() const;
/* [2] --- */ /* [2] --- */
@ -48,8 +52,8 @@ private:
/* [3] Private members */ /* [3] Private members */
QString address;
QString name; QString name;
QString address;
/* [3] --- */ /* [3] --- */
}; };

View File

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

View File

@ -19,18 +19,22 @@
#ifndef MIMEATTACHMENT_H #ifndef MIMEATTACHMENT_H
#define MIMEATTACHMENT_H #define MIMEATTACHMENT_H
#include <QFile>
#include "smtpmime_global.h"
#include "mimepart.h" #include "mimepart.h"
#include "mimefile.h" #include "mimefile.h"
class SMTP_MIME_EXPORT MimeAttachment : public MimeFile #include "smtpexports.h"
class SMTP_EXPORT MimeAttachment : public MimeFile
{ {
Q_OBJECT
public: public:
/* [1] Constructors and Destructors */ /* [1] Constructors and Destructors */
MimeAttachment(QFile* file); MimeAttachment(QFile* file);
MimeAttachment(const QByteArray& stream, const QString& fileName);
~MimeAttachment(); ~MimeAttachment();
/* [1] --- */ /* [1] --- */
@ -38,6 +42,9 @@ public:
protected: protected:
/* [2] Protected methods */ /* [2] Protected methods */
virtual void prepare();
/* [2] --- */ /* [2] --- */
}; };

View File

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

View File

@ -1,14 +0,0 @@
#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

@ -1,16 +0,0 @@
#include "mimebase64formatter.h"
MimeBase64Formatter::MimeBase64Formatter(QIODevice *out) :
MimeContentFormatter(out) {}
qint64 MimeBase64Formatter::writeData(const char *data, qint64 maxLength) {
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;
}

View File

@ -1,15 +0,0 @@
#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

@ -1,13 +0,0 @@
#include "mimebytearrayattachment.h"
MimeByteArrayAttachment::MimeByteArrayAttachment(const QString& name, const QByteArray &content) :
MimePart()
{
this->cType = "application/octet-stream";
this->cEncoding = Base64;
this->cName = name,
this->content = content;
}
MimeByteArrayAttachment::~MimeByteArrayAttachment() {}

View File

@ -1,20 +0,0 @@
#ifndef MIMEBYTEARRAYATTACHMENT_H
#define MIMEBYTEARRAYATTACHMENT_H
#include "smtpmime_global.h"
#include "mimepart.h"
class SMTP_MIME_EXPORT MimeByteArrayAttachment : public MimePart
{
public:
/* [1] Constructors and Destructors */
MimeByteArrayAttachment(const QString& name, const QByteArray &content);
~MimeByteArrayAttachment();
/* [1] --- */
};
#endif // MIMEBYTEARRAYATTACHMENT_H

View File

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

View File

@ -1,16 +0,0 @@
#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,20 +1,66 @@
/*
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" #include "mimecontentformatter.h"
MimeContentFormatter::MimeContentFormatter(QIODevice *out, int length) : MimeContentFormatter::MimeContentFormatter(int max_length) :
output(out), max_length(max_length)
lineLength(length) {}
{
QIODevice::open(WriteOnly); 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;
} }
int MimeContentFormatter::getLineLength() const { void MimeContentFormatter::setMaxLength(int l) {
return lineLength; max_length = l;
} }
void MimeContentFormatter::setLineLength(int l) { int MimeContentFormatter::getMaxLength() const {
lineLength = l; return max_length;
}
qint64 MimeContentFormatter::readData(char*, qint64) {
return -1;
} }

View File

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

View File

@ -29,8 +29,18 @@ MimeFile::MimeFile(QFile *file)
this->cEncoding = Base64; this->cEncoding = Base64;
} }
MimeFile::MimeFile(const QByteArray& stream, const QString& fileName)
{
this->cEncoding = Base64;
this->cType = "application/octet-stream";
this->file = 0;
this->cName = fileName;
this->content = stream;
}
MimeFile::~MimeFile() MimeFile::~MimeFile()
{ {
if (file)
delete file; delete file;
} }
@ -44,13 +54,16 @@ MimeFile::~MimeFile()
/* [3] Protected methods */ /* [3] Protected methods */
void MimeFile::prepare()
void MimeFile::writeContent(QIODevice &device) const { {
if (this->file)
{
file->open(QIODevice::ReadOnly); file->open(QIODevice::ReadOnly);
const QByteArray &fileContent = file->readAll(); this->content = file->readAll();
file->close(); file->close();
}
MimePart::writeContent(device, fileContent); /* !!! IMPORTANT !!!! */
MimePart::prepare();
} }
/* [3] --- */ /* [3] --- */

View File

@ -20,16 +20,18 @@
#define MIMEFILE_H #define MIMEFILE_H
#include "mimepart.h" #include "mimepart.h"
#include "smtpmime_global.h" #include <QFile>
class QFile; #include "smtpexports.h"
class SMTP_MIME_EXPORT MimeFile : public MimePart class SMTP_EXPORT MimeFile : public MimePart
{ {
Q_OBJECT
public: public:
/* [1] Constructors and Destructors */ /* [1] Constructors and Destructors */
MimeFile(const QByteArray& stream, const QString& fileName);
MimeFile(QFile *f); MimeFile(QFile *f);
~MimeFile(); ~MimeFile();
@ -51,8 +53,7 @@ protected:
/* [4] Protected methods */ /* [4] Protected methods */
void writeContent(QIODevice &device) const; virtual void prepare();
/* [4] --- */ /* [4] --- */

View File

@ -37,7 +37,7 @@ void MimeHtml::setHtml(const QString & html)
this->text = html; this->text = html;
} }
QString MimeHtml::getHtml() const const QString & MimeHtml::getHtml() const
{ {
return text; return text;
} }
@ -48,4 +48,10 @@ QString MimeHtml::getHtml() const
/* [3] Protected methods */ /* [3] Protected methods */
void MimeHtml::prepare()
{
/* !!! IMPORTANT !!! */
MimeText::prepare();
}
/* [3] --- */ /* [3] --- */

View File

@ -19,11 +19,13 @@
#ifndef MIMEHTML_H #ifndef MIMEHTML_H
#define MIMEHTML_H #define MIMEHTML_H
#include "smtpmime_global.h"
#include "mimetext.h" #include "mimetext.h"
class SMTP_MIME_EXPORT MimeHtml : public MimeText #include "smtpexports.h"
class SMTP_EXPORT MimeHtml : public MimeText
{ {
Q_OBJECT
public: public:
/* [1] Constructors and Destructors */ /* [1] Constructors and Destructors */
@ -38,7 +40,7 @@ public:
void setHtml(const QString & html); void setHtml(const QString & html);
QString getHtml() const; const QString& getHtml() const;
/* [2] --- */ /* [2] --- */
@ -51,6 +53,8 @@ protected:
/* [4] Protected methods */ /* [4] Protected methods */
virtual void prepare();
/* [4] --- */ /* [4] --- */
}; };

View File

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

View File

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

View File

@ -18,23 +18,29 @@
#include "mimemessage.h" #include "mimemessage.h"
#include <QDebug>
#include <QDateTime> #include <QDateTime>
#include <QBuffer> #include <QLocale>
#include "quotedprintable.h" #include "quotedprintable.h"
#include <typeinfo> #include <typeinfo>
/* [1] Constructors and Destructors */ /* [1] Constructors and Destructors */
MimeMessage::MimeMessage(bool createAutoMimeContent) : MimeMessage::MimeMessage(bool createAutoMimeContent) :
replyTo(nullptr),
hEncoding(MimePart::_8Bit) hEncoding(MimePart::_8Bit)
{ {
if (createAutoMimeContent) if (createAutoMimeContent)
this->content = new MimeMultiPart(); this->content = new MimeMultiPart();
autoMimeContentCreated = createAutoMimeContent;
} }
MimeMessage::~MimeMessage() MimeMessage::~MimeMessage()
{ {
if (this->autoMimeContentCreated)
{
this->autoMimeContentCreated = false;
delete (this->content);
}
} }
/* [1] --- */ /* [1] --- */
@ -46,15 +52,25 @@ MimePart& MimeMessage::getContent() {
} }
void MimeMessage::setContent(MimePart *content) { void MimeMessage::setContent(MimePart *content) {
if (this->autoMimeContentCreated)
{
this->autoMimeContentCreated = false;
delete (this->content);
}
this->content = content; this->content = content;
} }
void MimeMessage::setSender(const EmailAddress &sender) void MimeMessage::setReplyTo(EmailAddress* rto) {
{ replyTo = rto;
this->sender = sender;
} }
void MimeMessage::addRecipient(const EmailAddress &rcpt, RecipientType type) void MimeMessage::setSender(EmailAddress* e)
{
this->sender = e;
e->setParent(this);
}
void MimeMessage::addRecipient(EmailAddress* rcpt, RecipientType type)
{ {
switch (type) switch (type)
{ {
@ -68,25 +84,22 @@ void MimeMessage::addRecipient(const EmailAddress &rcpt, RecipientType type)
recipientsBcc << rcpt; recipientsBcc << rcpt;
break; break;
} }
rcpt->setParent(this);
} }
void MimeMessage::addTo(const EmailAddress &rcpt) { void MimeMessage::addTo(EmailAddress* rcpt) {
this->recipientsTo << rcpt; this->recipientsTo << rcpt;
} }
void MimeMessage::addCc(const EmailAddress &rcpt) { void MimeMessage::addCc(EmailAddress* rcpt) {
this->recipientsCc << rcpt; this->recipientsCc << rcpt;
} }
void MimeMessage::addBcc(const EmailAddress &rcpt) { void MimeMessage::addBcc(EmailAddress* rcpt) {
this->recipientsBcc << rcpt; this->recipientsBcc << rcpt;
} }
void MimeMessage::addCustomHeader(const QString &header)
{
this->customHeaders << header;
}
void MimeMessage::setSubject(const QString & subject) void MimeMessage::setSubject(const QString & subject)
{ {
this->subject = subject; this->subject = subject;
@ -99,17 +112,22 @@ void MimeMessage::addPart(MimePart *part)
}; };
} }
void MimeMessage::setInReplyTo(const QString& inReplyTo)
{
mInReplyTo = inReplyTo;
}
void MimeMessage::setHeaderEncoding(MimePart::Encoding hEnc) void MimeMessage::setHeaderEncoding(MimePart::Encoding hEnc)
{ {
this->hEncoding = hEnc; this->hEncoding = hEnc;
} }
EmailAddress MimeMessage::getSender() const const EmailAddress & MimeMessage::getSender() const
{ {
return sender; return *sender;
} }
const QList<EmailAddress> & MimeMessage::getRecipients(RecipientType type) const const QList<EmailAddress*> & MimeMessage::getRecipients(RecipientType type) const
{ {
switch (type) switch (type)
{ {
@ -123,7 +141,11 @@ const QList<EmailAddress> & MimeMessage::getRecipients(RecipientType type) const
} }
} }
QString MimeMessage::getSubject() const const EmailAddress* MimeMessage::getReplyTo() const {
return replyTo;
}
const QString & MimeMessage::getSubject() const
{ {
return subject; return subject;
} }
@ -145,88 +167,149 @@ const QList<MimePart*> & MimeMessage::getParts() const
/* [3] Public Methods */ /* [3] Public Methods */
QString MimeMessage::toString() const QString MimeMessage::toString()
{ {
QBuffer out; QString mime;
out.open(QIODevice::WriteOnly);
writeToDevice(out);
return QString(out.buffer());
}
QByteArray MimeMessage::formatAddress(const EmailAddress &address, MimePart::Encoding encoding) {
QByteArray result;
result.append(format(address.getName(), encoding));
result.append(" <" + address.getAddress() + ">");
return result;
}
QByteArray MimeMessage::format(const QString &text, MimePart::Encoding encoding)
{
QByteArray result;
if (!text.isEmpty())
{
switch (encoding)
{
case MimePart::Base64:
result.append(" =?utf-8?B?" + text.toUtf8().toBase64() + "?=");
break;
case MimePart::QuotedPrintable:
result.append(" =?utf-8?Q?" + QuotedPrintable::encode(text.toUtf8()).toLocal8Bit().replace(' ', "_").replace(':',"=3A") + "?=");
break;
default:
result.append(" ").append(text.toLocal8Bit());
}
}
return result;
}
void MimeMessage::writeToDevice(QIODevice &out) const {
/* =========== MIME HEADER ============ */ /* =========== MIME HEADER ============ */
/* ---------- Sender / From ----------- */ /* ---------- Sender / From ----------- */
QByteArray header; mime = "From:";
header.append("From:" + formatAddress(sender, hEncoding) + "\r\n"); if (sender->getName() != "")
{
switch (hEncoding)
{
case MimePart::Base64:
mime += " =?utf-8?B?" + QByteArray().append(sender->getName()).toBase64() + "?=";
break;
case MimePart::QuotedPrintable:
mime += " =?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append(sender->getName())).replace(' ', "_").replace(':',"=3A") + "?=";
break;
default:
mime += " " + sender->getName();
}
}
mime += " <" + sender->getAddress() + ">\r\n";
/* ---------------------------------- */ /* ---------------------------------- */
/* ------- Recipients / To ---------- */ /* ------- Recipients / To ---------- */
header.append("To:"); mime += "To:";
for (int i = 0; i<recipientsTo.size(); ++i) QList<EmailAddress*>::iterator it; int i;
for (i = 0, it = recipientsTo.begin(); it != recipientsTo.end(); ++it, ++i)
{ {
if (i != 0) { header.append(","); } if (i != 0) { mime += ","; }
header.append(formatAddress(recipientsTo.at(i), hEncoding));
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() + ">";
} }
header.append("\r\n"); mime += "\r\n";
/* ---------------------------------- */ /* ---------------------------------- */
/* ------- Recipients / Cc ---------- */ /* ------- Recipients / Cc ---------- */
if (recipientsCc.size() != 0) { if (recipientsCc.size() != 0) {
header.append("Cc:"); mime += "Cc:";
} }
for (int i = 0; i<recipientsCc.size(); ++i) for (i = 0, it = recipientsCc.begin(); it != recipientsCc.end(); ++it, ++i)
{ {
if (i != 0) { header.append(","); } if (i != 0) { mime += ","; }
header.append(formatAddress(recipientsCc.at(i), hEncoding));
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() + ">";
} }
if (recipientsCc.size() != 0) { if (recipientsCc.size() != 0) {
header.append("\r\n"); mime += "\r\n";
} }
/* ---------------------------------- */ /* ---------------------------------- */
/* ------------ Subject ------------- */ /* ------------ Subject ------------- */
header.append("Subject: "); mime += "Subject: ";
header.append(format(subject, hEncoding));
header.append("\r\n");
switch (hEncoding)
{
case MimePart::Base64:
mime += "=?utf-8?B?" + QByteArray().append(subject).toBase64() + "?=";
break;
case MimePart::QuotedPrintable:
mime += "=?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append(subject)).replace(' ', "_").replace(':',"=3A") + "?=";
break;
default:
mime += subject;
}
mime += "\r\n";
/* ---------------------------------- */ /* ---------------------------------- */
foreach (QString hdr, customHeaders) { /* ---------- Reply-To -------------- */
header.append(hdr.toLocal8Bit()); if (replyTo) {
header.append("\r\n"); mime += "Reply-To: ";
if (replyTo->getName() != "")
{
switch (hEncoding)
{
case MimePart::Base64:
mime += " =?utf-8?B?" + QByteArray().append(replyTo->getName()).toBase64() + "?=";
break;
case MimePart::QuotedPrintable:
mime += " =?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append(replyTo->getName())).replace(' ', "_").replace(':',"=3A") + "?=";
break;
default:
mime += " " + replyTo->getName();
}
}
mime += " <" + replyTo->getAddress() + ">\r\n";
} }
header.append("MIME-Version: 1.0\r\n"); /* ---------------------------------- */
out.write(header); mime += "MIME-Version: 1.0\r\n";
content->writeToDevice(out); if (!mInReplyTo.isEmpty())
{
mime += "In-Reply-To: <" + mInReplyTo + ">\r\n";
mime += "References: <" + mInReplyTo + ">\r\n";
}
QDateTime now = QDateTime::currentDateTime();
#if QT_VERSION_MAJOR < 5 //Qt4 workaround since RFC2822Date isn't defined
QString shortDayName = QLocale::c().dayName(now.date().dayOfWeek(), QLocale::ShortFormat);
QString shortMonthName = QLocale::c().monthName(now.date().month(), QLocale::ShortFormat);
int utcOffset = now.secsTo(QDateTime(now.date(), now.time(), Qt::UTC)) / 60;
char timezoneSign = utcOffset >= 0 ? '+' : '-';
utcOffset = utcOffset >= 0 ? utcOffset : -utcOffset;
QString timezone = QString("%1%2%3").arg(timezoneSign).arg(utcOffset / 60, 2, 10, QChar('0')).arg(utcOffset % 60, 2, 10, QChar('0'));
mime += QString("Date: %1\r\n").arg(now.toString("%1, dd %2 yyyy hh:mm:ss %3").arg(shortDayName).arg(shortMonthName).arg(timezone));
#else //Qt5 supported
mime += QString("Date: %1\r\n").arg(now.toString(Qt::RFC2822Date));
#endif //support RFC2822Date
mime += content->toString();
return mime;
} }
/* [3] --- */ /* [3] --- */

View File

@ -19,15 +19,14 @@
#ifndef MIMEMESSAGE_H #ifndef MIMEMESSAGE_H
#define MIMEMESSAGE_H #define MIMEMESSAGE_H
#include <QStringList>
#include <QTextStream>
#include "smtpmime_global.h"
#include "mimepart.h" #include "mimepart.h"
#include "mimemultipart.h" #include "mimemultipart.h"
#include "emailaddress.h" #include "emailaddress.h"
#include <QList>
class SMTP_MIME_EXPORT MimeMessage : public QObject #include "smtpexports.h"
class SMTP_EXPORT MimeMessage : public QObject
{ {
public: public:
@ -39,7 +38,7 @@ public:
/* [1] Constructors and Destructors */ /* [1] Constructors and Destructors */
MimeMessage(bool createAutoMimeContent = true); MimeMessage(bool createAutoMimeConent = true);
~MimeMessage(); ~MimeMessage();
/* [1] --- */ /* [1] --- */
@ -47,22 +46,24 @@ public:
/* [2] Getters and Setters */ /* [2] Getters and Setters */
void setSender(const EmailAddress &sndr); void setSender(EmailAddress* e);
void addRecipient(const EmailAddress &rcpt, RecipientType type = To); void addRecipient(EmailAddress* rcpt, RecipientType type = To);
void addTo(const EmailAddress &rcpt); void addTo(EmailAddress* rcpt);
void addCc(const EmailAddress &rcpt); void addCc(EmailAddress* rcpt);
void addBcc(const EmailAddress &rcpt); void addBcc(EmailAddress* rcpt);
void addCustomHeader(const QString &hdr); void setSubject(const QString & subject);
void setSubject(const QString &subject);
void addPart(MimePart* part); void addPart(MimePart* part);
void setReplyTo(EmailAddress* rto);
void setInReplyTo(const QString& inReplyTo);
void setHeaderEncoding(MimePart::Encoding); void setHeaderEncoding(MimePart::Encoding);
EmailAddress getSender() const; const EmailAddress & getSender() const;
const QList<EmailAddress> &getRecipients(RecipientType type = To) const; const QList<EmailAddress*> & getRecipients(RecipientType type = To) const;
QString getSubject() const; const QString & getSubject() const;
const QStringList &getCustomHeaders() const;
const QList<MimePart*> & getParts() const; const QList<MimePart*> & getParts() const;
const EmailAddress* getReplyTo() const;
MimePart& getContent(); MimePart& getContent();
void setContent(MimePart *content); void setContent(MimePart *content);
@ -71,8 +72,7 @@ public:
/* [3] Public methods */ /* [3] Public methods */
virtual QString toString() const; virtual QString toString();
void writeToDevice(QIODevice &device) const;
/* [3] --- */ /* [3] --- */
@ -80,17 +80,16 @@ protected:
/* [4] Protected members */ /* [4] Protected members */
EmailAddress sender; EmailAddress* sender;
QList<EmailAddress> recipientsTo, recipientsCc, recipientsBcc; EmailAddress* replyTo;
QList<EmailAddress*> recipientsTo, recipientsCc, recipientsBcc;
QString subject; QString subject;
QStringList customHeaders; QString mInReplyTo;
MimePart *content; MimePart *content;
bool autoMimeContentCreated;
MimePart::Encoding hEncoding; MimePart::Encoding hEncoding;
static QByteArray format(const QString &text, MimePart::Encoding encoding);
static QByteArray formatAddress(const EmailAddress &address, MimePart::Encoding encoding);
/* [4] --- */ /* [4] --- */

View File

@ -17,7 +17,6 @@
*/ */
#include "mimemultipart.h" #include "mimemultipart.h"
#include <QIODevice>
#include <QTime> #include <QTime>
#include <QCryptographicHash> #include <QCryptographicHash>
@ -43,9 +42,7 @@ MimeMultiPart::MimeMultiPart(MultiPartType type)
} }
MimeMultiPart::~MimeMultiPart() { MimeMultiPart::~MimeMultiPart() {
foreach (MimePart *part, parts) {
delete part;
}
} }
void MimeMultiPart::addPart(MimePart *part) { void MimeMultiPart::addPart(MimePart *part) {
@ -56,21 +53,20 @@ const QList<MimePart*> & MimeMultiPart::getParts() const {
return parts; return parts;
} }
void MimeMultiPart::writeContent(QIODevice &device) const { void MimeMultiPart::prepare() {
QList<MimePart*>::const_iterator it; QList<MimePart*>::iterator it;
for (it = parts.constBegin(); it != parts.constEnd(); it++) { content = "";
device.write("--" ); for (it = parts.begin(); it != parts.end(); it++) {
device.write(cBoundary.toLatin1()); content += "--" + cBoundary + "\r\n";
device.write("\r\n"); (*it)->prepare();
(*it)->writeToDevice(device); content += (*it)->toString();
}; };
device.write("--"); content += "--" + cBoundary + "--\r\n";
device.write(cBoundary.toLatin1());
device.write("--\r\n");
}
MimePart::prepare();
}
void MimeMultiPart::setMimeType(const MultiPartType type) { void MimeMultiPart::setMimeType(const MultiPartType type) {
this->type = type; this->type = type;

View File

@ -19,12 +19,13 @@
#ifndef MIMEMULTIPART_H #ifndef MIMEMULTIPART_H
#define MIMEMULTIPART_H #define MIMEMULTIPART_H
#include <QList>
#include "smtpmime_global.h"
#include "mimepart.h" #include "mimepart.h"
class SMTP_MIME_EXPORT MimeMultiPart : public MimePart #include "smtpexports.h"
class SMTP_EXPORT MimeMultiPart : public MimePart
{ {
Q_OBJECT
public: public:
/* [0] Enums */ /* [0] Enums */
@ -60,7 +61,7 @@ public:
void addPart(MimePart *part); void addPart(MimePart *part);
void writeContent(QIODevice &device) const; virtual void prepare();
/* [3] --- */ /* [3] --- */

View File

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

View File

@ -19,14 +19,14 @@
#ifndef MIMEPART_H #ifndef MIMEPART_H
#define MIMEPART_H #define MIMEPART_H
#include "smtpmime_global.h" #include <QObject>
#include <QByteArray> #include "mimecontentformatter.h"
#include <QString>
class QIODevice; #include "smtpexports.h"
class SMTP_MIME_EXPORT MimePart class SMTP_EXPORT MimePart : public QObject
{ {
Q_OBJECT
public: public:
/* [0] Enumerations */ /* [0] Enumerations */
@ -44,54 +44,56 @@ public:
/* [1] Constructors and Destructors */ /* [1] Constructors and Destructors */
MimePart(); MimePart();
virtual ~MimePart(); ~MimePart();
/* [1] --- */ /* [1] --- */
/* [2] Getters and Setters */ /* [2] Getters and Setters */
void setContent(const QByteArray & content); const QString& getHeader() const;
QByteArray getContent() const; const QByteArray& getContent() const;
void setHeader(const QString & headerLines); void setContent(const QByteArray & content);
QString getHeader() const; void setHeader(const QString & header);
void addHeaderLine(const QString & line); void addHeaderLine(const QString & line);
void setContentId(const QString & cId); void setContentId(const QString & cId);
QString getContentId() const; const QString & getContentId() const;
void setContentName(const QString & cName); void setContentName(const QString & cName);
QString getContentName() const; const QString & getContentName() const;
void setContentType(const QString & cType); void setContentType(const QString & cType);
QString getContentType() const; const QString & getContentType() const;
void setCharset(const QString & charset); void setCharset(const QString & charset);
QString getCharset() const; const QString & getCharset() const;
void setEncoding(Encoding enc); void setEncoding(Encoding enc);
Encoding getEncoding() const; Encoding getEncoding() const;
void setMaxLineLength(const int length); MimeContentFormatter& getContentFormatter();
int getMaxLineLength() const;
/* [2] --- */ /* [2] --- */
/* [3] Public methods */ /* [3] Public methods */
virtual QString toString() const; virtual QString toString();
void writeToDevice(QIODevice &device) const;
virtual void prepare();
/* [3] --- */ /* [3] --- */
protected: protected:
/* [4] Protected members */ /* [4] Protected members */
QString headerLines; QString header;
QByteArray content; QByteArray content;
QString cId; QString cId;
@ -101,15 +103,12 @@ protected:
QString cBoundary; QString cBoundary;
Encoding cEncoding; Encoding cEncoding;
int maxLineLength;
QString mimeString; QString mimeString;
bool prepared; bool prepared;
/* [4] --- */ MimeContentFormatter formatter;
virtual void writeContent(QIODevice &device) const; /* [4] --- */
void writeContent(QIODevice &device, const QByteArray &content) const;
}; };
#endif // MIMEPART_H #endif // MIMEPART_H

View File

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

View File

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

View File

@ -1,29 +0,0 @@
#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;
}

View File

@ -1,15 +0,0 @@
#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,8 +50,13 @@ const QString & MimeText::getText() const
/* [3] Protected Methods */ /* [3] Protected Methods */
void MimeText::writeContent(QIODevice &device) const { void MimeText::prepare()
MimePart::writeContent(device, text.toLocal8Bit()); {
this->content.clear();
this->content.append(text);
/* !!! IMPORTANT !!! */
MimePart::prepare();
} }
/* [3] --- */ /* [3] --- */

View File

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

View File

@ -20,19 +20,24 @@
QString QuotedPrintable::encode(const QByteArray &input) QString QuotedPrintable::encode(const QByteArray &input)
{ {
static const char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
QString output; QString output;
char byte;
const char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
for (int i = 0; i < input.length() ; ++i) for (int i = 0; i < input.length() ; ++i)
{ {
const char byte = input[i]; byte = input[i];
if ((byte == 0x20) || ((byte >= 33) && (byte <= 126) && (byte != 61))) { if ((byte == 0x20) || ((byte >= 33) && (byte <= 126) && (byte != 61)))
{
output.append(byte); output.append(byte);
} }
else { else
output.append('=').append(hex[((byte >> 4) & 0x0F)]).append(hex[(byte & 0x0F)]); {
output.append('=');
output.append(hex[((byte >> 4) & 0x0F)]);
output.append(hex[(byte & 0x0F)]);
} }
} }
@ -42,26 +47,16 @@ QString QuotedPrintable::encode(const QByteArray &input)
QByteArray QuotedPrintable::decode(const QString &input) QByteArray QuotedPrintable::decode(const QString &input)
{ {
// 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F
static const int hexVal[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15}; const int hexVal[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15};
QByteArray output; QByteArray output;
int len = input.length(); for (int i = 0; i < input.length(); ++i)
int i;
for (i = 0; i < len-2; ++i)
{ {
if (input.at(i).toLatin1() == '=') if (input.at(i).toLatin1() == '=')
{ {
int x = input.at(i+1).toLatin1() - '0'; output.append((hexVal[input.at(i + 1).toLatin1() - '0'] << 4) + hexVal[input.at(i + 2).toLatin1() - '0']);
int y = input.at(i+2).toLatin1() - '0';
if (x >= 0 && y >= 0 && x < 23 && y < 23) {
output.append(char((hexVal[x] << 4) + hexVal[y]));
}
else {
output.append('=').append(char(x + '0')).append(char(y + '0'));
}
i += 2; i += 2;
} }
else else
@ -70,10 +65,5 @@ QByteArray QuotedPrintable::decode(const QString &input)
} }
} }
while (i<len) {
output.append(input.at(i).toLatin1());
++i;
}
return output; return output;
} }

View File

@ -19,13 +19,21 @@
#ifndef QUOTEDPRINTABLE_H #ifndef QUOTEDPRINTABLE_H
#define QUOTEDPRINTABLE_H #define QUOTEDPRINTABLE_H
#include <QObject>
#include <QByteArray> #include <QByteArray>
#include <QString>
#include "smtpmime_global.h"
namespace QuotedPrintable { #include "smtpexports.h"
SMTP_MIME_EXPORT QString encode(const QByteArray &input);
SMTP_MIME_EXPORT QByteArray decode(const QString &input); class SMTP_EXPORT QuotedPrintable : public QObject
} {
Q_OBJECT
public:
static QString encode(const QByteArray &input);
static QByteArray decode(const QString &input);
private:
QuotedPrintable();
};
#endif // QUOTEDPRINTABLE_H #endif // QUOTEDPRINTABLE_H

View File

@ -20,24 +20,23 @@
#include <QFileInfo> #include <QFileInfo>
#include <QByteArray> #include <QByteArray>
#include <QTimer>
#include <QEventLoop>
#include <QMetaEnum>
/* [1] Constructors and destructors */ /* [1] Constructors and destructors */
SmtpClient::SmtpClient(const QString & host, int port, ConnectionType connectionType) : SmtpClient::SmtpClient(const QString & host, int port, ConnectionType connectionType) :
state(UnconnectedState), socket(NULL),
host(host),
port(port),
name("localhost"), name("localhost"),
isReadyConnected(false), authMethod(AuthPlain),
isAuthenticated(false), connectionTimeout(5000),
isMailSent(false), responseTimeout(5000),
isReset(false) sendMessageTimeout(60000)
{ {
setConnectionType(connectionType); setConnectionType(connectionType);
this->host = host;
this->port = port;
connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
this, SLOT(socketStateChanged(QAbstractSocket::SocketState))); this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
@ -46,189 +45,48 @@ SmtpClient::SmtpClient(const QString & host, int port, ConnectionType connection
this, SLOT(socketReadyRead())); this, SLOT(socketReadyRead()));
} }
SmtpClient::~SmtpClient() {} SmtpClient::~SmtpClient() {
if (socket)
delete socket;
}
/* [1] --- */ /* [1] --- */
/* [2] Getters and Setters */ /* [2] Getters and Setters */
/**
* @brief Returns the host name of the server. void SmtpClient::setUser(const QString &user)
*/
QString SmtpClient::getHost() const
{ {
return this->host; this->user = user;
} }
/** void SmtpClient::setPassword(const QString &password)
* @brief Return the port.
*/
int SmtpClient::getPort() const
{ {
return this->port; this->password = password;
} }
/** void SmtpClient::setAuthMethod(AuthMethod method)
* @brief Returns the connection type used.
*/
SmtpClient::ConnectionType SmtpClient::getConnectionType() const
{ {
return connectionType; this->authMethod = method;
} }
/** void SmtpClient::setHost(const QString &host)
* @brief Returns the client's name.
*/
QString SmtpClient::getName() const
{ {
return this->name; this->host = host;
} }
/** void SmtpClient::setPort(int port)
* @brief Sets the client's name. This name is sent by the EHLO command.
*/
void SmtpClient::setName(const QString &name)
{ {
this->name = name; this->port = port;
} }
/**
* @brief Returns the last response of the server.
*/
QString SmtpClient::getResponseText() const
{
return responseText;
}
/**
* @brief Returns the last response code recived by the client.
*/
int SmtpClient::getResponseCode() const
{
return responseCode;
}
/**
* @brief Return the socket used by the client. The type of the of the
* connection is QTcpConnection in case of TcpConnection, and QSslSocket
* for SslConnection and TlsConnection.
*/
QTcpSocket* SmtpClient::getSocket() {
return socket;
}
/* [2] --- */
/* [3] Public methods */
void SmtpClient::connectToHost()
{
if (state != UnconnectedState)
return;
changeState(ConnectingState);
}
void SmtpClient::login()
{
if (!isReadyConnected || isAuthenticated)
return;
changeState(AuthenticatingState);
}
void SmtpClient::login(const QString &user, const QString &password, AuthMethod method)
{
this->authInfo = AuthInfo(user, password, method);
login();
}
void SmtpClient::sendMail(const MimeMessage & email)
{
if (!isReadyConnected)
return;
isMailSent = false;
this->email = &email;
this->rcptType = 0;
changeState(MailSendingState);
}
void SmtpClient::quit()
{
changeState(DisconnectingState);
}
void SmtpClient::reset()
{
if (!isReadyConnected)
return;
isReset = false;
changeState(ResetState);
}
bool SmtpClient::waitForReadyConnected(int msec) {
if (state == UnconnectedState)
return false;
if (isReadyConnected)
return true;
waitForEvent(msec, SIGNAL(readyConnected()));
return isReadyConnected;
}
bool SmtpClient::waitForAuthenticated(int msec) {
if (!isReadyConnected)
return false;
if (isAuthenticated)
return true;
waitForEvent(msec, SIGNAL(authenticated()));
return isAuthenticated;
}
bool SmtpClient::waitForMailSent(int msec) {
if (!isReadyConnected)
return false;
if (isMailSent)
return true;
waitForEvent(msec, SIGNAL(mailSent()));
return isMailSent;
}
bool SmtpClient::waitForReset(int msec)
{
if (!isReadyConnected)
return false;
if (isReset)
return true;
waitForEvent(msec, SIGNAL(mailReset()));
return isReset;
}
/* [3] --- */
/* [4] Protected methods */
void SmtpClient::setConnectionType(ConnectionType ct) void SmtpClient::setConnectionType(ConnectionType ct)
{ {
this->connectionType = ct; this->connectionType = ct;
if (socket)
delete socket;
switch (connectionType) switch (connectionType)
{ {
case TcpConnection: case TcpConnection:
@ -237,338 +95,384 @@ void SmtpClient::setConnectionType(ConnectionType ct)
case SslConnection: case SslConnection:
case TlsConnection: case TlsConnection:
socket = new QSslSocket(this); socket = new QSslSocket(this);
connect(socket, SIGNAL(encrypted()),
this, SLOT(socketEncrypted()));
break;
} }
} }
void SmtpClient::changeState(SmtpClient::ClientState state) { const QString& SmtpClient::getHost() const
this->state = state; {
return this->host;
}
#ifdef QT_NO_DEBUG const QString& SmtpClient::getUser() const
// Emit stateChanged signal only for non-internal states {
if (state <= DisconnectingState) { return this->user;
emit stateChanged(state); }
}
#else
// emit all in debug mode
qDebug() << "[SmtpClient] State:" << staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("ClientState")).valueToKey(state);
emit stateChanged(state);
#endif
switch (state) 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
{
return connectionType;
}
const QString& SmtpClient::getName() const
{
return this->name;
}
void SmtpClient::setName(const QString &name)
{
this->name = name;
}
const QString & SmtpClient::getResponseText() const
{
return responseText;
}
int SmtpClient::getResponseCode() const
{
return responseCode;
}
QTcpSocket* SmtpClient::getSocket() {
return socket;
}
int SmtpClient::getConnectionTimeout() const
{
return connectionTimeout;
}
void SmtpClient::setConnectionTimeout(int msec)
{
connectionTimeout = msec;
}
int SmtpClient::getResponseTimeout() const
{
return responseTimeout;
}
void SmtpClient::setResponseTimeout(int msec)
{
responseTimeout = msec;
}
int SmtpClient::getSendMessageTimeout() const
{
return sendMessageTimeout;
}
void SmtpClient::setSendMessageTimeout(int msec)
{
sendMessageTimeout = msec;
}
/* [2] --- */
/* [3] Public methods */
bool SmtpClient::connectToHost()
{
switch (connectionType)
{ {
case ConnectingState: case TlsConnection:
switch (connectionType) case TcpConnection:
socket->connectToHost(host, port);
break;
case SslConnection:
((QSslSocket*) socket)->connectToHostEncrypted(host, port);
break;
}
// 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)
{ {
case TlsConnection: emit smtpError(ServerError);
case TcpConnection: return false;
socket->connectToHost(host, port);
break;
case SslConnection:
((QSslSocket*) socket)->connectToHostEncrypted(host, port);
break;
} }
break;
case AuthenticatingState: // Send a EHLO/HELO message to the server
isAuthenticated = false; // The client's first command must be EHLO/HELO
changeState(authInfo.authMethod == AuthPlain ? _AUTH_PLAIN_0 : _AUTH_LOGIN_0);
break;
case MailSendingState:
isMailSent = false;
changeState(_MAIL_0_FROM);
break;
case DisconnectingState:
sendMessage("QUIT");
socket->disconnectFromHost();
break;
case ResetState:
sendMessage("RSET");
break;
case _EHLO_State:
// Service ready. Send EHLO message and change the state
sendMessage("EHLO " + name); sendMessage("EHLO " + name);
break;
case _READY_Connected: // Wait for the server's response
isReadyConnected = true; waitForResponse();
changeState(ReadyState);
emit readyConnected();
break;
/* --- TLS --- */ // The response code needs to be 250.
case _TLS_State: if (responseCode != 250) {
changeState(_TLS_0_STARTTLS); emit smtpError(ServerError);
break; return false;
}
case _TLS_0_STARTTLS: if (connectionType == TlsConnection) {
// send a request to start TLS handshake // send a request to start TLS handshake
sendMessage("STARTTLS"); sendMessage("STARTTLS");
break;
case _TLS_1_ENCRYPT: // Wait for the server's response
((QSslSocket*) socket)->startClientEncryption(); waitForResponse();
break;
case _TLS_2_EHLO: // The response code needs to be 220.
// Send EHLO one more time if (responseCode != 220) {
sendMessage("EHLO " + name); emit smtpError(ServerError);
break; return false;
};
case _READY_Encrypted: ((QSslSocket*) socket)->startClientEncryption();
changeState(_READY_Connected);
break;
/* --- AUTH --- */ if (!((QSslSocket*) socket)->waitForEncrypted(connectionTimeout)) {
case _AUTH_PLAIN_0: qDebug() << ((QSslSocket*) socket)->errorString();
// Sending command: AUTH PLAIN base64('\0' + username + '\0' + password) emit smtpError(ConnectionTimeoutError);
sendMessage("AUTH PLAIN " + QByteArray().append((char) 0).append(authInfo.username) return false;
.append((char) 0).append(authInfo.password).toBase64()); }
break;
case _AUTH_LOGIN_0: // Send ELHO one more time
sendMessage("AUTH LOGIN"); sendMessage("EHLO " + name);
break;
case _AUTH_LOGIN_1_USER: // Wait for the server's response
// Send the username in base64 waitForResponse();
sendMessage(QByteArray().append(authInfo.username).toBase64());
break;
case _AUTH_LOGIN_2_PASS: // The response code needs to be 250.
// Send the password in base64 if (responseCode != 250) {
sendMessage(QByteArray().append(authInfo.password).toBase64()); emit smtpError(ServerError);
break; return false;
}
}
}
catch (ResponseTimeoutException)
{
return false;
}
catch (SendMessageTimeoutException)
{
return false;
}
case _READY_Authenticated: // If no errors occured the function returns true.
isAuthenticated = true; return true;
authInfo = AuthInfo(); }
changeState(ReadyState);
emit authenticated();
break;
/* --- MAIL --- */ bool SmtpClient::login()
case _MAIL_0_FROM: {
sendMessage("MAIL FROM:<" + email->getSender().getAddress() + ">"); return login(user, password, authMethod);
break; }
case _MAIL_1_RCPT_INIT: bool SmtpClient::login(const QString &user, const QString &password, AuthMethod method)
rcptType++; {
const QList<EmailAddress> *addressList; try {
switch (rcptType) if (method == AuthPlain)
{ {
case _TO: // Sending command: AUTH PLAIN base64('\0' + username + '\0' + password)
addressList = &email->getRecipients(MimeMessage::To); sendMessage("AUTH PLAIN " + QByteArray().append((char) 0).append(user).append((char) 0).append(password).toBase64());
break;
case _CC:
addressList = &email->getRecipients(MimeMessage::Cc);
break;
case _BCC:
addressList = &email->getRecipients(MimeMessage::Bcc);
break;
default:
changeState(_MAIL_3_DATA);
return;
}
addressIt = addressList->constBegin();
addressItEnd = addressList->constEnd();
changeState(_MAIL_2_RCPT);
break;
case _MAIL_2_RCPT: // Wait for the server's response
if (addressIt != addressItEnd) { waitForResponse();
sendMessage("RCPT TO:<" + addressIt->getAddress() + ">");
addressIt++;
} else {
changeState(_MAIL_1_RCPT_INIT);
}
break;
case _MAIL_3_DATA: // 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)
{
// Responce Timeout exceeded
emit smtpError(AuthenticationFailedError);
return false;
}
catch (SendMessageTimeoutException)
{
// Send 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<EmailAddress*>::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"); sendMessage("DATA");
break; waitForResponse();
case _MAIL_4_SEND_DATA: if (responseCode != 354) return false;
email->writeToDevice(*socket);
#ifndef QT_NO_DEBUG sendMessage(email.toString());
qDebug() << "[Socket] OUT:";
qDebug() << email->toString();
#endif
sendMessage("\r\n.");
break;
case _READY_MailSent: // Send \r\n.\r\n to end the mail data
isMailSent = true; sendMessage(".");
changeState(ReadyState);
emit mailSent();
break;
default: waitForResponse();
;
if (responseCode != 250) return false;
}
catch (ResponseTimeoutException)
{
return false;
}
catch (SendMessageTimeoutException)
{
return false;
}
return true;
}
void SmtpClient::quit()
{
try
{
sendMessage("QUIT");
}
catch(SmtpClient::SendMessageTimeoutException)
{
//Manually close the connection to the smtp server if message "QUIT" wasn't received by the smtp server
if(socket->state() == QAbstractSocket::ConnectedState || socket->state() == QAbstractSocket::ConnectingState || socket->state() == QAbstractSocket::HostLookupState)
socket->disconnectFromHost();
} }
} }
void SmtpClient::processResponse() { /* [3] --- */
switch (state)
{
case ConnectedState:
// Just connected to the server. Wait for 220 (Service ready)
if (responseCode != 220) {
emitError(ServerError);
return;
}
changeState(_EHLO_State);
break;
case ResetState: /* [4] Protected methods */
if (responseCode != 250) {
emitError(ServerError);
return;
}
emit mailReset();
changeState(ReadyState);
break;
case _EHLO_State: void SmtpClient::waitForResponse()
// The response code needs to be 250. {
if (responseCode != 250) { do {
emitError(ServerError); if (!socket->waitForReadyRead(responseTimeout))
return; {
emit smtpError(ResponseTimeoutError);
throw ResponseTimeoutException();
} }
changeState((connectionType != TlsConnection) ? _READY_Connected : _TLS_State); while (socket->canReadLine()) {
break; // Save the server's response
responseText = socket->readLine();
/* --- TLS --- */ // Extract the respose code from the server's responce (first 3 digits)
case _TLS_0_STARTTLS: responseCode = responseText.left(3).toInt();
// The response code needs to be 220.
if (responseCode != 220) { if (responseCode / 100 == 4)
emitError(ServerError); emit smtpError(ServerError);
return;
if (responseCode / 100 == 5)
emit smtpError(ClientError);
if (responseText[3] == ' ') { return; }
} }
changeState(_TLS_1_ENCRYPT); } while (true);
break;
case _TLS_2_EHLO:
// The response code needs to be 250.
if (responseCode != 250) {
emitError(ServerError);
return;
}
changeState(_READY_Encrypted);
break;
/* --- AUTH --- */
case _AUTH_PLAIN_0:
// If the response is not 235 then the authentication was failed
if (responseCode != 235) {
emitError(AuthenticationError);
return;
}
changeState(_READY_Authenticated);
break;
case _AUTH_LOGIN_0:
if (responseCode != 334) {
emitError(AuthenticationError);
return;
}
changeState(_AUTH_LOGIN_1_USER);
break;
case _AUTH_LOGIN_1_USER:
if (responseCode != 334) {
emitError(AuthenticationError);
return;
}
changeState(_AUTH_LOGIN_2_PASS);
break;
case _AUTH_LOGIN_2_PASS:
if (responseCode != 235) {
emitError(AuthenticationError);
return;
}
changeState(_READY_Authenticated);
break;
/* --- MAIL --- */
case _MAIL_0_FROM:
if (responseCode != 250) {
emitError(MailSendingError);
return;
}
changeState(_MAIL_1_RCPT_INIT);
break;
case _MAIL_2_RCPT:
if (responseCode != 250) {
emitError(MailSendingError);
return;
}
changeState(_MAIL_2_RCPT);
break;
case _MAIL_3_DATA:
if (responseCode != 354) {
emitError(MailSendingError);
return;
}
changeState(_MAIL_4_SEND_DATA);
break;
case _MAIL_4_SEND_DATA:
if (responseCode != 250) {
emitError(MailSendingError);
return;
}
changeState(_READY_MailSent);
break;
default:
;
}
} }
void SmtpClient::sendMessage(const QString &text) void SmtpClient::sendMessage(const QString &text)
{ {
#ifndef QT_NO_DEBUG
qDebug() << "[Socket] OUT:" << text;
#endif
socket->flush();
socket->write(text.toUtf8() + "\r\n"); socket->write(text.toUtf8() + "\r\n");
} if (! socket->waitForBytesWritten(sendMessageTimeout))
void SmtpClient::emitError(SmtpClient::SmtpError e)
{
emit error(e);
}
void SmtpClient::waitForEvent(int msec, const char *successSignal)
{
QEventLoop loop;
QObject::connect(this, successSignal, &loop, SLOT(quit()));
QObject::connect(this, SIGNAL(error(SmtpClient::SmtpError)), &loop, SLOT(quit()));
if(msec > 0)
{ {
QTimer timer; emit smtpError(SendDataTimeoutError);
timer.setSingleShot(true); throw SendMessageTimeoutException();
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
timer.start(msec);
} }
loop.exec();
} }
/* [4] --- */ /* [4] --- */
@ -576,79 +480,16 @@ void SmtpClient::waitForEvent(int msec, const char *successSignal)
/* [5] Slots for the socket's signals */ /* [5] Slots for the socket's signals */
void SmtpClient::socketStateChanged(QAbstractSocket::SocketState state) { void SmtpClient::socketStateChanged(QAbstractSocket::SocketState /*state*/)
{
#ifndef QT_NO_DEBUG
qDebug() << "[Socket] State:" << state;
#endif
switch (state)
{
case QAbstractSocket::ConnectedState:
changeState(ConnectedState);
break;
case QAbstractSocket::UnconnectedState:
changeState(UnconnectedState);
break;
default:
;
}
} }
void SmtpClient::socketError(QAbstractSocket::SocketError socketError) { void SmtpClient::socketError(QAbstractSocket::SocketError /*socketError*/)
#ifndef QT_NO_DEBUG {
qDebug() << "[Socket] ERROR:" << socketError;
#else
Q_UNUSED(socketError);
#endif
emit error(SocketError);
} }
void SmtpClient::socketReadyRead() void SmtpClient::socketReadyRead()
{ {
QString responseLine;
while (socket->canReadLine()) {
// Save the server's response
responseLine = socket->readLine();
tempResponse += responseLine;
#ifndef QT_NO_DEBUG
qDebug() << "[Socket] IN: " << responseLine;
#endif
}
// 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();
// Check for server error
if (responseCode / 100 == 4) {
emitError(ServerError);
return;
}
// Check for client error
if (responseCode / 100 == 5) {
emitError(ClientError);
return;
}
processResponse();
}
}
void SmtpClient::socketEncrypted() {
if (state == _TLS_1_ENCRYPT) {
changeState(_TLS_2_EHLO);
}
} }
/* [5] --- */ /* [5] --- */

View File

@ -21,15 +21,13 @@
#include <QObject> #include <QObject>
#include <QtNetwork/QSslSocket> #include <QtNetwork/QSslSocket>
#include <QEventLoop>
#include "smtpmime_global.h"
#include "mimemessage.h" #include "mimemessage.h"
#include "smtpexports.h"
class SMTP_EXPORT SmtpClient : public QObject
class SMTP_MIME_EXPORT SmtpClient : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_ENUMS (AuthMethod SmtpError ConnectionType ClientState)
public: public:
/* [0] Enumerations */ /* [0] Enumerations */
@ -42,60 +40,19 @@ public:
enum SmtpError enum SmtpError
{ {
ConnectionTimeoutError = 0, ConnectionTimeoutError,
ResponseTimeoutError = 1, ResponseTimeoutError,
AuthenticationError = 2, SendDataTimeoutError,
MailSendingError = 3, AuthenticationFailedError,
ServerError = 4, // 4xx smtp error ServerError, // 4xx smtp error
ClientError = 5, // 5xx smtp error ClientError // 5xx smtp error
SocketError = 6
}; };
enum ConnectionType enum ConnectionType
{ {
TcpConnection = 0, TcpConnection,
SslConnection = 1, SslConnection,
TlsConnection = 2 // STARTTLS TlsConnection // STARTTLS
};
enum ClientState {
UnconnectedState = 0,
ConnectingState = 1,
ConnectedState = 2,
ReadyState = 3,
AuthenticatingState = 4,
MailSendingState = 5,
DisconnectingState = 6,
ResetState = 7,
/* Internal States */
_EHLO_State = 50,
_TLS_State = 51,
_READY_Connected = 52,
_READY_Authenticated = 53,
_READY_MailSent = 54,
_READY_Encrypted = 55,
/* Internal Substates */
// TLS
_TLS_0_STARTTLS = 60,
_TLS_1_ENCRYPT = 61,
_TLS_2_EHLO = 62,
// AUTH
_AUTH_PLAIN_0 = 70,
_AUTH_LOGIN_0 = 71,
_AUTH_LOGIN_1_USER = 72,
_AUTH_LOGIN_2_PASS = 73,
// MAIL
_MAIL_0_FROM = 81,
_MAIL_1_RCPT_INIT = 82,
_MAIL_2_RCPT = 83,
_MAIL_3_DATA = 84,
_MAIL_4_SEND_DATA = 85
}; };
/* [0] --- */ /* [0] --- */
@ -112,36 +69,56 @@ public:
/* [2] Getters and Setters */ /* [2] Getters and Setters */
QString getHost() const; const QString& getHost() const;
int getPort() const; void setHost(const QString &host);
ConnectionType getConnectionType() const;
QString getName() const; int getPort() const;
void setPort(int port);
const QString& getName() const;
void setName(const QString &name); void setName(const QString &name);
QString getResponseText() const; ConnectionType getConnectionType() const;
void setConnectionType(ConnectionType ct);
const QString & getUser() const;
void setUser(const QString &user);
const QString & getPassword() const;
void setPassword(const QString &password);
SmtpClient::AuthMethod getAuthMethod() const;
void setAuthMethod(AuthMethod method);
const QString & getResponseText() const;
int getResponseCode() const; int getResponseCode() const;
int getConnectionTimeout() const;
void setConnectionTimeout(int msec);
int getResponseTimeout() const;
void setResponseTimeout(int msec);
int getSendMessageTimeout() const;
void setSendMessageTimeout(int msec);
QTcpSocket* getSocket(); QTcpSocket* getSocket();
/* [2] --- */ /* [2] --- */
/* [3] Public methods */ /* [3] Public methods */
void connectToHost(); bool connectToHost();
void login(const QString &user, const QString &password, AuthMethod method = AuthLogin);
void sendMail(const MimeMessage & email); bool login();
bool login(const QString &user, const QString &password, AuthMethod method = AuthLogin);
bool sendMail(MimeMessage& email);
void quit(); void quit();
void reset();
bool isConnected();
bool isLogged();
bool waitForReadyConnected(int msec = 30000);
bool waitForAuthenticated(int msec = 30000);
bool waitForMailSent(int msec = 30000);
bool waitForReset(int msec = 30000);
/* [3] --- */ /* [3] --- */
@ -149,54 +126,37 @@ protected:
/* [4] Protected members */ /* [4] Protected members */
struct AuthInfo {
QString username;
QString password;
AuthMethod authMethod;
AuthInfo(const QString & username = "", const QString &password = "", AuthMethod authMethod = AuthPlain) :
username(username), password(password), authMethod(authMethod) {}
};
QTcpSocket *socket; QTcpSocket *socket;
ClientState state;
const QString host; QString host;
const int port; int port;
ConnectionType connectionType; ConnectionType connectionType;
QString name; QString name;
AuthInfo authInfo; QString user;
QString password;
AuthMethod authMethod;
int connectionTimeout;
int responseTimeout;
int sendMessageTimeout;
QString responseText; QString responseText;
QString tempResponse;
int responseCode; int responseCode;
bool isReadyConnected;
bool isAuthenticated;
bool isMailSent;
bool isReset;
const MimeMessage *email; class ResponseTimeoutException {};
class SendMessageTimeoutException {};
int rcptType;
enum _RcptType { _TO = 1, _CC = 2, _BCC = 3};
QList<EmailAddress>::const_iterator addressIt;
QList<EmailAddress>::const_iterator addressItEnd;
/* [4] --- */ /* [4] --- */
/* [5] Protected methods */ /* [5] Protected methods */
void login();
void setConnectionType(ConnectionType ct); void waitForResponse();
void changeState(ClientState state);
void processResponse();
void sendMessage(const QString &text); void sendMessage(const QString &text);
void emitError(SmtpClient::SmtpError e);
void waitForEvent(int msec, const char *successSignal);
/* [5] --- */ /* [5] --- */
@ -207,7 +167,6 @@ protected slots:
void socketStateChanged(QAbstractSocket::SocketState state); void socketStateChanged(QAbstractSocket::SocketState state);
void socketError(QAbstractSocket::SocketError error); void socketError(QAbstractSocket::SocketError error);
void socketReadyRead(); void socketReadyRead();
void socketEncrypted();
/* [6] --- */ /* [6] --- */
@ -216,14 +175,7 @@ signals:
/* [7] Signals */ /* [7] Signals */
void error(SmtpClient::SmtpError e); void smtpError(SmtpClient::SmtpError e);
void stateChanged(SmtpClient::ClientState s);
void connected();
void readyConnected();
void authenticated();
void mailSent();
void mailReset();
void disconnected();
/* [7] --- */ /* [7] --- */

12
src/smtpexports.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef SMTPEXPORTS_H
#define SMTPEXPORTS_H
#ifdef SMTP_BUILD
#define SMTP_EXPORT Q_DECL_EXPORT
#elseif SMTP_USE
#define SMTP_EXPORT Q_DECL_IMPORT
#else
#define SMTP_EXPORT
#endif
#endif // SMTPEXPORTS_H

View File

@ -1,10 +0,0 @@
#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

View File

@ -1,10 +0,0 @@
smtp.gmail.com 25 1
smtp.gmail.com 465 2
smtp.gmail.com 587 3
smtp.mail.yahoo.com 25 1
smtp.mail.yahoo.com 465 2
smtp.1and1.com 25 1
smtp.1and1.com 465 2
smtp.1and1.com 587 3
smtp.live.com 25 1
smtp.live.com 587 3

View File

@ -1,55 +0,0 @@
#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() {
}

View File

@ -1,21 +0,0 @@
#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

View File

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

View File

@ -1,28 +0,0 @@
#-------------------------------------------------
#
# Project created by QtCreator 2012-09-22T16:39:45
#
#-------------------------------------------------
QT += testlib
QT -= 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