From aeb5da43242ab1be2c9f955f855bf901ac43513a Mon Sep 17 00:00:00 2001 From: Vincent Richard Date: Wed, 23 Mar 2005 08:23:55 +0000 Subject: [PATCH] Basic support for 'Disposition' header field. --- ChangeLog | 3 + SConstruct | 8 +- src/constants.cpp | 44 +++++ src/disposition.cpp | 314 +++++++++++++++++++++++++++++++ src/headerFieldFactory.cpp | 3 + tests/parser/dispositionTest.cpp | 168 +++++++++++++++++ vmime/constants.hpp | 40 ++++ vmime/disposition.hpp | 148 +++++++++++++++ vmime/vmime.hpp | 1 + 9 files changed, 728 insertions(+), 1 deletion(-) create mode 100644 src/disposition.cpp create mode 100644 tests/parser/dispositionTest.cpp create mode 100644 vmime/disposition.hpp diff --git a/ChangeLog b/ChangeLog index 90d86856..c2a6af0a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,9 @@ VERSION 0.6.4cvs deleteMessages() when 'to == -1' and last message not being deleted (thanks to Stefan Uhrig). + * SConstruct: fixed compilation/linking problem with g++ and X86-64 on + static library: added -fPIC/-fpic in compiler flags. + 2005-03-17 Vincent Richard * base.{cpp|hpp}: renamed 'MIME_VERSION' to 'SUPPORTED_MIME_VERSION'. diff --git a/SConstruct b/SConstruct index 850d4243..b9e7d872 100644 --- a/SConstruct +++ b/SConstruct @@ -94,6 +94,7 @@ libvmime_sources = [ 'contentTypeField.cpp', 'contentTypeField.hpp', 'dateTime.cpp', 'dateTime.hpp', 'defaultAttachment.cpp', 'defaultAttachment.hpp', + 'disposition.cpp', 'disposition.hpp', 'emptyContentHandler.cpp', 'emptyContentHandler.hpp', 'encoder.cpp', 'encoder.hpp', 'encoder7bit.cpp', 'encoder7bit.hpp', @@ -305,6 +306,7 @@ libvmimetest_common = [ libvmimetest_sources = [ [ 'tests/parser/bodyPartTest', [ 'tests/parser/bodyPartTest.cpp' ] ], + [ 'tests/parser/dispositionTest', [ 'tests/parser/dispositionTest.cpp' ] ], [ 'tests/parser/encoderTest', [ 'tests/parser/encoderTest.cpp' ] ], [ 'tests/parser/headerTest', [ 'tests/parser/headerTest.cpp' ] ], [ 'tests/parser/mailboxTest', [ 'tests/parser/mailboxTest.cpp' ] ], @@ -1412,7 +1414,6 @@ VMIME_BUILTIN_PLATFORMS='' configure_in.write(""" - # # Flags # @@ -1432,6 +1433,7 @@ EXTRA_LIBS="" CFLAGS="" CXXFLAGS="" +# -- Debug if test x$VMIME_DEBUG = x1 ; then # -g OLD_CXXFLAGS="$CXXFLAGS" @@ -1446,6 +1448,10 @@ else AC_TRY_COMPILE(,,echo yes,echo no; CXXFLAGS="$OLD_CXXFLAGS") fi +# -- HACK: add -fPIC or -fpic on static library object files +EXTRA_CFLAGS="$EXTRA_CFLAGS $lt_prog_compiler_pic" + + # # Check to see if the compiler can handle some flags diff --git a/src/constants.cpp b/src/constants.cpp index 55de71fb..d4feec9f 100644 --- a/src/constants.cpp +++ b/src/constants.cpp @@ -176,6 +176,50 @@ namespace fields const string::value_type* const X_MAILER = "X-Mailer"; const string::value_type* const X_PRIORITY = "X-Priority"; + + // RFC-3798: Message Disposition + const string::value_type* const ORIGINAL_MESSAGE_ID = "Original-Message-ID"; + const string::value_type* const DISPOSITION_NOTIFICATION_TO = "Disposition-Notification-To"; + const string::value_type* const DISPOSITION_NOTIFICATION_OPTIONS = "Disposition-Notification-Options"; + const string::value_type* const DISPOSITION = "Disposition"; + const string::value_type* const FAILURE = "Failure"; + const string::value_type* const ERROR = "Error"; + const string::value_type* const WARNING = "Warning"; + const string::value_type* const ORIGINAL_RECIPIENT = "Original-Recipient"; + const string::value_type* const FINAL_RECIPIENT = "Final-Recipient"; + const string::value_type* const REPORTING_UA = "Reporting-UA"; + const string::value_type* const MDN_GATEWAY = "MDN-Gateway"; +} + + +// Constants for disposition action modes (RFC-3978). +namespace dispositionActionModes +{ + const string::value_type* const MANUAL = "manual"; + const string::value_type* const AUTOMATIC = "automatic"; +} + + +// Constants for disposition sending modes (RFC-3798). +namespace dispositionSendingModes +{ + const string::value_type* const SENT_MANUALLY = "MDN-sent-manually"; + const string::value_type* const SENT_AUTOMATICALLY ="MDN-sent-automatically"; +} + + +// Constants for disposition types (RFC-3798). +namespace dispositionTypes +{ + const string::value_type* const DISPLAYED = "displayed"; + const string::value_type* const DELETED = "deleted"; +} + + +// Constants for disposition modifiers (RFC-3798). +namespace dispositionModifiers +{ + const string::value_type* const ERROR = "error"; } diff --git a/src/disposition.cpp b/src/disposition.cpp new file mode 100644 index 00000000..b894f85e --- /dev/null +++ b/src/disposition.cpp @@ -0,0 +1,314 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2005 Vincent Richard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program 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 +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include "vmime/disposition.hpp" + +#include "vmime/parserHelpers.hpp" +#include "vmime/utility/stringUtils.hpp" + + +namespace vmime +{ + + +disposition::disposition() +{ +} + + +disposition::disposition(const string& actionMode, const string& sendingMode, + const string& type, const string& modifier) + : m_actionMode(actionMode), m_sendingMode(sendingMode), m_type(type) +{ + m_modifiers.push_back(modifier); +} + + +disposition* disposition::clone() const +{ + disposition* disp = new disposition; + + disp->m_actionMode = m_actionMode; + disp->m_sendingMode = m_sendingMode; + disp->m_type = m_type; + disp->m_modifiers.resize(m_modifiers.size()); + + std::copy(m_modifiers.begin(), m_modifiers.end(), disp->m_modifiers.begin()); + + return (disp); +} + + +void disposition::copyFrom(const component& other) +{ + const disposition& disp = dynamic_cast (other); + + m_actionMode = disp.m_actionMode; + m_sendingMode = disp.m_sendingMode; + m_type = disp.m_type; + m_modifiers.resize(disp.m_modifiers.size()); + + std::copy(disp.m_modifiers.begin(), disp.m_modifiers.end(), m_modifiers.begin()); +} + + +disposition& disposition::operator=(const disposition& other) +{ + copyFrom(other); + return (*this); +} + + +const std::vector disposition::getChildComponents() const +{ + return std::vector (); +} + + +void disposition::setActionMode(const string& mode) +{ + m_actionMode = mode; +} + + +const string& disposition::getActionMode() const +{ + return (m_actionMode); +} + + +void disposition::setSendingMode(const string& mode) +{ + m_sendingMode = mode; +} + + +const string& disposition::getSendingMode() const +{ + return (m_sendingMode); +} + + +void disposition::setType(const string& type) +{ + m_type = type; +} + + +const string& disposition::getType() const +{ + return (m_type); +} + + +void disposition::addModifier(const string& modifier) +{ + if (!hasModifier(modifier)) + m_modifiers.push_back(utility::stringUtils::toLower(modifier)); +} + + +void disposition::removeModifier(const string& modifier) +{ + const string modifierLC = utility::stringUtils::toLower(modifier); + + for (std::vector ::iterator it = m_modifiers.begin() ; + it != m_modifiers.end() ; ++it) + { + if (*it == modifierLC) + { + m_modifiers.erase(it); + break; + } + } +} + + +void disposition::removeAllModifiers() +{ + m_modifiers.clear(); +} + + +const bool disposition::hasModifier(const string& modifier) const +{ + const string modifierLC = utility::stringUtils::toLower(modifier); + + for (std::vector ::const_iterator it = m_modifiers.begin() ; + it != m_modifiers.end() ; ++it) + { + if (*it == modifierLC) + return (true); + } + + return (false); +} + + +const std::vector disposition::getModifierList() const +{ + return (m_modifiers); +} + + +void disposition::parse(const string& buffer, const string::size_type position, + const string::size_type end, string::size_type* newPosition) +{ + // disposition-mode ";" disposition-type + // [ "/" disposition-modifier *( "," disposition-modifier ) ] + // + // disposition-mode = action-mode "/" sending-mode + + string::size_type pos = position; + + while (pos < end && parserHelpers::isSpace(buffer[pos])) + ++pos; + + // -- disposition-mode + const string::size_type modeStart = pos; + string::size_type modeEnd = pos; + + while (pos < end && buffer[pos] != ';') + { + ++modeEnd; + ++pos; + } + + while (modeEnd > modeStart && parserHelpers::isSpace(buffer[modeEnd - 1])) + --modeEnd; + + const string mode = string(buffer.begin() + modeStart, buffer.begin() + modeEnd); + const string::size_type slash = mode.find('/'); + + if (slash != string::npos) + { + m_actionMode = string(mode.begin(), mode.begin() + slash); + m_sendingMode = string(mode.begin() + slash + 1, mode.end()); + } + else + { + m_actionMode = mode; + m_sendingMode.clear(); + } + + if (pos < end) + { + // Skip ';' + ++pos; + } + + while (pos < end && parserHelpers::isSpace(buffer[pos])) + ++pos; + + // -- disposition-type + const string::size_type typeStart = pos; + string::size_type typeEnd = pos; + + while (pos < end && buffer[pos] != '/') + { + ++typeEnd; + ++pos; + } + + while (typeEnd > typeStart && parserHelpers::isSpace(buffer[typeEnd - 1])) + --typeEnd; + + m_type = string(buffer.begin() + typeStart, buffer.begin() + typeEnd); + + m_modifiers.clear(); + + if (pos < end) // modifiers follow + { + // Skip '/' + ++pos; + + while (pos < end) + { + while (pos < end && parserHelpers::isSpace(buffer[pos])) + ++pos; + + const string::size_type modifierStart = pos; + string::size_type modifierEnd = pos; + + while (pos < end && buffer[pos] != ',') + { + ++modifierEnd; + ++pos; + } + + while (modifierEnd > modifierStart && parserHelpers::isSpace(buffer[modifierEnd - 1])) + --modifierEnd; + + if (modifierEnd > modifierStart) + { + m_modifiers.push_back(string(buffer.begin() + modifierStart, + buffer.begin() + modifierEnd)); + } + + // Skip ',' + if (pos < end) + ++pos; + } + } + + if (newPosition) + *newPosition = pos; +} + + +void disposition::generate(utility::outputStream& os, const string::size_type maxLineLength, + const string::size_type curLinePos, string::size_type* newLinePos) const +{ + string::size_type pos = curLinePos; + + const string actionMode = (m_actionMode.empty() ? "automatic-action" : m_actionMode); + const string sendingMode = (m_sendingMode.empty() ? "MDN-sent-automatically" : m_sendingMode); + + os << actionMode << "/" << sendingMode << ";"; + pos += actionMode.length() + 1 + sendingMode.length() + 1; + + if (pos > maxLineLength) + { + os << NEW_LINE_SEQUENCE; + pos = NEW_LINE_SEQUENCE_LENGTH; + } + + const string type = (m_type.empty() ? "displayed" : m_type); + + os << type; + pos += type.length(); + + if (m_modifiers.size() >= 1) + { + os << "/" << m_modifiers[0]; + pos += 1 + m_modifiers[0].length(); + + for (std::vector ::size_type i = 1 ; i < m_modifiers.size() ; ++i) + { + os << "," << m_modifiers[i]; + pos += 1 + m_modifiers[i].length(); + } + } + + if (newLinePos) + *newLinePos = pos; +} + + +} diff --git a/src/headerFieldFactory.cpp b/src/headerFieldFactory.cpp index 93e1b7fe..544a2ac2 100644 --- a/src/headerFieldFactory.cpp +++ b/src/headerFieldFactory.cpp @@ -56,6 +56,9 @@ headerFieldFactory::headerFieldFactory() registerName (vmime::fields::MESSAGE_ID); registerName (vmime::fields::CONTENT_LOCATION); registerName (vmime::fields::IN_REPLY_TO); + + registerName (vmime::fields::ORIGINAL_MESSAGE_ID); + registerName (vmime::fields::DISPOSITION_NOTIFICATION_TO); } diff --git a/tests/parser/dispositionTest.cpp b/tests/parser/dispositionTest.cpp new file mode 100644 index 00000000..e0c269f7 --- /dev/null +++ b/tests/parser/dispositionTest.cpp @@ -0,0 +1,168 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2005 Vincent Richard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program 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 +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include "../lib/unit++/unit++.h" + +#include +#include + +#include "vmime/vmime.hpp" +#include "vmime/platforms/posix/posixHandler.hpp" + +#include "tests/parser/testUtils.hpp" + +using namespace unitpp; + + +namespace +{ + class dispositionTest : public suite + { + void testParse() + { + // disposition-mode ";" disposition-type + // [ "/" disposition-modifier *( "," disposition-modifier ) ] + // + // disposition-mode = action-mode "/" sending-mode + + vmime::disposition disp1; + disp1.parse("mode"); + + assert_eq("1.1", "mode", disp1.getActionMode()); + assert_eq("1.2", "", disp1.getSendingMode()); + assert_eq("1.3", "", disp1.getType()); + assert_eq("1.4", 0, static_cast (disp1.getModifierList().size())); + + vmime::disposition disp2; + disp2.parse("amode/smode"); + + assert_eq("2.1", "amode", disp2.getActionMode()); + assert_eq("2.2", "smode", disp2.getSendingMode()); + assert_eq("2.3", "", disp2.getType()); + assert_eq("2.4", 0, static_cast (disp2.getModifierList().size())); + + vmime::disposition disp3; + disp3.parse("amode/smode;type"); + + assert_eq("3.1", "amode", disp3.getActionMode()); + assert_eq("3.2", "smode", disp3.getSendingMode()); + assert_eq("3.3", "type", disp3.getType()); + assert_eq("3.4", 0, static_cast (disp3.getModifierList().size())); + + vmime::disposition disp4; + disp4.parse("amode/smode;type/modif"); + + assert_eq("4.1", "amode", disp4.getActionMode()); + assert_eq("4.2", "smode", disp4.getSendingMode()); + assert_eq("4.3", "type", disp4.getType()); + assert_eq("4.4", 1, static_cast (disp4.getModifierList().size())); + assert_eq("4.5", "modif", disp4.getModifierList()[0]); + + vmime::disposition disp5; + disp5.parse("amode/smode;type/modif1,modif2"); + + assert_eq("5.1", "amode", disp5.getActionMode()); + assert_eq("5.2", "smode", disp5.getSendingMode()); + assert_eq("5.3", "type", disp5.getType()); + assert_eq("5.4", 2, static_cast (disp5.getModifierList().size())); + assert_eq("5.5", "modif1", disp5.getModifierList()[0]); + assert_eq("5.6", "modif2", disp5.getModifierList()[1]); + } + + void testGenerate() + { + vmime::disposition disp; + + assert_eq("1", "automatic-action/MDN-sent-automatically;displayed", disp.generate()); + + disp.setActionMode("amode"); + + assert_eq("2", "amode/MDN-sent-automatically;displayed", disp.generate()); + + disp.setActionMode("amode"); + disp.setSendingMode("smode"); + + assert_eq("3", "amode/smode;displayed", disp.generate()); + + disp.setType("type"); + + assert_eq("4", "amode/smode;type", disp.generate()); + + disp.addModifier("modif1"); + + assert_eq("5", "amode/smode;type/modif1", disp.generate()); + + disp.addModifier("modif2"); + + assert_eq("6", "amode/smode;type/modif1,modif2", disp.generate()); + } + + void testModifiers() + { + vmime::disposition disp1; + + assert_eq("1", false, disp1.hasModifier("foo")); + assert_eq("2", 0, static_cast (disp1.getModifierList().size())); + + disp1.addModifier("bar"); + + assert_eq("3", false, disp1.hasModifier("foo")); + assert_eq("4", true, disp1.hasModifier("bar")); + assert_eq("5", 1, static_cast (disp1.getModifierList().size())); + + disp1.addModifier("plop"); + + assert_eq("6", false, disp1.hasModifier("foo")); + assert_eq("7", true, disp1.hasModifier("bar")); + assert_eq("8", true, disp1.hasModifier("plop")); + assert_eq("9", 2, static_cast (disp1.getModifierList().size())); + + disp1.removeModifier("bar"); + + assert_eq("10", false, disp1.hasModifier("foo")); + assert_eq("11", false, disp1.hasModifier("bar")); + assert_eq("12", true, disp1.hasModifier("plop")); + assert_eq("13", 1, static_cast (disp1.getModifierList().size())); + + disp1.removeModifier("PlOp"); + + assert_eq("14", false, disp1.hasModifier("foo")); + assert_eq("15", false, disp1.hasModifier("bar")); + assert_eq("16", false, disp1.hasModifier("plop")); + assert_eq("17", 0, static_cast (disp1.getModifierList().size())); + } + + public: + + dispositionTest() : suite("vmime::disposition") + { + vmime::platformDependant::setHandler(); + + add("Parse", testcase(this, "Parse", &dispositionTest::testParse)); + add("Generate", testcase(this, "Generate", &dispositionTest::testGenerate)); + + add("Modifiers", testcase(this, "Modifiers", &dispositionTest::testModifiers)); + + suite::main().add("vmime::disposition", this); + } + + }; + + dispositionTest* theTest = new dispositionTest(); +} diff --git a/vmime/constants.hpp b/vmime/constants.hpp index 89e6f0c3..a13ea437 100644 --- a/vmime/constants.hpp +++ b/vmime/constants.hpp @@ -179,6 +179,46 @@ namespace vmime extern const string::value_type* const X_MAILER; extern const string::value_type* const X_PRIORITY; + + // RFC-3798: Message Disposition Notification + extern const string::value_type* const ORIGINAL_MESSAGE_ID; + extern const string::value_type* const DISPOSITION_NOTIFICATION_TO; + extern const string::value_type* const DISPOSITION_NOTIFICATION_OPTIONS; + extern const string::value_type* const DISPOSITION; + extern const string::value_type* const FAILURE; + extern const string::value_type* const ERROR; + extern const string::value_type* const WARNING; + extern const string::value_type* const ORIGINAL_RECIPIENT; + extern const string::value_type* const FINAL_RECIPIENT; + extern const string::value_type* const REPORTING_UA; + extern const string::value_type* const MDN_GATEWAY; + } + + /** Constants for disposition action modes (RFC-3978). */ + namespace dispositionActionModes + { + extern const string::value_type* const MANUAL; + extern const string::value_type* const AUTOMATIC; + } + + /** Constants for disposition sending modes (RFC-3798). */ + namespace dispositionSendingModes + { + extern const string::value_type* const SENT_MANUALLY; + extern const string::value_type* const SENT_AUTOMATICALLY; + } + + /** Constants for disposition types (RFC-3798). */ + namespace dispositionTypes + { + extern const string::value_type* const DISPLAYED; + extern const string::value_type* const DELETED; + } + + /** Constants for disposition modifiers (RFC-3798). */ + namespace dispositionModifiers + { + extern const string::value_type* const ERROR; } } diff --git a/vmime/disposition.hpp b/vmime/disposition.hpp new file mode 100644 index 00000000..8421962e --- /dev/null +++ b/vmime/disposition.hpp @@ -0,0 +1,148 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2005 Vincent Richard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program 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 +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef VMIME_DISPOSITION_HPP_INCLUDED +#define VMIME_DISPOSITION_HPP_INCLUDED + + +#include "vmime/base.hpp" +#include "vmime/component.hpp" + +#include + + +namespace vmime +{ + + +/** Disposition - from RFC-3798 (basic type). + */ + +class disposition : public component +{ +public: + + disposition(); + disposition(const string& actionMode, const string& sendingMode, const string& type, const string& modifier); + + + disposition* clone() const; + void copyFrom(const component& other); + disposition& operator=(const disposition& other); + + const std::vector getChildComponents() const; + + + /** Set the disposition action mode. + * See the constants in vmime::dispositionActionModes. + * + * @param mode disposition action mode + */ + void setActionMode(const string& mode); + + /** Return the disposition action mode. + * See the constants in vmime::dispositionActionModes. + * + * @return disposition action mode + */ + const string& getActionMode() const; + + /** Set the disposition sending mode. + * See the constants in vmime::dispositionSendingModes. + * + * @param mode disposition sending mode + */ + void setSendingMode(const string& mode); + + /** Return the disposition sending mode. + * See the constants in vmime::dispositionSendingModes. + * + * @return disposition sending mode + */ + const string& getSendingMode() const; + + /** Set the disposition type. + * See the constants in vmime::dispositionTypes. + * + * @param type disposition type + */ + void setType(const string& type); + + /** Return the disposition type. + * See the constants in vmime::dispositionTypes. + * + * @return disposition type + */ + const string& getType() const; + + /** Add a disposition modifier if it does not exist. + * See the constants in vmime::dispositionModifiers. + * + * @param modifier modifier to add + */ + void addModifier(const string& modifier); + + /** Remove the specified disposition modifier. + * See the constants in vmime::dispositionModifiers. + * + * @param modifier modifier to remove + */ + void removeModifier(const string& modifier); + + /** Remove all disposition modifiers. + */ + void removeAllModifiers(); + + /** Test whether a disposition modifier is set. + * + * @param modifier modifier to test + * @return true if the specified modifier is set, false otherwise + */ + const bool hasModifier(const string& modifier) const; + + /** Return the list of modifiers. + * + * @return list of modifiers + */ + const std::vector getModifierList() const; + +private: + + string m_actionMode; + string m_sendingMode; + string m_type; + + std::vector m_modifiers; + +public: + + using component::parse; + using component::generate; + + // Component parsing & assembling + void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); + void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; +}; + + +} // vmime + + +#endif // VMIME_DISPOSITION_HPP_INCLUDED + diff --git a/vmime/vmime.hpp b/vmime/vmime.hpp index 079980f3..965b2184 100644 --- a/vmime/vmime.hpp +++ b/vmime/vmime.hpp @@ -45,6 +45,7 @@ #include "vmime/mediaType.hpp" #include "vmime/messageId.hpp" #include "vmime/relay.hpp" +#include "vmime/disposition.hpp" #include "vmime/emptyContentHandler.hpp" #include "vmime/stringContentHandler.hpp"