aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Richard <[email protected]>2013-02-18 21:00:29 +0000
committerVincent Richard <[email protected]>2013-02-18 21:00:29 +0000
commite3bb8020e0b91c81047a2f1e7008dd93af78a7e0 (patch)
treecb1879cef23175646f6518b5f4f73b40f82d45fb
parentAdded helper function to replace header field. (diff)
downloadvmime-e3bb8020e0b91c81047a2f1e7008dd93af78a7e0.tar.gz
vmime-e3bb8020e0b91c81047a2f1e7008dd93af78a7e0.zip
Process header before transmitting message via SMTP.
-rw-r--r--src/body.cpp7
-rw-r--r--src/bodyPart.cpp19
-rw-r--r--src/net/transport.cpp99
-rw-r--r--vmime/bodyPart.hpp12
-rw-r--r--vmime/net/transport.hpp22
5 files changed, 151 insertions, 8 deletions
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 <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;
+ }
}
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 <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();
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 <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.
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 <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
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 <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);
};