Merge pull request #1295 from ctrlaltca/servatrice_email_v2
Refactor servatrice email send
This commit is contained in:
commit
c0bb640a37
49 changed files with 2521 additions and 2574 deletions
|
@ -16,18 +16,11 @@ SET(servatrice_SOURCES
|
||||||
src/isl_interface.cpp
|
src/isl_interface.cpp
|
||||||
src/signalhandler.cpp
|
src/signalhandler.cpp
|
||||||
${VERSION_STRING_CPP}
|
${VERSION_STRING_CPP}
|
||||||
src/smtp/emailaddress.cpp
|
src/smtpclient.cpp
|
||||||
src/smtp/mimeattachment.cpp
|
src/smtp/qxthmac.cpp
|
||||||
src/smtp/mimecontentformatter.cpp
|
src/smtp/qxtmailattachment.cpp
|
||||||
src/smtp/mimefile.cpp
|
src/smtp/qxtmailmessage.cpp
|
||||||
src/smtp/mimehtml.cpp
|
src/smtp/qxtsmtp.cpp
|
||||||
src/smtp/mimeinlinefile.cpp
|
|
||||||
src/smtp/mimemessage.cpp
|
|
||||||
src/smtp/mimemultipart.cpp
|
|
||||||
src/smtp/mimepart.cpp
|
|
||||||
src/smtp/mimetext.cpp
|
|
||||||
src/smtp/quotedprintable.cpp
|
|
||||||
src/smtp/smtpclient.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(servatrice_RESOURCES servatrice.qrc)
|
set(servatrice_RESOURCES servatrice.qrc)
|
||||||
|
|
8
servatrice/migrations/servatrice_0001_to_0002.sql
Normal file
8
servatrice/migrations/servatrice_0001_to_0002.sql
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
-- Servatrice db migration from version 1 to version 2
|
||||||
|
|
||||||
|
-- FIX #1281
|
||||||
|
CREATE TABLE IF NOT EXISTS `cockatrice_activation_emails` (
|
||||||
|
`name` varchar(35) NOT NULL
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
UPDATE cockatrice_schema_version SET version=2 WHERE version=1;
|
|
@ -90,11 +90,11 @@ allowpunctuationprefix=false
|
||||||
|
|
||||||
[smtp]
|
[smtp]
|
||||||
|
|
||||||
; Connectin type: currently supported method are "tcp", "ssl" and "tls"
|
; Connectin type: currently supported method are "tcp" and "ssl"; tls is autodetected if available
|
||||||
connection=tcp
|
connection=tcp
|
||||||
|
|
||||||
; Auth type: currently supported method are "plain" and "login"
|
; Accept all certificates: in ssl mode, enable this if your server is using an invalid/self signed certificate
|
||||||
auth=plain
|
acceptallcerts=false;
|
||||||
|
|
||||||
; Hostname or IP addres of the smtp server
|
; Hostname or IP addres of the smtp server
|
||||||
host=localhost
|
host=localhost
|
||||||
|
|
|
@ -205,3 +205,7 @@ CREATE TABLE IF NOT EXISTS `cockatrice_log` (
|
||||||
KEY `target_id` (`target_id`),
|
KEY `target_id` (`target_id`),
|
||||||
KEY `target_name` (`target_name`)
|
KEY `target_name` (`target_name`)
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `cockatrice_activation_emails` (
|
||||||
|
`name` varchar(35) NOT NULL
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "server_logger.h"
|
#include "server_logger.h"
|
||||||
#include "settingscache.h"
|
#include "settingscache.h"
|
||||||
#include "signalhandler.h"
|
#include "signalhandler.h"
|
||||||
|
#include "smtpclient.h"
|
||||||
#include "rng_sfmt.h"
|
#include "rng_sfmt.h"
|
||||||
#include "version_string.h"
|
#include "version_string.h"
|
||||||
#include <google/protobuf/stubs/common.h>
|
#include <google/protobuf/stubs/common.h>
|
||||||
|
@ -38,6 +39,7 @@ ServerLogger *logger;
|
||||||
QThread *loggerThread;
|
QThread *loggerThread;
|
||||||
SettingsCache *settingsCache;
|
SettingsCache *settingsCache;
|
||||||
SignalHandler *signalhandler;
|
SignalHandler *signalhandler;
|
||||||
|
SmtpClient *smtpClient;
|
||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
|
|
||||||
|
@ -181,6 +183,8 @@ int main(int argc, char *argv[])
|
||||||
testRNG();
|
testRNG();
|
||||||
if (testHashFunction)
|
if (testHashFunction)
|
||||||
testHash();
|
testHash();
|
||||||
|
|
||||||
|
smtpClient = new SmtpClient();
|
||||||
|
|
||||||
Servatrice *server = new Servatrice();
|
Servatrice *server = new Servatrice();
|
||||||
QObject::connect(server, SIGNAL(destroyed()), &app, SLOT(quit()), Qt::QueuedConnection);
|
QObject::connect(server, SIGNAL(destroyed()), &app, SLOT(quit()), Qt::QueuedConnection);
|
||||||
|
@ -200,6 +204,7 @@ int main(int argc, char *argv[])
|
||||||
std::cerr << "-------------------------" << std::endl;
|
std::cerr << "-------------------------" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete smtpClient;
|
||||||
delete rng;
|
delete rng;
|
||||||
delete signalhandler;
|
delete signalhandler;
|
||||||
delete settingsCache;
|
delete settingsCache;
|
||||||
|
|
|
@ -4,9 +4,11 @@
|
||||||
class ServerLogger;
|
class ServerLogger;
|
||||||
class QThread;
|
class QThread;
|
||||||
class SettingsCache;
|
class SettingsCache;
|
||||||
|
class SmtpClient;
|
||||||
|
|
||||||
extern ServerLogger *logger;
|
extern ServerLogger *logger;
|
||||||
extern QThread *loggerThread;
|
extern QThread *loggerThread;
|
||||||
extern SettingsCache *settingsCache;
|
extern SettingsCache *settingsCache;
|
||||||
|
extern SmtpClient *smtpClient;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "server_logger.h"
|
#include "server_logger.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "decklist.h"
|
#include "decklist.h"
|
||||||
|
#include "smtpclient.h"
|
||||||
#include "pb/event_server_message.pb.h"
|
#include "pb/event_server_message.pb.h"
|
||||||
#include "pb/event_server_shutdown.pb.h"
|
#include "pb/event_server_shutdown.pb.h"
|
||||||
#include "pb/event_connection_closed.pb.h"
|
#include "pb/event_connection_closed.pb.h"
|
||||||
|
@ -473,6 +474,32 @@ void Servatrice::statusUpdate()
|
||||||
query->bindValue(":tx", tx);
|
query->bindValue(":tx", tx);
|
||||||
query->bindValue(":rx", rx);
|
query->bindValue(":rx", rx);
|
||||||
servatriceDatabaseInterface->execSqlQuery(query);
|
servatriceDatabaseInterface->execSqlQuery(query);
|
||||||
|
|
||||||
|
// send activation emails
|
||||||
|
bool registrationEnabled = settingsCache->value("registration/enabled", false).toBool();
|
||||||
|
bool requireEmailForRegistration = settingsCache->value("registration/requireemail", true).toBool();
|
||||||
|
if (registrationEnabled && requireEmailForRegistration)
|
||||||
|
{
|
||||||
|
QSqlQuery *query = servatriceDatabaseInterface->prepareQuery("select a.name, b.email, b.token from {prefix}_activation_emails a left join {prefix}_users b on a.name = b.name");
|
||||||
|
if (!servatriceDatabaseInterface->execSqlQuery(query))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QSqlQuery *queryDelete = servatriceDatabaseInterface->prepareQuery("delete from {prefix}_activation_emails where name = :name");
|
||||||
|
|
||||||
|
while (query->next()) {
|
||||||
|
const QString userName = query->value(0).toString();
|
||||||
|
const QString emailAddress = query->value(1).toString();
|
||||||
|
const QString token = query->value(2).toString();
|
||||||
|
|
||||||
|
if(smtpClient->enqueueActivationTokenMail(userName, emailAddress, token))
|
||||||
|
{
|
||||||
|
queryDelete->bindValue(":name", userName);
|
||||||
|
servatriceDatabaseInterface->execSqlQuery(queryDelete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
smtpClient->sendAllEmails();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Servatrice::scheduleShutdown(const QString &reason, int minutes)
|
void Servatrice::scheduleShutdown(const QString &reason, int minutes)
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "server_database_interface.h"
|
#include "server_database_interface.h"
|
||||||
|
|
||||||
#define DATABASE_SCHEMA_VERSION 1
|
#define DATABASE_SCHEMA_VERSION 2
|
||||||
|
|
||||||
class Servatrice;
|
class Servatrice;
|
||||||
|
|
||||||
|
|
|
@ -59,8 +59,6 @@
|
||||||
#include "pb/serverinfo_user.pb.h"
|
#include "pb/serverinfo_user.pb.h"
|
||||||
#include "pb/serverinfo_deckstorage.pb.h"
|
#include "pb/serverinfo_deckstorage.pb.h"
|
||||||
|
|
||||||
#include "smtp/SmtpMime"
|
|
||||||
|
|
||||||
#include "version_string.h"
|
#include "version_string.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -854,8 +852,11 @@ Response::ResponseCode ServerSocketInterface::cmdRegisterAccount(const Command_R
|
||||||
qDebug() << "Accepted register command for user: " << userName;
|
qDebug() << "Accepted register command for user: " << userName;
|
||||||
if(requireEmailForRegistration)
|
if(requireEmailForRegistration)
|
||||||
{
|
{
|
||||||
// TODO call a slot on another thread to send email
|
QSqlQuery *query = sqlInterface->prepareQuery("insert into {prefix}_activation_emails (name) values(:name)");
|
||||||
sendActivationTokenMail(userName, emailAddress, token);
|
query->bindValue(":name", userName);
|
||||||
|
if (!sqlInterface->execSqlQuery(query))
|
||||||
|
return Response::RespRegistrationFailed;
|
||||||
|
|
||||||
return Response::RespRegistrationAcceptedNeedsActivation;
|
return Response::RespRegistrationAcceptedNeedsActivation;
|
||||||
} else {
|
} else {
|
||||||
return Response::RespRegistrationAccepted;
|
return Response::RespRegistrationAccepted;
|
||||||
|
@ -865,88 +866,6 @@ Response::ResponseCode ServerSocketInterface::cmdRegisterAccount(const Command_R
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ServerSocketInterface::sendActivationTokenMail(const QString &nickname, const QString &recipient, const QString &token)
|
|
||||||
{
|
|
||||||
QString tmp = settingsCache->value("smtp/connection", "tcp").toString();
|
|
||||||
SmtpClient::ConnectionType connection = SmtpClient::TcpConnection;
|
|
||||||
if(tmp == "ssl")
|
|
||||||
connection = SmtpClient::SslConnection;
|
|
||||||
else if(tmp == "tls")
|
|
||||||
connection = SmtpClient::TlsConnection;
|
|
||||||
|
|
||||||
tmp = settingsCache->value("smtp/auth", "plain").toString();
|
|
||||||
SmtpClient::AuthMethod auth = SmtpClient::AuthPlain;
|
|
||||||
if(tmp == "login")
|
|
||||||
auth = SmtpClient::AuthLogin;
|
|
||||||
|
|
||||||
QString host = settingsCache->value("smtp/host", "localhost").toString();
|
|
||||||
int port = settingsCache->value("smtp/port", 25).toInt();
|
|
||||||
QString username = settingsCache->value("smtp/username", "").toString();
|
|
||||||
QString password = settingsCache->value("smtp/password", "").toString();
|
|
||||||
QString email = settingsCache->value("smtp/email", "").toString();
|
|
||||||
QString name = settingsCache->value("smtp/name", "").toString();
|
|
||||||
QString subject = settingsCache->value("smtp/subject", "").toString();
|
|
||||||
QString body = settingsCache->value("smtp/body", "").toString();
|
|
||||||
|
|
||||||
if(email.isEmpty())
|
|
||||||
{
|
|
||||||
qDebug() << "[MAIL] Missing email field" << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(body.isEmpty())
|
|
||||||
{
|
|
||||||
qDebug() << "[MAIL] Missing body field" << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(recipient.isEmpty())
|
|
||||||
{
|
|
||||||
qDebug() << "[MAIL] Missing recipient field" << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(token.isEmpty())
|
|
||||||
{
|
|
||||||
qDebug() << "[MAIL] Missing token field" << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SmtpClient smtp(host, port, connection);
|
|
||||||
smtp.setUser(username);
|
|
||||||
smtp.setPassword(password);
|
|
||||||
smtp.setAuthMethod(auth);
|
|
||||||
|
|
||||||
MimeMessage message;
|
|
||||||
EmailAddress sender(email, name);
|
|
||||||
message.setSender(&sender);
|
|
||||||
EmailAddress to(recipient, nickname);
|
|
||||||
message.addRecipient(&to);
|
|
||||||
message.setSubject(subject);
|
|
||||||
|
|
||||||
MimeText text;
|
|
||||||
text.setText(body.replace("%username", nickname).replace("%token", token));
|
|
||||||
message.addPart(&text);
|
|
||||||
|
|
||||||
// Now we can send the mail
|
|
||||||
|
|
||||||
if (!smtp.connectToHost()) {
|
|
||||||
qDebug() << "[MAIL] Failed to connect to host" << host << "on port" << port;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!smtp.login()) {
|
|
||||||
qDebug() << "[MAIL] Failed to login as " << username;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!smtp.sendMail(message)) {
|
|
||||||
qDebug() << "[MAIL] Failed to send mail to " << recipient;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
smtp.quit();
|
|
||||||
qDebug() << "[MAIL] Sent activation email to " << recipient << " for nickname " << nickname;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServerSocketInterface::tooManyRegistrationAttempts(const QString &ipAddress)
|
bool ServerSocketInterface::tooManyRegistrationAttempts(const QString &ipAddress)
|
||||||
{
|
{
|
||||||
// TODO: implement
|
// TODO: implement
|
||||||
|
|
|
@ -108,8 +108,6 @@ private:
|
||||||
Response::ResponseCode cmdAccountEdit(const Command_AccountEdit &cmd, ResponseContainer &rc);
|
Response::ResponseCode cmdAccountEdit(const Command_AccountEdit &cmd, ResponseContainer &rc);
|
||||||
Response::ResponseCode cmdAccountImage(const Command_AccountImage &cmd, ResponseContainer &rc);
|
Response::ResponseCode cmdAccountImage(const Command_AccountImage &cmd, ResponseContainer &rc);
|
||||||
Response::ResponseCode cmdAccountPassword(const Command_AccountPassword &cmd, ResponseContainer &rc);
|
Response::ResponseCode cmdAccountPassword(const Command_AccountPassword &cmd, ResponseContainer &rc);
|
||||||
|
|
||||||
bool sendActivationTokenMail(const QString &nickname, const QString &recipient, const QString &token);
|
|
||||||
public:
|
public:
|
||||||
ServerSocketInterface(Servatrice *_server, Servatrice_DatabaseInterface *_databaseInterface, QObject *parent = 0);
|
ServerSocketInterface(Servatrice *_server, Servatrice_DatabaseInterface *_databaseInterface, QObject *parent = 0);
|
||||||
~ServerSocketInterface();
|
~ServerSocketInterface();
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
/*
|
|
||||||
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 SMTPMIME_H
|
|
||||||
#define SMTPMIME_H
|
|
||||||
|
|
||||||
#include "smtpclient.h"
|
|
||||||
#include "mimepart.h"
|
|
||||||
#include "mimehtml.h"
|
|
||||||
#include "mimeattachment.h"
|
|
||||||
#include "mimemessage.h"
|
|
||||||
#include "mimetext.h"
|
|
||||||
#include "mimeinlinefile.h"
|
|
||||||
#include "mimefile.h"
|
|
||||||
|
|
||||||
#endif // SMTPMIME_H
|
|
|
@ -1,60 +0,0 @@
|
||||||
/*
|
|
||||||
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 "emailaddress.h"
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
|
|
||||||
EmailAddress::EmailAddress(const QString & address, const QString & name)
|
|
||||||
{
|
|
||||||
this->address = address;
|
|
||||||
this->name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
EmailAddress::~EmailAddress()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Getters and Setters */
|
|
||||||
|
|
||||||
void EmailAddress::setName(const QString & name)
|
|
||||||
{
|
|
||||||
this->name = name;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmailAddress::setAddress(const QString & address)
|
|
||||||
{
|
|
||||||
this->address = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString & EmailAddress::getName() const
|
|
||||||
{
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString & EmailAddress::getAddress() const
|
|
||||||
{
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
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 EMAILADDRESS_H
|
|
||||||
#define EMAILADDRESS_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
#include "smtpexports.h"
|
|
||||||
|
|
||||||
class SMTP_EXPORT EmailAddress : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
|
|
||||||
EmailAddress();
|
|
||||||
EmailAddress(const QString & address, const QString & name="");
|
|
||||||
|
|
||||||
~EmailAddress();
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Getters and Setters */
|
|
||||||
void setName(const QString & name);
|
|
||||||
void setAddress(const QString & address);
|
|
||||||
|
|
||||||
const QString & getName() const;
|
|
||||||
const QString & getAddress() const;
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
/* [3] Private members */
|
|
||||||
|
|
||||||
QString name;
|
|
||||||
QString address;
|
|
||||||
|
|
||||||
/* [3] --- */
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // EMAILADDRESS_H
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
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 "mimeattachment.h"
|
|
||||||
#include <QFileInfo>
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
|
|
||||||
MimeAttachment::MimeAttachment(QFile *file)
|
|
||||||
: MimeFile(file)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
MimeAttachment::MimeAttachment(const QByteArray& stream, const QString& fileName): MimeFile(stream, fileName)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
MimeAttachment::~MimeAttachment()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Protected methods */
|
|
||||||
|
|
||||||
void MimeAttachment::prepare()
|
|
||||||
{
|
|
||||||
this->header += "Content-disposition: attachment\r\n";
|
|
||||||
|
|
||||||
/* !!! IMPORTANT !!! */
|
|
||||||
MimeFile::prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
|
@ -1,51 +0,0 @@
|
||||||
/*
|
|
||||||
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 MIMEATTACHMENT_H
|
|
||||||
#define MIMEATTACHMENT_H
|
|
||||||
|
|
||||||
#include <QFile>
|
|
||||||
#include "mimepart.h"
|
|
||||||
#include "mimefile.h"
|
|
||||||
|
|
||||||
#include "smtpexports.h"
|
|
||||||
|
|
||||||
class SMTP_EXPORT MimeAttachment : public MimeFile
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
|
|
||||||
MimeAttachment(QFile* file);
|
|
||||||
MimeAttachment(const QByteArray& stream, const QString& fileName);
|
|
||||||
|
|
||||||
~MimeAttachment();
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/* [2] Protected methods */
|
|
||||||
|
|
||||||
virtual void prepare();
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MIMEATTACHMENT_H
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright (c) 2011-2012 - Tőkés Attila
|
|
||||||
|
|
||||||
This file is part of SmtpClient for Qt.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
See the LICENSE file for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "mimecontentformatter.h"
|
|
||||||
|
|
||||||
MimeContentFormatter::MimeContentFormatter(int max_length) :
|
|
||||||
max_length(max_length)
|
|
||||||
{}
|
|
||||||
|
|
||||||
QString MimeContentFormatter::format(const QString &content, bool quotedPrintable) const {
|
|
||||||
|
|
||||||
QString out;
|
|
||||||
|
|
||||||
int chars = 0;
|
|
||||||
for (int i = 0; i < content.length() ; ++i) {
|
|
||||||
chars++;
|
|
||||||
if (!quotedPrintable) {
|
|
||||||
if (chars > max_length) {
|
|
||||||
out.append("\r\n");
|
|
||||||
chars = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (content[i] == '\n') { // new line
|
|
||||||
out.append(content[i]);
|
|
||||||
chars = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((chars > max_length - 1)
|
|
||||||
|| ((content[i] == '=') && (chars > max_length - 3) )) {
|
|
||||||
out.append('=');
|
|
||||||
out.append("\r\n");
|
|
||||||
chars = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
out.append(content[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimeContentFormatter::setMaxLength(int l) {
|
|
||||||
max_length = l;
|
|
||||||
}
|
|
||||||
|
|
||||||
int MimeContentFormatter::getMaxLength() const {
|
|
||||||
return max_length;
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright (c) 2011-2012 - Tőkés Attila
|
|
||||||
|
|
||||||
This file is part of SmtpClient for Qt.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
See the LICENSE file for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MIMECONTENTFORMATTER_H
|
|
||||||
#define MIMECONTENTFORMATTER_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QByteArray>
|
|
||||||
|
|
||||||
#include "smtpexports.h"
|
|
||||||
|
|
||||||
class SMTP_EXPORT MimeContentFormatter : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
MimeContentFormatter (int max_length = 76);
|
|
||||||
|
|
||||||
void setMaxLength(int l);
|
|
||||||
int getMaxLength() const;
|
|
||||||
|
|
||||||
QString format(const QString &content, bool quotedPrintable = false) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
int max_length;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MIMECONTENTFORMATTER_H
|
|
|
@ -1,70 +0,0 @@
|
||||||
/*
|
|
||||||
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 "mimefile.h"
|
|
||||||
#include <QFileInfo>
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
|
|
||||||
MimeFile::MimeFile(QFile *file)
|
|
||||||
{
|
|
||||||
this->file = file;
|
|
||||||
this->cType = "application/octet-stream";
|
|
||||||
this->cName = QFileInfo(*file).fileName();
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
if (file)
|
|
||||||
delete file;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Getters and setters */
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [3] Protected methods */
|
|
||||||
|
|
||||||
void MimeFile::prepare()
|
|
||||||
{
|
|
||||||
if (this->file)
|
|
||||||
{
|
|
||||||
file->open(QIODevice::ReadOnly);
|
|
||||||
this->content = file->readAll();
|
|
||||||
file->close();
|
|
||||||
}
|
|
||||||
/* !!! IMPORTANT !!!! */
|
|
||||||
MimePart::prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [3] --- */
|
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
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 MIMEFILE_H
|
|
||||||
#define MIMEFILE_H
|
|
||||||
|
|
||||||
#include "mimepart.h"
|
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
#include "smtpexports.h"
|
|
||||||
|
|
||||||
class SMTP_EXPORT MimeFile : public MimePart
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
|
|
||||||
MimeFile(const QByteArray& stream, const QString& fileName);
|
|
||||||
MimeFile(QFile *f);
|
|
||||||
~MimeFile();
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Getters and Setters */
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/* [3] Protected members */
|
|
||||||
|
|
||||||
QFile* file;
|
|
||||||
|
|
||||||
/* [3] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [4] Protected methods */
|
|
||||||
|
|
||||||
virtual void prepare();
|
|
||||||
|
|
||||||
/* [4] --- */
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MIMEFILE_H
|
|
|
@ -1,57 +0,0 @@
|
||||||
/*
|
|
||||||
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 "mimehtml.h"
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
|
|
||||||
MimeHtml::MimeHtml(const QString &html) : MimeText(html)
|
|
||||||
{
|
|
||||||
this->cType = "text/html";
|
|
||||||
}
|
|
||||||
|
|
||||||
MimeHtml::~MimeHtml() {}
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Getters and Setters */
|
|
||||||
|
|
||||||
void MimeHtml::setHtml(const QString & html)
|
|
||||||
{
|
|
||||||
this->text = html;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString & MimeHtml::getHtml() const
|
|
||||||
{
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [3] Protected methods */
|
|
||||||
|
|
||||||
void MimeHtml::prepare()
|
|
||||||
{
|
|
||||||
/* !!! IMPORTANT !!! */
|
|
||||||
MimeText::prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [3] --- */
|
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
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 MIMEHTML_H
|
|
||||||
#define MIMEHTML_H
|
|
||||||
|
|
||||||
#include "mimetext.h"
|
|
||||||
|
|
||||||
#include "smtpexports.h"
|
|
||||||
|
|
||||||
class SMTP_EXPORT MimeHtml : public MimeText
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
|
|
||||||
MimeHtml(const QString &html = "");
|
|
||||||
~MimeHtml();
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Getters and Setters */
|
|
||||||
|
|
||||||
void setHtml(const QString & html);
|
|
||||||
|
|
||||||
const QString& getHtml() const;
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/* [3] Protected members */
|
|
||||||
|
|
||||||
/* [3] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [4] Protected methods */
|
|
||||||
|
|
||||||
virtual void prepare();
|
|
||||||
|
|
||||||
/* [4] --- */
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MIMEHTML_H
|
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
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 "mimeinlinefile.h"
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
|
|
||||||
MimeInlineFile::MimeInlineFile(QFile *f)
|
|
||||||
: MimeFile(f)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
MimeInlineFile::~MimeInlineFile()
|
|
||||||
{}
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Getters and Setters */
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [3] Protected methods */
|
|
||||||
|
|
||||||
void MimeInlineFile::prepare()
|
|
||||||
{
|
|
||||||
this->header += "Content-Disposition: inline\r\n";
|
|
||||||
|
|
||||||
/* !!! IMPORTANT !!! */
|
|
||||||
MimeFile::prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [3] --- */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
/*
|
|
||||||
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 MIMEINLINEFILE_H
|
|
||||||
#define MIMEINLINEFILE_H
|
|
||||||
|
|
||||||
#include "mimefile.h"
|
|
||||||
|
|
||||||
#include "smtpexports.h"
|
|
||||||
|
|
||||||
class SMTP_EXPORT MimeInlineFile : public MimeFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
|
|
||||||
MimeInlineFile(QFile *f);
|
|
||||||
~MimeInlineFile();
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Getters and Setters */
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/* [3] Protected members */
|
|
||||||
|
|
||||||
/* [3] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [4] Protected methods */
|
|
||||||
|
|
||||||
virtual void prepare();
|
|
||||||
|
|
||||||
/* [4] --- */
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MIMEINLINEFILE_H
|
|
|
@ -1,257 +0,0 @@
|
||||||
/*
|
|
||||||
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 "mimemessage.h"
|
|
||||||
|
|
||||||
#include <QDateTime>
|
|
||||||
#include "quotedprintable.h"
|
|
||||||
#include <typeinfo>
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
MimeMessage::MimeMessage(bool createAutoMimeContent) :
|
|
||||||
hEncoding(MimePart::_8Bit)
|
|
||||||
{
|
|
||||||
if (createAutoMimeContent)
|
|
||||||
this->content = new MimeMultiPart();
|
|
||||||
|
|
||||||
autoMimeContentCreated = createAutoMimeContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
MimeMessage::~MimeMessage()
|
|
||||||
{
|
|
||||||
if (this->autoMimeContentCreated)
|
|
||||||
{
|
|
||||||
this->autoMimeContentCreated = false;
|
|
||||||
delete (this->content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Getters and Setters */
|
|
||||||
MimePart& MimeMessage::getContent() {
|
|
||||||
return *content;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimeMessage::setContent(MimePart *content) {
|
|
||||||
if (this->autoMimeContentCreated)
|
|
||||||
{
|
|
||||||
this->autoMimeContentCreated = false;
|
|
||||||
delete (this->content);
|
|
||||||
}
|
|
||||||
this->content = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimeMessage::setSender(EmailAddress* e)
|
|
||||||
{
|
|
||||||
this->sender = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimeMessage::addRecipient(EmailAddress* rcpt, RecipientType type)
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case To:
|
|
||||||
recipientsTo << rcpt;
|
|
||||||
break;
|
|
||||||
case Cc:
|
|
||||||
recipientsCc << rcpt;
|
|
||||||
break;
|
|
||||||
case Bcc:
|
|
||||||
recipientsBcc << rcpt;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimeMessage::addTo(EmailAddress* rcpt) {
|
|
||||||
this->recipientsTo << rcpt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimeMessage::addCc(EmailAddress* rcpt) {
|
|
||||||
this->recipientsCc << rcpt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimeMessage::addBcc(EmailAddress* rcpt) {
|
|
||||||
this->recipientsBcc << rcpt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimeMessage::setSubject(const QString & subject)
|
|
||||||
{
|
|
||||||
this->subject = subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimeMessage::addPart(MimePart *part)
|
|
||||||
{
|
|
||||||
if (typeid(*content) == typeid(MimeMultiPart)) {
|
|
||||||
((MimeMultiPart*) content)->addPart(part);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimeMessage::setHeaderEncoding(MimePart::Encoding hEnc)
|
|
||||||
{
|
|
||||||
this->hEncoding = hEnc;
|
|
||||||
}
|
|
||||||
|
|
||||||
const EmailAddress & MimeMessage::getSender() const
|
|
||||||
{
|
|
||||||
return *sender;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QList<EmailAddress*> & MimeMessage::getRecipients(RecipientType type) const
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
case To:
|
|
||||||
return recipientsTo;
|
|
||||||
case Cc:
|
|
||||||
return recipientsCc;
|
|
||||||
case Bcc:
|
|
||||||
return recipientsBcc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString & MimeMessage::getSubject() const
|
|
||||||
{
|
|
||||||
return subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QList<MimePart*> & MimeMessage::getParts() const
|
|
||||||
{
|
|
||||||
if (typeid(*content) == typeid(MimeMultiPart)) {
|
|
||||||
return ((MimeMultiPart*) content)->getParts();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
QList<MimePart*> *res = new QList<MimePart*>();
|
|
||||||
res->append(content);
|
|
||||||
return *res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [3] Public Methods */
|
|
||||||
|
|
||||||
QString MimeMessage::toString()
|
|
||||||
{
|
|
||||||
QString mime;
|
|
||||||
|
|
||||||
/* =========== MIME HEADER ============ */
|
|
||||||
|
|
||||||
/* ---------- Sender / From ----------- */
|
|
||||||
mime = "From:";
|
|
||||||
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 ---------- */
|
|
||||||
mime += "To:";
|
|
||||||
QList<EmailAddress*>::iterator it; int i;
|
|
||||||
for (i = 0, it = recipientsTo.begin(); it != recipientsTo.end(); ++it, ++i)
|
|
||||||
{
|
|
||||||
if (i != 0) { mime += ","; }
|
|
||||||
|
|
||||||
if ((*it)->getName() != "")
|
|
||||||
{
|
|
||||||
switch (hEncoding)
|
|
||||||
{
|
|
||||||
case MimePart::Base64:
|
|
||||||
mime += " =?utf-8?B?" + QByteArray().append((*it)->getName()).toBase64() + "?=";
|
|
||||||
break;
|
|
||||||
case MimePart::QuotedPrintable:
|
|
||||||
mime += " =?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append((*it)->getName())).replace(' ', "_").replace(':',"=3A") + "?=";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mime += " " + (*it)->getName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mime += " <" + (*it)->getAddress() + ">";
|
|
||||||
}
|
|
||||||
mime += "\r\n";
|
|
||||||
/* ---------------------------------- */
|
|
||||||
|
|
||||||
/* ------- Recipients / Cc ---------- */
|
|
||||||
if (recipientsCc.size() != 0) {
|
|
||||||
mime += "Cc:";
|
|
||||||
}
|
|
||||||
for (i = 0, it = recipientsCc.begin(); it != recipientsCc.end(); ++it, ++i)
|
|
||||||
{
|
|
||||||
if (i != 0) { mime += ","; }
|
|
||||||
|
|
||||||
if ((*it)->getName() != "")
|
|
||||||
{
|
|
||||||
switch (hEncoding)
|
|
||||||
{
|
|
||||||
case MimePart::Base64:
|
|
||||||
mime += " =?utf-8?B?" + QByteArray().append((*it)->getName()).toBase64() + "?=";
|
|
||||||
break;
|
|
||||||
case MimePart::QuotedPrintable:
|
|
||||||
mime += " =?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append((*it)->getName())).replace(' ', "_").replace(':',"=3A") + "?=";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mime += " " + (*it)->getName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mime += " <" + (*it)->getAddress() + ">";
|
|
||||||
}
|
|
||||||
if (recipientsCc.size() != 0) {
|
|
||||||
mime += "\r\n";
|
|
||||||
}
|
|
||||||
/* ---------------------------------- */
|
|
||||||
|
|
||||||
/* ------------ Subject ------------- */
|
|
||||||
mime += "Subject: ";
|
|
||||||
|
|
||||||
|
|
||||||
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";
|
|
||||||
mime += "MIME-Version: 1.0\r\n";
|
|
||||||
|
|
||||||
mime += content->toString();
|
|
||||||
return mime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [3] --- */
|
|
|
@ -1,92 +0,0 @@
|
||||||
/*
|
|
||||||
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 MIMEMESSAGE_H
|
|
||||||
#define MIMEMESSAGE_H
|
|
||||||
|
|
||||||
#include "mimepart.h"
|
|
||||||
#include "mimemultipart.h"
|
|
||||||
#include "emailaddress.h"
|
|
||||||
#include <QList>
|
|
||||||
|
|
||||||
#include "smtpexports.h"
|
|
||||||
|
|
||||||
class SMTP_EXPORT MimeMessage : public QObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum RecipientType {
|
|
||||||
To, // primary
|
|
||||||
Cc, // carbon copy
|
|
||||||
Bcc // blind carbon copy
|
|
||||||
};
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
|
|
||||||
MimeMessage(bool createAutoMimeConent = true);
|
|
||||||
~MimeMessage();
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Getters and Setters */
|
|
||||||
|
|
||||||
void setSender(EmailAddress* e);
|
|
||||||
void addRecipient(EmailAddress* rcpt, RecipientType type = To);
|
|
||||||
void addTo(EmailAddress* rcpt);
|
|
||||||
void addCc(EmailAddress* rcpt);
|
|
||||||
void addBcc(EmailAddress* rcpt);
|
|
||||||
void setSubject(const QString & subject);
|
|
||||||
void addPart(MimePart* part);
|
|
||||||
|
|
||||||
void setHeaderEncoding(MimePart::Encoding);
|
|
||||||
|
|
||||||
const EmailAddress & getSender() const;
|
|
||||||
const QList<EmailAddress*> & getRecipients(RecipientType type = To) const;
|
|
||||||
const QString & getSubject() const;
|
|
||||||
const QList<MimePart*> & getParts() const;
|
|
||||||
|
|
||||||
MimePart& getContent();
|
|
||||||
void setContent(MimePart *content);
|
|
||||||
/* [2] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [3] Public methods */
|
|
||||||
|
|
||||||
virtual QString toString();
|
|
||||||
|
|
||||||
/* [3] --- */
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/* [4] Protected members */
|
|
||||||
|
|
||||||
EmailAddress* sender;
|
|
||||||
QList<EmailAddress*> recipientsTo, recipientsCc, recipientsBcc;
|
|
||||||
QString subject;
|
|
||||||
MimePart *content;
|
|
||||||
bool autoMimeContentCreated;
|
|
||||||
|
|
||||||
MimePart::Encoding hEncoding;
|
|
||||||
|
|
||||||
/* [4] --- */
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MIMEMESSAGE_H
|
|
|
@ -1,78 +0,0 @@
|
||||||
/*
|
|
||||||
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 "mimemultipart.h"
|
|
||||||
#include <QTime>
|
|
||||||
#include <QCryptographicHash>
|
|
||||||
|
|
||||||
const QString MULTI_PART_NAMES[] = {
|
|
||||||
"multipart/mixed", // Mixed
|
|
||||||
"multipart/digest", // Digest
|
|
||||||
"multipart/alternative", // Alternative
|
|
||||||
"multipart/related", // Related
|
|
||||||
"multipart/report", // Report
|
|
||||||
"multipart/signed", // Signed
|
|
||||||
"multipart/encrypted" // Encrypted
|
|
||||||
};
|
|
||||||
|
|
||||||
MimeMultiPart::MimeMultiPart(MultiPartType type)
|
|
||||||
{
|
|
||||||
this->type = type;
|
|
||||||
this->cType = MULTI_PART_NAMES[this->type];
|
|
||||||
this->cEncoding = _8Bit;
|
|
||||||
|
|
||||||
QCryptographicHash md5(QCryptographicHash::Md5);
|
|
||||||
md5.addData(QByteArray().append(qrand()));
|
|
||||||
cBoundary = md5.result().toHex();
|
|
||||||
}
|
|
||||||
|
|
||||||
MimeMultiPart::~MimeMultiPart() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimeMultiPart::addPart(MimePart *part) {
|
|
||||||
parts.append(part);
|
|
||||||
}
|
|
||||||
|
|
||||||
const QList<MimePart*> & MimeMultiPart::getParts() const {
|
|
||||||
return parts;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimeMultiPart::prepare() {
|
|
||||||
QList<MimePart*>::iterator it;
|
|
||||||
|
|
||||||
content = "";
|
|
||||||
for (it = parts.begin(); it != parts.end(); it++) {
|
|
||||||
content += "--" + cBoundary + "\r\n";
|
|
||||||
(*it)->prepare();
|
|
||||||
content += (*it)->toString();
|
|
||||||
};
|
|
||||||
|
|
||||||
content += "--" + cBoundary + "--\r\n";
|
|
||||||
|
|
||||||
MimePart::prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimeMultiPart::setMimeType(const MultiPartType type) {
|
|
||||||
this->type = type;
|
|
||||||
this->cType = MULTI_PART_NAMES[type];
|
|
||||||
}
|
|
||||||
|
|
||||||
MimeMultiPart::MultiPartType MimeMultiPart::getMimeType() const {
|
|
||||||
return type;
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
/*
|
|
||||||
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 MIMEMULTIPART_H
|
|
||||||
#define MIMEMULTIPART_H
|
|
||||||
|
|
||||||
#include "mimepart.h"
|
|
||||||
|
|
||||||
#include "smtpexports.h"
|
|
||||||
|
|
||||||
class SMTP_EXPORT MimeMultiPart : public MimePart
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
|
|
||||||
/* [0] Enums */
|
|
||||||
enum MultiPartType {
|
|
||||||
Mixed = 0, // RFC 2046, section 5.1.3
|
|
||||||
Digest = 1, // RFC 2046, section 5.1.5
|
|
||||||
Alternative = 2, // RFC 2046, section 5.1.4
|
|
||||||
Related = 3, // RFC 2387
|
|
||||||
Report = 4, // RFC 6522
|
|
||||||
Signed = 5, // RFC 1847, section 2.1
|
|
||||||
Encrypted = 6 // RFC 1847, section 2.2
|
|
||||||
};
|
|
||||||
|
|
||||||
/* [0] --- */
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
MimeMultiPart(const MultiPartType type = Related);
|
|
||||||
|
|
||||||
~MimeMultiPart();
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
/* [2] Getters and Setters */
|
|
||||||
|
|
||||||
void setMimeType(const MultiPartType type);
|
|
||||||
MultiPartType getMimeType() const;
|
|
||||||
|
|
||||||
const QList<MimePart*> & getParts() const;
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
||||||
|
|
||||||
/* [3] Public methods */
|
|
||||||
|
|
||||||
void addPart(MimePart *part);
|
|
||||||
|
|
||||||
virtual void prepare();
|
|
||||||
|
|
||||||
/* [3] --- */
|
|
||||||
|
|
||||||
protected:
|
|
||||||
QList< MimePart* > parts;
|
|
||||||
|
|
||||||
MultiPartType type;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MIMEMULTIPART_H
|
|
|
@ -1,214 +0,0 @@
|
||||||
/*
|
|
||||||
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 "mimepart.h"
|
|
||||||
#include "quotedprintable.h"
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
|
|
||||||
MimePart::MimePart()
|
|
||||||
{
|
|
||||||
cEncoding = _7Bit;
|
|
||||||
prepared = false;
|
|
||||||
cBoundary = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
MimePart::~MimePart()
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Getters and Setters */
|
|
||||||
|
|
||||||
void MimePart::setContent(const QByteArray & content)
|
|
||||||
{
|
|
||||||
this->content = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimePart::setHeader(const QString & header)
|
|
||||||
{
|
|
||||||
this->header = header;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimePart::addHeaderLine(const QString & line)
|
|
||||||
{
|
|
||||||
this->header += line + "\r\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString& MimePart::getHeader() const
|
|
||||||
{
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QByteArray& MimePart::getContent() const
|
|
||||||
{
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimePart::setContentId(const QString & cId)
|
|
||||||
{
|
|
||||||
this->cId = cId;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString & MimePart::getContentId() const
|
|
||||||
{
|
|
||||||
return this->cId;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimePart::setContentName(const QString & cName)
|
|
||||||
{
|
|
||||||
this->cName = cName;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString & MimePart::getContentName() const
|
|
||||||
{
|
|
||||||
return this->cName;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimePart::setContentType(const QString & cType)
|
|
||||||
{
|
|
||||||
this->cType = cType;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString & MimePart::getContentType() const
|
|
||||||
{
|
|
||||||
return this->cType;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimePart::setCharset(const QString & charset)
|
|
||||||
{
|
|
||||||
this->cCharset = charset;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString & MimePart::getCharset() const
|
|
||||||
{
|
|
||||||
return this->cCharset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MimePart::setEncoding(Encoding enc)
|
|
||||||
{
|
|
||||||
this->cEncoding = enc;
|
|
||||||
}
|
|
||||||
|
|
||||||
MimePart::Encoding MimePart::getEncoding() const
|
|
||||||
{
|
|
||||||
return this->cEncoding;
|
|
||||||
}
|
|
||||||
|
|
||||||
MimeContentFormatter& MimePart::getContentFormatter()
|
|
||||||
{
|
|
||||||
return this->formatter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [3] Public methods */
|
|
||||||
|
|
||||||
QString MimePart::toString()
|
|
||||||
{
|
|
||||||
if (!prepared)
|
|
||||||
prepare();
|
|
||||||
|
|
||||||
return mimeString;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [3] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [4] Protected methods */
|
|
||||||
|
|
||||||
void MimePart::prepare()
|
|
||||||
{
|
|
||||||
mimeString = QString();
|
|
||||||
|
|
||||||
/* === 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)
|
|
||||||
{
|
|
||||||
case _7Bit:
|
|
||||||
mimeString.append("7bit\r\n");
|
|
||||||
break;
|
|
||||||
case _8Bit:
|
|
||||||
mimeString.append("8bit\r\n");
|
|
||||||
break;
|
|
||||||
case Base64:
|
|
||||||
mimeString.append("base64\r\n");
|
|
||||||
break;
|
|
||||||
case QuotedPrintable:
|
|
||||||
mimeString.append("quoted-printable\r\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* ------------------------ */
|
|
||||||
|
|
||||||
/* 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] --- */
|
|
|
@ -1,114 +0,0 @@
|
||||||
/*
|
|
||||||
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 MIMEPART_H
|
|
||||||
#define MIMEPART_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include "mimecontentformatter.h"
|
|
||||||
|
|
||||||
#include "smtpexports.h"
|
|
||||||
|
|
||||||
class SMTP_EXPORT MimePart : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
|
|
||||||
/* [0] Enumerations */
|
|
||||||
enum Encoding {
|
|
||||||
_7Bit,
|
|
||||||
_8Bit,
|
|
||||||
Base64,
|
|
||||||
QuotedPrintable
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* [0] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
|
|
||||||
MimePart();
|
|
||||||
~MimePart();
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Getters and Setters */
|
|
||||||
|
|
||||||
const QString& getHeader() const;
|
|
||||||
const QByteArray& getContent() const;
|
|
||||||
|
|
||||||
void setContent(const QByteArray & content);
|
|
||||||
void setHeader(const QString & header);
|
|
||||||
|
|
||||||
void addHeaderLine(const QString & line);
|
|
||||||
|
|
||||||
void setContentId(const QString & cId);
|
|
||||||
const QString & getContentId() const;
|
|
||||||
|
|
||||||
void setContentName(const QString & cName);
|
|
||||||
const QString & getContentName() const;
|
|
||||||
|
|
||||||
void setContentType(const QString & cType);
|
|
||||||
const QString & getContentType() const;
|
|
||||||
|
|
||||||
void setCharset(const QString & charset);
|
|
||||||
const QString & getCharset() const;
|
|
||||||
|
|
||||||
void setEncoding(Encoding enc);
|
|
||||||
Encoding getEncoding() const;
|
|
||||||
|
|
||||||
MimeContentFormatter& getContentFormatter();
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [3] Public methods */
|
|
||||||
|
|
||||||
virtual QString toString();
|
|
||||||
|
|
||||||
virtual void prepare();
|
|
||||||
|
|
||||||
/* [3] --- */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/* [4] Protected members */
|
|
||||||
|
|
||||||
QString header;
|
|
||||||
QByteArray content;
|
|
||||||
|
|
||||||
QString cId;
|
|
||||||
QString cName;
|
|
||||||
QString cType;
|
|
||||||
QString cCharset;
|
|
||||||
QString cBoundary;
|
|
||||||
Encoding cEncoding;
|
|
||||||
|
|
||||||
QString mimeString;
|
|
||||||
bool prepared;
|
|
||||||
|
|
||||||
MimeContentFormatter formatter;
|
|
||||||
|
|
||||||
/* [4] --- */
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MIMEPART_H
|
|
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
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 "mimetext.h"
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
|
|
||||||
MimeText::MimeText(const QString &txt)
|
|
||||||
{
|
|
||||||
this->text = txt;
|
|
||||||
this->cType = "text/plain";
|
|
||||||
this->cCharset = "utf-8";
|
|
||||||
this->cEncoding = _8Bit;
|
|
||||||
}
|
|
||||||
|
|
||||||
MimeText::~MimeText() { }
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Getters and Setters */
|
|
||||||
|
|
||||||
void MimeText::setText(const QString & text)
|
|
||||||
{
|
|
||||||
this->text = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString & MimeText::getText() const
|
|
||||||
{
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [3] Protected Methods */
|
|
||||||
|
|
||||||
void MimeText::prepare()
|
|
||||||
{
|
|
||||||
this->content.clear();
|
|
||||||
this->content.append(text);
|
|
||||||
|
|
||||||
/* !!! IMPORTANT !!! */
|
|
||||||
MimePart::prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [3] --- */
|
|
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
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 MIMETEXT_H
|
|
||||||
#define MIMETEXT_H
|
|
||||||
|
|
||||||
#include "mimepart.h"
|
|
||||||
|
|
||||||
#include "smtpexports.h"
|
|
||||||
|
|
||||||
class SMTP_EXPORT MimeText : public MimePart
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
|
|
||||||
MimeText(const QString &text = "");
|
|
||||||
~MimeText();
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Getters and Setters*/
|
|
||||||
|
|
||||||
void setText(const QString & text);
|
|
||||||
|
|
||||||
const QString & getText() const;
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/* [3] Protected members */
|
|
||||||
|
|
||||||
QString text;
|
|
||||||
/* [3] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [4] Protected methods */
|
|
||||||
|
|
||||||
void prepare();
|
|
||||||
|
|
||||||
/* [4] --- */
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MIMETEXT_H
|
|
|
@ -1,69 +0,0 @@
|
||||||
/*
|
|
||||||
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 "quotedprintable.h"
|
|
||||||
|
|
||||||
QString QuotedPrintable::encode(const QByteArray &input)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
byte = input[i];
|
|
||||||
|
|
||||||
if ((byte == 0x20) || ((byte >= 33) && (byte <= 126) && (byte != 61)))
|
|
||||||
{
|
|
||||||
output.append(byte);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
output.append('=');
|
|
||||||
output.append(hex[((byte >> 4) & 0x0F)]);
|
|
||||||
output.append(hex[(byte & 0x0F)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QByteArray QuotedPrintable::decode(const QString &input)
|
|
||||||
{
|
|
||||||
// 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F
|
|
||||||
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;
|
|
||||||
|
|
||||||
for (int i = 0; i < input.length(); ++i)
|
|
||||||
{
|
|
||||||
if (input.at(i).toLatin1() == '=')
|
|
||||||
{
|
|
||||||
output.append((hexVal[input.at(i + 1).toLatin1() - '0'] << 4) + hexVal[input.at(i + 2).toLatin1() - '0']);
|
|
||||||
i += 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
output.append(input.at(i).toLatin1());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
/*
|
|
||||||
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 QUOTEDPRINTABLE_H
|
|
||||||
#define QUOTEDPRINTABLE_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QByteArray>
|
|
||||||
|
|
||||||
#include "smtpexports.h"
|
|
||||||
|
|
||||||
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
|
|
207
servatrice/src/smtp/qxtglobal.h
Normal file
207
servatrice/src/smtp/qxtglobal.h
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) Qxt Foundation. Some rights reserved.
|
||||||
|
**
|
||||||
|
** This file is part of the QxtCore module of the Qxt library.
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or modify it
|
||||||
|
** under the terms of the Common Public License, version 1.0, as published
|
||||||
|
** by IBM, and/or under the terms of the GNU Lesser General Public License,
|
||||||
|
** version 2.1, as published by the Free Software Foundation.
|
||||||
|
**
|
||||||
|
** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
|
||||||
|
** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the CPL and the LGPL along with this
|
||||||
|
** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
|
||||||
|
** included with the source distribution for more information.
|
||||||
|
** If you did not receive a copy of the licenses, contact the Qxt Foundation.
|
||||||
|
**
|
||||||
|
** <http://libqxt.org> <foundation@libqxt.org>
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QXTGLOBAL_H
|
||||||
|
#define QXTGLOBAL_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
#define QXT_VERSION 0x000602
|
||||||
|
#define QXT_VERSION_STR "0.6.2"
|
||||||
|
|
||||||
|
//--------------------------global macros------------------------------
|
||||||
|
|
||||||
|
#ifndef QXT_NO_MACROS
|
||||||
|
|
||||||
|
#endif // QXT_NO_MACROS
|
||||||
|
|
||||||
|
//--------------------------export macros------------------------------
|
||||||
|
|
||||||
|
#define QXT_DLLEXPORT DO_NOT_USE_THIS_ANYMORE
|
||||||
|
|
||||||
|
#if !defined(QXT_STATIC)
|
||||||
|
# if defined(BUILD_QXT_CORE)
|
||||||
|
# define QXT_CORE_EXPORT Q_DECL_EXPORT
|
||||||
|
# else
|
||||||
|
# define QXT_CORE_EXPORT Q_DECL_IMPORT
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define QXT_CORE_EXPORT
|
||||||
|
#endif // BUILD_QXT_CORE
|
||||||
|
|
||||||
|
#if !defined(QXT_STATIC)
|
||||||
|
# if defined(BUILD_QXT_GUI)
|
||||||
|
# define QXT_GUI_EXPORT Q_DECL_EXPORT
|
||||||
|
# else
|
||||||
|
# define QXT_GUI_EXPORT Q_DECL_IMPORT
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define QXT_GUI_EXPORT
|
||||||
|
#endif // BUILD_QXT_GUI
|
||||||
|
|
||||||
|
#if !defined(QXT_STATIC)
|
||||||
|
# if defined(BUILD_QXT_NETWORK)
|
||||||
|
# define QXT_NETWORK_EXPORT Q_DECL_EXPORT
|
||||||
|
# else
|
||||||
|
# define QXT_NETWORK_EXPORT Q_DECL_IMPORT
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define QXT_NETWORK_EXPORT
|
||||||
|
#endif // BUILD_QXT_NETWORK
|
||||||
|
|
||||||
|
#if !defined(QXT_STATIC)
|
||||||
|
# if defined(BUILD_QXT_SQL)
|
||||||
|
# define QXT_SQL_EXPORT Q_DECL_EXPORT
|
||||||
|
# else
|
||||||
|
# define QXT_SQL_EXPORT Q_DECL_IMPORT
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define QXT_SQL_EXPORT
|
||||||
|
#endif // BUILD_QXT_SQL
|
||||||
|
|
||||||
|
#if !defined(QXT_STATIC)
|
||||||
|
# if defined(BUILD_QXT_WEB)
|
||||||
|
# define QXT_WEB_EXPORT Q_DECL_EXPORT
|
||||||
|
# else
|
||||||
|
# define QXT_WEB_EXPORT Q_DECL_IMPORT
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define QXT_WEB_EXPORT
|
||||||
|
#endif // BUILD_QXT_WEB
|
||||||
|
|
||||||
|
#if !defined(QXT_STATIC)
|
||||||
|
# if defined(BUILD_QXT_BERKELEY)
|
||||||
|
# define QXT_BERKELEY_EXPORT Q_DECL_EXPORT
|
||||||
|
# else
|
||||||
|
# define QXT_BERKELEY_EXPORT Q_DECL_IMPORT
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define QXT_BERKELEY_EXPORT
|
||||||
|
#endif // BUILD_QXT_BERKELEY
|
||||||
|
|
||||||
|
#if !defined(QXT_STATIC)
|
||||||
|
# if defined(BUILD_QXT_ZEROCONF)
|
||||||
|
# define QXT_ZEROCONF_EXPORT Q_DECL_EXPORT
|
||||||
|
# else
|
||||||
|
# define QXT_ZEROCONF_EXPORT Q_DECL_IMPORT
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define QXT_ZEROCONF_EXPORT
|
||||||
|
#endif // QXT_ZEROCONF_EXPORT
|
||||||
|
|
||||||
|
#if defined BUILD_QXT_CORE || defined BUILD_QXT_GUI || defined BUILD_QXT_SQL || defined BUILD_QXT_NETWORK || defined BUILD_QXT_WEB || defined BUILD_QXT_BERKELEY || defined BUILD_QXT_ZEROCONF
|
||||||
|
# define BUILD_QXT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QXT_CORE_EXPORT const char* qxtVersion();
|
||||||
|
|
||||||
|
#ifndef QT_BEGIN_NAMESPACE
|
||||||
|
#define QT_BEGIN_NAMESPACE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef QT_END_NAMESPACE
|
||||||
|
#define QT_END_NAMESPACE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef QT_FORWARD_DECLARE_CLASS
|
||||||
|
#define QT_FORWARD_DECLARE_CLASS(Class) class Class;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
** This file is derived from code bearing the following notice:
|
||||||
|
** The sole author of this file, Adam Higerd, has explicitly disclaimed all
|
||||||
|
** copyright interest and protection for the content within. This file has
|
||||||
|
** been placed in the public domain according to United States copyright
|
||||||
|
** statute and case law. In jurisdictions where this public domain dedication
|
||||||
|
** is not legally recognized, anyone who receives a copy of this file is
|
||||||
|
** permitted to use, modify, duplicate, and redistribute this file, in whole
|
||||||
|
** or in part, with no restrictions or conditions. In these jurisdictions,
|
||||||
|
** this file shall be copyright (C) 2006-2008 by Adam Higerd.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#define QXT_DECLARE_PRIVATE(PUB) friend class PUB##Private; QxtPrivateInterface<PUB, PUB##Private> qxt_d;
|
||||||
|
#define QXT_DECLARE_PUBLIC(PUB) friend class PUB;
|
||||||
|
#define QXT_INIT_PRIVATE(PUB) qxt_d.setPublic(this);
|
||||||
|
#define QXT_D(PUB) PUB##Private& d = qxt_d()
|
||||||
|
#define QXT_P(PUB) PUB& p = qxt_p()
|
||||||
|
|
||||||
|
template <typename PUB>
|
||||||
|
class QxtPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~QxtPrivate()
|
||||||
|
{}
|
||||||
|
inline void QXT_setPublic(PUB* pub)
|
||||||
|
{
|
||||||
|
qxt_p_ptr = pub;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
inline PUB& qxt_p()
|
||||||
|
{
|
||||||
|
return *qxt_p_ptr;
|
||||||
|
}
|
||||||
|
inline const PUB& qxt_p() const
|
||||||
|
{
|
||||||
|
return *qxt_p_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PUB* qxt_p_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename PUB, typename PVT>
|
||||||
|
class QxtPrivateInterface
|
||||||
|
{
|
||||||
|
friend class QxtPrivate<PUB>;
|
||||||
|
public:
|
||||||
|
QxtPrivateInterface()
|
||||||
|
{
|
||||||
|
pvt = new PVT;
|
||||||
|
}
|
||||||
|
~QxtPrivateInterface()
|
||||||
|
{
|
||||||
|
delete pvt;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setPublic(PUB* pub)
|
||||||
|
{
|
||||||
|
pvt->QXT_setPublic(pub);
|
||||||
|
}
|
||||||
|
inline PVT& operator()()
|
||||||
|
{
|
||||||
|
return *static_cast<PVT*>(pvt);
|
||||||
|
}
|
||||||
|
inline const PVT& operator()() const
|
||||||
|
{
|
||||||
|
return *static_cast<PVT*>(pvt);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
QxtPrivateInterface(const QxtPrivateInterface&) { }
|
||||||
|
QxtPrivateInterface& operator=(const QxtPrivateInterface&) { }
|
||||||
|
QxtPrivate<PUB>* pvt;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QXT_GLOBAL
|
211
servatrice/src/smtp/qxthmac.cpp
Normal file
211
servatrice/src/smtp/qxthmac.cpp
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) Qxt Foundation. Some rights reserved.
|
||||||
|
**
|
||||||
|
** This file is part of the QxtCore module of the Qxt library.
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or modify it
|
||||||
|
** under the terms of the Common Public License, version 1.0, as published
|
||||||
|
** by IBM, and/or under the terms of the GNU Lesser General Public License,
|
||||||
|
** version 2.1, as published by the Free Software Foundation.
|
||||||
|
**
|
||||||
|
** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
|
||||||
|
** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the CPL and the LGPL along with this
|
||||||
|
** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
|
||||||
|
** included with the source distribution for more information.
|
||||||
|
** If you did not receive a copy of the licenses, contact the Qxt Foundation.
|
||||||
|
**
|
||||||
|
** <http://libqxt.org> <foundation@libqxt.org>
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "qxthmac.h"
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x040300
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
\class QxtHmac
|
||||||
|
|
||||||
|
\inmodule QxtCore
|
||||||
|
|
||||||
|
\brief The QxtHmac class calculates keyed-Hash Message Authentication Codes
|
||||||
|
|
||||||
|
HMAC is a well-known algorithm for generating a message authentication code (MAC) that can be used to verify the
|
||||||
|
integrity and authenticity of a message.
|
||||||
|
|
||||||
|
This class requires Qt 4.3.0 or greater.
|
||||||
|
|
||||||
|
To verify a message, the sender creates a MAC using a key, which is a secret known only to the sender and recipient,
|
||||||
|
and the content of the message. This MAC is then sent along with the message. The recipient then creates another MAC
|
||||||
|
using the shared key and the content of the message. If the two codes match, the message is verified.
|
||||||
|
|
||||||
|
HMAC has been used as a password encryption scheme. The final output of the HMAC algorithm depends on the shared key
|
||||||
|
and an inner hash. This inner hash is generated from the message content and the key. To use HMAC as a password
|
||||||
|
scheme, the key should be the username; the message should be the user's password. The authenticating party (for
|
||||||
|
instance, a login server) only needs to store this inner hash generated by the innerHash() function. When requesting
|
||||||
|
authentication, the user calculates a HMAC using this key and message and sends his username and this HMAC to the
|
||||||
|
authenticator. The authenticator can then use verify() using the provided HMAC and the stored inner hash. When using
|
||||||
|
this scheme, the password is never stored or transmitted in plain text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef QXT_DOXYGEN_RUN
|
||||||
|
class QxtHmacPrivate : public QxtPrivate<QxtHmac>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QXT_DECLARE_PUBLIC(QxtHmac)
|
||||||
|
QxtHmacPrivate() : ohash(0), ihash(0) {}
|
||||||
|
~QxtHmacPrivate()
|
||||||
|
{
|
||||||
|
// deleting NULL is safe, so no tests are needed here
|
||||||
|
delete ohash;
|
||||||
|
delete ihash;
|
||||||
|
}
|
||||||
|
QCryptographicHash* ohash;
|
||||||
|
QCryptographicHash* ihash;
|
||||||
|
QByteArray opad, ipad, result;
|
||||||
|
QCryptographicHash::Algorithm algorithm;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructs a QxtHmac object using the specified algorithm.
|
||||||
|
*/
|
||||||
|
QxtHmac::QxtHmac(QCryptographicHash::Algorithm algorithm)
|
||||||
|
{
|
||||||
|
QXT_INIT_PRIVATE(QxtHmac);
|
||||||
|
qxt_d().ohash = new QCryptographicHash(algorithm);
|
||||||
|
qxt_d().ihash = new QCryptographicHash(algorithm);
|
||||||
|
qxt_d().algorithm = algorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the shared secret key for the message authentication code.
|
||||||
|
*
|
||||||
|
* Any data that had been processed using addData() will be discarded.
|
||||||
|
*/
|
||||||
|
void QxtHmac::setKey(QByteArray key)
|
||||||
|
{
|
||||||
|
// We make the assumption that all hashes use a 512-bit block size; as of Qt 4.4.0 this is true of all supported hash functions
|
||||||
|
QxtHmacPrivate* d = &qxt_d();
|
||||||
|
d->opad = QByteArray(64, 0x5c);
|
||||||
|
d->ipad = QByteArray(64, 0x36);
|
||||||
|
if (key.size() > 64)
|
||||||
|
{
|
||||||
|
key = QCryptographicHash::hash(key, d->algorithm);
|
||||||
|
}
|
||||||
|
for (int i = key.size() - 1; i >= 0; --i)
|
||||||
|
{
|
||||||
|
d->opad[i] = d->opad[i] ^ key[i];
|
||||||
|
d->ipad[i] = d->ipad[i] ^ key[i];
|
||||||
|
}
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Resets the object.
|
||||||
|
*
|
||||||
|
* Any data that had been processed using addData() will be discarded.
|
||||||
|
* The key, if set, will be preserved.
|
||||||
|
*/
|
||||||
|
void QxtHmac::reset()
|
||||||
|
{
|
||||||
|
QxtHmacPrivate* d = &qxt_d();
|
||||||
|
d->ihash->reset();
|
||||||
|
d->ihash->addData(d->ipad);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the inner hash of the HMAC function.
|
||||||
|
*
|
||||||
|
* This hash can be stored in lieu of the shared secret on the authenticating side
|
||||||
|
* and used for verifying an HMAC code. When used in this manner, HMAC can be used
|
||||||
|
* to provide a form of secure password authentication. See the documentation above
|
||||||
|
* for details.
|
||||||
|
*/
|
||||||
|
QByteArray QxtHmac::innerHash() const
|
||||||
|
{
|
||||||
|
return qxt_d().ihash->result();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the authentication code for the message.
|
||||||
|
*/
|
||||||
|
QByteArray QxtHmac::result()
|
||||||
|
{
|
||||||
|
QxtHmacPrivate* d = &qxt_d();
|
||||||
|
Q_ASSERT(d->opad.size());
|
||||||
|
if (d->result.size())
|
||||||
|
return d->result;
|
||||||
|
d->ohash->reset();
|
||||||
|
d->ohash->addData(d->opad);
|
||||||
|
d->ohash->addData(innerHash());
|
||||||
|
d->result = d->ohash->result();
|
||||||
|
return d->result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Verifies the authentication code against a known inner hash.
|
||||||
|
*
|
||||||
|
* \sa innerHash()
|
||||||
|
*/
|
||||||
|
bool QxtHmac::verify(const QByteArray& otherInner)
|
||||||
|
{
|
||||||
|
result(); // populates d->result
|
||||||
|
QxtHmacPrivate* d = &qxt_d();
|
||||||
|
d->ohash->reset();
|
||||||
|
d->ohash->addData(d->opad);
|
||||||
|
d->ohash->addData(otherInner);
|
||||||
|
return d->result == d->ohash->result();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Adds the provided data to the message to be authenticated.
|
||||||
|
*/
|
||||||
|
void QxtHmac::addData(const char* data, int length)
|
||||||
|
{
|
||||||
|
Q_ASSERT(qxt_d().opad.size());
|
||||||
|
qxt_d().ihash->addData(data, length);
|
||||||
|
qxt_d().result.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Adds the provided data to the message to be authenticated.
|
||||||
|
*/
|
||||||
|
void QxtHmac::addData(const QByteArray& data)
|
||||||
|
{
|
||||||
|
addData(data.constData(), data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the HMAC of the provided data using the specified key and hashing algorithm.
|
||||||
|
*/
|
||||||
|
QByteArray QxtHmac::hash(const QByteArray& key, const QByteArray& data, Algorithm algorithm)
|
||||||
|
{
|
||||||
|
QxtHmac hmac(algorithm);
|
||||||
|
hmac.setKey(key);
|
||||||
|
hmac.addData(data);
|
||||||
|
return hmac.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Verifies a HMAC against a known key and inner hash using the specified hashing algorithm.
|
||||||
|
*/
|
||||||
|
bool QxtHmac::verify(const QByteArray& key, const QByteArray& hmac, const QByteArray& inner, Algorithm algorithm)
|
||||||
|
{
|
||||||
|
QxtHmac calc(algorithm);
|
||||||
|
calc.setKey(key);
|
||||||
|
|
||||||
|
QxtHmacPrivate* d = &calc.qxt_d();
|
||||||
|
d->ohash->reset();
|
||||||
|
d->ohash->addData(d->opad);
|
||||||
|
d->ohash->addData(inner);
|
||||||
|
return hmac == d->ohash->result();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
64
servatrice/src/smtp/qxthmac.h
Normal file
64
servatrice/src/smtp/qxthmac.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) Qxt Foundation. Some rights reserved.
|
||||||
|
**
|
||||||
|
** This file is part of the QxtCore module of the Qxt library.
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or modify it
|
||||||
|
** under the terms of the Common Public License, version 1.0, as published
|
||||||
|
** by IBM, and/or under the terms of the GNU Lesser General Public License,
|
||||||
|
** version 2.1, as published by the Free Software Foundation.
|
||||||
|
**
|
||||||
|
** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
|
||||||
|
** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the CPL and the LGPL along with this
|
||||||
|
** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
|
||||||
|
** included with the source distribution for more information.
|
||||||
|
** If you did not receive a copy of the licenses, contact the Qxt Foundation.
|
||||||
|
**
|
||||||
|
** <http://libqxt.org> <foundation@libqxt.org>
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QXTHMAC_H
|
||||||
|
#define QXTHMAC_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
#if QT_VERSION < 0x040300
|
||||||
|
# warning QxtHmac requires Qt 4.3.0 or greater
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
#include "qxtglobal.h"
|
||||||
|
|
||||||
|
class QxtHmacPrivate;
|
||||||
|
class QXT_CORE_EXPORT QxtHmac
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef QCryptographicHash::Algorithm Algorithm;
|
||||||
|
|
||||||
|
QxtHmac(QCryptographicHash::Algorithm algorithm);
|
||||||
|
|
||||||
|
void setKey(QByteArray key);
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void addData(const char* data, int length);
|
||||||
|
void addData(const QByteArray& data);
|
||||||
|
|
||||||
|
QByteArray innerHash() const;
|
||||||
|
QByteArray result();
|
||||||
|
bool verify(const QByteArray& otherInner);
|
||||||
|
|
||||||
|
static QByteArray hash(const QByteArray& key, const QByteArray& data, Algorithm algorithm);
|
||||||
|
static bool verify(const QByteArray& key, const QByteArray& hmac, const QByteArray& inner, Algorithm algorithm);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QXT_DECLARE_PRIVATE(QxtHmac)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
34
servatrice/src/smtp/qxtmail_p.h
Normal file
34
servatrice/src/smtp/qxtmail_p.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) Qxt Foundation. Some rights reserved.
|
||||||
|
**
|
||||||
|
** This file is part of the QxtWeb module of the Qxt library.
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or modify it
|
||||||
|
** under the terms of the Common Public License, version 1.0, as published
|
||||||
|
** by IBM, and/or under the terms of the GNU Lesser General Public License,
|
||||||
|
** version 2.1, as published by the Free Software Foundation.
|
||||||
|
**
|
||||||
|
** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
|
||||||
|
** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the CPL and the LGPL along with this
|
||||||
|
** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
|
||||||
|
** included with the source distribution for more information.
|
||||||
|
** If you did not receive a copy of the licenses, contact the Qxt Foundation.
|
||||||
|
**
|
||||||
|
** <http://libqxt.org> <foundation@libqxt.org>
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef QXTMAIL_P_H
|
||||||
|
#define QXTMAIL_P_H
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
|
||||||
|
#define QXT_MUST_QP(x) (x < char(32) || x > char(126) || x == '=' || x == '?')
|
||||||
|
QByteArray qxt_fold_mime_header(const QString& key, const QString& value, QTextCodec* latin1,
|
||||||
|
const QByteArray& prefix = QByteArray());
|
||||||
|
|
||||||
|
#endif // QXTMAIL_P_H
|
211
servatrice/src/smtp/qxtmailattachment.cpp
Normal file
211
servatrice/src/smtp/qxtmailattachment.cpp
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) Qxt Foundation. Some rights reserved.
|
||||||
|
**
|
||||||
|
** This file is part of the QxtWeb module of the Qxt library.
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or modify it
|
||||||
|
** under the terms of the Common Public License, version 1.0, as published
|
||||||
|
** by IBM, and/or under the terms of the GNU Lesser General Public License,
|
||||||
|
** version 2.1, as published by the Free Software Foundation.
|
||||||
|
**
|
||||||
|
** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
|
||||||
|
** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the CPL and the LGPL along with this
|
||||||
|
** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
|
||||||
|
** included with the source distribution for more information.
|
||||||
|
** If you did not receive a copy of the licenses, contact the Qxt Foundation.
|
||||||
|
**
|
||||||
|
** <http://libqxt.org> <foundation@libqxt.org>
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \class QxtMailAttachment
|
||||||
|
* \inmodule QxtNetwork
|
||||||
|
* \brief The QxtMailAttachment class represents an attachement to a QxtMailMessage
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "qxtmailattachment.h"
|
||||||
|
#include "qxtmail_p.h"
|
||||||
|
#include <QTextCodec>
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QtDebug>
|
||||||
|
|
||||||
|
struct QxtMailAttachmentPrivate : public QSharedData
|
||||||
|
{
|
||||||
|
QHash<QString, QString> extraHeaders;
|
||||||
|
QString contentType;
|
||||||
|
QPointer<QIODevice> content;
|
||||||
|
bool deleteContent;
|
||||||
|
|
||||||
|
QxtMailAttachmentPrivate()
|
||||||
|
{
|
||||||
|
content = 0;
|
||||||
|
deleteContent = false;
|
||||||
|
contentType = "text/plain";
|
||||||
|
}
|
||||||
|
|
||||||
|
~QxtMailAttachmentPrivate()
|
||||||
|
{
|
||||||
|
if (deleteContent && content)
|
||||||
|
content->deleteLater();
|
||||||
|
deleteContent = false;
|
||||||
|
content = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QxtMailAttachment::QxtMailAttachment()
|
||||||
|
{
|
||||||
|
qxt_d = new QxtMailAttachmentPrivate;
|
||||||
|
}
|
||||||
|
|
||||||
|
QxtMailAttachment::QxtMailAttachment(const QxtMailAttachment& other) : qxt_d(other.qxt_d)
|
||||||
|
{
|
||||||
|
// trivial copy constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
QxtMailAttachment::QxtMailAttachment(const QByteArray& content, const QString& contentType)
|
||||||
|
{
|
||||||
|
qxt_d = new QxtMailAttachmentPrivate;
|
||||||
|
setContentType(contentType);
|
||||||
|
setContent(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
QxtMailAttachment::QxtMailAttachment(QIODevice* content, const QString& contentType)
|
||||||
|
{
|
||||||
|
qxt_d = new QxtMailAttachmentPrivate;
|
||||||
|
setContentType(contentType);
|
||||||
|
setContent(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
QxtMailAttachment& QxtMailAttachment::operator=(const QxtMailAttachment & other)
|
||||||
|
{
|
||||||
|
qxt_d = other.qxt_d;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QxtMailAttachment::~QxtMailAttachment()
|
||||||
|
{
|
||||||
|
// trivial destructor
|
||||||
|
}
|
||||||
|
|
||||||
|
QIODevice* QxtMailAttachment::content() const
|
||||||
|
{
|
||||||
|
return qxt_d->content;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailAttachment::setContent(const QByteArray& content)
|
||||||
|
{
|
||||||
|
if (qxt_d->deleteContent && qxt_d->content)
|
||||||
|
qxt_d->content->deleteLater();
|
||||||
|
qxt_d->content = new QBuffer;
|
||||||
|
static_cast<QBuffer*>(qxt_d->content.data())->setData(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailAttachment::setContent(QIODevice* content)
|
||||||
|
{
|
||||||
|
if (qxt_d->deleteContent && qxt_d->content)
|
||||||
|
qxt_d->content->deleteLater();
|
||||||
|
qxt_d->content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QxtMailAttachment::deleteContent() const
|
||||||
|
{
|
||||||
|
return qxt_d->deleteContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailAttachment::setDeleteContent(bool enable)
|
||||||
|
{
|
||||||
|
qxt_d->deleteContent = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QxtMailAttachment::contentType() const
|
||||||
|
{
|
||||||
|
return qxt_d->contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailAttachment::setContentType(const QString& contentType)
|
||||||
|
{
|
||||||
|
qxt_d->contentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<QString, QString> QxtMailAttachment::extraHeaders() const
|
||||||
|
{
|
||||||
|
return qxt_d->extraHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QxtMailAttachment::extraHeader(const QString& key) const
|
||||||
|
{
|
||||||
|
return qxt_d->extraHeaders[key.toLower()];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QxtMailAttachment::hasExtraHeader(const QString& key) const
|
||||||
|
{
|
||||||
|
return qxt_d->extraHeaders.contains(key.toLower());
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailAttachment::setExtraHeader(const QString& key, const QString& value)
|
||||||
|
{
|
||||||
|
qxt_d->extraHeaders[key.toLower()] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailAttachment::setExtraHeaders(const QHash<QString, QString>& a)
|
||||||
|
{
|
||||||
|
QHash<QString, QString>& headers = qxt_d->extraHeaders;
|
||||||
|
headers.clear();
|
||||||
|
foreach(const QString& key, a.keys())
|
||||||
|
{
|
||||||
|
headers[key.toLower()] = a[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailAttachment::removeExtraHeader(const QString& key)
|
||||||
|
{
|
||||||
|
qxt_d->extraHeaders.remove(key.toLower());
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray QxtMailAttachment::mimeData()
|
||||||
|
{
|
||||||
|
QIODevice* c = content();
|
||||||
|
if (!c)
|
||||||
|
{
|
||||||
|
qWarning() << "QxtMailAttachment::mimeData(): Content not set or already output";
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
if (!c->isOpen() && !c->open(QIODevice::ReadOnly))
|
||||||
|
{
|
||||||
|
qWarning() << "QxtMailAttachment::mimeData(): Cannot open content for reading";
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextCodec* latin1 = QTextCodec::codecForName("latin1");
|
||||||
|
QByteArray rv = "Content-Type: " + qxt_d->contentType.toLatin1() + "\r\nContent-Transfer-Encoding: base64\r\n";
|
||||||
|
foreach(const QString& r, qxt_d->extraHeaders.keys())
|
||||||
|
{
|
||||||
|
rv += qxt_fold_mime_header(r.toLatin1(), extraHeader(r), latin1);
|
||||||
|
}
|
||||||
|
rv += "\r\n";
|
||||||
|
|
||||||
|
while (!c->atEnd())
|
||||||
|
{
|
||||||
|
rv += c->read(57).toBase64() + "\r\n";
|
||||||
|
}
|
||||||
|
setContent((QIODevice*)0);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
QxtMailAttachment QxtMailAttachment::fromFile(const QString& filename)
|
||||||
|
{
|
||||||
|
QxtMailAttachment rv(new QFile(filename));
|
||||||
|
rv.setDeleteContent(true);
|
||||||
|
return rv;
|
||||||
|
}
|
73
servatrice/src/smtp/qxtmailattachment.h
Normal file
73
servatrice/src/smtp/qxtmailattachment.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) Qxt Foundation. Some rights reserved.
|
||||||
|
**
|
||||||
|
** This file is part of the QxtWeb module of the Qxt library.
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or modify it
|
||||||
|
** under the terms of the Common Public License, version 1.0, as published
|
||||||
|
** by IBM, and/or under the terms of the GNU Lesser General Public License,
|
||||||
|
** version 2.1, as published by the Free Software Foundation.
|
||||||
|
**
|
||||||
|
** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
|
||||||
|
** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the CPL and the LGPL along with this
|
||||||
|
** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
|
||||||
|
** included with the source distribution for more information.
|
||||||
|
** If you did not receive a copy of the licenses, contact the Qxt Foundation.
|
||||||
|
**
|
||||||
|
** <http://libqxt.org> <foundation@libqxt.org>
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef QXTMAILATTACHMENT_H
|
||||||
|
#define QXTMAILATTACHMENT_H
|
||||||
|
|
||||||
|
#include "qxtglobal.h"
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QMetaType>
|
||||||
|
#include <QSharedDataPointer>
|
||||||
|
#include <QIODevice>
|
||||||
|
|
||||||
|
class QxtMailAttachmentPrivate;
|
||||||
|
class QXT_NETWORK_EXPORT QxtMailAttachment
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QxtMailAttachment();
|
||||||
|
QxtMailAttachment(const QxtMailAttachment& other);
|
||||||
|
QxtMailAttachment(const QByteArray& content, const QString& contentType = QString("application/octet-stream"));
|
||||||
|
QxtMailAttachment(QIODevice* content, const QString& contentType = QString("application/octet-stream"));
|
||||||
|
QxtMailAttachment& operator=(const QxtMailAttachment& other);
|
||||||
|
~QxtMailAttachment();
|
||||||
|
static QxtMailAttachment fromFile(const QString& filename);
|
||||||
|
|
||||||
|
QIODevice* content() const;
|
||||||
|
void setContent(const QByteArray& content);
|
||||||
|
void setContent(QIODevice* content);
|
||||||
|
|
||||||
|
bool deleteContent() const;
|
||||||
|
void setDeleteContent(bool enable);
|
||||||
|
|
||||||
|
QString contentType() const;
|
||||||
|
void setContentType(const QString& contentType);
|
||||||
|
|
||||||
|
QHash<QString, QString> extraHeaders() const;
|
||||||
|
QString extraHeader(const QString&) const;
|
||||||
|
bool hasExtraHeader(const QString&) const;
|
||||||
|
void setExtraHeader(const QString& key, const QString& value);
|
||||||
|
void setExtraHeaders(const QHash<QString, QString>&);
|
||||||
|
void removeExtraHeader(const QString& key);
|
||||||
|
|
||||||
|
QByteArray mimeData();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSharedDataPointer<QxtMailAttachmentPrivate> qxt_d;
|
||||||
|
};
|
||||||
|
Q_DECLARE_TYPEINFO(QxtMailAttachment, Q_MOVABLE_TYPE);
|
||||||
|
|
||||||
|
#endif // QXTMAILATTACHMENT_H
|
537
servatrice/src/smtp/qxtmailmessage.cpp
Normal file
537
servatrice/src/smtp/qxtmailmessage.cpp
Normal file
|
@ -0,0 +1,537 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) Qxt Foundation. Some rights reserved.
|
||||||
|
**
|
||||||
|
** This file is part of the QxtWeb module of the Qxt library.
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or modify it
|
||||||
|
** under the terms of the Common Public License, version 1.0, as published
|
||||||
|
** by IBM, and/or under the terms of the GNU Lesser General Public License,
|
||||||
|
** version 2.1, as published by the Free Software Foundation.
|
||||||
|
**
|
||||||
|
** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
|
||||||
|
** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the CPL and the LGPL along with this
|
||||||
|
** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
|
||||||
|
** included with the source distribution for more information.
|
||||||
|
** If you did not receive a copy of the licenses, contact the Qxt Foundation.
|
||||||
|
**
|
||||||
|
** <http://libqxt.org> <foundation@libqxt.org>
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \class QxtMailMessage
|
||||||
|
* \inmodule QxtNetwork
|
||||||
|
* \brief The QxtMailMessage class encapsulates an e-mail according to RFC 2822 and related specifications
|
||||||
|
* TODO: {implicitshared}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "qxtmailmessage.h"
|
||||||
|
#include "qxtmail_p.h"
|
||||||
|
#include <QTextCodec>
|
||||||
|
#include <QUuid>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QtDebug>
|
||||||
|
|
||||||
|
|
||||||
|
struct QxtMailMessagePrivate : public QSharedData
|
||||||
|
{
|
||||||
|
QxtMailMessagePrivate() {}
|
||||||
|
QxtMailMessagePrivate(const QxtMailMessagePrivate& other)
|
||||||
|
: QSharedData(other), rcptTo(other.rcptTo), rcptCc(other.rcptCc), rcptBcc(other.rcptBcc),
|
||||||
|
subject(other.subject), body(other.body), sender(other.sender),
|
||||||
|
extraHeaders(other.extraHeaders), attachments(other.attachments) {}
|
||||||
|
QStringList rcptTo, rcptCc, rcptBcc;
|
||||||
|
QString subject, body, sender;
|
||||||
|
QHash<QString, QString> extraHeaders;
|
||||||
|
QHash<QString, QxtMailAttachment> attachments;
|
||||||
|
mutable QByteArray boundary;
|
||||||
|
};
|
||||||
|
|
||||||
|
QxtMailMessage::QxtMailMessage()
|
||||||
|
{
|
||||||
|
qxt_d = new QxtMailMessagePrivate;
|
||||||
|
}
|
||||||
|
|
||||||
|
QxtMailMessage::QxtMailMessage(const QxtMailMessage& other) : qxt_d(other.qxt_d)
|
||||||
|
{
|
||||||
|
// trivial copy constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
QxtMailMessage::QxtMailMessage(const QString& sender, const QString& recipient)
|
||||||
|
{
|
||||||
|
qxt_d = new QxtMailMessagePrivate;
|
||||||
|
setSender(sender);
|
||||||
|
addRecipient(recipient);
|
||||||
|
}
|
||||||
|
|
||||||
|
QxtMailMessage::~QxtMailMessage()
|
||||||
|
{
|
||||||
|
// trivial destructor
|
||||||
|
}
|
||||||
|
|
||||||
|
QxtMailMessage& QxtMailMessage::operator=(const QxtMailMessage & other)
|
||||||
|
{
|
||||||
|
qxt_d = other.qxt_d;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QxtMailMessage::sender() const
|
||||||
|
{
|
||||||
|
return qxt_d->sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailMessage::setSender(const QString& a)
|
||||||
|
{
|
||||||
|
qxt_d->sender = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QxtMailMessage::subject() const
|
||||||
|
{
|
||||||
|
return qxt_d->subject;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailMessage::setSubject(const QString& a)
|
||||||
|
{
|
||||||
|
qxt_d->subject = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QxtMailMessage::body() const
|
||||||
|
{
|
||||||
|
return qxt_d->body;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailMessage::setBody(const QString& a)
|
||||||
|
{
|
||||||
|
qxt_d->body = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList QxtMailMessage::recipients(QxtMailMessage::RecipientType type) const
|
||||||
|
{
|
||||||
|
if (type == Bcc)
|
||||||
|
return qxt_d->rcptBcc;
|
||||||
|
if (type == Cc)
|
||||||
|
return qxt_d->rcptCc;
|
||||||
|
return qxt_d->rcptTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailMessage::addRecipient(const QString& a, QxtMailMessage::RecipientType type)
|
||||||
|
{
|
||||||
|
if (type == Bcc)
|
||||||
|
qxt_d->rcptBcc.append(a);
|
||||||
|
else if (type == Cc)
|
||||||
|
qxt_d->rcptCc.append(a);
|
||||||
|
else
|
||||||
|
qxt_d->rcptTo.append(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailMessage::removeRecipient(const QString& a)
|
||||||
|
{
|
||||||
|
qxt_d->rcptTo.removeAll(a);
|
||||||
|
qxt_d->rcptCc.removeAll(a);
|
||||||
|
qxt_d->rcptBcc.removeAll(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<QString, QString> QxtMailMessage::extraHeaders() const
|
||||||
|
{
|
||||||
|
return qxt_d->extraHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QxtMailMessage::extraHeader(const QString& key) const
|
||||||
|
{
|
||||||
|
return qxt_d->extraHeaders[key.toLower()];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QxtMailMessage::hasExtraHeader(const QString& key) const
|
||||||
|
{
|
||||||
|
return qxt_d->extraHeaders.contains(key.toLower());
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailMessage::setExtraHeader(const QString& key, const QString& value)
|
||||||
|
{
|
||||||
|
qxt_d->extraHeaders[key.toLower()] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailMessage::setExtraHeaders(const QHash<QString, QString>& a)
|
||||||
|
{
|
||||||
|
QHash<QString, QString>& headers = qxt_d->extraHeaders;
|
||||||
|
headers.clear();
|
||||||
|
foreach(const QString& key, a.keys())
|
||||||
|
{
|
||||||
|
headers[key.toLower()] = a[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailMessage::removeExtraHeader(const QString& key)
|
||||||
|
{
|
||||||
|
qxt_d->extraHeaders.remove(key.toLower());
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<QString, QxtMailAttachment> QxtMailMessage::attachments() const
|
||||||
|
{
|
||||||
|
return qxt_d->attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
QxtMailAttachment QxtMailMessage::attachment(const QString& filename) const
|
||||||
|
{
|
||||||
|
return qxt_d->attachments[filename];
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailMessage::addAttachment(const QString& filename, const QxtMailAttachment& attach)
|
||||||
|
{
|
||||||
|
if (qxt_d->attachments.contains(filename))
|
||||||
|
{
|
||||||
|
qWarning() << "QxtMailMessage::addAttachment: " << filename << " already in use";
|
||||||
|
int i = 1;
|
||||||
|
while (qxt_d->attachments.contains(filename + "." + QString::number(i)))
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
qxt_d->attachments[filename+"."+QString::number(i)] = attach;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qxt_d->attachments[filename] = attach;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtMailMessage::removeAttachment(const QString& filename)
|
||||||
|
{
|
||||||
|
qxt_d->attachments.remove(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray qxt_fold_mime_header(const QString& key, const QString& value, QTextCodec* latin1, const QByteArray& prefix)
|
||||||
|
{
|
||||||
|
QByteArray rv = "";
|
||||||
|
QByteArray line = key.toLatin1() + ": ";
|
||||||
|
if (!prefix.isEmpty()) line += prefix;
|
||||||
|
if (!value.contains("=?") && latin1->canEncode(value))
|
||||||
|
{
|
||||||
|
bool firstWord = true;
|
||||||
|
foreach(const QByteArray& word, value.toLatin1().split(' '))
|
||||||
|
{
|
||||||
|
if (line.size() > 78)
|
||||||
|
{
|
||||||
|
rv = rv + line + "\r\n";
|
||||||
|
line.clear();
|
||||||
|
}
|
||||||
|
if (firstWord)
|
||||||
|
line += word;
|
||||||
|
else
|
||||||
|
line += " " + word;
|
||||||
|
firstWord = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The text cannot be losslessly encoded as Latin-1. Therefore, we
|
||||||
|
// must use quoted-printable or base64 encoding. This is a quick
|
||||||
|
// heuristic based on the first 100 characters to see which
|
||||||
|
// encoding to use.
|
||||||
|
QByteArray utf8 = value.toUtf8();
|
||||||
|
int ct = utf8.length();
|
||||||
|
int nonAscii = 0;
|
||||||
|
for (int i = 0; i < ct && i < 100; i++)
|
||||||
|
{
|
||||||
|
if (QXT_MUST_QP(utf8[i])) nonAscii++;
|
||||||
|
}
|
||||||
|
if (nonAscii > 20)
|
||||||
|
{
|
||||||
|
// more than 20%-ish non-ASCII characters: use base64
|
||||||
|
QByteArray base64 = utf8.toBase64();
|
||||||
|
ct = base64.length();
|
||||||
|
line += "=?utf-8?b?";
|
||||||
|
for (int i = 0; i < ct; i += 4)
|
||||||
|
{
|
||||||
|
if (line.length() > 72)
|
||||||
|
{
|
||||||
|
rv += line + "?\r\n";
|
||||||
|
line = " =?utf-8?b?";
|
||||||
|
}
|
||||||
|
line = line + base64.mid(i, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// otherwise use Q-encoding
|
||||||
|
line += "=?utf-8?q?";
|
||||||
|
for (int i = 0; i < ct; i++)
|
||||||
|
{
|
||||||
|
if (line.length() > 73)
|
||||||
|
{
|
||||||
|
rv += line + "?\r\n";
|
||||||
|
line = " =?utf-8?q?";
|
||||||
|
}
|
||||||
|
if (QXT_MUST_QP(utf8[i]) || utf8[i] == ' ')
|
||||||
|
{
|
||||||
|
line += "=" + utf8.mid(i, 1).toHex().toUpper();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line += utf8[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
line += "?="; // end encoded-word atom
|
||||||
|
}
|
||||||
|
return rv + line + "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray QxtMailMessage::rfc2822() const
|
||||||
|
{
|
||||||
|
// Use quoted-printable if requested
|
||||||
|
bool useQuotedPrintable = (extraHeader("Content-Transfer-Encoding").toLower() == "quoted-printable");
|
||||||
|
// Use base64 if requested
|
||||||
|
bool useBase64 = (extraHeader("Content-Transfer-Encoding").toLower() == "base64");
|
||||||
|
// Check to see if plain text is ASCII-clean; assume it isn't if QP or base64 was requested
|
||||||
|
QTextCodec* latin1 = QTextCodec::codecForName("latin1");
|
||||||
|
bool bodyIsAscii = latin1->canEncode(body()) && !useQuotedPrintable && !useBase64;
|
||||||
|
|
||||||
|
QHash<QString, QxtMailAttachment> attach = attachments();
|
||||||
|
QByteArray rv;
|
||||||
|
|
||||||
|
if (!sender().isEmpty() && !hasExtraHeader("From"))
|
||||||
|
{
|
||||||
|
rv += qxt_fold_mime_header("From", sender(), latin1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!qxt_d->rcptTo.isEmpty())
|
||||||
|
{
|
||||||
|
rv += qxt_fold_mime_header("To", qxt_d->rcptTo.join(", "), latin1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!qxt_d->rcptCc.isEmpty())
|
||||||
|
{
|
||||||
|
rv += qxt_fold_mime_header("Cc", qxt_d->rcptCc.join(", "), latin1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!subject().isEmpty())
|
||||||
|
{
|
||||||
|
rv += qxt_fold_mime_header("Subject", subject(), latin1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bodyIsAscii)
|
||||||
|
{
|
||||||
|
if (!hasExtraHeader("MIME-Version") && !attach.count())
|
||||||
|
rv += "MIME-Version: 1.0\r\n";
|
||||||
|
|
||||||
|
// If no transfer encoding has been requested, guess.
|
||||||
|
// Heuristic: If >20% of the first 100 characters aren't
|
||||||
|
// 7-bit clean, use base64, otherwise use Q-P.
|
||||||
|
if(!bodyIsAscii && !useQuotedPrintable && !useBase64)
|
||||||
|
{
|
||||||
|
QString b = body();
|
||||||
|
int nonAscii = 0;
|
||||||
|
int ct = b.length();
|
||||||
|
for (int i = 0; i < ct && i < 100; i++)
|
||||||
|
{
|
||||||
|
if (QXT_MUST_QP(b[i])) nonAscii++;
|
||||||
|
}
|
||||||
|
useQuotedPrintable = !(nonAscii > 20);
|
||||||
|
useBase64 = !useQuotedPrintable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attach.count())
|
||||||
|
{
|
||||||
|
if (qxt_d->boundary.isEmpty())
|
||||||
|
qxt_d->boundary = QUuid::createUuid().toString().toLatin1().replace("{", "").replace("}", "");
|
||||||
|
if (!hasExtraHeader("MIME-Version"))
|
||||||
|
rv += "MIME-Version: 1.0\r\n";
|
||||||
|
if (!hasExtraHeader("Content-Type"))
|
||||||
|
rv += "Content-Type: multipart/mixed; boundary=" + qxt_d->boundary + "\r\n";
|
||||||
|
}
|
||||||
|
else if (!bodyIsAscii && !hasExtraHeader("Content-Transfer-Encoding"))
|
||||||
|
{
|
||||||
|
if (!useQuotedPrintable)
|
||||||
|
{
|
||||||
|
// base64
|
||||||
|
rv += "Content-Transfer-Encoding: base64\r\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// quoted-printable
|
||||||
|
rv += "Content-Transfer-Encoding: quoted-printable\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(const QString& r, qxt_d->extraHeaders.keys())
|
||||||
|
{
|
||||||
|
if ((r.toLower() == "content-type" || r.toLower() == "content-transfer-encoding") && attach.count())
|
||||||
|
{
|
||||||
|
// Since we're in multipart mode, we'll be outputting this later
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rv += qxt_fold_mime_header(r.toLatin1(), extraHeader(r), latin1);
|
||||||
|
}
|
||||||
|
|
||||||
|
rv += "\r\n";
|
||||||
|
|
||||||
|
if (attach.count())
|
||||||
|
{
|
||||||
|
// we're going to have attachments, so output the lead-in for the message body
|
||||||
|
rv += "This is a message with multiple parts in MIME format.\r\n";
|
||||||
|
rv += "--" + qxt_d->boundary + "\r\nContent-Type: ";
|
||||||
|
if (hasExtraHeader("Content-Type"))
|
||||||
|
rv += extraHeader("Content-Type") + "\r\n";
|
||||||
|
else
|
||||||
|
rv += "text/plain; charset=UTF-8\r\n";
|
||||||
|
if (hasExtraHeader("Content-Transfer-Encoding"))
|
||||||
|
{
|
||||||
|
rv += "Content-Transfer-Encoding: " + extraHeader("Content-Transfer-Encoding") + "\r\n";
|
||||||
|
}
|
||||||
|
else if (!bodyIsAscii)
|
||||||
|
{
|
||||||
|
if (!useQuotedPrintable)
|
||||||
|
{
|
||||||
|
// base64
|
||||||
|
rv += "Content-Transfer-Encoding: base64\r\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// quoted-printable
|
||||||
|
rv += "Content-Transfer-Encoding: quoted-printable\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rv += "\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bodyIsAscii)
|
||||||
|
{
|
||||||
|
QByteArray b = latin1->fromUnicode(body());
|
||||||
|
int len = b.length();
|
||||||
|
QByteArray line = "";
|
||||||
|
QByteArray word = "";
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
if (b[i] == '\n' || b[i] == '\r')
|
||||||
|
{
|
||||||
|
if (line.isEmpty())
|
||||||
|
{
|
||||||
|
line = word;
|
||||||
|
word = "";
|
||||||
|
}
|
||||||
|
else if (line.length() + word.length() + 1 <= 78)
|
||||||
|
{
|
||||||
|
line = line + ' ' + word;
|
||||||
|
word = "";
|
||||||
|
}
|
||||||
|
if(line[0] == '.')
|
||||||
|
rv += ".";
|
||||||
|
rv += line + "\r\n";
|
||||||
|
if ((b[i+1] == '\n' || b[i+1] == '\r') && b[i] != b[i+1])
|
||||||
|
{
|
||||||
|
// If we're looking at a CRLF pair, skip the second half
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
line = word;
|
||||||
|
}
|
||||||
|
else if (b[i] == ' ')
|
||||||
|
{
|
||||||
|
if (line.length() + word.length() + 1 > 78)
|
||||||
|
{
|
||||||
|
if(line[0] == '.')
|
||||||
|
rv += ".";
|
||||||
|
rv += line + "\r\n";
|
||||||
|
line = word;
|
||||||
|
}
|
||||||
|
else if (line.isEmpty())
|
||||||
|
{
|
||||||
|
line = word;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line = line + ' ' + word;
|
||||||
|
}
|
||||||
|
word = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
word += b[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (line.length() + word.length() + 1 > 78)
|
||||||
|
{
|
||||||
|
if(line[0] == '.')
|
||||||
|
rv += ".";
|
||||||
|
rv += line + "\r\n";
|
||||||
|
line = word;
|
||||||
|
}
|
||||||
|
else if (!word.isEmpty())
|
||||||
|
{
|
||||||
|
line += ' ' + word;
|
||||||
|
}
|
||||||
|
if(!line.isEmpty()) {
|
||||||
|
if(line[0] == '.')
|
||||||
|
rv += ".";
|
||||||
|
rv += line + "\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (useQuotedPrintable)
|
||||||
|
{
|
||||||
|
QByteArray b = body().toUtf8();
|
||||||
|
int ct = b.length();
|
||||||
|
QByteArray line;
|
||||||
|
for (int i = 0; i < ct; i++)
|
||||||
|
{
|
||||||
|
if(b[i] == '\n' || b[i] == '\r')
|
||||||
|
{
|
||||||
|
if(line[0] == '.')
|
||||||
|
rv += ".";
|
||||||
|
rv += line + "\r\n";
|
||||||
|
line = "";
|
||||||
|
if ((b[i+1] == '\n' || b[i+1] == '\r') && b[i] != b[i+1])
|
||||||
|
{
|
||||||
|
// If we're looking at a CRLF pair, skip the second half
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (line.length() > 74)
|
||||||
|
{
|
||||||
|
rv += line + "=\r\n";
|
||||||
|
line = "";
|
||||||
|
}
|
||||||
|
if (QXT_MUST_QP(b[i]))
|
||||||
|
{
|
||||||
|
line += "=" + b.mid(i, 1).toHex().toUpper();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line += b[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!line.isEmpty()) {
|
||||||
|
if(line[0] == '.')
|
||||||
|
rv += ".";
|
||||||
|
rv += line + "\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* base64 */
|
||||||
|
{
|
||||||
|
QByteArray b = body().toUtf8().toBase64();
|
||||||
|
int ct = b.length();
|
||||||
|
for (int i = 0; i < ct; i += 78)
|
||||||
|
{
|
||||||
|
rv += b.mid(i, 78) + "\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attach.count())
|
||||||
|
{
|
||||||
|
foreach(const QString& filename, attach.keys())
|
||||||
|
{
|
||||||
|
rv += "--" + qxt_d->boundary + "\r\n";
|
||||||
|
rv += qxt_fold_mime_header("Content-Disposition", QDir(filename).dirName(), latin1, "attachment; filename=");
|
||||||
|
rv += attach[filename].mimeData();
|
||||||
|
}
|
||||||
|
rv += "--" + qxt_d->boundary + "--\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
85
servatrice/src/smtp/qxtmailmessage.h
Normal file
85
servatrice/src/smtp/qxtmailmessage.h
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) Qxt Foundation. Some rights reserved.
|
||||||
|
**
|
||||||
|
** This file is part of the QxtWeb module of the Qxt library.
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or modify it
|
||||||
|
** under the terms of the Common Public License, version 1.0, as published
|
||||||
|
** by IBM, and/or under the terms of the GNU Lesser General Public License,
|
||||||
|
** version 2.1, as published by the Free Software Foundation.
|
||||||
|
**
|
||||||
|
** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
|
||||||
|
** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the CPL and the LGPL along with this
|
||||||
|
** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
|
||||||
|
** included with the source distribution for more information.
|
||||||
|
** If you did not receive a copy of the licenses, contact the Qxt Foundation.
|
||||||
|
**
|
||||||
|
** <http://libqxt.org> <foundation@libqxt.org>
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef QXTMAILMESSAGE_H
|
||||||
|
#define QXTMAILMESSAGE_H
|
||||||
|
|
||||||
|
#include "qxtglobal.h"
|
||||||
|
#include "qxtmailattachment.h"
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QMetaType>
|
||||||
|
#include <QSharedDataPointer>
|
||||||
|
|
||||||
|
struct QxtMailMessagePrivate;
|
||||||
|
class QXT_NETWORK_EXPORT QxtMailMessage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum RecipientType
|
||||||
|
{
|
||||||
|
To,
|
||||||
|
Cc,
|
||||||
|
Bcc
|
||||||
|
};
|
||||||
|
|
||||||
|
QxtMailMessage();
|
||||||
|
QxtMailMessage(const QxtMailMessage& other);
|
||||||
|
QxtMailMessage(const QString& sender, const QString& recipient);
|
||||||
|
QxtMailMessage& operator=(const QxtMailMessage& other);
|
||||||
|
~QxtMailMessage();
|
||||||
|
|
||||||
|
QString sender() const;
|
||||||
|
void setSender(const QString&);
|
||||||
|
|
||||||
|
QString subject() const;
|
||||||
|
void setSubject(const QString&);
|
||||||
|
|
||||||
|
QString body() const;
|
||||||
|
void setBody(const QString&);
|
||||||
|
|
||||||
|
QStringList recipients(RecipientType type = To) const;
|
||||||
|
void addRecipient(const QString&, RecipientType type = To);
|
||||||
|
void removeRecipient(const QString&);
|
||||||
|
|
||||||
|
QHash<QString, QString> extraHeaders() const;
|
||||||
|
QString extraHeader(const QString&) const;
|
||||||
|
bool hasExtraHeader(const QString&) const;
|
||||||
|
void setExtraHeader(const QString& key, const QString& value);
|
||||||
|
void setExtraHeaders(const QHash<QString, QString>&);
|
||||||
|
void removeExtraHeader(const QString& key);
|
||||||
|
|
||||||
|
QHash<QString, QxtMailAttachment> attachments() const;
|
||||||
|
QxtMailAttachment attachment(const QString& filename) const;
|
||||||
|
void addAttachment(const QString& filename, const QxtMailAttachment& attach);
|
||||||
|
void removeAttachment(const QString& filename);
|
||||||
|
|
||||||
|
QByteArray rfc2822() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSharedDataPointer<QxtMailMessagePrivate> qxt_d;
|
||||||
|
};
|
||||||
|
Q_DECLARE_TYPEINFO(QxtMailMessage, Q_MOVABLE_TYPE);
|
||||||
|
|
||||||
|
#endif // QXTMAIL_H
|
617
servatrice/src/smtp/qxtsmtp.cpp
Normal file
617
servatrice/src/smtp/qxtsmtp.cpp
Normal file
|
@ -0,0 +1,617 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) Qxt Foundation. Some rights reserved.
|
||||||
|
**
|
||||||
|
** This file is part of the QxtWeb module of the Qxt library.
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or modify it
|
||||||
|
** under the terms of the Common Public License, version 1.0, as published
|
||||||
|
** by IBM, and/or under the terms of the GNU Lesser General Public License,
|
||||||
|
** version 2.1, as published by the Free Software Foundation.
|
||||||
|
**
|
||||||
|
** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
|
||||||
|
** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the CPL and the LGPL along with this
|
||||||
|
** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
|
||||||
|
** included with the source distribution for more information.
|
||||||
|
** If you did not receive a copy of the licenses, contact the Qxt Foundation.
|
||||||
|
**
|
||||||
|
** <http://libqxt.org> <foundation@libqxt.org>
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \class QxtSmtp
|
||||||
|
* \inmodule QxtNetwork
|
||||||
|
* \brief The QxtSmtp class implements the SMTP protocol for sending email
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "qxtsmtp.h"
|
||||||
|
#include "qxtsmtp_p.h"
|
||||||
|
#include "qxthmac.h"
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QNetworkInterface>
|
||||||
|
#include <QSslSocket>
|
||||||
|
|
||||||
|
QxtSmtpPrivate::QxtSmtpPrivate() : QObject(0)
|
||||||
|
{
|
||||||
|
// empty ctor
|
||||||
|
}
|
||||||
|
|
||||||
|
QxtSmtp::QxtSmtp(QObject* parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
QXT_INIT_PRIVATE(QxtSmtp);
|
||||||
|
qxt_d().state = QxtSmtpPrivate::Disconnected;
|
||||||
|
qxt_d().nextID = 0;
|
||||||
|
qxt_d().socket = new QSslSocket(this);
|
||||||
|
QObject::connect(socket(), SIGNAL(encrypted()), this, SIGNAL(encrypted()));
|
||||||
|
//QObject::connect(socket(), SIGNAL(encrypted()), &qxt_d(), SLOT(ehlo()));
|
||||||
|
QObject::connect(socket(), SIGNAL(connected()), this, SIGNAL(connected()));
|
||||||
|
QObject::connect(socket(), SIGNAL(disconnected()), this, SIGNAL(disconnected()));
|
||||||
|
QObject::connect(socket(), SIGNAL(error(QAbstractSocket::SocketError)), &qxt_d(), SLOT(socketError(QAbstractSocket::SocketError)));
|
||||||
|
QObject::connect(this, SIGNAL(authenticated()), &qxt_d(), SLOT(sendNext()));
|
||||||
|
QObject::connect(socket(), SIGNAL(readyRead()), &qxt_d(), SLOT(socketRead()));
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray QxtSmtp::username() const
|
||||||
|
{
|
||||||
|
return qxt_d().username;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtp::setUsername(const QByteArray& username)
|
||||||
|
{
|
||||||
|
qxt_d().username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray QxtSmtp::password() const
|
||||||
|
{
|
||||||
|
return qxt_d().password;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtp::setPassword(const QByteArray& password)
|
||||||
|
{
|
||||||
|
qxt_d().password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
int QxtSmtp::send(const QxtMailMessage& message)
|
||||||
|
{
|
||||||
|
int messageID = ++qxt_d().nextID;
|
||||||
|
qxt_d().pending.append(qMakePair(messageID, message));
|
||||||
|
if (qxt_d().state == QxtSmtpPrivate::Waiting)
|
||||||
|
qxt_d().sendNext();
|
||||||
|
return messageID;
|
||||||
|
}
|
||||||
|
|
||||||
|
int QxtSmtp::pendingMessages() const
|
||||||
|
{
|
||||||
|
return qxt_d().pending.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
QTcpSocket* QxtSmtp::socket() const
|
||||||
|
{
|
||||||
|
return qxt_d().socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtp::connectToHost(const QString& hostName, quint16 port)
|
||||||
|
{
|
||||||
|
qxt_d().useSecure = false;
|
||||||
|
qxt_d().state = QxtSmtpPrivate::StartState;
|
||||||
|
socket()->connectToHost(hostName, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtp::connectToHost(const QHostAddress& address, quint16 port)
|
||||||
|
{
|
||||||
|
connectToHost(address.toString(), port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtp::disconnectFromHost()
|
||||||
|
{
|
||||||
|
socket()->disconnectFromHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QxtSmtp::startTlsDisabled() const
|
||||||
|
{
|
||||||
|
return qxt_d().disableStartTLS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtp::setStartTlsDisabled(bool disable)
|
||||||
|
{
|
||||||
|
qxt_d().disableStartTLS = disable;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSslSocket* QxtSmtp::sslSocket() const
|
||||||
|
{
|
||||||
|
return qxt_d().socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtp::connectToSecureHost(const QString& hostName, quint16 port)
|
||||||
|
{
|
||||||
|
qxt_d().useSecure = true;
|
||||||
|
qxt_d().state = QxtSmtpPrivate::StartState;
|
||||||
|
sslSocket()->connectToHostEncrypted(hostName, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtp::connectToSecureHost(const QHostAddress& address, quint16 port)
|
||||||
|
{
|
||||||
|
connectToSecureHost(address.toString(), port);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QxtSmtp::hasExtension(const QString& extension)
|
||||||
|
{
|
||||||
|
return qxt_d().extensions.contains(extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QxtSmtp::extensionData(const QString& extension)
|
||||||
|
{
|
||||||
|
return qxt_d().extensions[extension];
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtpPrivate::socketError(QAbstractSocket::SocketError err)
|
||||||
|
{
|
||||||
|
if (err == QAbstractSocket::SslHandshakeFailedError)
|
||||||
|
{
|
||||||
|
emit qxt_p().encryptionFailed();
|
||||||
|
emit qxt_p().encryptionFailed( socket->errorString().toLatin1() );
|
||||||
|
}
|
||||||
|
else if (state == StartState)
|
||||||
|
{
|
||||||
|
emit qxt_p().connectionFailed();
|
||||||
|
emit qxt_p().connectionFailed( socket->errorString().toLatin1() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtpPrivate::socketRead()
|
||||||
|
{
|
||||||
|
buffer += socket->readAll();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int pos = buffer.indexOf("\r\n");
|
||||||
|
if (pos < 0) return;
|
||||||
|
QByteArray line = buffer.left(pos);
|
||||||
|
buffer = buffer.mid(pos + 2);
|
||||||
|
QByteArray code = line.left(3);
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case StartState:
|
||||||
|
if (code[0] != '2')
|
||||||
|
{
|
||||||
|
socket->disconnectFromHost();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ehlo();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HeloSent:
|
||||||
|
case EhloSent:
|
||||||
|
case EhloGreetReceived:
|
||||||
|
parseEhlo(code, (line[3] != ' '), line.mid(4));
|
||||||
|
break;
|
||||||
|
case StartTLSSent:
|
||||||
|
if (code == "220")
|
||||||
|
{
|
||||||
|
socket->startClientEncryption();
|
||||||
|
ehlo();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
authenticate();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AuthRequestSent:
|
||||||
|
case AuthUsernameSent:
|
||||||
|
if (authType == AuthPlain) authPlain();
|
||||||
|
else if (authType == AuthLogin) authLogin();
|
||||||
|
else authCramMD5(line.mid(4));
|
||||||
|
break;
|
||||||
|
case AuthSent:
|
||||||
|
if (code[0] == '2')
|
||||||
|
{
|
||||||
|
state = Authenticated;
|
||||||
|
emit qxt_p().authenticated();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state = Disconnected;
|
||||||
|
emit qxt_p().authenticationFailed();
|
||||||
|
emit qxt_p().authenticationFailed( line );
|
||||||
|
emit socket->disconnectFromHost();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MailToSent:
|
||||||
|
case RcptAckPending:
|
||||||
|
if (code[0] != '2') {
|
||||||
|
emit qxt_p().mailFailed( pending.first().first, code.toInt() );
|
||||||
|
emit qxt_p().mailFailed(pending.first().first, code.toInt(), line);
|
||||||
|
// pending.removeFirst();
|
||||||
|
// DO NOT remove it, the body sent state needs this message to assigned the next mail failed message that will
|
||||||
|
// the sendNext
|
||||||
|
// a reset will be sent to clear things out
|
||||||
|
sendNext();
|
||||||
|
state = BodySent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sendNextRcpt(code, line);
|
||||||
|
break;
|
||||||
|
case SendingBody:
|
||||||
|
sendBody(code, line);
|
||||||
|
break;
|
||||||
|
case BodySent:
|
||||||
|
if ( pending.count() )
|
||||||
|
{
|
||||||
|
// if you removeFirst in RcpActpending/MailToSent on an error, and the queue is now empty,
|
||||||
|
// you will get into this state and then crash because no check is done. CHeck added but shouldnt
|
||||||
|
// be necessary since I commented out the removeFirst
|
||||||
|
if (code[0] != '2')
|
||||||
|
{
|
||||||
|
emit qxt_p().mailFailed(pending.first().first, code.toInt() );
|
||||||
|
emit qxt_p().mailFailed(pending.first().first, code.toInt(), line);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
emit qxt_p().mailSent(pending.first().first);
|
||||||
|
pending.removeFirst();
|
||||||
|
}
|
||||||
|
sendNext();
|
||||||
|
break;
|
||||||
|
case Resetting:
|
||||||
|
if (code[0] != '2') {
|
||||||
|
emit qxt_p().connectionFailed();
|
||||||
|
emit qxt_p().connectionFailed( line );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
state = Waiting;
|
||||||
|
sendNext();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Disconnected:
|
||||||
|
case EhloExtensionsReceived:
|
||||||
|
case EhloDone:
|
||||||
|
case Authenticated:
|
||||||
|
case Waiting:
|
||||||
|
// only to make compiler happy
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtpPrivate::ehlo()
|
||||||
|
{
|
||||||
|
QByteArray address = "127.0.0.1";
|
||||||
|
foreach(const QHostAddress& addr, QNetworkInterface::allAddresses())
|
||||||
|
{
|
||||||
|
if (addr == QHostAddress::LocalHost || addr == QHostAddress::LocalHostIPv6)
|
||||||
|
continue;
|
||||||
|
address = addr.toString().toLatin1();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
socket->write("ehlo " + address + "\r\n");
|
||||||
|
extensions.clear();
|
||||||
|
state = EhloSent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtpPrivate::parseEhlo(const QByteArray& code, bool cont, const QString& line)
|
||||||
|
{
|
||||||
|
if (code != "250")
|
||||||
|
{
|
||||||
|
// error!
|
||||||
|
if (state != HeloSent)
|
||||||
|
{
|
||||||
|
// maybe let's try HELO
|
||||||
|
socket->write("helo\r\n");
|
||||||
|
state = HeloSent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// nope
|
||||||
|
socket->write("QUIT\r\n");
|
||||||
|
socket->flush();
|
||||||
|
socket->disconnectFromHost();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (state != EhloGreetReceived)
|
||||||
|
{
|
||||||
|
if (!cont)
|
||||||
|
{
|
||||||
|
// greeting only, no extensions
|
||||||
|
state = EhloDone;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// greeting followed by extensions
|
||||||
|
state = EhloGreetReceived;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
extensions[line.section(' ', 0, 0).toUpper()] = line.section(' ', 1);
|
||||||
|
if (!cont)
|
||||||
|
state = EhloDone;
|
||||||
|
}
|
||||||
|
if (state != EhloDone) return;
|
||||||
|
if (extensions.contains("STARTTLS") && !disableStartTLS)
|
||||||
|
{
|
||||||
|
startTLS();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
authenticate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtpPrivate::startTLS()
|
||||||
|
{
|
||||||
|
socket->write("starttls\r\n");
|
||||||
|
state = StartTLSSent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtpPrivate::authenticate()
|
||||||
|
{
|
||||||
|
if (!extensions.contains("AUTH") || username.isEmpty() || password.isEmpty())
|
||||||
|
{
|
||||||
|
state = Authenticated;
|
||||||
|
emit qxt_p().authenticated();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QStringList auth = extensions["AUTH"].toUpper().split(' ', QString::SkipEmptyParts);
|
||||||
|
if (auth.contains("CRAM-MD5"))
|
||||||
|
{
|
||||||
|
authCramMD5();
|
||||||
|
}
|
||||||
|
else if (auth.contains("PLAIN"))
|
||||||
|
{
|
||||||
|
authPlain();
|
||||||
|
}
|
||||||
|
else if (auth.contains("LOGIN"))
|
||||||
|
{
|
||||||
|
authLogin();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state = Authenticated;
|
||||||
|
emit qxt_p().authenticated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtpPrivate::authCramMD5(const QByteArray& challenge)
|
||||||
|
{
|
||||||
|
if (state != AuthRequestSent)
|
||||||
|
{
|
||||||
|
socket->write("auth cram-md5\r\n");
|
||||||
|
authType = AuthCramMD5;
|
||||||
|
state = AuthRequestSent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QxtHmac hmac(QCryptographicHash::Md5);
|
||||||
|
hmac.setKey(password);
|
||||||
|
hmac.addData(QByteArray::fromBase64(challenge));
|
||||||
|
QByteArray response = username + ' ' + hmac.result().toHex();
|
||||||
|
socket->write(response.toBase64() + "\r\n");
|
||||||
|
state = AuthSent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtpPrivate::authPlain()
|
||||||
|
{
|
||||||
|
if (state != AuthRequestSent)
|
||||||
|
{
|
||||||
|
socket->write("auth plain\r\n");
|
||||||
|
authType = AuthPlain;
|
||||||
|
state = AuthRequestSent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QByteArray auth;
|
||||||
|
auth += '\0';
|
||||||
|
auth += username;
|
||||||
|
auth += '\0';
|
||||||
|
auth += password;
|
||||||
|
socket->write(auth.toBase64() + "\r\n");
|
||||||
|
state = AuthSent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtpPrivate::authLogin()
|
||||||
|
{
|
||||||
|
if (state != AuthRequestSent && state != AuthUsernameSent)
|
||||||
|
{
|
||||||
|
socket->write("auth login\r\n");
|
||||||
|
authType = AuthLogin;
|
||||||
|
state = AuthRequestSent;
|
||||||
|
}
|
||||||
|
else if (state == AuthRequestSent)
|
||||||
|
{
|
||||||
|
socket->write(username.toBase64() + "\r\n");
|
||||||
|
state = AuthUsernameSent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
socket->write(password.toBase64() + "\r\n");
|
||||||
|
state = AuthSent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static QByteArray qxt_extract_address(const QString& address)
|
||||||
|
{
|
||||||
|
int parenDepth = 0;
|
||||||
|
int addrStart = -1;
|
||||||
|
bool inQuote = false;
|
||||||
|
int ct = address.length();
|
||||||
|
|
||||||
|
for (int i = 0; i < ct; i++)
|
||||||
|
{
|
||||||
|
QChar ch = address[i];
|
||||||
|
if (inQuote)
|
||||||
|
{
|
||||||
|
if (ch == '"')
|
||||||
|
inQuote = false;
|
||||||
|
}
|
||||||
|
else if (addrStart != -1)
|
||||||
|
{
|
||||||
|
if (ch == '>')
|
||||||
|
return address.mid(addrStart, (i - addrStart)).toLatin1();
|
||||||
|
}
|
||||||
|
else if (ch == '(')
|
||||||
|
{
|
||||||
|
parenDepth++;
|
||||||
|
}
|
||||||
|
else if (ch == ')')
|
||||||
|
{
|
||||||
|
parenDepth--;
|
||||||
|
if (parenDepth < 0) parenDepth = 0;
|
||||||
|
}
|
||||||
|
else if (ch == '"')
|
||||||
|
{
|
||||||
|
if (parenDepth == 0)
|
||||||
|
inQuote = true;
|
||||||
|
}
|
||||||
|
else if (ch == '<')
|
||||||
|
{
|
||||||
|
if (!inQuote && parenDepth == 0)
|
||||||
|
addrStart = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return address.toLatin1();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtpPrivate::sendNext()
|
||||||
|
{
|
||||||
|
if (state == Disconnected)
|
||||||
|
{
|
||||||
|
// leave the mail in the queue if not ready to send
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pending.isEmpty())
|
||||||
|
{
|
||||||
|
// if there are no additional mails to send, finish up
|
||||||
|
state = Waiting;
|
||||||
|
emit qxt_p().finished();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(state != Waiting) {
|
||||||
|
state = Resetting;
|
||||||
|
socket->write("rset\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const QxtMailMessage& msg = pending.first().second;
|
||||||
|
rcptNumber = rcptAck = mailAck = 0;
|
||||||
|
recipients = msg.recipients(QxtMailMessage::To) +
|
||||||
|
msg.recipients(QxtMailMessage::Cc) +
|
||||||
|
msg.recipients(QxtMailMessage::Bcc);
|
||||||
|
if (recipients.count() == 0)
|
||||||
|
{
|
||||||
|
// can't send an e-mail with no recipients
|
||||||
|
emit qxt_p().mailFailed(pending.first().first, QxtSmtp::NoRecipients );
|
||||||
|
emit qxt_p().mailFailed(pending.first().first, QxtSmtp::NoRecipients, QByteArray( "e-mail has no recipients" ) );
|
||||||
|
pending.removeFirst();
|
||||||
|
sendNext();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// We explicitly use lowercase keywords because for some reason gmail
|
||||||
|
// interprets any string starting with an uppercase R as a request
|
||||||
|
// to renegotiate the SSL connection.
|
||||||
|
socket->write("mail from:<" + qxt_extract_address(msg.sender()) + ">\r\n");
|
||||||
|
if (extensions.contains("PIPELINING")) // almost all do nowadays
|
||||||
|
{
|
||||||
|
foreach(const QString& rcpt, recipients)
|
||||||
|
{
|
||||||
|
socket->write("rcpt to:<" + qxt_extract_address(rcpt) + ">\r\n");
|
||||||
|
}
|
||||||
|
state = RcptAckPending;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state = MailToSent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtpPrivate::sendNextRcpt(const QByteArray& code, const QByteArray&line)
|
||||||
|
{
|
||||||
|
int messageID = pending.first().first;
|
||||||
|
const QxtMailMessage& msg = pending.first().second;
|
||||||
|
|
||||||
|
if (code[0] != '2')
|
||||||
|
{
|
||||||
|
// on failure, emit a warning signal
|
||||||
|
if (!mailAck)
|
||||||
|
{
|
||||||
|
emit qxt_p().senderRejected(messageID, msg.sender());
|
||||||
|
emit qxt_p().senderRejected(messageID, msg.sender(), line );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emit qxt_p().recipientRejected(messageID, msg.sender());
|
||||||
|
emit qxt_p().recipientRejected(messageID, msg.sender(), line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!mailAck)
|
||||||
|
{
|
||||||
|
mailAck = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rcptAck++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rcptNumber == recipients.count())
|
||||||
|
{
|
||||||
|
// all recipients have been sent
|
||||||
|
if (rcptAck == 0)
|
||||||
|
{
|
||||||
|
// no recipients were considered valid
|
||||||
|
emit qxt_p().mailFailed(messageID, code.toInt() );
|
||||||
|
emit qxt_p().mailFailed(messageID, code.toInt(), line);
|
||||||
|
pending.removeFirst();
|
||||||
|
sendNext();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// at least one recipient was acknowledged, send mail body
|
||||||
|
socket->write("data\r\n");
|
||||||
|
state = SendingBody;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (state != RcptAckPending)
|
||||||
|
{
|
||||||
|
// send the next recipient unless we're only waiting on acks
|
||||||
|
socket->write("rcpt to:<" + qxt_extract_address(recipients[rcptNumber]) + ">\r\n");
|
||||||
|
rcptNumber++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If we're only waiting on acks, just count them
|
||||||
|
rcptNumber++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QxtSmtpPrivate::sendBody(const QByteArray& code, const QByteArray & line)
|
||||||
|
{
|
||||||
|
int messageID = pending.first().first;
|
||||||
|
const QxtMailMessage& msg = pending.first().second;
|
||||||
|
|
||||||
|
if (code[0] != '3')
|
||||||
|
{
|
||||||
|
emit qxt_p().mailFailed(messageID, code.toInt() );
|
||||||
|
emit qxt_p().mailFailed(messageID, code.toInt(), line);
|
||||||
|
pending.removeFirst();
|
||||||
|
sendNext();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket->write(msg.rfc2822());
|
||||||
|
socket->write(".\r\n");
|
||||||
|
state = BodySent;
|
||||||
|
}
|
111
servatrice/src/smtp/qxtsmtp.h
Normal file
111
servatrice/src/smtp/qxtsmtp.h
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) Qxt Foundation. Some rights reserved.
|
||||||
|
**
|
||||||
|
** This file is part of the QxtWeb module of the Qxt library.
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or modify it
|
||||||
|
** under the terms of the Common Public License, version 1.0, as published
|
||||||
|
** by IBM, and/or under the terms of the GNU Lesser General Public License,
|
||||||
|
** version 2.1, as published by the Free Software Foundation.
|
||||||
|
**
|
||||||
|
** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
|
||||||
|
** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the CPL and the LGPL along with this
|
||||||
|
** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
|
||||||
|
** included with the source distribution for more information.
|
||||||
|
** If you did not receive a copy of the licenses, contact the Qxt Foundation.
|
||||||
|
**
|
||||||
|
** <http://libqxt.org> <foundation@libqxt.org>
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef QXTSMTP_H
|
||||||
|
#define QXTSMTP_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QHostAddress>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "qxtglobal.h"
|
||||||
|
#include "qxtmailmessage.h"
|
||||||
|
|
||||||
|
class QTcpSocket;
|
||||||
|
class QSslSocket;
|
||||||
|
|
||||||
|
class QxtSmtpPrivate;
|
||||||
|
class QXT_NETWORK_EXPORT QxtSmtp : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum SmtpError
|
||||||
|
{
|
||||||
|
NoError,
|
||||||
|
NoRecipients,
|
||||||
|
CommandUnrecognized = 500,
|
||||||
|
SyntaxError,
|
||||||
|
CommandNotImplemented,
|
||||||
|
BadSequence,
|
||||||
|
ParameterNotImplemented,
|
||||||
|
MailboxUnavailable = 550,
|
||||||
|
UserNotLocal,
|
||||||
|
MessageTooLarge,
|
||||||
|
InvalidMailboxName,
|
||||||
|
TransactionFailed
|
||||||
|
};
|
||||||
|
|
||||||
|
QxtSmtp(QObject* parent = 0);
|
||||||
|
|
||||||
|
QByteArray username() const;
|
||||||
|
void setUsername(const QByteArray& name);
|
||||||
|
|
||||||
|
QByteArray password() const;
|
||||||
|
void setPassword(const QByteArray& password);
|
||||||
|
|
||||||
|
int send(const QxtMailMessage& message);
|
||||||
|
int pendingMessages() const;
|
||||||
|
|
||||||
|
QTcpSocket* socket() const;
|
||||||
|
void connectToHost(const QString& hostName, quint16 port = 25);
|
||||||
|
void connectToHost(const QHostAddress& address, quint16 port = 25);
|
||||||
|
void disconnectFromHost();
|
||||||
|
|
||||||
|
bool startTlsDisabled() const;
|
||||||
|
void setStartTlsDisabled(bool disable);
|
||||||
|
|
||||||
|
QSslSocket* sslSocket() const;
|
||||||
|
void connectToSecureHost(const QString& hostName, quint16 port = 465);
|
||||||
|
void connectToSecureHost(const QHostAddress& address, quint16 port = 465);
|
||||||
|
|
||||||
|
bool hasExtension(const QString& extension);
|
||||||
|
QString extensionData(const QString& extension);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void connected();
|
||||||
|
void connectionFailed();
|
||||||
|
void connectionFailed( const QByteArray & msg );
|
||||||
|
void encrypted();
|
||||||
|
void encryptionFailed();
|
||||||
|
void encryptionFailed( const QByteArray & msg );
|
||||||
|
void authenticated();
|
||||||
|
void authenticationFailed();
|
||||||
|
void authenticationFailed( const QByteArray & msg );
|
||||||
|
|
||||||
|
void senderRejected(int mailID, const QString& address );
|
||||||
|
void senderRejected(int mailID, const QString& address, const QByteArray & msg );
|
||||||
|
void recipientRejected(int mailID, const QString& address );
|
||||||
|
void recipientRejected(int mailID, const QString& address, const QByteArray & msg );
|
||||||
|
void mailFailed(int mailID, int errorCode);
|
||||||
|
void mailFailed(int mailID, int errorCode, const QByteArray & msg);
|
||||||
|
void mailSent(int mailID);
|
||||||
|
|
||||||
|
void finished();
|
||||||
|
void disconnected();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QXT_DECLARE_PRIVATE(QxtSmtp)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QXTSMTP_H
|
102
servatrice/src/smtp/qxtsmtp_p.h
Normal file
102
servatrice/src/smtp/qxtsmtp_p.h
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) Qxt Foundation. Some rights reserved.
|
||||||
|
**
|
||||||
|
** This file is part of the QxtWeb module of the Qxt library.
|
||||||
|
**
|
||||||
|
** This library is free software; you can redistribute it and/or modify it
|
||||||
|
** under the terms of the Common Public License, version 1.0, as published
|
||||||
|
** by IBM, and/or under the terms of the GNU Lesser General Public License,
|
||||||
|
** version 2.1, as published by the Free Software Foundation.
|
||||||
|
**
|
||||||
|
** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
|
||||||
|
** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
|
||||||
|
** FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
**
|
||||||
|
** You should have received a copy of the CPL and the LGPL along with this
|
||||||
|
** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
|
||||||
|
** included with the source distribution for more information.
|
||||||
|
** If you did not receive a copy of the licenses, contact the Qxt Foundation.
|
||||||
|
**
|
||||||
|
** <http://libqxt.org> <foundation@libqxt.org>
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef QXTSMTP_P_H
|
||||||
|
#define QXTSMTP_P_H
|
||||||
|
|
||||||
|
#include "qxtsmtp.h"
|
||||||
|
#include <QHash>
|
||||||
|
#include <QString>
|
||||||
|
#include <QList>
|
||||||
|
#include <QPair>
|
||||||
|
|
||||||
|
class QxtSmtpPrivate : public QObject, public QxtPrivate<QxtSmtp>
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
QxtSmtpPrivate();
|
||||||
|
|
||||||
|
QXT_DECLARE_PUBLIC(QxtSmtp)
|
||||||
|
|
||||||
|
enum SmtpState
|
||||||
|
{
|
||||||
|
Disconnected,
|
||||||
|
StartState,
|
||||||
|
EhloSent,
|
||||||
|
EhloGreetReceived,
|
||||||
|
EhloExtensionsReceived,
|
||||||
|
EhloDone,
|
||||||
|
HeloSent,
|
||||||
|
StartTLSSent,
|
||||||
|
AuthRequestSent,
|
||||||
|
AuthUsernameSent,
|
||||||
|
AuthSent,
|
||||||
|
Authenticated,
|
||||||
|
MailToSent,
|
||||||
|
RcptAckPending,
|
||||||
|
SendingBody,
|
||||||
|
BodySent,
|
||||||
|
Waiting,
|
||||||
|
Resetting
|
||||||
|
};
|
||||||
|
|
||||||
|
enum AuthType
|
||||||
|
{
|
||||||
|
AuthPlain,
|
||||||
|
AuthLogin,
|
||||||
|
AuthCramMD5
|
||||||
|
};
|
||||||
|
|
||||||
|
bool useSecure, disableStartTLS;
|
||||||
|
SmtpState state;// rather then an int use the enum. makes sure invalid states are entered at compile time, and makes debugging easier
|
||||||
|
AuthType authType;
|
||||||
|
QByteArray buffer, username, password;
|
||||||
|
QHash<QString, QString> extensions;
|
||||||
|
QList<QPair<int, QxtMailMessage> > pending;
|
||||||
|
QStringList recipients;
|
||||||
|
int nextID, rcptNumber, rcptAck;
|
||||||
|
bool mailAck;
|
||||||
|
|
||||||
|
QSslSocket* socket;
|
||||||
|
|
||||||
|
void parseEhlo(const QByteArray& code, bool cont, const QString& line);
|
||||||
|
void startTLS();
|
||||||
|
void authenticate();
|
||||||
|
|
||||||
|
void authCramMD5(const QByteArray& challenge = QByteArray());
|
||||||
|
void authPlain();
|
||||||
|
void authLogin();
|
||||||
|
|
||||||
|
void sendNextRcpt(const QByteArray& code, const QByteArray & line);
|
||||||
|
void sendBody(const QByteArray& code, const QByteArray & line);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void socketError(QAbstractSocket::SocketError err);
|
||||||
|
void socketRead();
|
||||||
|
|
||||||
|
void ehlo();
|
||||||
|
void sendNext();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QXTSMTP_P_H
|
|
@ -1,489 +0,0 @@
|
||||||
/*
|
|
||||||
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 "smtpclient.h"
|
|
||||||
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QByteArray>
|
|
||||||
|
|
||||||
|
|
||||||
/* [1] Constructors and destructors */
|
|
||||||
|
|
||||||
SmtpClient::SmtpClient(const QString & host, int port, ConnectionType connectionType) :
|
|
||||||
socket(NULL),
|
|
||||||
name("localhost"),
|
|
||||||
authMethod(AuthPlain),
|
|
||||||
connectionTimeout(5000),
|
|
||||||
responseTimeout(5000),
|
|
||||||
sendMessageTimeout(60000)
|
|
||||||
{
|
|
||||||
setConnectionType(connectionType);
|
|
||||||
|
|
||||||
this->host = host;
|
|
||||||
this->port = port;
|
|
||||||
|
|
||||||
connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
|
|
||||||
this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));
|
|
||||||
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
|
|
||||||
this, SLOT(socketError(QAbstractSocket::SocketError)));
|
|
||||||
connect(socket, SIGNAL(readyRead()),
|
|
||||||
this, SLOT(socketReadyRead()));
|
|
||||||
}
|
|
||||||
|
|
||||||
SmtpClient::~SmtpClient() {
|
|
||||||
if (socket)
|
|
||||||
delete socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Getters and Setters */
|
|
||||||
|
|
||||||
void SmtpClient::setUser(const QString &user)
|
|
||||||
{
|
|
||||||
this->user = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SmtpClient::setPassword(const QString &password)
|
|
||||||
{
|
|
||||||
this->password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SmtpClient::setAuthMethod(AuthMethod method)
|
|
||||||
{
|
|
||||||
this->authMethod = method;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SmtpClient::setHost(const QString &host)
|
|
||||||
{
|
|
||||||
this->host = host;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SmtpClient::setPort(int port)
|
|
||||||
{
|
|
||||||
this->port = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SmtpClient::setConnectionType(ConnectionType ct)
|
|
||||||
{
|
|
||||||
this->connectionType = ct;
|
|
||||||
|
|
||||||
if (socket)
|
|
||||||
delete socket;
|
|
||||||
|
|
||||||
switch (connectionType)
|
|
||||||
{
|
|
||||||
case TcpConnection:
|
|
||||||
socket = new QTcpSocket(this);
|
|
||||||
break;
|
|
||||||
case SslConnection:
|
|
||||||
case TlsConnection:
|
|
||||||
socket = new QSslSocket(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString& SmtpClient::getHost() const
|
|
||||||
{
|
|
||||||
return this->host;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString& SmtpClient::getUser() const
|
|
||||||
{
|
|
||||||
return this->user;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 TlsConnection:
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
emit smtpError(ServerError);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send a EHLO/HELO message to the server
|
|
||||||
// The client's first command must be EHLO/HELO
|
|
||||||
sendMessage("EHLO " + name);
|
|
||||||
|
|
||||||
// Wait for the server's response
|
|
||||||
waitForResponse();
|
|
||||||
|
|
||||||
// The response code needs to be 250.
|
|
||||||
if (responseCode != 250) {
|
|
||||||
emit smtpError(ServerError);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connectionType == TlsConnection) {
|
|
||||||
// send a request to start TLS handshake
|
|
||||||
sendMessage("STARTTLS");
|
|
||||||
|
|
||||||
// Wait for the server's response
|
|
||||||
waitForResponse();
|
|
||||||
|
|
||||||
// The response code needs to be 220.
|
|
||||||
if (responseCode != 220) {
|
|
||||||
emit smtpError(ServerError);
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
((QSslSocket*) socket)->startClientEncryption();
|
|
||||||
|
|
||||||
if (!((QSslSocket*) socket)->waitForEncrypted(connectionTimeout)) {
|
|
||||||
qDebug() << ((QSslSocket*) socket)->errorString();
|
|
||||||
emit smtpError(ConnectionTimeoutError);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send ELHO one more time
|
|
||||||
sendMessage("EHLO " + name);
|
|
||||||
|
|
||||||
// Wait for the server's response
|
|
||||||
waitForResponse();
|
|
||||||
|
|
||||||
// The response code needs to be 250.
|
|
||||||
if (responseCode != 250) {
|
|
||||||
emit smtpError(ServerError);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ResponseTimeoutException)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (SendMessageTimeoutException)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no errors occured the function returns true.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SmtpClient::login()
|
|
||||||
{
|
|
||||||
return login(user, password, authMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SmtpClient::login(const QString &user, const QString &password, AuthMethod method)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if (method == AuthPlain)
|
|
||||||
{
|
|
||||||
// Sending command: AUTH PLAIN base64('\0' + username + '\0' + password)
|
|
||||||
sendMessage("AUTH PLAIN " + QByteArray().append((char) 0).append(user).append((char) 0).append(password).toBase64());
|
|
||||||
|
|
||||||
// Wait for the server's response
|
|
||||||
waitForResponse();
|
|
||||||
|
|
||||||
// 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 e)
|
|
||||||
{
|
|
||||||
// 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");
|
|
||||||
waitForResponse();
|
|
||||||
|
|
||||||
if (responseCode != 354) return false;
|
|
||||||
|
|
||||||
sendMessage(email.toString());
|
|
||||||
|
|
||||||
// Send \r\n.\r\n to end the mail data
|
|
||||||
sendMessage(".");
|
|
||||||
|
|
||||||
waitForResponse();
|
|
||||||
|
|
||||||
if (responseCode != 250) return false;
|
|
||||||
}
|
|
||||||
catch (ResponseTimeoutException)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (SendMessageTimeoutException)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SmtpClient::quit()
|
|
||||||
{
|
|
||||||
sendMessage("QUIT");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [3] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [4] Protected methods */
|
|
||||||
|
|
||||||
void SmtpClient::waitForResponse() throw (ResponseTimeoutException)
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
if (!socket->waitForReadyRead(responseTimeout))
|
|
||||||
{
|
|
||||||
emit smtpError(ResponseTimeoutError);
|
|
||||||
throw ResponseTimeoutException();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (socket->canReadLine()) {
|
|
||||||
// Save the server's response
|
|
||||||
responseText = socket->readLine();
|
|
||||||
|
|
||||||
// Extract the respose code from the server's responce (first 3 digits)
|
|
||||||
responseCode = responseText.left(3).toInt();
|
|
||||||
|
|
||||||
if (responseCode / 100 == 4)
|
|
||||||
emit smtpError(ServerError);
|
|
||||||
|
|
||||||
if (responseCode / 100 == 5)
|
|
||||||
emit smtpError(ClientError);
|
|
||||||
|
|
||||||
if (responseText[3] == ' ') { return; }
|
|
||||||
}
|
|
||||||
} while (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SmtpClient::sendMessage(const QString &text) throw (SendMessageTimeoutException)
|
|
||||||
{
|
|
||||||
socket->write(text.toUtf8() + "\r\n");
|
|
||||||
if (! socket->waitForBytesWritten(sendMessageTimeout))
|
|
||||||
{
|
|
||||||
emit smtpError(SendDataTimeoutError);
|
|
||||||
throw SendMessageTimeoutException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [4] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [5] Slots for the socket's signals */
|
|
||||||
|
|
||||||
void SmtpClient::socketStateChanged(QAbstractSocket::SocketState /* state */)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SmtpClient::socketError(QAbstractSocket::SocketError /* socketError */)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SmtpClient::socketReadyRead()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/* [5] --- */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,184 +0,0 @@
|
||||||
/*
|
|
||||||
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 SMTPCLIENT_H
|
|
||||||
#define SMTPCLIENT_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QtNetwork/QSslSocket>
|
|
||||||
|
|
||||||
#include "mimemessage.h"
|
|
||||||
#include "smtpexports.h"
|
|
||||||
|
|
||||||
class SMTP_EXPORT SmtpClient : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
|
|
||||||
/* [0] Enumerations */
|
|
||||||
|
|
||||||
enum AuthMethod
|
|
||||||
{
|
|
||||||
AuthPlain,
|
|
||||||
AuthLogin
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SmtpError
|
|
||||||
{
|
|
||||||
ConnectionTimeoutError,
|
|
||||||
ResponseTimeoutError,
|
|
||||||
SendDataTimeoutError,
|
|
||||||
AuthenticationFailedError,
|
|
||||||
ServerError, // 4xx smtp error
|
|
||||||
ClientError // 5xx smtp error
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ConnectionType
|
|
||||||
{
|
|
||||||
TcpConnection,
|
|
||||||
SslConnection,
|
|
||||||
TlsConnection // STARTTLS
|
|
||||||
};
|
|
||||||
|
|
||||||
/* [0] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [1] Constructors and Destructors */
|
|
||||||
|
|
||||||
SmtpClient(const QString & host = "localhost", int port = 25, ConnectionType ct = TcpConnection);
|
|
||||||
|
|
||||||
~SmtpClient();
|
|
||||||
|
|
||||||
/* [1] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] Getters and Setters */
|
|
||||||
|
|
||||||
const QString& getHost() const;
|
|
||||||
void setHost(const QString &host);
|
|
||||||
|
|
||||||
int getPort() const;
|
|
||||||
void setPort(int port);
|
|
||||||
|
|
||||||
const QString& getName() const;
|
|
||||||
void setName(const QString &name);
|
|
||||||
|
|
||||||
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 getConnectionTimeout() const;
|
|
||||||
void setConnectionTimeout(int msec);
|
|
||||||
|
|
||||||
int getResponseTimeout() const;
|
|
||||||
void setResponseTimeout(int msec);
|
|
||||||
|
|
||||||
int getSendMessageTimeout() const;
|
|
||||||
void setSendMessageTimeout(int msec);
|
|
||||||
|
|
||||||
QTcpSocket* getSocket();
|
|
||||||
|
|
||||||
|
|
||||||
/* [2] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [3] Public methods */
|
|
||||||
|
|
||||||
bool connectToHost();
|
|
||||||
|
|
||||||
bool login();
|
|
||||||
bool login(const QString &user, const QString &password, AuthMethod method = AuthLogin);
|
|
||||||
|
|
||||||
bool sendMail(MimeMessage& email);
|
|
||||||
|
|
||||||
void quit();
|
|
||||||
|
|
||||||
|
|
||||||
/* [3] --- */
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/* [4] Protected members */
|
|
||||||
|
|
||||||
QTcpSocket *socket;
|
|
||||||
|
|
||||||
QString host;
|
|
||||||
int port;
|
|
||||||
ConnectionType connectionType;
|
|
||||||
QString name;
|
|
||||||
|
|
||||||
QString user;
|
|
||||||
QString password;
|
|
||||||
AuthMethod authMethod;
|
|
||||||
|
|
||||||
int connectionTimeout;
|
|
||||||
int responseTimeout;
|
|
||||||
int sendMessageTimeout;
|
|
||||||
|
|
||||||
|
|
||||||
QString responseText;
|
|
||||||
int responseCode;
|
|
||||||
|
|
||||||
|
|
||||||
class ResponseTimeoutException {};
|
|
||||||
class SendMessageTimeoutException {};
|
|
||||||
|
|
||||||
/* [4] --- */
|
|
||||||
|
|
||||||
|
|
||||||
/* [5] Protected methods */
|
|
||||||
|
|
||||||
void waitForResponse() throw (ResponseTimeoutException);
|
|
||||||
|
|
||||||
void sendMessage(const QString &text) throw (SendMessageTimeoutException);
|
|
||||||
|
|
||||||
/* [5] --- */
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
|
|
||||||
/* [6] Protected slots */
|
|
||||||
|
|
||||||
void socketStateChanged(QAbstractSocket::SocketState state);
|
|
||||||
void socketError(QAbstractSocket::SocketError error);
|
|
||||||
void socketReadyRead();
|
|
||||||
|
|
||||||
/* [6] --- */
|
|
||||||
|
|
||||||
|
|
||||||
signals:
|
|
||||||
|
|
||||||
/* [7] Signals */
|
|
||||||
|
|
||||||
void smtpError(SmtpClient::SmtpError e);
|
|
||||||
|
|
||||||
/* [7] --- */
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SMTPCLIENT_H
|
|
|
@ -1,15 +0,0 @@
|
||||||
#ifndef SMTPEXPORTS_H
|
|
||||||
#define SMTPEXPORTS_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
#ifdef SMTP_BUILD
|
|
||||||
#define SMTP_EXPORT Q_DECL_EXPORT
|
|
||||||
#else
|
|
||||||
#define SMTP_EXPORT Q_DECL_IMPORT
|
|
||||||
#endif
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Servatrice compiles this statically in, so there's no need to declare exports
|
|
||||||
#define SMTP_EXPORT
|
|
||||||
|
|
||||||
#endif // SMTPEXPORTS_H
|
|
175
servatrice/src/smtpclient.cpp
Normal file
175
servatrice/src/smtpclient.cpp
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
#include "smtpclient.h"
|
||||||
|
#include "settingscache.h"
|
||||||
|
#include "smtp/qxtsmtp.h"
|
||||||
|
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QSslSocket>
|
||||||
|
|
||||||
|
SmtpClient::SmtpClient(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
smtp = new QxtSmtp(this);
|
||||||
|
|
||||||
|
connect(smtp, SIGNAL(authenticated()), this, SLOT(authenticated()));
|
||||||
|
connect(smtp, SIGNAL(authenticationFailed(const QByteArray &)), this, SLOT(authenticationFailed(const QByteArray &)));
|
||||||
|
connect(smtp, SIGNAL(connected()), this, SLOT(connected()));
|
||||||
|
connect(smtp, SIGNAL(connectionFailed(const QByteArray &)), this, SLOT(connectionFailed(const QByteArray &)));
|
||||||
|
connect(smtp, SIGNAL(disconnected()), this, SLOT(disconnected()));
|
||||||
|
connect(smtp, SIGNAL(encrypted()), this, SLOT(encrypted()));
|
||||||
|
connect(smtp, SIGNAL(encryptionFailed(const QByteArray &)), this, SLOT(encryptionFailed(const QByteArray &)));
|
||||||
|
connect(smtp, SIGNAL(finished()), this, SLOT(finished()));
|
||||||
|
connect(smtp, SIGNAL(mailFailed(int, int, const QByteArray &)), this, SLOT(mailFailed(int, int, const QByteArray &)));
|
||||||
|
connect(smtp, SIGNAL(mailSent(int)), this, SLOT(mailSent(int)));
|
||||||
|
connect(smtp, SIGNAL(recipientRejected(int, const QString &, const QByteArray &)), this, SLOT(recipientRejected(int, const QString &, const QByteArray &)));
|
||||||
|
connect(smtp, SIGNAL(senderRejected(int, const QString &, const QByteArray &)), this, SLOT(senderRejected(int, const QString &, const QByteArray &)));
|
||||||
|
}
|
||||||
|
|
||||||
|
SmtpClient::~SmtpClient()
|
||||||
|
{
|
||||||
|
if(smtp)
|
||||||
|
{
|
||||||
|
delete smtp;
|
||||||
|
smtp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SmtpClient::enqueueActivationTokenMail(const QString &nickname, const QString &recipient, const QString &token)
|
||||||
|
{
|
||||||
|
QString email = settingsCache->value("smtp/email", "").toString();
|
||||||
|
QString name = settingsCache->value("smtp/name", "").toString();
|
||||||
|
QString subject = settingsCache->value("smtp/subject", "").toString();
|
||||||
|
QString body = settingsCache->value("smtp/body", "").toString();
|
||||||
|
|
||||||
|
if(email.isEmpty())
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] Missing sender email in configuration";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(subject.isEmpty())
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] Missing subject field in configuration";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(body.isEmpty())
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] Missing body field in configuration";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(recipient.isEmpty())
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] Missing recipient field for user " << nickname;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(token.isEmpty())
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] Missing token field for user " << nickname;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QxtMailMessage message;
|
||||||
|
message.setSender(name + " <" + email + ">");
|
||||||
|
message.addRecipient(recipient);
|
||||||
|
message.setSubject(subject);
|
||||||
|
message.setBody(body.replace("%username", nickname).replace("%token", token));
|
||||||
|
|
||||||
|
int id = smtp->send(message);
|
||||||
|
qDebug() << "[MAIL] Enqueued mail to" << recipient << "as" << id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmtpClient::sendAllEmails()
|
||||||
|
{
|
||||||
|
// still connected from the previous round
|
||||||
|
if(smtp->socket()->state() == QAbstractSocket::ConnectedState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(smtp->pendingMessages() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString connectionType = settingsCache->value("smtp/connection", "tcp").toString();
|
||||||
|
QString host = settingsCache->value("smtp/host", "localhost").toString();
|
||||||
|
int port = settingsCache->value("smtp/port", 25).toInt();
|
||||||
|
QByteArray username = settingsCache->value("smtp/username", "").toByteArray();
|
||||||
|
QByteArray password = settingsCache->value("smtp/password", "").toByteArray();
|
||||||
|
bool acceptAllCerts = settingsCache->value("smtp/acceptallcerts", false).toBool();
|
||||||
|
|
||||||
|
smtp->setUsername(username);
|
||||||
|
smtp->setPassword(password);
|
||||||
|
|
||||||
|
// Connect
|
||||||
|
if(connectionType == "ssl")
|
||||||
|
{
|
||||||
|
if(acceptAllCerts)
|
||||||
|
smtp->sslSocket()->setPeerVerifyMode(QSslSocket::QueryPeer);
|
||||||
|
smtp->connectToSecureHost(host, port);
|
||||||
|
} else {
|
||||||
|
smtp->connectToHost(host, port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmtpClient::authenticated()
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] authenticated";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmtpClient::authenticationFailed(const QByteArray & msg)
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] authenticationFailed" << QString(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmtpClient::connected()
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] connected";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmtpClient::connectionFailed(const QByteArray & msg)
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] connectionFailed" << QString(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmtpClient::disconnected()
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] disconnected";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmtpClient::encrypted()
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] encrypted";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmtpClient::encryptionFailed(const QByteArray & msg)
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] encryptionFailed" << QString(msg);
|
||||||
|
qDebug() << "[MAIL] Try enabling the \"acceptallcerts\" option in servatrice.ini";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmtpClient::finished()
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] finished";
|
||||||
|
smtp->disconnectFromHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmtpClient::mailFailed(int mailID, int errorCode, const QByteArray & msg)
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] mailFailed id=" << mailID << " errorCode=" << errorCode << "msg=" << QString(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmtpClient::mailSent(int mailID)
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] mailSent" << mailID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmtpClient::recipientRejected(int mailID, const QString & address, const QByteArray & msg)
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] recipientRejected id=" << mailID << " address=" << address << "msg=" << QString(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmtpClient::senderRejected(int mailID, const QString & address, const QByteArray & msg)
|
||||||
|
{
|
||||||
|
qDebug() << "[MAIL] senderRejected id=" << mailID << " address=" << address << "msg=" << QString(msg);
|
||||||
|
}
|
34
servatrice/src/smtpclient.h
Normal file
34
servatrice/src/smtpclient.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef SMTPCLIENT_H
|
||||||
|
#define SMTPCLIENT_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class QxtSmtp;
|
||||||
|
class QxtMailMessage;
|
||||||
|
|
||||||
|
class SmtpClient : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
SmtpClient(QObject *parent = 0);
|
||||||
|
~SmtpClient();
|
||||||
|
protected:
|
||||||
|
QxtSmtp *smtp;
|
||||||
|
public slots:
|
||||||
|
bool enqueueActivationTokenMail(const QString &nickname, const QString &recipient, const QString &token);
|
||||||
|
void sendAllEmails();
|
||||||
|
protected slots:
|
||||||
|
void authenticated();
|
||||||
|
void authenticationFailed(const QByteArray & msg);
|
||||||
|
void connected();
|
||||||
|
void connectionFailed(const QByteArray & msg);
|
||||||
|
void disconnected();
|
||||||
|
void encrypted();
|
||||||
|
void encryptionFailed(const QByteArray & msg);
|
||||||
|
void finished();
|
||||||
|
void mailFailed(int mailID, int errorCode, const QByteArray & msg);
|
||||||
|
void mailSent(int mailID);
|
||||||
|
void recipientRejected(int mailID, const QString & address, const QByteArray & msg);
|
||||||
|
void senderRejected(int mailID, const QString & address, const QByteArray & msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue