Added new basic type 'messageIdSequence'.

This commit is contained in:
Vincent Richard 2005-03-27 13:06:45 +00:00
parent d6f67b0a4a
commit 4ab9332ce6
16 changed files with 694 additions and 19 deletions

View File

@ -2,6 +2,12 @@
VERSION 0.6.4cvs
================
2005-03-27 Vincent Richard <vincent@vincent-richard.net>
* messageIdSequence.{cpp|hpp}: added a new basic type "messageIdSequence" for
a list of message-ids separated by CFWS (used in "References:" field, for
example).
2005-03-25 Vincent Richard <vincent@vincent-richard.net>
* mdn/*.{cpp|hpp}: added support for Message Disposition Notifications (MDN),

View File

@ -122,6 +122,7 @@ libvmime_sources = [
'messageBuilder.cpp', 'messageBuilder.hpp',
'message.cpp', 'message.hpp',
'messageId.cpp', 'messageId.hpp',
'messageIdSequence.cpp', 'messageIdSequence.hpp',
'messageParser.cpp', 'messageParser.hpp',
'options.cpp', 'options.hpp',
'path.cpp', 'path.hpp',
@ -317,6 +318,8 @@ libvmimetest_sources = [
[ 'tests/parser/headerTest', [ 'tests/parser/headerTest.cpp' ] ],
[ 'tests/parser/mailboxTest', [ 'tests/parser/mailboxTest.cpp' ] ],
[ 'tests/parser/mediaTypeTest', [ 'tests/parser/mediaTypeTest.cpp' ] ],
[ 'tests/parser/messageIdTest', [ 'tests/parser/messageIdTest.cpp' ] ],
[ 'tests/parser/messageIdSequenceTest', [ 'tests/parser/messageIdSequenceTest.cpp' ] ],
[ 'tests/parser/pathTest', [ 'tests/parser/pathTest.cpp' ] ],
[ 'tests/parser/textTest', [ 'tests/parser/textTest.cpp' ] ],
[ 'tests/utility/md5Test', [ 'tests/utility/md5Test.cpp' ] ],

View File

@ -70,29 +70,24 @@ void addressList::parse(const string& buffer, const string::size_type position,
void addressList::generate(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
string::size_type pos = curLinePos;
if (!m_list.empty())
{
string::size_type pos = curLinePos;
std::vector <address*>::const_iterator i = m_list.begin();
for ( ; ; )
for (std::vector <address*>::const_iterator i = m_list.begin() ; ; )
{
(*i)->generate(os, maxLineLength - 2, pos, &pos);
if (++i != m_list.end())
{
if (++i == m_list.end())
break;
os << ", ";
pos += 2;
}
else
{
break;
}
}
if (newLinePos)
*newLinePos = pos;
}
}

View File

@ -176,6 +176,7 @@ namespace fields
const string::value_type* const CONTENT_ID = "Content-Id";
const string::value_type* const CONTENT_LOCATION = "Content-Location";
const string::value_type* const IN_REPLY_TO = "In-Reply-To";
const string::value_type* const REFERENCES = "References";
const string::value_type* const X_MAILER = "X-Mailer";
const string::value_type* const X_PRIORITY = "X-Priority";

View File

@ -162,6 +162,18 @@ exception* no_such_mailbox::clone() const { return new no_such_mailbox(*this); }
const string no_such_mailbox::name() const { return "no_such_mailbox"; }
//
// no_such_message_id
//
no_such_message_id::~no_such_message_id() throw() {}
no_such_message_id::no_such_message_id(const exception& other)
: exception("Message-Id not found.", other) {}
exception* no_such_message_id::clone() const { return new no_such_message_id(*this); }
const string no_such_message_id::name() const { return "no_such_message_id"; }
//
// no_such_address
//

View File

@ -55,7 +55,8 @@ headerFieldFactory::headerFieldFactory()
registerName <messageIdField>(vmime::fields::CONTENT_ID);
registerName <messageIdField>(vmime::fields::MESSAGE_ID);
registerName <defaultField>(vmime::fields::CONTENT_LOCATION);
registerName <messageIdField>(vmime::fields::IN_REPLY_TO);
registerName <messageIdSequenceField>(vmime::fields::IN_REPLY_TO);
registerName <messageIdSequenceField>(vmime::fields::REFERENCES);
registerName <messageIdField>(vmime::fields::ORIGINAL_MESSAGE_ID);
registerName <dispositionField>(vmime::fields::DISPOSITION);

View File

@ -129,19 +129,58 @@ void messageId::parse(const string& buffer, const string::size_type position,
}
messageId* messageId::parseNext(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
string::size_type pos = position;
while (pos < end && parserHelpers::isSpace(buffer[pos]))
++pos;
if (pos != end)
{
const string::size_type begin = pos;
while (pos < end && !parserHelpers::isSpace(buffer[pos]))
++pos;
messageId* mid = new messageId();
mid->parse(buffer, begin, pos, NULL);
if (newPosition != NULL)
*newPosition = pos;
return (mid);
}
if (newPosition != NULL)
*newPosition = end;
return (NULL);
}
const string messageId::getId() const
{
return (m_left + '@' + m_right);
}
void messageId::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
void messageId::generate(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
string::size_type pos = curLinePos;
if (curLinePos + m_left.length() + m_right.length() + 3 > maxLineLength)
{
os << NEW_LINE_SEQUENCE;
pos = NEW_LINE_SEQUENCE_LENGTH;
}
os << '<' << m_left << '@' << m_right << '>';
if (newLinePos)
*newLinePos = curLinePos + m_left.length() + m_right.length() + 3;
*newLinePos = pos + m_left.length() + m_right.length() + 3;
}

246
src/messageIdSequence.cpp Normal file
View File

@ -0,0 +1,246 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
//
// 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/messageIdSequence.hpp"
#include "vmime/exception.hpp"
namespace vmime
{
messageIdSequence::messageIdSequence()
{
}
messageIdSequence::~messageIdSequence()
{
removeAllMessageIds();
}
messageIdSequence::messageIdSequence(const messageIdSequence& midSeq)
: component()
{
copyFrom(midSeq);
}
messageIdSequence* messageIdSequence::clone() const
{
return new messageIdSequence(*this);
}
void messageIdSequence::copyFrom(const component& other)
{
const messageIdSequence& midSeq = dynamic_cast <const messageIdSequence&>(other);
removeAllMessageIds();
for (unsigned int i = 0 ; i < midSeq.m_list.size() ; ++i)
m_list.push_back(midSeq.m_list[i]->clone());
}
messageIdSequence& messageIdSequence::operator=(const messageIdSequence& other)
{
copyFrom(other);
return (*this);
}
const std::vector <const component*> messageIdSequence::getChildComponents() const
{
std::vector <const component*> res;
copy_vector(m_list, res);
return (res);
}
void messageIdSequence::parse(const string& buffer, const string::size_type position,
const string::size_type end, string::size_type* newPosition)
{
removeAllMessageIds();
string::size_type pos = position;
while (pos < end)
{
messageId* parsedMid = messageId::parseNext(buffer, pos, end, &pos);
if (parsedMid != NULL)
m_list.push_back(parsedMid);
}
setParsedBounds(position, end);
if (newPosition)
*newPosition = end;
}
void messageIdSequence::generate(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
string::size_type pos = curLinePos;
if (!m_list.empty())
{
for (std::vector <messageId*>::const_iterator it = m_list.begin() ; ; )
{
(*it)->generate(os, maxLineLength - 2, pos, &pos);
if (++it == m_list.end())
break;
os << " ";
pos++;
}
}
if (newLinePos)
*newLinePos = pos;
}
void messageIdSequence::appendMessageId(messageId* mid)
{
m_list.push_back(mid);
}
void messageIdSequence::insertMessageIdBefore(messageId* beforeMid, messageId* mid)
{
const std::vector <messageId*>::iterator it = std::find
(m_list.begin(), m_list.end(), beforeMid);
if (it == m_list.end())
throw exceptions::no_such_message_id();
m_list.insert(it, mid);
}
void messageIdSequence::insertMessageIdBefore(const int pos, messageId* mid)
{
m_list.insert(m_list.begin() + pos, mid);
}
void messageIdSequence::insertMessageIdAfter(messageId* afterMid, messageId* mid)
{
const std::vector <messageId*>::iterator it = std::find
(m_list.begin(), m_list.end(), afterMid);
if (it == m_list.end())
throw exceptions::no_such_message_id();
m_list.insert(it + 1, mid);
}
void messageIdSequence::insertMessageIdAfter(const int pos, messageId* mid)
{
m_list.insert(m_list.begin() + pos + 1, mid);
}
void messageIdSequence::removeMessageId(messageId* mid)
{
const std::vector <messageId*>::iterator it = std::find
(m_list.begin(), m_list.end(), mid);
if (it == m_list.end())
throw exceptions::no_such_message_id();
delete (*it);
m_list.erase(it);
}
void messageIdSequence::removeMessageId(const int pos)
{
const std::vector <messageId*>::iterator it = m_list.begin() + pos;
delete (*it);
m_list.erase(it);
}
void messageIdSequence::removeAllMessageIds()
{
free_container(m_list);
}
const int messageIdSequence::getMessageIdCount() const
{
return (m_list.size());
}
const bool messageIdSequence::isEmpty() const
{
return (m_list.empty());
}
messageId* messageIdSequence::getMessageIdAt(const int pos)
{
return (m_list[pos]);
}
const messageId* messageIdSequence::getMessageIdAt(const int pos) const
{
return (m_list[pos]);
}
const std::vector <const messageId*> messageIdSequence::getMessageIdList() const
{
std::vector <const messageId*> list;
list.reserve(m_list.size());
for (std::vector <messageId*>::const_iterator it = m_list.begin() ;
it != m_list.end() ; ++it)
{
list.push_back(*it);
}
return (list);
}
const std::vector <messageId*> messageIdSequence::getMessageIdList()
{
return (m_list);
}
} // vmime

View File

@ -0,0 +1,95 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
//
// 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 <iostream>
#include <ostream>
#include "vmime/vmime.hpp"
#include "vmime/platforms/posix/posixHandler.hpp"
#include "tests/parser/testUtils.hpp"
using namespace unitpp;
namespace
{
class messageIdSequenceTest : public suite
{
void testParse()
{
vmime::messageIdSequence s1;
s1.parse("");
assert_eq("1", 0, s1.getMessageIdCount());
vmime::messageIdSequence s2;
s2.parse(" \t ");
assert_eq("2", 0, s2.getMessageIdCount());
vmime::messageIdSequence s3;
s3.parse("<a@b>");
assert_eq("3.1", 1, s3.getMessageIdCount());
assert_eq("3.2", "a", s3.getMessageIdAt(0)->getLeft());
assert_eq("3.3", "b", s3.getMessageIdAt(0)->getRight());
vmime::messageIdSequence s4;
s4.parse("<a@b> \r\n\t<c@d>");
assert_eq("4.1", 2, s4.getMessageIdCount());
assert_eq("4.2", "a", s4.getMessageIdAt(0)->getLeft());
assert_eq("4.3", "b", s4.getMessageIdAt(0)->getRight());
assert_eq("4.4", "c", s4.getMessageIdAt(1)->getLeft());
assert_eq("4.5", "d", s4.getMessageIdAt(1)->getRight());
}
void testGenerate()
{
vmime::messageIdSequence s1;
s1.appendMessageId(new vmime::messageId("a", "b"));
assert_eq("1", "<a@b>", s1.generate());
vmime::messageIdSequence s2;
s2.appendMessageId(new vmime::messageId("a", "b"));
s2.appendMessageId(new vmime::messageId("c", "d"));
assert_eq("2", "<a@b> <c@d>", s2.generate());
}
public:
messageIdSequenceTest() : suite("vmime::messageIdSequence")
{
vmime::platformDependant::setHandler<vmime::platforms::posix::posixHandler>();
add("Parse", testcase(this, "Parse", &messageIdSequenceTest::testParse));
add("Generate", testcase(this, "Generate", &messageIdSequenceTest::testGenerate));
suite::main().add("vmime::messageIdSequence", this);
}
};
messageIdSequenceTest* theTest = new messageIdSequenceTest();
}

View File

@ -0,0 +1,84 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
//
// 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 <iostream>
#include <ostream>
#include "vmime/vmime.hpp"
#include "vmime/platforms/posix/posixHandler.hpp"
#include "tests/parser/testUtils.hpp"
using namespace unitpp;
namespace
{
class messageIdTest : public suite
{
void testParse()
{
vmime::messageId m1;
m1.parse("<a@b>");
assert_eq("1.1", "a", m1.getLeft());
assert_eq("1.2", "b", m1.getRight());
}
void testGenerate()
{
vmime::messageId m1;
assert_eq("1", "<@>", m1.generate());
vmime::messageId m2;
m2.setLeft("a");
assert_eq("2", "<a@>", m2.generate());
vmime::messageId m3;
m3.setRight("b");
assert_eq("3", "<@b>", m3.generate());
vmime::messageId m4;
m4.setLeft("a");
m4.setRight("b");
assert_eq("4", "<a@b>", m4.generate());
}
public:
messageIdTest() : suite("vmime::messageId")
{
vmime::platformDependant::setHandler<vmime::platforms::posix::posixHandler>();
add("Parse", testcase(this, "Parse", &messageIdTest::testParse));
add("Generate", testcase(this, "Generate", &messageIdTest::testGenerate));
suite::main().add("vmime::messageId", this);
}
};
messageIdTest* theTest = new messageIdTest();
}

View File

@ -186,6 +186,7 @@ namespace vmime
extern const string::value_type* const CONTENT_ID;
extern const string::value_type* const CONTENT_LOCATION;
extern const string::value_type* const IN_REPLY_TO;
extern const string::value_type* const REFERENCES;
extern const string::value_type* const X_MAILER;
extern const string::value_type* const X_PRIORITY;

View File

@ -164,6 +164,18 @@ public:
};
class no_such_message_id : public vmime::exception
{
public:
no_such_message_id(const exception& other = NO_EXCEPTION);
~no_such_message_id() throw();
exception* clone() const;
const string name() const;
};
class no_such_address : public vmime::exception
{
public:

View File

@ -67,8 +67,9 @@ public:
FIELD_ACCESS(Sender, SENDER, mailboxField)
FIELD_ACCESS(ReplyTo, REPLY_TO, mailboxField)
FIELD_ACCESS(DeliveredTo, DELIVERED_TO, mailboxField)
FIELD_ACCESS(InReplyTo, IN_REPLY_TO, messageIdField)
FIELD_ACCESS(InReplyTo, IN_REPLY_TO, messageIdSequenceField)
FIELD_ACCESS(ReturnPath, RETURN_PATH, pathField)
FIELD_ACCESS(References, REFERENCES, messageIdSequenceField)
FIELD_ACCESS(To, TO, addressListField)
FIELD_ACCESS(Cc, CC, addressListField)

View File

@ -34,6 +34,8 @@ namespace vmime
class messageId : public component
{
friend class messageIdSequence;
public:
messageId();
@ -106,6 +108,18 @@ public:
// 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;
protected:
/** Parse a message-id from an input buffer.
*
* @param buffer input buffer
* @param position position in the input buffer
* @param end end position in the input buffer
* @param newPosition will receive the new position in the input buffer
* @return a new message-id object, or null if no more message-id can be parsed from the input buffer
*/
static messageId* parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition);
};

