diff --git a/src/body.cpp b/src/body.cpp index 1980f261..7cd7d401 100644 --- a/src/body.cpp +++ b/src/body.cpp @@ -674,6 +674,13 @@ void body::setParentPart(ref parent) { m_part = parent; m_header = (parent != NULL ? parent->getHeader() : NULL); + + for (std::vector >::iterator it = m_parts.begin() ; + it != m_parts.end() ; ++it) + { + ref childPart = *it; + childPart->m_parent = parent; + } } diff --git a/src/bodyPart.cpp b/src/bodyPart.cpp index 009a7b8c..fbe9f1ed 100644 --- a/src/bodyPart.cpp +++ b/src/bodyPart.cpp @@ -121,6 +121,12 @@ ref
bodyPart::getHeader() } +void bodyPart::setHeader(ref
h) +{ + m_header = h; +} + + const ref bodyPart::getBody() const { return (m_body); @@ -133,6 +139,19 @@ ref bodyPart::getBody() } +void bodyPart::setBody(ref b) +{ + ref oldPart = b->m_part.acquire(); + + m_body = b; + m_body->setParentPart(thisRef().dynamicCast ()); + + // A body is associated to one and only one part + if (oldPart != NULL) + oldPart->setBody(vmime::create ()); +} + + ref bodyPart::getParentPart() { return m_parent.acquire(); diff --git a/src/net/transport.cpp b/src/net/transport.cpp index f54d4dee..9a2db0ae 100644 --- a/src/net/transport.cpp +++ b/src/net/transport.cpp @@ -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 sess, const serviceInfos& infos, ref transport::processHeaderField(ref 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) +{ + if (header->getFieldCount() == 0) + return; + + // Remove/replace fields + for (size_t idx = header->getFieldCount() ; idx != 0 ; --idx) + { + ref field = header->getFieldAt(idx - 1); + ref 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 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
hdr = msg->getHeader()->clone().dynamicCast
(); + 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 bcc = msg->getHeader()->findField(fields::BCC); - msg->getHeader()->removeField(bcc); - } - catch (exceptions::no_such_field&) { } + XChangeMsgHeader(vmime::ref _msg, + vmime::ref _hdr) + : msg(_msg), hdr(msg->getHeader()) + { + // Set new header + msg->setHeader(_hdr); + } + + ~XChangeMsgHeader() + { + // Revert original header + msg->setHeader(hdr); + } + + private: + + vmime::ref msg; + vmime::ref hdr; + } headerExchanger(msg, hdr); // Generate the message, "stream" it and delegate the sending // to the generic send() function. diff --git a/vmime/bodyPart.hpp b/vmime/bodyPart.hpp index ff2a6481..6b96e923 100644 --- a/vmime/bodyPart.hpp +++ b/vmime/bodyPart.hpp @@ -60,6 +60,12 @@ public: */ ref
getHeader(); + /** Replaces the header section of this part. + * + * @param header the new header of this part + */ + void setHeader(ref
header); + /** Return the body section of this part. * * @return body section @@ -72,6 +78,12 @@ public: */ ref getBody(); + /** Replaces the body section of this part. + * + * @param body new body section + */ + void setBody(ref body); + /** Return the parent part of this part. * * @return parent part or NULL if not known diff --git a/vmime/net/transport.hpp b/vmime/net/transport.hpp index eeab625b..e39e3fd1 100644 --- a/vmime/net/transport.hpp +++ b/vmime/net/transport.hpp @@ -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 processHeaderField(ref 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); };