aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--SConstruct1
-rw-r--r--src/exception.cpp12
-rw-r--r--src/headerField.cpp11
-rw-r--r--src/headerFieldFactory.cpp15
-rw-r--r--tests/parser/headerFieldTest.cpp56
-rw-r--r--vmime/exception.hpp6
-rw-r--r--vmime/headerField.hpp6
-rw-r--r--vmime/headerFieldFactory.hpp35
8 files changed, 128 insertions, 14 deletions
diff --git a/SConstruct b/SConstruct
index 35ac452c..1db0d2e2 100644
--- a/SConstruct
+++ b/SConstruct
@@ -360,6 +360,7 @@ libvmimetest_sources = [
'tests/parser/dispositionTest.cpp',
'tests/parser/emailAddressTest.cpp',
'tests/parser/headerTest.cpp',
+ 'tests/parser/headerFieldTest.cpp',
'tests/parser/htmlTextPartTest.cpp',
'tests/parser/mailboxTest.cpp',
'tests/parser/mediaTypeTest.cpp',
diff --git a/src/exception.cpp b/src/exception.cpp
index 85f1f4f3..a341c161 100644
--- a/src/exception.cpp
+++ b/src/exception.cpp
@@ -94,15 +94,15 @@ namespace exceptions
//
-// bad_field_type
+// bad_field_value_type
//
-bad_field_type::~bad_field_type() throw() {}
-bad_field_type::bad_field_type(const exception& other)
- : exception("Bad field type.", other) {}
+bad_field_value_type::~bad_field_value_type() throw() {}
+bad_field_value_type::bad_field_value_type(const string& fieldName, const exception& other)
+ : exception("Bad value type for field '" + fieldName + "'.", other) {}
-exception* bad_field_type::clone() const { return new bad_field_type(*this); }
-const char* bad_field_type::name() const throw() { return "bad_field_type"; }
+exception* bad_field_value_type::clone() const { return new bad_field_value_type(*this); }
+const char* bad_field_value_type::name() const throw() { return "bad_field_value_type"; }
diff --git a/src/headerField.cpp b/src/headerField.cpp
index 0a17abac..59b10e76 100644
--- a/src/headerField.cpp
+++ b/src/headerField.cpp
@@ -26,6 +26,8 @@
#include "vmime/parserHelpers.hpp"
+#include "vmime/exception.hpp"
+
namespace vmime
{
@@ -324,6 +326,9 @@ ref <headerFieldValue> headerField::getValue()
void headerField::setValue(ref <headerFieldValue> value)
{
+ if (!headerFieldFactory::getInstance()->isValueTypeValid(*this, *value))
+ throw exceptions::bad_field_value_type(getName());
+
if (value != NULL)
m_value = value;
}
@@ -331,12 +336,18 @@ void headerField::setValue(ref <headerFieldValue> value)
void headerField::setValueConst(ref <const headerFieldValue> value)
{
+ if (!headerFieldFactory::getInstance()->isValueTypeValid(*this, *value))
+ throw exceptions::bad_field_value_type(getName());
+
m_value = value->clone().dynamicCast <headerFieldValue>();
}
void headerField::setValue(const headerFieldValue& value)
{
+ if (!headerFieldFactory::getInstance()->isValueTypeValid(*this, value))
+ throw exceptions::bad_field_value_type(getName());
+
m_value = value.clone().dynamicCast <headerFieldValue>();
}
diff --git a/src/headerFieldFactory.cpp b/src/headerFieldFactory.cpp
index e1c725c0..7e021f59 100644
--- a/src/headerFieldFactory.cpp
+++ b/src/headerFieldFactory.cpp
@@ -126,7 +126,7 @@ ref <headerFieldValue> headerFieldFactory::createValue(const string& fieldName)
ref <headerFieldValue> value = NULL;
if (pos != m_valueMap.end())
- value = ((*pos).second)();
+ value = ((*pos).second.allocFunc)();
else
value = registerer <headerFieldValue, text>::creator();
@@ -134,5 +134,18 @@ ref <headerFieldValue> headerFieldFactory::createValue(const string& fieldName)
}
+bool headerFieldFactory::isValueTypeValid
+ (const headerField& field, const headerFieldValue& value) const
+{
+ ValueMap::const_iterator pos = m_valueMap.find
+ (utility::stringUtils::toLower(field.getName()));
+
+ if (pos != m_valueMap.end())
+ return ((*pos).second.checkTypeFunc)(value);
+
+ return true; // No info on this field
+}
+
+
} // vmime
diff --git a/tests/parser/headerFieldTest.cpp b/tests/parser/headerFieldTest.cpp
new file mode 100644
index 00000000..2c8a954c
--- /dev/null
+++ b/tests/parser/headerFieldTest.cpp
@@ -0,0 +1,56 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2013 Vincent Richard <[email protected]>
+//
+// 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 3 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+#define VMIME_TEST_SUITE headerFieldTest
+#define VMIME_TEST_SUITE_MODULE "Parser"
+
+
+VMIME_TEST_SUITE_BEGIN
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testBadValueType)
+ VMIME_TEST_LIST_END
+
+
+ void testBadValueType()
+ {
+ vmime::headerFieldFactory *hfactory = vmime::headerFieldFactory::getInstance();
+
+ // "To" header field accepts values of type "addressList"
+ vmime::ref <vmime::headerField> to = hfactory->create(vmime::fields::TO);
+ VASSERT_THROW("to",
+ to->setValue(vmime::mailbox("[email protected]")),
+ vmime::exceptions::bad_field_value_type);
+
+ // Unregistered header field accepts any value type
+ vmime::ref <vmime::headerField> custom = hfactory->create("X-MyCustomHeader");
+ VASSERT_NO_THROW("custom/1",
+ custom->setValue(vmime::mailbox("[email protected]")));
+ VASSERT_NO_THROW("custom/2",
+ custom->setValue(vmime::text("field value text")));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime/exception.hpp b/vmime/exception.hpp
index 355cd851..fc9efed6 100644
--- a/vmime/exception.hpp
+++ b/vmime/exception.hpp
@@ -98,12 +98,12 @@ namespace exceptions
{
-class bad_field_type : public vmime::exception
+class bad_field_value_type : public vmime::exception
{
public:
- bad_field_type(const exception& other = NO_EXCEPTION);
- ~bad_field_type() throw();
+ bad_field_value_type(const string& fieldName, const exception& other = NO_EXCEPTION);
+ ~bad_field_value_type() throw();
exception* clone() const;
const char* name() const throw();
diff --git a/vmime/headerField.hpp b/vmime/headerField.hpp
index 857ee051..72d639c9 100644
--- a/vmime/headerField.hpp
+++ b/vmime/headerField.hpp
@@ -94,12 +94,16 @@ public:
/** Set the value of this field.
*
+ * @throw exceptions::bad_field_value_type if the value type is not
+ * valid for this header field
* @param value new value
*/
virtual void setValue(ref <headerFieldValue> value);
/** Set the value of this field by cloning the specified value.
*
+ * @throw exceptions::bad_field_value_type if the value type is not
+ * valid for this header field
* @param value new value
*/
virtual void setValueConst(ref <const headerFieldValue> value);
@@ -107,6 +111,8 @@ public:
/** Set the value of this field (reference version).
* The value will be cloned.
*
+ * @throw exceptions::bad_field_value_type if the value type is not
+ * valid for this header field
* @param value new value
*/
virtual void setValue(const headerFieldValue& value);
diff --git a/vmime/headerFieldFactory.hpp b/vmime/headerFieldFactory.hpp
index 67e7418c..6132cee6 100644
--- a/vmime/headerFieldFactory.hpp
+++ b/vmime/headerFieldFactory.hpp
@@ -48,8 +48,17 @@ protected:
NameMap m_nameMap;
- typedef ref <headerFieldValue> (*ValueAllocFunc)(void);
- typedef std::map <string, ValueAllocFunc> ValueMap;
+
+ struct ValueInfo
+ {
+ typedef ref <headerFieldValue> (*ValueAllocFunc)(void);
+ typedef bool (*ValueTypeCheckFunc)(const object&);
+
+ ValueAllocFunc allocFunc;
+ ValueTypeCheckFunc checkTypeFunc;
+ };
+
+ typedef std::map <string, ValueInfo> ValueMap;
ValueMap m_valueMap;
@@ -64,6 +73,12 @@ public:
{
public:
+ static bool checkType(const object& obj)
+ {
+ const TYPE* typedObj = dynamic_cast <const TYPE*>(&obj);
+ return typedObj != NULL;
+ }
+
static ref <BASE_TYPE> creator()
{
// Allocate a new object
@@ -94,9 +109,12 @@ public:
template <class T>
void registerFieldValue(const string& name)
{
+ ValueInfo vi;
+ vi.allocFunc = &registerer <headerFieldValue, T>::creator;
+ vi.checkTypeFunc = &registerer <headerField, T>::checkType;
+
m_valueMap.insert(ValueMap::value_type
- (utility::stringUtils::toLower(name),
- &registerer <headerFieldValue, T>::creator));
+ (utility::stringUtils::toLower(name), vi));
}
/** Create a new field object for the specified field name.
@@ -116,6 +134,15 @@ public:
* @return a new value object for the field
*/
ref <headerFieldValue> createValue(const string& fieldName);
+
+ /** Returns whether the specified value type is valid for the specified field.
+ *
+ * @param field header field
+ * @param value value for this header field
+ * @return true if the value type is compatible with the header field, or
+ * false otherwise
+ */
+ bool isValueTypeValid(const headerField& field, const headerFieldValue& value) const;
};