163
vmime/messageIdSequence.hpp Normal file
View File

@ -0,0 +1,163 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
//
// 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_MESSAGEIDSEQUENCE_HPP_INCLUDED
#define VMIME_MESSAGEIDSEQUENCE_HPP_INCLUDED
#include "vmime/messageId.hpp"
namespace vmime
{
/** A list of message identifiers (basic type).
*/
class messageIdSequence : public component
{
public:
messageIdSequence();
messageIdSequence(const messageIdSequence& midSeq);
~messageIdSequence();
messageIdSequence* clone() const;
void copyFrom(const component& other);
messageIdSequence& operator=(const messageIdSequence& other);
const std::vector <const component*> getChildComponents() const;
/** Add a message-id at the end of the list.
*
* @param mid message-id to append
*/
void appendMessageId(messageId* mid);
/** Insert a new message-id before the specified message-id.
*
* @param beforeMid message-id before which the new message-id will be inserted
* @param mid message-id to insert
* @throw exceptions::no_such_messageid if the message-id is not in the list
*/
void insertMessageIdBefore(messageId* beforeMid, messageId* mid);
/** Insert a new message-id before the specified position.
*
* @param pos position at which to insert the new message-id (0 to insert at
* the beginning of the list)
* @param mid message-id to insert
*/
void insertMessageIdBefore(const int pos, messageId* mid);
/** Insert a new message-id after the specified message-id.
*
* @param afterMid message-id after which the new message-id will be inserted
* @param mid message-id to insert
* @throw exceptions::no_such_message_id if the message-id is not in the list
*/
void insertMessageIdAfter(messageId* afterMid, messageId* mid);
/** Insert a new message-id after the specified position.
*
* @param pos position of the message-id before the new message-id
* @param mid message-id to insert
*/
void insertMessageIdAfter(const int pos, messageId* mid);
/** Remove the specified message-id from the list.
*
* @param mid message-id to remove
* @throw exceptions::no_such_message_id if the message-id is not in the list
*/
void removeMessageId(messageId* mid);
/** Remove the message-id at the specified position.
*
* @param pos position of the message-id to remove
*/
void removeMessageId(const int pos);
/** Remove all message-ids from the list.
*/
void removeAllMessageIds();
/** Return the number of message-ides in the list.
*
* @return number of message-ides
*/
const int getMessageIdCount() const;
/** Tests whether the list of message-ides is empty.
*
* @return true if there is no message-id, false otherwise
*/
const bool isEmpty() const;
/** Return the message-id at the specified position.
*
* @param pos position
* @return message-id at position 'pos'
*/
messageId* getMessageIdAt(const int pos);
/** Return the message-id at the specified position.
*
* @param pos position
* @return message-id at position 'pos'
*/
const messageId* getMessageIdAt(const int pos) const;
/** Return the message-id list.
*
* @return list of message-ids
*/
const std::vector <const messageId*> getMessageIdList() const;
/** Return the message-id list.
*
* @return list of message-ids
*/
const std::vector <messageId*> getMessageIdList();
private:
std::vector <messageId*> m_list;
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_MESSAGEIDSEQUENCE_HPP_INCLUDED

View File

@ -35,6 +35,7 @@
#include "vmime/mailboxList.hpp"
#include "vmime/disposition.hpp"
#include "vmime/path.hpp"
#include "vmime/messageIdSequence.hpp"
namespace vmime
@ -96,6 +97,7 @@ DECLARE_STANDARD_FIELD(relayField, relay);
DECLARE_STANDARD_FIELD(mailboxListField, mailboxList);
DECLARE_STANDARD_FIELD(dispositionField, disposition);
DECLARE_STANDARD_FIELD(pathField, path);
DECLARE_STANDARD_FIELD(messageIdSequenceField, messageIdSequence);
#undef DECLARE_STANDARD_FIELD