Process header before transmitting message via SMTP.
This commit is contained in:
parent
d8b3d2b641
commit
e3bb8020e0
@ -674,6 +674,13 @@ void body::setParentPart(ref <bodyPart> parent)
|
||||
{
|
||||
m_part = parent;
|
||||
m_header = (parent != NULL ? parent->getHeader() : NULL);
|
||||
|
||||
for (std::vector <ref <bodyPart> >::iterator it = m_parts.begin() ;
|
||||
it != m_parts.end() ; ++it)
|
||||
{
|
||||
ref <bodyPart> childPart = *it;
|
||||
childPart->m_parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -121,6 +121,12 @@ ref <header> bodyPart::getHeader()
|
||||
}
|
||||
|
||||
|
||||
void bodyPart::setHeader(ref <header> h)
|
||||
{
|
||||
m_header = h;
|
||||
}
|
||||
|
||||
|
||||
const ref <const body> bodyPart::getBody() const
|
||||
{
|
||||
return (m_body);
|
||||
@ -133,6 +139,19 @@ ref <body> bodyPart::getBody()
|
||||
}
|
||||
|
||||
|
||||
void bodyPart::setBody(ref <body> b)
|
||||
{
|
||||
ref <bodyPart> oldPart = b->m_part.acquire();
|
||||
|
||||
m_body = b;
|
||||
m_body->setParentPart(thisRef().dynamicCast <bodyPart>());
|
||||
|
||||
// A body is associated to one and only one part
|
||||
if (oldPart != NULL)
|
||||
oldPart->setBody(vmime::create <body>());
|
||||
}
|
||||
|
||||
|
||||
ref <bodyPart> bodyPart::getParentPart()
|
||||
{
|
||||
return m_parent.acquire();
|
||||
|
@ -32,6 +32,8 @@
|
||||
#include "vmime/utility/stream.hpp"
|
||||
#include "vmime/mailboxList.hpp"
|
||||
#include "vmime/message.hpp"
|
||||
#include "vmime/datetime.hpp"
|
||||
#include "vmime/messageId.hpp"
|
||||
|
||||
#include "vmime/utility/outputStreamAdapter.hpp"
|
||||
#include "vmime/utility/inputStreamStringAdapter.hpp"
|
||||
@ -47,6 +49,66 @@ transport::transport(ref <session> sess, const serviceInfos& infos, ref <securit
|
||||
}
|
||||
|
||||
|
||||
ref <headerField> transport::processHeaderField(ref <headerField> field)
|
||||
{
|
||||
if (utility::stringUtils::isStringEqualNoCase(field->getName(), fields::BCC))
|
||||
{
|
||||
// Remove Bcc headers from the message, as required by the RFC.
|
||||
// Some SMTP server automatically strip this header (Postfix, qmail),
|
||||
// and others have an option for this (Exim).
|
||||
return NULL;
|
||||
}
|
||||
else if (utility::stringUtils::isStringEqualNoCase(field->getName(), fields::RETURN_PATH))
|
||||
{
|
||||
// RFC-2821: Return-Path header is added by the final transport system
|
||||
// that delivers the message to its recipient. Then, it should not be
|
||||
// transmitted to MSA.
|
||||
return NULL;
|
||||
}
|
||||
else if (utility::stringUtils::isStringEqualNoCase(field->getName(), fields::ORIGINAL_RECIPIENT))
|
||||
{
|
||||
// RFC-2298: Delivering MTA may add the Original-Recipient header and
|
||||
// discard existing one; so, no need to send it.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Leave the header field as is
|
||||
return field;
|
||||
}
|
||||
|
||||
|
||||
void transport::processHeader(ref <header> header)
|
||||
{
|
||||
if (header->getFieldCount() == 0)
|
||||
return;
|
||||
|
||||
// Remove/replace fields
|
||||
for (size_t idx = header->getFieldCount() ; idx != 0 ; --idx)
|
||||
{
|
||||
ref <headerField> field = header->getFieldAt(idx - 1);
|
||||
ref <headerField> newField = processHeaderField(field);
|
||||
|
||||
if (newField == NULL)
|
||||
header->removeField(field);
|
||||
else if (newField != field)
|
||||
header->replaceField(field, newField);
|
||||
}
|
||||
|
||||
// Add missing header fields
|
||||
// -- Date
|
||||
if (!header->hasField(fields::DATE))
|
||||
header->Date()->setValue(datetime::now());
|
||||
|
||||
// -- Mime-Version
|
||||
if (!header->hasField(fields::MIME_VERSION))
|
||||
header->MimeVersion()->setValue(string(SUPPORTED_MIME_VERSION));
|
||||
|
||||
// -- Message-Id
|
||||
if (!header->hasField(fields::MESSAGE_ID))
|
||||
header->MessageId()->setValue(messageId::generateId());
|
||||
}
|
||||
|
||||
|
||||
static void extractMailboxes
|
||||
(mailboxList& recipients, const addressList& list)
|
||||
{
|
||||
@ -107,15 +169,36 @@ void transport::send(ref <vmime::message> msg, utility::progressListener* progre
|
||||
}
|
||||
catch (exceptions::no_such_field&) { }
|
||||
|
||||
// Remove BCC headers from the message we're about to send, as required by the RFC.
|
||||
// Some SMTP server automatically strip this header (Postfix, qmail), and others
|
||||
// have an option for this (Exim).
|
||||
try
|
||||
// Process message header by removing fields that should be removed
|
||||
// before transmitting the message to MSA, and adding missing fields
|
||||
// which are required/recommended by the RFCs.
|
||||
ref <header> hdr = msg->getHeader()->clone().dynamicCast <header>();
|
||||
processHeader(hdr);
|
||||
|
||||
// To avoid cloning message body (too much overhead), use processed
|
||||
// header during the time we are generating the message to a stream.
|
||||
// Revert it back to original header after.
|
||||
struct XChangeMsgHeader
|
||||
{
|
||||
ref <headerField> bcc = msg->getHeader()->findField(fields::BCC);
|
||||
msg->getHeader()->removeField(bcc);
|
||||
}
|
||||
catch (exceptions::no_such_field&) { }
|
||||
XChangeMsgHeader(vmime::ref <vmime::message> _msg,
|
||||
vmime::ref <vmime::header> _hdr)
|
||||
: msg(_msg), hdr(msg->getHeader())
|
||||
{
|
||||
// Set new header
|
||||
msg->setHeader(_hdr);
|
||||
}
|
||||
|
||||
~XChangeMsgHeader()
|
||||
{
|
||||
// Revert original header
|
||||
msg->setHeader(hdr);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
vmime::ref <vmime::message> msg;
|
||||
vmime::ref <vmime::header> hdr;
|
||||
} headerExchanger(msg, hdr);
|
||||
|
||||
// Generate the message, "stream" it and delegate the sending
|
||||
// to the generic send() function.
|
||||
|
@ -60,6 +60,12 @@ public:
|
||||
*/
|
||||
ref <header> getHeader();
|
||||
|
||||
/** Replaces the header section of this part.
|
||||
*
|
||||
* @param header the new header of this part
|
||||
*/
|
||||
void setHeader(ref <header> header);
|
||||
|
||||
/** Return the body section of this part.
|
||||
*
|
||||
* @return body section
|
||||
@ -72,6 +78,12 @@ public:
|
||||
*/
|
||||
ref <body> getBody();
|
||||
|
||||
/** Replaces the body section of this part.
|
||||
*
|
||||
* @param body new body section
|
||||
*/
|
||||
void setBody(ref <body> body);
|
||||
|
||||
/** Return the parent part of this part.
|
||||
*
|
||||
* @return parent part or NULL if not known
|
||||
|
@ -39,6 +39,8 @@
|
||||
|
||||
namespace vmime {
|
||||
|
||||
class header;
|
||||
class headerField;
|
||||
class message;
|
||||
class mailbox;
|
||||
class mailboxList;
|
||||
@ -77,6 +79,26 @@ public:
|
||||
|
||||
|
||||
Type getType() const;
|
||||
|
||||
protected:
|
||||
|
||||
/** Called by processHeader().
|
||||
* Decides what to do with the specified header field.
|
||||
*
|
||||
* @return NULL if the header should be removed, a reference to a new headerField
|
||||
* if the field is to be replaced, or a reference to the same headerField
|
||||
* that was passed if the field should be left as is
|
||||
*/
|
||||
ref <headerField> processHeaderField(ref <headerField> field);
|
||||
|
||||
/** Prepares the header before transmitting the message.
|
||||
* Removes headers that should not be present (eg. "Bcc", "Return-Path"),
|
||||
* or adds missing headers that are required/recommended by the RFCs.
|
||||
* The header is modified inline.
|
||||
*
|
||||
* @param header headers to process
|
||||
*/
|
||||
void processHeader(ref <header> header);
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user