aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/address.cpp201
-rw-r--r--src/address.hpp99
-rw-r--r--src/addressList.cpp188
-rw-r--r--src/addressList.hpp148
-rw-r--r--src/addressListField.cpp67
-rw-r--r--src/addressListField.hpp70
-rw-r--r--src/attachment.hpp82
-rw-r--r--src/base.cpp877
-rw-r--r--src/base.hpp216
-rw-r--r--src/body.cpp543
-rw-r--r--src/body.hpp234
-rw-r--r--src/bodyPart.cpp75
-rw-r--r--src/bodyPart.hpp80
-rw-r--r--src/charset.cpp305
-rw-r--r--src/charset.hpp86
-rw-r--r--src/charsetParameter.cpp50
-rw-r--r--src/charsetParameter.hpp55
-rw-r--r--src/component.cpp47
-rw-r--r--src/component.hpp84
-rw-r--r--src/constants.cpp151
-rw-r--r--src/constants.hpp156
-rw-r--r--src/contentDispositionField.cpp62
-rw-r--r--src/contentDispositionField.hpp79
-rw-r--r--src/contentEncodingField.cpp62
-rw-r--r--src/contentEncodingField.hpp61
-rw-r--r--src/contentHandler.cpp369
-rw-r--r--src/contentHandler.hpp125
-rw-r--r--src/contentTypeField.cpp62
-rw-r--r--src/contentTypeField.hpp72
-rw-r--r--src/dateField.cpp66
-rw-r--r--src/dateField.hpp70
-rw-r--r--src/dateParameter.cpp50
-rw-r--r--src/dateParameter.hpp55
-rw-r--r--src/dateTime.cpp702
-rw-r--r--src/dateTime.hpp242
-rw-r--r--src/defaultAttachment.cpp91
-rw-r--r--src/defaultAttachment.hpp69
-rw-r--r--src/defaultField.cpp71
-rw-r--r--src/defaultField.hpp70
-rw-r--r--src/defaultParameter.cpp117
-rw-r--r--src/defaultParameter.hpp55
-rw-r--r--src/defaultParameterizedHeaderField.cpp62
-rw-r--r--src/defaultParameterizedHeaderField.hpp63
-rw-r--r--src/disposition.cpp91
-rw-r--r--src/disposition.hpp74
-rw-r--r--src/encoder.cpp69
-rw-r--r--src/encoder.hpp95
-rw-r--r--src/encoder7bit.cpp32
-rw-r--r--src/encoder7bit.hpp45
-rw-r--r--src/encoder8bit.cpp32
-rw-r--r--src/encoder8bit.hpp45
-rw-r--r--src/encoderB64.cpp265
-rw-r--r--src/encoderB64.hpp55
-rw-r--r--src/encoderBinary.cpp32
-rw-r--r--src/encoderBinary.hpp45
-rw-r--r--src/encoderDefault.cpp50
-rw-r--r--src/encoderDefault.hpp48
-rw-r--r--src/encoderFactory.cpp70
-rw-r--r--src/encoderFactory.hpp183
-rw-r--r--src/encoderQP.cpp422
-rw-r--r--src/encoderQP.hpp55
-rw-r--r--src/encoderUUE.cpp289
-rw-r--r--src/encoderUUE.hpp50
-rw-r--r--src/encoding.cpp161
-rw-r--r--src/encoding.hpp87
-rw-r--r--src/exception.hpp558
-rw-r--r--src/fileAttachment.cpp123
-rw-r--r--src/fileAttachment.hpp90
-rw-r--r--src/header.cpp452
-rw-r--r--src/header.hpp266
-rw-r--r--src/headerField.cpp266
-rw-r--r--src/headerField.hpp113
-rw-r--r--src/headerFieldFactory.cpp139
-rw-r--r--src/headerFieldFactory.hpp85
-rw-r--r--src/htmlTextPart.cpp371
-rw-r--r--src/htmlTextPart.hpp180
-rw-r--r--src/mailbox.cpp450
-rw-r--r--src/mailbox.hpp105
-rw-r--r--src/mailboxField.cpp95
-rw-r--r--src/mailboxField.hpp70
-rw-r--r--src/mailboxGroup.cpp237
-rw-r--r--src/mailboxGroup.hpp155
-rw-r--r--src/mailboxList.cpp46
-rw-r--r--src/mailboxList.hpp127
-rw-r--r--src/mailboxListField.cpp60
-rw-r--r--src/mailboxListField.hpp68
-rw-r--r--src/mediaType.cpp127
-rw-r--r--src/mediaType.hpp78
-rw-r--r--src/message.cpp65
-rw-r--r--src/message.hpp55
-rw-r--r--src/messageBuilder.cpp188
-rw-r--r--src/messageBuilder.hpp99
-rw-r--r--src/messageId.cpp184
-rw-r--r--src/messageId.hpp82
-rw-r--r--src/messageIdField.cpp66
-rw-r--r--src/messageIdField.hpp70
-rw-r--r--src/messageParser.cpp321
-rw-r--r--src/messageParser.hpp98
-rw-r--r--src/messaging/IMAPConnection.cpp263
-rw-r--r--src/messaging/IMAPConnection.hpp110
-rw-r--r--src/messaging/IMAPFolder.cpp1490
-rw-r--r--src/messaging/IMAPFolder.hpp154
-rw-r--r--src/messaging/IMAPMessage.cpp843
-rw-r--r--src/messaging/IMAPMessage.hpp108
-rw-r--r--src/messaging/IMAPParser.hpp5075
-rw-r--r--src/messaging/IMAPStore.cpp257
-rw-r--r--src/messaging/IMAPStore.hpp112
-rw-r--r--src/messaging/IMAPTag.cpp97
-rw-r--r--src/messaging/IMAPTag.hpp64
-rw-r--r--src/messaging/IMAPUtils.cpp553
-rw-r--r--src/messaging/IMAPUtils.hpp65
-rw-r--r--src/messaging/POP3Folder.cpp661
-rw-r--r--src/messaging/POP3Folder.hpp142
-rw-r--r--src/messaging/POP3Message.cpp220
-rw-r--r--src/messaging/POP3Message.hpp88
-rw-r--r--src/messaging/POP3Store.cpp603
-rw-r--r--src/messaging/POP3Store.hpp110
-rw-r--r--src/messaging/SMTPTransport.cpp575
-rw-r--r--src/messaging/SMTPTransport.hpp95
-rw-r--r--src/messaging/authHelper.cpp105
-rw-r--r--src/messaging/authHelper.hpp38
-rw-r--r--src/messaging/authenticationInfos.cpp40
-rw-r--r--src/messaging/authenticationInfos.hpp64
-rw-r--r--src/messaging/authenticator.cpp33
-rw-r--r--src/messaging/authenticator.hpp53
-rw-r--r--src/messaging/builtinServices.inl46
-rw-r--r--src/messaging/defaultAuthenticator.cpp41
-rw-r--r--src/messaging/defaultAuthenticator.hpp55
-rw-r--r--src/messaging/events.cpp110
-rw-r--r--src/messaging/events.hpp174
-rw-r--r--src/messaging/folder.cpp96
-rw-r--r--src/messaging/folder.hpp373
-rw-r--r--src/messaging/maildirFolder.cpp552
-rw-r--r--src/messaging/maildirFolder.hpp144
-rw-r--r--src/messaging/maildirMessage.cpp28
-rw-r--r--src/messaging/maildirMessage.hpp78
-rw-r--r--src/messaging/maildirStore.cpp165
-rw-r--r--src/messaging/maildirStore.hpp102
-rw-r--r--src/messaging/maildirUtils.cpp87
-rw-r--r--src/messaging/maildirUtils.hpp72
-rw-r--r--src/messaging/message.cpp46
-rw-r--r--src/messaging/message.hpp280
-rw-r--r--src/messaging/progressionListener.hpp75
-rw-r--r--src/messaging/service.cpp44
-rw-r--r--src/messaging/service.hpp143
-rw-r--r--src/messaging/serviceFactory.cpp102
-rw-r--r--src/messaging/serviceFactory.hpp207
-rw-r--r--src/messaging/serviceInfos.hpp75
-rw-r--r--src/messaging/session.cpp88
-rw-r--r--src/messaging/session.hpp113
-rw-r--r--src/messaging/simpleAuthenticator.cpp45
-rw-r--r--src/messaging/simpleAuthenticator.hpp59
-rw-r--r--src/messaging/socket.hpp98
-rw-r--r--src/messaging/store.hpp75
-rw-r--r--src/messaging/timeoutHandler.hpp71
-rw-r--r--src/messaging/transport.hpp76
-rw-r--r--src/messaging/url.cpp226
-rw-r--r--src/messaging/url.hpp125
-rw-r--r--src/messaging/urlUtils.cpp93
-rw-r--r--src/messaging/urlUtils.hpp51
-rw-r--r--src/options.cpp27
-rw-r--r--src/options.hpp98
-rw-r--r--src/parameter.cpp43
-rw-r--r--src/parameter.hpp55
-rw-r--r--src/parameterFactory.cpp71
-rw-r--r--src/parameterFactory.hpp73
-rw-r--r--src/parameterizedHeaderField.cpp335
-rw-r--r--src/parameterizedHeaderField.hpp201
-rw-r--r--src/parserHelpers.hpp80
-rw-r--r--src/plainTextPart.cpp80
-rw-r--r--src/plainTextPart.hpp58
-rw-r--r--src/platformDependant.cpp35
-rw-r--r--src/platformDependant.hpp155
-rw-r--r--src/propertySet.cpp218
-rw-r--r--src/propertySet.hpp340
-rw-r--r--src/relayField.cpp239
-rw-r--r--src/relayField.hpp93
-rw-r--r--src/text.cpp240
-rw-r--r--src/text.hpp176
-rw-r--r--src/textField.cpp69
-rw-r--r--src/textField.hpp70
-rw-r--r--src/textParameter.cpp50
-rw-r--r--src/textParameter.hpp54
-rw-r--r--src/textPart.hpp66
-rw-r--r--src/textPartFactory.cpp60
-rw-r--r--src/textPartFactory.hpp74
-rw-r--r--src/types.hpp43
-rw-r--r--src/utility/file.hpp218
-rw-r--r--src/utility/md5.cpp331
-rw-r--r--src/utility/md5.hpp68
-rw-r--r--src/utility/path.cpp196
-rw-r--r--src/utility/path.hpp124
-rw-r--r--src/utility/random.cpp59
-rw-r--r--src/utility/random.hpp62
-rw-r--r--src/utility/singleton.cpp53
-rw-r--r--src/utility/singleton.hpp92
-rw-r--r--src/utility/smartPtr.hpp166
-rw-r--r--src/utility/stream.cpp257
-rw-r--r--src/utility/stream.hpp263
-rw-r--r--src/utility/stringProxy.cpp131
-rw-r--r--src/utility/stringProxy.hpp90
-rw-r--r--src/vmime93
-rw-r--r--src/word.cpp102
-rw-r--r--src/word.hpp74
204 files changed, 35988 insertions, 0 deletions
diff --git a/src/address.cpp b/src/address.cpp
new file mode 100644
index 00000000..481cc209
--- /dev/null
+++ b/src/address.cpp
@@ -0,0 +1,201 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "address.hpp"
+
+#include "mailbox.hpp"
+#include "mailboxGroup.hpp"
+
+#include "parserHelpers.hpp"
+
+
+namespace vmime
+{
+
+
+address::address()
+{
+}
+
+
+/*
+
+ RFC #2822:
+ 3.4. ADDRESS SPECIFICATION
+
+ Addresses occur in several message header fields to indicate senders
+ and recipients of messages. An address may either be an individual
+ mailbox, or a group of mailboxes.
+
+address = mailbox / group
+
+mailbox = name-addr / addr-spec
+
+name-addr = [display-name] angle-addr
+
+angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
+
+group = display-name ":" [mailbox-list / CFWS] ";"
+ [CFWS]
+
+display-name = phrase
+
+mailbox-list = (mailbox *("," mailbox)) / obs-mbox-list
+
+address-list = (address *("," address)) / obs-addr-list
+
+*/
+
+address* address::parseNext(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ bool escaped = false;
+ bool quoted = false;
+ bool quotedRFC2047 = false;
+ bool inRouteAddr = false;
+ bool isGroup = false;
+ bool stop = false;
+
+ string::size_type pos = position;
+
+ while (pos < end && isspace(buffer[pos]))
+ ++pos;
+
+ const string::size_type start = pos;
+
+ while (!stop && pos < end)
+ {
+ if (escaped)
+ {
+ escaped = false;
+ }
+ else
+ {
+ switch (buffer[pos])
+ {
+ case '\\':
+ escaped = true;
+ break;
+ case '"':
+ quoted = !quoted;
+ break;
+ case '<':
+ inRouteAddr = true;
+ break;
+ case '>':
+ inRouteAddr = false;
+ break;
+ case '=':
+
+ if (pos + 1 < end && buffer[pos + 1] == '?')
+ {
+ ++pos;
+ quotedRFC2047 = true;
+ }
+
+ break;
+
+ case '?':
+
+ if (quotedRFC2047 && pos + 1 < end && buffer[pos + 1] == '=')
+ {
+ ++pos;
+ quotedRFC2047 = false;
+ }
+
+ break;
+
+ default:
+ {
+ if (!quoted && !quotedRFC2047 && !inRouteAddr)
+ {
+ switch (buffer[pos])
+ {
+ case ';':
+
+ if (isGroup)
+ {
+ if (pos + 1 < end && buffer[pos + 1] == ',')
+ ++pos;
+ }
+
+ stop = true;
+ break;
+
+ case ':':
+
+ isGroup = true;
+ break;
+
+ case ',':
+
+ if (!isGroup) stop = true;
+ break;
+ }
+ }
+
+ break;
+ }
+
+ }
+ }
+
+ if (!stop)
+ ++pos;
+ }
+
+ if (newPosition)
+ {
+ if (pos == end)
+ *newPosition = end;
+ else
+ *newPosition = pos + 1; // ',' or ';'
+ }
+
+ // Parse extracted address (mailbox or group)
+ if (pos != start)
+ {
+ address* parsedAddress = isGroup
+ ? static_cast<address*>(new mailboxGroup)
+ : static_cast<address*>(new mailbox);
+
+ try
+ {
+ parsedAddress->parse(buffer, start, pos, NULL);
+ return (parsedAddress);
+ }
+ catch (std::exception&)
+ {
+ delete (parsedAddress);
+ throw;
+ }
+ }
+
+ return (NULL);
+}
+
+
+address& address::operator=(const address& addr)
+{
+ copyFrom(addr);
+ return (*this);
+}
+
+
+} // vmime
diff --git a/src/address.hpp b/src/address.hpp
new file mode 100644
index 00000000..a3d8cedb
--- /dev/null
+++ b/src/address.hpp
@@ -0,0 +1,99 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_ADDRESS_HPP_INCLUDED
+#define VMIME_ADDRESS_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+
+
+namespace vmime
+{
+
+
+/** Abstract class representing a mailbox or a group of mailboxes.
+ *
+ * This class define a common behaviour for the mailbox
+ * and mailboxGroup classes.
+ */
+
+class address : public component
+{
+ friend class addressList;
+
+protected:
+
+ address();
+
+public:
+
+ /** Copy data from another object to this object.
+ * Both objects must be the same type.
+ *
+ * @param addr other object
+ */
+ address& operator=(const address& addr);
+
+ /** Duplicate this object.
+ *
+ * @return a copy of this object
+ */
+ virtual address* clone() const = 0;
+
+ /** Copy data from another object to this object.
+ * Both objects must be the same type.
+ *
+ * @param addr other object
+ */
+ virtual void copyFrom(const address& addr) = 0;
+
+ /** Check whether this address is empty (no mailboxes specified
+ * if this is a mailboxGroup -or- no email specified if this is
+ * a mailbox).
+ *
+ * @return true if this address is empty
+ */
+ virtual const bool empty() const = 0;
+
+ /** Test whether this is object is a mailboxGroup.
+ *
+ * @return true if this is a mailboxGroup, false otherwise
+ */
+ virtual const bool isGroup() const = 0;
+
+protected:
+
+ /** Parse an address 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 address object, or null if no more address is available in the input buffer
+ */
+ static address* parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition);
+};
+
+
+} // vmime
+
+
+#endif // VMIME_ADDRESS_HPP_INCLUDED
diff --git a/src/addressList.cpp b/src/addressList.cpp
new file mode 100644
index 00000000..c532c16d
--- /dev/null
+++ b/src/addressList.cpp
@@ -0,0 +1,188 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "addressList.hpp"
+#include "parserHelpers.hpp"
+
+
+namespace vmime
+{
+
+
+addressList::addressList()
+{
+}
+
+
+addressList::addressList(const class addressList& addressList)
+ : component()
+{
+ copyFrom(addressList);
+}
+
+
+addressList::~addressList()
+{
+ clear();
+}
+
+
+void addressList::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ clear();
+
+ string::size_type pos = position;
+
+ while (pos < end)
+ {
+ address* parsedAddress = address::parseNext(buffer, pos, end, &pos);
+
+ if (parsedAddress != NULL)
+ m_list.push_back(parsedAddress);
+ }
+
+ if (newPosition)
+ *newPosition = end;
+}
+
+
+void addressList::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ if (!m_list.empty())
+ {
+ string::size_type pos = curLinePos;
+ const_iterator i = m_list.begin();
+
+ for ( ; ; )
+ {
+ (*i).generate(os, maxLineLength - 2, pos, &pos);
+
+ if (++i != m_list.end())
+ {
+ os << ", ";
+ pos += 2;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (newLinePos)
+ *newLinePos = pos;
+ }
+}
+
+
+/** Return the number of addresses in the list.
+ *
+ * @return number of addresses in the list
+ */
+
+const std::vector <address*>::size_type addressList::size() const
+{
+ return (m_list.size());
+}
+
+
+/** Return the number of addresses in the list.
+ *
+ * @return number of addresses in the list
+ */
+
+const std::vector <address*>::size_type addressList::count() const
+{
+ return (m_list.size());
+}
+
+
+/** Test whether the list is empty.
+ *
+ * @return true if the list is empty, false otherwise
+ */
+
+const bool addressList::empty() const
+{
+ return (m_list.empty());
+}
+
+
+/** Append an address to the list.
+ *
+ * @param addr the address to add
+ */
+
+void addressList::append(const address& addr)
+{
+ m_list.push_back(addr.clone());
+}
+
+
+/** Insert an address at the specified position in the list.
+ *
+ * @param it position of the new address
+ * @param addr the address to insert
+ */
+
+void addressList::insert(const iterator it, const address& addr)
+{
+ m_list.insert(it.m_iterator, addr.clone());
+}
+
+
+/** Remove the address at the specified position.
+ *
+ * @param it position of the address to remove
+ */
+
+void addressList::erase(const iterator it)
+{
+ delete (*it.m_iterator);
+ m_list.erase(it.m_iterator);
+}
+
+
+/** Remove all the addresses from the list.
+ */
+
+void addressList::clear()
+{
+ free_container(m_list);
+}
+
+
+void addressList::copyFrom(const addressList& source)
+{
+ clear();
+
+ for (std::vector <address*>::const_iterator i = source.m_list.begin() ; i != source.m_list.end() ; ++i)
+ m_list.push_back((*i)->clone());
+}
+
+
+addressList& addressList::operator=(const addressList& source)
+{
+ copyFrom(source);
+ return (*this);
+}
+
+
+} // vmime
diff --git a/src/addressList.hpp b/src/addressList.hpp
new file mode 100644
index 00000000..03a53e57
--- /dev/null
+++ b/src/addressList.hpp
@@ -0,0 +1,148 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_ADDRESSLIST_HPP_INCLUDED
+#define VMIME_ADDRESSLIST_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+
+#include "address.hpp"
+
+
+namespace vmime
+{
+
+
+/** A list of addresses.
+ */
+
+class addressList : public component
+{
+ friend class addressListField;
+ friend class mailboxListField;
+
+public:
+
+ addressList();
+ addressList(const class addressList& addressList);
+
+ ~addressList();
+
+public:
+
+ addressList& operator=(const addressList& source);
+
+ // Address iterator
+ class const_iterator;
+
+ class iterator
+ {
+ friend class addressList;
+ friend class const_iterator;
+
+ public:
+
+ iterator(std::vector <address*>::iterator it) : m_iterator(it) { }
+ iterator(const iterator& it) : m_iterator(it.m_iterator) { }
+
+ iterator& operator=(const iterator& it) { m_iterator = it.m_iterator; return (*this); }
+
+ address& operator*() const { return (**m_iterator); }
+ address* operator->() const { return (*m_iterator); }
+
+ iterator& operator++() { ++m_iterator; return (*this); }
+ iterator& operator++(int) { ++m_iterator; return (*this); }
+
+ const bool operator==(const iterator& it) const { return (it.m_iterator == m_iterator); }
+ const bool operator!=(const iterator& it) const { return (!(*this == it)); }
+
+ private:
+
+ std::vector <address*>::iterator m_iterator;
+ };
+
+ class const_iterator
+ {
+ friend class addressList;
+
+ public:
+
+ const_iterator(std::vector <address*>::const_iterator it) : m_iterator(it) { }
+ const_iterator(const iterator& it) : m_iterator(it.m_iterator) { }
+ const_iterator(const const_iterator& it) : m_iterator(it.m_iterator) { }
+
+ const_iterator& operator=(const const_iterator& it) { m_iterator = it.m_iterator; return (*this); }
+ const_iterator& operator=(const iterator& it) { m_iterator = it.m_iterator; return (*this); }
+
+ const address& operator*() const { return (**m_iterator); }
+ const address* operator->() const { return (*m_iterator); }
+
+ const_iterator& operator++() { ++m_iterator; return (*this); }
+ const_iterator& operator++(int) { ++m_iterator; return (*this); }
+
+ const bool operator==(const const_iterator& it) const { return (it.m_iterator == m_iterator); }
+ const bool operator!=(const const_iterator& it) const { return (!(*this == it)); }
+
+ private:
+
+ std::vector <address*>::const_iterator m_iterator;
+ };
+
+ iterator begin() { return (m_list.begin()); }
+ iterator end() { return (m_list.end()); }
+
+ const_iterator begin() const { return (const_iterator(m_list.begin())); }
+ const_iterator end() const { return (const_iterator(m_list.end())); }
+
+ const std::vector <address*>::size_type size() const;
+ const std::vector <address*>::size_type count() const;
+ const bool empty() const;
+
+ const address& operator[](const std::vector <address*>::size_type x) const { return (*m_list[x]); }
+ address& operator[](const std::vector <address*>::size_type x) { return (*m_list[x]); }
+
+ virtual void append(const address& addr);
+ virtual void insert(const iterator it, const address& addr);
+
+ void erase(const iterator it);
+ void clear();
+
+protected:
+
+ std::vector <address*> m_list;
+
+ void copyFrom(const addressList& source);
+
+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_ADDRESSLIST_HPP_INCLUDED
diff --git a/src/addressListField.cpp b/src/addressListField.cpp
new file mode 100644
index 00000000..020d6b10
--- /dev/null
+++ b/src/addressListField.cpp
@@ -0,0 +1,67 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "addressListField.hpp"
+
+
+namespace vmime
+{
+
+
+addressListField::addressListField()
+{
+}
+
+
+void addressListField::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ m_list.parse(buffer, position, end, newPosition);
+}
+
+
+void addressListField::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ string::size_type pos = curLinePos;
+
+ headerField::generate(os, maxLineLength, pos, &pos);
+
+ m_list.generate(os, maxLineLength, pos, newLinePos);
+}
+
+
+addressListField& addressListField::operator=(const addressList& list)
+{
+ m_list.copyFrom(list);
+ return (*this);
+}
+
+
+void addressListField::copyFrom(const headerField& field)
+{
+ const addressListField& source = dynamic_cast<const addressListField&>(field);
+ m_list = source.m_list;
+
+ headerField::copyFrom(field);
+}
+
+
+} // vmime
+
diff --git a/src/addressListField.hpp b/src/addressListField.hpp
new file mode 100644
index 00000000..1cc63ff6
--- /dev/null
+++ b/src/addressListField.hpp
@@ -0,0 +1,70 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_ADDRESSLISTFIELD_HPP_INCLUDED
+#define VMIME_ADDRESSLISTFIELD_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+
+#include "headerFieldFactory.hpp"
+#include "addressList.hpp"
+
+
+namespace vmime
+{
+
+
+class addressListField : public headerField
+{
+ friend class headerFieldFactory::registerer <addressListField>;
+
+protected:
+
+ addressListField();
+
+public:
+
+ void copyFrom(const headerField& field);
+
+ addressListField& operator=(const addressList& list);
+
+ const addressList& value() const { return (m_list); }
+ addressList& value() { return (m_list); }
+
+protected:
+
+ addressList m_list;
+
+public:
+
+ using headerField::parse;
+ using headerField::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_ADDRESSLISTFIELD_HPP_INCLUDED
diff --git a/src/attachment.hpp b/src/attachment.hpp
new file mode 100644
index 00000000..083f98d8
--- /dev/null
+++ b/src/attachment.hpp
@@ -0,0 +1,82 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_ATTACHMENT_HPP_INCLUDED
+#define VMIME_ATTACHMENT_HPP_INCLUDED
+
+
+#include "base.hpp"
+
+#include "bodyPart.hpp"
+#include "mediaType.hpp"
+#include "text.hpp"
+#include "contentHandler.hpp"
+#include "encoding.hpp"
+
+
+namespace vmime
+{
+
+
+class attachment
+{
+ friend class messageBuilder;
+ friend class messageParser;
+
+protected:
+
+ attachment() { }
+
+public:
+
+ virtual ~attachment() { }
+
+ virtual attachment& operator=(const attachment& attach) = 0;
+
+ /** Return the media type of this attachment.
+ * @return content type of the attachment
+ */
+ virtual const mediaType& type() const = 0;
+
+ /** Return the description of this attachment.
+ * @return attachment description
+ */
+ virtual const text& description() const = 0;
+
+ /** Return the data contained in this attachment.
+ * @return attachment data
+ */
+ virtual const contentHandler& data() const = 0;
+
+ /** Return the encoding used for this attachment.
+ * @return attachment data encoding
+ */
+ virtual const class encoding& encoding() const = 0;
+
+ /** Generate the attachment in the specified body part.
+ * @param parent body part in which to generate the attachment
+ */
+ virtual void generateIn(bodyPart& parent) const = 0;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_ATTACHMENT_HPP_INCLUDED
diff --git a/src/base.cpp b/src/base.cpp
new file mode 100644
index 00000000..84fdc9fc
--- /dev/null
+++ b/src/base.cpp
@@ -0,0 +1,877 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "config.hpp"
+
+#include "charset.hpp"
+#include "base.hpp"
+
+#include "encoder.hpp"
+#include "encoderB64.hpp"
+#include "encoderQP.hpp"
+
+#include "text.hpp"
+
+#include "parserHelpers.hpp"
+
+// For initializing
+#include "encoderFactory.hpp"
+#include "headerFieldFactory.hpp"
+#include "parameterFactory.hpp"
+#include "textPartFactory.hpp"
+#include "options.hpp"
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+ #include "messaging/serviceFactory.hpp"
+#endif
+
+
+namespace vmime
+{
+
+
+/** "Null" (empty) string.
+ */
+const string NULL_STRING;
+
+#if VMIME_WIDE_CHAR_SUPPORT
+ /** "Null" (empty) wide-char string.
+ */
+ const wstring NULL_WSTRING;
+#endif
+
+/** "Null" (empty) text.
+ */
+const text NULL_TEXT;
+
+
+/** Return the library name (eg. "libvmime").
+ *
+ * @return library name
+ */
+const string libname() { return (VMIME_PACKAGE); }
+
+/** Return the library version (eg. "0.5.2").
+ *
+ * @return library version
+ */
+const string libversion() { return (VMIME_VERSION " (" __DATE__ " " __TIME__ ")"); }
+
+
+// New line sequence to be used when folding header fields.
+const string NEW_LINE_SEQUENCE("\r\n ");
+const string::size_type NEW_LINE_SEQUENCE_LENGTH(1); // space
+
+/** The CR-LF sequence.
+ */
+const string CRLF("\r\n");
+
+
+/** The current MIME version supported by VMime.
+ */
+const string MIME_VERSION("1.0");
+
+
+// Line length limits
+namespace lineLengthLimits
+{
+ const string::size_type infinite = std::numeric_limits <string::size_type>::max();
+}
+
+
+
+/** Test two strings for equality (case insensitive).
+ * WARNING: use this with ASCII-only strings.
+ *
+ * @param s1 first string
+ * @param s2 second string (must be in lower-case!)
+ * @param n length of the second string
+ * @return true if the two strings compare equally, false otherwise
+ */
+
+bool isStringEqualNoCase(const string& s1, const char* s2, const string::size_type n)
+{
+ // 'n' is the number of characters to compare
+ // 's2' must be in lowercase letters only
+ if (s1.length() < n)
+ return (false);
+
+ bool equal = true;
+
+ for (string::size_type i = 0 ; equal && i < n ; ++i)
+ equal = (std::tolower(s1[i], std::locale()) == s2[i]);
+
+ return (equal);
+}
+
+
+/** Test two strings for equality (case insensitive).
+ * WARNING: use this with ASCII-only strings.
+ *
+ * @param s1 first string
+ * @param s2 second string
+ * @return true if the two strings compare equally, false otherwise
+ */
+
+bool isStringEqualNoCase(const string& s1, const string& s2)
+{
+ if (s1.length() != s2.length())
+ return (false);
+
+ bool equal = true;
+ const string::const_iterator end = s1.end();
+
+ for (string::const_iterator i = s1.begin(), j = s2.begin(); i != end ; ++i, ++j)
+ equal = (std::tolower(*i, std::locale()) == std::tolower(*j, std::locale()));
+
+ return (equal);
+}
+
+
+/** Test two strings for equality (case insensitive).
+ * WARNING: use this with ASCII-only strings.
+ *
+ * @param begin start position of the first string
+ * @param end end position of the first string
+ * @param s second string (must be in lower-case!)
+ * @param n length of the second string
+ * @return true if the two strings compare equally, false otherwise
+ */
+
+bool isStringEqualNoCase(const string::const_iterator begin, const string::const_iterator end,
+ const char* s, const string::size_type n)
+{
+ if ((string::size_type)(end - begin) < n)
+ return (false);
+
+ bool equal = true;
+ char* c = const_cast<char*>(s);
+ string::size_type r = n;
+
+ for (string::const_iterator i = begin ; equal && r && *c ; ++i, ++c, --r)
+ equal = (std::tolower(*i, std::locale()) == *c);
+
+ return (r == 0 && equal);
+}
+
+
+/** Transform all the characters in a string to lower-case.
+ * WARNING: use this with ASCII-only strings.
+ *
+ * @param str the string to transform
+ * @return a new string in lower-case
+ */
+
+const string toLower(const string& str)
+{
+ string out(str);
+ const string::iterator end = out.end();
+
+ for (string::iterator i = out.begin() ; i != end ; ++i)
+ *i = std::tolower(*i, std::locale());
+
+ return (out);
+}
+
+
+/** Strip the space characters (SPC, TAB, CR, LF) at the beginning
+ * and at the end of the specified string.
+ *
+ * @param str string in which to strip spaces
+ * @return a new string with space characters removed
+ */
+
+const string trim(const string& str)
+{
+ string::const_iterator b = str.begin();
+ string::const_iterator e = str.end();
+
+ if (b != e)
+ {
+ for ( ; b != e && isspace(*b) ; ++b);
+ for ( ; e != b && isspace(*(e - 1)) ; --e);
+ }
+
+ return (string(b, e));
+}
+
+
+/** Return the number of 7-bit US-ASCII characters in a string.
+ *
+ * @param begin start position
+ * @param end end position
+ * @return number of ASCII characters
+ */
+
+string::size_type countASCIIchars
+ (const string::const_iterator begin, const string::const_iterator end)
+{
+ string::size_type count = 0;
+
+ for (string::const_iterator i = begin ; i != end ; ++i)
+ {
+ if (isascii(*i))
+ {
+ if (*i != '=' || *(i + 1) != '?') // To avoid bad behaviour...
+ ++count;
+ }
+ }
+
+ return (count);
+}
+
+
+/** Encode and fold text in respect to RFC-2047.
+ *
+ * @param os output stream
+ * @param in input text
+ * @param maxLineLength maximum line length for output
+ * @param firstLineOffset the first line length (may be useful if the current output line is not empty)
+ * @param lastLineLength will receive the length of the last line written
+ * @param flags encoding flags (see encodeAndFoldFlags)
+ */
+
+void encodeAndFoldText(utility::outputStream& os, const text& in, const string::size_type maxLineLength,
+ const string::size_type firstLineOffset, string::size_type* lastLineLength, const int flags)
+{
+ string::size_type curLineLength = firstLineOffset;
+
+ for (text::const_iterator wi = in.begin() ; wi != in.end() ; ++wi)
+ {
+ const word& w = *wi;
+ const string& buffer = w.buffer();
+
+ // Calculate the number of ASCII chars to check whether encoding is needed
+ // and _which_ encoding to use.
+ const string::size_type asciiCount = countASCIIchars(buffer.begin(), buffer.end());
+
+ bool noEncoding = (flags & encodeAndFoldFlags::forceNoEncoding) ||
+ (!(flags & encodeAndFoldFlags::forceEncoding) && asciiCount == buffer.length());
+
+ if (noEncoding)
+ {
+ // We will fold lines without encoding them.
+
+ string::const_iterator lastWSpos = buffer.end(); // last white-space position
+ string::const_iterator curLineStart = buffer.begin(); // current line start
+
+ string::const_iterator p = buffer.begin();
+ const string::const_iterator end = buffer.end();
+
+ bool finished = false;
+ bool newLine = false;
+
+ while (!finished)
+ {
+ for ( ; p != end ; ++p, ++curLineLength)
+ {
+ // Exceeded maximum line length, but we have found a white-space
+ // where we can cut the line...
+ if (curLineLength >= maxLineLength && lastWSpos != end)
+ break;
+
+ if (*p == ' ' || *p == '\t')
+ {
+ // Remember the position of this white-space character
+ lastWSpos = p;
+ }
+ }
+
+ if (p != end)
+ ++curLineLength;
+
+ //if (p == end || curLineLength >= maxLineLength)
+ {
+ if (p == end || lastWSpos == end)
+ {
+ // If we are here, it means that we have found no whitespace
+ // before the first "maxLineLength" characters. In this case,
+ // we write the full line no matter of the max line length...
+
+ if (!newLine && p != end && lastWSpos == end &&
+ wi != in.begin() && curLineStart == buffer.begin())
+ {
+ // Here, we are continuing on the line of previous encoded
+ // word, but there is not even enough space to put the
+ // first word of this line, so we start a new line.
+ if (flags & encodeAndFoldFlags::noNewLineSequence)
+ {
+ os << CRLF;
+ curLineLength = 0;
+ }
+ else
+ {
+ os << NEW_LINE_SEQUENCE;
+ curLineLength = NEW_LINE_SEQUENCE_LENGTH;
+ }
+
+ p = curLineStart;
+ lastWSpos = end;
+ newLine = true;
+ }
+ else
+ {
+ os << string(curLineStart, p);
+
+ if (p == end)
+ {
+ finished = true;
+ }
+ else
+ {
+ if (flags & encodeAndFoldFlags::noNewLineSequence)
+ {
+ os << CRLF;
+ curLineLength = 0;
+ }
+ else
+ {
+ os << NEW_LINE_SEQUENCE;
+ curLineLength = NEW_LINE_SEQUENCE_LENGTH;
+ }
+
+ curLineStart = p;
+ lastWSpos = end;
+ newLine = true;
+ }
+ }
+ }
+ else
+ {
+ // In this case, there will not be enough space on the line for all the
+ // characters _after_ the last white-space; so we cut the line at this
+ // last white-space.
+
+#if 1
+ if (curLineLength != 1 && wi != in.begin())
+ os << " "; // Separate from previous word
+#endif
+
+ os << string(curLineStart, lastWSpos);
+
+ if (flags & encodeAndFoldFlags::noNewLineSequence)
+ {
+ os << CRLF;
+ curLineLength = 0;
+ }
+ else
+ {
+ os << NEW_LINE_SEQUENCE;
+ curLineLength = NEW_LINE_SEQUENCE_LENGTH;
+ }
+
+ curLineStart = lastWSpos + 1;
+
+ p = lastWSpos + 1;
+ lastWSpos = end;
+ newLine = true;
+ }
+ }
+ }
+ }
+ /*
+ RFC #2047:
+ 4. Encodings
+
+ Initially, the legal values for "encoding" are "Q" and "B". These
+ encodings are described below. The "Q" encoding is recommended for
+ use when most of the characters to be encoded are in the ASCII
+ character set; otherwise, the "B" encoding should be used.
+ Nevertheless, a mail reader which claims to recognize 'encoded-word's
+ MUST be able to accept either encoding for any character set which it
+ supports.
+ */
+ else
+ {
+ // We will encode _AND_ fold lines
+
+ /*
+ RFC #2047:
+ 2. Syntax of encoded-words
+
+ " While there is no limit to the length of a multiple-line header
+ field, each line of a header field that contains one or more
+ 'encoded-word's is limited to 76 characters. "
+ */
+
+ const string::size_type maxLineLength3 =
+ (maxLineLength == lineLengthLimits::infinite)
+ ? maxLineLength
+ : std::min(maxLineLength, (const string::size_type) 76);
+
+ // Base64 if more than 60% non-ascii, quoted-printable else (default)
+ const string::size_type asciiPercent = (100 * asciiCount) / buffer.length();
+ const string::value_type encoding = (asciiPercent <= 40) ? 'B' : 'Q';
+
+ string wordStart("=?" + w.charset().name() + "?" + encoding + "?");
+ string wordEnd("?=");
+
+ const string::size_type minWordLength = wordStart.length() + wordEnd.length();
+ const string::size_type maxLineLength2 = (maxLineLength3 < minWordLength + 1)
+ ? maxLineLength3 + minWordLength + 1 : maxLineLength3;
+
+ // Checks whether remaining space on this line is usable. If too few
+ // characters can be encoded, start a new line.
+ bool startNewLine = true;
+
+ if (curLineLength + 2 < maxLineLength2)
+ {
+ const string::size_type remainingSpaceOnLine = maxLineLength2 - curLineLength - 2;
+
+ if (remainingSpaceOnLine < minWordLength + 10)
+ {
+ // Space for no more than 10 encoded chars!
+ // It is not worth while to continue on this line...
+ startNewLine = true;
+ }
+ else
+ {
+ // OK, there is enough usable space on the current line.
+ startNewLine = false;
+ }
+ }
+
+ if (startNewLine)
+ {
+ os << NEW_LINE_SEQUENCE;
+ curLineLength = NEW_LINE_SEQUENCE_LENGTH;
+ }
+
+ // Encode and fold input buffer
+ string::const_iterator pos = buffer.begin();
+ string::size_type remaining = buffer.length();
+
+ encoder* theEncoder = ((encoding == 'B')
+ ? ((encoder*) new encoderB64)
+ : ((encoder*) new encoderQP));
+
+ string qpEncodedBuffer;
+
+ if (encoding == 'Q')
+ {
+ theEncoder->properties()["rfc2047"] = true;
+
+ // In the case of Quoted-Printable encoding, we cannot simply encode input
+ // buffer line by line. So, we encode the whole buffer and we will fold it
+ // in the next loop...
+ utility::inputStreamStringAdapter in(buffer);
+ utility::outputStreamStringAdapter out(qpEncodedBuffer);
+
+ theEncoder->encode(in, out);
+
+ pos = qpEncodedBuffer.begin();
+ remaining = qpEncodedBuffer.length();
+ }
+
+#if 1
+ if (curLineLength != 1 && wi != in.begin())
+ {
+ os << " "; // Separate from previous word
+ ++curLineLength;
+ }
+#endif
+
+ for ( ; remaining ; )
+ {
+ // Start a new encoded word
+ os << wordStart;
+ curLineLength += minWordLength;
+
+ // Compute the number of encoded chars that will fit on this line
+ const string::size_type fit = maxLineLength2 - curLineLength;
+
+ // Base-64 encoding
+ if (encoding == 'B')
+ {
+ // TODO: WARNING! "Any encoded word which encodes a non-integral
+ // number of characters or octets is incorrectly formed."
+
+ // Here, we have a formula to compute the maximum number of source
+ // characters to encode knowing the maximum number of encoded chars
+ // (with Base64, 3 bytes of input provide 4 bytes of output).
+ string::size_type count = (fit > 1) ? ((fit - 1) * 3) / 4 : 1;
+ if (count > remaining) count = remaining;
+
+ utility::inputStreamStringAdapter in
+ (buffer, pos - buffer.begin(), pos - buffer.begin() + count);
+
+ curLineLength += theEncoder->encode(in, os);
+
+ pos += count;
+ remaining -= count;
+ }
+ // Quoted-Printable encoding
+ else
+ {
+ // TODO: WARNING! "Any encoded word which encodes a non-integral
+ // number of characters or octets is incorrectly formed."
+
+ // All we have to do here is to take a certain number of character
+ // (that is less than or equal to "fit") from the QP encoded buffer,
+ // but we also make sure not to fold a "=XY" encoded char.
+ const string::const_iterator qpEnd = qpEncodedBuffer.end();
+ string::const_iterator lastFoldPos = pos;
+ string::const_iterator p = pos;
+ string::size_type n = 0;
+
+ while (n < fit && p != qpEnd)
+ {
+ if (*p == '=')
+ {
+ if (n + 3 >= fit)
+ {
+ lastFoldPos = p;
+ break;
+ }
+
+ p += 3;
+ n += 3;
+ }
+ else
+ {
+ ++p;
+ ++n;
+ }
+ }
+
+ if (lastFoldPos == pos)
+ lastFoldPos = p;
+
+ os << string(pos, lastFoldPos);
+
+ curLineLength += (lastFoldPos - pos) + 1;
+
+ pos += n;
+ remaining -= n;
+ }
+
+ // End of the encoded word
+ os << wordEnd;
+
+ if (remaining)
+ {
+ os << NEW_LINE_SEQUENCE;
+ curLineLength = NEW_LINE_SEQUENCE_LENGTH;
+ }
+ }
+
+ delete (theEncoder);
+ }
+ }
+
+ if (lastLineLength)
+ *lastLineLength = curLineLength;
+}
+
+
+void decodeAndUnfoldText(const string::const_iterator& inStart, const string::const_iterator& inEnd, text& out)
+{
+ // NOTE: See RFC-2047, Pages 11-12 for knowing about handling
+ // of white-spaces between encoded words.
+
+ out.clear();
+
+ string::const_iterator p = inStart;
+ const string::const_iterator end = inEnd;
+
+ const charset defaultCharset(charsets::US_ASCII);
+ charset prevWordCharset(defaultCharset);
+
+ bool prevIsEncoded = false;
+
+ string::const_iterator prevPos = p;
+
+ for ( ; ; )
+ {
+ if (p == end || *p == '\n')
+ {
+ string::const_iterator textEnd = p;
+
+ if (textEnd != inStart && *(textEnd - 1) == '\r')
+ --textEnd;
+
+ if (textEnd != prevPos)
+ {
+ if (out.size() && prevWordCharset == defaultCharset)
+ {
+ out.back().buffer() += string(prevPos, textEnd);
+ }
+ else
+ {
+ prevWordCharset = defaultCharset;
+ out.append(word(string(prevPos, textEnd), defaultCharset));
+ prevIsEncoded = false;
+ }
+ }
+
+ if (p == end)
+ {
+ // Finished
+ break;
+ }
+
+ // Skip the new-line character
+ prevPos = ++p;
+ }
+ else if (*p == '=' && (p + 1) != end && *(p + 1) == '?')
+ {
+ string::const_iterator wordPos = p;
+ p += 2; // skip '=?'
+
+ if (p != end)
+ {
+ const string::const_iterator charsetPos = p;
+
+ for ( ; p != end && *p != '?' ; ++p);
+
+ if (p != end) // a charset is specified
+ {
+ const string::const_iterator charsetEnd = p;
+ const string::const_iterator encPos = ++p; // skip '?'
+
+ for ( ; p != end && *p != '?' ; ++p);
+
+ if (p != end) // an encoding is specified
+ {
+ //const string::const_iterator encEnd = p;
+ const string::const_iterator dataPos = ++p; // skip '?'
+
+ for ( ; p != end && !(*p == '?' && *(p + 1) == '=') ; ++p);
+
+ if (p != end) // some data is specified
+ {
+ const string::const_iterator dataEnd = p;
+ p += 2; // skip '?='
+
+ encoder* theEncoder = NULL;
+
+ // Base-64 encoding
+ if (*encPos == 'B' || *encPos == 'b')
+ {
+ theEncoder = new encoderB64;
+ }
+ // Quoted-Printable encoding
+ else if (*encPos == 'Q' || *encPos == 'q')
+ {
+ theEncoder = new encoderQP;
+ theEncoder->properties()["rfc2047"] = true;
+ }
+
+ if (theEncoder)
+ {
+ // Decode text
+ string decodedBuffer;
+
+ utility::inputStreamStringAdapter ein(string(dataPos, dataEnd));
+ utility::outputStreamStringAdapter eout(decodedBuffer);
+
+ theEncoder->decode(ein, eout);
+ delete (theEncoder);
+
+ // Append all the unencoded text before this word
+ if (prevPos != wordPos)
+ {
+ string::const_iterator p = prevPos;
+
+ if (prevIsEncoded)
+ {
+ // Check whether there are only white-spaces between
+ // the two encoded words
+ for ( ; (p != wordPos) && isspace(*p) ; ++p);
+ }
+
+ if (p != wordPos) // if not empty
+ {
+ if (out.size() && prevWordCharset == defaultCharset)
+ {
+ out.back().buffer() += string(prevPos, wordPos);
+ }
+ else
+ {
+ out.append(word(string(prevPos, wordPos), defaultCharset));
+ prevWordCharset = defaultCharset;
+ }
+ }
+ }
+
+ // Append this fresh decoded word to output text
+ charset thisCharset(string(charsetPos, charsetEnd));
+
+ if (out.size() && prevWordCharset == thisCharset)
+ {
+ out.back().buffer() += decodedBuffer;
+ }
+ else
+ {
+ prevWordCharset = thisCharset;
+ out.append(word(decodedBuffer, thisCharset));
+ }
+
+ // This word has been decoded: we can advance in the input buffer
+ prevPos = p;
+ prevIsEncoded = true;
+ }
+ else
+ {
+ // Unknown encoding: can't decode this word, we will
+ // treat this word as ordinary text (RFC-2047, Page 9).
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ ++p;
+ }
+
+ for ( ; p != end && *p != '=' && *p != '\n' ; ++p);
+ }
+}
+
+
+void decodeAndUnfoldText(const string& in, text& out)
+{
+ decodeAndUnfoldText(in.begin(), in.end(), out);
+}
+
+
+/** This function can be used to make several encoded words from a text.
+ * All the characters in the text must be in the same specified charset.
+ *
+ * <p>Eg: giving:</p>
+ * <pre> &lt;iso-8859-1> "Linux dans un t'el'ephone mobile"
+ * ("=?iso-8859-1?Q?Linux_dans_un_t=E9l=E9phone_mobile?=")
+ * </pre><p>it will return:</p>
+ * <pre> &lt:us-ascii> "Linux dans un "
+ * &lt;iso-8859-1> "t'el'ephone "
+ * &lt;us-ascii> "mobile"
+ * ("Linux dans un =?iso-8859-1?Q?t=E9l=E9phone_?= mobile")
+ * </pre>
+ *
+ * @param in input string
+ * @param ch input charset
+ * @param out output text
+ */
+
+void makeWordsFromText(const string& in, const charset& ch, text& out)
+{
+ const string::const_iterator end = in.end();
+ string::const_iterator p = in.begin();
+ string::const_iterator start = in.begin();
+
+ bool is8bit = false; // is the current word 8-bit?
+ bool prevIs8bit = false; // is previous word 8-bit?
+ unsigned int count = 0; // total number of words
+
+ out.clear();
+
+ for ( ; ; )
+ {
+ if (p == end || isspace(*p))
+ {
+ if (p != end)
+ ++p;
+
+ if (is8bit)
+ {
+ if (prevIs8bit)
+ {
+ // No need to create a new encoded word, just append
+ // the current word to the previous one.
+ out.back().buffer() += string(start, p);
+ }
+ else
+ {
+ out.append(word(string(start, p), ch));
+ prevIs8bit = true;
+ ++count;
+ }
+ }
+ else
+ {
+ if (count && !prevIs8bit)
+ {
+ out.back().buffer() += string(start, p);
+ }
+ else
+ {
+ out.append(word(string(start, p), charset(charsets::US_ASCII)));
+ prevIs8bit = false;
+ ++count;
+ }
+ }
+
+ if (p == end)
+ break;
+
+ is8bit = false;
+ start = p;
+ }
+ else if (!isascii(*p))
+ {
+ is8bit = true;
+ ++p;
+ }
+ else
+ {
+ ++p;
+ }
+ }
+}
+
+
+//
+// V-Mime Initializer
+// ====================
+//
+// Force instanciation of singletons. This is to prevent problems that might
+// happen in multithreaded applications...
+//
+// WARNING: we put the initializer at the end of this compilation unit. This
+// ensures this object is initialized _after_ all other global variables in
+// the same compilation unit (in particular "lineLengthLimits::infinite",
+// which is used by the generate() function (called from "textPartFactory"
+// constructor, for example).
+//
+
+class initializer
+{
+public:
+
+ initializer()
+ {
+ options::getInstance();
+
+ encoderFactory::getInstance();
+ headerFieldFactory::getInstance();
+ parameterFactory::getInstance();
+ textPartFactory::getInstance();
+
+ #if VMIME_HAVE_MESSAGING_FEATURES
+ messaging::serviceFactory::getInstance();
+ #endif
+ }
+};
+
+initializer theInitializer;
+
+
+} // vmime
diff --git a/src/base.hpp b/src/base.hpp
new file mode 100644
index 00000000..a00d9c7d
--- /dev/null
+++ b/src/base.hpp
@@ -0,0 +1,216 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_BASE_HPP_INCLUDED
+#define VMIME_BASE_HPP_INCLUDED
+
+
+#include <string>
+#include <vector>
+#include <map>
+#include <sstream>
+#include <locale>
+
+#include "config.hpp"
+#include "types.hpp"
+#include "constants.hpp"
+#include "utility/stream.hpp"
+
+
+namespace vmime
+{
+ class text;
+ class charset;
+
+
+ // "Null" strings
+ extern const string NULL_STRING;
+#if VMIME_WIDE_CHAR_SUPPORT
+ extern const wstring NULL_WSTRING;
+#endif
+
+ extern const text NULL_TEXT;
+
+
+ //
+ // Library name and version
+ //
+
+ const string libname();
+ const string libversion();
+
+
+ //
+ // Helpful functions used for array -> iterator conversion
+ //
+
+ template <typename T, size_t N>
+ inline T const* begin(T const (&array)[N])
+ {
+ return (array);
+ }
+
+ template <typename T, size_t N>
+ inline T const* end(T const (&array)[N])
+ {
+ return (array + N);
+ }
+
+ template <typename T, size_t N>
+ inline size_t count(T const (&array)[N])
+ {
+ return (N);
+ }
+
+
+ //
+ // Some helpful functions
+ //
+
+ bool isStringEqualNoCase(const string& s1, const char* s2, const string::size_type n);
+ bool isStringEqualNoCase(const string& s1, const string& s2);
+ bool isStringEqualNoCase(const string::const_iterator begin, const string::const_iterator end, const char* s, const string::size_type n);
+
+
+ const string toLower(const string& str);
+ const string trim(const string& str);
+
+ template <class TYPE>
+ const string toString(const TYPE& value)
+ {
+ std::ostringstream oss;
+ oss << value;
+
+ return (oss.str());
+ }
+
+ template <class TYPE>
+ const TYPE fromString(const string& value)
+ {
+ TYPE ret;
+
+ std::istringstream iss(value);
+ iss >> ret;
+
+ return (ret);
+ }
+
+
+ // Free the pointer elements in a STL container and empty the container
+
+ template <class CONTAINER>
+ void free_container(CONTAINER& c)
+ {
+ for (typename CONTAINER::iterator it = c.begin() ; it != c.end() ; ++it)
+ delete (*it);
+
+ c.clear();
+ }
+
+
+ // Field contents encoding (RFC-2047 and folding)
+ string::size_type countASCIIchars(const string::const_iterator begin, const string::const_iterator end);
+
+ void encodeAndFoldText(utility::outputStream& os, const text& in, const string::size_type maxLineLength, const string::size_type firstLineOffset, string::size_type* lastLineLength, const int flags);
+ void decodeAndUnfoldText(const string& in, text& out);
+ void decodeAndUnfoldText(const string::const_iterator& inStart, const string::const_iterator& inEnd, text& out);
+
+ void makeWordsFromText(const string& in, const charset& ch, text& out);
+
+
+ //
+ // Some constants
+ //
+
+ // Flags used by "encodeAndFoldText" function
+ namespace encodeAndFoldFlags
+ {
+ enum
+ {
+ // If both "forceNoEncoding" and "forceEncoding" are specified,
+ // "forceNoEncoding" is used by default.
+ forceNoEncoding = (1 << 0),
+ forceEncoding = (1 << 1),
+
+ noNewLineSequence = (1 << 2),
+
+ none = 0
+ };
+ }
+
+ /*
+
+ RFC#2822
+ 2.1.1. Line Length Limits
+
+ There are two limits that this standard places on the number of
+ characters in a line. Each line of characters MUST be no more than
+ 998 characters, and SHOULD be no more than 78 characters, excluding
+ the CRLF.
+
+ The 998 character limit is due to limitations in many implementations
+ which send, receive, or store Internet Message Format messages that
+ simply cannot handle more than 998 characters on a line. Receiving
+ implementations would do well to handle an arbitrarily large number
+ of characters in a line for robustness sake. However, there are so
+ many implementations which (in compliance with the transport
+ requirements of [RFC2821]) do not accept messages containing more
+ than 1000 character including the CR and LF per line, it is important
+ for implementations not to create such messages.
+
+ The more conservative 78 character recommendation is to accommodate
+ the many implementations of user interfaces that display these
+ messages which may truncate, or disastrously wrap, the display of
+ more than 78 characters per line, in spite of the fact that such
+ implementations are non-conformant to the intent of this specification
+ (and that of [RFC2821] if they actually cause information to be lost).
+ Again, even though this limitation is put on messages, it is encumbant
+ upon implementations which display messages to handle an arbitrarily
+ large number of characters in a line (certainly at least up to the 998
+ character limit) for the sake of robustness.
+ */
+
+ namespace lineLengthLimits
+ {
+ extern const string::size_type infinite;
+
+ enum
+ {
+ max = 998,
+ convenient = 78
+ };
+ }
+
+
+ // New line sequence to be used when folding header fields.
+ extern const string NEW_LINE_SEQUENCE;
+ extern const string::size_type NEW_LINE_SEQUENCE_LENGTH;
+
+
+ // CR-LF sequence
+ extern const string CRLF;
+
+
+ // Mime version
+ extern const string MIME_VERSION;
+
+} // vmime
+
+
+#endif // VMIME_BASE_HPP_INCLUDED
diff --git a/src/body.cpp b/src/body.cpp
new file mode 100644
index 00000000..1b5c853b
--- /dev/null
+++ b/src/body.cpp
@@ -0,0 +1,543 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "bodyPart.hpp"
+#include "body.hpp"
+
+#include "options.hpp"
+
+#include "contentTypeField.hpp"
+#include "contentEncodingField.hpp"
+
+#include "utility/random.hpp"
+
+#include "parserHelpers.hpp"
+
+
+namespace vmime
+{
+
+
+body::body(bodyPart& part)
+ : parts(*this), m_part(part), m_header(part.header())
+{
+}
+
+
+void body::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ parts.clear();
+
+ // Check whether the body is a MIME-multipart
+ bool isMultipart = false;
+ string boundary;
+
+ try
+ {
+ const contentTypeField& ctf = dynamic_cast <contentTypeField&>
+ (m_header.fields.find(headerField::ContentType));
+
+ if (ctf.value().type() == mediaTypes::MULTIPART)
+ {
+ isMultipart = true;
+
+ try
+ {
+ boundary = ctf.boundary();
+ }
+ catch (exceptions::no_such_parameter&)
+ {
+ // No "boundary" parameter specified: we can try to
+ // guess it by scanning the body contents...
+ string::size_type pos = buffer.find("\n--", position);
+
+ if ((pos != string::npos) && (pos < end))
+ {
+ pos += 3;
+
+ const string::size_type start = pos;
+
+ char_t c = buffer[pos];
+ string::size_type length = 0;
+
+ // We have to stop after a reasonnably long boundary length (100)
+ // not to take the whole body contents for a boundary...
+ while (pos < end && length < 100 && !(c == '\r' || c == '\n'))
+ {
+ ++length;
+ c = buffer[pos++];
+ }
+
+ if (pos < end && length < 100)
+ {
+ // RFC #1521, Page 31:
+ // "...the boundary parameter, which consists of 1 to 70
+ // characters from a set of characters known to be very
+ // robust through email gateways, and NOT ending with
+ // white space..."
+ while (pos != start && isspace(buffer[pos - 1]))
+ --pos;
+
+ boundary = string(buffer.begin() + start,
+ buffer.begin() + pos);
+ }
+ }
+ }
+ }
+ }
+ catch (exceptions::no_such_field&)
+ {
+ // No "Content-Type" field...
+ }
+
+ // This is a multi-part body
+ if (isMultipart && !boundary.empty())
+ {
+ const string boundarySep("--" + boundary);
+
+ string::size_type partStart = position;
+ string::size_type pos = buffer.find(boundarySep, position);
+
+ bool lastPart = false;
+
+ if (pos != string::npos && pos < end)
+ {
+ m_prologText = string(buffer.begin() + position, buffer.begin() + pos);
+ }
+
+ for (int index = 0 ; !lastPart && (pos != string::npos) && (pos < end) ; ++index)
+ {
+ string::size_type partEnd = pos;
+
+ // Get rid of the [CR]LF just before the boundary string
+ if (pos - 1 >= position && buffer[pos - 1] == '\n') --partEnd;
+ if (pos - 2 >= position && buffer[pos - 2] == '\r') --partEnd;
+
+ // Check whether it is the last part (boundary terminated by "--")
+ pos += boundarySep.length();
+
+ if (pos + 1 < end && buffer[pos] == '-' && buffer[pos + 1] == '-')
+ {
+ lastPart = true;
+ pos += 2;
+ }
+
+ // RFC #1521, Page 31:
+ // "...(If a boundary appears to end with white space, the
+ // white space must be presumed to have been added by a
+ // gateway, and must be deleted.)..."
+ while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t'))
+ ++pos;
+
+ // End of boundary line
+ if (pos + 1 < end && buffer[pos] == '\r' && buffer[pos + 1] =='\n')
+ {
+ pos += 2;
+ }
+ else if (pos < end && buffer[pos] == '\n')
+ {
+ ++pos;
+ }
+
+ if (index > 0)
+ {
+ bodyPart* part = new bodyPart;
+
+ try
+ {
+ part->parse(buffer, partStart, partEnd, NULL);
+ }
+ catch (std::exception&)
+ {
+ delete (part);
+ throw;
+ }
+
+ parts.m_parts.push_back(part);
+ }
+
+ partStart = pos;
+ pos = buffer.find(boundarySep, partStart);
+ }
+
+ if (partStart < end)
+ m_epilogText = string(buffer.begin() + partStart, buffer.begin() + end);
+ }
+ // Treat the contents as 'simple' data
+ else
+ {
+ // Extract the (encoded) contents
+ m_contents.set(buffer, position, end, encoding());
+ }
+
+ if (newPosition)
+ *newPosition = end;
+}
+
+
+void body::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type /* curLinePos */, string::size_type* newLinePos) const
+{
+ // MIME-Multipart
+ if (parts.size() != 0)
+ {
+ string boundary;
+
+ try
+ {
+ contentTypeField& ctf = dynamic_cast<contentTypeField&>
+ (m_header.fields.find(headerField::ContentType));
+
+ boundary = ctf.boundary();
+ }
+ catch (exceptions::no_such_field&)
+ {
+ // Warning: no content-type and no boundary string specified!
+ boundary = generateRandomBoundaryString();
+ }
+ catch (exceptions::no_such_parameter&)
+ {
+ // Warning: no boundary string specified!
+ boundary = generateRandomBoundaryString();
+ }
+
+ const string& prologText =
+ m_prologText.empty()
+ ? (isRootPart()
+ ? options::getInstance()->multipart.prologText()
+ : NULL_STRING
+ )
+ : m_prologText;
+
+ const string& epilogText =
+ m_epilogText.empty()
+ ? (isRootPart()
+ ? options::getInstance()->multipart.epilogText()
+ : NULL_STRING
+ )
+ : m_epilogText;
+
+ if (!prologText.empty())
+ {
+ encodeAndFoldText(os, text(word(prologText, charset())), maxLineLength, 0,
+ NULL, encodeAndFoldFlags::forceNoEncoding | encodeAndFoldFlags::noNewLineSequence);
+
+ os << CRLF;
+ }
+
+ os << "--" << boundary;
+
+ for (std::vector <bodyPart*>::const_iterator
+ p = parts.m_parts.begin() ; p != parts.m_parts.end() ; ++p)
+ {
+ os << CRLF;
+
+ (*p)->generate(os, maxLineLength, 0);
+
+ os << CRLF << "--" << boundary;
+ }
+
+ os << "--" << CRLF;
+
+ if (!epilogText.empty())
+ {
+ encodeAndFoldText(os, text(word(epilogText, charset())), maxLineLength, 0,
+ NULL, encodeAndFoldFlags::forceNoEncoding | encodeAndFoldFlags::noNewLineSequence);
+
+ os << CRLF;
+ }
+
+ if (newLinePos)
+ *newLinePos = 0;
+ }
+ // Simple body
+ else
+ {
+ // Generate the contents
+ m_contents.generate(os, encoding(), maxLineLength);
+ }
+}
+
+
+/*
+ RFC #1521, Page 32:
+ 7.2.1. Multipart: The common syntax
+
+ "...Encapsulation boundaries must not appear within the
+ encapsulations, and must be no longer than 70 characters..."
+
+
+ boundary := 0*69<bchars> bcharsnospace
+
+ bchars := bcharsnospace / " "
+
+ bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" / "+" /"_"
+ / "," / "-" / "." / "/" / ":" / "=" / "?"
+*/
+
+const string body::generateRandomBoundaryString()
+{
+ // 64 characters that can be _safely_ used in a boundary string
+ static const char bchars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-+";
+
+ /*
+ RFC #1521, Page 19:
+
+ Since the hyphen character ("-") is represented as itself in the
+ Quoted-Printable encoding, care must be taken, when encapsulating a
+ quoted-printable encoded body in a multipart entity, to ensure that
+ the encapsulation boundary does not appear anywhere in the encoded
+ body. (A good strategy is to choose a boundary that includes a
+ character sequence such as "=_" which can never appear in a quoted-
+ printable body. See the definition of multipart messages later in
+ this document.)
+ */
+
+ string::value_type boundary[2 + 48 + 1] = { 0 };
+
+ boundary[0] = '=';
+ boundary[1] = '_';
+
+ // Generate a string of random characters
+ unsigned int r = utility::random::time();
+ unsigned int m = sizeof(unsigned int);
+
+ for (size_t i = 2 ; i < (sizeof(boundary) / sizeof(boundary[0]) - 1) ; ++i)
+ {
+ boundary[i] = bchars[r & 63];
+ r >>= 6;
+
+ if (--m == 0)
+ {
+ r = utility::random::next();
+ m = sizeof(unsigned int);
+ }
+ }
+
+ return (string(boundary));
+}
+
+
+const bool body::isValidBoundary(const string& boundary)
+{
+ static const string validChars("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'()+_,-./:=?");
+
+ const string::const_iterator end = boundary.end();
+ bool valid = false;
+
+ if (boundary.length() > 0 && boundary.length() < 70)
+ {
+ const string::value_type last = *(end - 1);
+
+ if (!(last == ' ' || last == '\t' || last == '\n'))
+ {
+ valid = true;
+
+ for (string::const_iterator i = boundary.begin() ; valid && i != end ; ++i)
+ valid = (validChars.find_first_of(*i) != string::npos);
+ }
+ }
+
+ return (valid);
+}
+
+
+//
+// Quick-access functions
+//
+
+const mediaType body::contentType() const
+{
+ try
+ {
+ const contentTypeField& ctf = dynamic_cast<contentTypeField&>(m_header.fields.find(headerField::ContentType));
+ return (ctf.value());
+ }
+ catch (exceptions::no_such_field&)
+ {
+ // Defaults to "text/plain" (RFC-1521)
+ return (mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN));
+ }
+}
+
+
+const class charset body::charset() const
+{
+ try
+ {
+ const contentTypeField& ctf = dynamic_cast<contentTypeField&>(m_header.fields.find(headerField::ContentType));
+ const class charset& cs = ctf.charset();
+
+ return (cs);
+ }
+ catch (exceptions::no_such_parameter&)
+ {
+ // Defaults to "us-ascii" (RFC-1521)
+ return (vmime::charset(charsets::US_ASCII));
+ }
+ catch (exceptions::no_such_field&)
+ {
+ // Defaults to "us-ascii" (RFC-1521)
+ return (vmime::charset(charsets::US_ASCII));
+ }
+}
+
+
+const class encoding body::encoding() const
+{
+ try
+ {
+ const contentEncodingField& cef = m_header.fields.ContentTransferEncoding();
+ return (cef.value());
+ }
+ catch (exceptions::no_such_field&)
+ {
+ // Defaults to "7bit" (RFC-1521)
+ return (vmime::encoding(encodingTypes::SEVEN_BIT));
+ }
+}
+
+
+const bool body::isRootPart() const
+{
+ return (m_part.parent() == NULL);
+}
+
+
+body& body::operator=(const body& b)
+{
+ m_prologText = b.m_prologText;
+ m_epilogText = b.m_epilogText;
+
+ m_contents = b.m_contents;
+
+ parts = b.parts;
+
+ return (*this);
+}
+
+
+/////////////////////
+// Parts container //
+/////////////////////
+
+
+body::partsContainer::partsContainer(class body& body)
+ : m_body(body)
+{
+}
+
+
+// Part insertion
+void body::partsContainer::append(bodyPart* part)
+{
+ part->m_parent = &(m_body.m_part);
+
+ m_parts.push_back(part);
+
+ // Check whether we have a boundary string
+ try
+ {
+ contentTypeField& ctf = dynamic_cast<contentTypeField&>
+ (m_body.m_header.fields.find(headerField::ContentType));
+
+ try
+ {
+ const string boundary = ctf.boundary();
+
+ if (boundary.empty() || !isValidBoundary(boundary))
+ throw exceptions::no_such_parameter("boundary"); // to generate a new one
+ }
+ catch (exceptions::no_such_parameter&)
+ {
+ // No "boundary" parameter: generate a random one.
+ ctf.boundary() = generateRandomBoundaryString();
+ }
+
+ if (ctf.value().type() != mediaTypes::MULTIPART)
+ {
+ // Warning: multi-part body but the Content-Type is
+ // not specified as "multipart/..."
+ }
+ }
+ catch (exceptions::no_such_field&)
+ {
+ // No "Content-Type" field: create a new one and generate
+ // a random boundary string.
+ contentTypeField& ctf = dynamic_cast<contentTypeField&>
+ (m_body.m_header.fields.get(headerField::ContentType));
+
+ ctf.value() = mediaType(mediaTypes::MULTIPART, mediaTypes::MULTIPART_MIXED);
+ ctf.boundary() = generateRandomBoundaryString();
+ }
+}
+
+
+void body::partsContainer::insert(const iterator it, bodyPart* part)
+{
+ part->m_parent = &(m_body.m_part);
+
+ m_parts.insert(it.m_iterator, part);
+}
+
+
+// Part removing
+void body::partsContainer::remove(const iterator it)
+{
+ delete (*it.m_iterator);
+ m_parts.erase(it.m_iterator);
+}
+
+
+void body::partsContainer::clear()
+{
+ free_container(m_parts);
+}
+
+
+body::partsContainer::~partsContainer()
+{
+ clear();
+}
+
+
+body::partsContainer& body::partsContainer::operator=(const partsContainer& c)
+{
+ std::vector <bodyPart*> parts;
+
+ for (std::vector <bodyPart*>::const_iterator it = c.m_parts.begin() ; it != c.m_parts.end() ; ++it)
+ {
+ bodyPart* p = (*it)->clone();
+ p->m_parent = &(m_body.m_part);
+
+ parts.push_back(p);
+ }
+
+ for (std::vector <bodyPart*>::iterator it = m_parts.begin() ; it != m_parts.end() ; ++it)
+ delete (*it);
+
+ m_parts.resize(parts.size());
+ std::copy(parts.begin(), parts.end(), m_parts.begin());
+
+ return (*this);
+}
+
+
+} // vmime
diff --git a/src/body.hpp b/src/body.hpp
new file mode 100644
index 00000000..9e43744c
--- /dev/null
+++ b/src/body.hpp
@@ -0,0 +1,234 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_BODY_HPP_INCLUDED
+#define VMIME_BODY_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+
+#include "header.hpp"
+
+#include "mediaType.hpp"
+#include "charset.hpp"
+#include "encoding.hpp"
+
+#include "contentHandler.hpp"
+
+
+namespace vmime
+{
+
+
+class bodyPart;
+
+
+/** Body section of a MIME part.
+ */
+
+class body : public component
+{
+ friend class bodyPart;
+
+protected:
+
+ body(bodyPart& part);
+
+public:
+
+ // A sub-class for part manipulation
+ class partsContainer
+ {
+ friend class body;
+
+ protected:
+
+ partsContainer(class body& body);
+ ~partsContainer();
+
+ public:
+
+ // Part iterator
+ class const_iterator;
+
+ class iterator
+ {
+ friend class body::partsContainer::const_iterator;
+ friend class body::partsContainer;
+
+ public:
+
+ typedef std::vector <bodyPart*>::iterator::difference_type difference_type;
+
+ iterator(std::vector <bodyPart*>::iterator it) : m_iterator(it) { }
+ iterator(const iterator& it) : m_iterator(it.m_iterator) { }
+
+ iterator& operator=(const iterator& it) { m_iterator = it.m_iterator; return (*this); }
+
+ bodyPart& operator*() const { return (**m_iterator); }
+ bodyPart* operator->() const { return (*m_iterator); }
+
+ iterator& operator++() { ++m_iterator; return (*this); }
+ iterator operator++(int) { iterator i(*this); ++m_iterator; return (i); }
+
+ iterator& operator--() { --m_iterator; return (*this); }
+ iterator operator--(int) { iterator i(*this); --m_iterator; return (i); }
+
+ iterator& operator+=(difference_type n) { m_iterator += n; return (*this); }
+ iterator& operator-=(difference_type n) { m_iterator -= n; return (*this); }
+
+ iterator operator-(difference_type x) const { return iterator(m_iterator - x); }
+
+ bodyPart& operator[](difference_type n) const { return *(m_iterator[n]); }
+
+ const bool operator==(const iterator& it) const { return (it.m_iterator == m_iterator); }
+ const bool operator!=(const iterator& it) const { return (!(*this == it)); }
+
+ protected:
+
+ std::vector <bodyPart*>::iterator m_iterator;
+ };
+
+ class const_iterator
+ {
+ public:
+
+ typedef std::vector <bodyPart*>::const_iterator::difference_type difference_type;
+
+ const_iterator(std::vector <bodyPart*>::const_iterator it) : m_iterator(it) { }
+ const_iterator(const iterator& it) : m_iterator(it.m_iterator) { }
+ const_iterator(const const_iterator& it) : m_iterator(it.m_iterator) { }
+
+ const_iterator& operator=(const const_iterator& it) { m_iterator = it.m_iterator; return (*this); }
+ const_iterator& operator=(const iterator& it) { m_iterator = it.m_iterator; return (*this); }
+
+ const bodyPart& operator*() const { return (**m_iterator); }
+ const bodyPart* operator->() const { return (*m_iterator); }
+
+ const_iterator& operator++() { ++m_iterator; return (*this); }
+ const_iterator operator++(int) { const_iterator i(*this); ++m_iterator; return (i); }
+
+ const_iterator& operator--() { --m_iterator; return (*this); }
+ const_iterator operator--(int) { const_iterator i(*this); --m_iterator; return (i); }
+
+ const_iterator& operator+=(difference_type n) { m_iterator += n; return (*this); }
+ const_iterator& operator-=(difference_type n) { m_iterator -= n; return (*this); }
+
+ const_iterator operator-(difference_type x) const { return const_iterator(m_iterator - x); }
+
+ const bodyPart& operator[](difference_type n) const { return *(m_iterator[n]); }
+
+ const bool operator==(const const_iterator& it) const { return (it.m_iterator == m_iterator); }
+ const bool operator!=(const const_iterator& it) const { return (!(*this == it)); }
+
+ protected:
+
+ std::vector <bodyPart*>::const_iterator m_iterator;
+ };
+
+ public:
+
+ iterator begin() { return (m_parts.begin()); }
+ iterator end() { return (m_parts.end()); }
+
+ const_iterator begin() const { return (const_iterator(m_parts.begin())); }
+ const_iterator end() const { return (const_iterator(m_parts.end())); }
+
+ const bodyPart& operator[](const std::vector <bodyPart*>::size_type x) const { return (*m_parts[x]); }
+ bodyPart& operator[](const std::vector <bodyPart*>::size_type x) { return (*m_parts[x]); }
+
+ // Part insertion
+ void append(bodyPart* part);
+ void insert(const iterator it, bodyPart* part);
+
+ // Part removing
+ void remove(const iterator it);
+ void clear();
+
+ // Part count
+ const size_t count() const { return (m_parts.size()); }
+ const size_t size() const { return (m_parts.size()); }
+
+ bodyPart& front() { return (*m_parts.front()); }
+ const bodyPart& front() const { return (*m_parts.front()); }
+ bodyPart& back() { return (*m_parts.back()); }
+ const bodyPart& back() const { return (*m_parts.back()); }
+
+ partsContainer& operator=(const partsContainer& c);
+
+ protected:
+
+ body& m_body;
+
+ std::vector <bodyPart*> m_parts;
+
+ } parts;
+
+ typedef partsContainer::iterator iterator;
+ typedef partsContainer::const_iterator const_iterator;
+
+
+ const string& prologText() const { return (m_prologText); }
+ string& prologText() { return (m_prologText); }
+
+ const string& epilogText() const { return (m_epilogText); }
+ string& epilogText() { return (m_epilogText); }
+
+ const contentHandler& contents() const { return (m_contents); }
+ contentHandler& contents() { return (m_contents); }
+
+ // Quick-access functions
+ const mediaType contentType() const;
+ const class charset charset() const;
+ const class encoding encoding() const;
+
+ // Boundary string functions
+ static const string generateRandomBoundaryString();
+ static const bool isValidBoundary(const string& boundary);
+
+ body& operator=(const body& b);
+
+protected:
+
+ string m_prologText;
+ string m_epilogText;
+
+ contentHandler m_contents;
+
+ bodyPart& m_part;
+ header& m_header;
+
+ const bool isRootPart() const;
+
+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_BODY_HPP_INCLUDED
diff --git a/src/bodyPart.cpp b/src/bodyPart.cpp
new file mode 100644
index 00000000..522a34cd
--- /dev/null
+++ b/src/bodyPart.cpp
@@ -0,0 +1,75 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "bodyPart.hpp"
+
+
+namespace vmime
+{
+
+
+bodyPart::bodyPart()
+ : m_body(*this), m_parent(NULL)
+{
+}
+
+
+void bodyPart::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ // Parse the headers
+ string::size_type pos = position;
+ m_header.parse(buffer, pos, end, &pos);
+
+ // Parse the body contents
+ m_body.parse(buffer, pos, end, NULL);
+
+ if (newPosition)
+ *newPosition = end;
+}
+
+
+void bodyPart::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type /* curLinePos */, string::size_type* newLinePos) const
+{
+ m_header.generate(os, maxLineLength);
+
+ os << CRLF;
+
+ m_body.generate(os, maxLineLength);
+
+ if (newLinePos)
+ *newLinePos = 0;
+}
+
+
+bodyPart* bodyPart::clone() const
+{
+ bodyPart* p = new bodyPart;
+
+ p->m_parent = NULL;
+ p->m_header = m_header;
+ p->m_body = m_body;
+
+ return (p);
+}
+
+
+} // vmime
+
diff --git a/src/bodyPart.hpp b/src/bodyPart.hpp
new file mode 100644
index 00000000..21e59b79
--- /dev/null
+++ b/src/bodyPart.hpp
@@ -0,0 +1,80 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_BODYPART_HPP_INCLUDED
+#define VMIME_BODYPART_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+
+#include "header.hpp"
+#include "body.hpp"
+
+
+namespace vmime
+{
+
+
+/** A MIME part.
+ */
+
+class bodyPart : public component
+{
+public:
+
+ bodyPart();
+
+ const class header& header() const { return (m_header); }
+ class header& header() { return (m_header); }
+
+ const class body& body() const { return (m_body); }
+ class body& body() { return (m_body); }
+
+ bodyPart* parent() const { return (m_parent); }
+
+ bodyPart* clone() const;
+
+protected:
+
+ class header m_header;
+ class body m_body;
+
+ bodyPart* m_parent;
+
+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;
+
+
+ // This is here because of a bug in g++ < 3.4
+ friend class body;
+ friend class body::partsContainer;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_BODYPART_HPP_INCLUDED
diff --git a/src/charset.cpp b/src/charset.cpp
new file mode 100644
index 00000000..5d5b872c
--- /dev/null
+++ b/src/charset.cpp
@@ -0,0 +1,305 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "charset.hpp"
+#include "exception.hpp"
+#include "platformDependant.hpp"
+
+
+extern "C"
+{
+ #include <iconv.h>
+
+ // HACK: prototypes may differ depending on the compiler and/or system (the
+ // second parameter may or may not be 'const'). This redeclaration is a hack
+ // to have a common prototype "iconv_cast".
+ typedef size_t (*iconv_const_hack)(iconv_t cd, const char* * inbuf,
+ size_t *inbytesleft, char* * outbuf, size_t *outbytesleft);
+
+ #define iconv_const ((iconv_const_hack) iconv)
+}
+
+
+namespace vmime
+{
+
+
+charset::charset()
+ : m_name(charsets::US_ASCII)
+{
+}
+
+
+charset::charset(const string& name)
+ : m_name(name)
+{
+}
+
+
+void charset::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ m_name = string(buffer.begin() + position, buffer.begin() + end);
+
+ if (newPosition)
+ *newPosition = end;
+}
+
+
+void charset::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ os << m_name;
+
+ if (newLinePos)
+ *newLinePos = curLinePos + m_name.length();
+}
+
+
+/** Convert the contents of an input stream in a specified charset
+ * to another charset and write the result to an output stream.
+ *
+ * @param in input stream to read data from
+ * @param out output stream to write the converted data
+ * @param source input charset
+ * @param dest output charset
+ */
+
+void charset::convert(utility::inputStream& in, utility::outputStream& out,
+ const charset& source, const charset& dest)
+{
+ // Get an iconv descriptor
+ const iconv_t cd = iconv_open(dest.name().c_str(), source.name().c_str());
+
+ if (cd != (iconv_t) -1)
+ {
+ char inBuffer[5];
+ char outBuffer[32768];
+ size_t inPos = 0;
+
+ bool prevIsInvalid = false;
+
+ while (true)
+ {
+ // Fullfill the buffer
+ size_t inLength = (size_t) in.read(inBuffer + inPos, sizeof(inBuffer) - inPos) + inPos;
+ size_t outLength = sizeof(outBuffer);
+
+ const char* inPtr = inBuffer;
+ char* outPtr = outBuffer;
+
+ // Convert input bytes
+ if (iconv_const(cd, &inPtr, &inLength, &outPtr, &outLength) == (size_t) -1)
+ {
+ // Illegal input sequence or input sequence has no equivalent
+ // sequence in the destination charset.
+ if (prevIsInvalid)
+ {
+ // Write successfully converted bytes
+ out.write(outBuffer, sizeof(outBuffer) - outLength);
+
+ // Output a special character to indicate we don't known how to
+ // convert the sequence at this position
+ out.write("?", 1);
+
+ // Skip a byte and leave unconverted bytes in the input buffer
+ std::copy((char*) inPtr + 1, inBuffer + sizeof(inBuffer), inBuffer);
+ inPos = inLength - 1;
+ }
+ else
+ {
+ // Write successfully converted bytes
+ out.write(outBuffer, sizeof(outBuffer) - outLength);
+
+ // Leave unconverted bytes in the input buffer
+ std::copy((char*) inPtr, inBuffer + sizeof(inBuffer), inBuffer);
+ inPos = inLength;
+
+ prevIsInvalid = true;
+ }
+ }
+ else
+ {
+ // Write successfully converted bytes
+ out.write(outBuffer, sizeof(outBuffer) - outLength);
+
+ inPos = 0;
+ prevIsInvalid = false;
+ }
+
+ // Check for end of data
+ if (in.eof() && inPos == 0)
+ break;
+ }
+
+ // Close iconv handle
+ iconv_close(cd);
+ }
+ else
+ {
+ throw exceptions::charset_conv_error();
+ }
+}
+
+
+/** Convert a string buffer in a specified charset to a string
+ * buffer in another charset.
+ *
+ * @param in input buffer
+ * @param out output buffer
+ * @param from input charset
+ * @param to output charset
+ */
+
+template <class STRINGF, class STRINGT>
+void charset::iconvert(const STRINGF& in, STRINGT& out, const charset& from, const charset& to)
+{
+ // Get an iconv descriptor
+ const iconv_t cd = iconv_open(to.name().c_str(), from.name().c_str());
+
+ typedef typename STRINGF::value_type ivt;
+ typedef typename STRINGT::value_type ovt;
+
+ if (cd != (iconv_t) -1)
+ {
+ out.clear();
+
+ char buffer[65536];
+
+ const char* inBuffer = (const char*) in.data();
+ size_t inBytesLeft = in.length();
+
+ for ( ; inBytesLeft > 0 ; )
+ {
+ size_t outBytesLeft = sizeof(buffer);
+ char* outBuffer = buffer;
+
+ if (iconv_const(cd, &inBuffer, &inBytesLeft,
+ &outBuffer, &outBytesLeft) == (size_t) -1)
+ {
+ out += STRINGT((ovt*) buffer, sizeof(buffer) - outBytesLeft);
+
+ // Ignore this "blocking" character and continue
+ out += '?';
+ ++inBuffer;
+ --inBytesLeft;
+ }
+ else
+ {
+ out += STRINGT((ovt*) buffer, sizeof(buffer) - outBytesLeft);
+ }
+ }
+
+ // Close iconv handle
+ iconv_close(cd);
+ }
+ else
+ {
+ throw exceptions::charset_conv_error();
+ }
+}
+
+
+#if VMIME_WIDE_CHAR_SUPPORT
+
+/** Convert a string buffer in the specified charset to a wide-char
+ * string buffer.
+ *
+ * @param in input buffer
+ * @param out output buffer
+ * @param ch input charset
+ */
+
+void charset::decode(const string& in, wstring& out, const charset& ch)
+{
+ iconvert(in, out, ch, charset("WCHAR_T"));
+}
+
+
+/** Convert a wide-char string buffer to a string buffer in the
+ * specified charset.
+ *
+ * @param in input buffer
+ * @param out output buffer
+ * @param ch output charset
+ */
+
+void charset::encode(const wstring& in, string& out, const charset& ch)
+{
+ iconvert(in, out, charset("WCHAR_T"), ch);
+}
+
+#endif
+
+
+/** Convert a string buffer from one charset to another charset.
+ *
+ * @param in input buffer
+ * @param out output buffer
+ * @param source input charset
+ * @param dest output charset
+ */
+
+void charset::convert(const string& in, string& out, const charset& source, const charset& dest)
+{
+ iconvert(in, out, source, dest);
+}
+
+
+/** Returns the default charset used on the system.
+ *
+ * This function simply calls <code>platformDependantHandler::getLocaleCharset()</code>
+ * and is provided for convenience.
+ *
+ * @return system default charset
+ */
+
+const charset charset::getLocaleCharset()
+{
+ return (platformDependant::getHandler()->getLocaleCharset());
+}
+
+
+charset& charset::operator=(const charset& source)
+{
+ m_name = source.m_name;
+ return (*this);
+}
+
+
+charset& charset::operator=(const string& name)
+{
+ parse(name);
+ return (*this);
+}
+
+
+const bool charset::operator==(const charset& value) const
+{
+ return (isStringEqualNoCase(m_name, value.m_name));
+}
+
+
+const bool charset::operator!=(const charset& value) const
+{
+ return !(*this == value);
+}
+
+
+} // vmime
diff --git a/src/charset.hpp b/src/charset.hpp
new file mode 100644
index 00000000..4d7f8c5b
--- /dev/null
+++ b/src/charset.hpp
@@ -0,0 +1,86 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_CHARSET_HPP_INCLUDED
+#define VMIME_CHARSET_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+
+
+namespace vmime
+{
+
+
+/** Charset description (basic type).
+ */
+
+class charset : public component
+{
+public:
+
+ charset();
+ charset(const string& name);
+
+public:
+
+ const string name() const { return (m_name); }
+
+ charset& operator=(const charset& source);
+ charset& operator=(const string& name);
+
+ const bool operator==(const charset& value) const;
+ const bool operator!=(const charset& value) const;
+
+ static const charset getLocaleCharset();
+
+#if VMIME_WIDE_CHAR_SUPPORT
+ static void decode(const string& in, wstring& out, const charset& ch);
+ static void encode(const wstring& in, string& out, const charset& ch);
+#endif
+
+ // In-memory conversion
+ static void convert(const string& in, string& out, const charset& source, const charset& dest);
+
+ // Stream conversion
+ static void convert(utility::inputStream& in, utility::outputStream& out, const charset& source, const charset& dest);
+
+protected:
+
+ string m_name;
+
+ template <class STRINGF, class STRINGT>
+ static void iconvert(const STRINGF& in, STRINGT& out, const charset& from, const charset& to);
+
+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_CHARSET_HPP_INCLUDED
diff --git a/src/charsetParameter.cpp b/src/charsetParameter.cpp
new file mode 100644
index 00000000..ccbe7b43
--- /dev/null
+++ b/src/charsetParameter.cpp
@@ -0,0 +1,50 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "charsetParameter.hpp"
+#include "parserHelpers.hpp"
+
+
+namespace vmime
+{
+
+
+void charsetParameter::parseValue(const string& buffer, const string::size_type position,
+ const string::size_type end)
+{
+ m_value.parse(buffer, position, end);
+}
+
+
+const string charsetParameter::generateValue() const
+{
+ return (m_value.name());
+}
+
+
+void charsetParameter::copyFrom(const parameter& param)
+{
+ const charsetParameter& source = dynamic_cast<const charsetParameter&>(param);
+ m_value = source.m_value;
+
+ defaultParameter::copyFrom(param);
+}
+
+
+} // vmime
diff --git a/src/charsetParameter.hpp b/src/charsetParameter.hpp
new file mode 100644
index 00000000..4e5e89d9
--- /dev/null
+++ b/src/charsetParameter.hpp
@@ -0,0 +1,55 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_CHARSETPARAMETER_HPP_INCLUDED
+#define VMIME_CHARSETPARAMETER_HPP_INCLUDED
+
+
+#include "defaultParameter.hpp"
+#include "charset.hpp"
+
+
+namespace vmime
+{
+
+
+class charsetParameter : public defaultParameter
+{
+protected:
+
+ charset m_value;
+
+public:
+
+ void copyFrom(const parameter& param);
+
+ const charset& value() const { return (m_value); }
+ charset& value() { return (m_value); }
+
+protected:
+
+ void parseValue(const string& buffer, const string::size_type position, const string::size_type end);
+ const string generateValue() const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_CHARSETPARAMETER_HPP_INCLUDED
diff --git a/src/component.cpp b/src/component.cpp
new file mode 100644
index 00000000..b8c65cd1
--- /dev/null
+++ b/src/component.cpp
@@ -0,0 +1,47 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "component.hpp"
+
+#include <sstream>
+
+
+namespace vmime
+{
+
+
+void component::parse(const string& buffer)
+{
+ parse(buffer, 0, buffer.length(), NULL);
+}
+
+
+const string component::generate(const string::size_type maxLineLength,
+ const string::size_type curLinePos) const
+{
+ std::ostringstream oss;
+ utility::outputStreamAdapter adapter(oss);
+
+ generate(adapter, maxLineLength, curLinePos, NULL);
+
+ return (oss.str());
+}
+
+
+}
diff --git a/src/component.hpp b/src/component.hpp
new file mode 100644
index 00000000..f7c874d7
--- /dev/null
+++ b/src/component.hpp
@@ -0,0 +1,84 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_COMPONENT_HPP_INCLUDED
+#define VMIME_COMPONENT_HPP_INCLUDED
+
+
+#include "base.hpp"
+
+
+namespace vmime
+{
+
+
+/** This abstract class is the base for all the classes in the library.
+ * It defines the methods for parsing and generating all the components.
+ */
+
+class component
+{
+protected:
+
+ virtual ~component() {}
+
+protected:
+
+ /** Parse RFC-822/MIME data for this component.
+ *
+ * @param buffer input buffer
+ */
+ void parse(const string& buffer);
+
+ /** Parse RFC-822/MIME data for this component.
+ *
+ * @param buffer input buffer
+ * @param position current position in the input buffer
+ * @param end end position in the input buffer
+ * @param newPosition will receive the new position in the input buffer
+ */
+ virtual void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL) = 0;
+
+public:
+
+ /** Generate RFC-2822/MIME data for this component.
+ *
+ * \deprecated Use the new generate() method, which takes an outputStream parameter.
+ *
+ * @param maxLineLength maximum line length for output
+ * @param curLinePos length of the current line in the output buffer
+ * @return generated data
+ */
+ virtual const string generate(const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0) const;
+
+ /** Generate RFC-2822/MIME data for this component.
+ *
+ * @param os output stream
+ * @param maxLineLength maximum line length for output
+ * @param curLinePos length of the current line in the output buffer
+ * @param newLinePos will receive the new line position (length of the last line written)
+ */
+ virtual void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const = 0;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_COMPONENT_HPP_INCLUDED
diff --git a/src/constants.cpp b/src/constants.cpp
new file mode 100644
index 00000000..c46c7a25
--- /dev/null
+++ b/src/constants.cpp
@@ -0,0 +1,151 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "constants.hpp"
+
+
+namespace vmime
+{
+
+
+// Media Types
+namespace mediaTypes
+{
+ // Types
+ const string::value_type* const TEXT = "text";
+ const string::value_type* const MULTIPART = "multipart";
+ const string::value_type* const MESSAGE = "message";
+ const string::value_type* const APPLICATION = "application";
+ const string::value_type* const IMAGE = "image";
+ const string::value_type* const AUDIO = "audio";
+ const string::value_type* const VIDEO = "video";
+
+ // Sub-types
+ const string::value_type* const TEXT_PLAIN = "plain";
+ const string::value_type* const TEXT_HTML = "html";
+ const string::value_type* const TEXT_RICHTEXT = "richtext";
+ const string::value_type* const TEXT_ENRICHED = "enriched";
+
+ const string::value_type* const MULTIPART_MIXED = "mixed";
+ const string::value_type* const MULTIPART_RELATED = "related";
+ const string::value_type* const MULTIPART_ALTERNATIVE = "alternative";
+ const string::value_type* const MULTIPART_PARALLEL = "parallel";
+ const string::value_type* const MULTIPART_DIGEST = "digest";
+
+ const string::value_type* const MESSAGE_RFC822 = "rfc822";
+ const string::value_type* const MESSAGE_PARTIAL = "partial";
+ const string::value_type* const MESSAGE_EXTERNAL_BODY = "external-body";
+
+ const string::value_type* const APPLICATION_OCTET_STREAM = "octet-stream";
+
+ const string::value_type* const IMAGE_JPEG = "jpeg";
+ const string::value_type* const IMAGE_GIF = "gif";
+
+ const string::value_type* const AUDIO_BASIC = "basic";
+
+ const string::value_type* const VIDEO_MPEG = "mpeg";
+}
+
+
+// Encoding types
+namespace encodingTypes
+{
+ const string::value_type* const SEVEN_BIT = "7bit";
+ const string::value_type* const EIGHT_BIT = "8bit";
+ const string::value_type* const BASE64 = "base64";
+ const string::value_type* const QUOTED_PRINTABLE = "quoted-printable";
+ const string::value_type* const BINARY = "binary";
+ const string::value_type* const UUENCODE = "uuencode";
+}
+
+
+// Disposition types = "RFC-2183)
+namespace dispositionTypes
+{
+ const string::value_type* const INLINE = "inline";
+ const string::value_type* const ATTACHMENT = "attachment";
+}
+
+
+// Charsets
+namespace charsets
+{
+ const string::value_type* const ISO8859_1 = "iso-8859-1";
+ const string::value_type* const ISO8859_2 = "iso-8859-2";
+ const string::value_type* const ISO8859_3 = "iso-8859-3";
+ const string::value_type* const ISO8859_4 = "iso-8859-4";
+ const string::value_type* const ISO8859_5 = "iso-8859-5";
+ const string::value_type* const ISO8859_6 = "iso-8859-6";
+ const string::value_type* const ISO8859_7 = "iso-8859-7";
+ const string::value_type* const ISO8859_8 = "iso-8859-8";
+ const string::value_type* const ISO8859_9 = "iso-8859-9";
+ const string::value_type* const ISO8859_10 = "iso-8859-10";
+ const string::value_type* const ISO8859_13 = "iso-8859-13";
+ const string::value_type* const ISO8859_14 = "iso-8859-14";
+ const string::value_type* const ISO8859_15 = "iso-8859-15";
+ const string::value_type* const ISO8859_16 = "iso-8859-16";
+
+ const string::value_type* const CP_437 = "cp-437";
+ const string::value_type* const CP_737 = "cp-737";
+ const string::value_type* const CP_775 = "cp-775";
+ const string::value_type* const CP_850 = "cp-850";
+ const string::value_type* const CP_852 = "cp-852";
+ const string::value_type* const CP_853 = "cp-853";
+ const string::value_type* const CP_855 = "cp-855";
+ const string::value_type* const CP_857 = "cp-857";
+ const string::value_type* const CP_858 = "cp-858";
+ const string::value_type* const CP_860 = "cp-860";
+ const string::value_type* const CP_861 = "cp-861";
+ const string::value_type* const CP_862 = "cp-862";
+ const string::value_type* const CP_863 = "cp-863";
+ const string::value_type* const CP_864 = "cp-864";
+ const string::value_type* const CP_865 = "cp-865";
+ const string::value_type* const CP_866 = "cp-866";
+ const string::value_type* const CP_869 = "cp-869";
+ const string::value_type* const CP_874 = "cp-874";
+ const string::value_type* const CP_1125 = "cp-1125";
+ const string::value_type* const CP_1250 = "cp-1250";
+ const string::value_type* const CP_1251 = "cp-1251";
+ const string::value_type* const CP_1252 = "cp-1252";
+ const string::value_type* const CP_1253 = "cp-1253";
+ const string::value_type* const CP_1254 = "cp-1254";
+ const string::value_type* const CP_1255 = "cp-1255";
+ const string::value_type* const CP_1256 = "cp-1256";
+ const string::value_type* const CP_1257 = "cp-1257";
+
+ const string::value_type* const US_ASCII = "us-ascii";
+
+ const string::value_type* const UTF_7 = "utf-7";
+ const string::value_type* const UTF_8 = "utf-8";
+ const string::value_type* const UTF_16 = "utf-16";
+ const string::value_type* const UTF_32 = "utf-32";
+
+ const string::value_type* const WINDOWS_1250 = "windows-1250";
+ const string::value_type* const WINDOWS_1251 = "windows-1251";
+ const string::value_type* const WINDOWS_1252 = "windows-1252";
+ const string::value_type* const WINDOWS_1253 = "windows-1253";
+ const string::value_type* const WINDOWS_1254 = "windows-1254";
+ const string::value_type* const WINDOWS_1255 = "windows-1255";
+ const string::value_type* const WINDOWS_1256 = "windows-1256";
+ const string::value_type* const WINDOWS_1257 = "windows-1257";
+ const string::value_type* const WINDOWS_1258 = "windows-1258";
+}
+
+
+} // vmime
diff --git a/src/constants.hpp b/src/constants.hpp
new file mode 100644
index 00000000..1970e626
--- /dev/null
+++ b/src/constants.hpp
@@ -0,0 +1,156 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_CONSTANTS_HPP_INCLUDED
+#define VMIME_CONSTANTS_HPP_INCLUDED
+
+
+#include <string>
+
+#include "types.hpp"
+
+
+namespace vmime
+{
+ // Media types (predefined types)
+ namespace mediaTypes
+ {
+ // Types
+ extern const string::value_type* const TEXT;
+ extern const string::value_type* const MULTIPART;
+ extern const string::value_type* const MESSAGE;
+ extern const string::value_type* const APPLICATION;
+ extern const string::value_type* const IMAGE;
+ extern const string::value_type* const AUDIO;
+ extern const string::value_type* const VIDEO;
+
+ // Sub-types
+ extern const string::value_type* const TEXT_PLAIN;
+ extern const string::value_type* const TEXT_HTML;
+ extern const string::value_type* const TEXT_RICHTEXT;
+ extern const string::value_type* const TEXT_ENRICHED;
+
+ extern const string::value_type* const MULTIPART_MIXED;
+ extern const string::value_type* const MULTIPART_RELATED;
+ extern const string::value_type* const MULTIPART_ALTERNATIVE;
+ extern const string::value_type* const MULTIPART_PARALLEL;
+ extern const string::value_type* const MULTIPART_DIGEST;
+
+ extern const string::value_type* const MESSAGE_RFC822;
+ extern const string::value_type* const MESSAGE_PARTIAL;
+ extern const string::value_type* const MESSAGE_EXTERNAL_BODY;
+
+ extern const string::value_type* const APPLICATION_OCTET_STREAM;
+
+ extern const string::value_type* const IMAGE_JPEG;
+ extern const string::value_type* const IMAGE_GIF;
+
+ extern const string::value_type* const AUDIO_BASIC;
+
+ extern const string::value_type* const VIDEO_MPEG;
+ }
+
+
+ // Encoding types
+ namespace encodingTypes
+ {
+ extern const string::value_type* const SEVEN_BIT;
+ extern const string::value_type* const EIGHT_BIT;
+ extern const string::value_type* const BASE64;
+ extern const string::value_type* const QUOTED_PRINTABLE;
+ extern const string::value_type* const BINARY;
+ extern const string::value_type* const UUENCODE;
+ }
+
+
+ // Disposition types (RFC-2183)
+ namespace dispositionTypes
+ {
+ extern const string::value_type* const INLINE;
+ extern const string::value_type* const ATTACHMENT;
+ }
+
+
+ // Charsets
+ namespace charsets
+ {
+ extern const string::value_type* const ISO8859_1;
+ extern const string::value_type* const ISO8859_2;
+ extern const string::value_type* const ISO8859_3;
+ extern const string::value_type* const ISO8859_4;
+ extern const string::value_type* const ISO8859_5;
+ extern const string::value_type* const ISO8859_6;
+ extern const string::value_type* const ISO8859_7;
+ extern const string::value_type* const ISO8859_8;
+ extern const string::value_type* const ISO8859_9;
+ extern const string::value_type* const ISO8859_10;
+ extern const string::value_type* const ISO8859_13;
+ extern const string::value_type* const ISO8859_14;
+ extern const string::value_type* const ISO8859_15;
+ extern const string::value_type* const ISO8859_16;
+
+ extern const string::value_type* const CP_437;
+ extern const string::value_type* const CP_737;
+ extern const string::value_type* const CP_775;
+ extern const string::value_type* const CP_850;
+ extern const string::value_type* const CP_852;
+ extern const string::value_type* const CP_853;
+ extern const string::value_type* const CP_855;
+ extern const string::value_type* const CP_857;
+ extern const string::value_type* const CP_858;
+ extern const string::value_type* const CP_860;
+ extern const string::value_type* const CP_861;
+ extern const string::value_type* const CP_862;
+ extern const string::value_type* const CP_863;
+ extern const string::value_type* const CP_864;
+ extern const string::value_type* const CP_865;
+ extern const string::value_type* const CP_866;
+ extern const string::value_type* const CP_869;
+ extern const string::value_type* const CP_874;
+ extern const string::value_type* const CP_1125;
+ extern const string::value_type* const CP_1250;
+ extern const string::value_type* const CP_1251;
+ extern const string::value_type* const CP_1252;
+ extern const string::value_type* const CP_1253;
+ extern const string::value_type* const CP_1254;
+ extern const string::value_type* const CP_1255;
+ extern const string::value_type* const CP_1256;
+ extern const string::value_type* const CP_1257;
+
+ extern const string::value_type* const US_ASCII;
+
+ extern const string::value_type* const UTF_7;
+ extern const string::value_type* const UTF_8;
+ extern const string::value_type* const UTF_16;
+ extern const string::value_type* const UTF_32;
+
+ extern const string::value_type* const WINDOWS_1250;
+ extern const string::value_type* const WINDOWS_1251;
+ extern const string::value_type* const WINDOWS_1252;
+ extern const string::value_type* const WINDOWS_1253;
+ extern const string::value_type* const WINDOWS_1254;
+ extern const string::value_type* const WINDOWS_1255;
+ extern const string::value_type* const WINDOWS_1256;
+ extern const string::value_type* const WINDOWS_1257;
+ extern const string::value_type* const WINDOWS_1258;
+ }
+}
+
+
+#endif // VMIME_CONSTANTS_HPP_INCLUDED
diff --git a/src/contentDispositionField.cpp b/src/contentDispositionField.cpp
new file mode 100644
index 00000000..c076633f
--- /dev/null
+++ b/src/contentDispositionField.cpp
@@ -0,0 +1,62 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "contentDispositionField.hpp"
+#include "exception.hpp"
+
+
+namespace vmime
+{
+
+
+contentDispositionField::contentDispositionField()
+{
+}
+
+
+void contentDispositionField::parseValue(const string& buffer, const string::size_type position,
+ const string::size_type end)
+{
+ m_value.parse(buffer, position, end);
+}
+
+
+const string contentDispositionField::generateValue() const
+{
+ return (m_value.generate());
+}
+
+
+contentDispositionField& contentDispositionField::operator=(const disposition& type)
+{
+ m_value = type;
+ return (*this);
+}
+
+
+void contentDispositionField::copyFrom(const headerField& field)
+{
+ const contentDispositionField& source = dynamic_cast<const contentDispositionField&>(field);
+ m_value = source.m_value;
+
+ parameterizedHeaderField::copyFrom(field);
+}
+
+
+} // vmime
diff --git a/src/contentDispositionField.hpp b/src/contentDispositionField.hpp
new file mode 100644
index 00000000..d0cf0b88
--- /dev/null
+++ b/src/contentDispositionField.hpp
@@ -0,0 +1,79 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_CONTENTDISPOSITIONFIELD_HPP_INCLUDED
+#define VMIME_CONTENTDISPOSITIONFIELD_HPP_INCLUDED
+
+
+#include "parameterizedHeaderField.hpp"
+#include "disposition.hpp"
+
+#include "dateParameter.hpp"
+#include "textParameter.hpp"
+
+
+namespace vmime
+{
+
+
+class contentDispositionField : public parameterizedHeaderField
+{
+ friend class headerFieldFactory::registerer <contentDispositionField>;
+
+protected:
+
+ contentDispositionField();
+
+public:
+
+ void copyFrom(const headerField& field);
+
+ contentDispositionField& operator=(const disposition& type);
+
+ const disposition& value() const { return (m_value); }
+ disposition& value() { return (m_value); }
+
+ const datetime& creationDate() const { return (dynamic_cast<const dateParameter&>(parameters.find("creation-date")).value()); }
+ datetime& creationDate() { return (dynamic_cast<dateParameter&>(parameters.get("creation-date")).value()); }
+
+ const datetime& modificationDate() const { return (dynamic_cast<const dateParameter&>(parameters.find("modification-date")).value()); }
+ datetime& modificationDate() { return (dynamic_cast<dateParameter&>(parameters.get("modification-date")).value()); }
+
+ const datetime& readDate() const { return (dynamic_cast<const dateParameter&>(parameters.find("read-date")).value()); }
+ datetime& readDate() { return (dynamic_cast<dateParameter&>(parameters.get("read-date")).value()); }
+
+ const string& filename() const { return (dynamic_cast<const textParameter&>(parameters.find("filename")).value()); }
+ string& filename() { return (dynamic_cast<textParameter&>(parameters.get("filename")).value()); }
+
+ const string& size() const { return (dynamic_cast<const textParameter&>(parameters.find("size")).value()); }
+ string& size() { return (dynamic_cast<textParameter&>(parameters.get("size")).value()); }
+
+protected:
+
+ disposition m_value;
+
+ void parseValue(const string& buffer, const string::size_type position, const string::size_type end);
+ const string generateValue() const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_CONTENTDISPOSITIONFIELD_HPP_INCLUDED
diff --git a/src/contentEncodingField.cpp b/src/contentEncodingField.cpp
new file mode 100644
index 00000000..f16fd551
--- /dev/null
+++ b/src/contentEncodingField.cpp
@@ -0,0 +1,62 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "contentEncodingField.hpp"
+#include "exception.hpp"
+
+
+namespace vmime
+{
+
+
+contentEncodingField::contentEncodingField()
+{
+}
+
+
+void contentEncodingField::parseValue(const string& buffer, const string::size_type position,
+ const string::size_type end)
+{
+ m_value.parse(buffer, position, end);
+}
+
+
+const string contentEncodingField::generateValue() const
+{
+ return (m_value.generate());
+}
+
+
+contentEncodingField& contentEncodingField::operator=(const encoding& type)
+{
+ m_value = type;
+ return (*this);
+}
+
+
+void contentEncodingField::copyFrom(const headerField& field)
+{
+ const contentEncodingField& source = dynamic_cast<const contentEncodingField&>(field);
+ m_value = source.m_value;
+
+ parameterizedHeaderField::copyFrom(field);
+}
+
+
+} // vmime
diff --git a/src/contentEncodingField.hpp b/src/contentEncodingField.hpp
new file mode 100644
index 00000000..18d01ca7
--- /dev/null
+++ b/src/contentEncodingField.hpp
@@ -0,0 +1,61 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_CONTENTENCODINGFIELD_HPP_INCLUDED
+#define VMIME_CONTENTENCODINGFIELD_HPP_INCLUDED
+
+
+#include "defaultParameterizedHeaderField.hpp"
+#include "encoding.hpp"
+
+
+namespace vmime
+{
+
+
+class contentEncodingField : public parameterizedHeaderField
+{
+ friend class headerFieldFactory::registerer <contentEncodingField>;
+
+protected:
+
+ contentEncodingField();
+
+public:
+
+ void copyFrom(const headerField& field);
+
+ contentEncodingField& operator=(const encoding& type);
+
+ const encoding& value() const { return (m_value); }
+ encoding& value() { return (m_value); }
+
+protected:
+
+ encoding m_value;
+
+ void parseValue(const string& buffer, const string::size_type position, const string::size_type end);
+ const string generateValue() const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_CONTENTENCODINGFIELD_HPP_INCLUDED
diff --git a/src/contentHandler.cpp b/src/contentHandler.cpp
new file mode 100644
index 00000000..e33d0e5c
--- /dev/null
+++ b/src/contentHandler.cpp
@@ -0,0 +1,369 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "contentHandler.hpp"
+
+
+namespace vmime
+{
+
+
+// No encoding = "binary" encoding
+const encoding contentHandler::NO_ENCODING(encodingTypes::BINARY);
+
+
+contentHandler::contentHandler()
+ : m_type(TYPE_NONE), m_encoding(NO_ENCODING), m_ownedStream(NULL), m_stream(NULL)
+{
+}
+
+
+contentHandler::contentHandler(const string& buffer, const vmime::encoding& enc)
+ : m_type(TYPE_STRING), m_encoding(enc), m_string(buffer),
+ m_ownedStream(NULL), m_stream(NULL)
+{
+}
+
+
+contentHandler::~contentHandler()
+{
+}
+
+
+contentHandler::contentHandler(const contentHandler& cts)
+ : m_type(cts.m_type), m_encoding(cts.m_encoding), m_string(cts.m_string),
+ m_ownedStream(const_cast <utility::smart_ptr <utility::inputStream>&>(cts.m_ownedStream)),
+ m_stream(cts.m_stream), m_length(cts.m_length)
+{
+}
+
+
+contentHandler& contentHandler::operator=(const contentHandler& cts)
+{
+ m_type = cts.m_type;
+ m_encoding = cts.m_encoding;
+
+ m_string = cts.m_string;
+
+ m_ownedStream = const_cast <utility::smart_ptr <utility::inputStream>&>(cts.m_ownedStream);
+ m_stream = cts.m_stream;
+ m_length = cts.m_length;
+
+ return (*this);
+}
+
+
+void contentHandler::set(const utility::stringProxy& str, const vmime::encoding& enc)
+{
+ m_type = TYPE_STRING;
+ m_encoding = enc;
+
+ m_string = str;
+
+ m_ownedStream = NULL;
+ m_stream = NULL;
+}
+
+
+void contentHandler::set(const string& buffer, const vmime::encoding& enc)
+{
+ m_type = TYPE_STRING;
+ m_encoding = enc;
+
+ m_string.set(buffer);
+
+ m_ownedStream = NULL;
+ m_stream = NULL;
+}
+
+
+void contentHandler::set(const string& buffer, const string::size_type start,
+ const string::size_type end, const vmime::encoding& enc)
+{
+ m_type = TYPE_STRING;
+ m_encoding = enc;
+
+ m_string.set(buffer, start, end);
+
+ m_ownedStream = NULL;
+ m_stream = NULL;
+}
+
+
+void contentHandler::set(utility::inputStream* const is, const string::size_type length,
+ const bool own, const vmime::encoding& enc)
+{
+ m_type = TYPE_STREAM;
+ m_encoding = enc;
+
+ m_length = length;
+
+ if (own)
+ {
+ m_ownedStream = is;
+ m_stream = NULL;
+ }
+ else
+ {
+ m_ownedStream = NULL;
+ m_stream = is;
+ }
+
+ m_string.detach();
+}
+
+
+contentHandler& contentHandler::operator=(const string& buffer)
+{
+ set(buffer, NO_ENCODING);
+ return (*this);
+}
+
+
+void contentHandler::generate(utility::outputStream& os, const vmime::encoding& enc,
+ const string::size_type maxLineLength) const
+{
+ if (m_type == TYPE_NONE)
+ return;
+
+ // Managed data is already encoded
+ if (isEncoded())
+ {
+ // The data is already encoded but the encoding specified for
+ // the generation is different from the current one. We need
+ // to re-encode data: decode from input buffer to temporary
+ // buffer, and then re-encode to output stream...
+ if (m_encoding != enc)
+ {
+ utility::auto_ptr <encoder> theDecoder(m_encoding.getEncoder());
+ utility::auto_ptr <encoder> theEncoder(enc.getEncoder());
+
+ theEncoder->properties()["maxlinelength"] = maxLineLength;
+
+ switch (m_type)
+ {
+ default:
+ {
+ // No data
+ break;
+ }
+ case TYPE_STRING:
+ {
+ utility::inputStreamStringProxyAdapter in(m_string);
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter tempOut(oss);
+
+ theDecoder->decode(in, tempOut);
+
+ string str = oss.str();
+ utility::inputStreamStringAdapter tempIn(str);
+
+ theEncoder->encode(tempIn, os);
+
+ break;
+ }
+ case TYPE_STREAM:
+ {
+ utility::inputStream& in = const_cast <utility::inputStream&>
+ (*(m_stream ? m_stream : m_ownedStream.ptr()));
+
+ in.reset(); // may not work...
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter tempOut(oss);
+
+ theDecoder->decode(in, tempOut);
+
+ string str = oss.str();
+ utility::inputStreamStringAdapter tempIn(str);
+
+ theEncoder->encode(tempIn, os);
+
+ break;
+ }
+
+ }
+ }
+ // No encoding to perform
+ else
+ {
+ switch (m_type)
+ {
+ default:
+ {
+ // No data
+ break;
+ }
+ case TYPE_STRING:
+ {
+ m_string.extract(os);
+ break;
+ }
+ case TYPE_STREAM:
+ {
+ utility::inputStream& in = const_cast <utility::inputStream&>
+ (*(m_stream ? m_stream : m_ownedStream.ptr()));
+
+ in.reset(); // may not work...
+
+ utility::bufferedStreamCopy(in, os);
+ break;
+ }
+
+ }
+ }
+ }
+ // Need to encode data before
+ else
+ {
+ utility::auto_ptr <encoder> theEncoder(enc.getEncoder());
+ theEncoder->properties()["maxlinelength"] = maxLineLength;
+
+ // Encode the contents
+ switch (m_type)
+ {
+ default:
+ {
+ // No data
+ break;
+ }
+ case TYPE_STRING:
+ {
+ utility::inputStreamStringProxyAdapter in(m_string);
+
+ theEncoder->encode(in, os);
+ break;
+ }
+ case TYPE_STREAM:
+ {
+ utility::inputStream& in = const_cast <utility::inputStream&>
+ (*(m_stream ? m_stream : m_ownedStream.ptr()));
+
+ in.reset(); // may not work...
+
+ theEncoder->encode(in, os);
+ break;
+ }
+
+ }
+ }
+}
+
+
+void contentHandler::extract(utility::outputStream& os) const
+{
+ if (m_type == TYPE_NONE)
+ return;
+
+ // No decoding to perform
+ if (!isEncoded())
+ {
+ switch (m_type)
+ {
+ default:
+ {
+ // No data
+ break;
+ }
+ case TYPE_STRING:
+ {
+ m_string.extract(os);
+ break;
+ }
+ case TYPE_STREAM:
+ {
+ utility::inputStream& in = const_cast <utility::inputStream&>
+ (*(m_stream ? m_stream : m_ownedStream.ptr()));
+
+ in.reset(); // may not work...
+
+ utility::bufferedStreamCopy(in, os);
+ break;
+ }
+
+ }
+ }
+ // Need to decode data
+ else
+ {
+ utility::auto_ptr <encoder> theDecoder(m_encoding.getEncoder());
+
+ switch (m_type)
+ {
+ default:
+ {
+ // No data
+ break;
+ }
+ case TYPE_STRING:
+ {
+ utility::inputStreamStringProxyAdapter in(m_string);
+
+ theDecoder->decode(in, os);
+ break;
+ }
+ case TYPE_STREAM:
+ {
+ utility::inputStream& in = const_cast <utility::inputStream&>
+ (*(m_stream ? m_stream : m_ownedStream.ptr()));
+
+ in.reset(); // may not work...
+
+ theDecoder->decode(in, os);
+ break;
+ }
+
+ }
+ }
+}
+
+
+const string::size_type contentHandler::length() const
+{
+ switch (m_type)
+ {
+ case TYPE_NONE: return (0);
+ case TYPE_STRING: return (m_string.length());
+ case TYPE_STREAM: return (m_length);
+ }
+
+ return (0);
+}
+
+
+const bool contentHandler::empty() const
+{
+ return (m_type == TYPE_NONE);
+}
+
+
+const bool contentHandler::isEncoded() const
+{
+ return (m_encoding != NO_ENCODING);
+}
+
+
+const vmime::encoding& contentHandler::encoding() const
+{
+ return (m_encoding);
+}
+
+
+} // vmime
diff --git a/src/contentHandler.hpp b/src/contentHandler.hpp
new file mode 100644
index 00000000..a0ffd3d9
--- /dev/null
+++ b/src/contentHandler.hpp
@@ -0,0 +1,125 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_CONTENTHANDLER_HPP_INCLUDED
+#define VMIME_CONTENTHANDLER_HPP_INCLUDED
+
+
+#include <limits>
+
+#include "base.hpp"
+#include "utility/stringProxy.hpp"
+#include "utility/smartPtr.hpp"
+#include "encoding.hpp"
+
+
+namespace vmime
+{
+
+
+class contentHandler
+{
+private:
+
+ static const vmime::encoding NO_ENCODING;
+
+public:
+
+ contentHandler();
+ contentHandler(const string& buffer, const vmime::encoding& enc = NO_ENCODING); // for compatibility
+ ~contentHandler();
+
+ // Copy
+ contentHandler(const contentHandler& cts);
+ contentHandler& operator=(const contentHandler& cts);
+
+ // Set the data contained in the body.
+ //
+ // The two first functions take advantage of the COW (copy-on-write) system that
+ // might be implemented into std::string. This is done using "stringProxy" object.
+ //
+ // Set "enc" parameter to anything other than NO_ENCODING if the data managed by
+ // this content handler is already encoded with the specified encoding (so, no
+ // encoding/decoding will be performed on generate()/extract()). Note that the
+ // data may be re-encoded (that is, decoded and encoded) if the encoding passed
+ // to generate() is different from this one...
+ //
+ // The 'length' parameter is optional (user-defined). You can pass 0 if you want,
+ // VMime does not make use of it.
+ void set(const utility::stringProxy& str, const vmime::encoding& enc = NO_ENCODING);
+ void set(const string& buffer, const vmime::encoding& enc = NO_ENCODING);
+ void set(const string& buffer, const string::size_type start, const string::size_type end, const vmime::encoding& enc = NO_ENCODING);
+ void set(utility::inputStream* const is, const utility::stream::size_type length, const bool own, const vmime::encoding& enc = NO_ENCODING);
+
+ // For compatibility
+ contentHandler& operator=(const string& buffer);
+
+ // WRITE: Output the contents into the specified stream. Data will be
+ // encoded before being written into the stream. This is used internally
+ // by the body object to generate the message, you may not need to use
+ // this (see function extract() if you want to get the contents).
+ void generate(utility::outputStream& os, const vmime::encoding& enc, const string::size_type maxLineLength = lineLengthLimits::infinite) const;
+
+ // READ: Extract the contents into the specified stream. If needed, data
+ // will be decoded before being written into the stream.
+ void extract(utility::outputStream& os) const;
+
+ // Returns the actual length of the data. WARNING: this can return 0 if no
+ // length was specified when setting data of this object.
+ const string::size_type length() const;
+
+ // Returns 'true' if the data managed by this object is encoded.
+ const bool isEncoded() const;
+
+ // Returns the encoding used for the data (or "binary" if not encoded).
+ const vmime::encoding& encoding() const;
+
+ // Returns 'true' if there is no data set.
+ const bool empty() const;
+
+private:
+
+ // Source of data managed by this content handler
+ enum Types
+ {
+ TYPE_NONE,
+ TYPE_STRING,
+ TYPE_STREAM
+ };
+
+ Types m_type;
+
+ // Equals to NO_ENCODING if data is not encoded, otherwise this
+ // specifies the encoding that have been used to encode the data.
+ vmime::encoding m_encoding;
+
+ // Used if m_type == TYPE_STRING
+ utility::stringProxy m_string;
+
+ // Used if m_type == TYPE_STREAM
+ utility::smart_ptr <utility::inputStream> m_ownedStream; // 'contentHandler' objects are copiable...
+ utility::inputStream* m_stream;
+ string::size_type m_length;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_CONTENTHANDLER_HPP_INCLUDED
diff --git a/src/contentTypeField.cpp b/src/contentTypeField.cpp
new file mode 100644
index 00000000..3149606e
--- /dev/null
+++ b/src/contentTypeField.cpp
@@ -0,0 +1,62 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "contentTypeField.hpp"
+#include "exception.hpp"
+
+
+namespace vmime
+{
+
+
+contentTypeField::contentTypeField()
+{
+}
+
+
+void contentTypeField::parseValue(const string& buffer,
+ const string::size_type position, const string::size_type end)
+{
+ m_value.parse(buffer, position, end);
+}
+
+
+const string contentTypeField::generateValue() const
+{
+ return (m_value.generate());
+}
+
+
+contentTypeField& contentTypeField::operator=(const mediaType& type)
+{
+ m_value = type;
+ return (*this);
+}
+
+
+void contentTypeField::copyFrom(const headerField& field)
+{
+ const contentTypeField& source = dynamic_cast<const contentTypeField&>(field);
+ m_value = source.m_value;
+
+ parameterizedHeaderField::copyFrom(field);
+}
+
+
+} // vmime
diff --git a/src/contentTypeField.hpp b/src/contentTypeField.hpp
new file mode 100644
index 00000000..5244e454
--- /dev/null
+++ b/src/contentTypeField.hpp
@@ -0,0 +1,72 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_CONTENTTYPEFIELD_HPP_INCLUDED
+#define VMIME_CONTENTTYPEFIELD_HPP_INCLUDED
+
+
+#include "parameterizedHeaderField.hpp"
+
+#include "mediaType.hpp"
+#include "charset.hpp"
+
+#include "textParameter.hpp"
+#include "charsetParameter.hpp"
+
+
+namespace vmime
+{
+
+
+class contentTypeField : public parameterizedHeaderField
+{
+ friend class headerFieldFactory::registerer <contentTypeField>;
+
+protected:
+
+ contentTypeField();
+
+public:
+
+ void copyFrom(const headerField& field);
+
+ contentTypeField& operator=(const mediaType& type);
+
+ const mediaType& value() const { return (m_value); }
+ mediaType& value() { return (m_value); }
+
+ const string& boundary() const { return (dynamic_cast<const textParameter&>(parameters.find("boundary")).value()); }
+ string& boundary() { return (dynamic_cast<textParameter&>(parameters.get("boundary")).value()); }
+
+ const class charset& charset() const { return (dynamic_cast<const charsetParameter&>(parameters.find("charset")).value()); }
+ class charset& charset() { return (dynamic_cast<charsetParameter&>(parameters.get("charset")).value()); }
+
+protected:
+
+ mediaType m_value;
+
+ void parseValue(const string& buffer, const string::size_type position, const string::size_type end);
+ const string generateValue() const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_CONTENTTYPEFIELD_HPP_INCLUDED
diff --git a/src/dateField.cpp b/src/dateField.cpp
new file mode 100644
index 00000000..ed673505
--- /dev/null
+++ b/src/dateField.cpp
@@ -0,0 +1,66 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "dateField.hpp"
+
+
+namespace vmime
+{
+
+
+dateField::dateField()
+{
+}
+
+
+void dateField::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ m_datetime.parse(buffer, position, end, newPosition);
+}
+
+
+void dateField::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ string::size_type pos = curLinePos;
+
+ headerField::generate(os, maxLineLength, pos, &pos);
+
+ m_datetime.generate(os, maxLineLength, pos, newLinePos);
+}
+
+
+dateField& dateField::operator=(const class datetime& datetime)
+{
+ m_datetime = datetime;
+ return (*this);
+}
+
+
+void dateField::copyFrom(const headerField& field)
+{
+ const dateField& source = dynamic_cast<const dateField&>(field);
+ m_datetime = source.m_datetime;
+
+ headerField::copyFrom(field);
+}
+
+
+} // vmime
diff --git a/src/dateField.hpp b/src/dateField.hpp
new file mode 100644
index 00000000..76f47128
--- /dev/null
+++ b/src/dateField.hpp
@@ -0,0 +1,70 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_DATEFIELD_HPP_INCLUDED
+#define VMIME_DATEFIELD_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+
+#include "headerFieldFactory.hpp"
+#include "dateTime.hpp"
+
+
+namespace vmime
+{
+
+
+class dateField : public headerField
+{
+ friend class headerFieldFactory::registerer <dateField>;
+
+protected:
+
+ dateField();
+
+public:
+
+ void copyFrom(const headerField& field);
+
+ dateField& operator=(const class datetime& datetime);
+
+ const datetime& value() const { return (m_datetime); }
+ datetime& value() { return (m_datetime); }
+
+protected:
+
+ datetime m_datetime;
+
+public:
+
+ using headerField::parse;
+ using headerField::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_DATEFIELD_HPP_INCLUDED
diff --git a/src/dateParameter.cpp b/src/dateParameter.cpp
new file mode 100644
index 00000000..f0f4d8cd
--- /dev/null
+++ b/src/dateParameter.cpp
@@ -0,0 +1,50 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "dateParameter.hpp"
+#include "parserHelpers.hpp"
+
+
+namespace vmime
+{
+
+
+void dateParameter::parseValue(const string& buffer, const string::size_type position,
+ const string::size_type end)
+{
+ m_value.parse(buffer, position, end);
+}
+
+
+const string dateParameter::generateValue() const
+{
+ return (m_value.generate());
+}
+
+
+void dateParameter::copyFrom(const parameter& param)
+{
+ const dateParameter& source = dynamic_cast<const dateParameter&>(param);
+ m_value = source.m_value;
+
+ defaultParameter::copyFrom(param);
+}
+
+
+} // vmime
diff --git a/src/dateParameter.hpp b/src/dateParameter.hpp
new file mode 100644
index 00000000..aa4ffd63
--- /dev/null
+++ b/src/dateParameter.hpp
@@ -0,0 +1,55 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_DATEPARAMETER_HPP_INCLUDED
+#define VMIME_DATEPARAMETER_HPP_INCLUDED
+
+
+#include "defaultParameter.hpp"
+#include "dateTime.hpp"
+
+
+namespace vmime
+{
+
+
+class dateParameter : public defaultParameter
+{
+protected:
+
+ datetime m_value;
+
+public:
+
+ void copyFrom(const parameter& param);
+
+ const datetime& value() const { return (m_value); }
+ datetime& value() { return (m_value); }
+
+protected:
+
+ void parseValue(const string& buffer, const string::size_type position, const string::size_type end);
+ const string generateValue() const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_DATEPARAMETER_HPP_INCLUDED
diff --git a/src/dateTime.cpp b/src/dateTime.cpp
new file mode 100644
index 00000000..ceaec6f1
--- /dev/null
+++ b/src/dateTime.cpp
@@ -0,0 +1,702 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 <iomanip>
+
+#include "dateTime.hpp"
+#include "platformDependant.hpp"
+#include "parserHelpers.hpp"
+
+
+namespace vmime
+{
+
+/*
+
+ RFC #822:
+ 5. DATE AND TIME SPECIFICATION
+
+date-time = [ day "," ] date time ; dd mm yy
+ ; hh:mm:ss zzz
+day = "Mon" / "Tue" / "Wed" / "Thu" /
+ "Fri" / "Sat" / "Sun"
+
+date = 1*2DIGIT month 2DIGIT ; day month year
+ ; e.g. 20 Jun 82
+month = "Jan" / "Feb" / "Mar" / "Apr" /
+ "May" / "Jun" / "Jul" / "Aug" /
+ "Sep" / "Oct" / "Nov" / "Dec"
+
+time = hour zone ; ANSI and Military
+
+hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59
+
+zone = "UT" / "GMT" ; Universal Time
+ ; North American : UT
+ / "EST" / "EDT" ; Eastern: - 5/ - 4
+ / "CST" / "CDT" ; Central: - 6/ - 5
+ / "MST" / "MDT" ; Mountain: - 7/ - 6
+ / "PST" / "PDT" ; Pacific: - 8/ - 7
+ / 1ALPHA ; Military: Z = UT;
+ ; A:-1; (J not used)
+ ; M:-12; N:+1; Y:+12
+ / ( ("+" / "-") 4DIGIT ) ; Local differential
+ ; hours+min. (HHMM)
+*/
+
+
+void datetime::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ const string::value_type* const pend = buffer.data() + end;
+ const string::value_type* p = buffer.data() + position;
+
+ // Parse the date and time value
+ while (p < pend && isspace(*p)) ++p;
+
+ if (p < pend)
+ {
+ if (isalpha(*p))
+ {
+ // Ignore week day
+ while (p < pend && isalpha(*p)) ++p;
+ while (p < pend && isspace(*p)) ++p;
+ if (p < pend && *p == ',') ++p;
+ while (p < pend && isspace(*p)) ++p;
+ }
+
+ while (p < pend && !isdigit(*p)) ++p;
+
+ if (p < pend && isdigit(*p))
+ {
+ // Month day
+ comp_t day = 0;
+
+ do
+ {
+ day = day * 10 + (*p - '0');
+ ++p;
+ }
+ while (p < pend && isdigit(*p));
+
+ m_day = (day >= 1 && day <= 31) ? day : 1;
+
+ while (p < pend && !isspace(*p)) ++p;
+ while (p < pend && isspace(*p)) ++p;
+ }
+ else
+ {
+ m_day = 1;
+
+ // Skip everything to the next field
+ while (p < pend && !isspace(*p)) ++p;
+ while (p < pend && isspace(*p)) ++p;
+ }
+
+ if (p < pend && isalpha(*p))
+ {
+ // Month
+ char_t month[4] = { 0 };
+ int monthLength = 0;
+
+ do
+ {
+ month[monthLength++] = *p;
+ ++p;
+ }
+ while (monthLength < 3 && p < pend && isalpha(*p));
+
+ while (p < pend && isalpha(*p)) ++p;
+
+ switch (month[0])
+ {
+ case 'a':
+ case 'A':
+ {
+ if (month[1] == 'u' || month[1] == 'U')
+ m_month = AUGUST;
+ else
+ m_month = APRIL; // by default
+
+ break;
+ }
+ case 'd':
+ case 'D':
+ {
+ m_month = DECEMBER;
+ break;
+ }
+ case 'f':
+ case 'F':
+ {
+ m_month = FEBRUARY;
+ break;
+ }
+ case 'j':
+ case 'J':
+ {
+ if (month[1] == 'u' || month[1] == 'U')
+ {
+ if (month[2] == 'l' || month[2] == 'L')
+ m_month = JULY;
+ else // if (month[2] == 'n' || month[2] == 'N')
+ m_month = JUNE;
+ }
+ else
+ {
+ m_month = JANUARY; // by default
+ }
+
+ break;
+ }
+ case 'm':
+ case 'M':
+ {
+ if ((month[1] == 'a' || month[1] == 'A') &&
+ (month[2] == 'y' || month[2] == 'Y'))
+ {
+ m_month = MAY;
+ }
+ else
+ {
+ m_month = MARCH; // by default
+ }
+
+ break;
+ }
+ case 'n':
+ case 'N':
+ {
+ m_month = NOVEMBER;
+ break;
+ }
+ case 'o':
+ case 'O':
+ {
+ m_month = OCTOBER;
+ break;
+ }
+ case 's':
+ case 'S':
+ {
+ m_month = SEPTEMBER;
+ break;
+ }
+ default:
+ {
+ m_month = JANUARY; // by default
+ break;
+ }
+
+ }
+
+ while (p < pend && !isspace(*p)) ++p;
+ while (p < pend && isspace(*p)) ++p;
+ }
+ else
+ {
+ m_month = JANUARY;
+
+ // Skip everything to the next field
+ while (p < pend && !isspace(*p)) ++p;
+ while (p < pend && isspace(*p)) ++p;
+ }
+
+ if (p < pend && isdigit(*p))
+ {
+ // Year
+ comp_t year = 0;
+
+ do
+ {
+ year = year * 10 + (*p - '0');
+ ++p;
+ }
+ while (p < pend && isdigit(*p));
+
+ if (year < 70) m_year = year + 2000;
+ else if (year < 1000) m_year = year + 1900;
+ else m_year = year;
+
+ while (p < pend && !isspace(*p)) ++p;
+ while (p < pend && isspace(*p)) ++p;
+ }
+ else
+ {
+ m_year = 1970;
+
+ // Skip everything to the next field
+ while (p < pend && !isspace(*p)) ++p;
+ while (p < pend && isspace(*p)) ++p;
+ }
+
+ if (p < pend && isdigit(*p))
+ {
+ // Hour
+ comp_t hour = 0;
+
+ do
+ {
+ hour = hour * 10 + (*p - '0');
+ ++p;
+ }
+ while (p < pend && isdigit(*p));
+
+ m_hour = (hour >= 0 && hour <= 23) ? hour : 0;
+
+ while (p < pend && isspace(*p)) ++p;
+
+ if (p < pend && *p == ':')
+ {
+ ++p;
+
+ while (p < pend && isspace(*p)) ++p;
+
+ if (p < pend && isdigit(*p))
+ {
+ // Minute
+ comp_t minute = 0;
+
+ do
+ {
+ minute = minute * 10 + (*p - '0');
+ ++p;
+ }
+ while (p < pend && isdigit(*p));
+
+ m_minute = (minute >= 0 && minute <= 59) ? minute : 0;
+
+ while (p < pend && isspace(*p)) ++p;
+
+ if (p < pend && *p == ':')
+ {
+ ++p;
+
+ while (p < pend && isspace(*p)) ++p;
+
+ if (p < pend && isdigit(*p))
+ {
+ // Second
+ comp_t second = 0;
+
+ do
+ {
+ second = second * 10 + (*p - '0');
+ ++p;
+ }
+ while (p < pend && isdigit(*p));
+
+ m_second = (second >= 0 && second <= 59) ? second : 0;
+
+ while (p < pend && !isspace(*p)) ++p;
+ while (p < pend && isspace(*p)) ++p;
+ }
+ else
+ {
+ m_second = 0;
+ }
+ }
+ else
+ {
+ m_second = 0;
+ }
+ }
+ else
+ {
+ m_minute = 0;
+ }
+ }
+ else
+ {
+ m_minute = 0;
+ }
+ }
+ else
+ {
+ m_hour = 0;
+
+ // Skip everything to the next field
+ while (p < pend && !isspace(*p)) ++p;
+ while (p < pend && isspace(*p)) ++p;
+ }
+
+ if (p + 1 < pend && (*p == '+' || *p == '-') && isdigit(*(p + 1)))
+ {
+ const char_t sign = *p;
+ ++p;
+
+ // Zone offset (in hour/minutes)
+ comp_t offset = 0;
+
+ do
+ {
+ offset = offset * 10 + (*p - '0');
+ ++p;
+ }
+ while (p < pend && isdigit(*p));
+
+ const comp_t hourOff = offset / 100;
+ const comp_t minOff = offset % 100;
+
+ if (sign == '+')
+ m_zone = hourOff * 60 + minOff;
+ else
+ m_zone = -(hourOff * 60 + minOff);
+ }
+ else if (p < pend && isalpha(*p))
+ {
+ bool done = false;
+
+ // Zone offset (Time zone name)
+ char_t zone[4] = { 0 };
+ int zoneLength = 0;
+
+ do
+ {
+ zone[zoneLength++] = *p;
+ ++p;
+ }
+ while (zoneLength < 3 && p < pend && isdigit(*p));
+
+ switch (zone[0])
+ {
+ case 'c':
+ case 'C':
+ {
+ if (zoneLength >= 2)
+ {
+ if (zone[1] == 's' || zone[1] == 'S')
+ m_zone = CST;
+ else
+ m_zone = CDT;
+
+ done = true;
+ }
+
+ break;
+ }
+ case 'e':
+ case 'E':
+ {
+ if (zoneLength >= 2)
+ {
+ if (zone[1] == 's' || zone[1] == 'S')
+ m_zone = EST;
+ else
+ m_zone = EDT;
+
+ done = true;
+ }
+
+ break;
+ }
+ case 'm':
+ case 'M':
+ {
+ if (zoneLength >= 2)
+ {
+ if (zone[1] == 's' || zone[1] == 'S')
+ m_zone = MST;
+ else
+ m_zone = MDT;
+
+ done = true;
+ }
+
+ break;
+ }
+ case 'p':
+ case 'P':
+ {
+ if (zoneLength >= 2)
+ {
+ if (zone[1] == 's' || zone[1] == 'S')
+ m_zone = PST;
+ else
+ m_zone = PDT;
+
+ done = true;
+ }
+
+ break;
+ }
+ case 'u':
+ case 'U':
+ {
+ if (zoneLength >= 2)
+ {
+ m_zone = GMT; // = UTC
+ done = true;
+ }
+
+ break;
+ }
+
+ }
+
+ if (!done)
+ {
+ const char_t z = zone[0];
+
+ // Military time zone
+ if (z != 'j' && z != 'J')
+ {
+ typedef std::map <char_t, int> Map;
+ static const Map::value_type offsetMapInit[] =
+ {
+ Map::value_type('a', -60),
+ Map::value_type('b', -120),
+ Map::value_type('c', -180),
+ Map::value_type('d', -240),
+ Map::value_type('e', -300),
+ Map::value_type('f', -360),
+ Map::value_type('g', -420),
+ Map::value_type('h', -480),
+ Map::value_type('i', -540),
+ Map::value_type('k', -600),
+ Map::value_type('l', -660),
+ Map::value_type('m', -720),
+
+ Map::value_type('n', 60),
+ Map::value_type('o', 120),
+ Map::value_type('p', 180),
+ Map::value_type('q', 240),
+ Map::value_type('r', 300),
+ Map::value_type('s', 360),
+ Map::value_type('t', 420),
+ Map::value_type('u', 480),
+ Map::value_type('v', 540),
+ Map::value_type('w', 600),
+ Map::value_type('x', 660),
+ Map::value_type('y', 720),
+
+ Map::value_type('z', 0),
+ };
+ static const Map offsetMap
+ (::vmime::begin(offsetMapInit),
+ ::vmime::end(offsetMapInit));
+
+ Map::const_iterator pos =
+ offsetMap.find(tolower(z));
+
+ if (pos != offsetMap.end())
+ m_zone = (*pos).second;
+ else
+ m_zone = GMT;
+ }
+ else
+ {
+ m_zone = GMT;
+ }
+ }
+ }
+ else
+ {
+ m_zone = 0;
+ }
+ }
+ else
+ {
+ m_year = 1970;
+ m_month = JANUARY;
+ m_day = 1;
+
+ m_hour = 0;
+ m_minute = 0;
+ m_second = 0;
+
+ m_zone = 0;
+ }
+
+ if (newPosition)
+ *newPosition = end;
+}
+
+
+void datetime::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ static const string::value_type* dayNames[] =
+ { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+ static const string::value_type* monthNames[] =
+ { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+ const comp_t z = ((m_zone < 0) ? -m_zone : m_zone);
+ const comp_t zh = z / 60;
+ const comp_t zm = z % 60;
+
+ std::ostringstream oss;
+ oss << dayNames[dayOfWeek(m_year, m_month, m_day)] << ", "
+ << m_day << " " << monthNames[month() - 1] << " " << year()
+ << " " << std::setfill('0') << std::setw(2) << m_hour << ":"
+ << std::setfill('0') << std::setw(2) << m_minute << ":"
+ << std::setfill('0') << std::setw(2) << m_second
+ << " " << ((m_zone < 0) ? '-' : '+') << std::setfill('0') << std::setw(2) << zh
+ << std::setfill('0') << std::setw(2) << zm;
+
+ const string& str = oss.str();
+ os << str;
+
+ if (newLinePos)
+ *newLinePos = curLinePos + str.length();
+}
+
+
+datetime::datetime()
+ : m_year(1970), m_month(1), m_day(1),
+ m_hour(0), m_minute(0), m_second(0), m_zone(0)
+{
+}
+
+
+datetime::datetime(const comp_t year, const comp_t month, const comp_t day)
+ : m_year(year), m_month(month), m_day(day),
+ m_hour(0), m_minute(0), m_second(0), m_zone(0)
+{
+}
+
+
+datetime::datetime(const comp_t year, const comp_t month, const comp_t day,
+ const comp_t hour, const comp_t minute, const comp_t second,
+ const comp_t zone)
+ : m_year(year), m_month(month), m_day(day),
+ m_hour(hour), m_minute(minute), m_second(second), m_zone(zone)
+{
+}
+
+
+datetime::datetime(const datetime& d)
+ : component(), m_year(d.m_year), m_month(d.m_month), m_day(d.m_day),
+ m_hour(d.m_hour), m_minute(d.m_minute), m_second(d.m_second), m_zone(d.m_zone)
+{
+}
+
+
+datetime::datetime(const string& date)
+{
+ parse(date);
+}
+
+
+datetime::~datetime()
+{
+}
+
+
+void datetime::copyFrom(const datetime& d)
+{
+ m_year = d.m_year;
+ m_month = d.m_month;
+ m_day = d.m_day;
+ m_hour = d.m_hour;
+ m_minute = d.m_minute;
+ m_second = d.m_second;
+ m_zone = d.m_zone;
+}
+
+
+datetime& datetime::operator=(const datetime& d)
+{
+ copyFrom(d);
+ return (*this);
+}
+
+
+datetime& datetime::operator=(const string& s)
+{
+ parse(s);
+ return (*this);
+}
+
+
+void datetime::getTime(comp_t& hour, comp_t& minute, comp_t& second, comp_t& zone) const
+{
+ hour = m_hour;
+ minute = m_minute;
+ second = m_second;
+ zone = m_zone;
+}
+
+
+void datetime::getTime(comp_t& hour, comp_t& minute, comp_t& second) const
+{
+ hour = m_hour;
+ minute = m_minute;
+ second = m_second;
+}
+
+
+void datetime::getDate(comp_t& year, comp_t& month, comp_t& day) const
+{
+ year = m_year;
+ month = m_month;
+ day = m_day;
+}
+
+
+void datetime::setTime(const comp_t hour, const comp_t minute,
+ const comp_t second, const comp_t zone)
+{
+ m_hour = hour;
+ m_minute = minute;
+ m_second = second;
+ m_zone = zone;
+}
+
+
+void datetime::setDate(const comp_t year, const comp_t month, const comp_t day)
+{
+ m_year = year;
+ m_month = month;
+ m_day = day;
+}
+
+
+const datetime::comp_t datetime::dayOfWeek(const comp_t year, const comp_t month, const comp_t day)
+{
+ comp_t y = year;
+ comp_t m = month;
+
+ // From RFC-3339 - Appendix B. Day of the Week
+
+ // Adjust months so February is the last one
+ m -= 2;
+
+ if (m < 1)
+ {
+ m += 12;
+ --y;
+ }
+
+ // Split by century
+ const comp_t cent = y / 100;
+ y %= 100;
+
+ return (((26 * m - 2) / 10 + day + y + (y >> 2) + (cent >> 2) + 5 * cent) % 7);
+}
+
+
+const datetime datetime::now()
+{
+ return (platformDependant::getHandler()->getCurrentLocalTime());
+}
+
+
+} // vmime
diff --git a/src/dateTime.hpp b/src/dateTime.hpp
new file mode 100644
index 00000000..b50e6483
--- /dev/null
+++ b/src/dateTime.hpp
@@ -0,0 +1,242 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_DATETIME_HPP_INCLUDED
+#define VMIME_DATETIME_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+
+
+namespace vmime
+{
+
+
+/** Date and time (basic type).
+ */
+
+class datetime : public component
+{
+public:
+
+ // Data type for a date/time component
+ typedef int comp_t;
+
+ // Constructors
+ datetime();
+ datetime(const comp_t year, const comp_t month, const comp_t day);
+ datetime(const comp_t year, const comp_t month, const comp_t day, const comp_t hour, const comp_t minute, const comp_t second, const comp_t zone = GMT);
+ datetime(const datetime& d);
+ datetime(const string& date);
+
+ // Destructor
+ ~datetime();
+
+ // Some time zones (in minutes)
+ enum TimeZones
+ {
+ GMT_12 = -720, // GMT-12h
+ GMT_11 = -660, // GMT-11h
+ GMT_10 = -600, // GMT-10h
+ GMT_9 = -540, // GMT-9h
+ GMT_8 = -480, // GMT-8h
+ GMT_7 = -420, // GMT-7h
+ GMT_6 = -360, // GMT-6h
+ GMT_5 = -300, // GMT-5h
+ GMT_4 = -240, // GMT-4h
+ GMT_3 = -180, // GMT-3h
+ GMT_2 = -120, // GMT-2h
+ GMT_1 = -60, // GMT-1h
+ GMT = 0, // GMT
+ GMT1 = 60, // GMT+1h
+ GMT2 = 120, // GMT+2h
+ GMT3 = 180, // GMT+3h
+ GMT4 = 240, // GMT+4h
+ GMT5 = 300, // GMT+5h
+ GMT6 = 360, // GMT+6h
+ GMT7 = 420, // GMT+7h
+ GMT8 = 480, // GMT+8h
+ GMT9 = 540, // GMT+9h
+ GMT10 = 600, // GMT+10h
+ GMT11 = 660, // GMT+11h
+ GMT12 = 720, // GMT+12h
+
+ UT = GMT, // Universal Time
+
+ EST = GMT_5, // Eastern
+ EDT = GMT_4,
+ CST = GMT_6, // Central
+ CDT = GMT_5,
+ MST = GMT_7, // Mountain
+ MDT = GMT_6,
+ PST = GMT_8, // Pacific
+ PDT = GMT_7,
+
+ // Military time zones
+ A = GMT_1,
+ B = GMT_2,
+ C = GMT_3,
+ D = GMT_4,
+ E = GMT_5,
+ F = GMT_6,
+ G = GMT_7,
+ H = GMT_8,
+ I = GMT_9, // J not used
+ K = GMT_10,
+ L = GMT_11,
+ M = GMT_12,
+
+ N = GMT1,
+ O = GMT2,
+ P = GMT3,
+ Q = GMT4,
+ R = GMT5,
+ S = GMT6,
+ T = GMT7,
+ U = GMT8,
+ V = GMT9,
+ W = GMT10,
+ X = GMT11,
+ Y = GMT12,
+
+ Z = GMT
+ };
+
+ // Months list
+ enum Months
+ {
+ // Long
+ JANUARY = 1,
+ FEBRUARY = 2,
+ MARCH = 3,
+ APRIL = 4,
+ MAY = 5,
+ JUNE = 6,
+ JULY = 7,
+ AUGUST = 8,
+ SEPTEMBER = 9,
+ OCTOBER = 10,
+ NOVEMBER = 11,
+ DECEMBER = 12,
+
+ // Short
+ JAN = 1,
+ FEB = 2,
+ MAR = 3,
+ APR = 4,
+ JUN = 6,
+ JUL = 7,
+ AUG = 8,
+ SEP = 9,
+ OCT = 10,
+ NOV = 11,
+ DEC = 12
+ };
+
+ // Days of week list
+ enum DaysOfWeek
+ {
+ // Long
+ SUNDAY = 0,
+ MONDAY = 1,
+ TUESDAY = 2,
+ WEDNESDAY = 3,
+ THURSDAY = 4,
+ FRIDAY = 5,
+ SATURDAY = 6,
+
+ // Short
+ SUN = 0,
+ MON = 1,
+ TUE = 2,
+ WED = 3,
+ THU = 4,
+ FRI = 5,
+ SAT = 6
+ };
+
+protected:
+
+ // Date components
+ comp_t m_year;
+ comp_t m_month;
+ comp_t m_day;
+
+ // Time components
+ comp_t m_hour;
+ comp_t m_minute;
+ comp_t m_second;
+ comp_t m_zone;
+
+public:
+
+ // Get
+ const comp_t year() const { return (m_year); }
+ const comp_t month() const { return (m_month); }
+ const comp_t day() const { return (m_day); }
+ const comp_t hour() const { return (m_hour); }
+ const comp_t minute() const { return (m_minute); }
+ const comp_t second() const { return (m_second); }
+ const comp_t zone() const { return (m_zone); }
+
+ void getTime(comp_t& hour, comp_t& minute, comp_t& second, comp_t& zone) const;
+ void getTime(comp_t& hour, comp_t& minute, comp_t& second) const;
+ void getDate(comp_t& year, comp_t& month, comp_t& day) const;
+
+ // Set
+ comp_t& year() { return (m_year); }
+ comp_t& month() { return (m_month); }
+ comp_t& day() { return (m_day); }
+ comp_t& hour() { return (m_hour); }
+ comp_t& minute() { return (m_minute); }
+ comp_t& second() { return (m_second); }
+ comp_t& zone() { return (m_zone); }
+
+ void setTime(const comp_t hour = 0, const comp_t minute = 0, const comp_t second = 0, const comp_t zone = GMT);
+ void setDate(const comp_t year, const comp_t month, const comp_t day);
+
+ // Assignment
+ datetime& operator=(const datetime& d);
+ datetime& operator=(const string& s);
+
+ void copyFrom(const datetime& d);
+
+ // Current date and time
+ static const datetime now();
+
+protected:
+
+ static const comp_t dayOfWeek(const comp_t year, const comp_t month, const comp_t day);
+
+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_DATETIME_HPP_INCLUDED
diff --git a/src/defaultAttachment.cpp b/src/defaultAttachment.cpp
new file mode 100644
index 00000000..20f649cb
--- /dev/null
+++ b/src/defaultAttachment.cpp
@@ -0,0 +1,91 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "defaultAttachment.hpp"
+#include "encoding.hpp"
+
+
+namespace vmime
+{
+
+
+defaultAttachment::defaultAttachment()
+{
+}
+
+
+defaultAttachment::defaultAttachment(const contentHandler& data,
+ const class encoding& enc, const mediaType& type, const text& desc)
+ : m_type(type), m_desc(desc), m_data(data), m_encoding(enc)
+{
+}
+
+
+defaultAttachment::defaultAttachment(const contentHandler& data,
+ const mediaType& type, const text& desc)
+ : m_type(type), m_desc(desc), m_data(data), m_encoding(encoding::decide(data))
+{
+}
+
+
+defaultAttachment::defaultAttachment(const defaultAttachment& attach)
+ : attachment(), m_type(attach.m_type), m_desc(attach.m_desc),
+ m_data(attach.m_data), m_encoding(attach.m_encoding)
+{
+}
+
+
+attachment& defaultAttachment::operator=(const attachment& attach)
+{
+ const defaultAttachment& att =
+ dynamic_cast <const defaultAttachment&>(attach);
+
+ m_type = att.m_type;
+ m_desc = att.m_desc;
+ m_data = att.m_data;
+ m_encoding = att.m_encoding;
+
+ return (*this);
+}
+
+
+void defaultAttachment::generateIn(bodyPart& parent) const
+{
+ // Create and append a new part for this attachment
+ bodyPart* part = new bodyPart;
+ parent.body().parts.append(part);
+
+ generatePart(*part);
+}
+
+
+void defaultAttachment::generatePart(bodyPart& part) const
+{
+ // Set header fields
+ part.header().fields.ContentType() = m_type;
+ if (!m_desc.empty()) part.header().fields.ContentDescription() = m_desc;
+ part.header().fields.ContentTransferEncoding() = m_encoding;
+ part.header().fields.ContentDisposition() = disposition(dispositionTypes::ATTACHMENT);
+
+ // Set contents
+ part.body().contents() = m_data;
+}
+
+
+} // vmime
diff --git a/src/defaultAttachment.hpp b/src/defaultAttachment.hpp
new file mode 100644
index 00000000..2cf11638
--- /dev/null
+++ b/src/defaultAttachment.hpp
@@ -0,0 +1,69 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_DEFAULTATTACHMENT_HPP_INCLUDED
+#define VMIME_DEFAULTATTACHMENT_HPP_INCLUDED
+
+
+#include "attachment.hpp"
+#include "encoding.hpp"
+
+
+namespace vmime
+{
+
+
+class defaultAttachment : public attachment
+{
+protected:
+
+ // For use in derived classes.
+ defaultAttachment();
+
+public:
+
+ defaultAttachment(const contentHandler& data, const class encoding& enc, const mediaType& type, const text& desc = NULL_TEXT);
+ defaultAttachment(const contentHandler& data, const mediaType& type, const text& desc = NULL_TEXT);
+ defaultAttachment(const defaultAttachment& attach);
+
+ attachment& operator=(const attachment& attach);
+
+ const mediaType& type() const { return (m_type); }
+ const text& description() const { return (m_desc); }
+ const contentHandler& data() const { return (m_data); }
+ const class encoding& encoding() const { return (m_encoding); }
+
+protected:
+
+ mediaType m_type; // Media type (eg. "application/octet-stream")
+ text m_desc; // Description (eg. "The image you requested")
+ contentHandler m_data; // Attachment data (eg. the file contents)
+ class encoding m_encoding; // Encoding
+
+ // No need to override "generateIn", use "generatePart" instead (see below).
+ void generateIn(bodyPart& parent) const;
+
+ virtual void generatePart(bodyPart& part) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_DEFAULTATTACHMENT_HPP_INCLUDED
diff --git a/src/defaultField.cpp b/src/defaultField.cpp
new file mode 100644
index 00000000..77392725
--- /dev/null
+++ b/src/defaultField.cpp
@@ -0,0 +1,71 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "defaultField.hpp"
+#include "text.hpp"
+
+
+namespace vmime
+{
+
+
+defaultField::defaultField()
+{
+}
+
+
+void defaultField::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ m_text = string(buffer.begin() + position, buffer.begin() + end);
+
+ if (newPosition)
+ *newPosition = end;
+}
+
+
+void defaultField::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ string::size_type pos = curLinePos;
+
+ headerField::generate(os, maxLineLength, pos, &pos);
+
+ encodeAndFoldText(os, vmime::text(word(m_text, charset())), maxLineLength,
+ pos, newLinePos, encodeAndFoldFlags::forceNoEncoding);
+}
+
+
+defaultField& defaultField::operator=(const string& text)
+{
+ m_text = text;
+ return (*this);
+}
+
+
+void defaultField::copyFrom(const headerField& field)
+{
+ const defaultField& source = dynamic_cast<const defaultField&>(field);
+ m_text = source.m_text;
+
+ headerField::copyFrom(field);
+}
+
+
+} // vmime
diff --git a/src/defaultField.hpp b/src/defaultField.hpp
new file mode 100644
index 00000000..c855ca8c
--- /dev/null
+++ b/src/defaultField.hpp
@@ -0,0 +1,70 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_DEFAULTFIELD_HPP_INCLUDED
+#define VMIME_DEFAULTFIELD_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+
+#include "headerFieldFactory.hpp"
+
+
+namespace vmime
+{
+
+
+class defaultField : public headerField
+{
+ friend class headerFieldFactory;
+ friend class headerFieldFactory::registerer <defaultField>;
+
+protected:
+
+ defaultField();
+
+public:
+
+ void copyFrom(const headerField& field);
+
+ defaultField& operator=(const string& text);
+
+ const string& value() const { return (m_text); }
+ string& value() { return (m_text); }
+
+protected:
+
+ string m_text;
+
+public:
+
+ using headerField::parse;
+ using headerField::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_DEFAULTFIELD_HPP_INCLUDED
diff --git a/src/defaultParameter.cpp b/src/defaultParameter.cpp
new file mode 100644
index 00000000..2d9e72db
--- /dev/null
+++ b/src/defaultParameter.cpp
@@ -0,0 +1,117 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "defaultParameter.hpp"
+
+
+namespace vmime
+{
+
+
+void defaultParameter::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ parseValue(buffer, position, end);
+
+ if (newPosition)
+ *newPosition = end;
+}
+
+
+void defaultParameter::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 value = quotedValue();
+
+ pos += m_name.length() + value.length() + 2;
+
+ if (pos > maxLineLength)
+ {
+ os << NEW_LINE_SEQUENCE;
+ pos = NEW_LINE_SEQUENCE_LENGTH;
+ }
+
+ os << m_name << "=" << value;
+
+ if (newLinePos)
+ *newLinePos = pos;
+}
+
+
+const string defaultParameter::quotedValue() const
+{
+ const string value(generateValue());
+
+ std::ostringstream ss;
+ string::const_iterator start = value.begin();
+ bool quoted = false;
+
+ for (string::const_iterator i = value.begin() ; i != value.end() ; ++i)
+ {
+ switch (*i)
+ {
+ // Characters that need to be quoted _and_ escaped
+ case '"':
+ case '\\':
+
+ ss << string(start, i) << "\\" << *i;
+
+ start = i + 1;
+ quoted = true;
+
+ break;
+
+ // Other characters that need quoting
+ case ' ':
+ case '\t':
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ',':
+ case ';':
+ case ':':
+ case '/':
+ case '[':
+ case ']':
+ case '?':
+ case '=':
+
+ quoted = true;
+ break;
+ }
+ }
+
+ if (start != value.end())
+ ss << string(start, value.end());
+
+ return (quoted ? ("\"" + ss.str() + "\"") : (ss.str()));
+}
+
+
+void defaultParameter::copyFrom(const parameter& param)
+{
+ parameter::copyFrom(param);
+}
+
+
+} // vmime
diff --git a/src/defaultParameter.hpp b/src/defaultParameter.hpp
new file mode 100644
index 00000000..feb8c6f9
--- /dev/null
+++ b/src/defaultParameter.hpp
@@ -0,0 +1,55 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_DEFAULTPARAMETER_HPP_INCLUDED
+#define VMIME_DEFAULTPARAMETER_HPP_INCLUDED
+
+
+#include "parameter.hpp"
+
+
+namespace vmime
+{
+
+
+class defaultParameter : public parameter
+{
+protected:
+
+ void copyFrom(const parameter& param);
+
+ virtual void parseValue(const string& buffer, const string::size_type position, const string::size_type end) = 0;
+ virtual const string generateValue() const = 0;
+
+private:
+
+ const string quotedValue() const;
+
+ // No need to override these in class that derive from "defaultParameter".
+ // "defaultParameter" provides a default handling for value parsing/building.
+ // Instead, you must define two functions: "parseValue" and "generateValue" (see above).
+ 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_DEFAULTPARAMETER_HPP_INCLUDED
diff --git a/src/defaultParameterizedHeaderField.cpp b/src/defaultParameterizedHeaderField.cpp
new file mode 100644
index 00000000..9ca8d154
--- /dev/null
+++ b/src/defaultParameterizedHeaderField.cpp
@@ -0,0 +1,62 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "defaultParameterizedHeaderField.hpp"
+
+
+namespace vmime
+{
+
+
+defaultParameterizedHeaderField::defaultParameterizedHeaderField()
+{
+}
+
+
+void defaultParameterizedHeaderField::parseValue(const string& buffer,
+ const string::size_type position, const string::size_type end)
+{
+ m_value = string(buffer.begin() + position, buffer.begin() + end);
+}
+
+
+const string defaultParameterizedHeaderField::generateValue() const
+{
+ return (m_value);
+}
+
+
+void defaultParameterizedHeaderField::copyFrom(const headerField& field)
+{
+ const defaultParameterizedHeaderField& source = dynamic_cast
+ <const defaultParameterizedHeaderField&>(field);
+ m_value = source.m_value;
+
+ parameterizedHeaderField::copyFrom(field);
+}
+
+
+defaultParameterizedHeaderField& defaultParameterizedHeaderField::operator=(const string& value)
+{
+ m_value = value;
+ return (*this);
+}
+
+
+} // vmime
diff --git a/src/defaultParameterizedHeaderField.hpp b/src/defaultParameterizedHeaderField.hpp
new file mode 100644
index 00000000..d85fde59
--- /dev/null
+++ b/src/defaultParameterizedHeaderField.hpp
@@ -0,0 +1,63 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_DEFAULTPARAMETERIZEDHEADERFIELD_HPP_INCLUDED
+#define VMIME_DEFAULTPARAMETERIZEDHEADERFIELD_HPP_INCLUDED
+
+
+#include "parameterizedHeaderField.hpp"
+#include "base.hpp"
+
+
+namespace vmime
+{
+
+
+class defaultParameterizedHeaderField : public parameterizedHeaderField
+{
+ friend class headerFieldFactory::registerer <defaultParameterizedHeaderField>;
+
+protected:
+
+ defaultParameterizedHeaderField();
+
+public:
+
+ void copyFrom(const headerField& field);
+
+ defaultParameterizedHeaderField& operator=(const string& value);
+
+ const string& value() const { return (m_value); }
+ string& value() { return (m_value); }
+
+protected:
+
+ string m_value;
+
+protected:
+
+ void parseValue(const string& buffer, const string::size_type position, const string::size_type end);
+ const string generateValue() const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_DEFAULTPARAMETERIZEDHEADERFIELD_HPP_INCLUDED
diff --git a/src/disposition.cpp b/src/disposition.cpp
new file mode 100644
index 00000000..7f8962f0
--- /dev/null
+++ b/src/disposition.cpp
@@ -0,0 +1,91 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "disposition.hpp"
+
+
+namespace vmime
+{
+
+
+disposition::disposition()
+ : m_name(dispositionTypes::INLINE)
+{
+}
+
+
+disposition::disposition(const string& name)
+ : m_name(toLower(name))
+{
+}
+
+
+disposition::disposition(const disposition& type)
+ : component(), m_name(type.m_name)
+{
+}
+
+
+void disposition::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ m_name = toLower(string(buffer.begin() + position, buffer.begin() + end));
+
+ if (newPosition)
+ *newPosition = end;
+}
+
+
+void disposition::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ os << m_name;
+
+ if (newLinePos)
+ *newLinePos = curLinePos + m_name.length();
+}
+
+
+disposition& disposition::operator=(const disposition& source)
+{
+ m_name = source.m_name;
+ return (*this);
+}
+
+
+disposition& disposition::operator=(const string& name)
+{
+ m_name = toLower(name);
+ return (*this);
+}
+
+
+const bool disposition::operator==(const disposition& value) const
+{
+ return (toLower(m_name) == value.m_name);
+}
+
+
+const bool disposition::operator!=(const disposition& value) const
+{
+ return !(*this == value);
+}
+
+
+} // vmime
diff --git a/src/disposition.hpp b/src/disposition.hpp
new file mode 100644
index 00000000..c994a723
--- /dev/null
+++ b/src/disposition.hpp
@@ -0,0 +1,74 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "base.hpp"
+#include "component.hpp"
+
+
+namespace vmime
+{
+
+
+/** Content disposition (basic type).
+ */
+
+class disposition : public component
+{
+public:
+
+ disposition();
+ disposition(const string& name);
+ disposition(const disposition& disp);
+
+public:
+
+ const string& name() const { return (m_name); }
+ string& name() { return (m_name); }
+
+public:
+
+ disposition& operator=(const disposition& source);
+ disposition& operator=(const string& name);
+
+ const bool operator==(const disposition& value) const;
+ const bool operator!=(const disposition& value) const;
+
+protected:
+
+ string m_name;
+
+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/src/encoder.cpp b/src/encoder.cpp
new file mode 100644
index 00000000..6634f7bb
--- /dev/null
+++ b/src/encoder.cpp
@@ -0,0 +1,69 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "encoder.hpp"
+#include "exception.hpp"
+
+
+namespace vmime
+{
+
+
+encoder::encoder()
+{
+}
+
+
+encoder::~encoder()
+{
+}
+
+
+const propertySet& encoder::properties() const
+{
+ return (m_props);
+}
+
+
+propertySet& encoder::properties()
+{
+ return (m_props);
+}
+
+
+const propertySet& encoder::results() const
+{
+ return (m_results);
+}
+
+
+propertySet& encoder::results()
+{
+ return (m_results);
+}
+
+
+const std::vector <string> encoder::availableProperties() const
+{
+ std::vector <string> list;
+ return (list);
+}
+
+
+} // vmime
diff --git a/src/encoder.hpp b/src/encoder.hpp
new file mode 100644
index 00000000..1aa97d49
--- /dev/null
+++ b/src/encoder.hpp
@@ -0,0 +1,95 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_ENCODER_HPP_INCLUDED
+#define VMIME_ENCODER_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "propertySet.hpp"
+#include "exception.hpp"
+
+
+namespace vmime
+{
+
+
+class encoder
+{
+public:
+
+ encoder();
+ virtual ~encoder();
+
+ /** Encode data.
+ *
+ * @param in input data (decoded)
+ * @param out output stream for encoded data
+ * @return number of bytes written into output stream
+ */
+ virtual const utility::stream::size_type encode(utility::inputStream& in, utility::outputStream& out) = 0;
+
+ /** Decode data.
+ *
+ * @param in input data (encoded)
+ * @param out output stream for decoded data
+ * @return number of bytes written into output stream
+ */
+ virtual const utility::stream::size_type decode(utility::inputStream& in, utility::outputStream& out) = 0;
+
+ /** Return the properties of the encoder.
+ *
+ * @return properties of the encoder
+ */
+ const propertySet& properties() const;
+
+ /** Return the properties of the encoder.
+ *
+ * @return properties of the encoder
+ */
+ propertySet& properties();
+
+ /** Return a list of property names that can be set for
+ * this encoder.
+ *
+ * @return list of property names
+ */
+ virtual const std::vector <string> availableProperties() const;
+
+ /** Return the results returned by this encoder.
+ *
+ * @return results returned by the encoder
+ */
+ const propertySet& results() const;
+
+protected:
+
+ propertySet& results();
+
+private:
+
+ propertySet m_props;
+ propertySet m_results;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_ENCODER_HPP_INCLUDED
diff --git a/src/encoder7bit.cpp b/src/encoder7bit.cpp
new file mode 100644
index 00000000..b5ae3820
--- /dev/null
+++ b/src/encoder7bit.cpp
@@ -0,0 +1,32 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "encoder7bit.hpp"
+
+
+namespace vmime
+{
+
+
+encoder7bit::encoder7bit()
+{
+}
+
+
+} // vmime
diff --git a/src/encoder7bit.hpp b/src/encoder7bit.hpp
new file mode 100644
index 00000000..a4b64cdf
--- /dev/null
+++ b/src/encoder7bit.hpp
@@ -0,0 +1,45 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_ENCODER7BIT_HPP_INCLUDED
+#define VMIME_ENCODER7BIT_HPP_INCLUDED
+
+
+#include "encoderDefault.hpp"
+
+
+namespace vmime
+{
+
+
+/** 7-bit encoder.
+ */
+
+class encoder7bit : public encoderDefault
+{
+public:
+
+ encoder7bit();
+};
+
+
+} // vmime
+
+
+#endif // VMIME_ENCODER7BIT_HPP_INCLUDED
diff --git a/src/encoder8bit.cpp b/src/encoder8bit.cpp
new file mode 100644
index 00000000..b9b91457
--- /dev/null
+++ b/src/encoder8bit.cpp
@@ -0,0 +1,32 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "encoder8bit.hpp"
+
+
+namespace vmime
+{
+
+
+encoder8bit::encoder8bit()
+{
+}
+
+
+} // vmime
diff --git a/src/encoder8bit.hpp b/src/encoder8bit.hpp
new file mode 100644
index 00000000..7cbbd417
--- /dev/null
+++ b/src/encoder8bit.hpp
@@ -0,0 +1,45 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_ENCODER8BIT_HPP_INCLUDED
+#define VMIME_ENCODER8BIT_HPP_INCLUDED
+
+
+#include "encoderDefault.hpp"
+
+
+namespace vmime
+{
+
+
+/** 8-bit encoder.
+ */
+
+class encoder8bit : public encoderDefault
+{
+public:
+
+ encoder8bit();
+};
+
+
+} // vmime
+
+
+#endif // VMIME_ENCODER8BIT_HPP_INCLUDED
diff --git a/src/encoderB64.cpp b/src/encoderB64.cpp
new file mode 100644
index 00000000..25b15ad9
--- /dev/null
+++ b/src/encoderB64.cpp
@@ -0,0 +1,265 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "encoderB64.hpp"
+#include "parserHelpers.hpp"
+
+
+namespace vmime
+{
+
+
+encoderB64::encoderB64()
+{
+}
+
+
+const std::vector <string> encoderB64::availableProperties() const
+{
+ std::vector <string> list(encoder::availableProperties());
+
+ list.push_back("maxlinelength");
+
+ return (list);
+}
+
+
+// 7-bits alphabet used to encode binary data
+const unsigned char encoderB64::sm_alphabet[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+
+const unsigned char encoderB64::sm_decodeMap[256] =
+{
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0x00 - 0x0f
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0x10 - 0x1f
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3e,0xff,0xff,0xff,0x3f, // 0x20 - 0x2f
+ 0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0xff,0xff,0xff,0x3d,0xff,0xff, // 0x30 - 0x3f
+ 0xff,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e, // 0x40 - 0x4f
+ 0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0xff,0xff,0xff,0xff,0xff, // 0x50 - 0x5f
+ 0xff,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28, // 0x60 - 0x6f
+ 0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0xff,0xff,0xff,0xff, // 0x70 - 0x7f
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0x80 - 0x8f
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0x90 - 0x9f
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xa0 - 0xaf
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xb0 - 0xbf
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xc0 - 0xcf
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xd0 - 0xdf
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xe0 - 0xef
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xf0 - 0xff
+};
+
+
+
+const utility::stream::size_type encoderB64::encode(utility::inputStream& in, utility::outputStream& out)
+{
+ in.reset(); // may not work...
+
+ const int propMaxLineLength = properties().get <int>("maxlinelength", -1);
+
+ const bool cutLines = (propMaxLineLength != -1);
+ const int maxLineLength = std::min(propMaxLineLength, 76);
+
+ // Process data
+ utility::stream::value_type buffer[65536];
+ utility::stream::size_type bufferLength = 0;
+ utility::stream::size_type bufferPos = 0;
+
+ unsigned char bytes[3];
+ unsigned char output[4];
+
+ utility::stream::size_type total = 0;
+
+ int curCol = 0;
+
+ while (bufferPos < bufferLength || !in.eof())
+ {
+ if (bufferPos >= bufferLength)
+ {
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+
+ if (bufferLength == 0)
+ break;
+ }
+
+ // Get 3 bytes of data
+ int count = 0;
+
+ while (count < 3 && bufferPos < bufferLength)
+ bytes[count++] = buffer[bufferPos++];
+
+ if (count != 3)
+ {
+ // There may be more data in the next chunk...
+ if (bufferPos >= bufferLength)
+ {
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+ }
+
+ while (count < 3 && bufferPos < bufferLength)
+ bytes[count++] = buffer[bufferPos++];
+ }
+
+ // Encode data
+ switch (count)
+ {
+ case 1:
+
+ output[0] = sm_alphabet[(bytes[0] & 0xFC) >> 2];
+ output[1] = sm_alphabet[(bytes[0] & 0x03) << 4];
+ output[2] = sm_alphabet[64]; // padding
+ output[3] = sm_alphabet[64]; // padding
+
+ break;
+
+ case 2:
+
+ output[0] = sm_alphabet[(bytes[0] & 0xFC) >> 2];
+ output[1] = sm_alphabet[((bytes[0] & 0x03) << 4) | ((bytes[1] & 0xF0) >> 4)];
+ output[2] = sm_alphabet[(bytes[1] & 0x0F) << 2];
+ output[3] = sm_alphabet[64]; // padding
+
+ break;
+
+ default:
+ case 3:
+
+ output[0] = sm_alphabet[(bytes[0] & 0xFC) >> 2];
+ output[1] = sm_alphabet[((bytes[0] & 0x03) << 4) | ((bytes[1] & 0xF0) >> 4)];
+ output[2] = sm_alphabet[((bytes[1] & 0x0F) << 2) | ((bytes[2] & 0xC0) >> 6)];
+ output[3] = sm_alphabet[(bytes[2] & 0x3F)];
+
+ break;
+ }
+
+ // Write encoded data to output stream
+ out.write((char*) output, 4);
+
+ total += 4;
+ curCol += 4;
+
+ if (cutLines && curCol >= maxLineLength - 1)
+ {
+ out.write("\r\n", 2);
+ curCol = 0;
+ }
+ }
+
+ return (total);
+}
+
+
+const utility::stream::size_type encoderB64::decode(utility::inputStream& in, utility::outputStream& out)
+{
+ in.reset(); // may not work...
+
+ // Process the data
+ char buffer[16384];
+ int bufferLength = 0;
+ int bufferPos = 0;
+
+ utility::stream::size_type total = 0;
+
+ unsigned char bytes[4];
+ unsigned char output[3];
+
+ while (bufferPos < bufferLength || !in.eof())
+ {
+ // Need to get more data?
+ if (bufferPos >= bufferLength)
+ {
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+
+ // No more data
+ if (bufferLength == 0)
+ break;
+ }
+
+ // 4 bytes of input provide 3 bytes of output, so
+ // get the next 4 bytes from the input stream.
+ int count = 0;
+
+ while (count < 4 && bufferPos < bufferLength)
+ {
+ const unsigned char c = buffer[bufferPos++];
+
+ if (!isspace(c))
+ bytes[count++] = c;
+ }
+
+ if (count != 4)
+ {
+ while (count < 4 && !in.eof())
+ {
+ // Data continues on the next chunk
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+
+ while (count < 4 && bufferPos < bufferLength)
+ {
+ const unsigned char c = buffer[bufferPos++];
+
+ if (!isspace(c))
+ bytes[count++] = c;
+ }
+ }
+ }
+
+ // Decode the bytes
+ unsigned char c1 = bytes[0];
+ unsigned char c2 = bytes[1];
+
+ if (c1 == '=' || c2 == '=') // end
+ break;
+
+ output[0] = (unsigned char)((sm_decodeMap[c1] << 2) | ((sm_decodeMap[c2] & 0x30) >> 4));
+
+ c1 = bytes[2];
+
+ if (c1 == '=') // end
+ {
+ out.write((char*) output, 1);
+ total += 1;
+ break;
+ }
+
+ output[1] = (unsigned char)(((sm_decodeMap[c2] & 0xf) << 4) | ((sm_decodeMap[c1] & 0x3c) >> 2));
+
+ c2 = bytes[3];
+
+ if (c2 == '=') // end
+ {
+ out.write((char*) output, 2);
+ total += 2;
+ break;
+ }
+
+ output[2] = (unsigned char)(((sm_decodeMap[c1] & 0x03) << 6) | sm_decodeMap[c2]);
+
+ out.write((char*) output, 3);
+ total += 3;
+ }
+
+ return (total);
+}
+
+
+} // vmime
diff --git a/src/encoderB64.hpp b/src/encoderB64.hpp
new file mode 100644
index 00000000..ff978985
--- /dev/null
+++ b/src/encoderB64.hpp
@@ -0,0 +1,55 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_ENCODERB64_HPP_INCLUDED
+#define VMIME_ENCODERB64_HPP_INCLUDED
+
+
+#include "encoder.hpp"
+
+
+namespace vmime
+{
+
+
+/** Base64 encoder.
+ */
+
+class encoderB64 : public encoder
+{
+public:
+
+ encoderB64();
+
+ const utility::stream::size_type encode(utility::inputStream& in, utility::outputStream& out);
+ const utility::stream::size_type decode(utility::inputStream& in, utility::outputStream& out);
+
+ const std::vector <string> availableProperties() const;
+
+protected:
+
+ static const unsigned char sm_alphabet[];
+ static const unsigned char sm_decodeMap[256];
+};
+
+
+} // vmime
+
+
+#endif // VMIME_ENCODERB64_HPP_INCLUDED
diff --git a/src/encoderBinary.cpp b/src/encoderBinary.cpp
new file mode 100644
index 00000000..606da99c
--- /dev/null
+++ b/src/encoderBinary.cpp
@@ -0,0 +1,32 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "encoderBinary.hpp"
+
+
+namespace vmime
+{
+
+
+encoderBinary::encoderBinary()
+{
+}
+
+
+} // vmime
diff --git a/src/encoderBinary.hpp b/src/encoderBinary.hpp
new file mode 100644
index 00000000..dadca217
--- /dev/null
+++ b/src/encoderBinary.hpp
@@ -0,0 +1,45 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_ENCODERBINARY_HPP_INCLUDED
+#define VMIME_ENCODERBINARY_HPP_INCLUDED
+
+
+#include "encoderDefault.hpp"
+
+
+namespace vmime
+{
+
+
+/** Binary encoder.
+ */
+
+class encoderBinary : public encoderDefault
+{
+public:
+
+ encoderBinary();
+};
+
+
+} // vmime
+
+
+#endif // VMIME_ENCODERBINARY_HPP_INCLUDED
diff --git a/src/encoderDefault.cpp b/src/encoderDefault.cpp
new file mode 100644
index 00000000..cdff3735
--- /dev/null
+++ b/src/encoderDefault.cpp
@@ -0,0 +1,50 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "encoderDefault.hpp"
+
+
+namespace vmime
+{
+
+
+encoderDefault::encoderDefault()
+{
+}
+
+
+const utility::stream::size_type encoderDefault::encode(utility::inputStream& in, utility::outputStream& out)
+{
+ in.reset(); // may not work...
+
+ // No encoding performed
+ return (utility::bufferedStreamCopy(in, out));
+}
+
+
+const utility::stream::size_type encoderDefault::decode(utility::inputStream& in, utility::outputStream& out)
+{
+ in.reset(); // may not work...
+
+ // No decoding performed
+ return (utility::bufferedStreamCopy(in, out));
+}
+
+
+} // vmime
diff --git a/src/encoderDefault.hpp b/src/encoderDefault.hpp
new file mode 100644
index 00000000..d54d1f0f
--- /dev/null
+++ b/src/encoderDefault.hpp
@@ -0,0 +1,48 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_ENCODERDEFAULT_HPP_INCLUDED
+#define VMIME_ENCODERDEFAULT_HPP_INCLUDED
+
+
+#include "encoder.hpp"
+
+
+namespace vmime
+{
+
+
+/** Default encoder (simple copy, no encoding/decoding is performed).
+ */
+
+class encoderDefault : public encoder
+{
+public:
+
+ encoderDefault();
+
+ const utility::stream::size_type encode(utility::inputStream& in, utility::outputStream& out);
+ const utility::stream::size_type decode(utility::inputStream& in, utility::outputStream& out);
+};
+
+
+} // vmime
+
+
+#endif // VMIME_ENCODERDEFAUL_HPP_INCLUDED
diff --git a/src/encoderFactory.cpp b/src/encoderFactory.cpp
new file mode 100644
index 00000000..6da09dbb
--- /dev/null
+++ b/src/encoderFactory.cpp
@@ -0,0 +1,70 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "encoderFactory.hpp"
+#include "exception.hpp"
+
+#include "encoderB64.hpp"
+#include "encoderQP.hpp"
+#include "encoderUUE.hpp"
+#include "encoderBinary.hpp"
+#include "encoder7bit.hpp"
+#include "encoder8bit.hpp"
+
+
+namespace vmime
+{
+
+
+encoderFactory::encoderFactory()
+{
+ // Register some default encoders
+ registerName <encoderB64>("base64");
+ registerName <encoderQP>("quoted-printable");
+ registerName <encoderUUE>("uuencode");
+ registerName <encoder7bit>("7bit");
+ registerName <encoder8bit>("8bit");
+ registerName <encoderBinary>("binary");
+}
+
+
+encoderFactory::~encoderFactory()
+{
+ for (NameMap::iterator it = m_nameMap.begin() ; it != m_nameMap.end() ; ++it)
+ delete ((*it).second);
+}
+
+
+encoder* encoderFactory::create(const string& name)
+{
+ NameMap::const_iterator pos = m_nameMap.find(toLower(name));
+
+ if (pos != m_nameMap.end())
+ {
+ return ((*pos).second)->create();
+ }
+ else
+ {
+ throw exceptions::no_encoder_available();
+ return (NULL);
+ }
+}
+
+
+} // vmime
diff --git a/src/encoderFactory.hpp b/src/encoderFactory.hpp
new file mode 100644
index 00000000..cbd52048
--- /dev/null
+++ b/src/encoderFactory.hpp
@@ -0,0 +1,183 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_ENCODERFACTORY_HPP_INCLUDED
+#define VMIME_ENCODERFACTORY_HPP_INCLUDED
+
+
+#include "encoder.hpp"
+#include "utility/singleton.hpp"
+
+
+namespace vmime
+{
+
+
+/** A factory to create 'encoder' objects for the specified encoding.
+ */
+
+class encoderFactory : public utility::singleton <encoderFactory>
+{
+ friend class utility::singleton <encoderFactory>;
+
+private:
+
+ encoderFactory();
+ ~encoderFactory();
+
+public:
+
+ class registeredEncoder
+ {
+ friend class encoderFactory;
+
+ protected:
+
+ virtual ~registeredEncoder() { }
+
+ public:
+
+ virtual encoder* create() = 0;
+
+ virtual const string& name() const = 0;
+ };
+
+private:
+
+ template <class E>
+ class registeredEncoderImpl : public registeredEncoder
+ {
+ friend class encoderFactory;
+
+ protected:
+
+ registeredEncoderImpl(const string& name) : m_name(name) { }
+
+ public:
+
+ encoder* create()
+ {
+ return new E;
+ }
+
+ const string& name() const
+ {
+ return (m_name);
+ }
+
+ private:
+
+ const string m_name;
+ };
+
+
+ typedef std::map <string, registeredEncoder*> NameMap;
+ NameMap m_nameMap;
+
+public:
+
+ template <class E>
+ void registerName(const string& name)
+ {
+ const string _name = toLower(name);
+ m_nameMap.insert(NameMap::value_type(_name,
+ new registeredEncoderImpl <E>(_name)));
+ }
+
+ encoder* create(const string& name);
+
+ const registeredEncoder& operator[](const string& name) const;
+
+
+ class iterator;
+
+ class const_iterator
+ {
+ friend class encoderFactory;
+
+ public:
+
+ const_iterator() { }
+ const_iterator(const const_iterator& it) : m_it(it.m_it) { }
+ const_iterator(const iterator& it) : m_it(it.m_it) { }
+
+ const_iterator& operator=(const const_iterator& it) { m_it = it.m_it; return (*this); }
+
+ const registeredEncoder& operator*() const { return (*(*m_it).second); }
+ const registeredEncoder* operator->() const { return ((*m_it).second); }
+
+ const_iterator& operator++() { ++m_it; return (*this); }
+ const_iterator operator++(int) { return (m_it++); }
+
+ const_iterator& operator--() { --m_it; return (*this); }
+ const_iterator operator--(int) { return (m_it--); }
+
+ const bool operator==(const const_iterator& it) const { return (m_it == it.m_it); }
+ const bool operator!=(const const_iterator& it) const { return (m_it != it.m_it); }
+
+ private:
+
+ const_iterator(const NameMap::const_iterator it) : m_it(it) { }
+
+ NameMap::const_iterator m_it;
+ };
+
+ class iterator
+ {
+ friend class encoderFactory;
+ friend class encoderFactory::const_iterator;
+
+ public:
+
+ iterator() { }
+ iterator(const iterator& it) : m_it(it.m_it) { }
+
+ iterator& operator=(const iterator& it) { m_it = it.m_it; return (*this); }
+
+ registeredEncoder& operator*() const { return (*(*m_it).second); }
+ registeredEncoder* operator->() const { return ((*m_it).second); }
+
+ iterator& operator++() { ++m_it; return (*this); }
+ iterator operator++(int) { return (m_it++); }
+
+ iterator& operator--() { --m_it; return (*this); }
+ iterator operator--(int) { return (m_it--); }
+
+ const bool operator==(const iterator& it) const { return (m_it == it.m_it); }
+ const bool operator!=(const iterator& it) const { return (m_it != it.m_it); }
+
+ private:
+
+ iterator(const NameMap::iterator it) : m_it(it) { }
+
+ NameMap::iterator m_it;
+ };
+
+ iterator begin() { return iterator(m_nameMap.begin()); }
+ iterator end() { return iterator(m_nameMap.end()); }
+
+ const_iterator begin() const { return const_iterator(m_nameMap.begin()); }
+ const_iterator end() const { return const_iterator(m_nameMap.end()); }
+};
+
+
+} // vmime
+
+
+#endif // VMIME_ENCODERFACTORY_HPP_INCLUDED
diff --git a/src/encoderQP.cpp b/src/encoderQP.cpp
new file mode 100644
index 00000000..46125c93
--- /dev/null
+++ b/src/encoderQP.cpp
@@ -0,0 +1,422 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "encoderQP.hpp"
+#include "parserHelpers.hpp"
+
+
+namespace vmime
+{
+
+
+encoderQP::encoderQP()
+{
+}
+
+
+const std::vector <string> encoderQP::availableProperties() const
+{
+ std::vector <string> list(encoder::availableProperties());
+
+ list.push_back("maxlinelength");
+
+ list.push_back("text"); // if set, '\r' and '\n' are not hex-encoded.
+ // WARNING! You should not use this for binary data!
+
+ list.push_back("rfc2047"); // for header fields encoding (RFC #2047)
+
+ return (list);
+}
+
+
+
+// Encoding table
+const unsigned char encoderQP::sm_hexDigits[] = "0123456789ABCDEF";
+
+// Decoding table
+const unsigned char encoderQP::sm_hexDecodeTable[256] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+#define QP_ENCODE_HEX(x) \
+ outBuffer[outBufferPos] = '='; \
+ outBuffer[outBufferPos + 1] = sm_hexDigits[x >> 4]; \
+ outBuffer[outBufferPos + 2] = sm_hexDigits[x & 0xF]; \
+ outBufferPos += 3; \
+ curCol += 3;
+
+
+const utility::stream::size_type encoderQP::encode(utility::inputStream& in, utility::outputStream& out)
+{
+ in.reset(); // may not work...
+
+ const string::size_type propMaxLineLength =
+ properties().get <string::size_type>("maxlinelength", (string::size_type) -1);
+
+ const bool rfc2047 = properties().get <bool>("rfc2047", false);
+ const bool text = properties().get <bool>("text", false); // binary mode by default
+
+ const bool cutLines = (propMaxLineLength != (string::size_type) -1);
+ const string::size_type maxLineLength = std::min(propMaxLineLength, (string::size_type) 74);
+
+ // Process the data
+ char buffer[16384];
+ int bufferLength = 0;
+ int bufferPos = 0;
+
+ string::size_type curCol = 0;
+
+ unsigned char outBuffer[16384];
+ int outBufferPos = 0;
+
+ utility::stream::size_type total = 0;
+
+ while (bufferPos < bufferLength || !in.eof())
+ {
+ // Flush current output buffer
+ if (outBufferPos + 6 >= (int) sizeof(outBuffer))
+ {
+ out.write((char*) outBuffer, outBufferPos);
+
+ total += outBufferPos;
+ outBufferPos = 0;
+ }
+
+ // Need to get more data?
+ if (bufferPos >= bufferLength)
+ {
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+
+ // No more data
+ if (bufferLength == 0)
+ break;
+ }
+
+ // Get the next char and encode it
+ const unsigned char c = (unsigned char) buffer[bufferPos++];
+
+ switch (c)
+ {
+ case '.':
+ {
+ if (!rfc2047 && curCol == 0)
+ {
+ // If a '.' appears at the beginning of a line, we encode it to
+ // to avoid problems with SMTP servers... ("\r\n.\r\n" means the
+ // end of data transmission).
+ QP_ENCODE_HEX('.')
+ continue;
+ }
+
+ outBuffer[outBufferPos++] = '.';
+ ++curCol;
+ break;
+ }
+ case ' ':
+ {
+ // RFC-2047, Page 5, 4.2. The "Q" encoding:
+ // << The 8-bit hexadecimal value 20 (e.g., ISO-8859-1 SPACE) may be
+ // represented as "_" (underscore, ASCII 95.). >>
+ if (rfc2047)
+ {
+ outBuffer[outBufferPos++] = ' ';
+ ++curCol;
+ }
+ else
+ {
+ // Need to get more data?
+ if (bufferPos >= bufferLength)
+ {
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+ }
+
+ // Spaces cannot appear at the end of a line. So, encode the space.
+ if (bufferPos >= bufferLength ||
+ (buffer[bufferPos] == '\r' || buffer[bufferPos] == '\n'))
+ {
+ QP_ENCODE_HEX(' ');
+ }
+ else
+ {
+ outBuffer[outBufferPos++] = ' ';
+ ++curCol;
+ }
+ }
+
+ break;
+ }
+ case '\t':
+ {
+ QP_ENCODE_HEX(c)
+ break;
+ }
+ case '\r':
+ case '\n':
+ {
+ // Text mode (where using CRLF or LF or ... does not
+ // care for a new line...)
+ if (text)
+ {
+ outBuffer[outBufferPos++] = c;
+ ++curCol;
+ }
+ // Binary mode (where CR and LF bytes are important!)
+ else
+ {
+ QP_ENCODE_HEX(c)
+ }
+
+ break;
+ }
+ case '=':
+ {
+ QP_ENCODE_HEX('=')
+ break;
+ }
+ case ',':
+ case ';':
+ case ':':
+ case '_':
+ {
+ if (rfc2047)
+ {
+ QP_ENCODE_HEX(c)
+ }
+ else
+ {
+ outBuffer[outBufferPos++] = c;
+ ++curCol;
+ }
+
+ break;
+ }
+ /*
+ Rule #2: (Literal representation) Octets with decimal values of 33
+ through 60 inclusive, and 62 through 126, inclusive, MAY be
+ represented as the ASCII characters which correspond to those
+ octets (EXCLAMATION POINT through LESS THAN, and GREATER THAN
+ through TILDE, respectively).
+ */
+ default:
+ {
+ //if ((c >= 33 && c <= 60) || (c >= 62 && c <= 126))
+ if (c >= 33 && c <= 126 && c != 61)
+ {
+ outBuffer[outBufferPos++] = c;
+ ++curCol;
+ }
+ // Other characters: '=' + hexadecimal encoding
+ else
+ {
+ QP_ENCODE_HEX(c)
+ }
+
+ break;
+ }
+
+ }
+
+ // Soft line break : "=\r\n"
+ if (cutLines && curCol >= maxLineLength - 1)
+ {
+ outBuffer[outBufferPos] = '=';
+ outBuffer[outBufferPos + 1] = '\r';
+ outBuffer[outBufferPos + 2] = '\n';
+
+ outBufferPos += 3;
+ curCol = 0;
+ }
+ }
+
+ // Flush remaining output buffer
+ if (outBufferPos != 0)
+ {
+ out.write((char*) outBuffer, outBufferPos);
+ total += outBufferPos;
+ }
+
+ return (total);
+}
+
+
+const utility::stream::size_type encoderQP::decode(utility::inputStream& in, utility::outputStream& out)
+{
+ in.reset(); // may not work...
+
+ // Process the data
+ const bool rfc2047 = properties().get <bool>("rfc2047", false);
+
+ char buffer[16384];
+ int bufferLength = 0;
+ int bufferPos = 0;
+
+ unsigned char outBuffer[16384];
+ int outBufferPos = 0;
+
+ utility::stream::size_type total = 0;
+
+ while (bufferPos < bufferLength || !in.eof())
+ {
+ // Flush current output buffer
+ if (outBufferPos >= (int) sizeof(outBuffer))
+ {
+ out.write((char*) outBuffer, outBufferPos);
+
+ total += outBufferPos;
+ outBufferPos = 0;
+ }
+
+ // Need to get more data?
+ if (bufferPos >= bufferLength)
+ {
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+
+ // No more data
+ if (bufferLength == 0)
+ break;
+ }
+
+ // Decode the next sequence (hex-encoded byte or printable character)
+ unsigned char c = (unsigned char) buffer[bufferPos++];
+
+ switch (c)
+ {
+ case '=':
+ {
+ if (bufferPos >= bufferLength)
+ {
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+ }
+
+ if (bufferPos < bufferLength)
+ {
+ c = (unsigned char) buffer[bufferPos++];
+
+ switch (c)
+ {
+ // Ignore soft line break ("=\r\n" or "=\n")
+ case '\r':
+
+ // Read one byte more
+ if (bufferPos >= bufferLength)
+ {
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+ }
+
+ if (bufferPos < bufferLength)
+ ++bufferPos;
+
+ break;
+
+ case '\n':
+
+ break;
+
+ // Hex-encoded char
+ default:
+ {
+ // We need another byte...
+ if (bufferPos >= bufferLength)
+ {
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+ }
+
+ if (bufferPos < bufferLength)
+ {
+ const unsigned char next = (unsigned char) buffer[bufferPos++];
+
+ const unsigned char value =
+ sm_hexDecodeTable[c] * 16
+ + sm_hexDecodeTable[next];
+
+ outBuffer[outBufferPos++] = value;
+ }
+ else
+ {
+ // Premature end-of-data
+ }
+
+ break;
+ }
+
+ }
+ }
+ else
+ {
+ // Premature end-of-data
+ }
+
+ break;
+ }
+ case '_':
+ {
+ if (rfc2047)
+ {
+ // RFC-2047, Page 5, 4.2. The "Q" encoding:
+ // << Note that the "_" always represents hexadecimal 20, even if the SPACE
+ // character occupies a different code position in the character set in use. >>
+ outBuffer[outBufferPos++] = 0x20;
+ break;
+ }
+
+ // no break here...
+ }
+ default:
+ {
+ outBuffer[outBufferPos++] = c;
+ }
+
+ }
+ }
+
+ // Flush remaining output buffer
+ if (outBufferPos != 0)
+ {
+ out.write((char*) outBuffer, outBufferPos);
+ total += outBufferPos;
+ }
+
+ return (total);
+}
+
+
+} // vmime
diff --git a/src/encoderQP.hpp b/src/encoderQP.hpp
new file mode 100644
index 00000000..519f43f1
--- /dev/null
+++ b/src/encoderQP.hpp
@@ -0,0 +1,55 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_ENCODERQP_HPP_INCLUDED
+#define VMIME_ENCODERQP_HPP_INCLUDED
+
+
+#include "encoder.hpp"
+
+
+namespace vmime
+{
+
+
+/** Quoted-printable encoder.
+ */
+
+class encoderQP : public encoder
+{
+public:
+
+ encoderQP();
+
+ const utility::stream::size_type encode(utility::inputStream& in, utility::outputStream& out);
+ const utility::stream::size_type decode(utility::inputStream& in, utility::outputStream& out);
+
+ const std::vector <string> availableProperties() const;
+
+protected:
+
+ static const unsigned char sm_hexDigits[17];
+ static const unsigned char sm_hexDecodeTable[256];
+};
+
+
+} // vmime
+
+
+#endif // VMIME_ENCODERQP_HPP_INCLUDED
diff --git a/src/encoderUUE.cpp b/src/encoderUUE.cpp
new file mode 100644
index 00000000..78dffa0c
--- /dev/null
+++ b/src/encoderUUE.cpp
@@ -0,0 +1,289 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "encoderUUE.hpp"
+#include "parserHelpers.hpp"
+
+
+namespace vmime
+{
+
+
+encoderUUE::encoderUUE()
+{
+ properties()["mode"] = 644;
+ properties()["filename"] = "no_name";
+ properties()["maxlinelength"] = 46;
+}
+
+
+const std::vector <string> encoderUUE::availableProperties() const
+{
+ std::vector <string> list(encoder::availableProperties());
+
+ list.push_back("maxlinelength");
+
+ list.push_back("mode");
+ list.push_back("filename");
+
+ return (list);
+}
+
+
+// This is the character encoding function to make a character printable
+static inline const unsigned char UUENCODE(const unsigned char c)
+{
+ return ((c & 077) + ' ');
+}
+
+// Single character decoding
+static inline const unsigned char UUDECODE(const unsigned char c)
+{
+ return ((c - ' ') & 077);
+}
+
+
+const utility::stream::size_type encoderUUE::encode(utility::inputStream& in, utility::outputStream& out)
+{
+ in.reset(); // may not work...
+
+ const string propFilename = properties().get <string>("filename", "");
+ const string propMode = properties().get <string>("mode", "644");
+
+ const string::size_type maxLineLength =
+ std::min(properties().get <string::size_type>("maxlinelength", 46),
+ static_cast <string::size_type>(46));
+
+ utility::stream::size_type total = 0;
+
+ // Output the prelude text ("begin [mode] [filename]")
+ out << "begin";
+
+ if (!propFilename.empty())
+ {
+ out << " " << propMode << " " << propFilename;
+ total += 2 + propMode.length() + propFilename.length();
+ }
+
+ out << "\r\n";
+ total += 7;
+
+ // Process the data
+ utility::stream::value_type inBuffer[64];
+ utility::stream::value_type outBuffer[64];
+
+ while (!in.eof())
+ {
+ // Process up to 45 characters per line
+ std::fill(inBuffer, inBuffer + sizeof(inBuffer), 0);
+
+ const utility::stream::size_type inLength = in.read(inBuffer, maxLineLength - 1);
+
+ outBuffer[0] = UUENCODE(inLength); // Line length
+
+ utility::stream::size_type j = 1;
+
+ for (utility::stream::size_type i = 0 ; i < inLength ; i += 3, j += 4)
+ {
+ const unsigned char c1 = (unsigned char) inBuffer[i];
+ const unsigned char c2 = (unsigned char) inBuffer[i + 1];
+ const unsigned char c3 = (unsigned char) inBuffer[i + 2];
+
+ outBuffer[j] = UUENCODE(c1 >> 2);
+ outBuffer[j + 1] = UUENCODE((c1 << 4) & 060 | (c2 >> 4) & 017);
+ outBuffer[j + 2] = UUENCODE((c2 << 2) & 074 | (c3 >> 6) & 03);
+ outBuffer[j + 3] = UUENCODE(c3 & 077);
+ }
+
+ outBuffer[j] = '\r';
+ outBuffer[j + 1] = '\n';
+
+ out.write(outBuffer, j + 2);
+
+ total += j + 2;
+ }
+
+ out << "end\r\n";
+ total += 5;
+
+ return (total);
+}
+
+
+const utility::stream::size_type encoderUUE::decode(utility::inputStream& in, utility::outputStream& out)
+{
+ in.reset(); // may not work...
+
+ // Process the data
+ utility::stream::value_type inBuffer[64];
+ utility::stream::value_type outBuffer[64];
+
+ utility::stream::size_type total = 0;
+
+ bool stop = false;
+
+ std::fill(inBuffer, inBuffer + sizeof(inBuffer), 0);
+
+ while (!stop && !in.eof())
+ {
+ // Get the line length
+ utility::stream::value_type lengthChar;
+
+ if (in.read(&lengthChar, 1) == 0)
+ break;
+
+ const utility::stream::size_type outLength = UUDECODE(lengthChar);
+ const utility::stream::size_type inLength = std::min((outLength * 4) / 3, (utility::stream::size_type) 64);
+ utility::stream::value_type inPos = 0;
+
+ switch (lengthChar)
+ {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ {
+ // Ignore
+ continue;
+ }
+ case 'b':
+ {
+ // Read 5 characters more to check for begin ("begin ...\r\n" or "begin ...\n")
+ inPos = in.read(inBuffer, 5);
+
+ if (inPos == 5 &&
+ inBuffer[0] == 'e' &&
+ inBuffer[1] == 'g' &&
+ inBuffer[2] == 'i' &&
+ inBuffer[3] == 'n' &&
+ isspace(inBuffer[4]))
+ {
+ utility::stream::value_type c = 0;
+
+ utility::stream::size_type count = 0;
+ utility::stream::value_type buffer[512];
+
+ while (count < sizeof(buffer) - 1 && in.read(&c, 1) == 1)
+ {
+ if (c == '\n')
+ break;
+
+ buffer[count++] = c;
+ }
+
+ if (c != '\n')
+ {
+ // OOPS! Weird line. Don't try to decode more...
+ return (total);
+ }
+
+ // Parse filename and mode
+ if (count > 0)
+ {
+ buffer[count] = '\0';
+
+ utility::stream::value_type* p = buffer;
+
+ while (*p && isspace(*p)) ++p;
+
+ utility::stream::value_type* modeStart = buffer;
+
+ while (*p && !isspace(*p)) ++p;
+
+ results()["mode"] = string(modeStart, p);
+
+ while (*p && isspace(*p)) ++p;
+
+ utility::stream::value_type* filenameStart = buffer;
+
+ while (*p && !(*p == '\r' || *p == '\n')) ++p;
+
+ results()["filename"] = string(filenameStart, p);
+ }
+ // No filename or mode specified
+ else
+ {
+ results()["filename"] = "untitled";
+ results()["mode"] = 644;
+ }
+
+ continue;
+ }
+
+ break;
+ }
+ case 'e':
+ {
+ // Read 3 characters more to check for end ("end\r\n" or "end\n")
+ inPos = in.read(inBuffer, 3);
+
+ if (inPos == 3 &&
+ inBuffer[0] == 'n' &&
+ inBuffer[1] == 'd' &&
+ (inBuffer[2] == '\r' || inBuffer[2] == '\n'))
+ {
+ stop = true;
+ continue;
+ }
+
+ break;
+ }
+
+ }
+
+ // Read encoded data
+ if (in.read(inBuffer + inPos, inLength - inPos) != inLength - inPos)
+ {
+ // Premature end of data
+ break;
+ }
+
+ // Decode data
+ for (utility::stream::size_type i = 0, j = 0 ; i < inLength ; i += 4, j += 3)
+ {
+ const unsigned char c1 = (unsigned char) inBuffer[i];
+ const unsigned char c2 = (unsigned char) inBuffer[i + 1];
+ const unsigned char c3 = (unsigned char) inBuffer[i + 2];
+ const unsigned char c4 = (unsigned char) inBuffer[i + 3];
+
+ const utility::stream::size_type n =
+ std::min(inLength - i, static_cast <utility::stream::size_type>(3));
+
+ switch (n)
+ {
+ default:
+ case 3: outBuffer[j + 2] = UUDECODE(c3) << 6 | UUDECODE(c4);
+ case 2: outBuffer[j + 1] = UUDECODE(c2) << 4 | UUDECODE(c3) >> 2;
+ case 1: outBuffer[j] = UUDECODE(c1) << 2 | UUDECODE(c2) >> 4;
+ case 0: break;
+ }
+
+ total += n;
+ }
+
+ out.write(outBuffer, outLength);
+
+ std::fill(inBuffer, inBuffer + sizeof(inBuffer), 0);
+ }
+
+ return (total);
+}
+
+
+} // vmime
diff --git a/src/encoderUUE.hpp b/src/encoderUUE.hpp
new file mode 100644
index 00000000..c7784474
--- /dev/null
+++ b/src/encoderUUE.hpp
@@ -0,0 +1,50 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_ENCODERUUE_HPP_INCLUDED
+#define VMIME_ENCODERUUE_HPP_INCLUDED
+
+
+#include "encoder.hpp"
+
+
+namespace vmime
+{
+
+
+/** UUEncode encoder.
+ */
+
+class encoderUUE : public encoder
+{
+public:
+
+ encoderUUE();
+
+ const utility::stream::size_type encode(utility::inputStream& in, utility::outputStream& out);
+ const utility::stream::size_type decode(utility::inputStream& in, utility::outputStream& out);
+
+ const std::vector <string> availableProperties() const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_ENCODERUUE_HPP_INCLUDED
diff --git a/src/encoding.cpp b/src/encoding.cpp
new file mode 100644
index 00000000..c797cf18
--- /dev/null
+++ b/src/encoding.cpp
@@ -0,0 +1,161 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "encoding.hpp"
+#include "encoderFactory.hpp"
+#include "contentHandler.hpp"
+
+#include <algorithm>
+
+
+namespace vmime
+{
+
+
+encoding::encoding()
+ : m_name(encodingTypes::SEVEN_BIT)
+{
+}
+
+
+encoding::encoding(const string& name)
+ : m_name(toLower(name))
+{
+}
+
+
+encoding::encoding(const encoding& enc)
+ : component(), m_name(enc.m_name)
+{
+}
+
+
+void encoding::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ m_name = toLower(string(buffer.begin() + position, buffer.begin() + end));
+
+ if (newPosition)
+ *newPosition = end;
+}
+
+
+void encoding::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ os << m_name;
+
+ if (newLinePos)
+ *newLinePos = curLinePos + m_name.length();
+}
+
+
+encoder* encoding::getEncoder() const
+{
+ return (encoderFactory::getInstance()->create(generate()));
+}
+
+
+encoding& encoding::operator=(const encoding& source)
+{
+ m_name = source.m_name;
+ return (*this);
+}
+
+
+encoding& encoding::operator=(const string& name)
+{
+ m_name = toLower(name);
+ return (*this);
+}
+
+
+const bool encoding::operator==(const encoding& value) const
+{
+ return (toLower(m_name) == value.m_name);
+}
+
+
+const bool encoding::operator!=(const encoding& value) const
+{
+ return !(*this == value);
+}
+
+
+const encoding encoding::decide
+ (const string::const_iterator begin, const string::const_iterator end)
+{
+ const string::difference_type length = end - begin;
+ const string::difference_type count = std::count_if
+ (begin, end, std::bind2nd(std::less<unsigned char>(), 127));
+
+ // All is in 7-bit US-ASCII --> 7-bit (or Quoted-Printable...)
+ if (length == count)
+ {
+ // Now, we check if there is any line with more than
+ // "lineLengthLimits::convenient" characters (7-bit requires that)
+ string::const_iterator p = begin;
+
+ const string::size_type maxLen = lineLengthLimits::convenient;
+ string::size_type len = 0;
+
+ for ( ; p != end && len <= maxLen ; )
+ {
+ if (*p == '\n')
+ {
+ len = 0;
+ ++p;
+
+ // May or may not need to be encoded, we don't take
+ // any risk (avoid problems with SMTP)
+ if (p != end && *p == '.')
+ len = maxLen + 1;
+ }
+ else
+ {
+ ++len;
+ ++p;
+ }
+ }
+
+ if (len > maxLen)
+ return (encoding(encodingTypes::QUOTED_PRINTABLE));
+ else
+ return (encoding(encodingTypes::SEVEN_BIT));
+ }
+ // Less than 20% non US-ASCII --> Quoted-Printable
+ else if ((length - count) <= length / 5)
+ {
+ return (encoding(encodingTypes::QUOTED_PRINTABLE));
+ }
+ // Otherwise --> Base64
+ else
+ {
+ return (encoding(encodingTypes::BASE64));
+ }
+}
+
+
+const encoding encoding::decide(const contentHandler& /* data */)
+{
+ return (encoding(encodingTypes::BASE64));
+}
+
+
+} // vmime
diff --git a/src/encoding.hpp b/src/encoding.hpp
new file mode 100644
index 00000000..ca344fff
--- /dev/null
+++ b/src/encoding.hpp
@@ -0,0 +1,87 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_ENCODING_HPP_INCLUDED
+#define VMIME_ENCODING_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+#include "encoder.hpp"
+
+
+namespace vmime
+{
+
+
+class contentHandler;
+
+
+/** Content encoding (basic type).
+ */
+
+class encoding : public component
+{
+public:
+
+ encoding();
+ encoding(const string& name);
+ encoding(const encoding& enc);
+
+public:
+
+ const string& name() const { return (m_name); }
+ string& name() { return (m_name); }
+
+public:
+
+ encoding& operator=(const encoding& source);
+ encoding& operator=(const string& name);
+
+ const bool operator==(const encoding& value) const;
+ const bool operator!=(const encoding& value) const;
+
+ // Decide which encoding to use based on the data
+ static const encoding decide(const string::const_iterator begin, const string::const_iterator end);
+ static const encoding decide(const contentHandler& data);
+
+public:
+
+ // Obtain an encoder/decoder for the current encoding type
+ encoder* getEncoder() const;
+
+protected:
+
+ string m_name;
+
+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_ENCODING_HPP_INCLUDED
diff --git a/src/exception.hpp b/src/exception.hpp
new file mode 100644
index 00000000..b7880d31
--- /dev/null
+++ b/src/exception.hpp
@@ -0,0 +1,558 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_EXCEPTION_HPP_INCLUDED
+#define VMIME_EXCEPTION_HPP_INCLUDED
+
+
+#include "config.hpp"
+#include "base.hpp"
+#include "utility/path.hpp"
+
+
+namespace vmime
+{
+
+
+class exception
+{
+protected:
+
+ string m_what;
+
+public:
+
+ exception(const string& what) : m_what(what) { }
+ virtual ~exception() { }
+
+ const string what() const throw() { return (m_what); };
+};
+
+
+namespace exceptions
+{
+
+
+class bad_field_type : public vmime::exception
+{
+public:
+
+ bad_field_type() : exception("Bad field type.") {}
+ ~bad_field_type() throw() {}
+};
+
+
+class charset_conv_error : public vmime::exception
+{
+public:
+
+ charset_conv_error() : exception("Charset conversion error.") {}
+ ~charset_conv_error() throw() {}
+};
+
+
+class no_encoder_available : public vmime::exception
+{
+public:
+
+ no_encoder_available() : exception("No encoder available.") {}
+ ~no_encoder_available() throw() {}
+};
+
+
+class no_such_parameter : public vmime::exception
+{
+public:
+
+ no_such_parameter(const string& name) : exception
+ (string("Parameter not found: '") + name + string("'.")) {}
+ ~no_such_parameter() throw() {}
+};
+
+
+class no_such_field : public vmime::exception
+{
+public:
+
+ no_such_field() : exception("Field not found.") {}
+ ~no_such_field() throw() {}
+};
+
+
+class open_file_error : public vmime::exception
+{
+public:
+
+ open_file_error() : exception("Error opening file.") {}
+ ~open_file_error() throw() {}
+};
+
+
+class no_factory_available : public vmime::exception
+{
+public:
+
+ no_factory_available() : exception("No factory available.") {}
+ ~no_factory_available() throw() {}
+};
+
+
+class no_platform_dependant_handler : public vmime::exception
+{
+public:
+
+ no_platform_dependant_handler() : exception("No platform-dependant handler installed.") {}
+ ~no_platform_dependant_handler() throw() {}
+};
+
+
+class no_expeditor : public vmime::exception
+{
+public:
+
+ no_expeditor() : exception("No expeditor specified.") {}
+ ~no_expeditor() throw() {}
+};
+
+
+class no_recipient : public vmime::exception
+{
+public:
+
+ no_recipient() : exception("No recipient specified.") {}
+ ~no_recipient() throw() {}
+};
+
+
+class no_object_found : public vmime::exception
+{
+public:
+
+ no_object_found() : exception("No object found.") {}
+ ~no_object_found() throw() {}
+};
+
+
+// There is no property with that name in the set.
+
+class no_such_property : public vmime::exception
+{
+public:
+
+ no_such_property(const string& name) : exception
+ (std::string("No such property: '") + name + string("'.")) { }
+ ~no_such_property() throw() {}
+};
+
+
+// Bad type specified when reading property.
+
+class invalid_property_type : public vmime::exception
+{
+public:
+
+ invalid_property_type() : exception("Invalid property type.") {}
+ ~invalid_property_type() throw() {}
+};
+
+
+// Bad argument was passed to the function.
+
+class invalid_argument : public vmime::exception
+{
+public:
+
+ invalid_argument() : exception("Invalid argument.") {}
+ ~invalid_argument() throw() {}
+};
+
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+/** Base class for exceptions thrown by the messaging module.
+ */
+
+class messaging_exception : public vmime::exception
+{
+public:
+
+ messaging_exception(const string& what) : exception(what) {}
+ ~messaging_exception() throw() {}
+};
+
+
+/** Error while connecting to the server: this may be a DNS resolution error
+ * or a connection error (for example, time-out while connecting).
+ */
+
+class connection_error : public messaging_exception
+{
+public:
+
+ connection_error() : messaging_exception("Connection error.") {}
+ ~connection_error() throw() {}
+};
+
+
+/** Server did not initiated the connection correctly.
+ */
+
+class connection_greeting_error : public messaging_exception
+{
+public:
+
+ connection_greeting_error(const string& response)
+ : messaging_exception("Greeting error."), m_response(response) {}
+ ~connection_greeting_error() throw() {}
+
+ const string& response() const { return (m_response); }
+
+private:
+
+ string m_response;
+};
+
+
+/** Error while giving credentials to the server (wrong username
+ * or password, or wrong authentication method).
+ */
+
+class authentication_error : public messaging_exception
+{
+public:
+
+ authentication_error(const string& response)
+ : messaging_exception("Authentication error."), m_response(response) {}
+ ~authentication_error() throw() {}
+
+ const string& response() const { return (m_response); }
+
+private:
+
+ string m_response;
+};
+
+
+/** Option not supported.
+ */
+
+class unsupported_option : public messaging_exception
+{
+public:
+
+ unsupported_option() : messaging_exception("Unsupported option.") {}
+ ~unsupported_option() throw() {}
+};
+
+
+/** No service available for this protocol.
+ */
+
+class no_service_available : public messaging_exception
+{
+public:
+
+ no_service_available() : messaging_exception("No service available for this protocol.") {}
+ ~no_service_available() throw() {}
+};
+
+
+/** The current state of the object does not permit to execute the
+ * operation (for example, you try to close a folder which is not open).
+ */
+
+class illegal_state : public messaging_exception
+{
+public:
+
+ illegal_state(const string& state)
+ : messaging_exception("Illegal state to accomplish the operation: '" + state + "'.") {}
+ ~illegal_state() throw() {}
+};
+
+
+/** Folder not found (does not exist).
+ */
+
+class folder_not_found : public messaging_exception
+{
+public:
+
+ folder_not_found() : messaging_exception("Folder not found.") {}
+ ~folder_not_found() throw() {}
+};
+
+
+/** Message not found (does not exist).
+ */
+
+class message_not_found : public messaging_exception
+{
+public:
+
+ message_not_found() : messaging_exception("Message not found.") {}
+ ~message_not_found() throw() {}
+};
+
+
+/** Operation not supported by the underlying protocol.
+ */
+
+class operation_not_supported : public messaging_exception
+{
+public:
+
+ operation_not_supported() : messaging_exception("Operation not supported.") {}
+ ~operation_not_supported() throw() {}
+};
+
+
+/** The operation timed out (time-out delay is elapsed).
+ */
+
+class operation_timed_out : public messaging_exception
+{
+public:
+
+ operation_timed_out() : messaging_exception("Operation timed out.") {}
+ ~operation_timed_out() throw() {}
+};
+
+
+/** The operation has been cancelled.
+ */
+
+class operation_cancelled : public messaging_exception
+{
+public:
+
+ operation_cancelled() : messaging_exception("Operation cancelled by the user.") {}
+ ~operation_cancelled() throw() {}
+};
+
+
+/** Must call fetchMessage() or fetchHeader() before accessing
+ * the requested object.
+ */
+
+class unfetched_object : public messaging_exception
+{
+public:
+
+ unfetched_object() : messaging_exception("Object not fetched.") {}
+ ~unfetched_object() throw() {}
+};
+
+
+/** The service is not currently connected.
+ */
+
+class not_connected : public messaging_exception
+{
+public:
+
+ not_connected() : messaging_exception("Not connected to a service.") {}
+ ~not_connected() throw() {}
+};
+
+
+/** The service is already connected (must disconnect before).
+ */
+
+class already_connected : public messaging_exception
+{
+public:
+
+ already_connected() : messaging_exception("Already connected to a service. Disconnect and retry.") {}
+ ~already_connected() throw() {}
+};
+
+
+/** Command error: operation failed (this is specific to the underlying protocol).
+ */
+
+class command_error : public messaging_exception
+{
+public:
+
+ command_error(const string& command, const string& response, const string& desc = "")
+ : messaging_exception(desc.empty()
+ ? "Error while executing command '" + command + "'."
+ : "Error while executing command '" + command + "': " + desc + "."
+ ),
+ m_command(command), m_response(response) {}
+ ~command_error() throw() {}
+
+ /** Return the name of the command which have thrown the exception.
+ * This is protocol-dependant.
+ *
+ * @return command name (protocol-dependant)
+ */
+ const string& command() const { return (m_command); }
+
+ /** Return the invalid response line.
+ * The meaning is protocol-dependant.
+ *
+ * @return response line (protocol-dependant)
+ */
+ const string& response() const { return (m_response); }
+
+private:
+
+ string m_command;
+ string m_response;
+};
+
+
+/** The server returned an invalid response.
+ */
+
+class invalid_response : public messaging_exception
+{
+public:
+
+ invalid_response(const string& command, const string& response)
+ : messaging_exception(command.empty()
+ ? "Received invalid response."
+ : "Received invalid response for command '" + command + "'."
+ ),
+ m_command(command), m_response(response) {}
+ ~invalid_response() throw() {}
+
+ /** Return the name of the command which have thrown the exception.
+ * This is protocol-dependant.
+ *
+ * @return command name (protocol-dependant)
+ */
+ const string& command() const { return (m_command); }
+
+ /** Return the invalid response line.
+ * The meaning is protocol-dependant.
+ *
+ * @return response line (protocol-dependant)
+ */
+ const string& response() const { return (m_response); }
+
+private:
+
+ string m_command;
+ string m_response;
+};
+
+
+/** Partial fetch is not supported by the underlying protocol.
+ */
+
+class partial_fetch_not_supported : public messaging_exception
+{
+public:
+
+ partial_fetch_not_supported() : messaging_exception("Partial fetch not supported.") {}
+ ~partial_fetch_not_supported() throw() {}
+};
+
+
+/** The URL is malformed.
+ */
+
+class malformed_url : public messaging_exception
+{
+public:
+
+ malformed_url(const string& error) : messaging_exception("Malformed URL: " + error + ".") {}
+ ~malformed_url() throw() {}
+};
+
+
+/** Folder name is invalid.
+ */
+
+class invalid_folder_name : public messaging_exception
+{
+public:
+
+ invalid_folder_name(const string& error) : messaging_exception("Invalid folder name: " + error + ".") {}
+ ~invalid_folder_name() throw() {}
+};
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+/** Base class for exceptions thrown by the filesystem features.
+ */
+
+class filesystem_exception : public vmime::exception
+{
+public:
+
+ filesystem_exception(const string& what, const utility::path& path) : exception(what), m_path(path) {}
+ ~filesystem_exception() throw() {}
+
+ /** Return the full path of the file have thrown the exception.
+ *
+ * @return full path of the file/directory
+ */
+ const utility::path& path() const { return (m_path); }
+
+private:
+
+ const utility::path m_path;
+};
+
+
+/** File is not a directory.
+ */
+
+class not_a_directory : public filesystem_exception
+{
+public:
+
+ not_a_directory(const utility::path& path) : filesystem_exception("Operation failed: this is not a directory.", path) {}
+ ~not_a_directory() throw() {}
+};
+
+
+/** File not found.
+ */
+
+class file_not_found : public filesystem_exception
+{
+public:
+
+ file_not_found(const utility::path& path) : filesystem_exception("File not found.", path) {}
+ ~file_not_found() throw() {}
+};
+
+
+#endif // VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+} // exceptions
+
+
+} // vmime
+
+
+#endif // VMIME_EXCEPTION_HPP_INCLUDED
diff --git a/src/fileAttachment.cpp b/src/fileAttachment.cpp
new file mode 100644
index 00000000..ca7ff789
--- /dev/null
+++ b/src/fileAttachment.cpp
@@ -0,0 +1,123 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 <fstream>
+#include <sstream>
+
+#include "fileAttachment.hpp"
+#include "exception.hpp"
+
+
+namespace vmime
+{
+
+
+fileAttachment::fileAttachment(const string& filename, const mediaType& type, const text& desc)
+{
+ m_type = type;
+ m_desc = desc;
+
+ setData(filename);
+
+ m_encoding = encoding::decide(m_data);
+}
+
+
+fileAttachment::fileAttachment(const string& filename, const mediaType& type,
+ const class encoding& enc, const text& desc)
+{
+ m_type = type;
+ m_desc = desc;
+
+ setData(filename);
+
+ m_encoding = enc;
+}
+
+
+void fileAttachment::setData(const string& filename)
+{
+ std::ifstream* file = new std::ifstream();
+ file->open(filename.c_str(), std::ios::in | std::ios::binary);
+
+ if (!*file)
+ {
+ delete (file);
+ throw exceptions::open_file_error();
+ }
+
+ m_data.set(new utility::inputStreamPointerAdapter(file, true), 0, true);
+}
+
+
+void fileAttachment::generatePart(bodyPart& part) const
+{
+ defaultAttachment::generatePart(part);
+
+ contentDispositionField& cdf = part.header().fields.ContentDisposition();
+
+ if (m_fileInfo.hasSize()) cdf.size() = toString(m_fileInfo.getSize());
+ if (m_fileInfo.hasFilename()) cdf.filename() = m_fileInfo.getFilename();
+ if (m_fileInfo.hasCreationDate()) cdf.creationDate() = m_fileInfo.getCreationDate();
+ if (m_fileInfo.hasModificationDate()) cdf.modificationDate() = m_fileInfo.getModificationDate();
+ if (m_fileInfo.hasReadDate()) cdf.readDate() = m_fileInfo.getReadDate();
+}
+
+
+//
+// fileAttachment::fileInfo
+//
+
+fileAttachment::fileInfo::fileInfo()
+ : m_filename(NULL), m_size(NULL), m_creationDate(NULL), m_modifDate(NULL), m_readDate(NULL)
+{
+}
+
+
+fileAttachment::fileInfo::~fileInfo()
+{
+ delete (m_filename);
+ delete (m_size);
+ delete (m_creationDate);
+ delete (m_modifDate);
+ delete (m_readDate);
+}
+
+const bool fileAttachment::fileInfo::hasFilename() const { return (m_filename != NULL); }
+const string& fileAttachment::fileInfo::getFilename() const { return (*m_filename); }
+void fileAttachment::fileInfo::setFilename(const string& name) { if (m_filename) { *m_filename = name; } else { m_filename = new string(name); } }
+
+const bool fileAttachment::fileInfo::hasCreationDate() const { return (m_creationDate != NULL); }
+const datetime& fileAttachment::fileInfo::getCreationDate() const { return (*m_creationDate); }
+void fileAttachment::fileInfo::setCreationDate(const datetime& date) { if (m_creationDate) { *m_creationDate = date; } else { m_creationDate = new datetime(date); } }
+
+const bool fileAttachment::fileInfo::hasModificationDate() const { return (m_modifDate != NULL); }
+const datetime& fileAttachment::fileInfo::getModificationDate() const { return (*m_modifDate); }
+void fileAttachment::fileInfo::setModificationDate(const datetime& date) { if (m_modifDate) { *m_modifDate = date; } else { m_modifDate = new datetime(date); } }
+
+const bool fileAttachment::fileInfo::hasReadDate() const { return (m_readDate != NULL); }
+const datetime& fileAttachment::fileInfo::getReadDate() const { return (*m_readDate); }
+void fileAttachment::fileInfo::setReadDate(const datetime& date) { if (m_readDate) { *m_readDate = date; } else { m_readDate = new datetime(date); } }
+
+const bool fileAttachment::fileInfo::hasSize() const { return (m_size != NULL); }
+const unsigned int fileAttachment::fileInfo::getSize() const { return (*m_size); }
+void fileAttachment::fileInfo::setSize(const unsigned int& size) { if (m_size) { *m_size = size; } else { m_size = new unsigned int(size); } }
+
+
+} // vmime
diff --git a/src/fileAttachment.hpp b/src/fileAttachment.hpp
new file mode 100644
index 00000000..66cb258d
--- /dev/null
+++ b/src/fileAttachment.hpp
@@ -0,0 +1,90 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_FILEATTACHMENT_HPP_INCLUDED
+#define VMIME_FILEATTACHMENT_HPP_INCLUDED
+
+
+#include "defaultAttachment.hpp"
+
+
+namespace vmime
+{
+
+
+class fileAttachment : public defaultAttachment
+{
+public:
+
+ fileAttachment(const string& filename, const mediaType& type, const text& desc = NULL_TEXT);
+ fileAttachment(const string& filename, const mediaType& type, const class encoding& enc, const text& desc = NULL_TEXT);
+
+ class fileInfo
+ {
+ public:
+
+ fileInfo();
+ ~fileInfo();
+
+ const bool hasFilename() const;
+ const string& getFilename() const;
+ void setFilename(const string& name);
+
+ const bool hasCreationDate() const;
+ const datetime& getCreationDate() const;
+ void setCreationDate(const datetime& date);
+
+ const bool hasModificationDate() const;
+ const datetime& getModificationDate() const;
+ void setModificationDate(const datetime& date);
+
+ const bool hasReadDate() const;
+ const datetime& getReadDate() const;
+ void setReadDate(const datetime& date);
+
+ const bool hasSize() const;
+ const unsigned int getSize() const;
+ void setSize(const unsigned int& size);
+
+ protected:
+
+ string* m_filename;
+ unsigned int* m_size;
+ datetime* m_creationDate;
+ datetime* m_modifDate;
+ datetime* m_readDate;
+ };
+
+ const class fileInfo& fileInfo() const { return (m_fileInfo); }
+ class fileInfo& fileInfo() { return (m_fileInfo); }
+
+protected:
+
+ void setData(const string& filename);
+
+ class fileInfo m_fileInfo;
+
+ void generatePart(bodyPart& part) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_FILEATTACHMENT_HPP_INCLUDED
diff --git a/src/header.cpp b/src/header.cpp
new file mode 100644
index 00000000..f7745360
--- /dev/null
+++ b/src/header.cpp
@@ -0,0 +1,452 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "header.hpp"
+#include "parserHelpers.hpp"
+
+
+namespace vmime
+{
+
+
+header::header()
+{
+}
+
+
+header::~header()
+{
+}
+
+
+/*
+
+ RFC #822:
+ 3.2. HEADER FIELD DEFINITIONS
+
+field = field-name ":" [ field-body ] CRLF
+
+field-name = 1*<any CHAR, excluding CTLs, SPACE, and ":">
+
+field-body = field-body-contents
+ [CRLF LWSP-char field-body]
+
+field-body-contents =
+ <the ASCII characters making up the field-body, as
+ defined in the following sections, and consisting
+ of combinations of atom, quoted-string, and
+ specials tokens, or else consisting of texts>
+*/
+
+void header::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ string::size_type pos = position;
+
+ fields.clear();
+
+ while (pos < end)
+ {
+ char_t c = buffer[pos];
+
+ // Check for end of headers (empty line): although RFC-822 recommends
+ // to use CRLF for header/body separator (see 4.1 SYNTAX), here, we
+ // also check for LF just in case...
+ if (c == '\n')
+ {
+ ++pos;
+ break;
+ }
+ else if (c == '\r' && pos + 1 < end && buffer[pos + 1] == '\n')
+ {
+ pos += 2;
+ break;
+ }
+
+ // This line may be a field description
+ if (!isspace(c))
+ {
+ const string::size_type nameStart = pos; // remember the start position of the line
+
+ while (pos < end && (buffer[pos] != ':' && !isspace(buffer[pos])))
+ ++pos;
+
+ const string::size_type nameEnd = pos;
+
+ while (pos < end && isspace(buffer[pos]))
+ ++pos;
+
+ if (buffer[pos] != ':')
+ {
+ // Humm...does not seem to be a valid header line.
+ // Skip this error and advance to the next line
+ pos = nameStart;
+
+ while (pos < end && buffer[pos] != '\n')
+ ++pos;
+
+ if (buffer[pos] == '\n')
+ ++pos;
+ }
+ else
+ {
+ // Extract the field name
+ const string name(buffer.begin() + nameStart,
+ buffer.begin() + nameEnd);
+
+ // Skip ':' character
+ ++pos;
+
+ // Skip spaces between ':' and the field contents
+ while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t'))
+ ++pos;
+
+ // Extract the field value
+ string contents;
+
+ while (pos < end)
+ {
+ c = buffer[pos];
+
+ // Check for end of contents
+ if (c == '\r' && pos + 1 < end && buffer[pos + 1] == '\n')
+ {
+ pos += 2;
+ break;
+ }
+ else if (c == '\n')
+ {
+ ++pos;
+ break;
+ }
+
+ const string::size_type ctsStart = pos;
+ string::size_type ctsEnd = pos;
+
+ while (pos < end)
+ {
+ c = buffer[pos];
+
+ // Check for end of line
+ if (c == '\r' && pos + 1 < end && buffer[pos + 1] == '\n')
+ {
+ ctsEnd = pos;
+ pos += 2;
+ break;
+ }
+ else if (c == '\n')
+ {
+ ctsEnd = pos;
+ ++pos;
+ break;
+ }
+
+ ++pos;
+ }
+
+ if (ctsEnd != ctsStart)
+ {
+ // Append this line to contents
+ contents.append(buffer.begin() + ctsStart,
+ buffer.begin() + ctsEnd);
+ }
+
+ // Handle the case of folded lines
+ if (buffer[pos] == ' ' || buffer[pos] == '\t')
+ {
+ // This is a folding white-space: we keep it as is and
+ // we continue with contents parsing...
+ }
+ else
+ {
+ // End of this field
+ break;
+ }
+ }
+
+ // Add a new field to list
+ fields.m_fields.push_back(headerFieldFactory::getInstance()->
+ create(headerField::nameToType(name), name, contents));
+ }
+ }
+ else
+ {
+ // Skip this error and advance to the next line
+ while (pos < end && buffer[pos] != '\n')
+ ++pos;
+
+ if (buffer[pos] == '\n')
+ ++pos;
+ }
+ }
+
+ // If we have found the header/body separator, skip it
+ if (pos < end)
+ {
+ if (buffer[pos] == '\n')
+ {
+ // This is a LF (illegal but...)
+ ++pos;
+ }
+ else if (buffer[pos] == '\r' && pos + 1 < end)
+ {
+ // This is a CRLF
+ pos += 2;
+ }
+ }
+
+ if (newPosition)
+ *newPosition = pos;
+}
+
+
+void header::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type /* curLinePos */, string::size_type* newLinePos) const
+{
+ // Generate the fields
+ for (std::vector <headerField*>::const_iterator
+ it = fields.m_fields.begin() ; it != fields.m_fields.end() ; ++it)
+ {
+ (*it)->generate(os, maxLineLength);
+ os << CRLF;
+ }
+
+ if (newLinePos)
+ *newLinePos = 0;
+}
+
+
+header& header::operator=(const header& h)
+{
+ fields = h.fields;
+
+ return (*this);
+}
+
+
+
+//////////////////////
+// Fields container //
+//////////////////////
+
+
+header::fieldsContainer::fieldsContainer()
+{
+}
+
+
+header::fieldsContainer::~fieldsContainer()
+{
+ for (std::vector <headerField*>::iterator i = m_fields.begin() ; i != m_fields.end() ; ++i)
+ delete (*i);
+}
+
+
+// Checks whether (at least) one field with this type/name exists
+const bool header::fieldsContainer::has(const headerField::Types fieldType) const
+{
+ std::vector <headerField*>::const_iterator pos = m_fields.begin();
+ const std::vector <headerField*>::const_iterator end = m_fields.end();
+
+ for ( ; pos != end && (*pos)->type() != fieldType ; ++pos);
+
+ return (pos != end);
+}
+
+
+const bool header::fieldsContainer::has(const string& fieldName) const
+{
+ headerField::Types type = headerField::nameToType(fieldName);
+ if (type != headerField::Custom) return (has(type));
+
+ const string name = toLower(fieldName);
+
+ std::vector <headerField*>::const_iterator pos = m_fields.begin();
+ const std::vector <headerField*>::const_iterator end = m_fields.end();
+
+ for ( ; pos != end && toLower((*pos)->name()) != name ; ++pos);
+
+ return (pos != end);
+}
+
+
+// Find the first field that matches the specified type/name.
+// If no field is found, an exception is thrown.
+headerField& header::fieldsContainer::find(const headerField::Types fieldType) const
+{
+ // Find the first field that matches the specified type
+ std::vector <headerField*>::const_iterator pos = m_fields.begin();
+ const std::vector <headerField*>::const_iterator end = m_fields.end();
+
+ for ( ; pos != end && (*pos)->type() != fieldType ; ++pos);
+
+ // No field with this type can be found
+ if (pos == end)
+ {
+ throw exceptions::no_such_field();
+ }
+ // Else, return a reference to the existing field
+ else
+ {
+ return (**pos);
+ }
+}
+
+
+headerField& header::fieldsContainer::find(const string& fieldName) const
+{
+ headerField::Types type = headerField::nameToType(fieldName);
+ if (type != headerField::Custom) return (find(type));
+
+ const string name = toLower(fieldName);
+
+ // Find the first field that matches the specified name
+ std::vector <headerField*>::const_iterator pos = m_fields.begin();
+ const std::vector <headerField*>::const_iterator end = m_fields.end();
+
+ for ( ; pos != end && toLower((*pos)->name()) != name ; ++pos);
+
+ // No field with this name can be found
+ if (pos == end)
+ {
+ throw exceptions::no_such_field();
+ }
+ // Else, return a reference to the existing field
+ else
+ {
+ return (**pos);
+ }
+}
+
+
+// Find the first field that matches the specified type/name
+headerField& header::fieldsContainer::get(const headerField::Types fieldType)
+{
+ // Find the first field that matches the specified type
+ std::vector <headerField*>::const_iterator pos = m_fields.begin();
+ const std::vector <headerField*>::const_iterator end = m_fields.end();
+
+ for ( ; pos != end && (*pos)->type() != fieldType ; ++pos);
+
+ // If no field with this type can be found, create a new one
+ if (pos == end)
+ {
+ headerField* field = headerFieldFactory::getInstance()->create(fieldType);
+ insertSorted(field);
+
+ // Return a reference to the new field
+ return (*field);
+ }
+ // Else, return a reference to the existing field
+ else
+ {
+ return (**pos);
+ }
+}
+
+
+headerField& header::fieldsContainer::get(const string& fieldName)
+{
+ headerField::Types type = headerField::nameToType(fieldName);
+ if (type != headerField::Custom) return (get(type));
+
+ const string name = toLower(fieldName);
+
+ // Find the first field that matches the specified name
+ std::vector <headerField*>::const_iterator pos = m_fields.begin();
+ const std::vector <headerField*>::const_iterator end = m_fields.end();
+
+ for ( ; pos != end && toLower((*pos)->name()) != name ; ++pos);
+
+ // If no field with this name can be found, create a new one
+ if (pos == end)
+ {
+ headerField* field = headerFieldFactory::getInstance()->create(fieldName);
+ insertSorted(field);
+
+ // Return a reference to the new field
+ return (*field);
+ }
+ // Else, return a reference to the existing field
+ else
+ {
+ return (**pos);
+ }
+}
+
+
+void header::fieldsContainer::insertSorted(headerField* field)
+{
+ const headerField::Types type = field->type();
+ std::vector <headerField*>::iterator i;
+
+ for (i = m_fields.begin() ; (i != m_fields.end()) && ((*i)->type() < type) ; ++i);
+
+ m_fields.insert(i, field);
+}
+
+
+// Field insertion
+void header::fieldsContainer::append(const headerField& field)
+{
+ m_fields.push_back(field.clone());
+}
+
+
+void header::fieldsContainer::insert(const iterator it, const headerField& field)
+{
+ m_fields.insert(it.m_iterator, field.clone());
+}
+
+
+// Field removing
+void header::fieldsContainer::remove(const iterator it)
+{
+ delete (*it.m_iterator);
+ m_fields.erase(it.m_iterator);
+}
+
+
+void header::fieldsContainer::clear()
+{
+ for (std::vector <headerField*>::iterator it = m_fields.begin() ; it != m_fields.end() ; ++it)
+ delete (*it);
+
+ m_fields.clear();
+}
+
+
+header::fieldsContainer& header::fieldsContainer::operator=(const fieldsContainer& c)
+{
+ std::vector <headerField*> fields;
+
+ for (std::vector <headerField*>::const_iterator it = c.m_fields.begin() ; it != c.m_fields.end() ; ++it)
+ fields.push_back((*it)->clone());
+
+ for (std::vector <headerField*>::iterator it = m_fields.begin() ; it != m_fields.end() ; ++it)
+ delete (*it);
+
+ m_fields.resize(fields.size());
+ std::copy(fields.begin(), fields.end(), m_fields.begin());
+
+ return (*this);
+}
+
+
+} // vmime
diff --git a/src/header.hpp b/src/header.hpp
new file mode 100644
index 00000000..8ce070b9
--- /dev/null
+++ b/src/header.hpp
@@ -0,0 +1,266 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_HEADER_HPP_INCLUDED
+#define VMIME_HEADER_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+#include "exception.hpp"
+
+#include "headerField.hpp"
+#include "headerFieldFactory.hpp"
+
+#include "addressListField.hpp"
+#include "mailboxListField.hpp"
+#include "mailboxField.hpp"
+#include "textField.hpp"
+#include "dateField.hpp"
+#include "contentTypeField.hpp"
+#include "contentEncodingField.hpp"
+#include "defaultField.hpp"
+#include "contentDispositionField.hpp"
+#include "messageIdField.hpp"
+
+
+namespace vmime
+{
+
+
+class bodyPart;
+
+
+/** Header section of a MIME part.
+ */
+
+class header : public component
+{
+ friend class bodyPart;
+ friend class body;
+ friend class message;
+
+protected:
+
+ header();
+ ~header();
+
+public:
+
+ // A sub-class for field manipulation
+ class fieldsContainer
+ {
+ friend class header;
+
+ protected:
+
+ fieldsContainer();
+ ~fieldsContainer();
+
+ public:
+
+ // Field access
+ mailboxField& From() { return (dynamic_cast<mailboxField&>(get(headerField::From))); }
+ mailboxField& Sender() { return (dynamic_cast<mailboxField&>(get(headerField::Sender))); }
+ mailboxField& ReplyTo() { return (dynamic_cast<mailboxField&>(get(headerField::ReplyTo))); }
+ mailboxField& DeliveredTo() { return (dynamic_cast<mailboxField&>(get(headerField::DeliveredTo))); }
+ addressListField& To() { return (dynamic_cast<addressListField&>(get(headerField::To))); }
+ addressListField& Cc() { return (dynamic_cast<addressListField&>(get(headerField::Cc))); }
+ addressListField& Bcc() { return (dynamic_cast<addressListField&>(get(headerField::Bcc))); }
+ dateField& Date() { return (dynamic_cast<dateField&>(get(headerField::Date))); }
+ textField& Subject() { return (dynamic_cast<textField&>(get(headerField::Subject))); }
+ textField& Organization() { return (dynamic_cast<textField&>(get(headerField::Organization))); }
+ textField& UserAgent() { return (dynamic_cast<textField&>(get(headerField::UserAgent))); }
+ contentTypeField& ContentType() { return (dynamic_cast<contentTypeField&>(get(headerField::ContentType))); }
+ textField& ContentDescription() { return (dynamic_cast<textField&>(get(headerField::ContentDescription))); }
+ contentEncodingField& ContentTransferEncoding() { return (dynamic_cast<contentEncodingField&>(get(headerField::ContentTransferEncoding))); }
+ defaultField& MimeVersion() { return (dynamic_cast<defaultField&>(get(headerField::MimeVersion))); }
+ contentDispositionField& ContentDisposition() { return (dynamic_cast<contentDispositionField&>(get(headerField::ContentDisposition))); }
+ messageIdField& ContentId() { return (dynamic_cast<messageIdField&>(get(headerField::ContentId))); }
+ messageIdField& MessageId() { return (dynamic_cast<messageIdField&>(get(headerField::MessageId))); }
+ defaultField& ContentLocation() { return (dynamic_cast<defaultField&>(get(headerField::ContentLocation))); }
+
+ const mailboxField& From() const { return (dynamic_cast<mailboxField&>(find(headerField::From))); }
+ const mailboxField& Sender() const { return (dynamic_cast<mailboxField&>(find(headerField::Sender))); }
+ const mailboxField& ReplyTo() const { return (dynamic_cast<mailboxField&>(find(headerField::ReplyTo))); }
+ const mailboxField& DeliveredTo() const { return (dynamic_cast<mailboxField&>(find(headerField::DeliveredTo))); }
+ const addressListField& To() const { return (dynamic_cast<addressListField&>(find(headerField::To))); }
+ const addressListField& Cc() const { return (dynamic_cast<addressListField&>(find(headerField::Cc))); }
+ const addressListField& Bcc() const { return (dynamic_cast<addressListField&>(find(headerField::Bcc))); }
+ const dateField& Date() const { return (dynamic_cast<dateField&>(find(headerField::Date))); }
+ const textField& Subject() const { return (dynamic_cast<textField&>(find(headerField::Subject))); }
+ const textField& Organization() const { return (dynamic_cast<textField&>(find(headerField::Organization))); }
+ const textField& UserAgent() const { return (dynamic_cast<textField&>(find(headerField::UserAgent))); }
+ const contentTypeField& ContentType() const { return (dynamic_cast<contentTypeField&>(find(headerField::ContentType))); }
+ const textField& ContentDescription() const { return (dynamic_cast<textField&>(find(headerField::ContentDescription))); }
+ const contentEncodingField& ContentTransferEncoding() const { return (dynamic_cast<contentEncodingField&>(find(headerField::ContentTransferEncoding))); }
+ const defaultField& MimeVersion() const { return (dynamic_cast<defaultField&>(find(headerField::MimeVersion))); }
+ const contentDispositionField& ContentDisposition() const { return (dynamic_cast<contentDispositionField&>(find(headerField::ContentDisposition))); }
+ const messageIdField& ContentId() const { return (dynamic_cast<messageIdField&>(find(headerField::ContentId))); }
+ const messageIdField& MessageId() const { return (dynamic_cast<messageIdField&>(find(headerField::MessageId))); }
+ const defaultField& ContentLocation() const { return (dynamic_cast<defaultField&>(find(headerField::ContentLocation))); }
+
+ // Checks whether (at least) one field with this type/name exists
+ const bool has(const headerField::Types fieldType) const;
+ const bool has(const string& fieldName) const;
+
+ // Find the first field that matches the specified type/name.
+ // If no field is found, an exception is thrown.
+ headerField& find(const headerField::Types fieldType) const;
+ headerField& find(const string& fieldName) const;
+
+ // Find the first field that matches the specified type/name.
+ // If no field is found, one will be created.
+ headerField& get(const headerField::Types fieldType);
+ headerField& get(const string& fieldName);
+
+ // Field iterator
+ class const_iterator;
+
+ class iterator
+ {
+ friend class header::fieldsContainer::const_iterator;
+ friend class header::fieldsContainer;
+
+ public:
+
+ typedef std::vector <headerField*>::iterator::difference_type difference_type;
+
+ iterator(std::vector <headerField*>::iterator it) : m_iterator(it) { }
+ iterator(const iterator& it) : m_iterator(it.m_iterator) { }
+
+ iterator& operator=(const iterator& it) { m_iterator = it.m_iterator; return (*this); }
+
+ headerField& operator*() const { return (**m_iterator); }
+ headerField* operator->() const { return (*m_iterator); }
+
+ iterator& operator++() { ++m_iterator; return (*this); }
+ iterator operator++(int) { iterator i(*this); ++m_iterator; return (i); }
+
+ iterator& operator--() { --m_iterator; return (*this); }
+ iterator operator--(int) { iterator i(*this); --m_iterator; return (i); }
+
+ iterator& operator+=(difference_type n) { m_iterator += n; return (*this); }
+ iterator& operator-=(difference_type n) { m_iterator -= n; return (*this); }
+
+ iterator operator-(difference_type x) const { return iterator(m_iterator - x); }
+
+ headerField& operator[](difference_type n) const { return *(m_iterator[n]); }
+
+ const bool operator==(const iterator& it) const { return (it.m_iterator == m_iterator); }
+ const bool operator!=(const iterator& it) const { return (!(*this == it)); }
+
+ protected:
+
+ std::vector <headerField*>::iterator m_iterator;
+ };
+
+ class const_iterator
+ {
+ public:
+
+ typedef std::vector <headerField*>::const_iterator::difference_type difference_type;
+
+ const_iterator(std::vector <headerField*>::const_iterator it) : m_iterator(it) { }
+ const_iterator(const iterator& it) : m_iterator(it.m_iterator) { }
+ const_iterator(const const_iterator& it) : m_iterator(it.m_iterator) { }
+
+ const_iterator& operator=(const const_iterator& it) { m_iterator = it.m_iterator; return (*this); }
+ const_iterator& operator=(const iterator& it) { m_iterator = it.m_iterator; return (*this); }
+
+ const headerField& operator*() const { return (**m_iterator); }
+ const headerField* operator->() const { return (*m_iterator); }
+
+ const_iterator& operator++() { ++m_iterator; return (*this); }
+ const_iterator operator++(int) { const_iterator i(*this); ++m_iterator; return (i); }
+
+ const_iterator& operator--() { --m_iterator; return (*this); }
+ const_iterator operator--(int) { const_iterator i(*this); --m_iterator; return (i); }
+
+ const_iterator& operator+=(difference_type n) { m_iterator += n; return (*this); }
+ const_iterator& operator-=(difference_type n) { m_iterator -= n; return (*this); }
+
+ const_iterator operator-(difference_type x) const { return const_iterator(m_iterator - x); }
+
+ const headerField& operator[](difference_type n) const { return *(m_iterator[n]); }
+
+ const bool operator==(const const_iterator& it) const { return (it.m_iterator == m_iterator); }
+ const bool operator!=(const const_iterator& it) const { return (!(*this == it)); }
+
+ protected:
+
+ std::vector <headerField*>::const_iterator m_iterator;
+ };
+
+ public:
+
+ iterator begin() { return (m_fields.begin()); }
+ iterator end() { return (m_fields.end()); }
+
+ const_iterator begin() const { return (const_iterator(m_fields.begin())); }
+ const_iterator end() const { return (const_iterator(m_fields.end())); }
+
+ // Field insertion
+ void append(const headerField& field);
+ void insert(const iterator it, const headerField& field);
+
+ // Field removing
+ void remove(const iterator it);
+ void clear();
+
+ // Field count
+ const std::vector <headerField*>::size_type count() const { return (m_fields.size()); }
+ const std::vector <headerField*>::size_type size() const { return (m_fields.size()); }
+ const bool empty() const { return (m_fields.empty()); }
+
+ headerField& front() { return (*m_fields.front()); }
+ const headerField& front() const { return (*m_fields.front()); }
+ headerField& back() { return (*m_fields.back()); }
+ const headerField& back() const { return (*m_fields.back()); }
+
+ fieldsContainer& operator=(const fieldsContainer& c);
+
+ protected:
+
+ void insertSorted(headerField* field);
+
+ std::vector <headerField*> m_fields;
+
+ } fields;
+
+ typedef fieldsContainer::iterator iterator;
+ typedef fieldsContainer::const_iterator const_iterator;
+
+ header& operator=(const header& h);
+
+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_HEADER_HPP_INCLUDED
diff --git a/src/headerField.cpp b/src/headerField.cpp
new file mode 100644
index 00000000..20f90251
--- /dev/null
+++ b/src/headerField.cpp
@@ -0,0 +1,266 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "headerField.hpp"
+#include "headerFieldFactory.hpp"
+
+
+namespace vmime
+{
+
+
+headerField::headerField()
+ : m_type(Custom), m_name("Undefined")
+{
+}
+
+
+headerField::headerField(const string& fieldName)
+ : m_type(Custom), m_name(fieldName)
+{
+}
+
+
+headerField::~headerField()
+{
+}
+
+
+headerField* headerField::clone() const
+{
+ headerField* field = NULL;
+
+ if (m_type == Custom)
+ field = headerFieldFactory::getInstance()->create(m_name);
+ else
+ field = headerFieldFactory::getInstance()->create(m_type);
+
+ field->copyFrom(*this);
+
+ return (field);
+}
+
+
+const bool headerField::operator<(const headerField& field) const
+{
+ return (m_type < field.m_type);
+}
+
+
+headerField& headerField::operator=(const headerField& field)
+{
+ copyFrom(field);
+ return (*this);
+}
+
+
+void headerField::copyFrom(const headerField& field)
+{
+ m_type = field.m_type;
+ m_name = field.m_name;
+}
+
+
+void headerField::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ if (m_type == Custom)
+ {
+ os << m_name + ": ";
+
+ if (newLinePos)
+ *newLinePos = curLinePos + m_name.length() + 2;
+ }
+ else
+ {
+ const string name = typeToName(m_type);
+
+ os << name + ": ";
+
+ if (newLinePos)
+ *newLinePos = curLinePos + name.length() + 2;
+ }
+}
+
+
+/** Return the field type corresponding to the specified name.
+ *
+ * @param name field name
+ * @return field type (see headerField::Types) or headerField::custom
+ * if this is a custom field
+ */
+
+const headerField::Types headerField::nameToType(const string& name)
+{
+ switch (name[0])
+ {
+ case 'B':
+ case 'b':
+ {
+ if (isStringEqualNoCase(name, "bcc", 3)) return (Bcc);
+ break;
+ }
+ case 'C':
+ case 'c':
+ {
+ if (isStringEqualNoCase(name, "cc", 2)) return (Cc);
+ else if (isStringEqualNoCase(name, "content-type", 12)) return (ContentType);
+ else if (isStringEqualNoCase(name, "content-transfer-encoding", 25)) return (ContentTransferEncoding);
+ else if (isStringEqualNoCase(name, "content-description", 19)) return (ContentDescription);
+ else if (isStringEqualNoCase(name, "content-disposition", 19)) return (ContentDisposition);
+ else if (isStringEqualNoCase(name, "content-id", 10)) return (ContentId);
+ else if (isStringEqualNoCase(name, "content-location", 16)) return (ContentLocation);
+ break;
+ }
+ case 'd':
+ case 'D':
+ {
+ if (isStringEqualNoCase(name, "date", 4)) return (Date);
+ else if (isStringEqualNoCase(name, "delivered-to", 12)) return (DeliveredTo);
+ break;
+ }
+ case 'f':
+ case 'F':
+ {
+ if (isStringEqualNoCase(name, "from", 4)) return (From);
+ break;
+ }
+ case 'm':
+ case 'M':
+ {
+ if (isStringEqualNoCase(name, "mime-version", 12)) return (MimeVersion);
+ else if (isStringEqualNoCase(name, "message-id", 10)) return (MessageId);
+ break;
+ }
+ case 'o':
+ case 'O':
+ {
+ if (isStringEqualNoCase(name, "organization", 12)) return (Organization);
+ break;
+ }
+ case 'r':
+ case 'R':
+ {
+ if (isStringEqualNoCase(name, "received", 8)) return (Received);
+ else if (isStringEqualNoCase(name, "reply-to", 8)) return (ReplyTo);
+ else if (isStringEqualNoCase(name, "return-path", 11)) return (ReturnPath);
+ break;
+ }
+ case 's':
+ case 'S':
+ {
+ if (isStringEqualNoCase(name, "sender", 6)) return (Sender);
+ else if (isStringEqualNoCase(name, "subject", 7)) return (Subject);
+ break;
+ }
+ case 't':
+ case 'T':
+ {
+ if (isStringEqualNoCase(name, "to", 2)) return (To);
+ break;
+ }
+ case 'u':
+ case 'U':
+ {
+ if (isStringEqualNoCase(name, "user-agent", 10)) return (UserAgent);
+ break;
+ }
+
+ }
+
+ return (Custom);
+}
+
+
+/** Return the name for the specified field type.
+ * Eg: returns "From" for headerField::From.
+ *
+ * @param type field type
+ * @return name for the specified field type
+ */
+
+const string headerField::typeToName(const Types type)
+{
+ switch (type)
+ {
+ case From: return "From";
+ case Sender: return "Sender";
+ case To: return "To";
+ case Cc: return "Cc";
+ case Bcc: return "Bcc";
+ case Date: return "Date";
+ case Received: return "Received";
+ case Subject: return "Subject";
+ case ReplyTo: return "Reply-To";
+ case Organization: return "Organization";
+ case DeliveredTo: return "Delivered-To";
+ case UserAgent: return "User-Agent";
+ case ReturnPath: return "Return-Path";
+ case ContentType: return "Content-Type";
+ case ContentTransferEncoding: return "Content-Transfer-Encoding";
+ case ContentDescription: return "Content-Description";
+ case MimeVersion: return "Mime-Version";
+ case ContentDisposition: return "Content-Disposition";
+ case ContentId: return "Content-Id";
+ case MessageId: return "Message-Id";
+ case ContentLocation: return "Content-Location";
+
+ case Custom:
+ case Last:
+ return "?";
+ };
+
+ return "?";
+}
+
+
+/** Return the type of this field.
+ *
+ * @return field type (see headerField::Types)
+ */
+
+const headerField::Types headerField::type() const
+{
+ return (m_type);
+}
+
+
+/** Return the name of this field.
+ *
+ * @return field name
+ */
+
+const string headerField::name() const
+{
+ return ((m_type == Custom) ? m_name : typeToName(m_type));
+}
+
+
+/** Check whether this field is a custom field.
+ *
+ * @return true if the field is a custom field, false otherwise
+ */
+
+const bool headerField::isCustom() const
+{
+ return (m_type == Custom);
+}
+
+
+} // vmime
diff --git a/src/headerField.hpp b/src/headerField.hpp
new file mode 100644
index 00000000..70a74eff
--- /dev/null
+++ b/src/headerField.hpp
@@ -0,0 +1,113 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_HEADERFIELD_HPP_INCLUDED
+#define VMIME_HEADERFIELD_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+
+
+namespace vmime
+{
+
+
+/** Base class for header fields.
+ */
+
+class headerField : public component
+{
+ friend class headerFieldFactory;
+
+protected:
+
+ headerField();
+ headerField(const string& fieldName);
+
+public:
+
+ ~headerField();
+
+public:
+
+ // Header field types (in the order in which they will appear
+ // in the message header)
+ enum Types
+ {
+ Received, // Relay
+ From, // Expeditor
+ Sender, // Sender
+ ReplyTo, // Reply-To
+ To, // Recipient(s)
+ Cc, // Carbon copy recipient(s)
+ Bcc, // Blind carbon-copy recipient(s)
+ Date, // Date sent
+ Subject, // Subject
+ Organization, // Organization
+ UserAgent, // User agent
+ DeliveredTo, // Delivered-To
+ ReturnPath, // Return-Path
+ MimeVersion, // Mime-Version
+ MessageId, // Message-Id
+ ContentType, // Content-Type
+ ContentTransferEncoding, // Content-Transfer-Encoding
+ ContentDescription, // Content-Description
+ ContentDisposition, // Content-Disposition
+ ContentId, // Content-Id
+ ContentLocation, // Content-Location
+
+ Custom, // Unknown or custom field (eg. X-Priority, X-Mailer, etc.)
+
+ Last
+ };
+
+protected:
+
+ Types m_type;
+ string m_name; // In case of custom field
+
+public:
+
+ const bool operator<(const headerField& field) const;
+
+ const Types type() const;
+ const string name() const;
+
+ const bool isCustom() const;
+
+ virtual void copyFrom(const headerField& field);
+ headerField& operator=(const headerField& field);
+ headerField* clone() const;
+
+ static const Types nameToType(const string& name);
+ static const string typeToName(const Types type);
+
+
+ // Component assembling
+ using component::generate;
+
+ 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_HEADERFIELD_HPP_INCLUDED
diff --git a/src/headerFieldFactory.cpp b/src/headerFieldFactory.cpp
new file mode 100644
index 00000000..0187c26d
--- /dev/null
+++ b/src/headerFieldFactory.cpp
@@ -0,0 +1,139 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "headerFieldFactory.hpp"
+#include "exception.hpp"
+
+#include "defaultField.hpp"
+
+#include "mailboxField.hpp"
+#include "addressListField.hpp"
+#include "addressListField.hpp"
+#include "addressListField.hpp"
+#include "mailboxField.hpp"
+#include "dateField.hpp"
+#include "relayField.hpp"
+#include "textField.hpp"
+#include "mailboxField.hpp"
+#include "contentTypeField.hpp"
+#include "contentEncodingField.hpp"
+#include "contentDispositionField.hpp"
+#include "messageIdField.hpp"
+
+
+namespace vmime
+{
+
+
+headerFieldFactory::headerFieldFactory()
+{
+ // Register some default field types
+ registerType <mailboxField>(headerField::From);
+ registerType <addressListField>(headerField::To);
+ registerType <addressListField>(headerField::Cc);
+ registerType <addressListField>(headerField::Bcc);
+ registerType <mailboxField>(headerField::Sender);
+ registerType <dateField>(headerField::Date);
+ registerType <relayField>(headerField::Received);
+ registerType <textField>(headerField::Subject);
+ registerType <mailboxField>(headerField::ReplyTo);
+ registerType <mailboxField>(headerField::DeliveredTo);
+ registerType <textField>(headerField::Organization);
+ registerType <textField>(headerField::UserAgent);
+ registerType <mailboxField>(headerField::ReturnPath);
+ registerType <contentTypeField>(headerField::ContentType);
+ registerType <contentEncodingField>(headerField::ContentTransferEncoding);
+ registerType <textField>(headerField::ContentDescription);
+ registerType <defaultField>(headerField::MimeVersion);
+ registerType <contentDispositionField>(headerField::ContentDisposition);
+ registerType <messageIdField>(headerField::ContentId);
+ registerType <messageIdField>(headerField::MessageId);
+ registerType <defaultField>(headerField::ContentLocation);
+}
+
+
+headerFieldFactory::~headerFieldFactory()
+{
+}
+
+
+headerField* headerFieldFactory::create
+ (const string& name, const string& body)
+{
+ const headerField::Types type = headerField::nameToType(name);
+
+ if (type != headerField::Custom)
+ {
+ return (create(type, name, body));
+ }
+ else
+ {
+ NameMap::const_iterator pos = m_nameMap.find(toLower(name));
+ headerField* field = NULL;
+
+ if (pos != m_nameMap.end())
+ {
+ field = ((*pos).second)();
+ }
+ else
+ {
+ field = new defaultField;
+ }
+
+ field->m_type = headerField::Custom;
+ field->m_name = name;
+
+ if (body != NULL_STRING)
+ field->parse(body);
+
+ return (field);
+ }
+}
+
+
+headerField* headerFieldFactory::create(const headerField::Types type,
+ const string& name, const string& body)
+{
+ if (type == headerField::Custom)
+ {
+ return (create(name, body));
+ }
+ else
+ {
+ TypeMap::const_iterator pos = m_typeMap.find(type);
+
+ if (pos != m_typeMap.end())
+ {
+ headerField* field = ((*pos).second)();
+
+ field->m_type = type;
+ if (name != NULL_STRING) field->m_name = name;
+ if (body != NULL_STRING) field->parse(body);
+
+ return (field);
+ }
+ else
+ {
+ throw exceptions::bad_field_type();
+ }
+ }
+}
+
+
+} // vmime
diff --git a/src/headerFieldFactory.hpp b/src/headerFieldFactory.hpp
new file mode 100644
index 00000000..13024fd6
--- /dev/null
+++ b/src/headerFieldFactory.hpp
@@ -0,0 +1,85 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_HEADERFIELDFACTORY_HPP_INCLUDED
+#define VMIME_HEADERFIELDFACTORY_HPP_INCLUDED
+
+
+#include "headerField.hpp"
+#include "utility/singleton.hpp"
+
+
+namespace vmime
+{
+
+
+class headerFieldFactory : public utility::singleton <headerFieldFactory>
+{
+ friend class utility::singleton <headerFieldFactory>;
+
+protected:
+
+ headerFieldFactory();
+ ~headerFieldFactory();
+
+ typedef headerField* (*AllocFunc)(void);
+ typedef std::map <string, AllocFunc> NameMap;
+ typedef std::map <headerField::Types, AllocFunc> TypeMap;
+
+ NameMap m_nameMap;
+ TypeMap m_typeMap;
+
+public:
+
+ template <class TYPE>
+ class registerer
+ {
+ public:
+
+ static headerField* creator()
+ {
+ // Allocate a new object
+ return new TYPE();
+ }
+ };
+
+
+ template <class T>
+ void registerName(const string& name)
+ {
+ m_nameMap.insert(NameMap::value_type(toLower(name), &registerer<T>::creator));
+ }
+
+ headerField* create(const string& name, const string& body = NULL_STRING);
+ headerField* create(const headerField::Types type, const string& name = NULL_STRING, const string& body = NULL_STRING);
+
+protected:
+
+ template <class T>
+ void registerType(const headerField::Types type)
+ {
+ m_typeMap.insert(TypeMap::value_type(type, &registerer<T>::creator));
+ }
+};
+
+
+} // vmime
+
+
+#endif // VMIME_HEADERFIELDFACTORY_HPP_INCLUDED
diff --git a/src/htmlTextPart.cpp b/src/htmlTextPart.cpp
new file mode 100644
index 00000000..f864272d
--- /dev/null
+++ b/src/htmlTextPart.cpp
@@ -0,0 +1,371 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "htmlTextPart.hpp"
+#include "exception.hpp"
+
+
+namespace vmime
+{
+
+
+htmlTextPart::~htmlTextPart()
+{
+}
+
+
+const mediaType htmlTextPart::type() const
+{
+ return (mediaType(mediaTypes::TEXT, mediaTypes::TEXT_HTML));
+}
+
+
+const int htmlTextPart::getPartCount() const
+{
+ return (m_plainText.empty() ? 1 : 2);
+}
+
+
+void htmlTextPart::generateIn(bodyPart& /* message */, bodyPart& parent) const
+{
+ // Plain text
+ if (!m_plainText.empty())
+ {
+ // -- Create a new part
+ bodyPart* part = new bodyPart();
+ parent.body().parts.append(part);
+
+ // -- Set header fields
+ part->header().fields.ContentType() = mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN);
+ part->header().fields.ContentType().charset() = m_charset;
+ part->header().fields.ContentTransferEncoding() = encoding(encodingTypes::QUOTED_PRINTABLE);
+
+ // -- Set contents
+ part->body().contents() = m_plainText;
+ }
+
+ // HTML text
+ // -- Create a new part
+ bodyPart* htmlPart = new bodyPart();
+
+ // -- Set header fields
+ htmlPart->header().fields.ContentType() = mediaType(mediaTypes::TEXT, mediaTypes::TEXT_HTML);
+ htmlPart->header().fields.ContentType().charset() = m_charset;
+ htmlPart->header().fields.ContentTransferEncoding() = encoding(encodingTypes::QUOTED_PRINTABLE);
+
+ // -- Set contents
+ htmlPart->body().contents() = m_text;
+
+ // Handle the case we have embedded objects
+ if (!embeddedObjects.empty())
+ {
+ // Create a "multipart/related" body part
+ bodyPart* relPart = new bodyPart();
+ parent.body().parts.append(relPart);
+
+ relPart->header().fields.ContentType() = mediaType
+ (mediaTypes::MULTIPART, mediaTypes::MULTIPART_RELATED);
+
+ // Add the HTML part into this part
+ relPart->body().parts.append(htmlPart);
+
+ // Also add images into this part
+ for (embeddedObjectsContainer::const_iterator i = embeddedObjects.begin() ;
+ i != embeddedObjects.end() ; ++i)
+ {
+ bodyPart* objPart = new bodyPart();
+ relPart->body().parts.append(objPart);
+
+ string id = (*i).id();
+
+ if (id.substr(0, 4) == "CID:")
+ id = id.substr(4);
+
+ objPart->header().fields.ContentType() = (*i).type();
+ objPart->header().fields.ContentId() = messageId("<" + id + ">");
+ objPart->header().fields.ContentDisposition() = disposition(dispositionTypes::INLINE);
+ objPart->header().fields.ContentTransferEncoding() = (*i).encoding();
+ //encoding(encodingTypes::BASE64);
+
+ objPart->body().contents() = (*i).data();
+ }
+ }
+ else
+ {
+ // Add the HTML part into the parent part
+ parent.body().parts.append(htmlPart);
+ }
+}
+
+
+void htmlTextPart::findEmbeddedParts(const bodyPart& part,
+ std::vector <const bodyPart*>& cidParts, std::vector <const bodyPart*>& locParts)
+{
+ for (body::const_iterator p = part.body().parts.begin() ; p != part.body().parts.end() ; ++p)
+ {
+ try
+ {
+ dynamic_cast<messageIdField&>((*p).header().fields.find(headerField::ContentId));
+ cidParts.push_back(&(*p));
+ }
+ catch (exceptions::no_such_field)
+ {
+ // No "Content-id" field.
+ // Maybe there is a "Content-Location" field...
+ try
+ {
+ dynamic_cast<messageIdField&>((*p).header().fields.find(headerField::ContentId));
+ locParts.push_back(&(*p));
+ }
+ catch (exceptions::no_such_field)
+ {
+ // No "Content-Location" field.
+ // Cannot be an embedded object since it cannot be referenced in HTML text.
+ }
+ }
+
+ findEmbeddedParts((*p), cidParts, locParts);
+ }
+}
+
+
+void htmlTextPart::addEmbeddedObject(const bodyPart& part, const string& id)
+{
+ mediaType type;
+
+ try
+ {
+ const contentTypeField& ctf = dynamic_cast<contentTypeField&>
+ (part.header().fields.find(headerField::ContentType));
+
+ type = ctf.value();
+ }
+ catch (exceptions::no_such_field)
+ {
+ // No "Content-type" field: assume "application/octet-stream".
+ }
+
+ embeddedObjects.m_list.push_back(new embeddedObject
+ (part.body().contents(), part.body().encoding(), id, type));
+}
+
+
+void htmlTextPart::parse(const bodyPart& message, const bodyPart& parent, const bodyPart& textPart)
+{
+ // Search for possible embedded objects in the _whole_ message.
+ std::vector <const bodyPart*> cidParts;
+ std::vector <const bodyPart*> locParts;
+
+ findEmbeddedParts(message, cidParts, locParts);
+
+ // Extract HTML text
+ std::ostringstream oss;
+ utility::outputStreamAdapter adapter(oss);
+
+ textPart.body().contents().extract(adapter);
+
+ const string data = oss.str();
+
+ m_text = textPart.body().contents();
+
+ try
+ {
+ const contentTypeField& ctf = dynamic_cast<contentTypeField&>
+ (textPart.header().fields.find(headerField::ContentType));
+
+ m_charset = ctf.charset();
+ }
+ catch (exceptions::no_such_field)
+ {
+ // No "Content-type" field.
+ }
+ catch (exceptions::no_such_parameter)
+ {
+ // No "charset" parameter.
+ }
+
+ // Extract embedded objects. The algorithm is quite simple: for each previously
+ // found inline part, we check if its CID/Location is contained in the HTML text.
+ for (std::vector <const bodyPart*>::const_iterator p = cidParts.begin() ; p != cidParts.end() ; ++p)
+ {
+ const messageIdField& midField = dynamic_cast<messageIdField&>
+ ((**p).header().fields.find(headerField::ContentId));
+
+ const string searchFor("CID:" + midField.value().id());
+
+ if (data.find(searchFor) != string::npos)
+ {
+ // This part is referenced in the HTML text.
+ // Add it to the embedded object list.
+ addEmbeddedObject(**p, "CID:" + midField.value().id());
+ }
+ }
+
+ for (std::vector <const bodyPart*>::const_iterator p = locParts.begin() ; p != locParts.end() ; ++p)
+ {
+ const defaultField& locField = dynamic_cast<defaultField&>
+ ((**p).header().fields.find(headerField::ContentLocation));
+
+ if (data.find(locField.value()) != string::npos)
+ {
+ // This part is referenced in the HTML text.
+ // Add it to the embedded object list.
+ addEmbeddedObject(**p, locField.value());
+ }
+ }
+
+ // Extract plain text, if any.
+ findPlainTextPart(message, parent, textPart);
+}
+
+
+bool htmlTextPart::findPlainTextPart(const bodyPart& part, const bodyPart& parent, const bodyPart& textPart)
+{
+ // We search for the nearest "multipart/alternative" part.
+ try
+ {
+ const contentTypeField& ctf = dynamic_cast<contentTypeField&>
+ (part.header().fields.find(headerField::ContentType));
+
+ if (ctf.value().type() == mediaTypes::MULTIPART &&
+ ctf.value().subType() == mediaTypes::MULTIPART_ALTERNATIVE)
+ {
+ bodyPart const* foundPart = NULL;
+
+ for (body::const_iterator p = part.body().parts.begin() ; !foundPart && p != part.body().parts.end() ; ++p)
+ {
+ if (&(*p) == &parent || // if "text/html" is in "multipart/related"
+ &(*p) == &textPart) // if not...
+ {
+ foundPart = &(*p);
+ }
+ }
+
+ if (foundPart)
+ {
+ bool found = false;
+
+ // Now, search for the alternative plain text part
+ for (body::const_iterator p = part.body().parts.begin() ;
+ !found && p != part.body().parts.end() ; ++p)
+ {
+ try
+ {
+ const contentTypeField& ctf = dynamic_cast<contentTypeField&>
+ ((*p).header().fields.find(headerField::ContentType));
+
+ if (ctf.value().type() == mediaTypes::TEXT &&
+ ctf.value().subType() == mediaTypes::TEXT_PLAIN)
+ {
+ m_plainText = (*p).body().contents();
+ found = true;
+ }
+ }
+ catch (exceptions::no_such_field)
+ {
+ // No "Content-type" field.
+ }
+ }
+
+ // If we don't have found the plain text part here, it means that
+ // it does not exists (the MUA which built this message probably
+ // did not include it...).
+ return (found);
+ }
+ }
+ }
+ catch (exceptions::no_such_field)
+ {
+ // No "Content-type" field.
+ }
+
+ bool found = false;
+
+ for (body::const_iterator p = part.body().parts.begin() ; !found && p != part.body().parts.end() ; ++p)
+ {
+ found = findPlainTextPart(*p, parent, textPart);
+ }
+
+ return (found);
+}
+
+
+
+////////////////////////////////
+// Embedded objects container //
+////////////////////////////////
+
+
+htmlTextPart::embeddedObjectsContainer::~embeddedObjectsContainer()
+{
+ free_container(m_list);
+}
+
+
+const htmlTextPart::embeddedObject& htmlTextPart::embeddedObjectsContainer::find(const string& id) const
+{
+ for (std::vector <embeddedObject*>::const_iterator o = m_list.begin() ; o != m_list.end() ; ++o)
+ {
+ if ((**o).id() == id)
+ return (**o);
+ }
+
+ throw exceptions::no_object_found();
+}
+
+
+const bool htmlTextPart::embeddedObjectsContainer::has(const string& id) const
+{
+ for (std::vector <embeddedObject*>::const_iterator o = m_list.begin() ; o != m_list.end() ; ++o)
+ {
+ if ((**o).id() == id)
+ return (true);
+ }
+
+ return (false);
+}
+
+
+const string htmlTextPart::embeddedObjectsContainer::add
+ (const contentHandler& data, const vmime::encoding& enc, const mediaType& type)
+{
+ const messageId mid(messageId::generateId());
+ const string id = "CID:" + mid.id();
+
+ m_list.push_back(new embeddedObject(data, enc, id, type));
+
+ return (id);
+}
+
+
+const string htmlTextPart::embeddedObjectsContainer::add
+ (const contentHandler& data, const mediaType& type)
+{
+ return (add(data, encoding::decide(data), type));
+}
+
+
+const string htmlTextPart::embeddedObjectsContainer::add
+ (const string& data, const mediaType& type)
+{
+ return (add(contentHandler(data), encoding::decide(data), type));
+}
+
+
+} // vmime
diff --git a/src/htmlTextPart.hpp b/src/htmlTextPart.hpp
new file mode 100644
index 00000000..eeb7b618
--- /dev/null
+++ b/src/htmlTextPart.hpp
@@ -0,0 +1,180 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_HTMLTEXTPART_HPP_INCLUDED
+#define VMIME_HTMLTEXTPART_HPP_INCLUDED
+
+
+#include "textPart.hpp"
+#include "messageId.hpp"
+#include "encoding.hpp"
+
+#include "contentHandler.hpp"
+
+
+namespace vmime
+{
+
+
+class htmlTextPart : public textPart
+{
+protected:
+
+ ~htmlTextPart();
+
+public:
+
+ const mediaType type() const;
+
+ const vmime::charset& charset() const { return (m_charset); }
+ vmime::charset& charset() { return (m_charset); }
+
+ const contentHandler& plainText() const { return (m_plainText); }
+ contentHandler& plainText() { return (m_plainText); }
+
+ const contentHandler& text() const { return (m_text); }
+ contentHandler& text() { return (m_text); }
+
+ // Embedded object (eg. image for <IMG> tag)
+ class embeddedObject
+ {
+ public:
+
+ embeddedObject(const contentHandler& data, const vmime::encoding& enc,
+ const string& id, const mediaType& type)
+ : m_data(data), m_encoding(enc), m_id(id), m_type(type)
+ {
+ }
+
+ public:
+
+ const contentHandler& data() const { return (m_data); }
+ const vmime::encoding& encoding() const { return (m_encoding); }
+ const string& id() const { return (m_id); }
+ const mediaType& type() const { return (m_type); }
+
+ private:
+
+ contentHandler m_data;
+ vmime::encoding m_encoding;
+ string m_id;
+ mediaType m_type;
+ };
+
+ // Embedded objects container
+ class embeddedObjectsContainer
+ {
+ friend class htmlTextPart;
+
+ protected:
+
+ ~embeddedObjectsContainer();
+
+ public:
+
+ // Test the existence/get an embedded object given its identifier.
+ const bool has(const string& id) const;
+ const embeddedObject& find(const string& id) const;
+
+ // Embed an object and returns a string which identifies it.
+ const string add(const string& data, const mediaType& type);
+ const string add(const contentHandler& data, const mediaType& type);
+ const string add(const contentHandler& data, const encoding& enc, const mediaType& type);
+
+ // Embedded objects enumerator
+ class const_iterator
+ {
+ public:
+
+ typedef std::vector <embeddedObject*>::const_iterator::difference_type difference_type;
+
+ const_iterator(std::vector <embeddedObject*>::const_iterator it) : m_iterator(it) { }
+ const_iterator(const const_iterator& it) : m_iterator(it.m_iterator) { }
+
+ const_iterator& operator=(const const_iterator& it) { m_iterator = it.m_iterator; return (*this); }
+
+ const embeddedObject& operator*() const { return (**m_iterator); }
+ const embeddedObject* operator->() const { return (*m_iterator); }
+
+ const_iterator& operator++() { ++m_iterator; return (*this); }
+ const_iterator operator++(int) { const_iterator i(*this); ++m_iterator; return (i); }
+
+ const_iterator& operator--() { --m_iterator; return (*this); }
+ const_iterator operator--(int) { const_iterator i(*this); --m_iterator; return (i); }
+
+ const_iterator& operator+=(difference_type n) { m_iterator += n; return (*this); }
+ const_iterator& operator-=(difference_type n) { m_iterator -= n; return (*this); }
+
+ const_iterator operator-(difference_type x) const { return const_iterator(m_iterator - x); }
+
+ const embeddedObject& operator[](difference_type n) const { return *(m_iterator[n]); }
+
+ const bool operator==(const const_iterator& it) const { return (it.m_iterator == m_iterator); }
+ const bool operator!=(const const_iterator& it) const { return (!(*this == it)); }
+
+ protected:
+
+ std::vector <embeddedObject*>::const_iterator m_iterator;
+ };
+
+ public:
+
+ const_iterator begin() const { return (const_iterator(m_list.begin())); }
+ const_iterator end() const { return (const_iterator(m_list.end())); }
+
+ // Object count
+ const std::vector <embeddedObject*>::size_type count() const { return (m_list.size()); }
+ const std::vector <embeddedObject*>::size_type size() const { return (m_list.size()); }
+ const bool empty() const { return (m_list.empty()); }
+
+ embeddedObject& front() { return (*m_list.front()); }
+ const embeddedObject& front() const { return (*m_list.front()); }
+ embeddedObject& back() { return (*m_list.back()); }
+ const embeddedObject& back() const { return (*m_list.back()); }
+
+ protected:
+
+ std::vector <embeddedObject*> m_list;
+
+ } embeddedObjects;
+
+ typedef embeddedObjectsContainer::const_iterator const_iterator;
+
+protected:
+
+ contentHandler m_plainText;
+ contentHandler m_text;
+ vmime::charset m_charset;
+
+ void findEmbeddedParts(const bodyPart& part, std::vector <const bodyPart*>& cidParts, std::vector <const bodyPart*>& locParts);
+ void addEmbeddedObject(const bodyPart& part, const string& id);
+
+ bool findPlainTextPart(const bodyPart& part, const bodyPart& parent, const bodyPart& textPart);
+
+ const int getPartCount() const;
+
+ void generateIn(bodyPart& message, bodyPart& parent) const;
+ virtual void parse(const bodyPart& message, const bodyPart& parent, const bodyPart& textPart);
+};
+
+
+} // vmime
+
+
+#endif // VMIME_HTMLTEXTPART_HPP_INCLUDED
diff --git a/src/mailbox.cpp b/src/mailbox.cpp
new file mode 100644
index 00000000..6560296c
--- /dev/null
+++ b/src/mailbox.cpp
@@ -0,0 +1,450 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "mailbox.hpp"
+#include "parserHelpers.hpp"
+
+
+namespace vmime
+{
+
+
+mailbox::mailbox()
+{
+}
+
+
+mailbox::mailbox(const class mailbox& mailbox)
+ : address(), m_name(mailbox.m_name), m_email(mailbox.m_email)
+{
+}
+
+
+mailbox::mailbox(const string& email)
+ : m_email(email)
+{
+}
+
+
+mailbox::mailbox(const text& name, const string& email)
+ : m_name(name), m_email(email)
+{
+}
+
+
+/*
+
+ RFC #2822:
+ 3.4. ADDRESS SPECIFICATION
+
+mailbox = name-addr / addr-spec
+
+name-addr = [display-name] angle-addr
+
+angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
+
+*/
+
+void mailbox::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ const string::value_type* const pend = buffer.data() + end;
+ const string::value_type* const pstart = buffer.data() + position;
+ const string::value_type* p = pstart;
+
+ // Ignore blank spaces at the beginning
+ while (p < pend && isspace(*p)) ++p;
+
+ // Current state for parsing machine
+ enum States
+ {
+ State_None,
+ State_Name,
+ State_Address
+ };
+
+ States state = State_Name; // let's start with name, we will see later (*)
+
+ // Temporary buffers for extracted name and address
+ string name;
+ string address;
+
+ while (p < pend)
+ {
+ if (state == State_Name)
+ {
+ if (*p == '<')
+ {
+ state = State_Address;
+ continue;
+ }
+
+ if (*p == '"') // Quoted string
+ {
+ ++p;
+
+ bool escaped = false;
+
+ while (p < pend)
+ {
+ if (escaped)
+ {
+ name += *p;
+ escaped = false;
+ }
+ else if (*p == '\\')
+ {
+ escaped = true;
+ }
+ else
+ {
+ if (*p == '"')
+ {
+ ++p;
+ break;
+ }
+ else
+ {
+ name += *p;
+ }
+ }
+
+ ++p;
+ }
+ }
+ else
+ {
+ bool escaped = false;
+ int comment = 0;
+
+ while (p < pend)
+ {
+ if (escaped)
+ {
+ if (!comment) name += *p;
+ escaped = false;
+ }
+ else if (comment)
+ {
+ if (*p == '\\')
+ escaped = true;
+ else if (*p == '(')
+ ++comment;
+ else if (*p == ')')
+ --comment;
+ }
+ else if (*p == '\\')
+ {
+ escaped = true;
+ }
+ else if (*p == '(')
+ {
+ ++comment;
+ }
+ else if (*p == '<')
+ {
+ // Erase any space between display name and <address>
+ string::iterator q = name.end();
+ for ( ; q != name.begin() && isspace(*(q - 1)) ; --q);
+ name.erase(q, name.end());
+
+ break;
+ }
+ else if (/* isspace(*p) || */ *p == '@')
+ {
+ break;
+ }
+ else
+ {
+ name += *p;
+ }
+
+ ++p;
+ }
+ }
+
+ if (p < pend && *p == '@')
+ {
+ // (*) Actually, we were parsing the local-part of an address
+ // and not a display name...
+ address = name;
+ name.clear();
+
+ bool escaped = false;
+ int comment = 0;
+
+ while (p < pend)
+ {
+ if (escaped)
+ {
+ if (!comment) address += *p;
+ escaped = false;
+ }
+ else if (comment)
+ {
+ if (*p == '\\')
+ escaped = true;
+ else if (*p == '(')
+ ++comment;
+ else if (*p == ')')
+ --comment;
+ }
+ else if (*p == '\\')
+ {
+ escaped = true;
+ }
+ else if (*p == '(')
+ {
+ ++comment;
+ }
+ else if (isspace(*p))
+ {
+ break;
+ }
+ else
+ {
+ address += *p;
+ }
+
+ ++p;
+ }
+
+ break;
+ }
+ else
+ {
+ while (p < pend && isspace(*p)) ++p;
+ state = State_None;
+ }
+ }
+ else if (state == State_Address)
+ {
+ // Skip '<' character
+ if (*p == '<')
+ ++p;
+
+ bool escaped = false;
+ int comment = 0;
+
+ while (p < pend)
+ {
+ if (escaped)
+ {
+ if (!comment) address += *p;
+ escaped = false;
+ }
+ else if (comment)
+ {
+ if (*p == '\\')
+ escaped = true;
+ else if (*p == '(')
+ ++comment;
+ else if (*p == ')')
+ --comment;
+ }
+ else if (*p == '(')
+ {
+ ++comment;
+ }
+ else if (*p == '\\')
+ {
+ escaped = true;
+ }
+ else if (*p == '<')
+ {
+ // If we found a '<' here, it means that the address
+ // starts _only_ here...and the stuff we have parsed
+ // before belongs actually to the display name!
+ name += address;
+ address.clear();
+ }
+ else if (*p == '>')
+ {
+ break;
+ }
+ else if (!isspace(*p))
+ {
+ address += *p;
+ }
+
+ ++p;
+ }
+
+ break;
+ }
+ else
+ {
+ while (p < pend && isspace(*p)) ++p;
+
+ if (p < pend)
+ {
+ //if (*p == '<')
+ state = State_Address;
+ }
+ }
+ }
+
+ decodeAndUnfoldText(name, m_name);
+ m_email = address;
+
+ if (newPosition)
+ *newPosition = position + (p - pstart);
+}
+
+
+void mailbox::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ if (m_name.empty())
+ {
+ bool newLine = false;
+
+ // No display name is specified, only email address.
+ if (curLinePos /* + 2 */ + m_email.length() > maxLineLength)
+ {
+ os << NEW_LINE_SEQUENCE;
+ newLine = true;
+ }
+
+ //os << "<" << m_email << ">";
+ os << m_email;
+
+ if (newLinePos)
+ {
+ *newLinePos = curLinePos + m_email.length() /* + 2 */;
+ if (newLine) *newLinePos += 1;
+ }
+ }
+ else
+ {
+ // We have to encode the name:
+ // - if it contains characters in a charset different from "US-ASCII",
+ // - and/or if it contains one or more of these special chars:
+ // SPACE TAB " ; , < > ( ) @ / ? . = :
+
+ // Check whether there are words that are not "US-ASCII"
+ // and/or contain the special chars.
+ bool forceEncode = false;
+
+ for (text::const_iterator w = m_name.begin() ; !forceEncode && w != m_name.end() ; ++w)
+ {
+ if ((*w).charset() == charset(charsets::US_ASCII))
+ {
+ const string& buffer = (*w).buffer();
+
+ for (string::const_iterator c = buffer.begin() ;
+ !forceEncode && c != buffer.end() ; ++c)
+ {
+ switch (*c)
+ {
+ case ' ':
+ case '\t':
+ case ';':
+ case ',':
+ case '<': case '>':
+ case '(': case ')':
+ case '@':
+ case '/':
+ case '?':
+ case '.':
+ case '=':
+ case ':':
+ case '"':
+
+ forceEncode = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ forceEncode = true;
+ }
+ }
+
+ string::size_type pos = curLinePos;
+ bool newLine = true;
+
+ encodeAndFoldText(os, m_name, maxLineLength, pos, &pos,
+ forceEncode ? encodeAndFoldFlags::forceEncoding : encodeAndFoldFlags::none);
+
+ if (pos + m_email.length() + 3 > maxLineLength)
+ {
+ os << NEW_LINE_SEQUENCE;
+ newLine = true;
+ }
+
+ os << " <" << m_email << ">";
+
+ if (newLinePos)
+ {
+ *newLinePos = pos + m_email.length() + 3;
+ if (newLine) *newLinePos += NEW_LINE_SEQUENCE.length();
+ }
+ }
+}
+
+
+const bool mailbox::operator==(const class mailbox& mailbox) const
+{
+ return (m_name == mailbox.m_name && m_email == mailbox.m_email);
+}
+
+
+const bool mailbox::operator!=(const class mailbox& mailbox) const
+{
+ return !(*this == mailbox);
+}
+
+
+void mailbox::copyFrom(const address& addr)
+{
+ const mailbox& source = dynamic_cast<const mailbox&>(addr);
+
+ m_name = source.m_name;
+ m_email = source.m_email;
+}
+
+
+address* mailbox::clone() const
+{
+ return new mailbox(*this);
+}
+
+
+const bool mailbox::empty() const
+{
+ return (m_email.empty());
+}
+
+
+void mailbox::clear()
+{
+ m_name.clear();
+ m_email.clear();
+}
+
+
+const bool mailbox::isGroup() const
+{
+ return (false);
+}
+
+
+} // vmime
diff --git a/src/mailbox.hpp b/src/mailbox.hpp
new file mode 100644
index 00000000..3fa79045
--- /dev/null
+++ b/src/mailbox.hpp
@@ -0,0 +1,105 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MAILBOX_HPP_INCLUDED
+#define VMIME_MAILBOX_HPP_INCLUDED
+
+
+#include "address.hpp"
+#include "text.hpp"
+
+
+namespace vmime
+{
+
+
+/** A mailbox: full name + email (basic type).
+ */
+
+class mailbox : public address
+{
+ friend class mailboxGroup;
+ friend class mailboxField;
+
+public:
+
+ mailbox();
+ mailbox(const class mailbox& mailbox);
+ mailbox(const string& email);
+ mailbox(const text& name, const string& email);
+
+ /** Return the full name of the mailbox (empty if not specified).
+ *
+ * @return full name of the mailbox
+ */
+ const text& name() const { return (m_name); }
+
+ /** Return the full name of the mailbox (empty if not specified).
+ *
+ * @return full name of the mailbox
+ */
+ text& name() { return (m_name); }
+
+ /** Return the email of the mailbox.
+ *
+ * @return email of the mailbox
+ */
+ const string& email() const { return (m_email); }
+
+ /** Return the email of the mailbox.
+ *
+ * @return email of the mailbox
+ */
+ string& email() { return (m_email); }
+
+ // Comparison
+ const bool operator==(const class mailbox& mailbox) const;
+ const bool operator!=(const class mailbox& mailbox) const;
+
+ // Assignment
+ void copyFrom(const address& addr);
+ address* clone() const;
+
+ const bool empty() const;
+
+ void clear();
+
+
+ const bool isGroup() const;
+
+protected:
+
+ text m_name;
+ string m_email;
+
+public:
+
+ using address::parse;
+ using address::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_MAILBOX_HPP_INCLUDED
diff --git a/src/mailboxField.cpp b/src/mailboxField.cpp
new file mode 100644
index 00000000..e4e0164c
--- /dev/null
+++ b/src/mailboxField.cpp
@@ -0,0 +1,95 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "mailboxField.hpp"
+#include "mailboxGroup.hpp"
+
+
+namespace vmime
+{
+
+
+mailboxField::mailboxField()
+{
+}
+
+
+void mailboxField::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ m_mailbox.clear();
+
+ // Here, we cannot simply call "m_mailbox.parse()" because it
+ // may have more than one address specified (even if this field
+ // should contain only one). We are never too much careful...
+ address* parsedAddress = address::parseNext(buffer, position, end, newPosition);
+
+ if (parsedAddress)
+ {
+ if (parsedAddress->isGroup())
+ {
+ // If it is a group of mailboxes, take the first
+ // mailbox of the group
+ mailboxGroup* group = static_cast <mailboxGroup*>(parsedAddress);
+
+ if (!group->empty())
+ m_mailbox = *(group->begin());
+ }
+ else
+ {
+ // Parse only if it is a mailbox
+ m_mailbox = *static_cast <mailbox*>(parsedAddress);
+ }
+ }
+
+ delete (parsedAddress);
+
+ if (newPosition)
+ *newPosition = end;
+}
+
+
+void mailboxField::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ string::size_type pos = curLinePos;
+
+ headerField::generate(os, maxLineLength, pos, &pos);
+
+ m_mailbox.generate(os, maxLineLength, pos, newLinePos);
+}
+
+
+mailboxField& mailboxField::operator=(const class mailbox& mailbox)
+{
+ m_mailbox = mailbox;
+ return (*this);
+}
+
+
+void mailboxField::copyFrom(const headerField& field)
+{
+ const mailboxField& source = dynamic_cast<const mailboxField&>(field);
+ m_mailbox = source.m_mailbox;
+
+ headerField::copyFrom(field);
+}
+
+
+} // vmime
diff --git a/src/mailboxField.hpp b/src/mailboxField.hpp
new file mode 100644
index 00000000..13cd8e49
--- /dev/null
+++ b/src/mailboxField.hpp
@@ -0,0 +1,70 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MAILBOXFIELD_HPP_INCLUDED
+#define VMIME_MAILBOXFIELD_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+
+#include "headerFieldFactory.hpp"
+#include "mailbox.hpp"
+
+
+namespace vmime
+{
+
+
+class mailboxField : public headerField
+{
+ friend class headerFieldFactory::registerer <mailboxField>;
+
+protected:
+
+ mailboxField();
+
+public:
+
+ void copyFrom(const headerField& field);
+
+ mailboxField& operator=(const class mailbox& mailbox);
+
+ const mailbox& value() const { return (m_mailbox); }
+ mailbox& value() { return (m_mailbox); }
+
+protected:
+
+ mailbox m_mailbox;
+
+public:
+
+ using headerField::parse;
+ using headerField::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_MAILBOXFIELD_HPP_INCLUDED
diff --git a/src/mailboxGroup.cpp b/src/mailboxGroup.cpp
new file mode 100644
index 00000000..ff708313
--- /dev/null
+++ b/src/mailboxGroup.cpp
@@ -0,0 +1,237 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "mailboxGroup.hpp"
+#include "parserHelpers.hpp"
+
+
+namespace vmime
+{
+
+
+mailboxGroup::mailboxGroup()
+{
+}
+
+
+mailboxGroup::mailboxGroup(const class mailboxGroup& mailboxGroup)
+ : address()
+{
+ copyFrom(mailboxGroup);
+}
+
+
+mailboxGroup::mailboxGroup(const text& name)
+ : m_name(name)
+{
+}
+
+
+mailboxGroup::~mailboxGroup()
+{
+ clear();
+}
+
+
+void mailboxGroup::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ const string::value_type* const pend = buffer.data() + end;
+ const string::value_type* const pstart = buffer.data() + position;
+ const string::value_type* p = pstart;
+
+ while (p < pend && isspace(*p))
+ ++p;
+
+ string name;
+
+ while (p < pend && *p != ':')
+ {
+ name += *p;
+ ++p;
+ }
+
+ if (p < pend && *p == ':')
+ ++p;
+
+
+ string::size_type pos = position + (p - pstart);
+
+ while (pos < end)
+ {
+ address* parsedAddress = address::parseNext(buffer, pos, end, &pos);
+
+ if (parsedAddress)
+ {
+ if (parsedAddress->isGroup())
+ {
+ mailboxGroup* group = static_cast <mailboxGroup*>(parsedAddress);
+
+ // Sub-groups are not allowed in mailbox groups: so, we add all
+ // the contents of the sub-group into this group...
+ for (mailboxGroup::const_iterator
+ it = group->begin() ; it != group->end() ; ++it)
+ {
+ m_list.push_back(static_cast <mailbox*>((*it).clone()));
+ }
+
+ delete (parsedAddress);
+ }
+ else
+ {
+ m_list.push_back(static_cast <mailbox*>(parsedAddress));
+ }
+ }
+ }
+
+ decodeAndUnfoldText(name, m_name);
+
+ if (newPosition)
+ *newPosition = end;
+}
+
+
+void mailboxGroup::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ // We have to encode the name:
+ // - if it contains characters in a charset different from "US-ASCII",
+ // - and/or if it contains one or more of these special chars:
+ // SPACE TAB " ; , < > ( ) @ / ? . = :
+
+ // Check whether there are words that are not "US-ASCII"
+ // and/or contain the special chars.
+ bool forceEncode = false;
+
+ for (text::const_iterator w = m_name.begin() ; !forceEncode && w != m_name.end() ; ++w)
+ {
+ if ((*w).charset() == charset(charsets::US_ASCII))
+ {
+ const string& buffer = (*w).buffer();
+
+ for (string::const_iterator c = buffer.begin() ;
+ !forceEncode && c != buffer.end() ; ++c)
+ {
+ switch (*c)
+ {
+ case ' ':
+ case '\t':
+ case ';':
+ case ',':
+ case '<': case '>':
+ case '(': case ')':
+ case '@':
+ case '/':
+ case '?':
+ case '.':
+ case '=':
+ case ':':
+
+ forceEncode = true;
+ break;
+ }
+ }
+ }
+ }
+
+ string::size_type pos = curLinePos;
+
+ encodeAndFoldText(os, m_name, maxLineLength - 2, pos, &pos,
+ forceEncode ? encodeAndFoldFlags::forceEncoding : encodeAndFoldFlags::none);
+
+ os << ":";
+ ++pos;
+
+ for (const_iterator it = m_list.begin() ; it != m_list.end() ; ++it)
+ {
+ if (it != m_list.begin())
+ {
+ os << ", ";
+ pos += 2;
+ }
+ else
+ {
+ os << " ";
+ ++pos;
+ }
+
+ (*it).generate(os, maxLineLength - 2, pos, &pos);
+ }
+
+ os << ";";
+ pos++;
+
+ if (newLinePos)
+ *newLinePos = pos;
+}
+
+
+address* mailboxGroup::clone() const
+{
+ return new mailboxGroup(*this);
+}
+
+
+// Mailbox insertion
+void mailboxGroup::append(const mailbox& field)
+{
+ m_list.push_back(static_cast<mailbox*>(field.clone()));
+}
+
+
+void mailboxGroup::insert(const iterator it, const mailbox& field)
+{
+ m_list.insert(it.m_iterator, static_cast<mailbox*>(field.clone()));
+}
+
+
+// Mailbox removing
+void mailboxGroup::erase(const iterator it)
+{
+ delete (*it.m_iterator);
+ m_list.erase(it.m_iterator);
+}
+
+
+void mailboxGroup::clear()
+{
+ free_container(m_list);
+}
+
+
+void mailboxGroup::copyFrom(const address& addr)
+{
+ const mailboxGroup& source = dynamic_cast<const mailboxGroup&>(addr);
+
+ m_name = source.m_name;
+
+ clear();
+
+ for (std::vector <mailbox*>::const_iterator i = source.m_list.begin() ; i != source.m_list.end() ; ++i)
+ m_list.push_back(static_cast<mailbox*>((*i)->clone()));
+}
+
+
+const bool mailboxGroup::isGroup() const
+{
+ return (true);
+}
+
+
+} // vmime
diff --git a/src/mailboxGroup.hpp b/src/mailboxGroup.hpp
new file mode 100644
index 00000000..0187f37c
--- /dev/null
+++ b/src/mailboxGroup.hpp
@@ -0,0 +1,155 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MAILBOXGROUP_HPP_INCLUDED
+#define VMIME_MAILBOXGROUP_HPP_INCLUDED
+
+
+#include "address.hpp"
+#include "mailbox.hpp"
+#include "text.hpp"
+
+
+namespace vmime
+{
+
+
+/** A group of mailboxes (basic type).
+ */
+
+class mailboxGroup : public address
+{
+public:
+
+ mailboxGroup();
+ mailboxGroup(const class mailboxGroup& mailboxGroup);
+ mailboxGroup(const text& name);
+
+ ~mailboxGroup();
+
+ // Properties set/get
+ const text& name() const { return (m_name); }
+ text& name() { return (m_name); }
+
+ // Assignment
+ void copyFrom(const address& addr);
+ address* clone() const;
+
+public:
+
+ // Mailbox iterator
+ class const_iterator;
+
+ class iterator
+ {
+ friend class mailboxGroup;
+ friend class const_iterator;
+
+ public:
+
+ iterator(std::vector <mailbox*>::iterator it) : m_iterator(it) { }
+ iterator(const iterator& it) : m_iterator(it.m_iterator) { }
+
+ iterator& operator=(const iterator& it) { m_iterator = it.m_iterator; return (*this); }
+
+ mailbox& operator*() const { return (**m_iterator); }
+ mailbox* operator->() const { return (*m_iterator); }
+
+ iterator& operator++() { ++m_iterator; return (*this); }
+ iterator& operator++(int) { ++m_iterator; return (*this); }
+
+ const bool operator==(const iterator& it) const { return (it.m_iterator == m_iterator); }
+ const bool operator!=(const iterator& it) const { return (!(*this == it)); }
+
+ private:
+
+ std::vector <mailbox*>::iterator m_iterator;
+ };
+
+ class const_iterator
+ {
+ friend class mailboxGroup;
+
+ public:
+
+ const_iterator(std::vector <mailbox*>::const_iterator it) : m_iterator(it) { }
+ const_iterator(const iterator& it) : m_iterator(it.m_iterator) { }
+ const_iterator(const const_iterator& it) : m_iterator(it.m_iterator) { }
+
+ const_iterator& operator=(const const_iterator& it) { m_iterator = it.m_iterator; return (*this); }
+ const_iterator& operator=(const iterator& it) { m_iterator = it.m_iterator; return (*this); }
+
+ const mailbox& operator*() const { return (**m_iterator); }
+ const mailbox* operator->() const { return (*m_iterator); }
+
+ const_iterator& operator++() { ++m_iterator; return (*this); }
+ const_iterator& operator++(int) { ++m_iterator; return (*this); }
+
+ const bool operator==(const const_iterator& it) const { return (it.m_iterator == m_iterator); }
+ const bool operator!=(const const_iterator& it) const { return (!(*this == it)); }
+
+ private:
+
+ std::vector <mailbox*>::const_iterator m_iterator;
+ };
+
+ iterator begin() { return (m_list.begin()); }
+ iterator end() { return (m_list.end()); }
+
+ const_iterator begin() const { return (const_iterator(m_list.begin())); }
+ const_iterator end() const { return (const_iterator(m_list.end())); }
+
+ const std::vector <mailbox*>::size_type size() const { return (m_list.size()); }
+ const std::vector <mailbox*>::size_type count() const { return (m_list.size()); }
+ const bool empty() const { return (m_list.empty()); }
+
+ const mailbox& operator[](const std::vector <mailbox*>::size_type x) const { return (*m_list[x]); }
+ mailbox& operator[](const std::vector <mailbox*>::size_type x) { return (*m_list[x]); }
+
+ // Mailbox insertion
+ virtual void append(const mailbox& field);
+ virtual void insert(const iterator it, const mailbox& field);
+
+ // Mailbox removing
+ void erase(const iterator it);
+ void clear();
+
+
+ const bool isGroup() const;
+
+protected:
+
+ text m_name;
+ std::vector <mailbox*> m_list;
+
+public:
+
+ using address::parse;
+ using address::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_MAILBOXGROUP_HPP_INCLUDED
diff --git a/src/mailboxList.cpp b/src/mailboxList.cpp
new file mode 100644
index 00000000..ded7ede1
--- /dev/null
+++ b/src/mailboxList.cpp
@@ -0,0 +1,46 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "mailboxList.hpp"
+
+
+namespace vmime
+{
+
+
+// Address insertion
+void mailboxList::append(const address& addr)
+{
+ // Ensure this is a "mailbox" object
+ const mailbox& mb = dynamic_cast<const mailbox&>(addr);
+
+ m_list.push_back(mb.clone());
+}
+
+
+void mailboxList::insert(const iterator it, const address& addr)
+{
+ // Ensure this is a "mailbox" object
+ const mailbox& mb = dynamic_cast<const mailbox&>(addr);
+
+ m_list.insert(it.m_iterator, mb.clone());
+}
+
+
+} // vmime
diff --git a/src/mailboxList.hpp b/src/mailboxList.hpp
new file mode 100644
index 00000000..28c6152b
--- /dev/null
+++ b/src/mailboxList.hpp
@@ -0,0 +1,127 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MAILBOXLIST_HPP_INCLUDED
+#define VMIME_MAILBOXLIST_HPP_INCLUDED
+
+
+#include "addressList.hpp"
+#include "mailbox.hpp"
+
+
+namespace vmime
+{
+
+
+/** A list of mailboxes (basic type).
+ */
+
+class mailboxList : public addressList
+{
+ friend class mailboxGroup;
+
+public:
+
+ //
+ // The following functions have the same name and work *exactly* like
+ // the ones in "addressList", except we don't accept anything other
+ // than objects of type "mailbox" (instead of a generic "address").
+ //
+ // This prevents user from inserting mailbox groups where it is not
+ // allowed by the RFC.
+ //
+
+ // Address iterator
+ class const_iterator;
+
+ class iterator
+ {
+ friend class mailboxList;
+ friend class const_iterator;
+
+ protected:
+
+ iterator(std::vector <address*>::iterator it) : m_iterator(it) { }
+
+ public:
+
+ iterator(const iterator& it) : m_iterator(it.m_iterator) { }
+
+ iterator& operator=(const iterator& it) { m_iterator = it.m_iterator; return (*this); }
+
+ mailbox& operator*() const { return static_cast<mailbox&>(**m_iterator); }
+ mailbox* operator->() const { return static_cast<mailbox*>(*m_iterator); }
+
+ iterator& operator++() { ++m_iterator; return (*this); }
+ iterator& operator++(int) { ++m_iterator; return (*this); }
+
+ const bool operator==(const iterator& it) const { return (it.m_iterator == m_iterator); }
+ const bool operator!=(const iterator& it) const { return (!(*this == it)); }
+
+ private:
+
+ std::vector <address*>::iterator m_iterator;
+ };
+
+ class const_iterator
+ {
+ friend class mailboxList;
+
+ protected:
+
+ const_iterator(std::vector <address*>::const_iterator it) : m_iterator(it) { }
+
+ public:
+
+ const_iterator(const iterator& it) : m_iterator(it.m_iterator) { }
+ const_iterator(const const_iterator& it) : m_iterator(it.m_iterator) { }
+
+ const_iterator& operator=(const const_iterator& it) { m_iterator = it.m_iterator; return (*this); }
+ const_iterator& operator=(const iterator& it) { m_iterator = it.m_iterator; return (*this); }
+
+ const mailbox& operator*() const { return static_cast<const mailbox&>(**m_iterator); }
+ const mailbox* operator->() const { return static_cast<const mailbox*>(*m_iterator); }
+
+ const_iterator& operator++() { ++m_iterator; return (*this); }
+ const_iterator& operator++(int) { ++m_iterator; return (*this); }
+
+ const bool operator==(const const_iterator& it) const { return (it.m_iterator == m_iterator); }
+ const bool operator!=(const const_iterator& it) const { return (!(*this == it)); }
+
+ private:
+
+ std::vector <address*>::const_iterator m_iterator;
+ };
+
+ iterator begin() { return (m_list.begin()); }
+ iterator end() { return (m_list.end()); }
+
+ const_iterator begin() const { return (const_iterator(m_list.begin())); }
+ const_iterator end() const { return (const_iterator(m_list.end())); }
+
+ // Address insertion
+ void append(const address& addr);
+ void insert(const iterator it, const address& addr);
+};
+
+
+} // vmime
+
+
+#endif // VMIME_MAILBOXLIST_HPP_INCLUDED
diff --git a/src/mailboxListField.cpp b/src/mailboxListField.cpp
new file mode 100644
index 00000000..69c328f5
--- /dev/null
+++ b/src/mailboxListField.cpp
@@ -0,0 +1,60 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "mailboxListField.hpp"
+
+
+namespace vmime
+{
+
+
+mailboxListField::mailboxListField()
+{
+}
+
+
+void mailboxListField::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ m_list.parse(buffer, position, end, newPosition);
+}
+
+
+void mailboxListField::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ string::size_type pos = curLinePos;
+
+ headerField::generate(os, maxLineLength, pos, &pos);
+
+ m_list.generate(os, maxLineLength, pos, newLinePos);
+}
+
+
+void mailboxListField::copyFrom(const headerField& field)
+{
+ const mailboxListField& source = dynamic_cast<const mailboxListField&>(field);
+ m_list = source.m_list;
+
+ headerField::copyFrom(field);
+}
+
+
+} // vmime
+
diff --git a/src/mailboxListField.hpp b/src/mailboxListField.hpp
new file mode 100644
index 00000000..6e01c278
--- /dev/null
+++ b/src/mailboxListField.hpp
@@ -0,0 +1,68 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MAILBOXLISTFIELD_HPP_INCLUDED
+#define VMIME_MAILBOXLISTFIELD_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+
+#include "headerFieldFactory.hpp"
+#include "mailboxList.hpp"
+
+
+namespace vmime
+{
+
+
+class mailboxListField : public headerField
+{
+ friend class headerFieldFactory::registerer <mailboxListField>;
+
+protected:
+
+ mailboxListField();
+
+public:
+
+ void copyFrom(const headerField& field);
+
+ const mailboxList& value() const { return (m_list); }
+ mailboxList& value() { return (m_list); }
+
+protected:
+
+ mailboxList m_list;
+
+public:
+
+ using headerField::parse;
+ using headerField::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_MAILBOXLISTFIELD_HPP_INCLUDED
diff --git a/src/mediaType.cpp b/src/mediaType.cpp
new file mode 100644
index 00000000..6681a0dc
--- /dev/null
+++ b/src/mediaType.cpp
@@ -0,0 +1,127 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "mediaType.hpp"
+#include "parserHelpers.hpp"
+
+
+namespace vmime
+{
+
+
+mediaType::mediaType()
+ : m_type(mediaTypes::APPLICATION), m_subType(mediaTypes::APPLICATION_OCTET_STREAM)
+{
+}
+
+
+mediaType::mediaType(const string& type)
+{
+ parse(type);
+}
+
+
+mediaType::mediaType(const string& type, const string& subType)
+{
+ set(type, subType);
+}
+
+
+void mediaType::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ const string::value_type* const pend = buffer.data() + end;
+ const string::value_type* const pstart = buffer.data() + position;
+ const string::value_type* p = pstart;
+
+ // Extract the type
+ const string::size_type typeStart = position;
+
+ while (p < pend && *p != '/') ++p;
+
+ m_type = toLower(string(buffer.begin() + typeStart,
+ buffer.begin() + position + (p - pstart)));
+
+ if (p < pend)
+ {
+ // Skip '/' character
+ ++p;
+
+ // Extract the sub-type
+ m_subType = toLower(string(buffer.begin() + position + (p - pstart),
+ buffer.begin() + end));
+ }
+
+ if (newPosition)
+ *newPosition = end;
+}
+
+
+void mediaType::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ const string value = toLower(m_type) + "/" + toLower(m_subType);
+
+ if (curLinePos + value.length() > maxLineLength)
+ {
+ os << NEW_LINE_SEQUENCE;
+ os << value;
+
+ if (newLinePos)
+ *newLinePos = NEW_LINE_SEQUENCE_LENGTH + value.length();
+ }
+ else
+ {
+ os << value;
+
+ if (newLinePos)
+ *newLinePos = curLinePos + value.length();
+ }
+}
+
+
+const bool mediaType::operator==(const mediaType& type) const
+{
+ return (m_type == type.m_type && m_subType == type.m_subType);
+}
+
+
+const bool mediaType::operator!=(const mediaType& type) const
+{
+ return !(*this == type);
+}
+
+
+mediaType& mediaType::operator=(const mediaType& type)
+{
+ m_type = type.m_type;
+ m_subType = type.m_subType;
+
+ return (*this);
+}
+
+
+mediaType& mediaType::operator=(const string& type)
+{
+ parse(type);
+ return (*this);
+}
+
+
+} // vmime
diff --git a/src/mediaType.hpp b/src/mediaType.hpp
new file mode 100644
index 00000000..f4148e5c
--- /dev/null
+++ b/src/mediaType.hpp
@@ -0,0 +1,78 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MEDIATYPE_HPP_INCLUDED
+#define VMIME_MEDIATYPE_HPP_INCLUDED
+
+
+#include "component.hpp"
+
+
+namespace vmime
+{
+
+
+/** Content media type (basic type).
+ */
+
+class mediaType : public component
+{
+public:
+
+ mediaType();
+ mediaType(const string& type);
+ mediaType(const string& type, const string& subType);
+
+public:
+
+ const bool operator==(const mediaType& type) const;
+ const bool operator!=(const mediaType& type) const;
+
+ mediaType& operator=(const mediaType& type);
+ mediaType& operator=(const string& type);
+
+ const string& type() const { return (m_type); };
+ string& type() { return (m_type); }
+
+ const string& subType() const { return (m_subType); };
+ string& subType() { return (m_subType); }
+
+ void set(const string& type) { parse(type); }
+ void set(const string& type, const string& subType) { m_type = type; m_subType = subType; }
+
+protected:
+
+ string m_type;
+ string m_subType;
+
+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_MEDIATYPE_HPP_INCLUDED
diff --git a/src/message.cpp b/src/message.cpp
new file mode 100644
index 00000000..bd6f6085
--- /dev/null
+++ b/src/message.cpp
@@ -0,0 +1,65 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "message.hpp"
+#include "options.hpp"
+
+#include <sstream>
+
+
+namespace vmime
+{
+
+
+message::message()
+{
+}
+
+
+void message::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ // We override this function to change the default value for the
+ // "maxLineLength" parameter. So, the user will just have to call
+ // message::generate() without any argument to use the maximum line
+ // length specified in vmime::options...
+ bodyPart::generate(os, maxLineLength, curLinePos, newLinePos);
+}
+
+
+const string message::generate(const string::size_type maxLineLength,
+ const string::size_type curLinePos) const
+{
+ std::ostringstream oss;
+ utility::outputStreamAdapter adapter(oss);
+
+ generate(adapter, maxLineLength, curLinePos, NULL);
+
+ return (oss.str());
+}
+
+
+void message::parse(const string& buffer)
+{
+ bodyPart::parse(buffer);
+}
+
+
+} // vmime
+
diff --git a/src/message.hpp b/src/message.hpp
new file mode 100644
index 00000000..9b3c6cc9
--- /dev/null
+++ b/src/message.hpp
@@ -0,0 +1,55 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGE_HPP_INCLUDED
+#define VMIME_MESSAGE_HPP_INCLUDED
+
+
+#include "bodyPart.hpp"
+#include "options.hpp"
+
+
+namespace vmime
+{
+
+
+/** A MIME message.
+ */
+
+class message : public bodyPart
+{
+public:
+
+ message();
+
+
+ // Component parsing & assembling
+ void generate(utility::outputStream& os, const string::size_type maxLineLength = options::getInstance()->message.maxLineLength(), const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
+
+ const string generate(const string::size_type maxLineLength = options::getInstance()->message.maxLineLength(), const string::size_type curLinePos = 0) const;
+
+ void parse(const string& buffer);
+};
+
+
+
+} // vmime
+
+
+#endif // VMIME_MESSAGE_HPP_INCLUDED
diff --git a/src/messageBuilder.cpp b/src/messageBuilder.cpp
new file mode 100644
index 00000000..52ee6390
--- /dev/null
+++ b/src/messageBuilder.cpp
@@ -0,0 +1,188 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "messageBuilder.hpp"
+
+#include "textPartFactory.hpp"
+
+
+namespace vmime
+{
+
+
+messageBuilder::messageBuilder()
+ : m_textPart(NULL)
+{
+ // By default there is one text part of type "text/plain"
+ constructTextPart(mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN));
+}
+
+
+messageBuilder::~messageBuilder()
+{
+ delete (m_textPart);
+
+ free_container(m_attach);
+}
+
+
+message* messageBuilder::construct() const
+{
+ // Create a new message
+ message* msg = new message;
+
+ // Generate the header fields
+ msg->header().fields.Subject() = m_subject;
+
+ if (m_from.empty())
+ throw exceptions::no_expeditor();
+
+ if (m_to.empty() || (*m_to.begin()).empty())
+ throw exceptions::no_recipient();
+
+ msg->header().fields.From() = m_from;
+ msg->header().fields.To() = m_to;
+
+ if (!m_cc.empty())
+ msg->header().fields.Cc() = m_cc;
+
+ if (!m_bcc.empty())
+ msg->header().fields.Bcc() = m_bcc;
+
+ // Add a "Date" field
+ msg->header().fields.Date() = datetime::now();
+
+ // Add a "Mime-Version" header field
+ msg->header().fields.MimeVersion().value() = MIME_VERSION;
+
+ // If there is one or more attachments (or other parts that are
+ // not "text/...") and if there is more than one parts for the
+ // text part, we generate these text parts into a sub-part:
+ //
+ // [message]
+ // |
+ // +-- multipart/mixed
+ // |
+ // +-- multipart/alternative
+ // | |
+ // | +-- text part #1 (eg. plain text "text/plain")
+ // | +-- text part #2 (eg. HTML "text/html")
+ // | +-- ...
+ // |
+ // +-- application/octet-stream (attachment #1)
+ // |
+ // +-- ... (other attachments/parts)
+ //
+ if (!m_attach.empty() && m_textPart->getPartCount() > 1)
+ {
+ // Set parent part (message) to "multipart/mixed"
+ msg->header().fields.ContentType() = mediaType
+ (mediaTypes::MULTIPART, mediaTypes::MULTIPART_MIXED);
+
+ // Create a sub-part "multipart/alternative" for text parts
+ bodyPart* subPart = new bodyPart;
+ msg->body().parts.append(subPart);
+
+ subPart->header().fields.ContentType() = mediaType
+ (mediaTypes::MULTIPART, mediaTypes::MULTIPART_ALTERNATIVE);
+
+ // Generate the text parts into this sub-part (normally, this
+ // sub-part will have the "multipart/alternative" content-type...)
+ m_textPart->generateIn(*msg, *subPart);
+ }
+ else
+ {
+ // Generate the text part(s) directly into the message
+ m_textPart->generateIn(*msg, *msg);
+
+ // If any attachment, set message content-type to "multipart/mixed"
+ if (!m_attach.empty())
+ {
+ msg->header().fields.ContentType() = mediaType
+ (mediaTypes::MULTIPART, mediaTypes::MULTIPART_MIXED);
+ }
+ // Else, set it to "multipart/alternative" if there are more than one text part.
+ else if (m_textPart->getPartCount() > 1)
+ {
+ msg->header().fields.ContentType() = mediaType
+ (mediaTypes::MULTIPART, mediaTypes::MULTIPART_ALTERNATIVE);
+ }
+ }
+
+ // Generate the attachments
+ if (!m_attach.empty())
+ {
+ for (std::vector <attachment*>::const_iterator a = m_attach.begin() ; a != m_attach.end() ; ++a)
+ {
+ (*a)->generateIn(*msg);
+ }
+ }
+
+ // If there is only one part in the message, move it into the message
+ // (hence, the message will not be multipart...)
+ if (msg->body().parts.size() == 1)
+ {
+ const bodyPart& part = msg->body().parts.front();
+
+ // First, copy (and replace) the header fields
+ const header::fieldsContainer& hdr = part.header().fields;
+
+ for (header::const_iterator f = hdr.begin() ; f != hdr.end() ; ++f)
+ msg->header().fields.get((*f).name()) = *f;
+
+ // Second, copy the body contents and sub-parts (this also remove
+ // the body part we are copying...)
+ msg->body() = part.body();
+ }
+
+ return (msg);
+}
+
+
+void messageBuilder::attach(attachment* attach)
+{
+ m_attach.push_back(attach);
+}
+
+
+void messageBuilder::constructTextPart(const mediaType& type)
+{
+ class textPart* part = NULL;
+
+ try
+ {
+ part = textPartFactory::getInstance()->create(type);
+ }
+ catch (exceptions::no_factory_available& e)
+ {
+ throw;
+ }
+
+ delete (m_textPart);
+ m_textPart = part;
+}
+
+
+class textPart& messageBuilder::textPart()
+{
+ return (*m_textPart);
+}
+
+
+} // vmime
diff --git a/src/messageBuilder.hpp b/src/messageBuilder.hpp
new file mode 100644
index 00000000..ce7d34b1
--- /dev/null
+++ b/src/messageBuilder.hpp
@@ -0,0 +1,99 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGEBUILDER_HPP_INCLUDED
+#define VMIME_MESSAGEBUILDER_HPP_INCLUDED
+
+
+#include "base.hpp"
+
+#include "mailbox.hpp"
+#include "addressList.hpp"
+#include "text.hpp"
+#include "message.hpp"
+#include "mediaType.hpp"
+#include "attachment.hpp"
+#include "textPart.hpp"
+#include "bodyPart.hpp"
+
+
+namespace vmime
+{
+
+
+/** A helper for building MIME messages.
+ */
+
+class messageBuilder
+{
+public:
+
+ messageBuilder();
+ ~messageBuilder();
+
+public:
+
+ // Expeditor and recipients
+ const mailbox& expeditor() const { return (m_from); }
+ mailbox& expeditor() { return (m_from); }
+
+ const addressList& recipients() const { return (m_to); }
+ addressList& recipients() { return (m_to); }
+
+ const addressList& copyRecipients() const { return (m_cc); }
+ addressList& copyRecipients() { return (m_cc); }
+
+ const addressList& blindCopyRecipients() const { return (m_bcc); }
+ addressList& blindCopyRecipients() { return (m_bcc); }
+
+ // Subject
+ const text& subject() const { return (m_subject); }
+ text& subject() { return (m_subject); }
+
+ // Attachements
+ void attach(attachment* attach);
+ const std::vector <attachment*>& attachments() const { return (m_attach); }
+
+ // Text parts
+ void constructTextPart(const mediaType& type);
+ class textPart& textPart();
+
+ // Construction
+ message* construct() const;
+
+protected:
+
+ mailbox m_from;
+
+ addressList m_to;
+ addressList m_cc;
+ addressList m_bcc;
+
+ text m_subject;
+
+ class textPart* m_textPart;
+
+ std::vector <attachment*> m_attach;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_MESSAGEBUILDER_HPP_INCLUDED
diff --git a/src/messageId.cpp b/src/messageId.cpp
new file mode 100644
index 00000000..1ea99d1f
--- /dev/null
+++ b/src/messageId.cpp
@@ -0,0 +1,184 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "messageId.hpp"
+#include "utility/random.hpp"
+#include "platformDependant.hpp"
+#include "parserHelpers.hpp"
+
+
+namespace vmime
+{
+
+
+messageId::messageId()
+{
+}
+
+
+messageId::messageId(const string& id)
+{
+ parse(id);
+}
+
+
+messageId::messageId(const messageId& mid)
+ : component(), m_left(mid.m_left), m_right(mid.m_right)
+{
+}
+
+
+messageId::messageId(const string& left, const string& right)
+ : m_left(left), m_right(right)
+{
+}
+
+
+/*
+ RFC-2822:
+ 3.6.4. Identification fields
+
+ msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]
+*/
+
+void messageId::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ const string::value_type* const pend = buffer.data() + end;
+ const string::value_type* const pstart = buffer.data() + position;
+ const string::value_type* p = pstart;
+
+ m_left.clear();
+ m_right.clear();
+
+ unsigned int commentLevel = 0;
+ bool escape = false;
+ bool stop = false;
+
+ for ( ; !stop && p < pend ; ++p)
+ {
+ if (escape)
+ {
+ // Ignore this character
+ }
+ else
+ {
+ switch (*p)
+ {
+ case '(': ++commentLevel; break;
+ case ')': --commentLevel; break;
+ case '\\': escape = true; break;
+ case '<':
+ {
+ if (commentLevel == 0)
+ {
+ stop = true;
+ break;
+ }
+ }
+
+ }
+ }
+ }
+
+ if (p < pend)
+ {
+ // Extract left part
+ const string::size_type leftStart = position + (p - pstart);
+
+ while (p < pend && *p != '@') ++p;
+
+ m_left = string(buffer.begin() + leftStart,
+ buffer.begin() + position + (p - pstart));
+
+ if (p < pend)
+ {
+ // Skip '@'
+ ++p;
+
+ // Extract right part
+ const string::size_type rightStart = position + (p - pstart);
+
+ while (p < pend && *p != '>') ++p;
+
+ m_right = string(buffer.begin() + rightStart,
+ buffer.begin() + position + (p - pstart));
+ }
+ }
+
+ if (newPosition)
+ *newPosition = end;
+}
+
+
+const string messageId::id() const
+{
+ return (m_left + '@' + m_right);
+}
+
+
+void messageId::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ os << '<' << m_left << '@' << m_right << '>';
+
+ if (newLinePos)
+ *newLinePos = curLinePos + m_left.length() + m_right.length() + 3;
+}
+
+
+messageId& messageId::operator=(const messageId& source)
+{
+ m_left = source.m_left;
+ m_right = source.m_right;
+ return (*this);
+}
+
+
+messageId& messageId::operator=(const string& id)
+{
+ parse(id);
+ return (*this);
+}
+
+
+messageId messageId::generateId()
+{
+ std::ostringstream left;
+
+ left << "vmime";
+ left << '.';
+ left << std::hex << utility::random::time();
+ left << '.';
+ left << std::hex << utility::random::process();
+ left << '.';
+ left << std::hex << utility::random::next();
+ left << std::hex << utility::random::next();
+
+ return (messageId(left.str(), platformDependant::getHandler()->getHostName()));
+}
+
+
+const bool messageId::operator==(const messageId& mid) const
+{
+ return (m_left == mid.m_left && m_right == mid.m_right);
+}
+
+
+} // vmime
diff --git a/src/messageId.hpp b/src/messageId.hpp
new file mode 100644
index 00000000..e280dfaf
--- /dev/null
+++ b/src/messageId.hpp
@@ -0,0 +1,82 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGEID_HPP_INCLUDED
+#define VMIME_MESSAGEID_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+
+
+namespace vmime
+{
+
+
+/** Message identifier (basic type).
+ */
+
+class messageId : public component
+{
+public:
+
+ messageId();
+ messageId(const string& id);
+ messageId(const messageId& mid);
+ messageId(const string& left, const string& right);
+
+public:
+
+ const string& left() const { return (m_left); }
+ string& left() { return (m_left); }
+
+ const string& right() const { return (m_right); }
+ string& right() { return (m_right); }
+
+public:
+
+ messageId& operator=(const messageId& source);
+ messageId& operator=(const string& id);
+
+ const bool operator==(const messageId& mid) const;
+
+ static messageId generateId();
+
+ const string id() const;
+
+protected:
+
+ string m_left;
+ string m_right;
+
+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_MESSAGEID_HPP_INCLUDED
diff --git a/src/messageIdField.cpp b/src/messageIdField.cpp
new file mode 100644
index 00000000..ecdb901c
--- /dev/null
+++ b/src/messageIdField.cpp
@@ -0,0 +1,66 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "messageIdField.hpp"
+
+
+namespace vmime
+{
+
+
+messageIdField::messageIdField()
+{
+}
+
+
+void messageIdField::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ m_id.parse(buffer, position, end, newPosition);
+}
+
+
+void messageIdField::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ string::size_type pos = curLinePos;
+
+ headerField::generate(os, maxLineLength, pos, &pos);
+
+ m_id.generate(os, maxLineLength, pos, newLinePos);
+}
+
+
+messageIdField& messageIdField::operator=(const messageId& mid)
+{
+ m_id = mid;
+ return (*this);
+}
+
+
+void messageIdField::copyFrom(const headerField& field)
+{
+ const messageIdField& source = dynamic_cast<const messageIdField&>(field);
+ m_id = source.m_id;
+
+ headerField::copyFrom(field);
+}
+
+
+} // vmime
diff --git a/src/messageIdField.hpp b/src/messageIdField.hpp
new file mode 100644
index 00000000..4809e5ed
--- /dev/null
+++ b/src/messageIdField.hpp
@@ -0,0 +1,70 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGEIDFIELD_HPP_INCLUDED
+#define VMIME_MESSAGEIDFIELD_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+
+#include "headerFieldFactory.hpp"
+#include "messageId.hpp"
+
+
+namespace vmime
+{
+
+
+class messageIdField : public headerField
+{
+ friend class headerFieldFactory::registerer <messageIdField>;
+
+protected:
+
+ messageIdField();
+
+public:
+
+ void copyFrom(const headerField& field);
+
+ messageIdField& operator=(const messageId& mid);
+
+ const messageId& value() const { return (m_id); }
+ messageId& value() { return (m_id); }
+
+protected:
+
+ messageId m_id;
+
+public:
+
+ using headerField::parse;
+ using headerField::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_MESSAGEIDFIELD_HPP_INCLUDED
diff --git a/src/messageParser.cpp b/src/messageParser.cpp
new file mode 100644
index 00000000..d68c95e9
--- /dev/null
+++ b/src/messageParser.cpp
@@ -0,0 +1,321 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "messageParser.hpp"
+
+#include "defaultAttachment.hpp"
+#include "textPartFactory.hpp"
+
+#include "relayField.hpp"
+
+
+namespace vmime
+{
+
+
+messageParser::messageParser(const string& buffer)
+{
+ vmime::message msg;
+ msg.parse(buffer);
+
+ parse(msg);
+}
+
+
+messageParser::messageParser(const message& msg)
+{
+ parse(msg);
+}
+
+
+messageParser::~messageParser()
+{
+ free_container(m_attach);
+ free_container(m_textParts);
+
+ for (std::map <attachment*, contentDispositionField*>::iterator
+ it = m_attachInfo.begin() ; it != m_attachInfo.end() ; ++it)
+ {
+ delete ((*it).second);
+ }
+}
+
+
+void messageParser::parse(const message& msg)
+{
+ // Header fields (if field is present, copy its value, else do nothing)
+#define TRY_FIELD(x) try { x; } catch (exceptions::no_such_field) { }
+ TRY_FIELD(m_from = dynamic_cast<mailboxField&>(msg.header().fields.find(headerField::From)).value());
+
+ TRY_FIELD(m_to = dynamic_cast<addressListField&>(msg.header().fields.find(headerField::To)).value());
+ TRY_FIELD(m_cc = dynamic_cast<addressListField&>(msg.header().fields.find(headerField::Cc)).value());
+ TRY_FIELD(m_bcc = dynamic_cast<addressListField&>(msg.header().fields.find(headerField::Bcc)).value());
+
+ TRY_FIELD(m_subject = dynamic_cast<textField&>(msg.header().fields.find(headerField::Subject)).value());
+#undef TRY_FIELD
+
+ // Date
+ try
+ {
+ vmime::relayField& recv = static_cast<vmime::relayField&>(msg.header().fields.find(headerField::Received));
+ m_date = recv.date();
+ }
+ catch (vmime::exceptions::no_such_field&)
+ {
+ try
+ {
+ vmime::dateField& date = static_cast<vmime::dateField&>(msg.header().fields.find(headerField::Date));
+ m_date = date.value();
+ }
+ catch (vmime::exceptions::no_such_field&)
+ {
+ m_date = datetime::now();
+ }
+ }
+
+ // Attachments
+ findAttachments(msg);
+
+ // Text parts
+ findTextParts(msg, msg);
+}
+
+
+void messageParser::findAttachments(const bodyPart& part)
+{
+ // We simply search for parts that are not "Content-disposition: inline".
+ for (body::const_iterator p = part.body().parts.begin() ; p != part.body().parts.end() ; ++p)
+ {
+ const header& hdr = (*p).header();
+ const body& bdy = (*p).body();
+
+ // Is this part an attachment?
+ bool isAttachment = false;
+ const contentDispositionField* contentDispField = NULL;
+
+ try
+ {
+ const contentDispositionField& cdf = dynamic_cast<contentDispositionField&>
+ (hdr.fields.find(headerField::ContentDisposition));
+
+ if (cdf.value().name() != dispositionTypes::INLINE)
+ {
+ contentDispField = &cdf;
+ isAttachment = true;
+ }
+ }
+ catch (exceptions::no_such_field)
+ {
+ // No "Content-disposition" field: assume "attachment" if
+ // type is not "text/..." or "multipart/...".
+ mediaType type;
+
+ try
+ {
+ const contentTypeField& ctf = dynamic_cast<contentTypeField&>
+ (hdr.fields.find(headerField::ContentType));
+
+ type = ctf.value();
+ }
+ catch (exceptions::no_such_field)
+ {
+ // No "Content-type" field: assume "application/octet-stream".
+ type = mediaType(mediaTypes::APPLICATION,
+ mediaTypes::APPLICATION_OCTET_STREAM);
+ }
+
+ if (type.type() != mediaTypes::TEXT && type.type() != mediaTypes::MULTIPART)
+ isAttachment = true;
+ }
+
+ if (isAttachment)
+ {
+ // Determine the media type of this attachment
+ mediaType type;
+
+ try
+ {
+ const contentTypeField& ctf = dynamic_cast<contentTypeField&>
+ (hdr.fields.find(headerField::ContentType));
+
+ type = ctf.value();
+ }
+ catch (exceptions::no_such_field)
+ {
+ // No "Content-type" field: assume "application/octet-stream".
+ type = mediaType(mediaTypes::APPLICATION,
+ mediaTypes::APPLICATION_OCTET_STREAM);
+ }
+
+ // Get the description (if available)
+ text description;
+
+ try
+ {
+ const textField& cd = dynamic_cast<textField&>
+ (hdr.fields.find(headerField::ContentDescription));
+
+ description = cd.value();
+ }
+ catch (exceptions::no_such_field)
+ {
+ // No description available.
+ }
+
+ // Construct the attachment object
+ attachment* attach = new defaultAttachment
+ (bdy.contents(), bdy.encoding(), type, description);
+
+ if (contentDispField != NULL)
+ {
+ m_attachInfo.insert(std::map <attachment*, contentDispositionField*>::
+ value_type(attach, static_cast <contentDispositionField*>
+ (contentDispField->clone())));
+ }
+
+ // Add the attachment to the list
+ m_attach.push_back(attach);
+ }
+
+ // Try to find attachments in sub-parts
+ if (bdy.parts.size())
+ findAttachments(*p);
+ }
+}
+
+
+void messageParser::findTextParts(const bodyPart& msg, const bodyPart& part)
+{
+ // Handle the case in which the message is not multipart: if the body part is
+ // "text/*", take this part.
+ if (part.body().parts.count() == 0)
+ {
+ mediaType type(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN);
+ bool accept = false;
+
+ try
+ {
+ const contentTypeField& ctf = dynamic_cast<contentTypeField&>
+ (msg.header().fields.find(headerField::ContentType));
+
+ if (ctf.value().type() == mediaTypes::TEXT)
+ {
+ type = ctf.value();
+ accept = true;
+ }
+ }
+ catch (exceptions::no_such_field)
+ {
+ // No "Content-type" field: assume "text/plain".
+ accept = true;
+ }
+
+ if (accept)
+ {
+ textPart* textPart = textPartFactory::getInstance()->create(type);
+ textPart->parse(msg, msg, msg);
+
+ m_textParts.push_back(textPart);
+ }
+ }
+ // Multipart message
+ else
+ {
+ findSubTextParts(msg, part);
+ }
+}
+
+
+bool messageParser::findSubTextParts(const bodyPart& msg, const bodyPart& part)
+{
+ // In general, all the text parts are contained in parallel in the same
+ // parent part (or message).
+ // So, wherever the text parts are, all we have to do is to find the first
+ // MIME part which is a text part.
+
+ std::vector <const bodyPart*> textParts;
+
+ for (body::const_iterator p = part.body().parts.begin() ;
+ p != part.body().parts.end() ; ++p)
+ {
+ try
+ {
+ const contentTypeField& ctf = dynamic_cast<contentTypeField&>
+ ((*p).header().fields.find(headerField::ContentType));
+
+ if (ctf.value().type() == mediaTypes::TEXT)
+ {
+ textParts.push_back(&(*p));
+ }
+ }
+ catch (exceptions::no_such_field)
+ {
+ // No "Content-type" field.
+ }
+ }
+
+ if (textParts.size())
+ {
+ // Okay. So we have found at least one text part
+ for (std::vector <const bodyPart*>::const_iterator p = textParts.begin() ; p != textParts.end() ; ++p)
+ {
+ const contentTypeField& ctf = dynamic_cast<contentTypeField&>
+ ((*p)->header().fields.find(headerField::ContentType));
+
+ try
+ {
+ textPart* textPart = textPartFactory::getInstance()->create(ctf.value());
+ textPart->parse(msg, part, **p);
+
+ m_textParts.push_back(textPart);
+ }
+ catch (exceptions::no_factory_available& e)
+ {
+ // Content-type not recognized.
+ }
+ }
+
+ //return true;
+ }
+
+ //else
+ {
+ bool found = false;
+
+ for (body::const_iterator p = part.body().parts.begin() ;
+ !found && p != part.body().parts.end() ; ++p)
+ {
+ found = findSubTextParts(msg, *p);
+ }
+
+ return found;
+ }
+}
+
+
+const contentDispositionField* messageParser::attachmentInfo(attachment* a) const
+{
+ std::map <attachment*, contentDispositionField*>::const_iterator
+ it = m_attachInfo.find(a);
+
+ return (it != m_attachInfo.end() ? (*it).second : NULL);
+}
+
+
+} // vmime
diff --git a/src/messageParser.hpp b/src/messageParser.hpp
new file mode 100644
index 00000000..d3dc1478
--- /dev/null
+++ b/src/messageParser.hpp
@@ -0,0 +1,98 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGEPARSER_HPP_INCLUDED
+#define VMIME_MESSAGEPARSER_HPP_INCLUDED
+
+
+#include "base.hpp"
+
+#include "message.hpp"
+#include "attachment.hpp"
+
+#include "textPart.hpp"
+
+
+namespace vmime
+{
+
+
+/** A helper for parsing MIME messages.
+ */
+
+class messageParser
+{
+public:
+
+ messageParser(const string& buffer);
+ messageParser(const message& msg);
+ ~messageParser();
+
+public:
+
+ // Expeditor and recipients
+ const mailbox& expeditor() const { return (m_from); }
+
+ const addressList& recipients() const { return (m_to); }
+ const addressList& copyRecipients() const { return (m_cc); }
+ const addressList& blindCopyRecipients() const { return (m_bcc); }
+
+ // Subject
+ const text& subject() const { return (m_subject); }
+
+ // Date
+ const datetime& date() const { return (m_date); }
+
+ // Attachments
+ const std::vector <attachment*>& attachments() const { return (m_attach); }
+ const contentDispositionField* attachmentInfo(attachment* a) const;
+
+ // Text parts
+ const std::vector <textPart*>& textParts() const { return (m_textParts); }
+
+protected:
+
+ mailbox m_from;
+
+ addressList m_to;
+ addressList m_cc;
+ addressList m_bcc;
+
+ text m_subject;
+
+ datetime m_date;
+
+ std::vector <attachment*> m_attach;
+ std::map <attachment*, contentDispositionField*> m_attachInfo;
+
+ std::vector <textPart*> m_textParts;
+
+ void parse(const message& msg);
+
+ void findAttachments(const bodyPart& part);
+
+ void findTextParts(const bodyPart& msg, const bodyPart& part);
+ bool findSubTextParts(const bodyPart& msg, const bodyPart& part);
+};
+
+
+} // vmime
+
+
+#endif // VMIME_MESSAGEPARSER_HPP_INCLUDED
diff --git a/src/messaging/IMAPConnection.cpp b/src/messaging/IMAPConnection.cpp
new file mode 100644
index 00000000..007cf353
--- /dev/null
+++ b/src/messaging/IMAPConnection.cpp
@@ -0,0 +1,263 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "IMAPTag.hpp"
+#include "IMAPConnection.hpp"
+#include "IMAPUtils.hpp"
+#include "IMAPStore.hpp"
+
+#include "../exception.hpp"
+#include "../platformDependant.hpp"
+
+#include <sstream>
+
+
+namespace vmime {
+namespace messaging {
+
+
+IMAPConnection::IMAPConnection(IMAPStore* store, authenticator* auth)
+ : m_store(store), m_auth(auth), m_socket(NULL), m_parser(NULL), m_tag(NULL),
+ m_hierarchySeparator('\0'), m_state(STATE_NONE), m_timeoutHandler(NULL)
+{
+}
+
+
+IMAPConnection::~IMAPConnection()
+{
+ if (isConnected())
+ disconnect();
+ else if (m_socket)
+ internalDisconnect();
+
+ delete (m_tag);
+ delete (m_parser);
+}
+
+
+void IMAPConnection::connect()
+{
+ if (isConnected())
+ throw exceptions::already_connected();
+
+ m_state = STATE_NONE;
+ m_hierarchySeparator = '\0';
+
+ const string address = m_store->session().properties()[m_store->infos().propertyPrefix() + "server.address"];
+ const port_t port = m_store->session().properties().get(m_store->infos().propertyPrefix() + "server.port", m_store->infos().defaultPort());
+
+ // Create the time-out handler
+ if (session().properties().exists
+ (m_store->infos().propertyPrefix() + "timeout.factory"))
+ {
+ timeoutHandlerFactory* tof = platformDependant::getHandler()->
+ getTimeoutHandlerFactory(session().properties()
+ [m_store->infos().propertyPrefix() + "timeout.factory"]);
+
+ m_timeoutHandler = tof->create();
+ }
+
+ // Create and connect the socket
+ socketFactory* sf = platformDependant::getHandler()->getSocketFactory
+ (m_store->session().properties().get
+ (m_store->infos().propertyPrefix() + "server.socket-factory", string("default")));
+
+ m_socket = sf->create();
+ m_socket->connect(address, port);
+
+ delete (m_tag);
+ m_tag = new IMAPTag();
+
+ delete (m_parser);
+ m_parser = new IMAPParser(m_tag, m_socket, m_timeoutHandler);
+
+
+ setState(STATE_NON_AUTHENTICATED);
+
+
+ // Connection greeting
+ //
+ // eg: C: <connection to server>
+ // --- S: * OK mydomain.org IMAP4rev1 v12.256 server ready
+
+ utility::auto_ptr <IMAPParser::greeting> greet(m_parser->readGreeting());
+
+ if (greet->resp_cond_bye())
+ {
+ internalDisconnect();
+ throw exceptions::connection_greeting_error(m_parser->lastLine());
+ }
+ else if (greet->resp_cond_auth()->condition() != IMAPParser::resp_cond_auth::PREAUTH)
+ {
+ const authenticationInfos auth = m_auth->requestAuthInfos();
+
+ // TODO: other authentication methods
+
+ send(true, "LOGIN " + IMAPUtils::quoteString(auth.username())
+ + " " + IMAPUtils::quoteString(auth.password()), true);
+
+ utility::auto_ptr <IMAPParser::response> resp(m_parser->readResponse());
+
+ if (resp->isBad())
+ {
+ internalDisconnect();
+ throw exceptions::command_error("LOGIN", m_parser->lastLine());
+ }
+ else if (resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ internalDisconnect();
+ throw exceptions::authentication_error(m_parser->lastLine());
+ }
+ }
+
+ // Get the hierarchy separator character
+ initHierarchySeparator();
+
+ // Switch to state "Authenticated"
+ setState(STATE_AUTHENTICATED);
+}
+
+
+const bool IMAPConnection::isConnected() const
+{
+ return (m_socket && m_socket->isConnected() &&
+ (m_state == STATE_AUTHENTICATED || m_state == STATE_SELECTED));
+}
+
+
+void IMAPConnection::disconnect()
+{
+ if (!isConnected())
+ throw exceptions::not_connected();
+
+ internalDisconnect();
+}
+
+
+void IMAPConnection::internalDisconnect()
+{
+ send(true, "LOGOUT", true);
+
+ m_socket->disconnect();
+
+ delete (m_socket);
+ m_socket = NULL;
+
+ delete (m_timeoutHandler);
+ m_timeoutHandler = NULL;
+
+ m_state = STATE_LOGOUT;
+}
+
+
+void IMAPConnection::initHierarchySeparator()
+{
+ send(true, "LIST \"\" \"\"", true);
+
+ utility::auto_ptr <IMAPParser::response> resp(m_parser->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ internalDisconnect();
+ throw exceptions::command_error("LIST", m_parser->lastLine(), "bad response");
+ }
+
+ const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
+ resp->continue_req_or_response_data();
+
+ if (respDataList.size() < 1 || respDataList[0]->response_data() == NULL)
+ {
+ internalDisconnect();
+ throw exceptions::command_error("LIST", m_parser->lastLine(), "unexpected response");
+ }
+
+ const IMAPParser::mailbox_data* mailboxData =
+ static_cast <const IMAPParser::response_data*>(respDataList[0]->response_data())->
+ mailbox_data();
+
+ if (mailboxData == NULL || mailboxData->type() != IMAPParser::mailbox_data::LIST)
+ {
+ internalDisconnect();
+ throw exceptions::command_error("LIST", m_parser->lastLine(), "invalid type");
+ }
+
+ if (mailboxData->mailbox_list()->quoted_char() == '\0')
+ {
+ internalDisconnect();
+ throw exceptions::command_error("LIST", m_parser->lastLine(), "no hierarchy separator");
+ }
+
+ m_hierarchySeparator = mailboxData->mailbox_list()->quoted_char();
+}
+
+
+void IMAPConnection::send(bool tag, const string& what, bool end)
+{
+#if VMIME_DEBUG
+ std::ostringstream oss;
+
+ if (tag)
+ {
+ ++(*m_tag);
+
+ oss << (string) *m_tag;
+ oss << " ";
+ }
+
+ oss << what;
+
+ if (end)
+ oss << "\r\n";
+
+ m_socket->send(oss.str());
+#else
+ if (tag)
+ {
+ ++(*m_tag);
+
+ m_socket->send(*m_tag);
+ m_socket->send(" ");
+ }
+
+ m_socket->send(what);
+
+ if (end)
+ {
+ m_socket->send("\r\n");
+ }
+#endif
+}
+
+
+void IMAPConnection::sendRaw(const char* buffer, const int count)
+{
+ m_socket->sendRaw(buffer, count);
+}
+
+
+IMAPParser::response* IMAPConnection::readResponse(IMAPParser::literalHandler* lh)
+{
+ return (m_parser->readResponse(lh));
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/IMAPConnection.hpp b/src/messaging/IMAPConnection.hpp
new file mode 100644
index 00000000..ae92f1e3
--- /dev/null
+++ b/src/messaging/IMAPConnection.hpp
@@ -0,0 +1,110 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_IMAPCONNECTION_HPP_INCLUDED
+#define VMIME_MESSAGING_IMAPCONNECTION_HPP_INCLUDED
+
+
+#include "authenticator.hpp"
+#include "socket.hpp"
+#include "../config.hpp"
+#include "timeoutHandler.hpp"
+
+#include "IMAPParser.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+class IMAPTag;
+class IMAPStore;
+
+
+class IMAPConnection
+{
+public:
+
+ IMAPConnection(IMAPStore* store, authenticator* auth);
+ ~IMAPConnection();
+
+
+ void connect();
+ const bool isConnected() const;
+ void disconnect();
+
+
+ enum ProtocolStates
+ {
+ STATE_NONE,
+ STATE_NON_AUTHENTICATED,
+ STATE_AUTHENTICATED,
+ STATE_SELECTED,
+ STATE_LOGOUT
+ };
+
+ const ProtocolStates state() const { return (m_state); }
+ void setState(const ProtocolStates state) { m_state = state; }
+
+
+ const char hierarchySeparator() const { return (m_hierarchySeparator); }
+
+
+ void send(bool tag, const string& what, bool end);
+ void sendRaw(const char* buffer, const int count);
+
+ IMAPParser::response* readResponse(IMAPParser::literalHandler* lh = NULL);
+
+
+ const IMAPTag* tag() const { return (m_tag); }
+ const IMAPParser* parser() const { return (m_parser); }
+
+ const IMAPStore* store() const { return (m_store); }
+ IMAPStore* store() { return (m_store); }
+
+private:
+
+ IMAPStore* m_store;
+
+ authenticator* m_auth;
+
+ socket* m_socket;
+
+ IMAPParser* m_parser;
+
+ IMAPTag* m_tag;
+
+ char m_hierarchySeparator;
+
+ ProtocolStates m_state;
+
+ timeoutHandler* m_timeoutHandler;
+
+
+ void internalDisconnect();
+
+ void initHierarchySeparator();
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_IMAPCONNECTION_HPP_INCLUDED
diff --git a/src/messaging/IMAPFolder.cpp b/src/messaging/IMAPFolder.cpp
new file mode 100644
index 00000000..717e4817
--- /dev/null
+++ b/src/messaging/IMAPFolder.cpp
@@ -0,0 +1,1490 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "IMAPFolder.hpp"
+
+#include "IMAPStore.hpp"
+#include "IMAPParser.hpp"
+#include "IMAPMessage.hpp"
+#include "IMAPUtils.hpp"
+#include "IMAPConnection.hpp"
+
+#include "../exception.hpp"
+#include "../utility/smartPtr.hpp"
+
+#include <algorithm>
+#include <sstream>
+
+
+namespace vmime {
+namespace messaging {
+
+
+IMAPFolder::IMAPFolder(const folder::path& path, IMAPStore* store, const int type, const int flags)
+ : m_store(store), m_connection(m_store->connection()), m_path(path),
+ m_name(path.last()), m_mode(-1), m_open(false), m_type(type), m_flags(flags),
+ m_messageCount(0), m_uidValidity(0)
+{
+ m_store->registerFolder(this);
+}
+
+
+IMAPFolder::~IMAPFolder()
+{
+ if (m_store)
+ {
+ if (m_open)
+ close(false);
+
+ m_store->unregisterFolder(this);
+ }
+ else if (m_open)
+ {
+ delete (m_connection);
+ onClose();
+ }
+}
+
+
+const int IMAPFolder::mode() const
+{
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ return (m_mode);
+}
+
+
+const int IMAPFolder::type()
+{
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ // Root folder
+ if (m_path.empty())
+ {
+ return (TYPE_CONTAINS_FOLDERS);
+ }
+ else
+ {
+ if (m_type == TYPE_UNDEFINED)
+ testExistAndGetType();
+
+ return (m_type);
+ }
+}
+
+
+const int IMAPFolder::flags()
+{
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ // Root folder
+ if (m_path.empty())
+ {
+ return (FLAG_CHILDREN | FLAG_NO_OPEN);
+ }
+ else
+ {
+ if (m_flags == FLAG_UNDEFINED)
+ testExistAndGetType();
+
+ return (m_flags);
+ }
+}
+
+
+const folder::path::component IMAPFolder::name() const
+{
+ return (m_name);
+}
+
+
+const folder::path IMAPFolder::fullPath() const
+{
+ return (m_path);
+}
+
+
+void IMAPFolder::open(const int mode, bool failIfModeIsNotAvailable)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+
+ // Open a connection for this folder
+ IMAPConnection* connection =
+ new IMAPConnection(m_store, m_store->oneTimeAuthenticator());
+
+ try
+ {
+ connection->connect();
+
+ // Emit the "SELECT" command
+ //
+ // Example: C: A142 SELECT INBOX
+ // S: * 172 EXISTS
+ // S: * 1 RECENT
+ // S: * OK [UNSEEN 12] Message 12 is first unseen
+ // S: * OK [UIDVALIDITY 3857529045] UIDs valid
+ // S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+ // S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
+ // S: A142 OK [READ-WRITE] SELECT completed
+
+ std::ostringstream oss;
+
+ if (mode == MODE_READ_ONLY)
+ oss << "EXAMINE ";
+ else
+ oss << "SELECT ";
+
+ oss << IMAPUtils::quoteString(IMAPUtils::pathToString
+ (connection->hierarchySeparator(), fullPath()));
+
+ connection->send(true, oss.str(), true);
+
+ // Read the response
+ utility::auto_ptr <IMAPParser::response> resp(connection->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("SELECT",
+ connection->parser()->lastLine(), "bad response");
+ }
+
+ const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
+ resp->continue_req_or_response_data();
+
+ for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
+ it = respDataList.begin() ; it != respDataList.end() ; ++it)
+ {
+ if ((*it)->response_data() == NULL)
+ {
+ throw exceptions::command_error("SELECT",
+ connection->parser()->lastLine(), "invalid response");
+ }
+
+ const IMAPParser::response_data* responseData = (*it)->response_data();
+
+ // OK Untagged responses: UNSEEN, PERMANENTFLAGS, UIDVALIDITY (optional)
+ if (responseData->resp_cond_state())
+ {
+ const IMAPParser::resp_text_code* code =
+ responseData->resp_cond_state()->resp_text()->resp_text_code();
+
+ if (code != NULL)
+ {
+ switch (code->type())
+ {
+ case IMAPParser::resp_text_code::UIDVALIDITY:
+
+ m_uidValidity = code->nz_number()->value();
+ break;
+
+ default:
+
+ break;
+ }
+ }
+ }
+ // Untagged responses: FLAGS, EXISTS, RECENT (required)
+ else if (responseData->mailbox_data())
+ {
+ switch (responseData->mailbox_data()->type())
+ {
+ default: break;
+
+ case IMAPParser::mailbox_data::FLAGS:
+ {
+ m_type = IMAPUtils::folderTypeFromFlags
+ (responseData->mailbox_data()->mailbox_flag_list());
+
+ m_flags = IMAPUtils::folderFlagsFromFlags
+ (responseData->mailbox_data()->mailbox_flag_list());
+
+ break;
+ }
+ case IMAPParser::mailbox_data::EXISTS:
+ {
+ m_messageCount = responseData->mailbox_data()->number()->value();
+ break;
+ }
+ case IMAPParser::mailbox_data::RECENT:
+ {
+ // TODO
+ break;
+ }
+
+ }
+ }
+ }
+
+ // Check for access mode (read-only or read-write)
+ const IMAPParser::resp_text_code* respTextCode = resp->response_done()->
+ response_tagged()->resp_cond_state()->resp_text()->resp_text_code();
+
+ if (respTextCode)
+ {
+ const int openMode =
+ (respTextCode->type() == IMAPParser::resp_text_code::READ_WRITE)
+ ? MODE_READ_WRITE : MODE_READ_ONLY;
+
+ if (failIfModeIsNotAvailable &&
+ mode == MODE_READ_WRITE && openMode == MODE_READ_ONLY)
+ {
+ throw exceptions::operation_not_supported();
+ }
+ }
+
+
+ m_connection = connection;
+ m_open = true;
+ m_mode = mode;
+ }
+ catch (std::exception&)
+ {
+ delete (connection);
+ throw;
+ }
+}
+
+
+void IMAPFolder::close(const bool expunge)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ IMAPConnection* oldConnection = m_connection;
+
+ // Emit the "CLOSE" command to expunge messages marked
+ // as deleted (this is fastest than "EXPUNGE")
+ if (expunge)
+ {
+ if (m_mode == MODE_READ_ONLY)
+ throw exceptions::operation_not_supported();
+
+ oldConnection->send(true, "CLOSE", true);
+ }
+
+ // Close this folder connection
+ oldConnection->disconnect();
+
+ // Now use default store connection
+ m_connection = m_store->connection();
+
+ m_open = false;
+ m_mode = -1;
+
+ m_uidValidity = 0;
+
+ onClose();
+
+ delete (oldConnection);
+}
+
+
+void IMAPFolder::onClose()
+{
+ for (std::vector <IMAPMessage*>::iterator it = m_messages.begin() ;
+ it != m_messages.end() ; ++it)
+ {
+ (*it)->onFolderClosed();
+ }
+
+ m_messages.clear();
+}
+
+
+void IMAPFolder::create(const int type)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (isOpen())
+ throw exceptions::illegal_state("Folder is open");
+ else if (exists())
+ throw exceptions::illegal_state("Folder already exists");
+
+ // Emit the "CREATE" command
+ //
+ // Example: C: A003 CREATE owatagusiam/
+ // S: A003 OK CREATE completed
+ // C: A004 CREATE owatagusiam/blurdybloop
+ // S: A004 OK CREATE completed
+
+ string mailbox = IMAPUtils::pathToString
+ (m_connection->hierarchySeparator(), fullPath());
+
+ if (type & TYPE_CONTAINS_FOLDERS)
+ mailbox += m_connection->hierarchySeparator();
+
+ std::ostringstream oss;
+ oss << "CREATE " << IMAPUtils::quoteString(mailbox);
+
+ m_connection->send(true, oss.str(), true);
+
+
+ utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("CREATE",
+ m_connection->parser()->lastLine(), "bad response");
+ }
+
+ // Notify folder created
+ events::folderEvent event(this, events::folderEvent::TYPE_CREATED, m_path, m_path);
+ notifyFolder(event);
+}
+
+
+const bool IMAPFolder::exists()
+{
+ if (!isOpen() && !m_store)
+ throw exceptions::illegal_state("Store disconnected");
+
+ return (testExistAndGetType() != TYPE_UNDEFINED);
+}
+
+
+const int IMAPFolder::testExistAndGetType()
+{
+ m_type = TYPE_UNDEFINED;
+
+ // To test whether a folder exists, we simple list it using
+ // the "LIST" command, and there should be one unique mailbox
+ // with this name...
+ //
+ // Eg. Test whether '/foo/bar' exists
+ //
+ // C: a005 list "" foo/bar
+ // S: * LIST (\NoSelect) "/" foo/bar
+ // S: a005 OK LIST completed
+ //
+ // ==> OK, exists
+ //
+ // Test whether '/foo/bar/zap' exists
+ //
+ // C: a005 list "" foo/bar/zap
+ // S: a005 OK LIST completed
+ //
+ // ==> NO, does not exist
+
+ std::ostringstream oss;
+ oss << "LIST \"\" ";
+ oss << IMAPUtils::quoteString(IMAPUtils::pathToString
+ (m_connection->hierarchySeparator(), fullPath()));
+
+ m_connection->send(true, oss.str(), true);
+
+
+ utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("LIST",
+ m_connection->parser()->lastLine(), "bad response");
+ }
+
+ // Check whether the result mailbox list contains this folder
+ const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
+ resp->continue_req_or_response_data();
+
+ for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
+ it = respDataList.begin() ; it != respDataList.end() ; ++it)
+ {
+ if ((*it)->response_data() == NULL)
+ {
+ throw exceptions::command_error("LIST",
+ m_connection->parser()->lastLine(), "invalid response");
+ }
+
+ const IMAPParser::mailbox_data* mailboxData =
+ (*it)->response_data()->mailbox_data();
+
+ // We are only interested in responses of type "LIST"
+ if (mailboxData != NULL && mailboxData->type() == IMAPParser::mailbox_data::LIST)
+ {
+ // Get the folder type/flags at the same time
+ m_type = IMAPUtils::folderTypeFromFlags
+ (mailboxData->mailbox_list()->mailbox_flag_list());
+
+ m_flags = IMAPUtils::folderFlagsFromFlags
+ (mailboxData->mailbox_list()->mailbox_flag_list());
+ }
+ }
+
+ return (m_type);
+}
+
+
+const bool IMAPFolder::isOpen() const
+{
+ return (m_open);
+}
+
+
+message* IMAPFolder::getMessage(const int num)
+{
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ if (num < 1 || num > m_messageCount)
+ throw exceptions::message_not_found();
+
+ return new IMAPMessage(this, num);
+}
+
+
+std::vector <message*> IMAPFolder::getMessages(const int from, const int to)
+{
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ std::vector <message*> v;
+
+ for (int i = from ; i <= to ; ++i)
+ v.push_back(new IMAPMessage(this, i));
+
+ return (v);
+}
+
+
+std::vector <message*> IMAPFolder::getMessages(const std::vector <int>& nums)
+{
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ std::vector <message*> v;
+
+ for (std::vector <int>::const_iterator it = nums.begin() ; it != nums.end() ; ++it)
+ v.push_back(new IMAPMessage(this, *it));
+
+ return (v);
+}
+
+
+const int IMAPFolder::getMessageCount()
+{
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ return (m_messageCount);
+}
+
+
+folder* IMAPFolder::getFolder(const folder::path::component& name)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+
+ return new IMAPFolder(m_path / name, m_store);
+}
+
+
+std::vector <folder*> IMAPFolder::getFolders(const bool recursive)
+{
+ if (!isOpen() && !m_store)
+ throw exceptions::illegal_state("Store disconnected");
+
+ // Eg. List folders in '/foo/bar'
+ //
+ // C: a005 list "foo/bar" *
+ // S: * LIST (\NoSelect) "/" foo/bar
+ // S: * LIST (\NoInferiors) "/" foo/bar/zap
+ // S: a005 OK LIST completed
+
+ std::ostringstream oss;
+ oss << "LIST ";
+ oss << IMAPUtils::quoteString
+ (IMAPUtils::pathToString(m_connection->hierarchySeparator(), fullPath()));
+
+ if (recursive)
+ oss << " *";
+ else
+ oss << " %";
+
+ m_connection->send(true, oss.str(), true);
+
+
+ utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("LIST", m_connection->parser()->lastLine(), "bad response");
+ }
+
+ const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
+ resp->continue_req_or_response_data();
+
+
+ std::vector <folder*> v;
+
+ try
+ {
+ for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
+ it = respDataList.begin() ; it != respDataList.end() ; ++it)
+ {
+ if ((*it)->response_data() == NULL)
+ {
+ throw exceptions::command_error("LIST",
+ m_connection->parser()->lastLine(), "invalid response");
+ }
+
+ const IMAPParser::mailbox_data* mailboxData =
+ (*it)->response_data()->mailbox_data();
+
+ if (mailboxData == NULL || mailboxData->type() != IMAPParser::mailbox_data::LIST)
+ continue;
+
+ // Get folder path
+ const class IMAPParser::mailbox* mailbox =
+ mailboxData->mailbox_list()->mailbox();
+
+ folder::path path = IMAPUtils::stringToPath
+ (mailboxData->mailbox_list()->quoted_char(), mailbox->name());
+
+ if (recursive || m_path.isDirectParentOf(path))
+ {
+ // Append folder to list
+ const class IMAPParser::mailbox_flag_list* mailbox_flag_list =
+ mailboxData->mailbox_list()->mailbox_flag_list();
+
+ v.push_back(new IMAPFolder(path, m_store,
+ IMAPUtils::folderTypeFromFlags(mailbox_flag_list),
+ IMAPUtils::folderFlagsFromFlags(mailbox_flag_list)));
+ }
+ }
+ }
+ catch (std::exception&)
+ {
+ for (std::vector <folder*>::iterator it = v.begin() ; it != v.end() ; ++it)
+ delete (*it);
+
+ throw;
+ }
+
+ return (v);
+}
+
+
+void IMAPFolder::fetchMessages(std::vector <message*>& msg, const int options,
+ progressionListener* progress)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ const int total = msg.size();
+ int current = 0;
+
+ if (progress)
+ progress->start(total);
+
+ for (std::vector <message*>::iterator it = msg.begin() ;
+ it != msg.end() ; ++it)
+ {
+ dynamic_cast <IMAPMessage*>(*it)->fetch(this, options);
+
+ if (progress)
+ progress->progress(++current, total);
+ }
+
+ if (progress)
+ progress->stop(total);
+}
+
+
+void IMAPFolder::fetchMessage(message* msg, const int options)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ dynamic_cast <IMAPMessage*>(msg)->fetch(this, options);
+}
+
+
+const int IMAPFolder::getFetchCapabilities() const
+{
+ return (FETCH_ENVELOPE | FETCH_CONTENT_INFO | FETCH_STRUCTURE |
+ FETCH_FLAGS | FETCH_SIZE | FETCH_FULL_HEADER | FETCH_UID);
+}
+
+
+folder* IMAPFolder::getParent()
+{
+ return (m_path.empty() ? NULL : new IMAPFolder(m_path.parent(), m_store));
+}
+
+
+const class store& IMAPFolder::store() const
+{
+ return (*m_store);
+}
+
+
+class store& IMAPFolder::store()
+{
+ return (*m_store);
+}
+
+
+void IMAPFolder::registerMessage(IMAPMessage* msg)
+{
+ m_messages.push_back(msg);
+}
+
+
+void IMAPFolder::unregisterMessage(IMAPMessage* msg)
+{
+ std::remove(m_messages.begin(), m_messages.end(), msg);
+}
+
+
+void IMAPFolder::onStoreDisconnected()
+{
+ m_store = NULL;
+}
+
+
+void IMAPFolder::deleteMessage(const int num)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+ else if (m_mode == MODE_READ_ONLY)
+ throw exceptions::illegal_state("Folder is read-only");
+
+ // Build the request text
+ std::ostringstream command;
+ command << "STORE " << num << " +FLAGS.SILENT (\\Deleted)";
+
+ // Send the request
+ m_connection->send(true, command.str(), true);
+
+ // Get the response
+ utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("STORE",
+ m_connection->parser()->lastLine(), "bad response");
+ }
+
+ // Update local flags
+ for (std::vector <IMAPMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it)
+ {
+ if ((*it)->number() == num &&
+ (*it)->m_flags != message::FLAG_UNDEFINED)
+ {
+ (*it)->m_flags |= message::FLAG_DELETED;
+ }
+ }
+
+ // Notify message flags changed
+ std::vector <int> nums;
+ nums.push_back(num);
+
+ events::messageChangedEvent event(this, events::messageChangedEvent::TYPE_FLAGS, nums);
+
+ notifyMessageChanged(event);
+}
+
+
+void IMAPFolder::deleteMessages(const int from, const int to)
+{
+ if (from < 1 || (to < from && to != -1))
+ throw exceptions::invalid_argument();
+
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+ else if (m_mode == MODE_READ_ONLY)
+ throw exceptions::illegal_state("Folder is read-only");
+
+ // Build the request text
+ std::ostringstream command;
+ command << "STORE " << from << ":";
+
+ if (to == -1) command << m_messageCount;
+ else command << to;
+
+ command << " +FLAGS.SILENT (\\Deleted)";
+
+ // Send the request
+ m_connection->send(true, command.str(), true);
+
+ // Get the response
+ utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("STORE",
+ m_connection->parser()->lastLine(), "bad response");
+ }
+
+ // Update local flags
+ const int to2 = (to == -1) ? m_messageCount : to;
+ const int count = to - from + 1;
+
+ for (std::vector <IMAPMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it)
+ {
+ if ((*it)->number() >= from && (*it)->number() <= to2 &&
+ (*it)->m_flags != message::FLAG_UNDEFINED)
+ {
+ (*it)->m_flags |= message::FLAG_DELETED;
+ }
+ }
+
+ // Notify message flags changed
+ std::vector <int> nums;
+ nums.resize(count);
+
+ for (int i = from, j = 0 ; i <= to2 ; ++i, ++j)
+ nums[j] = i;
+
+ events::messageChangedEvent event(this, events::messageChangedEvent::TYPE_FLAGS, nums);
+
+ notifyMessageChanged(event);
+}
+
+
+void IMAPFolder::deleteMessages(const std::vector <int>& nums)
+{
+ if (nums.empty())
+ throw exceptions::invalid_argument();
+
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+ else if (m_mode == MODE_READ_ONLY)
+ throw exceptions::illegal_state("Folder is read-only");
+
+ // Sort the list of message numbers
+ std::vector <int> list;
+
+ list.resize(nums.size());
+ std::copy(nums.begin(), nums.end(), list.begin());
+
+ std::sort(list.begin(), list.end());
+
+ // Build the request text
+ std::ostringstream command;
+ command << "STORE ";
+ command << IMAPUtils::listToSet(list, m_messageCount, true);
+ command << " +FLAGS.SILENT (\\Deleted)";
+
+ // Send the request
+ m_connection->send(true, command.str(), true);
+
+ // Get the response
+ utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("STORE",
+ m_connection->parser()->lastLine(), "bad response");
+ }
+
+ // Update local flags
+ for (std::vector <IMAPMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it)
+ {
+ if (std::binary_search(list.begin(), list.end(), (*it)->number()))
+ {
+ if ((*it)->m_flags != message::FLAG_UNDEFINED)
+ (*it)->m_flags |= message::FLAG_DELETED;
+ }
+ }
+
+ // Notify message flags changed
+ events::messageChangedEvent event(this, events::messageChangedEvent::TYPE_FLAGS, list);
+
+ notifyMessageChanged(event);
+}
+
+
+void IMAPFolder::setMessageFlags(const int from, const int to, const int flags, const int mode)
+{
+ if (from < 1 || (to < from && to != -1))
+ throw exceptions::invalid_argument();
+
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+ else if (m_mode == MODE_READ_ONLY)
+ throw exceptions::illegal_state("Folder is read-only");
+
+ std::ostringstream oss;
+
+ if (to == -1)
+ oss << from << ":*";
+ else
+ oss << from << ":" << to;
+
+ setMessageFlags(oss.str(), flags, mode);
+
+ // Update local flags
+ const int to2 = (to == -1) ? m_messageCount : to;
+ const int count = to - from + 1;
+
+ switch (mode)
+ {
+ case message::FLAG_MODE_ADD:
+ {
+ for (std::vector <IMAPMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it)
+ {
+ if ((*it)->number() >= from && (*it)->number() <= to2 &&
+ (*it)->m_flags != message::FLAG_UNDEFINED)
+ {
+ (*it)->m_flags |= flags;
+ }
+ }
+
+ break;
+ }
+ case message::FLAG_MODE_REMOVE:
+ {
+ for (std::vector <IMAPMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it)
+ {
+ if ((*it)->number() >= from && (*it)->number() <= to2 &&
+ (*it)->m_flags != message::FLAG_UNDEFINED)
+ {
+ (*it)->m_flags &= ~flags;
+ }
+ }
+
+ break;
+ }
+ default:
+ case message::FLAG_MODE_SET:
+ {
+ for (std::vector <IMAPMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it)
+ {
+ if ((*it)->number() >= from && (*it)->number() <= to2 &&
+ (*it)->m_flags != message::FLAG_UNDEFINED)
+ {
+ (*it)->m_flags = flags;
+ }
+ }
+
+ break;
+ }
+
+ }
+
+ // Notify message flags changed
+ std::vector <int> nums;
+ nums.resize(count);
+
+ for (int i = from, j = 0 ; i <= to2 ; ++i, ++j)
+ nums[j] = i;
+
+ events::messageChangedEvent event(this, events::messageChangedEvent::TYPE_FLAGS, nums);
+
+ notifyMessageChanged(event);
+}
+
+
+void IMAPFolder::setMessageFlags(const std::vector <int>& nums, const int flags, const int mode)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+ else if (m_mode == MODE_READ_ONLY)
+ throw exceptions::illegal_state("Folder is read-only");
+
+ // Sort the list of message numbers
+ std::vector <int> list;
+
+ list.resize(nums.size());
+ std::copy(nums.begin(), nums.end(), list.begin());
+
+ std::sort(list.begin(), list.end());
+
+ // Delegates call
+ setMessageFlags(IMAPUtils::listToSet(list, m_messageCount, true), flags, mode);
+
+ // Update local flags
+ switch (mode)
+ {
+ case message::FLAG_MODE_ADD:
+ {
+ for (std::vector <IMAPMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it)
+ {
+ if (std::binary_search(list.begin(), list.end(), (*it)->number()) &&
+ (*it)->m_flags != message::FLAG_UNDEFINED)
+ {
+ (*it)->m_flags |= flags;
+ }
+ }
+
+ break;
+ }
+ case message::FLAG_MODE_REMOVE:
+ {
+ for (std::vector <IMAPMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it)
+ {
+ if (std::binary_search(list.begin(), list.end(), (*it)->number()) &&
+ (*it)->m_flags != message::FLAG_UNDEFINED)
+ {
+ (*it)->m_flags &= ~flags;
+ }
+ }
+
+ break;
+ }
+ default:
+ case message::FLAG_MODE_SET:
+ {
+ for (std::vector <IMAPMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it)
+ {
+ if (std::binary_search(list.begin(), list.end(), (*it)->number()) &&
+ (*it)->m_flags != message::FLAG_UNDEFINED)
+ {
+ (*it)->m_flags = flags;
+ }
+ }
+
+ break;
+ }
+
+ }
+
+ // Notify message flags changed
+ events::messageChangedEvent event(this, events::messageChangedEvent::TYPE_FLAGS, nums);
+
+ notifyMessageChanged(event);
+}
+
+
+void IMAPFolder::setMessageFlags(const string& set, const int flags, const int mode)
+{
+ // Build the request text
+ std::ostringstream command;
+ command << "STORE " << set;
+
+ switch (mode)
+ {
+ case message::FLAG_MODE_ADD: command << " +FLAGS.SILENT "; break;
+ case message::FLAG_MODE_REMOVE: command << " -FLAGS.SILENT "; break;
+ default:
+ case message::FLAG_MODE_SET: command << " FLAGS.SILENT "; break;
+ }
+
+ const string flagList = IMAPUtils::messageFlagList(flags);
+
+ if (!flagList.empty())
+ {
+ command << flagList;
+
+ // Send the request
+ m_connection->send(true, command.str(), true);
+
+ // Get the response
+ utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("STORE",
+ m_connection->parser()->lastLine(), "bad response");
+ }
+ }
+}
+
+
+void IMAPFolder::addMessage(vmime::message* msg, const int flags,
+ vmime::datetime* date, progressionListener* progress)
+{
+ std::ostringstream oss;
+ utility::outputStreamAdapter ossAdapter(oss);
+
+ msg->generate(ossAdapter);
+
+ const std::string& str = oss.str();
+ utility::inputStreamStringAdapter strAdapter(str);
+
+ addMessage(strAdapter, str.length(), flags, date, progress);
+}
+
+
+void IMAPFolder::addMessage(utility::inputStream& is, const int size, const int flags,
+ vmime::datetime* date, progressionListener* progress)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+ else if (m_mode == MODE_READ_ONLY)
+ throw exceptions::illegal_state("Folder is read-only");
+
+ // Build the request text
+ std::ostringstream command;
+ command << "APPEND " << IMAPUtils::quoteString(IMAPUtils::pathToString
+ (m_connection->hierarchySeparator(), fullPath())) << ' ';
+
+ const string flagList = IMAPUtils::messageFlagList(flags);
+
+ if (flags != message::FLAG_UNDEFINED && !flagList.empty())
+ {
+ command << flagList;
+ command << ' ';
+ }
+
+ if (date != NULL)
+ {
+ command << IMAPUtils::dateTime(*date);
+ command << ' ';
+ }
+
+ command << '{' << size << '}';
+
+ // Send the request
+ m_connection->send(true, command.str(), true);
+
+ // Get the response
+ utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ bool ok = false;
+ const std::vector <IMAPParser::continue_req_or_response_data*>& respList
+ = resp->continue_req_or_response_data();
+
+ for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
+ it = respList.begin() ; !ok && (it != respList.end()) ; ++it)
+ {
+ if ((*it)->continue_req())
+ ok = true;
+ }
+
+ if (!ok)
+ {
+ throw exceptions::command_error("APPEND",
+ m_connection->parser()->lastLine(), "bad response");
+ }
+
+ // Send message data
+ const int total = size;
+ int current = 0;
+
+ if (progress)
+ progress->start(total);
+
+ char buffer[65536];
+
+ while (!is.eof())
+ {
+ // Read some data from the input stream
+ const int read = is.read(buffer, sizeof(buffer));
+ current += read;
+
+ // Put read data into socket output stream
+ m_connection->sendRaw(buffer, read);
+
+ // Notify progression
+ if (progress)
+ progress->progress(current, total);
+ }
+
+ m_connection->send(false, "", true);
+
+ if (progress)
+ progress->stop(total);
+
+ // Get the response
+ utility::auto_ptr <IMAPParser::response> finalResp(m_connection->readResponse());
+
+ if (finalResp->isBad() || finalResp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("APPEND",
+ m_connection->parser()->lastLine(), "bad response");
+ }
+
+ // Notify message added
+ std::vector <int> nums;
+ nums.push_back(m_messageCount + 1);
+
+ events::messageCountEvent event(this, events::messageCountEvent::TYPE_ADDED, nums);
+
+ m_messageCount++;
+ notifyMessageCount(event);
+}
+
+
+void IMAPFolder::expunge()
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+ else if (m_mode == MODE_READ_ONLY)
+ throw exceptions::illegal_state("Folder is read-only");
+
+ // Send the request
+ m_connection->send(true, "EXPUNGE", true);
+
+ // Get the response
+ utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("EXPUNGE",
+ m_connection->parser()->lastLine(), "bad response");
+ }
+
+ // Update the numbering of the messages
+ const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
+ resp->continue_req_or_response_data();
+
+ std::vector <int> nums;
+
+ for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
+ it = respDataList.begin() ; it != respDataList.end() ; ++it)
+ {
+ if ((*it)->response_data() == NULL)
+ {
+ throw exceptions::command_error("EXPUNGE",
+ m_connection->parser()->lastLine(), "invalid response");
+ }
+
+ const IMAPParser::message_data* messageData =
+ (*it)->response_data()->message_data();
+
+ // We are only interested in responses of type "EXPUNGE"
+ if (messageData == NULL ||
+ messageData->type() != IMAPParser::message_data::EXPUNGE)
+ {
+ continue;
+ }
+
+ const int number = messageData->number();
+
+ nums.push_back(number);
+
+ for (std::vector <IMAPMessage*>::iterator jt =
+ m_messages.begin() ; jt != m_messages.end() ; ++jt)
+ {
+ if ((*jt)->m_num == number)
+ (*jt)->m_expunged = true;
+ else if ((*jt)->m_num > number)
+ (*jt)->m_num--;
+ }
+ }
+
+ // Notify message expunged
+ events::messageCountEvent event(this, events::messageCountEvent::TYPE_REMOVED, nums);
+
+ m_messageCount -= nums.size();
+ notifyMessageCount(event);
+}
+
+
+void IMAPFolder::rename(const folder::path& newPath)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (isOpen())
+ throw exceptions::illegal_state("Folder open");
+
+ // Build the request text
+ std::ostringstream command;
+ command << "RENAME ";
+ command << IMAPUtils::quoteString(IMAPUtils::pathToString
+ (m_connection->hierarchySeparator(), fullPath())) << " ";
+ command << IMAPUtils::quoteString(IMAPUtils::pathToString
+ (m_connection->hierarchySeparator(), newPath));
+
+ // Send the request
+ m_connection->send(true, command.str(), true);
+
+ // Get the response
+ utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("RENAME",
+ m_connection->parser()->lastLine(), "bad response");
+ }
+
+ // Notify folder renamed
+ folder::path oldPath(m_path);
+
+ m_path = newPath;
+ m_name = newPath.last();
+
+ events::folderEvent event(this, events::folderEvent::TYPE_RENAMED, oldPath, newPath);
+ notifyFolder(event);
+}
+
+
+void IMAPFolder::copyMessage(const folder::path& dest, const int num)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ // Construct set
+ std::ostringstream set;
+ set << num;
+
+ // Delegate message copy
+ copyMessages(set.str(), dest);
+
+ // Notify message count changed
+ std::vector <int> nums;
+ nums.push_back(num);
+
+ events::messageCountEvent event(this, events::messageCountEvent::TYPE_ADDED, nums);
+
+ for (std::list <IMAPFolder*>::iterator it = m_store->m_folders.begin() ;
+ it != m_store->m_folders.end() ; ++it)
+ {
+ if ((*it)->fullPath() == dest)
+ {
+ (*it)->m_messageCount++;
+ (*it)->notifyMessageCount(event);
+ }
+ }
+}
+
+
+void IMAPFolder::copyMessages(const folder::path& dest, const int from, const int to)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+ else if (from < 1 || (to < from && to != -1))
+ throw exceptions::invalid_argument();
+
+ // Construct set
+ std::ostringstream set;
+
+ if (to == -1)
+ set << from << ":*";
+ else
+ set << from << ":" << to;
+
+ // Delegate message copy
+ copyMessages(set.str(), dest);
+
+ // Notify message count changed
+ const int to2 = (to == -1) ? m_messageCount : to;
+ const int count = to - from + 1;
+
+ std::vector <int> nums;
+ nums.resize(count);
+
+ for (int i = from, j = 0 ; i <= to2 ; ++i, ++j)
+ nums[j] = i;
+
+ events::messageCountEvent event(this, events::messageCountEvent::TYPE_ADDED, nums);
+
+ for (std::list <IMAPFolder*>::iterator it = m_store->m_folders.begin() ;
+ it != m_store->m_folders.end() ; ++it)
+ {
+ if ((*it)->fullPath() == dest)
+ {
+ (*it)->m_messageCount += count;
+ (*it)->notifyMessageCount(event);
+ }
+ }
+}
+
+
+void IMAPFolder::copyMessages(const folder::path& dest, const std::vector <int>& nums)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ // Delegate message copy
+ copyMessages(IMAPUtils::listToSet(nums, m_messageCount), dest);
+
+ // Notify message count changed
+ const int count = nums.size();
+
+ events::messageCountEvent event(this, events::messageCountEvent::TYPE_ADDED, nums);
+
+ for (std::list <IMAPFolder*>::iterator it = m_store->m_folders.begin() ;
+ it != m_store->m_folders.end() ; ++it)
+ {
+ if ((*it)->fullPath() == dest)
+ {
+ (*it)->m_messageCount += count;
+ (*it)->notifyMessageCount(event);
+ }
+ }
+}
+
+
+void IMAPFolder::copyMessages(const string& set, const folder::path& dest)
+{
+ // Build the request text
+ std::ostringstream command;
+ command << "COPY " << set << " ";
+ command << IMAPUtils::quoteString(IMAPUtils::pathToString
+ (m_connection->hierarchySeparator(), dest));
+
+ // Send the request
+ m_connection->send(true, command.str(), true);
+
+ // Get the response
+ utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("COPY",
+ m_connection->parser()->lastLine(), "bad response");
+ }
+}
+
+
+void IMAPFolder::status(int& count, int& unseen)
+{
+ count = 0;
+ unseen = 0;
+
+ // Build the request text
+ std::ostringstream command;
+ command << "STATUS ";
+ command << IMAPUtils::quoteString(IMAPUtils::pathToString
+ (m_connection->hierarchySeparator(), fullPath()));
+ command << "(MESSAGES UNSEEN)";
+
+ // Send the request
+ m_store->m_connection->send(true, command.str(), true);
+
+ // Get the response
+ utility::auto_ptr <IMAPParser::response> resp(m_store->m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("STATUS",
+ m_store->m_connection->parser()->lastLine(), "bad response");
+ }
+
+ const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
+ resp->continue_req_or_response_data();
+
+ for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
+ it = respDataList.begin() ; it != respDataList.end() ; ++it)
+ {
+ if ((*it)->response_data() == NULL)
+ {
+ throw exceptions::command_error("STATUS",
+ m_store->m_connection->parser()->lastLine(), "invalid response");
+ }
+
+ const IMAPParser::response_data* responseData = (*it)->response_data();
+
+ if (responseData->mailbox_data() &&
+ responseData->mailbox_data()->type() == IMAPParser::mailbox_data::STATUS)
+ {
+ const std::vector <IMAPParser::status_info*>& statusList =
+ responseData->mailbox_data()->status_info_list();
+
+ for (std::vector <IMAPParser::status_info*>::const_iterator
+ jt = statusList.begin() ; jt != statusList.end() ; ++jt)
+ {
+ switch ((*jt)->status_att()->type())
+ {
+ case IMAPParser::status_att::MESSAGES:
+
+ count = (*jt)->number()->value();
+ break;
+
+ case IMAPParser::status_att::UNSEEN:
+
+ unseen = (*jt)->number()->value();
+ break;
+
+ default:
+
+ break;
+ }
+ }
+ }
+ }
+
+ // Notify message count changed (new messages)
+ if (m_messageCount != count)
+ {
+ const int oldCount = m_messageCount;
+
+ m_messageCount = count;
+
+ if (count > oldCount)
+ {
+ std::vector <int> nums;
+ nums.reserve(count - oldCount);
+
+ for (int i = oldCount + 1, j = 0 ; i <= count ; ++i, ++j)
+ nums[j] = i;
+
+ events::messageCountEvent event(this, events::messageCountEvent::TYPE_ADDED, nums);
+
+ for (std::list <IMAPFolder*>::iterator it = m_store->m_folders.begin() ;
+ it != m_store->m_folders.end() ; ++it)
+ {
+ if ((*it)->fullPath() == m_path)
+ {
+ (*it)->m_messageCount = count;
+ (*it)->notifyMessageCount(event);
+ }
+ }
+ }
+ }
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/IMAPFolder.hpp b/src/messaging/IMAPFolder.hpp
new file mode 100644
index 00000000..bbedb030
--- /dev/null
+++ b/src/messaging/IMAPFolder.hpp
@@ -0,0 +1,154 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_IMAPFOLDER_HPP_INCLUDED
+#define VMIME_MESSAGING_IMAPFOLDER_HPP_INCLUDED
+
+
+#include <vector>
+#include <map>
+
+#include "../types.hpp"
+#include "folder.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+class IMAPStore;
+class IMAPMessage;
+class IMAPConnection;
+
+
+/** IMAP folder implementation.
+ */
+
+class IMAPFolder : public folder
+{
+protected:
+
+ friend class IMAPStore;
+ friend class IMAPMessage;
+
+
+ IMAPFolder(const folder::path& path, IMAPStore* store, const int type = TYPE_UNDEFINED, const int flags = FLAG_UNDEFINED);
+ IMAPFolder(const IMAPFolder&) : folder() { }
+
+ ~IMAPFolder();
+
+public:
+
+ const int mode() const;
+
+ const int type();
+
+ const int flags();
+
+ const folder::path::component name() const;
+ const folder::path fullPath() const;
+
+ void open(const int mode, bool failIfModeIsNotAvailable = false);
+ void close(const bool expunge);
+ void create(const int type);
+
+ const bool exists();
+
+ const bool isOpen() const;
+
+ message* getMessage(const int num);
+ std::vector <message*> getMessages(const int from = 1, const int to = -1);
+ std::vector <message*> getMessages(const std::vector <int>& nums);
+ const int getMessageCount();
+
+ folder* getFolder(const folder::path::component& name);
+ std::vector <folder*> getFolders(const bool recursive = false);
+
+ void rename(const folder::path& newPath);
+
+ void deleteMessage(const int num);
+ void deleteMessages(const int from = 1, const int to = -1);
+ void deleteMessages(const std::vector <int>& nums);
+
+ void setMessageFlags(const int from, const int to, const int flags, const int mode = message::FLAG_MODE_SET);
+ void setMessageFlags(const std::vector <int>& nums, const int flags, const int mode = message::FLAG_MODE_SET);
+
+ void addMessage(vmime::message* msg, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, progressionListener* progress = NULL);
+ void addMessage(utility::inputStream& is, const int size, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, progressionListener* progress = NULL);
+
+ void copyMessage(const folder::path& dest, const int num);
+ void copyMessages(const folder::path& dest, const int from = 1, const int to = -1);
+ void copyMessages(const folder::path& dest, const std::vector <int>& nums);
+
+ void status(int& count, int& unseen);
+
+ void expunge();
+
+ folder* getParent();
+
+ const class store& store() const;
+ class store& store();
+
+
+ void fetchMessages(std::vector <message*>& msg, const int options, progressionListener* progress = NULL);
+ void fetchMessage(message* msg, const int options);
+
+ const int getFetchCapabilities() const;
+
+private:
+
+ void registerMessage(IMAPMessage* msg);
+ void unregisterMessage(IMAPMessage* msg);
+
+ void onStoreDisconnected();
+
+ void onClose();
+
+ const int testExistAndGetType();
+
+ void setMessageFlags(const string& set, const int flags, const int mode);
+
+ void copyMessages(const string& set, const folder::path& dest);
+
+
+ IMAPStore* m_store;
+ IMAPConnection* m_connection;
+
+ folder::path m_path;
+ folder::path::component m_name;
+
+ int m_mode;
+ bool m_open;
+
+ int m_type;
+ int m_flags;
+
+ int m_messageCount;
+
+ int m_uidValidity;
+
+ std::vector <IMAPMessage*> m_messages;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_IMAPFOLDER_HPP_INCLUDED
diff --git a/src/messaging/IMAPMessage.cpp b/src/messaging/IMAPMessage.cpp
new file mode 100644
index 00000000..1c2dce7c
--- /dev/null
+++ b/src/messaging/IMAPMessage.cpp
@@ -0,0 +1,843 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "IMAPParser.hpp"
+#include "IMAPMessage.hpp"
+#include "IMAPFolder.hpp"
+#include "IMAPStore.hpp"
+#include "IMAPConnection.hpp"
+#include "IMAPUtils.hpp"
+
+#include <sstream>
+#include <iterator>
+
+
+namespace vmime {
+namespace messaging {
+
+
+//
+// IMAPheader
+//
+
+
+class IMAPheader : public header
+{
+public:
+
+ IMAPheader()
+ {
+ }
+
+ void parse(const string& str)
+ {
+ header::parse(str);
+ }
+};
+
+
+
+//
+// IMAPpart
+//
+
+class IMAPpart : public part
+{
+private:
+
+ IMAPpart(IMAPpart* parent, const int number, const IMAPParser::body_type_mpart* mpart);
+ IMAPpart(IMAPpart* parent, const int number, const IMAPParser::body_type_1part* part);
+
+public:
+
+ const class structure& structure() const;
+ class structure& structure();
+
+ const IMAPpart* parent() const { return (m_parent); }
+
+ const mediaType& type() const { return (m_mediaType); }
+ const int size() const { return (m_size); }
+ const int number() const { return (m_number); }
+
+ const class header& header() const;
+
+
+ static IMAPpart* create(IMAPpart* parent, const int number, const IMAPParser::body* body)
+ {
+ if (body->body_type_mpart())
+ return new IMAPpart(parent, number, body->body_type_mpart());
+ else
+ return new IMAPpart(parent, number, body->body_type_1part());
+ }
+
+
+ IMAPheader& getOrCreateHeader()
+ {
+ if (m_header != NULL)
+ return (*m_header);
+ else
+ return (*(m_header = new IMAPheader()));
+ }
+
+private:
+
+ IMAPstructure* m_structure;
+ IMAPpart* m_parent;
+ IMAPheader* m_header;
+
+ int m_number;
+ int m_size;
+ mediaType m_mediaType;
+};
+
+
+
+//
+// IMAPstructure
+//
+
+
+class IMAPstructure : public structure
+{
+private:
+
+ IMAPstructure()
+ {
+ }
+
+public:
+
+ IMAPstructure(const IMAPParser::body* body)
+ {
+ m_parts.push_back(IMAPpart::create(NULL, 1, body));
+ }
+
+ IMAPstructure(IMAPpart* parent, const std::vector <IMAPParser::body*>& list)
+ {
+ int number = 1;
+
+ for (std::vector <IMAPParser::body*>::const_iterator
+ it = list.begin() ; it != list.end() ; ++it, ++number)
+ {
+ m_parts.push_back(IMAPpart::create(parent, number, *it));
+ }
+ }
+
+
+ const part& operator[](const int x) const
+ {
+ return (*m_parts[x - 1]);
+ }
+
+ part& operator[](const int x)
+ {
+ return (*m_parts[x - 1]);
+ }
+
+ const int count() const
+ {
+ return (m_parts.size());
+ }
+
+
+ static IMAPstructure* emptyStructure()
+ {
+ return (&m_emptyStructure);
+ }
+
+private:
+
+ static IMAPstructure m_emptyStructure;
+
+ std::vector <IMAPpart*> m_parts;
+};
+
+
+IMAPstructure IMAPstructure::m_emptyStructure;
+
+
+
+IMAPpart::IMAPpart(IMAPpart* parent, const int number, const IMAPParser::body_type_mpart* mpart)
+ : m_parent(parent), m_header(NULL), m_number(number), m_size(0)
+{
+ m_mediaType = vmime::mediaType
+ ("multipart", mpart->media_subtype()->value());
+
+ m_structure = new IMAPstructure(this, mpart->list());
+}
+
+
+IMAPpart::IMAPpart(IMAPpart* parent, const int number, const IMAPParser::body_type_1part* part)
+ : m_parent(parent), m_header(NULL), m_number(number), m_size(0)
+{
+ if (part->body_type_text())
+ {
+ m_mediaType = vmime::mediaType
+ ("text", part->body_type_text()->
+ media_text()->media_subtype()->value());
+
+ m_size = part->body_type_text()->body_fields()->body_fld_octets()->value();
+ }
+ else if (part->body_type_msg())
+ {
+ m_mediaType = vmime::mediaType
+ ("message", part->body_type_msg()->
+ media_message()->media_subtype()->value());
+ }
+ else
+ {
+ m_mediaType = vmime::mediaType
+ (part->body_type_basic()->media_basic()->media_type()->value(),
+ part->body_type_basic()->media_basic()->media_subtype()->value());
+
+ m_size = part->body_type_basic()->body_fields()->body_fld_octets()->value();
+ }
+
+ m_structure = NULL;
+}
+
+
+const class header& IMAPpart::header() const
+{
+ if (m_header == NULL)
+ throw exceptions::unfetched_object();
+ else
+ return (*m_header);
+}
+
+
+const class structure& IMAPpart::structure() const
+{
+ if (m_structure != NULL)
+ return (*m_structure);
+ else
+ return (*IMAPstructure::emptyStructure());
+}
+
+
+class structure& IMAPpart::structure()
+{
+ if (m_structure != NULL)
+ return (*m_structure);
+ else
+ return (*IMAPstructure::emptyStructure());
+}
+
+
+
+//
+// IMAPMessage_literalHandler
+//
+
+class IMAPMessage_literalHandler : public IMAPParser::literalHandler
+{
+public:
+
+ IMAPMessage_literalHandler(utility::outputStream& os, progressionListener* progress)
+ : m_os(os), m_progress(progress)
+ {
+ }
+
+ target* targetFor(const IMAPParser::component& comp, const int /* data */)
+ {
+ if (typeid(comp) == typeid(IMAPParser::msg_att_item))
+ {
+ const int type = static_cast
+ <const IMAPParser::msg_att_item&>(comp).type();
+
+ if (type == IMAPParser::msg_att_item::BODY_SECTION ||
+ type == IMAPParser::msg_att_item::RFC822_TEXT)
+ {
+ return new targetStream(m_progress, m_os);
+ }
+ }
+
+ return (NULL);
+ }
+
+private:
+
+ utility::outputStream& m_os;
+ progressionListener* m_progress;
+};
+
+
+
+//
+// IMAPMessage
+//
+
+
+IMAPMessage::IMAPMessage(IMAPFolder* folder, const int num)
+ : m_folder(folder), m_num(num), m_size(-1), m_flags(FLAG_UNDEFINED),
+ m_expunged(false), m_header(NULL), m_structure(NULL)
+{
+ m_folder->registerMessage(this);
+}
+
+
+IMAPMessage::~IMAPMessage()
+{
+ m_folder->unregisterMessage(this);
+ delete dynamic_cast <IMAPheader*>(m_header);
+}
+
+
+void IMAPMessage::onFolderClosed()
+{
+ m_folder = NULL;
+}
+
+
+const int IMAPMessage::number() const
+{
+ return (m_num);
+}
+
+
+const message::uid IMAPMessage::uniqueId() const
+{
+ return (m_uid);
+}
+
+
+const int IMAPMessage::size() const
+{
+ if (m_size == -1)
+ throw exceptions::unfetched_object();
+
+ return (m_size);
+}
+
+
+const bool IMAPMessage::isExpunged() const
+{
+ return (m_expunged);
+}
+
+
+const int IMAPMessage::flags() const
+{
+ if (m_flags == FLAG_UNDEFINED)
+ throw exceptions::unfetched_object();
+
+ return (m_flags);
+}
+
+
+const class structure& IMAPMessage::structure() const
+{
+ if (m_structure == NULL)
+ throw exceptions::unfetched_object();
+
+ return (*m_structure);
+}
+
+
+class structure& IMAPMessage::structure()
+{
+ if (m_structure == NULL)
+ throw exceptions::unfetched_object();
+
+ return (*m_structure);
+}
+
+
+const class header& IMAPMessage::header() const
+{
+ if (m_header == NULL)
+ throw exceptions::unfetched_object();
+
+ return (*m_header);
+}
+
+
+void IMAPMessage::extract(utility::outputStream& os, progressionListener* progress,
+ const int start, const int length) const
+{
+ if (!m_folder)
+ throw exceptions::folder_not_found();
+
+ extract(NULL, os, progress, start, length, false);
+}
+
+
+void IMAPMessage::extractPart
+ (const part& p, utility::outputStream& os, progressionListener* progress,
+ const int start, const int length) const
+{
+ if (!m_folder)
+ throw exceptions::folder_not_found();
+
+ extract(&p, os, progress, start, length, false);
+}
+
+
+void IMAPMessage::fetchPartHeader(part& p)
+{
+ if (!m_folder)
+ throw exceptions::folder_not_found();
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter ossAdapter(oss);
+
+ extract(&p, ossAdapter, NULL, 0, -1, true);
+
+ static_cast <IMAPpart&>(p).getOrCreateHeader().parse(oss.str());
+}
+
+
+void IMAPMessage::extract(const part* p, utility::outputStream& os, progressionListener* progress,
+ const int start, const int length, const bool headerOnly) const
+{
+ IMAPMessage_literalHandler literalHandler(os, progress);
+
+ // Construct section identifier
+ std::ostringstream section;
+
+ if (p != NULL)
+ {
+ const IMAPpart* currentPart = static_cast <const IMAPpart*>(p);
+ std::vector <int> numbers;
+
+ numbers.push_back(currentPart->number());
+ currentPart = currentPart->parent();
+
+ while (currentPart != NULL)
+ {
+ numbers.push_back(currentPart->number());
+ currentPart = currentPart->parent();
+ }
+
+ numbers.erase(numbers.end() - 1);
+
+ for (std::vector <int>::reverse_iterator it = numbers.rbegin() ; it != numbers.rend() ; ++it)
+ {
+ if (it != numbers.rbegin()) section << ".";
+ section << *it;
+ }
+ }
+
+ // Build the request text
+ std::ostringstream command;
+
+ command << "FETCH " << m_num << " BODY[";
+ command << section.str();
+ if (headerOnly) command << ".MIME"; // "MIME" not "HEADER" for parts
+ command << "]";
+
+ if (start != 0 || length != -1)
+ command << "<" << start << "." << length << ">";
+
+ // Send the request
+ m_folder->m_connection->send(true, command.str(), true);
+
+ // Get the response
+ utility::auto_ptr <IMAPParser::response> resp
+ (m_folder->m_connection->readResponse(&literalHandler));
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("FETCH",
+ m_folder->m_connection->parser()->lastLine(), "bad response");
+ }
+
+
+ if (!headerOnly)
+ {
+ // TODO: update the flags (eg. flag "\Seen" may have been set)
+ }
+}
+
+
+void IMAPMessage::fetch(IMAPFolder* folder, const int options)
+{
+ if (m_folder != folder)
+ throw exceptions::folder_not_found();
+
+ // TODO: optimization: send the request for multiple
+ // messages at the same time (FETCH x:y)
+
+ // Example:
+ // C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
+ // S: * 2 FETCH ....
+ // S: * 3 FETCH ....
+ // S: * 4 FETCH ....
+ // S: A654 OK FETCH completed
+
+ std::vector <string> items;
+
+ if (options & folder::FETCH_SIZE)
+ items.push_back("RFC822.SIZE");
+
+ if (options & folder::FETCH_FLAGS)
+ items.push_back("FLAGS");
+
+ if (options & folder::FETCH_STRUCTURE)
+ items.push_back("BODYSTRUCTURE");
+
+ if (options & folder::FETCH_UID)
+ items.push_back("UID");
+
+ if (options & folder::FETCH_FULL_HEADER)
+ items.push_back("RFC822.HEADER");
+ else
+ {
+ if (options & folder::FETCH_ENVELOPE)
+ items.push_back("ENVELOPE");
+
+ if (options & folder::FETCH_CONTENT_INFO)
+ items.push_back("BODY[HEADER.FIELDS (CONTENT-TYPE)]");
+ }
+
+ // Build the request text
+ std::ostringstream command;
+ command << "FETCH " << m_num << " (";
+
+ for (std::vector <string>::const_iterator it = items.begin() ;
+ it != items.end() ; ++it)
+ {
+ if (it != items.begin()) command << " ";
+ command << *it;
+ }
+
+ command << ")";
+
+ // Send the request
+ m_folder->m_connection->send(true, command.str(), true);
+
+ // Get the response
+ utility::auto_ptr <IMAPParser::response> resp(m_folder->m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("FETCH",
+ m_folder->m_connection->parser()->lastLine(), "bad response");
+ }
+
+ const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
+ resp->continue_req_or_response_data();
+
+ for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
+ it = respDataList.begin() ; it != respDataList.end() ; ++it)
+ {
+ if ((*it)->response_data() == NULL)
+ {
+ throw exceptions::command_error("FETCH",
+ m_folder->m_connection->parser()->lastLine(), "invalid response");
+ }
+
+ const IMAPParser::message_data* messageData =
+ (*it)->response_data()->message_data();
+
+ // We are only interested in responses of type "FETCH"
+ if (messageData == NULL || messageData->type() != IMAPParser::message_data::FETCH)
+ continue;
+
+ if (static_cast <int>(messageData->number()) != m_num)
+ continue;
+
+ // Process fetch response for this message
+ processFetchResponse(options, messageData->msg_att());
+ }
+}
+
+
+void IMAPMessage::processFetchResponse
+ (const int options, const IMAPParser::msg_att* msgAtt)
+{
+ // Get message attributes
+ const std::vector <IMAPParser::msg_att_item*> atts =
+ msgAtt->items();
+
+ int flags = 0;
+
+ for (std::vector <IMAPParser::msg_att_item*>::const_iterator
+ it = atts.begin() ; it != atts.end() ; ++it)
+ {
+ switch ((*it)->type())
+ {
+ case IMAPParser::msg_att_item::FLAGS:
+ {
+ flags |= IMAPUtils::messageFlagsFromFlags((*it)->flag_list());
+ break;
+ }
+ case IMAPParser::msg_att_item::UID:
+ {
+ std::ostringstream oss;
+ oss << m_folder->m_uidValidity << ":" << (*it)->unique_id()->value();
+
+ m_uid = oss.str();
+ break;
+ }
+ case IMAPParser::msg_att_item::ENVELOPE:
+ {
+ if (!(options & folder::FETCH_FULL_HEADER))
+ {
+ const IMAPParser::envelope* env = (*it)->envelope();
+ vmime::header& hdr = getOrCreateHeader();
+
+ // Date
+ hdr.fields.Date() = env->env_date()->value();
+
+ // Subject
+ text subject;
+ decodeAndUnfoldText(env->env_subject()->value(), subject);
+
+ hdr.fields.Subject() = subject;
+
+ // From
+ mailboxList from;
+ convertAddressList(*(env->env_from()), from);
+
+ if (!from.empty())
+ hdr.fields.From() = *(from.begin());
+
+ // To
+ mailboxList to;
+ convertAddressList(*(env->env_to()), to);
+
+ hdr.fields.To() = to;
+
+ // Sender
+ mailboxList sender;
+ convertAddressList(*(env->env_sender()), sender);
+
+ if (!sender.empty())
+ hdr.fields.Sender() = *(sender.begin());
+
+ // Reply-to
+ mailboxList replyTo;
+ convertAddressList(*(env->env_reply_to()), replyTo);
+
+ if (!replyTo.empty())
+ hdr.fields.ReplyTo() = *(replyTo.begin());
+
+ // Cc
+ mailboxList cc;
+ convertAddressList(*(env->env_cc()), cc);
+
+ if (!cc.empty())
+ hdr.fields.Cc() = cc;
+
+ // Bcc
+ mailboxList bcc;
+ convertAddressList(*(env->env_bcc()), bcc);
+
+ if (!bcc.empty())
+ hdr.fields.Bcc() = bcc;
+ }
+
+ break;
+ }
+ case IMAPParser::msg_att_item::BODY_STRUCTURE:
+ {
+ delete (m_structure);
+ m_structure = new IMAPstructure((*it)->body());
+ break;
+ }
+ case IMAPParser::msg_att_item::RFC822_HEADER:
+ {
+ getOrCreateHeader().parse((*it)->nstring()->value());
+ break;
+ }
+ case IMAPParser::msg_att_item::RFC822_SIZE:
+ {
+ m_size = (*it)->number()->value();
+ break;
+ }
+ case IMAPParser::msg_att_item::BODY_SECTION:
+ {
+ if (!(options & folder::FETCH_FULL_HEADER))
+ {
+ if ((*it)->section()->section_text1() &&
+ (*it)->section()->section_text1()->type()
+ == IMAPParser::section_text::HEADER_FIELDS)
+ {
+ IMAPheader tempHeader;
+ tempHeader.parse((*it)->nstring()->value());
+
+ vmime::header& hdr = getOrCreateHeader();
+
+ for (header::const_iterator jt = tempHeader.fields.begin() ;
+ jt != tempHeader.fields.end() ; ++jt)
+ {
+ hdr.fields.append(*jt);
+ }
+ }
+ }
+
+ break;
+ }
+ case IMAPParser::msg_att_item::INTERNALDATE:
+ case IMAPParser::msg_att_item::RFC822:
+ case IMAPParser::msg_att_item::RFC822_TEXT:
+ case IMAPParser::msg_att_item::BODY:
+ {
+ break;
+ }
+
+ }
+ }
+
+ if (options & folder::FETCH_FLAGS)
+ m_flags = flags;
+}
+
+
+IMAPheader& IMAPMessage::getOrCreateHeader()
+{
+ if (m_header != NULL)
+ return (*m_header);
+ else
+ return (*(m_header = new IMAPheader()));
+}
+
+
+void IMAPMessage::convertAddressList
+ (const IMAPParser::address_list& src, mailboxList& dest)
+{
+ for (std::vector <IMAPParser::address*>::const_iterator
+ it = src.addresses().begin() ; it != src.addresses().end() ; ++it)
+ {
+ const IMAPParser::address& addr = **it;
+
+ text name;
+ decodeAndUnfoldText(addr.addr_name()->value(), name);
+
+ string email = addr.addr_mailbox()->value()
+ + "@" + addr.addr_host()->value();
+
+ dest.append(mailbox(name, email));
+ }
+}
+
+
+void IMAPMessage::setFlags(const int flags, const int mode)
+{
+ if (!m_folder)
+ throw exceptions::folder_not_found();
+ else if (m_folder->m_mode == folder::MODE_READ_ONLY)
+ throw exceptions::illegal_state("Folder is read-only");
+
+ // Build the request text
+ std::ostringstream command;
+ command << "STORE " << m_num;
+
+ switch (mode)
+ {
+ case FLAG_MODE_ADD: command << " +FLAGS"; break;
+ case FLAG_MODE_REMOVE: command << " -FLAGS"; break;
+ default:
+ case FLAG_MODE_SET: command << " FLAGS"; break;
+ }
+
+ if (m_flags == FLAG_UNDEFINED) // Update local flags only if they
+ command << ".SILENT "; // have been fetched previously
+ else
+ command << " ";
+
+ std::vector <string> flagList;
+
+ if (flags & FLAG_REPLIED) flagList.push_back("\\Answered");
+ if (flags & FLAG_MARKED) flagList.push_back("\\Flagged");
+ if (flags & FLAG_DELETED) flagList.push_back("\\Deleted");
+ if (flags & FLAG_SEEN) flagList.push_back("\\Seen");
+
+ if (!flagList.empty())
+ {
+ command << "(";
+
+ if (flagList.size() >= 2)
+ {
+ std::copy(flagList.begin(), flagList.end() - 1,
+ std::ostream_iterator <string>(command, " "));
+ }
+
+ command << *(flagList.end() - 1) << ")";
+
+ // Send the request
+ m_folder->m_connection->send(true, command.str(), true);
+
+ // Get the response
+ utility::auto_ptr <IMAPParser::response> resp(m_folder->m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("STORE",
+ m_folder->m_connection->parser()->lastLine(), "bad response");
+ }
+
+ // Update the local flags for this message
+ if (m_flags != FLAG_UNDEFINED)
+ {
+ const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
+ resp->continue_req_or_response_data();
+
+ int newFlags = 0;
+
+ for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
+ it = respDataList.begin() ; it != respDataList.end() ; ++it)
+ {
+ if ((*it)->response_data() == NULL)
+ continue;
+
+ const IMAPParser::message_data* messageData =
+ (*it)->response_data()->message_data();
+
+ // We are only interested in responses of type "FETCH"
+ if (messageData == NULL || messageData->type() != IMAPParser::message_data::FETCH)
+ continue;
+
+ // Get message attributes
+ const std::vector <IMAPParser::msg_att_item*> atts =
+ messageData->msg_att()->items();
+
+ for (std::vector <IMAPParser::msg_att_item*>::const_iterator
+ it = atts.begin() ; it != atts.end() ; ++it)
+ {
+ if ((*it)->type() == IMAPParser::msg_att_item::FLAGS)
+ newFlags |= IMAPUtils::messageFlagsFromFlags((*it)->flag_list());
+ }
+ }
+
+ m_flags = newFlags;
+ }
+
+ // Notify message flags changed
+ std::vector <int> nums;
+ nums.push_back(m_num);
+
+ events::messageChangedEvent event(m_folder, events::messageChangedEvent::TYPE_FLAGS, nums);
+
+ for (std::list <IMAPFolder*>::iterator it = m_folder->m_store->m_folders.begin() ;
+ it != m_folder->m_store->m_folders.end() ; ++it)
+ {
+ if ((*it)->fullPath() == m_folder->m_path)
+ (*it)->notifyMessageChanged(event);
+ }
+ }
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/IMAPMessage.hpp b/src/messaging/IMAPMessage.hpp
new file mode 100644
index 00000000..74c7a36f
--- /dev/null
+++ b/src/messaging/IMAPMessage.hpp
@@ -0,0 +1,108 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_IMAPMESSAGE_HPP_INCLUDED
+#define VMIME_MESSAGING_IMAPMESSAGE_HPP_INCLUDED
+
+
+#include "message.hpp"
+#include "folder.hpp"
+#include "../mailboxList.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+class IMAPheader;
+class IMAPstructure;
+
+
+/** IMAP message implementation.
+ */
+
+class IMAPMessage : public message
+{
+protected:
+
+ friend class IMAPFolder;
+
+ IMAPMessage(IMAPFolder* folder, const int num);
+ IMAPMessage(const IMAPMessage&) : message() { }
+
+ ~IMAPMessage();
+
+public:
+
+ const int number() const;
+
+ const uid uniqueId() const;
+
+ const int size() const;
+
+ const bool isExpunged() const;
+
+ const class structure& structure() const;
+ class structure& structure();
+
+ const class header& header() const;
+
+ const int flags() const;
+ void setFlags(const int flags, const int mode = FLAG_MODE_SET);
+
+ void extract(utility::outputStream& os, progressionListener* progress = NULL, const int start = 0, const int length = -1) const;
+ void extractPart(const part& p, utility::outputStream& os, progressionListener* progress = NULL, const int start = 0, const int length = -1) const;
+
+ void fetchPartHeader(part& p);
+
+private:
+
+ void fetch(IMAPFolder* folder, const int options);
+
+ void processFetchResponse(const int options, const IMAPParser::msg_att* msgAtt);
+
+ void extract(const part* p, utility::outputStream& os, progressionListener* progress, const int start, const int length, const bool headerOnly) const;
+
+
+ void convertAddressList(const IMAPParser::address_list& src, mailboxList& dest);
+
+
+ IMAPheader& getOrCreateHeader();
+
+
+ void onFolderClosed();
+
+ IMAPFolder* m_folder;
+
+ int m_num;
+ int m_size;
+ int m_flags;
+ bool m_expunged;
+ uid m_uid;
+
+ class IMAPheader* m_header;
+ class IMAPstructure* m_structure;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_IMAPMESSAGE_HPP_INCLUDED
diff --git a/src/messaging/IMAPParser.hpp b/src/messaging/IMAPParser.hpp
new file mode 100644
index 00000000..2e4a56ab
--- /dev/null
+++ b/src/messaging/IMAPParser.hpp
@@ -0,0 +1,5075 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_IMAPPARSER_HPP_INCLUDED
+#define VMIME_MESSAGING_IMAPPARSER_HPP_INCLUDED
+
+
+#include "../base.hpp"
+#include "../dateTime.hpp"
+#include "../charset.hpp"
+#include "../exception.hpp"
+#include "../utility/smartPtr.hpp"
+
+#include "../encoderB64.hpp"
+#include "../encoderQP.hpp"
+
+#include "../platformDependant.hpp"
+
+#include "progressionListener.hpp"
+#include "timeoutHandler.hpp"
+#include "socket.hpp"
+
+#include "IMAPTag.hpp"
+
+#include <vector>
+#include <stdexcept>
+
+
+//#define DEBUG_RESPONSE 1
+
+
+#if DEBUG_RESPONSE
+# include <iostream>
+#endif
+
+
+namespace vmime {
+namespace messaging {
+
+
+#if DEBUG_RESPONSE
+ static string DEBUG_RESPONSE_level;
+ static std::vector <string> DEBUG_RESPONSE_components;
+
+# define DEBUG_ENTER_COMPONENT(x) \
+ DEBUG_RESPONSE_components.push_back(x); \
+ std::cout << DEBUG_RESPONSE_level \
+ << "(" << DEBUG_RESPONSE_level.length() << ") " \
+ << (x) << std::endl;
+# define DEBUG_FOUND(x, y) \
+ std::cout << "FOUND: " << x << ": " << y << std::endl;
+#else
+# define DEBUG_ENTER_COMPONENT(x)
+# define DEBUG_FOUND(x, y)
+#endif
+
+
+class IMAPParser
+{
+public:
+
+ IMAPParser(IMAPTag* tag, socket* sok, timeoutHandler* _timeoutHandler)
+ : m_tag(tag), m_socket(sok), m_progress(NULL),
+ m_literalHandler(NULL), m_timeoutHandler(_timeoutHandler)
+ {
+ }
+
+
+ const IMAPTag* tag() const
+ {
+ return (m_tag);
+ }
+
+
+ const string lastLine() const
+ {
+ // Remove blanks and new lines at the end of the line.
+ string line(m_lastLine);
+
+ string::const_iterator it = line.end();
+ int count = 0;
+
+ while (it != line.begin())
+ {
+ const unsigned char c = *(it - 1);
+
+ if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r'))
+ break;
+
+ ++count;
+ --it;
+ }
+
+ line.resize(line.length() - count);
+
+ return (line);
+ }
+
+
+
+ //
+ // literalHandler : literal content handler
+ //
+
+ class component;
+
+ class literalHandler
+ {
+ public:
+
+ virtual ~literalHandler() { }
+
+
+ // Abstract target class
+ class target
+ {
+ protected:
+
+ target(class progressionListener* progress) : m_progress(progress) {}
+ target(const target&) {}
+
+ public:
+
+ virtual ~target() { }
+
+
+ class progressionListener* progressionListener() { return (m_progress); }
+
+ virtual void putData(const string& chunk) = 0;
+
+ private:
+
+ class progressionListener* m_progress;
+ };
+
+
+ // Target: put in a string
+ class targetString : public target
+ {
+ public:
+
+ targetString(class progressionListener* progress, vmime::string& str)
+ : target(progress), m_string(str) { }
+
+ const vmime::string& string() const { return (m_string); }
+ vmime::string& string() { return (m_string); }
+
+
+ void putData(const vmime::string& chunk)
+ {
+ m_string += chunk;
+ }
+
+ private:
+
+ vmime::string& m_string;
+ };
+
+
+ // Target: redirect to an output stream
+ class targetStream : public target
+ {
+ public:
+
+ targetStream(class progressionListener* progress, utility::outputStream& stream)
+ : target(progress), m_stream(stream) { }
+
+ const utility::outputStream& stream() const { return (m_stream); }
+ utility::outputStream& stream() { return (m_stream); }
+
+
+ void putData(const string& chunk)
+ {
+ m_stream.write(chunk.data(), chunk.length());
+ }
+
+ private:
+
+ utility::outputStream& m_stream;
+ };
+
+
+ // Called when the parser needs to know what to do with a literal
+ // . comp: the component in which we are at this moment
+ // . data: data specific to the component (may not be used)
+ //
+ // Returns :
+ // . == NULL to put the literal into the response
+ // . != NULL to redirect the literal to the specified target
+
+ virtual target* targetFor(const component& comp, const int data) = 0;
+ };
+
+
+ //
+ // Base class for a terminal or a non-terminal
+ //
+
+ class component
+ {
+ public:
+
+ component() { }
+ virtual ~component() { }
+
+ virtual void go(IMAPParser& parser, string& line, string::size_type* currentPos) = 0;
+
+
+ const string makeResponseLine(const string& comp, const string& line,
+ const string::size_type pos)
+ {
+#if DEBUG_RESPONSE
+ if (pos > line.length())
+ std::cout << "WARNING: component::makeResponseLine(): pos > line.length()" << std::endl;
+#endif
+
+ string result(line.substr(0, pos));
+ result += "[^]"; // indicates current parser position
+ result += line.substr(pos, line.length());
+ if (!comp.empty()) result += " [" + comp + "]";
+
+ return (result);
+ }
+ };
+
+
+
+ //
+ // Parse one character
+ //
+
+ template <char C>
+ class one_char : public component
+ {
+ public:
+
+ void go(IMAPParser& /* parser */, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT(string("one_char <") + C + ">: current='" + ((*currentPos < line.length() ? line[*currentPos] : '?')) + "'");
+
+ const string::size_type pos = *currentPos;
+
+ if (pos < line.length() && line[pos] == C)
+ *currentPos = pos + 1;
+ else
+ throw exceptions::invalid_response("", makeResponseLine("", line, pos));
+ }
+ };
+
+
+ //
+ // SPACE ::= <ASCII SP, space, 0x20>
+ //
+
+ class SPACE : public component
+ {
+ public:
+
+ void go(IMAPParser& /* parser */, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("SPACE");
+
+ string::size_type pos = *currentPos;
+
+ while (pos < line.length() && (line[pos] == ' ' || line[pos] == '\t'))
+ ++pos;
+
+ if (pos > *currentPos)
+ *currentPos = pos;
+ else
+ throw exceptions::invalid_response("", makeResponseLine("SPACE", line, pos));
+ }
+ };
+
+
+ //
+ // CR ::= <ASCII CR, carriage return, 0x0D>
+ // LF ::= <ASCII LF, line feed, 0x0A>
+ // CRLF ::= CR LF
+ //
+
+ class CRLF : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("CRLF");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <SPACE>(line, &pos, true);
+
+ if (pos + 1 < line.length() &&
+ line[pos] == 0x0d && line[pos + 1] == 0x0a)
+ {
+ *currentPos = pos + 2;
+ }
+ else
+ {
+ throw exceptions::invalid_response("", makeResponseLine("CRLF", line, pos));
+ }
+ }
+ };
+
+
+ //
+ // SPACE ::= <ASCII SP, space, 0x20>
+ // CTL ::= <any ASCII control character and DEL, 0x00 - 0x1f, 0x7f>
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ // ATOM_CHAR ::= <any CHAR except atom_specials>
+ // atom_specials ::= "(" / ")" / "{" / SPACE / CTL / list_wildcards / quoted_specials
+ // list_wildcards ::= "%" / "*"
+ // quoted_specials ::= <"> / "\"
+ //
+ // tag ::= 1*<any ATOM_CHAR except "+"> (named "xtag")
+ //
+
+ class xtag : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("tag");
+
+ string::size_type pos = *currentPos;
+
+ bool end = false;
+
+ string tagString;
+ tagString.reserve(10);
+
+ while (!end && pos < line.length())
+ {
+ const unsigned char c = line[pos];
+
+ switch (c)
+ {
+ case '+':
+ case '(':
+ case ')':
+ case '{':
+ case 0x20: // SPACE
+ case '%': // list_wildcards
+ case '*': // list_wildcards
+ case '"': // quoted_specials
+ case '\\': // quoted_specials
+
+ end = true;
+ break;
+
+ default:
+
+ if (c <= 0x1f || c >= 0x7f)
+ end = true;
+ else
+ {
+ tagString += c;
+ ++pos;
+ }
+
+ break;
+ }
+ }
+
+ if (tagString == (string) *(parser.tag()))
+ {
+ *currentPos = pos;
+ }
+ else
+ {
+ // Invalid tag
+ throw exceptions::invalid_response("", makeResponseLine("tag", line, pos));
+ }
+ }
+ };
+
+
+ //
+ // digit ::= "0" / digit_nz
+ // digit_nz ::= "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"
+ //
+ // number ::= 1*digit
+ // ;; Unsigned 32-bit integer
+ // ;; (0 <= n < 4,294,967,296)
+ //
+
+ class number : public component
+ {
+ public:
+
+ number(const bool nonZero = false)
+ : m_nonZero(nonZero), m_value(0)
+ {
+ }
+
+ void go(IMAPParser& /* parser */, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("number");
+
+ string::size_type pos = *currentPos;
+
+ bool valid = true;
+ unsigned int val = 0;
+
+ while (valid && pos < line.length())
+ {
+ const char c = line[pos];
+
+ if (c >= '0' && c <= '9')
+ {
+ val = (val * 10) + (c - '0');
+ ++pos;
+ }
+ else
+ {
+ valid = false;
+ }
+ }
+
+ // Check for non-null length (and for non-zero number)
+ if (!(m_nonZero && val == 0) && pos != *currentPos)
+ {
+ m_value = val;
+ *currentPos = pos;
+ }
+ else
+ {
+ throw exceptions::invalid_response("", makeResponseLine("number", line, pos));
+ }
+ }
+
+ private:
+
+ const bool m_nonZero;
+ unsigned int m_value;
+
+ public:
+
+ const unsigned int value() const { return (m_value); }
+ };
+
+
+ // nz_number ::= digit_nz *digit
+ // ;; Non-zero unsigned 32-bit integer
+ // ;; (0 < n < 4,294,967,296)
+ //
+
+ class nz_number : public number
+ {
+ public:
+
+ nz_number() : number(true)
+ {
+ }
+ };
+
+
+ //
+ // text ::= 1*TEXT_CHAR
+ //
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ // TEXT_CHAR ::= <any CHAR except CR and LF>
+ //
+
+ class text : public component
+ {
+ public:
+
+ text(bool allow8bits = false, const char except = 0)
+ : m_allow8bits(allow8bits), m_except(except)
+ {
+ }
+
+ void go(IMAPParser& /* parser */, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("text");
+
+ string::size_type pos = *currentPos;
+ string::size_type len = 0;
+
+ if (m_allow8bits)
+ {
+ const unsigned char except = m_except;
+
+ for (bool end = false ; !end && pos < line.length() ; )
+ {
+ const unsigned char c = line[pos];
+
+ if (c == 0x00 || c == 0x0d || c == 0x0a || c == except)
+ {
+ end = true;
+ }
+ else
+ {
+ ++pos;
+ ++len;
+ }
+ }
+ }
+ else
+ {
+ const unsigned char except = m_except;
+
+ for (bool end = false ; !end && pos < line.length() ; )
+ {
+ const unsigned char c = line[pos];
+
+ if (c < 0x01 || c > 0x7f || c == 0x0d || c == 0x0a || c == except)
+ {
+ end = true;
+ }
+ else
+ {
+ ++pos;
+ ++len;
+ }
+ }
+ }
+
+ if (len != 0)
+ {
+ m_value.resize(len);
+ std::copy(line.begin() + *currentPos, line.begin() + pos, m_value.begin());
+
+ *currentPos = pos;
+ }
+ else
+ {
+ throw exceptions::invalid_response("", makeResponseLine("text", line, pos));
+ }
+ }
+
+ private:
+
+ string m_value;
+ const bool m_allow8bits;
+ const char m_except;
+
+ public:
+
+ const string& value() const { return (m_value); }
+ };
+
+
+ class text8 : public text
+ {
+ public:
+
+ text8() : text(true)
+ {
+ }
+ };
+
+
+ template <char C>
+ class text_except : public text
+ {
+ public:
+
+ text_except() : text(false, C)
+ {
+ }
+ };
+
+
+ template <char C>
+ class text8_except : public text
+ {
+ public:
+
+ text8_except() : text(true, C)
+ {
+ }
+ };
+
+
+ //
+ // QUOTED_CHAR ::= <any TEXT_CHAR except quoted_specials> / "\" quoted_specials
+ // quoted_specials ::= <"> / "\"
+ // TEXT_CHAR ::= <any CHAR except CR and LF>
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ //
+
+ class QUOTED_CHAR : public component
+ {
+ public:
+
+ void go(IMAPParser& /* parser */, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("quoted_char");
+
+ string::size_type pos = *currentPos;
+
+ const unsigned char c = (pos < line.length() ? line[pos] : 0);
+
+ if (c >= 0x01 && c <= 0x7f && // 0x01 - 0x7f
+ c != '"' && c != '\\' && // quoted_specials
+ c != '\r' && c != '\n') // CR and LF
+ {
+ m_value = c;
+ *currentPos = pos + 1;
+ }
+ else if (c == '\\' && pos + 1 < line.length() &&
+ (line[pos + 1] == '"' || line[pos + 1] == '\\'))
+ {
+ m_value = line[pos + 1];
+ *currentPos = pos + 2;
+ }
+ else
+ {
+ throw exceptions::invalid_response("", makeResponseLine("QUOTED_CHAR", line, pos));
+ }
+ }
+
+ private:
+
+ char m_value;
+
+ public:
+
+ const char value() const { return (m_value); }
+ };
+
+
+ //
+ // quoted ::= <"> *QUOTED_CHAR <">
+ // QUOTED_CHAR ::= <any TEXT_CHAR except quoted_specials> / "\" quoted_specials
+ // quoted_specials ::= <"> / "\"
+ // TEXT_CHAR ::= <any CHAR except CR and LF>
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ //
+
+ class quoted_text : public component
+ {
+ public:
+
+ void go(IMAPParser& /* parser */, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("quoted_text");
+
+ string::size_type pos = *currentPos;
+ string::size_type len = 0;
+ bool valid = false;
+
+ m_value.reserve(line.length() - pos);
+
+ for (bool end = false, quoted = false ; !end && pos < line.length() ; )
+ {
+ const unsigned char c = line[pos];
+
+ if (quoted)
+ {
+ if (c == '"' || c == '\\')
+ m_value += c;
+ else
+ {
+ m_value += '\\';
+ m_value += c;
+ }
+
+ quoted = false;
+
+ ++pos;
+ ++len;
+ }
+ else
+ {
+ if (c == '\\')
+ {
+ quoted = true;
+
+ ++pos;
+ ++len;
+ }
+ else if (c == '"')
+ {
+ valid = true;
+ end = true;
+ }
+ else if (c >= 0x01 && c <= 0x7f && // CHAR
+ c != 0x0a && c != 0x0d) // CR and LF
+ {
+ m_value += c;
+
+ ++pos;
+ ++len;
+ }
+ else
+ {
+ valid = false;
+ end = true;
+ }
+ }
+ }
+
+ if (valid)
+ {
+ *currentPos = pos;
+ }
+ else
+ {
+ throw exceptions::invalid_response("", makeResponseLine("quoted_text", line, pos));
+ }
+ }
+
+ private:
+
+ string m_value;
+
+ public:
+
+ const string& value() const { return (m_value); }
+ };
+
+
+ //
+ // nil ::= "NIL"
+ //
+
+ class NIL : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("NIL");
+
+ string::size_type pos = *currentPos;
+
+ parser.checkWithArg <special_atom>(line, &pos, "nil");
+
+ *currentPos = pos;
+ }
+ };
+
+
+ //
+ // string ::= quoted / literal ----> named 'xstring'
+ //
+ // nil ::= "NIL"
+ // quoted ::= <"> *QUOTED_CHAR <">
+ // QUOTED_CHAR ::= <any TEXT_CHAR except quoted_specials> / "\" quoted_specials
+ // quoted_specials ::= <"> / "\"
+ // TEXT_CHAR ::= <any CHAR except CR and LF>
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ // literal ::= "{" number "}" CRLF *CHAR8
+ // ;; Number represents the number of CHAR8 octets
+ // CHAR8 ::= <any 8-bit octet except NUL, 0x01 - 0xff>
+ //
+
+ class xstring : public component
+ {
+ public:
+
+ xstring(const bool canBeNIL = false, component* comp = NULL, const int data = 0)
+ : m_canBeNIL(canBeNIL), m_component(comp), m_data(data)
+ {
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("string");
+
+ string::size_type pos = *currentPos;
+
+ if (m_canBeNIL &&
+ parser.checkWithArg <special_atom>(line, &pos, "nil", true))
+ {
+ // NIL
+ }
+ else
+ {
+ pos = *currentPos;
+
+ // quoted ::= <"> *QUOTED_CHAR <">
+ if (parser.check <one_char <'"'> >(line, &pos, true))
+ {
+ utility::auto_ptr <quoted_text> text(parser.get <quoted_text>(line, &pos));
+ parser.check <one_char <'"'> >(line, &pos);
+
+ if (parser.m_literalHandler != NULL)
+ {
+ literalHandler::target* target =
+ parser.m_literalHandler->targetFor(*m_component, m_data);
+
+ if (target != NULL)
+ {
+ m_value = "[literal-handler]";
+
+ const string::size_type length = text->value().length();
+ progressionListener* progress = target->progressionListener();
+
+ if (progress)
+ {
+ progress->start(length);
+ }
+
+ target->putData(text->value());
+
+ if (progress)
+ {
+ progress->progress(length, length);
+ progress->stop(length);
+ }
+
+ delete (target);
+ }
+ else
+ {
+ m_value = text->value();
+ }
+ }
+ else
+ {
+ m_value = text->value();
+ }
+
+ DEBUG_FOUND("string[quoted]", "<length=" << m_value.length() << ", value='" << m_value << "'>");
+ }
+ // literal ::= "{" number "}" CRLF *CHAR8
+ else
+ {
+ parser.check <one_char <'{'> >(line, &pos);
+
+ number* num = parser.get <number>(line, &pos);
+
+ const string::size_type length = num->value();
+ delete (num);
+
+ parser.check <one_char <'}'> >(line, &pos);
+
+ parser.check <CRLF>(line, &pos);
+
+
+ if (parser.m_literalHandler != NULL)
+ {
+ literalHandler::target* target =
+ parser.m_literalHandler->targetFor(*m_component, m_data);
+
+ if (target != NULL)
+ {
+ m_value = "[literal-handler]";
+
+ parser.m_progress = target->progressionListener();
+ parser.readLiteral(*target, length);
+ parser.m_progress = NULL;
+
+ delete (target);
+ }
+ else
+ {
+ literalHandler::targetString target(NULL, m_value);
+ parser.readLiteral(target, length);
+ }
+ }
+ else
+ {
+ literalHandler::targetString target(NULL, m_value);
+ parser.readLiteral(target, length);
+ }
+
+ line += parser.readLine();
+
+ DEBUG_FOUND("string[literal]", "<length=" << length << ", value='" << m_value << "'>");
+ }
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ bool m_canBeNIL;
+ string m_value;
+
+ component* m_component;
+ const int m_data;
+
+ public:
+
+ const string& value() const { return (m_value); }
+ };
+
+
+ //
+ // nstring ::= string / nil
+ //
+
+ class nstring : public xstring
+ {
+ public:
+
+ nstring(component* comp = NULL, const int data = 0)
+ : xstring(true, comp, data)
+ {
+ }
+ };
+
+
+ //
+ // astring ::= atom / string
+ //
+
+ class astring : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("astring");
+
+ string::size_type pos = *currentPos;
+
+ xstring* str = NULL;
+
+ if ((str = parser.get <xstring>(line, &pos, true)))
+ {
+ m_value = str->value();
+ delete (str);
+ }
+ else
+ {
+ atom* at = parser.get <atom>(line, &pos);
+ m_value = at->value();
+ delete (at);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ string m_value;
+
+ public:
+
+ const string& value() const { return (m_value); }
+ };
+
+
+ //
+ // atom ::= 1*ATOM_CHAR
+ //
+ // ATOM_CHAR ::= <any CHAR except atom_specials>
+ // atom_specials ::= "(" / ")" / "{" / SPACE / CTL / list_wildcards / quoted_specials
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ // CTL ::= <any ASCII control character and DEL, 0x00 - 0x1f, 0x7f>
+ // list_wildcards ::= "%" / "*"
+ // quoted_specials ::= <"> / "\"
+ // SPACE ::= <ASCII SP, space, 0x20>
+ //
+
+ class atom : public component
+ {
+ public:
+
+ void go(IMAPParser& /* parser */, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("atom");
+
+ string::size_type pos = *currentPos;
+ string::size_type len = 0;
+
+ for (bool end = false ; !end && pos < line.length() ; )
+ {
+ const unsigned char c = line[pos];
+
+ switch (c)
+ {
+ case '(':
+ case ')':
+ case '{':
+ case 0x20: // SPACE
+ case '%': // list_wildcards
+ case '*': // list_wildcards
+ case '"': // quoted_specials
+ case '\\': // quoted_specials
+
+ case '[':
+ case ']': // for "special_atom"
+
+ end = true;
+ break;
+
+ default:
+
+ if (c <= 0x1f || c >= 0x7f)
+ end = true;
+ else
+ {
+ ++pos;
+ ++len;
+ }
+ }
+ }
+
+ if (len != 0)
+ {
+ m_value.resize(len);
+ std::copy(line.begin() + *currentPos, line.begin() + pos, m_value.begin());
+
+ *currentPos = pos;
+ }
+ else
+ {
+ throw exceptions::invalid_response("", makeResponseLine("atom", line, pos));
+ }
+ }
+
+ private:
+
+ string m_value;
+
+ public:
+
+ const string& value() const { return (m_value); }
+ };
+
+
+ //
+ // special atom (eg. "CAPABILITY", "FLAGS", "STATUS"...)
+ //
+ // " Except as noted otherwise, all alphabetic characters are case-
+ // insensitive. The use of upper or lower case characters to define
+ // token strings is for editorial clarity only. Implementations MUST
+ // accept these strings in a case-insensitive fashion. "
+ //
+
+ class special_atom : public atom
+ {
+ public:
+
+ special_atom(const char* str)
+ : m_string(str) // 'string' must be in lower-case
+ {
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT(string("special_atom(") + m_string + ")");
+
+ string::size_type pos = *currentPos;
+
+ atom::go(parser, line, &pos);
+
+ const char* cmp = value().c_str();
+ const char* with = m_string;
+
+ bool ok = true;
+
+ while (ok && *cmp && *with)
+ {
+ ok = (std::tolower(*cmp, std::locale()) == *with);
+
+ ++cmp;
+ ++with;
+ }
+
+ if (!ok || *cmp || *with)
+ {
+ throw exceptions::invalid_response("", makeResponseLine(string("special_atom <") + m_string + ">", line, pos));
+ }
+ else
+ {
+ *currentPos = pos;
+ }
+ }
+
+ private:
+
+ const char* m_string;
+ };
+
+
+ //
+ // text_mime2 ::= "=?" <charset> "?" <encoding> "?" <encoded-text> "?="
+ // ;; Syntax defined in [MIME-HDRS]
+ //
+
+ class text_mime2 : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("text_mime2");
+
+ string::size_type pos = *currentPos;
+
+ atom* theCharset = NULL, *theEncoding = NULL;
+ text* theText = NULL;
+
+ try
+ {
+ parser.check <one_char <'='> >(line, &pos);
+ parser.check <one_char <'?'> >(line, &pos);
+
+ theCharset = parser.get <atom>(line, &pos);
+
+ parser.check <one_char <'?'> >(line, &pos);
+
+ theEncoding = parser.get <atom>(line, &pos);
+
+ parser.check <one_char <'?'> >(line, &pos);
+
+ theText = parser.get <text8_except <'?'> >(line, &pos);
+
+ parser.check <one_char <'?'> >(line, &pos);
+ parser.check <one_char <'='> >(line, &pos);
+ }
+ catch (std::exception& e)
+ {
+ delete (theCharset);
+ delete (theEncoding);
+ delete (theText);
+
+ throw;
+ }
+
+ m_charset = theCharset->value();
+ delete (theCharset);
+
+ // Decode text
+ encoder* theEncoder = NULL;
+
+ if (theEncoding->value()[0] == 'q' || theEncoding->value()[0] == 'Q')
+ {
+ // Quoted-printable
+ theEncoder = new encoderQP;
+ theEncoder->properties()["rfc2047"] = true;
+ }
+ else if (theEncoding->value()[0] == 'b' || theEncoding->value()[0] == 'B')
+ {
+ // Base64
+ theEncoder = new encoderB64;
+ }
+
+ if (theEncoder)
+ {
+ utility::inputStreamStringAdapter in(theText->value());
+ utility::outputStreamStringAdapter out(m_value);
+
+ theEncoder->decode(in, out);
+ delete (theEncoder);
+ }
+ // No decoder available
+ else
+ {
+ m_value = theText->value();
+ }
+
+ delete (theEncoding);
+ delete (theText);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ vmime::charset m_charset;
+ string m_value;
+
+ public:
+
+ const vmime::charset& charset() const { return (m_charset); }
+ const string& value() const { return (m_value); }
+ };
+
+
+ //
+ // flag ::= "\Answered" / "\Flagged" / "\Deleted" /
+ // "\Seen" / "\Draft" / flag_keyword / flag_extension
+ //
+ // flag_extension ::= "\" atom
+ // ;; Future expansion. Client implementations
+ // ;; MUST accept flag_extension flags. Server
+ // ;; implementations MUST NOT generate
+ // ;; flag_extension flags except as defined by
+ // ;; future standard or standards-track
+ // ;; revisions of this specification.
+ //
+ // flag_keyword ::= atom
+ //
+
+ class flag : public component
+ {
+ public:
+
+ flag()
+ : m_flag_keyword(NULL)
+ {
+ }
+
+ ~flag()
+ {
+ delete (m_flag_keyword);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("flag_keyword");
+
+ string::size_type pos = *currentPos;
+
+ if (parser.check <one_char <'\\'> >(line, &pos, true))
+ {
+ if (parser.check <one_char <'*'> >(line, &pos, true))
+ {
+ m_type = STAR;
+ }
+ else
+ {
+ atom* at = parser.get <atom>(line, &pos);
+ const string name = toLower(at->value());
+ delete (at);
+
+ if (name == "answered")
+ m_type = ANSWERED;
+ else if (name == "flagged")
+ m_type = FLAGGED;
+ else if (name == "deleted")
+ m_type = DELETED;
+ else if (name == "seen")
+ m_type = SEEN;
+ else if (name == "draft")
+ m_type = DRAFT;
+ else
+ {
+ m_type = UNKNOWN;
+ m_name = name;
+ }
+ }
+ }
+ else
+ {
+ m_flag_keyword = parser.get <atom>(line, &pos);
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ UNKNOWN,
+ ANSWERED,
+ FLAGGED,
+ DELETED,
+ SEEN,
+ DRAFT,
+ STAR // * = custom flags allowed
+ };
+
+ private:
+
+ Type m_type;
+ string m_name;
+
+ IMAPParser::atom* m_flag_keyword;
+
+ public:
+
+ const Type type() const { return (m_type); }
+ const string& name() const { return (m_name); }
+
+ const IMAPParser::atom* flag_keyword() const { return (m_flag_keyword); }
+ };
+
+
+ //
+ // flag_list ::= "(" #flag ")"
+ //
+
+ class flag_list : public component
+ {
+ public:
+
+ ~flag_list()
+ {
+ for (std::vector <flag*>::iterator it = m_flags.begin() ;
+ it != m_flags.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("flag_list");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'('> >(line, &pos);
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ {
+ m_flags.push_back(parser.get <flag>(line, &pos));
+ parser.check <SPACE>(line, &pos, true);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ std::vector <flag*> m_flags;
+
+ public:
+
+ const std::vector <flag*>& flags() const { return (m_flags); }
+ };
+
+
+ //
+ // mailbox ::= "INBOX" / astring
+ // ;; INBOX is case-insensitive. All case variants of
+ // ;; INBOX (e.g. "iNbOx") MUST be interpreted as INBOX
+ // ;; not as an astring. Refer to section 5.1 for
+ // ;; further semantic details of mailbox names.
+ //
+
+ class mailbox : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("mailbox");
+
+ string::size_type pos = *currentPos;
+
+ if (parser.checkWithArg <special_atom>(line, &pos, "inbox", true))
+ {
+ m_type = INBOX;
+ m_name = "INBOX";
+ }
+ else
+ {
+ m_type = OTHER;
+
+ astring* astr = parser.get <astring>(line, &pos);
+ m_name = astr->value();
+ delete (astr);
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ INBOX,
+ OTHER
+ };
+
+ private:
+
+ Type m_type;
+ string m_name;
+
+ public:
+
+ const Type type() const { return (m_type); }
+ const string& name() const { return (m_name); }
+ };
+
+
+ //
+ // mailbox_flag := "\Marked" / "\Noinferiors" /
+ // "\Noselect" / "\Unmarked" / flag_extension
+ //
+
+ class mailbox_flag : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("mailbox_flag");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'\\'> >(line, &pos);
+
+ atom* at = parser.get <atom>(line, &pos);
+ const string name = toLower(at->value());
+ delete (at);
+
+ if (name == "marked")
+ m_type = MARKED;
+ else if (name == "noinferiors")
+ m_type = NOINFERIORS;
+ else if (name == "noselect")
+ m_type = NOSELECT;
+ else if (name == "unmarked")
+ m_type = UNMARKED;
+ else
+ {
+ m_type = UNKNOWN;
+ m_name = name;
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ UNKNOWN,
+ MARKED,
+ NOINFERIORS,
+ NOSELECT,
+ UNMARKED
+ };
+
+ private:
+
+ Type m_type;
+ string m_name;
+
+ public:
+
+ const Type type() const { return (m_type); }
+ const string& name() const { return (m_name); }
+ };
+
+
+ //
+ // mailbox_flag_list ::= "(" #(mailbox_flag) ")"
+ //
+
+ class mailbox_flag_list : public component
+ {
+ public:
+
+ ~mailbox_flag_list()
+ {
+ for (std::vector <mailbox_flag*>::iterator it = m_flags.begin() ;
+ it != m_flags.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("mailbox_flag_list");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'('> >(line, &pos);
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ {
+ m_flags.push_back(parser.get <mailbox_flag>(line, &pos));
+ parser.check <SPACE>(line, &pos, true);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ std::vector <mailbox_flag*> m_flags;
+
+ public:
+
+ const std::vector <mailbox_flag*>& flags() const { return (m_flags); }
+ };
+
+
+ //
+ // mailbox_list ::= mailbox_flag_list SPACE
+ // (<"> QUOTED_CHAR <"> / nil) SPACE mailbox
+ //
+
+ class mailbox_list : public component
+ {
+ public:
+
+ mailbox_list()
+ : m_mailbox_flag_list(NULL),
+ m_mailbox(NULL), m_quoted_char('\0')
+ {
+ }
+
+ ~mailbox_list()
+ {
+ delete (m_mailbox_flag_list);
+ delete (m_mailbox);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("mailbox_list");
+
+ string::size_type pos = *currentPos;
+
+ m_mailbox_flag_list = parser.get <IMAPParser::mailbox_flag_list>(line, &pos);
+
+ parser.check <SPACE>(line, &pos);
+
+ if (!parser.check <NIL>(line, &pos, true))
+ {
+ parser.check <one_char <'"'> >(line, &pos);
+
+ QUOTED_CHAR* qc = parser.get <QUOTED_CHAR>(line, &pos);
+ m_quoted_char = qc->value();
+ delete (qc);
+
+ parser.check <one_char <'"'> >(line, &pos);
+ }
+
+ parser.check <SPACE>(line, &pos);
+
+ m_mailbox = parser.get <IMAPParser::mailbox>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::mailbox_flag_list* m_mailbox_flag_list;
+ IMAPParser::mailbox* m_mailbox;
+ char m_quoted_char;
+
+ public:
+
+ const IMAPParser::mailbox_flag_list* mailbox_flag_list() const { return (m_mailbox_flag_list); }
+ const IMAPParser::mailbox* mailbox() const { return (m_mailbox); }
+ const char quoted_char() const { return (m_quoted_char); }
+ };
+
+
+ //
+ // resp_text_code ::= "ALERT" / "PARSE" /
+ // "PERMANENTFLAGS" SPACE "(" #(flag / "\*") ")" /
+ // "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
+ // "UIDVALIDITY" SPACE nz_number /
+ // "UNSEEN" SPACE nz_number /
+ // atom [SPACE 1*<any TEXT_CHAR except "]">]
+
+ class resp_text_code : public component
+ {
+ public:
+
+ resp_text_code()
+ : m_nz_number(NULL), m_atom(NULL), m_flag_list(NULL), m_text(NULL)
+ {
+ }
+
+ ~resp_text_code()
+ {
+ delete (m_nz_number);
+ delete (m_atom);
+ delete (m_flag_list);
+ delete (m_text);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("resp_text_code");
+
+ string::size_type pos = *currentPos;
+
+ // "ALERT"
+ if (parser.checkWithArg <special_atom>(line, &pos, "alert", true))
+ {
+ m_type = ALERT;
+ }
+ // "PARSE"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "parse", true))
+ {
+ m_type = PARSE;
+ }
+ // "PERMANENTFLAGS" SPACE flag_list
+ else if (parser.checkWithArg <special_atom>(line, &pos, "permanentflags", true))
+ {
+ m_type = PERMANENTFLAGS;
+
+ parser.check <SPACE>(line, &pos);
+
+ m_flag_list = parser.get <IMAPParser::flag_list>(line, &pos);
+ }
+ // "READ-ONLY"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "read-only", true))
+ {
+ m_type = READ_ONLY;
+ }
+ // "READ-WRITE"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "read-write", true))
+ {
+ m_type = READ_WRITE;
+ }
+ // "TRYCREATE"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "trycreate", true))
+ {
+ m_type = TRYCREATE;
+ }
+ // "UIDVALIDITY" SPACE nz_number
+ else if (parser.checkWithArg <special_atom>(line, &pos, "uidvalidity", true))
+ {
+ m_type = UIDVALIDITY;
+
+ parser.check <SPACE>(line, &pos);
+ m_nz_number = parser.get <IMAPParser::nz_number>(line, &pos);
+ }
+ // "UNSEEN" SPACE nz_number
+ else if (parser.checkWithArg <special_atom>(line, &pos, "unseen", true))
+ {
+ m_type = UNSEEN;
+
+ parser.check <SPACE>(line, &pos);
+ m_nz_number = parser.get <IMAPParser::nz_number>(line, &pos);
+ }
+ // atom [SPACE 1*<any TEXT_CHAR except "]">]
+ else
+ {
+ m_type = OTHER;
+
+ m_atom = parser.get <IMAPParser::atom>(line, &pos);
+
+ if (parser.check <SPACE>(line, &pos, true))
+ m_text = parser.get <text_except <']'> >(line, &pos);
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ ALERT,
+ PARSE,
+ PERMANENTFLAGS,
+ READ_ONLY,
+ READ_WRITE,
+ TRYCREATE,
+ UIDVALIDITY,
+ UNSEEN,
+ OTHER
+ };
+
+ private:
+
+ Type m_type;
+
+ IMAPParser::nz_number* m_nz_number;
+ IMAPParser::atom* m_atom;
+ IMAPParser::flag_list* m_flag_list;
+ IMAPParser::text* m_text;
+
+ public:
+
+ const Type type() const { return (m_type); }
+
+ const IMAPParser::nz_number* nz_number() const { return (m_nz_number); }
+ const IMAPParser::atom* atom() const { return (m_atom); }
+ const IMAPParser::flag_list* flag_list() const { return (m_flag_list); }
+ const IMAPParser::text* text() const { return (m_text); }
+ };
+
+
+ //
+ // resp_text ::= ["[" resp_text_code "]" SPACE] (text_mime2 / text)
+ // ;; text SHOULD NOT begin with "[" or "="
+
+ class resp_text : public component
+ {
+ public:
+
+ resp_text()
+ : m_resp_text_code(NULL)
+ {
+ }
+
+ ~resp_text()
+ {
+ delete (m_resp_text_code);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("resp_text");
+
+ string::size_type pos = *currentPos;
+
+ if (parser.check <one_char <'['> >(line, &pos, true))
+ {
+ m_resp_text_code = parser.get <IMAPParser::resp_text_code>(line, &pos);
+
+ parser.check <one_char <']'> >(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ }
+
+ text_mime2* text1 = parser.get <text_mime2>(line, &pos, true);
+
+ if (text1 != NULL)
+ {
+ m_text = text1->value();
+ delete (text1);
+ }
+ else
+ {
+ IMAPParser::text* text2 =
+ parser.get <IMAPParser::text>(line, &pos);
+
+ m_text = text2->value();
+ delete (text2);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::resp_text_code* m_resp_text_code;
+ string m_text;
+
+ public:
+
+ const IMAPParser::resp_text_code* resp_text_code() const { return (m_resp_text_code); }
+ const string& text() const { return (m_text); }
+ };
+
+
+ //
+ // continue_req ::= "+" SPACE (resp_text / base64)
+ //
+
+ class continue_req : public component
+ {
+ public:
+
+ continue_req()
+ : m_resp_text(NULL)
+ {
+ }
+
+ ~continue_req()
+ {
+ delete (m_resp_text);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("continue_req");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'+'> >(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_resp_text = parser.get <IMAPParser::resp_text>(line, &pos);
+
+ parser.check <CRLF>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::resp_text* m_resp_text;
+
+ public:
+
+ const IMAPParser::resp_text* resp_text() const { return (m_resp_text); }
+ };
+
+
+ //
+ // auth_type ::= atom
+ // ;; Defined by [IMAP-AUTH]
+ //
+
+ class auth_type : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("auth_type");
+
+ atom* at = parser.get <atom>(line, currentPos);
+ m_name = toLower(at->value());
+ delete (at);
+
+ if (m_name == "kerberos_v4")
+ m_type = KERBEROS_V4;
+ else if (m_name == "gssapi")
+ m_type = GSSAPI;
+ else if (m_name == "skey")
+ m_type = SKEY;
+ else
+ m_type = UNKNOWN;
+ }
+
+
+ enum Type
+ {
+ UNKNOWN,
+
+ // RFC 1731 - IMAP4 Authentication Mechanisms
+ KERBEROS_V4,
+ GSSAPI,
+ SKEY
+ };
+
+ private:
+
+ Type m_type;
+ string m_name;
+
+ public:
+
+ const Type type() const { return (m_type); }
+ const string name() const { return (m_name); }
+ };
+
+
+ //
+ // status_att ::= "MESSAGES" / "RECENT" / "UIDNEXT" /
+ // "UIDVALIDITY" / "UNSEEN"
+ //
+
+ class status_att : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("status_att");
+
+ string::size_type pos = *currentPos;
+
+ if (parser.checkWithArg <special_atom>(line, &pos, "messages", true))
+ {
+ m_type = MESSAGES;
+ }
+ else if (parser.checkWithArg <special_atom>(line, &pos, "recent", true))
+ {
+ m_type = RECENT;
+ }
+ else if (parser.checkWithArg <special_atom>(line, &pos, "uidnext", true))
+ {
+ m_type = UIDNEXT;
+ }
+ else if (parser.checkWithArg <special_atom>(line, &pos, "uidvalidity", true))
+ {
+ m_type = UIDVALIDITY;
+ }
+ else
+ {
+ parser.checkWithArg <special_atom>(line, &pos, "unseen");
+ m_type = UNSEEN;
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ MESSAGES,
+ RECENT,
+ UIDNEXT,
+ UIDVALIDITY,
+ UNSEEN
+ };
+
+ private:
+
+ Type m_type;
+
+ public:
+
+ const Type type() const { return (m_type); }
+ };
+
+
+ //
+ // capability ::= "AUTH=" auth_type / atom
+ // ;; New capabilities MUST begin with "X" or be
+ // ;; registered with IANA as standard or standards-track
+ //
+
+ class capability : public component
+ {
+ public:
+
+ capability()
+ : m_auth_type(NULL), m_atom(NULL)
+ {
+ }
+
+ ~capability()
+ {
+ delete (m_auth_type);
+ delete (m_atom);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("capability");
+
+ string::size_type pos = *currentPos;
+
+ class atom* at = parser.get <IMAPParser::atom>(line, &pos);
+
+ string value = at->value();
+ const char* str = value.c_str();
+
+ if ((str[0] == 'a' || str[0] == 'A') &&
+ (str[1] == 'u' || str[1] == 'U') &&
+ (str[2] == 't' || str[2] == 'T') &&
+ (str[3] == 'h' || str[3] == 'H') &&
+ (str[4] == '='))
+ {
+ string::size_type pos = 5;
+ m_auth_type = parser.get <IMAPParser::auth_type>(value, &pos);
+ delete (at);
+ }
+ else
+ {
+ m_atom = at;
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::auth_type* m_auth_type;
+ IMAPParser::atom* m_atom;
+
+ public:
+
+ const IMAPParser::auth_type* auth_type() const { return (m_auth_type); }
+ const IMAPParser::atom* atom() const { return (m_atom); }
+ };
+
+
+ //
+ // capability_data ::= "CAPABILITY" SPACE [1#capability SPACE] "IMAP4rev1"
+ // [SPACE 1#capability]
+ // ;; IMAP4rev1 servers which offer RFC 1730
+ // ;; compatibility MUST list "IMAP4" as the first
+ // ;; capability.
+ //
+
+ class capability_data : public component
+ {
+ public:
+
+ ~capability_data()
+ {
+ for (std::vector <capability*>::iterator it = m_capabilities.begin() ;
+ it != m_capabilities.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("capability_data");
+
+ string::size_type pos = *currentPos;
+
+ parser.checkWithArg <special_atom>(line, &pos, "capability");
+ parser.check <SPACE>(line, &pos);
+
+ bool IMAP4rev1 = false;
+
+ for (bool end = false ; !end && !IMAP4rev1 ; )
+ {
+ if (parser.checkWithArg <special_atom>(line, &pos, "imap4rev1", true))
+ {
+ IMAP4rev1 = true;
+ }
+ else
+ {
+ capability* cap = parser.get <capability>(line, &pos);
+ end = (cap == NULL);
+
+ if (cap)
+ {
+ m_capabilities.push_back(cap);
+ }
+ }
+
+ parser.check <SPACE>(line, &pos);
+ }
+
+
+ if (parser.check <SPACE>(line, &pos, true))
+ {
+ for (capability* cap = NULL ;
+ (cap = parser.get <capability>(line, &pos)) != NULL ; )
+ {
+ m_capabilities.push_back(cap);
+
+ parser.check <SPACE>(line, &pos);
+ }
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ std::vector <capability*> m_capabilities;
+
+ public:
+
+ const std::vector <capability*>& capabilities() const { return (m_capabilities); }
+ };
+
+
+ //
+ // date_day_fixed ::= (SPACE digit) / 2digit
+ // ;; Fixed-format version of date_day
+ //
+ // date_month ::= "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
+ // "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
+ //
+ // date_year ::= 4digit
+ //
+ // time ::= 2digit ":" 2digit ":" 2digit
+ // ;; Hours minutes seconds
+ //
+ // zone ::= ("+" / "-") 4digit
+ // ;; Signed four-digit value of hhmm representing
+ // ;; hours and minutes west of Greenwich (that is,
+ // ;; (the amount that the given time differs from
+ // ;; Universal Time). Subtracting the timezone
+ // ;; from the given time will give the UT form.
+ // ;; The Universal Time zone is "+0000".
+ //
+ // date_time ::= <"> date_day_fixed "-" date_month "-" date_year
+ // SPACE time SPACE zone <">
+ //
+
+ class date_time : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("date_time");
+
+ string::size_type pos = *currentPos;
+
+ // <"> date_day_fixed "-" date_month "-" date_year
+ parser.check <one_char <'"'> >(line, &pos);
+ parser.check <SPACE>(line, &pos, true);
+
+ utility::auto_ptr <number> nd(parser.get <number>(line, &pos));
+
+ parser.check <one_char <'-'> >(line, &pos);
+
+ utility::auto_ptr <atom> amo(parser.get <atom>(line, &pos));
+
+ parser.check <one_char <'-'> >(line, &pos);
+
+ utility::auto_ptr <number> ny(parser.get <number>(line, &pos));
+
+ parser.check <SPACE>(line, &pos, true);
+
+ // 2digit ":" 2digit ":" 2digit
+ utility::auto_ptr <number> nh(parser.get <number>(line, &pos));
+
+ parser.check <one_char <':'> >(line, &pos);
+
+ utility::auto_ptr <number> nmi(parser.get <number>(line, &pos));
+
+ parser.check <one_char <':'> >(line, &pos);
+
+ utility::auto_ptr <number> ns(parser.get <number>(line, &pos));
+
+ parser.check <SPACE>(line, &pos, true);
+
+ // ("+" / "-") 4digit
+ int sign = 1;
+
+ if (!(parser.check <one_char <'+'> >(line, &pos, true)))
+ parser.check <one_char <'-'> >(line, &pos);
+
+ utility::auto_ptr <number> nz(parser.get <number>(line, &pos));
+
+ parser.check <one_char <'"'> >(line, &pos);
+
+
+ m_datetime.hour() = std::min(std::max(nh->value(), 0u), 23u);
+ m_datetime.minute() = std::min(std::max(nmi->value(), 0u), 59u);
+ m_datetime.second() = std::min(std::max(ns->value(), 0u), 59u);
+
+ const int zone = static_cast <int>(nz->value());
+ const int zh = zone / 100; // hour offset
+ const int zm = zone % 100; // minute offset
+
+ m_datetime.zone() = ((zh * 60) + zm) * sign;
+
+ m_datetime.day() = std::min(std::max(nd->value(), 1u), 31u);
+ m_datetime.year() = ny->value();
+
+ const string month(vmime::toLower(amo->value()));
+ vmime::datetime::comp_t mon = vmime::datetime::JANUARY;
+
+ if (month.length() >= 3)
+ {
+ switch (month[0])
+ {
+ case 'j':
+ {
+ switch (month[1])
+ {
+ case 'a': mon = vmime::datetime::JANUARY; break;
+ case 'u':
+ {
+ switch (month[2])
+ {
+ case 'n': mon = vmime::datetime::JUNE; break;
+ default: mon = vmime::datetime::JULY; break;
+ }
+
+ break;
+ }
+
+ }
+
+ break;
+ }
+ case 'f': mon = vmime::datetime::FEBRUARY; break;
+ case 'm':
+ {
+ switch (month[2])
+ {
+ case 'r': mon = vmime::datetime::MARCH; break;
+ default: mon = vmime::datetime::MAY; break;
+ }
+
+ break;
+ }
+ case 'a':
+ {
+ switch (month[1])
+ {
+ case 'p': mon = vmime::datetime::APRIL; break;
+ default: mon = vmime::datetime::AUGUST; break;
+ }
+
+ break;
+ }
+ case 's': mon = vmime::datetime::SEPTEMBER; break;
+ case 'o': mon = vmime::datetime::OCTOBER; break;
+ case 'n': mon = vmime::datetime::NOVEMBER; break;
+ case 'd': mon = vmime::datetime::DECEMBER; break;
+ }
+ }
+
+ m_datetime.month() = mon;
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ vmime::datetime m_datetime;
+ };
+
+
+ //
+ // header_fld_name ::= astring
+ //
+
+ typedef astring header_fld_name;
+
+
+ //
+ // header_list ::= "(" 1#header_fld_name ")"
+ //
+
+ class header_list : public component
+ {
+ public:
+
+ ~header_list()
+ {
+ for (std::vector <header_fld_name*>::iterator it = m_fld_names.begin() ;
+ it != m_fld_names.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("header_list");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'('> >(line, &pos);
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ {
+ m_fld_names.push_back(parser.get <header_fld_name>(line, &pos));
+ parser.check <SPACE>(line, &pos, true);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ std::vector <header_fld_name*> m_fld_names;
+
+ public:
+
+ const std::vector <header_fld_name*>& fld_names() const { return (m_fld_names); }
+ };
+
+
+ //
+ // body_extension ::= nstring / number / "(" 1#body_extension ")"
+ // ;; Future expansion. Client implementations
+ // ;; MUST accept body_extension fields. Server
+ // ;; implementations MUST NOT generate
+ // ;; body_extension fields except as defined by
+ // ;; future standard or standards-track
+ // ;; revisions of this specification.
+ //
+
+ class body_extension : public component
+ {
+ public:
+
+ body_extension()
+ : m_nstring(NULL), m_number(NULL)
+ {
+ }
+
+ ~body_extension()
+ {
+ delete (m_nstring);
+ delete (m_number);
+
+ for (std::vector <body_extension*>::iterator it = m_body_extensions.begin() ;
+ it != m_body_extensions.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ string::size_type pos = *currentPos;
+
+ if (parser.check <one_char <'('> >(line, &pos, true))
+ {
+ m_body_extensions.push_back
+ (parser.get <body_extension>(line, &pos));
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ m_body_extensions.push_back(parser.get <body_extension>(line, &pos, true));
+ }
+ else
+ {
+ if (!(m_nstring = parser.get <IMAPParser::nstring>(line, &pos, true)))
+ m_number = parser.get <IMAPParser::number>(line, &pos);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::nstring* m_nstring;
+ IMAPParser::number* m_number;
+
+ std::vector <body_extension*> m_body_extensions;
+
+ public:
+
+ IMAPParser::nstring* nstring() const { return (m_nstring); }
+ IMAPParser::number* number() const { return (m_number); }
+
+ const std::vector <body_extension*>& body_extensions() const { return (m_body_extensions); }
+ };
+
+
+ //
+ // section_text ::= "HEADER" / "HEADER.FIELDS" [".NOT"]
+ // SPACE header_list / "TEXT" / "MIME"
+ //
+
+ class section_text : public component
+ {
+ public:
+
+ section_text()
+ : m_header_list(NULL)
+ {
+ }
+
+ ~section_text()
+ {
+ delete (m_header_list);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("section_text");
+
+ string::size_type pos = *currentPos;
+
+ // "HEADER.FIELDS" [".NOT"] SPACE header_list
+ const bool b1 = parser.checkWithArg <special_atom>(line, &pos, "header.fields.not", true);
+ const bool b2 = (b1 ? false : parser.checkWithArg <special_atom>(line, &pos, "header.fields", true));
+
+ if (b1 || b2)
+ {
+ m_type = b1 ? HEADER_FIELDS_NOT : HEADER_FIELDS;
+
+ parser.check <SPACE>(line, &pos);
+ m_header_list = parser.get <IMAPParser::header_list>(line, &pos);
+ }
+ // "HEADER"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "header", true))
+ {
+ m_type = HEADER;
+ }
+ // "MIME"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "mime", true))
+ {
+ m_type = MIME;
+ }
+ // "TEXT"
+ else
+ {
+ m_type = TEXT;
+
+ parser.checkWithArg <special_atom>(line, &pos, "text");
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ HEADER,
+ HEADER_FIELDS,
+ HEADER_FIELDS_NOT,
+ MIME,
+ TEXT
+ };
+
+ private:
+
+ Type m_type;
+ IMAPParser::header_list* m_header_list;
+
+ public:
+
+ const Type type() const { return (m_type); }
+ const IMAPParser::header_list* header_list() const { return (m_header_list); }
+ };
+
+
+ //
+ // section ::= "[" [section_text / (nz_number *["." nz_number]
+ // ["." (section_text / "MIME")])] "]"
+ //
+
+ class section : public component
+ {
+ public:
+
+ section()
+ : m_section_text1(NULL), m_section_text2(NULL)
+ {
+ }
+
+ ~section()
+ {
+ delete (m_section_text1);
+ delete (m_section_text2);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("section");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'['> >(line, &pos);
+
+ if (!parser.check <one_char <']'> >(line, &pos, true))
+ {
+ if (!(m_section_text1 = parser.get <section_text>(line, &pos, true)))
+ {
+ nz_number* num = parser.get <nz_number>(line, &pos);
+ m_nz_numbers.push_back(num->value());
+ delete (num);
+
+ while (parser.check <one_char <'.'> >(line, &pos, true))
+ {
+ if ((num = parser.get <nz_number>(line, &pos, true)))
+ {
+ m_nz_numbers.push_back(num->value());
+ delete (num);
+ }
+ else
+ {
+ m_section_text2 = parser.get <section_text>(line, &pos);
+ break;
+ }
+ }
+ }
+
+ parser.check <one_char <']'> >(line, &pos);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ section_text* m_section_text1;
+ section_text* m_section_text2;
+ std::vector <unsigned int> m_nz_numbers;
+
+ public:
+
+ const section_text* section_text1() const { return (m_section_text1); }
+ const section_text* section_text2() const { return (m_section_text2); }
+ const std::vector <unsigned int>& nz_numbers() const { return (m_nz_numbers); }
+ };
+
+
+ //
+ // addr_adl ::= nstring
+ // ;; Holds route from [RFC-822] route-addr if
+ // ;; non-NIL
+ //
+ // addr_host ::= nstring
+ // ;; NIL indicates [RFC-822] group syntax.
+ // ;; Otherwise, holds [RFC-822] domain name
+ //
+ // addr_mailbox ::= nstring
+ // ;; NIL indicates end of [RFC-822] group; if
+ // ;; non-NIL and addr_host is NIL, holds
+ // ;; [RFC-822] group name.
+ // ;; Otherwise, holds [RFC-822] local-part
+ //
+ // addr_name ::= nstring
+ // ;; Holds phrase from [RFC-822] mailbox if
+ // ;; non-NIL
+ //
+ // address ::= "(" addr_name SPACE addr_adl SPACE addr_mailbox
+ // SPACE addr_host ")"
+ //
+
+ class address : public component
+ {
+ public:
+
+ address()
+ : m_addr_name(NULL), m_addr_adl(NULL),
+ m_addr_mailbox(NULL), m_addr_host(NULL)
+ {
+ }
+
+ ~address()
+ {
+ delete (m_addr_name);
+ delete (m_addr_adl);
+ delete (m_addr_mailbox);
+ delete (m_addr_host);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("address");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'('> >(line, &pos);
+ m_addr_name = parser.get <nstring>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_addr_adl = parser.get <nstring>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_addr_mailbox = parser.get <nstring>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_addr_host = parser.get <nstring>(line, &pos);
+ parser.check <one_char <')'> >(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ nstring* m_addr_name;
+ nstring* m_addr_adl;
+ nstring* m_addr_mailbox;
+ nstring* m_addr_host;
+
+ public:
+
+ nstring* addr_name() const { return (m_addr_name); }
+ nstring* addr_adl() const { return (m_addr_adl); }
+ nstring* addr_mailbox() const { return (m_addr_mailbox); }
+ nstring* addr_host() const { return (m_addr_host); }
+ };
+
+
+ //
+ // address_list ::= "(" 1*address ")" / nil
+ //
+
+ class address_list : public component
+ {
+ public:
+
+ ~address_list()
+ {
+ for (std::vector <address*>::iterator it = m_addresses.begin() ;
+ it != m_addresses.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("address_list");
+
+ string::size_type pos = *currentPos;
+
+ if (!parser.check <NIL>(line, &pos, true))
+ {
+ parser.check <one_char <'('> >(line, &pos);
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ {
+ m_addresses.push_back(parser.get <address>(line, &pos));
+ parser.check <SPACE>(line, &pos, true);
+ }
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ std::vector <address*> m_addresses;
+
+ public:
+
+ const std::vector <address*>& addresses() const { return (m_addresses); }
+ };
+
+
+ //
+ // env_bcc ::= "(" 1*address ")" / nil
+ //
+
+ typedef address_list env_bcc;
+
+
+ //
+ // env_cc ::= "(" 1*address ")" / nil
+ //
+
+ typedef address_list env_cc;
+
+
+ //
+ // env_date ::= nstring
+ //
+
+ typedef nstring env_date;
+
+
+ //
+ // env_from ::= "(" 1*address ")" / nil
+ //
+
+ typedef address_list env_from;
+
+
+ //
+ // env_in_reply_to ::= nstring
+ //
+
+ typedef nstring env_in_reply_to;
+
+
+ //
+ // env_message_id ::= nstring
+ //
+
+ typedef nstring env_message_id;
+
+
+ //
+ // env_reply_to ::= "(" 1*address ")" / nil
+ //
+
+ typedef address_list env_reply_to;
+
+
+ //
+ // env_sender ::= "(" 1*address ")" / nil
+ //
+
+ typedef address_list env_sender;
+
+
+ //
+ // env_subject ::= nstring
+ //
+
+ typedef nstring env_subject;
+
+
+ //
+ // env_to ::= "(" 1*address ")" / nil
+ //
+
+ typedef address_list env_to;
+
+
+ //
+ // envelope ::= "(" env_date SPACE env_subject SPACE env_from
+ // SPACE env_sender SPACE env_reply_to SPACE env_to
+ // SPACE env_cc SPACE env_bcc SPACE env_in_reply_to
+ // SPACE env_message_id ")"
+ //
+
+ class envelope : public component
+ {
+ public:
+
+ envelope()
+ : m_env_date(NULL), m_env_subject(NULL),
+ m_env_from(NULL), m_env_sender(NULL), m_env_reply_to(NULL),
+ m_env_to(NULL), m_env_cc(NULL), m_env_bcc(NULL),
+ m_env_in_reply_to(NULL), m_env_message_id(NULL)
+ {
+ }
+
+ ~envelope()
+ {
+ delete (m_env_date);
+ delete (m_env_subject);
+ delete (m_env_from);
+ delete (m_env_sender);
+ delete (m_env_reply_to);
+ delete (m_env_to);
+ delete (m_env_cc);
+ delete (m_env_bcc);
+ delete (m_env_in_reply_to);
+ delete (m_env_message_id);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("envelope");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'('> >(line, &pos);
+
+ m_env_date = parser.get <IMAPParser::env_date>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_subject = parser.get <IMAPParser::env_subject>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_from = parser.get <IMAPParser::env_from>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_sender = parser.get <IMAPParser::env_sender>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_reply_to = parser.get <IMAPParser::env_reply_to>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_to = parser.get <IMAPParser::env_to>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_cc = parser.get <IMAPParser::env_cc>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_bcc = parser.get <IMAPParser::env_bcc>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_in_reply_to = parser.get <IMAPParser::env_in_reply_to>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_env_message_id = parser.get <IMAPParser::env_message_id>(line, &pos);
+
+ parser.check <one_char <')'> >(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::env_date* m_env_date;
+ IMAPParser::env_subject* m_env_subject;
+ IMAPParser::env_from* m_env_from;
+ IMAPParser::env_sender* m_env_sender;
+ IMAPParser::env_reply_to* m_env_reply_to;
+ IMAPParser::env_to* m_env_to;
+ IMAPParser::env_cc* m_env_cc;
+ IMAPParser::env_bcc* m_env_bcc;
+ IMAPParser::env_in_reply_to* m_env_in_reply_to;
+ IMAPParser::env_message_id* m_env_message_id;
+
+ public:
+
+ const IMAPParser::env_date* env_date() const { return (m_env_date); }
+ const IMAPParser::env_subject* env_subject() const { return (m_env_subject); }
+ const IMAPParser::env_from* env_from() const { return (m_env_from); }
+ const IMAPParser::env_sender* env_sender() const { return (m_env_sender); }
+ const IMAPParser::env_reply_to* env_reply_to() const { return (m_env_reply_to); }
+ const IMAPParser::env_to* env_to() const { return (m_env_to); }
+ const IMAPParser::env_cc* env_cc() const { return (m_env_cc); }
+ const IMAPParser::env_bcc* env_bcc() const { return (m_env_bcc); }
+ const IMAPParser::env_in_reply_to* env_in_reply_to() const { return (m_env_in_reply_to); }
+ const IMAPParser::env_message_id* env_message_id() const { return (m_env_message_id); }
+ };
+
+
+ //
+ // body_fld_desc ::= nstring
+ //
+
+ typedef nstring body_fld_desc;
+
+
+ //
+ // body_fld_id ::= nstring
+ //
+
+ typedef nstring body_fld_id;
+
+
+ //
+ // body_fld_md5 ::= nstring
+ //
+
+ typedef nstring body_fld_md5;
+
+
+ //
+ // body_fld_octets ::= number
+ //
+
+ typedef number body_fld_octets;
+
+
+ //
+ // body_fld_lines ::= number
+ //
+
+ typedef number body_fld_lines;
+
+
+ //
+ // body_fld_enc ::= (<"> ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
+ // "QUOTED-PRINTABLE") <">) / string
+ //
+
+ typedef xstring body_fld_enc;
+
+
+ //
+ // body_fld_param_item ::= string SPACE string
+ //
+
+ class body_fld_param_item : public component
+ {
+ public:
+
+ body_fld_param_item()
+ : m_string1(NULL), m_string2(NULL)
+ {
+ }
+
+ ~body_fld_param_item()
+ {
+ delete (m_string1);
+ delete (m_string2);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_fld_param_item");
+
+ string::size_type pos = *currentPos;
+
+ m_string1 = parser.get <xstring>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_string2 = parser.get <xstring>(line, &pos);
+
+ DEBUG_FOUND("body_fld_param_item", "<" << m_string1->value() << ", " << m_string2->value() << ">");
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ xstring* m_string1;
+ xstring* m_string2;
+
+ public:
+
+ const xstring* string1() const { return (m_string1); }
+ const xstring* string2() const { return (m_string2); }
+ };
+
+
+ //
+ // body_fld_param ::= "(" 1#(body_fld_param_item) ")" / nil
+ //
+
+ class body_fld_param : public component
+ {
+ public:
+
+ ~body_fld_param()
+ {
+ for (std::vector <body_fld_param_item*>::iterator it = m_items.begin() ;
+ it != m_items.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_fld_param");
+
+ string::size_type pos = *currentPos;
+
+ if (!parser.check <NIL>(line, &pos, true))
+ {
+ parser.check <one_char <'('> >(line, &pos);
+
+ m_items.push_back(parser.get <body_fld_param_item>(line, &pos));
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ {
+ parser.check <SPACE>(line, &pos);
+ m_items.push_back(parser.get <body_fld_param_item>(line, &pos));
+ }
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ std::vector <body_fld_param_item*> m_items;
+
+ public:
+
+ const std::vector <body_fld_param_item*>& items() const { return (m_items); }
+ };
+
+
+ //
+ // body_fld_dsp ::= "(" string SPACE body_fld_param ")" / nil
+ //
+
+ class body_fld_dsp : public component
+ {
+ public:
+
+ body_fld_dsp()
+ : m_string(NULL), m_body_fld_param(NULL)
+ {
+ }
+
+ ~body_fld_dsp()
+ {
+ delete (m_string);
+ delete (m_body_fld_param);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_fld_dsp");
+
+ string::size_type pos = *currentPos;
+
+ if (!parser.check <NIL>(line, &pos, true))
+ {
+ parser.check <one_char <'('> >(line, &pos);
+ m_string = parser.get <xstring>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fld_param = parser.get <class body_fld_param>(line, &pos);
+ parser.check <one_char <')'> >(line, &pos);
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ class xstring* m_string;
+ class body_fld_param* m_body_fld_param;
+
+ public:
+
+ const class xstring* str() const { return (m_string); }
+ const class body_fld_param* body_fld_param() const { return (m_body_fld_param); }
+ };
+
+
+ //
+ // body_fld_lang ::= nstring / "(" 1#string ")"
+ //
+
+ class body_fld_lang : public component
+ {
+ public:
+
+ ~body_fld_lang()
+ {
+ for (std::vector <xstring*>::iterator it = m_strings.begin() ;
+ it != m_strings.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_fld_lang");
+
+ string::size_type pos = *currentPos;
+
+ if (parser.check <one_char <'('> >(line, &pos, true))
+ {
+ m_strings.push_back(parser.get <class xstring>(line, &pos));
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ m_strings.push_back(parser.get <class xstring>(line, &pos));
+ }
+ else
+ {
+ m_strings.push_back(parser.get <class nstring>(line, &pos));
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ std::vector <xstring*> m_strings;
+
+ public:
+
+ const std::vector <xstring*>& strings() const { return (m_strings); }
+ };
+
+
+ //
+ // body_fields ::= body_fld_param SPACE body_fld_id SPACE
+ // body_fld_desc SPACE body_fld_enc SPACE
+ // body_fld_octets
+ //
+
+ class body_fields : public component
+ {
+ public:
+
+ body_fields()
+ : m_body_fld_param(NULL), m_body_fld_id(NULL),
+ m_body_fld_desc(NULL), m_body_fld_enc(NULL), m_body_fld_octets(NULL)
+ {
+ }
+
+ ~body_fields()
+ {
+ delete (m_body_fld_param);
+ delete (m_body_fld_id);
+ delete (m_body_fld_desc);
+ delete (m_body_fld_enc);
+ delete (m_body_fld_octets);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_fields");
+
+ string::size_type pos = *currentPos;
+
+ m_body_fld_param = parser.get <IMAPParser::body_fld_param>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fld_id = parser.get <IMAPParser::body_fld_id>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fld_desc = parser.get <IMAPParser::body_fld_desc>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fld_enc = parser.get <IMAPParser::body_fld_enc>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fld_octets = parser.get <IMAPParser::body_fld_octets>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::body_fld_param* m_body_fld_param;
+ IMAPParser::body_fld_id* m_body_fld_id;
+ IMAPParser::body_fld_desc* m_body_fld_desc;
+ IMAPParser::body_fld_enc* m_body_fld_enc;
+ IMAPParser::body_fld_octets* m_body_fld_octets;
+
+ public:
+
+ const IMAPParser::body_fld_param* body_fld_param() const { return (m_body_fld_param); }
+ const IMAPParser::body_fld_id* body_fld_id() const { return (m_body_fld_id); }
+ const IMAPParser::body_fld_desc* body_fld_desc() const { return (m_body_fld_desc); }
+ const IMAPParser::body_fld_enc* body_fld_enc() const { return (m_body_fld_enc); }
+ const IMAPParser::body_fld_octets* body_fld_octets() const { return (m_body_fld_octets); }
+ };
+
+
+ //
+ // media_subtype ::= string
+ // ;; Defined in [MIME-IMT]
+ //
+
+ typedef xstring media_subtype;
+
+
+ //
+ // media_text ::= <"> "TEXT" <"> SPACE media_subtype
+ // ;; Defined in [MIME-IMT]
+ //
+
+ class media_text : public component
+ {
+ public:
+
+ media_text()
+ : m_media_subtype(NULL)
+ {
+ }
+
+ ~media_text()
+ {
+ delete (m_media_subtype);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("media_text");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'"'> >(line, &pos);
+ parser.checkWithArg <special_atom>(line, &pos, "text");
+ parser.check <one_char <'"'> >(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_media_subtype = parser.get <IMAPParser::media_subtype>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::media_subtype* m_media_subtype;
+
+ public:
+
+ const IMAPParser::media_subtype* media_subtype() const { return (m_media_subtype); }
+ };
+
+
+ //
+ // media_message ::= <"> "MESSAGE" <"> SPACE <"> "RFC822" <">
+ // ;; Defined in [MIME-IMT]
+ //
+
+ class media_message : public component
+ {
+ public:
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("media_message");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'"'> >(line, &pos);
+ parser.checkWithArg <special_atom>(line, &pos, "message");
+ parser.check <one_char <'"'> >(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ //parser.check <one_char <'"'> >(line, &pos);
+ //parser.checkWithArg <special_atom>(line, &pos, "rfc822");
+ //parser.check <one_char <'"'> >(line, &pos);
+
+ m_media_subtype = parser.get <IMAPParser::media_subtype>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::media_subtype* m_media_subtype;
+
+ public:
+
+ const IMAPParser::media_subtype* media_subtype() const { return (m_media_subtype); }
+ };
+
+
+ //
+ // media_basic ::= (<"> ("APPLICATION" / "AUDIO" / "IMAGE" /
+ // "MESSAGE" / "VIDEO") <">) / string)
+ // SPACE media_subtype
+ // ;; Defined in [MIME-IMT]
+
+ class media_basic : public component
+ {
+ public:
+
+ media_basic()
+ : m_media_type(NULL), m_media_subtype(NULL)
+ {
+ }
+
+ ~media_basic()
+ {
+ delete (m_media_type);
+ delete (m_media_subtype);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("media_basic");
+
+ string::size_type pos = *currentPos;
+
+ m_media_type = parser.get <xstring>(line, &pos);
+
+ parser.check <SPACE>(line, &pos);
+
+ m_media_subtype = parser.get <IMAPParser::media_subtype>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::xstring* m_media_type;
+ IMAPParser::media_subtype* m_media_subtype;
+
+ public:
+
+ const IMAPParser::xstring* media_type() const { return (m_media_type); }
+ const IMAPParser::media_subtype* media_subtype() const { return (m_media_subtype); }
+ };
+
+
+ //
+ // body_ext_1part ::= body_fld_md5 [SPACE body_fld_dsp
+ // [SPACE body_fld_lang
+ // [SPACE 1#body_extension]]]
+ // ;; MUST NOT be returned on non-extensible
+ // ;; "BODY" fetch
+ //
+
+ class body_ext_1part : public component
+ {
+ public:
+
+ body_ext_1part()
+ : m_body_fld_md5(NULL), m_body_fld_dsp(NULL), m_body_fld_lang(NULL)
+ {
+ }
+
+ ~body_ext_1part()
+ {
+ delete (m_body_fld_md5);
+ delete (m_body_fld_dsp);
+ delete (m_body_fld_lang);
+
+ for (std::vector <body_extension*>::iterator it = m_body_extensions.begin() ;
+ it != m_body_extensions.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_ext_1part");
+
+ string::size_type pos = *currentPos;
+
+ m_body_fld_md5 = parser.get <IMAPParser::body_fld_md5>(line, &pos);
+
+ // [SPACE body_fld_dsp
+ if (parser.check <SPACE>(line, &pos, true))
+ {
+ m_body_fld_dsp = parser.get <IMAPParser::body_fld_dsp>(line, &pos);
+
+ // [SPACE body_fld_lang
+ if (parser.check <SPACE>(line, &pos, true))
+ {
+ m_body_fld_lang = parser.get <IMAPParser::body_fld_lang>(line, &pos);
+
+ // [SPACE 1#body_extension]
+ if (parser.check <SPACE>(line, &pos, true))
+ {
+ m_body_extensions.push_back
+ (parser.get <body_extension>(line, &pos));
+
+ body_extension* ext = NULL;
+
+ while ((ext = parser.get <body_extension>(line, &pos, true)) != NULL)
+ m_body_extensions.push_back(ext);
+ }
+ }
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::body_fld_md5* m_body_fld_md5;
+ IMAPParser::body_fld_dsp* m_body_fld_dsp;
+ IMAPParser::body_fld_lang* m_body_fld_lang;
+
+ std::vector <body_extension*> m_body_extensions;
+
+ public:
+
+ const IMAPParser::body_fld_md5* body_fld_md5() const { return (m_body_fld_md5); }
+ const IMAPParser::body_fld_dsp* body_fld_dsp() const { return (m_body_fld_dsp); }
+ const IMAPParser::body_fld_lang* body_fld_lang() const { return (m_body_fld_lang); }
+
+ const std::vector <body_extension*> body_extensions() const { return (m_body_extensions); }
+ };
+
+
+ //
+ // body_ext_mpart ::= body_fld_param
+ // [SPACE body_fld_dsp SPACE body_fld_lang
+ // [SPACE 1#body_extension]]
+ // ;; MUST NOT be returned on non-extensible
+ // ;; "BODY" fetch
+
+ class body_ext_mpart : public component
+ {
+ public:
+
+ body_ext_mpart()
+ : m_body_fld_param(NULL), m_body_fld_dsp(NULL), m_body_fld_lang(NULL)
+ {
+ }
+
+ ~body_ext_mpart()
+ {
+ delete (m_body_fld_param);
+ delete (m_body_fld_dsp);
+ delete (m_body_fld_lang);
+
+ for (std::vector <body_extension*>::iterator it = m_body_extensions.begin() ;
+ it != m_body_extensions.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_ext_mpart");
+
+ string::size_type pos = *currentPos;
+
+ m_body_fld_param = parser.get <IMAPParser::body_fld_param>(line, &pos);
+
+ // [SPACE body_fld_dsp SPACE body_fld_lang [SPACE 1#body_extension]]
+ if (parser.check <SPACE>(line, &pos, true))
+ {
+ m_body_fld_dsp = parser.get <IMAPParser::body_fld_dsp>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fld_lang = parser.get <IMAPParser::body_fld_lang>(line, &pos);
+
+ // [SPACE 1#body_extension]
+ if (parser.check <SPACE>(line, &pos, true))
+ {
+ m_body_extensions.push_back
+ (parser.get <body_extension>(line, &pos));
+
+ body_extension* ext = NULL;
+
+ while ((ext = parser.get <body_extension>(line, &pos, true)) != NULL)
+ m_body_extensions.push_back(ext);
+ }
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::body_fld_param* m_body_fld_param;
+ IMAPParser::body_fld_dsp* m_body_fld_dsp;
+ IMAPParser::body_fld_lang* m_body_fld_lang;
+
+ std::vector <body_extension*> m_body_extensions;
+
+ public:
+
+ const IMAPParser::body_fld_param* body_fld_param() const { return (m_body_fld_param); }
+ const IMAPParser::body_fld_dsp* body_fld_dsp() const { return (m_body_fld_dsp); }
+ const IMAPParser::body_fld_lang* body_fld_lang() const { return (m_body_fld_lang); }
+
+ const std::vector <body_extension*> body_extensions() const { return (m_body_extensions); }
+ };
+
+
+ //
+ // body_type_basic ::= media_basic SPACE body_fields
+ // ;; MESSAGE subtype MUST NOT be "RFC822"
+ //
+
+ class body_type_basic : public component
+ {
+ public:
+
+ body_type_basic()
+ : m_media_basic(NULL), m_body_fields(NULL)
+ {
+ }
+
+ ~body_type_basic()
+ {
+ delete (m_media_basic);
+ delete (m_body_fields);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_type_basic");
+
+ string::size_type pos = *currentPos;
+
+ m_media_basic = parser.get <IMAPParser::media_basic>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fields = parser.get <IMAPParser::body_fields>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::media_basic* m_media_basic;
+ IMAPParser::body_fields* m_body_fields;
+
+ public:
+
+ const IMAPParser::media_basic* media_basic() const { return (m_media_basic); }
+ const IMAPParser::body_fields* body_fields() const { return (m_body_fields); }
+ };
+
+
+ //
+ // body_type_msg ::= media_message SPACE body_fields SPACE envelope
+ // SPACE body SPACE body_fld_lines
+ //
+
+ class xbody;
+ typedef xbody body;
+
+ class body_type_msg : public component
+ {
+ public:
+
+ body_type_msg()
+ : m_media_message(NULL), m_body_fields(NULL),
+ m_envelope(NULL), m_body(NULL), m_body_fld_lines(NULL)
+ {
+ }
+
+ ~body_type_msg()
+ {
+ delete (m_media_message);
+ delete (m_body_fields);
+ delete (m_envelope);
+ delete (m_body);
+ delete (m_body_fld_lines);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_type_msg");
+
+ string::size_type pos = *currentPos;
+
+ m_media_message = parser.get <IMAPParser::media_message>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fields = parser.get <IMAPParser::body_fields>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_envelope = parser.get <IMAPParser::envelope>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body = parser.get <IMAPParser::xbody>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fld_lines = parser.get <IMAPParser::body_fld_lines>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::media_message* m_media_message;
+ IMAPParser::body_fields* m_body_fields;
+ IMAPParser::envelope* m_envelope;
+ IMAPParser::xbody* m_body;
+ IMAPParser::body_fld_lines* m_body_fld_lines;
+
+ public:
+
+ const IMAPParser::media_message* media_message() const { return (m_media_message); }
+ const IMAPParser::body_fields* body_fields() const { return (m_body_fields); }
+ const IMAPParser::envelope* envelope() const { return (m_envelope); }
+ const IMAPParser::xbody* body() const { return (m_body); }
+ const IMAPParser::body_fld_lines* body_fld_lines() const { return (m_body_fld_lines); }
+ };
+
+
+ //
+ // body_type_text ::= media_text SPACE body_fields SPACE body_fld_lines
+ //
+
+ class body_type_text : public component
+ {
+ public:
+
+ body_type_text()
+ : m_media_text(NULL),
+ m_body_fields(NULL), m_body_fld_lines(NULL)
+ {
+ }
+
+ ~body_type_text()
+ {
+ delete (m_media_text);
+ delete (m_body_fields);
+ delete (m_body_fld_lines);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_type_text");
+
+ string::size_type pos = *currentPos;
+
+ m_media_text = parser.get <IMAPParser::media_text>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fields = parser.get <IMAPParser::body_fields>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_body_fld_lines = parser.get <IMAPParser::body_fld_lines>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::media_text* m_media_text;
+ IMAPParser::body_fields* m_body_fields;
+ IMAPParser::body_fld_lines* m_body_fld_lines;
+
+ public:
+
+ const IMAPParser::media_text* media_text() const { return (m_media_text); }
+ const IMAPParser::body_fields* body_fields() const { return (m_body_fields); }
+ const IMAPParser::body_fld_lines* body_fld_lines() const { return (m_body_fld_lines); }
+ };
+
+
+ //
+ // body_type_1part ::= (body_type_basic / body_type_msg / body_type_text)
+ // [SPACE body_ext_1part]
+ //
+
+ class body_type_1part : public component
+ {
+ public:
+
+ body_type_1part()
+ : m_body_type_basic(NULL), m_body_type_msg(NULL),
+ m_body_type_text(NULL), m_body_ext_1part(NULL)
+ {
+ }
+
+ ~body_type_1part()
+ {
+ delete (m_body_type_basic);
+ delete (m_body_type_msg);
+ delete (m_body_type_text);
+
+ delete (m_body_ext_1part);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_type_1part");
+
+ string::size_type pos = *currentPos;
+
+ if (!(m_body_type_text = parser.get <IMAPParser::body_type_text>(line, &pos, true)))
+ if (!(m_body_type_msg = parser.get <IMAPParser::body_type_msg>(line, &pos, true)))
+ m_body_type_basic = parser.get <IMAPParser::body_type_basic>(line, &pos);
+
+ if (parser.check <SPACE>(line, &pos, true))
+ m_body_ext_1part = parser.get <IMAPParser::body_ext_1part>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::body_type_basic* m_body_type_basic;
+ IMAPParser::body_type_msg* m_body_type_msg;
+ IMAPParser::body_type_text* m_body_type_text;
+
+ IMAPParser::body_ext_1part* m_body_ext_1part;
+
+ public:
+
+ const IMAPParser::body_type_basic* body_type_basic() const { return (m_body_type_basic); }
+ const IMAPParser::body_type_msg* body_type_msg() const { return (m_body_type_msg); }
+ const IMAPParser::body_type_text* body_type_text() const { return (m_body_type_text); }
+
+ const IMAPParser::body_ext_1part* body_ext_1part() const { return (m_body_ext_1part); }
+ };
+
+
+ //
+ // body_type_mpart ::= 1*body SPACE media_subtype
+ // [SPACE body_ext_mpart]
+ //
+
+ class body_type_mpart : public component
+ {
+ public:
+
+ body_type_mpart()
+ : m_media_subtype(NULL), m_body_ext_mpart(NULL)
+ {
+ }
+
+ ~body_type_mpart()
+ {
+ delete (m_media_subtype);
+ delete (m_body_ext_mpart);
+
+ for (std::vector <xbody*>::iterator it = m_list.begin() ;
+ it != m_list.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body_type_mpart");
+
+ string::size_type pos = *currentPos;
+
+ m_list.push_back(parser.get <xbody>(line, &pos));
+
+ for (xbody* b ; (b = parser.get <xbody>(line, &pos, true)) ; )
+ m_list.push_back(b);
+
+ parser.check <SPACE>(line, &pos);
+
+ m_media_subtype = parser.get <IMAPParser::media_subtype>(line, &pos);
+
+ if (parser.check <SPACE>(line, &pos, true))
+ m_body_ext_mpart = parser.get <IMAPParser::body_ext_mpart>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::media_subtype* m_media_subtype;
+ IMAPParser::body_ext_mpart* m_body_ext_mpart;
+
+ std::vector <xbody*> m_list;
+
+ public:
+
+ const std::vector <IMAPParser::xbody*>& list() const { return (m_list); }
+
+ const IMAPParser::media_subtype* media_subtype() const { return (m_media_subtype); }
+ const IMAPParser::body_ext_mpart* body_ext_mpart() const { return (m_body_ext_mpart); }
+ };
+
+
+ //
+ // xbody ::= "(" body_type_1part / body_type_mpart ")"
+ //
+
+ class xbody : public component
+ {
+ public:
+
+ xbody()
+ : m_body_type_1part(NULL), m_body_type_mpart(NULL)
+ {
+ }
+
+ ~xbody()
+ {
+ delete (m_body_type_1part);
+ delete (m_body_type_mpart);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("body");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'('> >(line, &pos);
+
+ if (!(m_body_type_1part = parser.get <IMAPParser::body_type_1part>(line, &pos, true)))
+ m_body_type_mpart = parser.get <IMAPParser::body_type_mpart>(line, &pos);
+
+ parser.check <one_char <')'> >(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::body_type_1part* m_body_type_1part;
+ IMAPParser::body_type_mpart* m_body_type_mpart;
+
+ public:
+
+ const IMAPParser::body_type_1part* body_type_1part() const { return (m_body_type_1part); }
+ const IMAPParser::body_type_mpart* body_type_mpart() const { return (m_body_type_mpart); }
+ };
+
+
+ //
+ // uniqueid ::= nz_number
+ // ;; Strictly ascending
+ //
+ // msg_att_item ::= "ENVELOPE" SPACE envelope /
+ // "FLAGS" SPACE "(" #(flag / "\Recent") ")" /
+ // "INTERNALDATE" SPACE date_time /
+ // "RFC822" [".HEADER" / ".TEXT"] SPACE nstring /
+ // "RFC822.SIZE" SPACE number /
+ // "BODY" ["STRUCTURE"] SPACE body /
+ // "BODY" section ["<" number ">"] SPACE nstring /
+ // "UID" SPACE uniqueid
+ //
+
+ class msg_att_item : public component
+ {
+ public:
+
+ msg_att_item()
+ : m_date_time(NULL), m_number(NULL), m_envelope(NULL),
+ m_uniqueid(NULL), m_nstring(NULL), m_body(NULL), m_flag_list(NULL)
+ {
+ }
+
+ ~msg_att_item()
+ {
+ delete (m_date_time);
+ delete (m_number);
+ delete (m_envelope);
+ delete (m_uniqueid);
+ delete (m_nstring);
+ delete (m_body);
+ delete (m_flag_list);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("msg_att_item");
+
+ string::size_type pos = *currentPos;
+
+ // "ENVELOPE" SPACE envelope
+ if (parser.checkWithArg <special_atom>(line, &pos, "envelope", true))
+ {
+ m_type = ENVELOPE;
+
+ parser.check <SPACE>(line, &pos);
+ m_envelope = parser.get <IMAPParser::envelope>(line, &pos);
+ }
+ // "FLAGS" SPACE "(" #(flag / "\Recent") ")"
+ else if (parser.checkWithArg <special_atom>(line, &pos, "flags", true))
+ {
+ m_type = FLAGS;
+
+ parser.check <SPACE>(line, &pos);
+
+ m_flag_list = parser.get <IMAPParser::flag_list>(line, &pos);
+ }
+ // "INTERNALDATE" SPACE date_time
+ else if (parser.checkWithArg <special_atom>(line, &pos, "internaldate", true))
+ {
+ m_type = INTERNALDATE;
+
+ parser.check <SPACE>(line, &pos);
+ m_date_time = parser.get <IMAPParser::date_time>(line, &pos);
+ }
+ // "RFC822" ".HEADER" SPACE nstring
+ else if (parser.checkWithArg <special_atom>(line, &pos, "rfc822.header", true))
+ {
+ m_type = RFC822_HEADER;
+
+ parser.check <SPACE>(line, &pos);
+
+ m_nstring = parser.get <IMAPParser::nstring>(line, &pos);
+ }
+ // "RFC822" ".TEXT" SPACE nstring
+ else if (parser.checkWithArg <special_atom>(line, &pos, "rfc822.text", true))
+ {
+ m_type = RFC822_TEXT;
+
+ parser.check <SPACE>(line, &pos);
+
+ m_nstring = parser.getWithArgs <IMAPParser::nstring>
+ (line, &pos, this, RFC822_TEXT);
+ }
+ // "RFC822.SIZE" SPACE number
+ else if (parser.checkWithArg <special_atom>(line, &pos, "rfc822.size", true))
+ {
+ m_type = RFC822_SIZE;
+
+ parser.check <SPACE>(line, &pos);
+ m_number = parser.get <IMAPParser::number>(line, &pos);
+ }
+ // "RFC822" SPACE nstring
+ else if (parser.checkWithArg <special_atom>(line, &pos, "rfc822", true))
+ {
+ m_type = RFC822;
+
+ parser.check <SPACE>(line, &pos);
+
+ m_nstring = parser.get <IMAPParser::nstring>(line, &pos);
+ }
+ // "BODY" "STRUCTURE" SPACE body
+ else if (parser.checkWithArg <special_atom>(line, &pos, "bodystructure", true))
+ {
+ m_type = BODY_STRUCTURE;
+
+ parser.check <SPACE>(line, &pos);
+
+ m_body = parser.get <IMAPParser::body>(line, &pos);
+ }
+ // "BODY" section ["<" number ">"] SPACE nstring
+ // "BODY" SPACE body
+ else if (parser.checkWithArg <special_atom>(line, &pos, "body", true))
+ {
+ m_section = parser.get <IMAPParser::section>(line, &pos, true);
+
+ // "BODY" section ["<" number ">"] SPACE nstring
+ if (m_section != NULL)
+ {
+ m_type = BODY_SECTION;
+
+ if (parser.check <one_char <'<'> >(line, &pos, true))
+ {
+ m_number = parser.get <IMAPParser::number>(line, &pos);
+ parser.check <one_char <'>'> >(line, &pos);
+ }
+
+ parser.check <SPACE>(line, &pos);
+
+ m_nstring = parser.getWithArgs <IMAPParser::nstring>
+ (line, &pos, this, BODY_SECTION);
+ }
+ // "BODY" SPACE body
+ else
+ {
+ m_type = BODY;
+
+ parser.check <SPACE>(line, &pos);
+
+ m_body = parser.get <IMAPParser::body>(line, &pos);
+ }
+ }
+ // "UID" SPACE uniqueid
+ else
+ {
+ m_type = UID;
+
+ parser.checkWithArg <special_atom>(line, &pos, "uid");
+ parser.check <SPACE>(line, &pos);
+
+ m_uniqueid = parser.get <nz_number>(line, &pos);
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ ENVELOPE,
+ FLAGS,
+ INTERNALDATE,
+ RFC822,
+ RFC822_SIZE,
+ RFC822_HEADER,
+ RFC822_TEXT,
+ BODY,
+ BODY_SECTION,
+ BODY_STRUCTURE,
+ UID
+ };
+
+ private:
+
+ Type m_type;
+
+ IMAPParser::date_time* m_date_time;
+ IMAPParser::number* m_number;
+ IMAPParser::envelope* m_envelope;
+ IMAPParser::nz_number* m_uniqueid;
+ IMAPParser::nstring* m_nstring;
+ IMAPParser::xbody* m_body;
+ IMAPParser::flag_list* m_flag_list;
+ IMAPParser::section* m_section;
+
+ public:
+
+ const Type type() const { return (m_type); }
+
+ const IMAPParser::date_time* date_time() const { return (m_date_time); }
+ const IMAPParser::number* number() const { return (m_number); }
+ const IMAPParser::envelope* envelope() const { return (m_envelope); }
+ const IMAPParser::nz_number* unique_id() const { return (m_uniqueid); }
+ const IMAPParser::nstring* nstring() const { return (m_nstring); }
+ const IMAPParser::xbody* body() const { return (m_body); }
+ const IMAPParser::flag_list* flag_list() const { return (m_flag_list); }
+ const IMAPParser::section* section() const { return (m_section); }
+ };
+
+
+ //
+ // msg_att ::= "(" 1#(msg_att_item) ")"
+ //
+
+ class msg_att : public component
+ {
+ public:
+
+ ~msg_att()
+ {
+ for (std::vector <msg_att_item*>::iterator it = m_items.begin() ;
+ it != m_items.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("msg_att");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'('> >(line, &pos);
+
+ m_items.push_back(parser.get <msg_att_item>(line, &pos));
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ {
+ parser.check <SPACE>(line, &pos);
+ m_items.push_back(parser.get <msg_att_item>(line, &pos));
+ }
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ std::vector <msg_att_item*> m_items;
+
+ public:
+
+ const std::vector <msg_att_item*>& items() const { return (m_items); }
+ };
+
+
+ //
+ // message_data ::= nz_number SPACE ("EXPUNGE" /
+ // ("FETCH" SPACE msg_att))
+ //
+
+ class message_data : public component
+ {
+ public:
+
+ message_data()
+ : m_number(0), m_msg_att(NULL)
+ {
+ }
+
+ ~message_data()
+ {
+ delete (m_msg_att);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("message_data");
+
+ string::size_type pos = *currentPos;
+
+ nz_number* num = parser.get <nz_number>(line, &pos);
+ m_number = num->value();
+ delete (num);
+
+ parser.check <SPACE>(line, &pos);
+
+ if (parser.checkWithArg <special_atom>(line, &pos, "expunge", true))
+ {
+ m_type = EXPUNGE;
+ }
+ else
+ {
+ parser.checkWithArg <special_atom>(line, &pos, "fetch");
+
+ parser.check <SPACE>(line, &pos);
+
+ m_type = FETCH;
+ m_msg_att = parser.get <IMAPParser::msg_att>(line, &pos);
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ EXPUNGE,
+ FETCH
+ };
+
+ private:
+
+ Type m_type;
+ unsigned int m_number;
+ IMAPParser::msg_att* m_msg_att;
+
+ public:
+
+ const Type type() const { return (m_type); }
+ const unsigned int number() const { return (m_number); }
+ const IMAPParser::msg_att* msg_att() const { return (m_msg_att); }
+ };
+
+
+ //
+ // resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text
+ // ;; Status condition
+ //
+
+ class resp_cond_state : public component
+ {
+ public:
+
+ resp_cond_state()
+ : m_resp_text(NULL), m_status(BAD)
+ {
+ }
+
+ ~resp_cond_state()
+ {
+ delete (m_resp_text);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("resp_cond_state");
+
+ string::size_type pos = *currentPos;
+
+ if (parser.checkWithArg <special_atom>(line, &pos, "ok", true))
+ {
+ m_status = OK;
+ }
+ else if (parser.checkWithArg <special_atom>(line, &pos, "no", true))
+ {
+ m_status = NO;
+ }
+ else
+ {
+ parser.checkWithArg <special_atom>(line, &pos, "bad");
+ m_status = BAD;
+ }
+
+ parser.check <SPACE>(line, &pos);
+
+ m_resp_text = parser.get <IMAPParser::resp_text>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+
+ enum Status
+ {
+ OK,
+ NO,
+ BAD
+ };
+
+ private:
+
+ IMAPParser::resp_text* m_resp_text;
+ Status m_status;
+
+ public:
+
+ const IMAPParser::resp_text* resp_text() const { return (m_resp_text); }
+ const Status status() const { return (m_status); }
+ };
+
+
+ //
+ // resp_cond_bye ::= "BYE" SPACE resp_text
+ //
+
+ class resp_cond_bye : public component
+ {
+ public:
+
+ resp_cond_bye()
+ : m_resp_text(NULL)
+ {
+ }
+
+ ~resp_cond_bye()
+ {
+ delete (m_resp_text);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("resp_cond_bye");
+
+ string::size_type pos = *currentPos;
+
+ parser.checkWithArg <special_atom>(line, &pos, "bye");
+
+ parser.check <SPACE>(line, &pos);
+
+ m_resp_text = parser.get <IMAPParser::resp_text>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::resp_text* m_resp_text;
+
+ public:
+
+ const IMAPParser::resp_text* resp_text() const { return (m_resp_text); }
+ };
+
+
+ //
+ // resp_cond_auth ::= ("OK" / "PREAUTH") SPACE resp_text
+ // ;; Authentication condition
+ //
+
+ class resp_cond_auth : public component
+ {
+ public:
+
+ resp_cond_auth()
+ : m_resp_text(NULL)
+ {
+ }
+
+ ~resp_cond_auth()
+ {
+ delete (m_resp_text);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("resp_cond_auth");
+
+ string::size_type pos = *currentPos;
+
+ if (parser.checkWithArg <special_atom>(line, &pos, "ok", true))
+ {
+ m_cond = OK;
+ }
+ else
+ {
+ parser.checkWithArg <special_atom>(line, &pos, "preauth");
+
+ m_cond = PREAUTH;
+ }
+
+ parser.check <SPACE>(line, &pos);
+
+ m_resp_text = parser.get <IMAPParser::resp_text>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+
+ enum Condition
+ {
+ OK,
+ PREAUTH
+ };
+
+ private:
+
+ Condition m_cond;
+ IMAPParser::resp_text* m_resp_text;
+
+ public:
+
+ const Condition condition() const { return (m_cond); }
+ const IMAPParser::resp_text* resp_text() const { return (m_resp_text); }
+ };
+
+
+ //
+ // status_info ::= status_att SPACE number
+ //
+
+ class status_info : public component
+ {
+ public:
+
+ status_info()
+ : m_status_att(NULL), m_number(NULL)
+ {
+ }
+
+ ~status_info()
+ {
+ delete (m_status_att);
+ delete (m_number);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("status_info");
+
+ string::size_type pos = *currentPos;
+
+ m_status_att = parser.get <IMAPParser::status_att>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_number = parser.get <IMAPParser::number>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::status_att* m_status_att;
+ IMAPParser::number* m_number;
+
+ public:
+
+ const IMAPParser::status_att* status_att() const { return (m_status_att); }
+ const IMAPParser::number* number() const { return (m_number); }
+ };
+
+
+ //
+ // mailbox_data ::= "FLAGS" SPACE mailbox_flag_list /
+ // "LIST" SPACE mailbox_list /
+ // "LSUB" SPACE mailbox_list /
+ // "MAILBOX" SPACE text /
+ // "SEARCH" [SPACE 1#nz_number] /
+ // "STATUS" SPACE mailbox SPACE
+ // "(" #<status_att number ")" /
+ // number SPACE "EXISTS" /
+ // number SPACE "RECENT"
+ //
+
+ class mailbox_data : public component
+ {
+ public:
+
+ mailbox_data()
+ : m_number(NULL), m_mailbox_flag_list(NULL), m_mailbox_list(NULL),
+ m_mailbox(NULL), m_text(NULL)
+ {
+ }
+
+ ~mailbox_data()
+ {
+ delete (m_number);
+ delete (m_mailbox_flag_list);
+ delete (m_mailbox_list);
+ delete (m_mailbox);
+ delete (m_text);
+
+ for (std::vector <nz_number*>::iterator it = m_search_nz_number_list.begin() ;
+ it != m_search_nz_number_list.end() ; ++it)
+ {
+ delete (*it);
+ }
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("mailbox_data");
+
+ string::size_type pos = *currentPos;
+
+ m_number = parser.get <IMAPParser::number>(line, &pos, true);
+
+ if (m_number)
+ {
+ parser.check <SPACE>(line, &pos);
+
+ if (parser.checkWithArg <special_atom>(line, &pos, "exists", true))
+ {
+ m_type = EXISTS;
+ }
+ else
+ {
+ parser.checkWithArg <special_atom>(line, &pos, "recent");
+
+ m_type = RECENT;
+ }
+ }
+ else
+ {
+ // "FLAGS" SPACE mailbox_flag_list
+ if (parser.checkWithArg <special_atom>(line, &pos, "flags", true))
+ {
+ parser.check <SPACE>(line, &pos);
+
+ m_mailbox_flag_list = parser.get <IMAPParser::mailbox_flag_list>(line, &pos);
+
+ m_type = FLAGS;
+ }
+ // "LIST" SPACE mailbox_list
+ else if (parser.checkWithArg <special_atom>(line, &pos, "list", true))
+ {
+ parser.check <SPACE>(line, &pos);
+
+ m_mailbox_list = parser.get <IMAPParser::mailbox_list>(line, &pos);
+
+ m_type = LIST;
+ }
+ // "LSUB" SPACE mailbox_list
+ else if (parser.checkWithArg <special_atom>(line, &pos, "lsub", true))
+ {
+ parser.check <SPACE>(line, &pos);
+
+ m_mailbox_list = parser.get <IMAPParser::mailbox_list>(line, &pos);
+
+ m_type = LSUB;
+ }
+ // "MAILBOX" SPACE text
+ else if (parser.checkWithArg <special_atom>(line, &pos, "mailbox", true))
+ {
+ parser.check <SPACE>(line, &pos);
+
+ m_text = parser.get <IMAPParser::text>(line, &pos);
+
+ m_type = MAILBOX;
+ }
+ // "SEARCH" [SPACE 1#nz_number]
+ else if (parser.checkWithArg <special_atom>(line, &pos, "search", true))
+ {
+ if (parser.check <SPACE>(line, &pos, true))
+ {
+ m_search_nz_number_list.push_back
+ (parser.get <nz_number>(line, &pos));
+
+ while (parser.check <SPACE>(line, &pos, true))
+ {
+ m_search_nz_number_list.push_back
+ (parser.get <nz_number>(line, &pos));
+ }
+ }
+
+ m_type = SEARCH;
+ }
+ // "STATUS" SPACE mailbox SPACE
+ // "(" #<status_att number)] ")"
+ //
+ // "(" [status_att SPACE number *(SPACE status_att SPACE number)] ")"
+ else
+ {
+ parser.checkWithArg <special_atom>(line, &pos, "status");
+ parser.check <SPACE>(line, &pos);
+
+ m_mailbox = parser.get <IMAPParser::mailbox>(line, &pos);
+
+ parser.check <SPACE>(line, &pos);
+ parser.check <one_char <'('> >(line, &pos);
+
+ m_status_info_list.push_back(parser.get <status_info>(line, &pos));
+
+ while (!parser.check <one_char <')'> >(line, &pos, true))
+ m_status_info_list.push_back(parser.get <status_info>(line, &pos));
+
+ m_type = STATUS;
+ }
+ }
+
+ *currentPos = pos;
+ }
+
+
+ enum Type
+ {
+ FLAGS,
+ LIST,
+ LSUB,
+ MAILBOX,
+ SEARCH,
+ STATUS,
+ EXISTS,
+ RECENT
+ };
+
+ private:
+
+ Type m_type;
+
+ IMAPParser::number* m_number;
+ IMAPParser::mailbox_flag_list* m_mailbox_flag_list;
+ IMAPParser::mailbox_list* m_mailbox_list;
+ IMAPParser::mailbox* m_mailbox;
+ IMAPParser::text* m_text;
+ std::vector <nz_number*> m_search_nz_number_list;
+ std::vector <status_info*> m_status_info_list;
+
+ public:
+
+ const Type type() const { return (m_type); }
+
+ const IMAPParser::number* number() const { return (m_number); }
+ const IMAPParser::mailbox_flag_list* mailbox_flag_list() const { return (m_mailbox_flag_list); }
+ const IMAPParser::mailbox_list* mailbox_list() const { return (m_mailbox_list); }
+ const IMAPParser::mailbox* mailbox() const { return (m_mailbox); }
+ const IMAPParser::text* text() const { return (m_text); }
+ const std::vector <nz_number*>& search_nz_number_list() const { return (m_search_nz_number_list); }
+ const std::vector <status_info*>& status_info_list() const { return (m_status_info_list); }
+ };
+
+
+ //
+ // response_data ::= "*" SPACE (resp_cond_state / resp_cond_bye /
+ // mailbox_data / message_data / capability_data) CRLF
+ //
+
+ class response_data : public component
+ {
+ public:
+
+ response_data()
+ : m_resp_cond_state(NULL), m_resp_cond_bye(NULL),
+ m_mailbox_data(NULL), m_message_data(NULL), m_capability_data(NULL)
+ {
+ }
+
+ ~response_data()
+ {
+ delete (m_resp_cond_state);
+ delete (m_resp_cond_bye);
+ delete (m_mailbox_data);
+ delete (m_message_data);
+ delete (m_capability_data);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("response_data");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'*'> >(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ if (!(m_resp_cond_state = parser.get <IMAPParser::resp_cond_state>(line, &pos, true)))
+ if (!(m_resp_cond_bye = parser.get <IMAPParser::resp_cond_bye>(line, &pos, true)))
+ if (!(m_mailbox_data = parser.get <IMAPParser::mailbox_data>(line, &pos, true)))
+ if (!(m_message_data = parser.get <IMAPParser::message_data>(line, &pos, true)))
+ m_capability_data = parser.get <IMAPParser::capability_data>(line, &pos);
+
+ parser.check <CRLF>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::resp_cond_state* m_resp_cond_state;
+ IMAPParser::resp_cond_bye* m_resp_cond_bye;
+ IMAPParser::mailbox_data* m_mailbox_data;
+ IMAPParser::message_data* m_message_data;
+ IMAPParser::capability_data* m_capability_data;
+
+ public:
+
+ const IMAPParser::resp_cond_state* resp_cond_state() const { return (m_resp_cond_state); }
+ const IMAPParser::resp_cond_bye* resp_cond_bye() const { return (m_resp_cond_bye); }
+ const IMAPParser::mailbox_data* mailbox_data() const { return (m_mailbox_data); }
+ const IMAPParser::message_data* message_data() const { return (m_message_data); }
+ const IMAPParser::capability_data* capability_data() const { return (m_capability_data); }
+ };
+
+
+ class continue_req_or_response_data : public component
+ {
+ public:
+
+ continue_req_or_response_data()
+ : m_continue_req(NULL), m_response_data(NULL)
+ {
+ }
+
+ ~continue_req_or_response_data()
+ {
+ delete (m_continue_req);
+ delete (m_response_data);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("continue_req_or_response_data");
+
+ string::size_type pos = *currentPos;
+
+ if (!(m_continue_req = parser.get <IMAPParser::continue_req>(line, &pos, true)))
+ m_response_data = parser.get <IMAPParser::response_data>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::continue_req* m_continue_req;
+ IMAPParser::response_data* m_response_data;
+
+ public:
+
+ const IMAPParser::continue_req* continue_req() const { return (m_continue_req); }
+ const IMAPParser::response_data* response_data() const { return (m_response_data); }
+ };
+
+
+ //
+ // response_fatal ::= "*" SPACE resp_cond_bye CRLF
+ // ;; Server closes connection immediately
+ //
+
+ class response_fatal : public component
+ {
+ public:
+
+ response_fatal()
+ : m_resp_cond_bye(NULL)
+ {
+ }
+
+ ~response_fatal()
+ {
+ delete (m_resp_cond_bye);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("response_fatal");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'*'> >(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ m_resp_cond_bye = parser.get <IMAPParser::resp_cond_bye>(line, &pos);
+
+ parser.check <CRLF>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::resp_cond_bye* m_resp_cond_bye;
+
+ public:
+
+ const IMAPParser::resp_cond_bye* resp_cond_bye() const { return (m_resp_cond_bye); }
+ };
+
+
+ //
+ // response_tagged ::= tag SPACE resp_cond_state CRLF
+ //
+
+ class response_tagged : public component
+ {
+ public:
+
+ response_tagged()
+ : m_resp_cond_state(NULL)
+ {
+ }
+
+ ~response_tagged()
+ {
+ delete (m_resp_cond_state);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("response_tagged");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <IMAPParser::xtag>(line, &pos);
+ parser.check <SPACE>(line, &pos);
+ m_resp_cond_state = parser.get <IMAPParser::resp_cond_state>(line, &pos);
+ parser.check <CRLF>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::resp_cond_state* m_resp_cond_state;
+
+ public:
+
+ const IMAPParser::resp_cond_state* resp_cond_state() const { return (m_resp_cond_state); }
+ };
+
+
+ //
+ // response_done ::= response_tagged / response_fatal
+ //
+
+ class response_done : public component
+ {
+ public:
+
+ response_done()
+ : m_response_tagged(NULL), m_response_fatal(NULL)
+ {
+ }
+
+ ~response_done()
+ {
+ delete (m_response_tagged);
+ delete (m_response_fatal);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("response_done");
+
+ string::size_type pos = *currentPos;
+
+ if (!(m_response_tagged = parser.get <IMAPParser::response_tagged>(line, &pos, true)))
+ m_response_fatal = parser.get <IMAPParser::response_fatal>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::response_tagged* m_response_tagged;
+ IMAPParser::response_fatal* m_response_fatal;
+
+ public:
+
+ const IMAPParser::response_tagged* response_tagged() const { return (m_response_tagged); }
+ const IMAPParser::response_fatal* response_fatal() const { return (m_response_fatal); }
+ };
+
+
+ //
+ // response ::= *(continue_req / response_data) response_done
+ //
+
+ class response : public component
+ {
+ public:
+
+ response()
+ : m_response_done(NULL)
+ {
+ }
+
+ ~response()
+ {
+ for (std::vector <IMAPParser::continue_req_or_response_data*>::iterator
+ it = m_continue_req_or_response_data.begin() ;
+ it != m_continue_req_or_response_data.end() ; ++it)
+ {
+ delete (*it);
+ }
+
+ delete (m_response_done);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("response");
+
+ string::size_type pos = *currentPos;
+ string curLine = line;
+ bool partial = false; // partial response
+
+ IMAPParser::continue_req_or_response_data* resp = NULL;
+
+ while ((resp = parser.get <IMAPParser::continue_req_or_response_data>(curLine, &pos, true)) != NULL)
+ {
+ m_continue_req_or_response_data.push_back(resp);
+
+ // Partial response (continue_req)
+ if (resp->continue_req())
+ {
+ partial = true;
+ break;
+ }
+
+ // We have read a CRLF, read another line
+ curLine = parser.readLine();
+ pos = 0;
+ }
+
+ if (!partial)
+ m_response_done = parser.get <IMAPParser::response_done>(curLine, &pos);
+
+ *currentPos = pos;
+ }
+
+
+ const bool isBad() const
+ {
+ if (!response_done()) // incomplete (partial) response
+ return (true);
+
+ if (response_done()->response_fatal())
+ return (true);
+
+ if (response_done()->response_tagged()->resp_cond_state()->
+ status() == IMAPParser::resp_cond_state::BAD)
+ {
+ return (true);
+ }
+
+ return (false);
+ }
+
+ private:
+
+ std::vector <IMAPParser::continue_req_or_response_data*> m_continue_req_or_response_data;
+ IMAPParser::response_done* m_response_done;
+
+ public:
+
+ const std::vector <IMAPParser::continue_req_or_response_data*>& continue_req_or_response_data() const { return (m_continue_req_or_response_data); }
+ const IMAPParser::response_done* response_done() const { return (m_response_done); }
+ };
+
+
+ //
+ // greeting ::= "*" SPACE (resp_cond_auth / resp_cond_bye) CRLF
+ //
+
+ class greeting : public component
+ {
+ public:
+
+ greeting()
+ : m_resp_cond_auth(NULL), m_resp_cond_bye(NULL)
+ {
+ }
+
+ ~greeting()
+ {
+ delete (m_resp_cond_auth);
+ delete (m_resp_cond_bye);
+ }
+
+ void go(IMAPParser& parser, string& line, string::size_type* currentPos)
+ {
+ DEBUG_ENTER_COMPONENT("greeting");
+
+ string::size_type pos = *currentPos;
+
+ parser.check <one_char <'*'> >(line, &pos);
+ parser.check <SPACE>(line, &pos);
+
+ if (!(m_resp_cond_auth = parser.get <IMAPParser::resp_cond_auth>(line, &pos, true)))
+ m_resp_cond_bye = parser.get <IMAPParser::resp_cond_bye>(line, &pos);
+
+ parser.check <CRLF>(line, &pos);
+
+ *currentPos = pos;
+ }
+
+ private:
+
+ IMAPParser::resp_cond_auth* m_resp_cond_auth;
+ IMAPParser::resp_cond_bye* m_resp_cond_bye;
+
+ public:
+
+ const IMAPParser::resp_cond_auth* resp_cond_auth() const { return (m_resp_cond_auth); }
+ const IMAPParser::resp_cond_bye* resp_cond_bye() const { return (m_resp_cond_bye); }
+ };
+
+
+
+ //
+ // The main functions used to parse a response
+ //
+
+ response* readResponse(literalHandler* lh = NULL)
+ {
+ string::size_type pos = 0;
+ string line = readLine();
+
+ m_literalHandler = lh;
+ response* resp = get <response>(line, &pos);
+ m_literalHandler = NULL;
+
+ return (resp);
+ }
+
+
+ greeting* readGreeting()
+ {
+ string::size_type pos = 0;
+ string line = readLine();
+
+ return get <greeting>(line, &pos);
+ }
+
+
+ //
+ // Get a token and advance
+ //
+
+ template <class TYPE>
+ TYPE* get(string& line, string::size_type* currentPos,
+ const bool noThrow = false)
+ {
+ component* resp = new TYPE;
+ return internalGet <TYPE>(resp, line, currentPos, noThrow);
+ }
+
+
+ template <class TYPE, class ARG1_TYPE, class ARG2_TYPE>
+ TYPE* getWithArgs(string& line, string::size_type* currentPos,
+ ARG1_TYPE arg1, ARG2_TYPE arg2, const bool noThrow = false)
+ {
+ component* resp = new TYPE(arg1, arg2);
+ return internalGet <TYPE>(resp, line, currentPos, noThrow);
+ }
+
+
+private:
+
+ template <class TYPE>
+ TYPE* internalGet(component* resp, string& line, string::size_type* currentPos,
+ const bool noThrow = false)
+ {
+#if DEBUG_RESPONSE
+ DEBUG_RESPONSE_level += " ";
+#endif
+
+ try
+ {
+ resp->go(*this, line, currentPos);
+
+#if DEBUG_RESPONSE
+ std::cout << DEBUG_RESPONSE_level << "SUCCESS! (" << DEBUG_RESPONSE_components.back() << ")" << std::endl;
+
+ DEBUG_RESPONSE_level.erase(DEBUG_RESPONSE_level.begin() + DEBUG_RESPONSE_level.length() - 1);
+ DEBUG_RESPONSE_components.pop_back();
+#endif
+ }
+ catch (...)
+ {
+#if DEBUG_RESPONSE
+ std::cout << DEBUG_RESPONSE_level << "FAILED! (" << DEBUG_RESPONSE_components.back() << ")" << std::endl;
+
+ DEBUG_RESPONSE_level.erase(DEBUG_RESPONSE_level.begin() + DEBUG_RESPONSE_level.length() - 1);
+ DEBUG_RESPONSE_components.pop_back();
+#endif
+
+ delete (resp);
+ if (!noThrow) throw;
+ return (NULL);
+ }
+
+ return static_cast <TYPE*>(resp);
+ }
+
+
+public:
+
+ //
+ // Check a token and advance
+ //
+
+ template <class TYPE>
+ const bool check(string& line, string::size_type* currentPos,
+ const bool noThrow = false)
+ {
+ try
+ {
+ TYPE term;
+ term.go(*this, line, currentPos);
+
+#if DEBUG_RESPONSE
+ std::cout << DEBUG_RESPONSE_level << "SUCCESS! (" << DEBUG_RESPONSE_components.back() << ")" << std::endl;
+ DEBUG_RESPONSE_components.pop_back();
+#endif
+ }
+ catch (...)
+ {
+#if DEBUG_RESPONSE
+ std::cout << DEBUG_RESPONSE_level << "FAILED! (" << DEBUG_RESPONSE_components.back() << ")" << std::endl;
+ DEBUG_RESPONSE_components.pop_back();
+#endif
+
+ if (!noThrow) throw;
+ return false;
+ }
+
+ return true;
+ }
+
+ template <class TYPE, class ARG_TYPE>
+ const bool checkWithArg(string& line, string::size_type* currentPos,
+ const ARG_TYPE arg, const bool noThrow = false)
+ {
+ try
+ {
+ TYPE term(arg);
+ term.go(*this, line, currentPos);
+
+#if DEBUG_RESPONSE
+ std::cout << DEBUG_RESPONSE_level << "SUCCESS! (" << DEBUG_RESPONSE_components.back() << ")" << std::endl;
+ DEBUG_RESPONSE_components.pop_back();
+#endif
+ }
+ catch (...)
+ {
+#if DEBUG_RESPONSE
+ std::cout << DEBUG_RESPONSE_level << "FAILED! (" << DEBUG_RESPONSE_components.back() << ")" << std::endl;
+ DEBUG_RESPONSE_components.pop_back();
+#endif
+
+ if (!noThrow) throw;
+ return false;
+ }
+
+ return true;
+ }
+
+
+private:
+
+ IMAPTag* m_tag;
+ socket* m_socket;
+
+ progressionListener* m_progress;
+
+ literalHandler* m_literalHandler;
+
+ timeoutHandler* m_timeoutHandler;
+
+
+ string m_buffer;
+ int m_pos;
+
+ string m_lastLine;
+
+public:
+
+ //
+ // Read one line
+ //
+
+ const string readLine()
+ {
+ string::size_type pos;
+
+ while ((pos = m_buffer.find('\n')) == string::npos)
+ {
+ read();
+ }
+
+ string line;
+ line.resize(pos + 1);
+ std::copy(m_buffer.begin(), m_buffer.begin() + pos + 1, line.begin());
+
+ m_buffer.erase(m_buffer.begin(), m_buffer.begin() + pos + 1);
+
+ m_lastLine = line;
+
+#if DEBUG_RESPONSE
+ std::cout << std::endl << "Read line:" << std::endl << line << std::endl;
+#endif
+
+ return (line);
+ }
+
+
+ //
+ // Read available data from socket stream
+ //
+
+ void read()
+ {
+ string receiveBuffer;
+
+ while (receiveBuffer.empty())
+ {
+ // Check whether the time-out delay is elapsed
+ if (m_timeoutHandler && m_timeoutHandler->isTimeOut())
+ {
+ if (!m_timeoutHandler->handleTimeOut())
+ throw exceptions::operation_timed_out();
+ }
+
+ // We have received data: reset the time-out counter
+ m_socket->receive(receiveBuffer);
+
+ if (receiveBuffer.empty()) // buffer is empty
+ {
+ platformDependant::getHandler()->wait();
+ continue;
+ }
+
+ // We have received data ...
+ if (m_timeoutHandler)
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ m_buffer += receiveBuffer;
+ }
+
+
+ void readLiteral(literalHandler::target& buffer, string::size_type count)
+ {
+ string::size_type len = 0;
+ string receiveBuffer;
+
+ if (m_progress)
+ m_progress->start(count);
+
+ if (m_timeoutHandler)
+ m_timeoutHandler->resetTimeOut();
+
+ if (!m_buffer.empty())
+ {
+ if (m_buffer.length() > count)
+ {
+ buffer.putData(string(m_buffer.begin(), m_buffer.begin() + count));
+ m_buffer.erase(m_buffer.begin(), m_buffer.begin() + count);
+ len = count;
+ }
+ else
+ {
+ len += m_buffer.length();
+ buffer.putData(m_buffer);
+ m_buffer.clear();
+ }
+ }
+
+ while (len < count)
+ {
+ // Check whether the time-out delay is elapsed
+ if (m_timeoutHandler && m_timeoutHandler->isTimeOut())
+ {
+ if (!m_timeoutHandler->handleTimeOut())
+ throw exceptions::operation_timed_out();
+ }
+
+ // Receive data from the socket
+ m_socket->receive(receiveBuffer);
+
+ if (receiveBuffer.empty()) // buffer is empty
+ {
+ platformDependant::getHandler()->wait();
+ continue;
+ }
+
+ // We have received data: reset the time-out counter
+ if (m_timeoutHandler)
+ m_timeoutHandler->resetTimeOut();
+
+ if (len + receiveBuffer.length() > count)
+ {
+ const string::size_type remaining = count - len;
+
+ // Get the needed amount of data
+ buffer.putData(string(receiveBuffer.begin(), receiveBuffer.begin() + remaining));
+
+ // Put the remaining data into the internal response buffer
+ receiveBuffer.erase(receiveBuffer.begin(), receiveBuffer.begin() + remaining);
+ m_buffer += receiveBuffer;
+
+ len = count;
+ }
+ else
+ {
+ buffer.putData(receiveBuffer);
+ len += receiveBuffer.length();
+ }
+
+ // Notify progression
+ if (m_progress)
+ m_progress->progress(len, count);
+ }
+
+ if (m_progress)
+ m_progress->stop(count);
+ }
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_IMAPPARSER_HPP_INCLUDED
diff --git a/src/messaging/IMAPStore.cpp b/src/messaging/IMAPStore.cpp
new file mode 100644
index 00000000..7d2bc823
--- /dev/null
+++ b/src/messaging/IMAPStore.cpp
@@ -0,0 +1,257 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "IMAPStore.hpp"
+#include "IMAPFolder.hpp"
+#include "IMAPConnection.hpp"
+
+#include "../exception.hpp"
+#include "../platformDependant.hpp"
+
+#include <map>
+
+
+namespace vmime {
+namespace messaging {
+
+
+//
+// IMAPauthenticator: private class used internally
+//
+// Used to request user credentials only in the first authentication
+// and reuse this information the next times
+//
+
+class IMAPauthenticator : public authenticator
+{
+public:
+
+ IMAPauthenticator(authenticator* auth)
+ : m_auth(auth), m_infos(NULL)
+ {
+ }
+
+ ~IMAPauthenticator()
+ {
+ delete (m_infos);
+ }
+
+ const authenticationInfos requestAuthInfos() const
+ {
+ if (m_infos == NULL)
+ m_infos = new authenticationInfos(m_auth->requestAuthInfos());
+
+ return (*m_infos);
+ }
+
+private:
+
+ authenticator* m_auth;
+ mutable authenticationInfos* m_infos;
+};
+
+
+
+//
+// IMAPStore
+//
+
+IMAPStore::IMAPStore(class session& sess, class authenticator* auth)
+ : store(sess, infosInstance(), auth),
+ m_connection(NULL), m_oneTimeAuth(NULL)
+{
+}
+
+
+IMAPStore::~IMAPStore()
+{
+ if (isConnected())
+ disconnect();
+}
+
+
+authenticator* IMAPStore::oneTimeAuthenticator()
+{
+ return (m_oneTimeAuth);
+}
+
+
+const string IMAPStore::protocolName() const
+{
+ return "imap";
+}
+
+
+folder* IMAPStore::getRootFolder()
+{
+ if (!isConnected())
+ throw exceptions::illegal_state("Not connected");
+
+ return new IMAPFolder(folder::path(), this);
+}
+
+
+folder* IMAPStore::getDefaultFolder()
+{
+ if (!isConnected())
+ throw exceptions::illegal_state("Not connected");
+
+ return new IMAPFolder(folder::path::component("INBOX"), this);
+}
+
+
+folder* IMAPStore::getFolder(const folder::path& path)
+{
+ if (!isConnected())
+ throw exceptions::illegal_state("Not connected");
+
+ return new IMAPFolder(path, this);
+}
+
+
+void IMAPStore::connect()
+{
+ if (isConnected())
+ throw exceptions::already_connected();
+
+ m_oneTimeAuth = new IMAPauthenticator(&authenticator());
+
+ m_connection = new IMAPConnection(this, m_oneTimeAuth);
+
+ try
+ {
+ m_connection->connect();
+ }
+ catch (std::exception&)
+ {
+ delete (m_connection);
+ m_connection = NULL;
+ throw;
+ }
+}
+
+
+const bool IMAPStore::isConnected() const
+{
+ return (m_connection && m_connection->isConnected());
+}
+
+
+void IMAPStore::disconnect()
+{
+ if (!isConnected())
+ throw exceptions::not_connected();
+
+ for (std::list <IMAPFolder*>::iterator it = m_folders.begin() ;
+ it != m_folders.end() ; ++it)
+ {
+ (*it)->onStoreDisconnected();
+ }
+
+ m_folders.clear();
+
+
+ m_connection->disconnect();
+
+ delete (m_oneTimeAuth);
+ m_oneTimeAuth = NULL;
+
+ delete (m_connection);
+ m_connection = NULL;
+}
+
+
+void IMAPStore::noop()
+{
+ if (!isConnected())
+ throw exceptions::not_connected();
+
+ m_connection->send(true, "NOOP", true);
+
+ utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done()->response_tagged()->
+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
+ {
+ throw exceptions::command_error("NOOP", m_connection->parser()->lastLine());
+ }
+}
+
+
+IMAPConnection* IMAPStore::connection()
+{
+ return (m_connection);
+}
+
+
+void IMAPStore::registerFolder(IMAPFolder* folder)
+{
+ m_folders.push_back(folder);
+}
+
+
+void IMAPStore::unregisterFolder(IMAPFolder* folder)
+{
+ std::list <IMAPFolder*>::iterator it = std::find(m_folders.begin(), m_folders.end(), folder);
+ if (it != m_folders.end()) m_folders.erase(it);
+}
+
+
+
+
+// Service infos
+
+IMAPStore::_infos IMAPStore::sm_infos;
+
+
+const port_t IMAPStore::_infos::defaultPort() const
+{
+ return (143);
+}
+
+
+const string IMAPStore::_infos::propertyPrefix() const
+{
+ return "store.imap.";
+}
+
+
+const std::vector <string> IMAPStore::_infos::availableProperties() const
+{
+ std::vector <string> list;
+
+ // IMAP-specific options
+ //list.push_back("auth.mechanism");
+
+ // Common properties
+ list.push_back("auth.username");
+ list.push_back("auth.password");
+
+ list.push_back("server.address");
+ list.push_back("server.port");
+ list.push_back("server.socket-factory");
+
+ list.push_back("timeout.factory");
+
+ return (list);
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/IMAPStore.hpp b/src/messaging/IMAPStore.hpp
new file mode 100644
index 00000000..cab9419f
--- /dev/null
+++ b/src/messaging/IMAPStore.hpp
@@ -0,0 +1,112 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_IMAPSTORE_HPP_INCLUDED
+#define VMIME_MESSAGING_IMAPSTORE_HPP_INCLUDED
+
+
+#include "store.hpp"
+#include "socket.hpp"
+#include "folder.hpp"
+#include "../config.hpp"
+
+#include <ostream>
+
+
+namespace vmime {
+namespace messaging {
+
+
+class IMAPParser;
+class IMAPTag;
+class IMAPConnection;
+
+
+/** IMAP store service.
+ */
+
+class IMAPStore : public store
+{
+ friend class IMAPFolder;
+ friend class IMAPMessage;
+
+public:
+
+ IMAPStore(class session& sess, class authenticator* auth);
+ ~IMAPStore();
+
+ const string protocolName() const;
+
+ folder* getDefaultFolder();
+ folder* getRootFolder();
+ folder* getFolder(const folder::path& path);
+
+ static const serviceInfos& infosInstance() { return (sm_infos); }
+ const serviceInfos& infos() const { return (sm_infos); }
+
+ void connect();
+ const bool isConnected() const;
+ void disconnect();
+
+ void noop();
+
+private:
+
+ // Connection
+ IMAPConnection* m_connection;
+
+ // Used to request the authentication informations only the
+ // first time, and reuse these informations the next time.
+ class authenticator* m_oneTimeAuth;
+
+
+
+ class authenticator* oneTimeAuthenticator();
+
+
+ IMAPConnection* connection();
+
+
+ void registerFolder(IMAPFolder* folder);
+ void unregisterFolder(IMAPFolder* folder);
+
+ std::list <IMAPFolder*> m_folders;
+
+
+
+ // Service infos
+ class _infos : public serviceInfos
+ {
+ public:
+
+ const port_t defaultPort() const;
+
+ const string propertyPrefix() const;
+ const std::vector <string> availableProperties() const;
+ };
+
+ static _infos sm_infos;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_IMAPSTORE_HPP_INCLUDED
diff --git a/src/messaging/IMAPTag.cpp b/src/messaging/IMAPTag.cpp
new file mode 100644
index 00000000..023130bb
--- /dev/null
+++ b/src/messaging/IMAPTag.cpp
@@ -0,0 +1,97 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "IMAPTag.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+const int IMAPTag::sm_maxNumber = 52 * 10 * 10 * 10;
+
+
+IMAPTag::IMAPTag(const int number)
+ : m_number(number)
+{
+ m_tag.resize(4);
+}
+
+
+IMAPTag::IMAPTag(const IMAPTag& tag)
+ : m_number(tag.m_number)
+{
+ m_tag.resize(4);
+}
+
+
+IMAPTag::IMAPTag()
+ : m_number(0)
+{
+ m_tag.resize(4);
+}
+
+
+IMAPTag& IMAPTag::operator++()
+{
+ ++m_number;
+
+ if (m_number >= sm_maxNumber)
+ m_number = 1;
+
+ generate();
+
+ return (*this);
+}
+
+
+const IMAPTag IMAPTag::operator++(int)
+{
+ IMAPTag old(*this);
+ operator++();
+ return (old);
+}
+
+
+const int IMAPTag::number() const
+{
+ return (m_number);
+}
+
+
+IMAPTag::operator string() const
+{
+ return (m_tag);
+}
+
+
+void IMAPTag::generate()
+{
+ static const char prefixChars[53] =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ m_tag[0] = prefixChars[m_number / 1000];
+ m_tag[1] = '0' + (m_number % 1000) / 100;
+ m_tag[2] = '0' + (m_number % 100) / 10;
+ m_tag[3] = '0' + (m_number % 10);
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/IMAPTag.hpp b/src/messaging/IMAPTag.hpp
new file mode 100644
index 00000000..c7c48f31
--- /dev/null
+++ b/src/messaging/IMAPTag.hpp
@@ -0,0 +1,64 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_IMAPTAG_HPP_INCLUDED
+#define VMIME_MESSAGING_IMAPTAG_HPP_INCLUDED
+
+
+#include "types.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+class IMAPTag
+{
+private:
+
+ IMAPTag(const int number);
+ IMAPTag(const IMAPTag& tag);
+
+public:
+
+ IMAPTag();
+
+ IMAPTag& operator++(); // ++IMAPTag
+ const IMAPTag operator++(int); // IMAPTag++
+
+ const int number() const;
+
+ operator string() const;
+
+private:
+
+ void generate();
+
+ static const int sm_maxNumber;
+
+ int m_number;
+ string m_tag;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_IMAPTAG_HPP_INCLUDED
diff --git a/src/messaging/IMAPUtils.cpp b/src/messaging/IMAPUtils.cpp
new file mode 100644
index 00000000..2413c86d
--- /dev/null
+++ b/src/messaging/IMAPUtils.cpp
@@ -0,0 +1,553 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "IMAPUtils.hpp"
+#include "message.hpp"
+
+#include <sstream>
+#include <iterator>
+#include <algorithm>
+
+
+namespace vmime {
+namespace messaging {
+
+
+const string IMAPUtils::quoteString(const string& text)
+{
+ //
+ // ATOM_CHAR ::= <any CHAR except atom_specials>
+ //
+ // atom_specials ::= "(" / ")" / "{" / SPACE / CTL /
+ // list_wildcards / quoted_specials
+ //
+ // list_wildcards ::= "%" / "*"
+ //
+ // quoted_specials ::= <"> / "\"
+ //
+ // CHAR ::= <any 7-bit US-ASCII character except NUL,
+ // 0x01 - 0x7f>
+ //
+ // CTL ::= <any ASCII control character and DEL,
+ // 0x00 - 0x1f, 0x7f>
+ //
+
+ bool needQuoting = text.empty();
+
+ for (string::const_iterator it = text.begin() ;
+ !needQuoting && it != text.end() ; ++it)
+ {
+ const unsigned char c = *it;
+
+ switch (c)
+ {
+ case '(':
+ case ')':
+ case '{':
+ case 0x20: // SPACE
+ case '%':
+ case '*':
+ case '"':
+ case '\\':
+
+ needQuoting = true;
+ break;
+
+ default:
+
+ if (c <= 0x1f || c >= 0x7f)
+ needQuoting = true;
+ }
+ }
+
+ if (needQuoting)
+ {
+ string quoted;
+ quoted.reserve((text.length() * 3) / 2 + 2);
+
+ quoted += '"';
+
+ for (string::const_iterator it = text.begin() ;
+ !needQuoting && it != text.end() ; ++it)
+ {
+ const unsigned char c = *it;
+
+ if (c == '\\' || c == '"')
+ quoted += '\\';
+
+ quoted += c;
+ }
+
+ quoted += '"';
+
+ return (quoted);
+ }
+ else
+ {
+ return (text);
+ }
+}
+
+
+const string IMAPUtils::pathToString
+ (const char hierarchySeparator, const folder::path& path)
+{
+ string result;
+
+ for (int i = 0 ; i < path.size() ; ++i)
+ {
+ if (i > 0) result += hierarchySeparator;
+ result += toModifiedUTF7(hierarchySeparator, path[i]);
+ }
+
+ return (result);
+}
+
+
+const folder::path IMAPUtils::stringToPath
+ (const char hierarchySeparator, const string& str)
+{
+ folder::path result;
+ string::const_iterator begin = str.begin();
+
+ for (string::const_iterator it = str.begin() ; it != str.end() ; ++it)
+ {
+ if (*it == hierarchySeparator)
+ {
+ result /= fromModifiedUTF7(string(begin, it));
+ begin = it + 1;
+ }
+ }
+
+ if (begin != str.end())
+ {
+ result /= fromModifiedUTF7(string(begin, str.end()));
+ }
+
+ return (result);
+}
+
+
+const string IMAPUtils::toModifiedUTF7
+ (const char hierarchySeparator, const folder::path::component& text)
+{
+ // We will replace the hierarchy separator with an equivalent
+ // UTF-7 sequence, so we compute it here...
+ const char base64alphabet[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,=";
+
+ const unsigned int hs = (unsigned int)(unsigned char) hierarchySeparator;
+
+ string hsUTF7;
+ hsUTF7.resize(3);
+
+ hsUTF7[0] = base64alphabet[0];
+ hsUTF7[1] = base64alphabet[(hs & 0xF0) >> 4];
+ hsUTF7[2] = base64alphabet[(hs & 0x0F) << 2];
+
+ // Transcode path component to UTF-7 charset.
+ // WARNING: This may throw "exceptions::charset_conv_error"
+ const string cvt = text.getConvertedText(charset(charsets::UTF_7));
+
+ // Transcode to modified UTF-7 (RFC-2060).
+ string out;
+ out.reserve((cvt.length() * 3) / 2);
+
+ bool inB64sequence = false;
+
+ for (string::const_iterator it = cvt.begin() ; it != cvt.end() ; ++it)
+ {
+ const unsigned char c = *it;
+
+ // Replace hierarchy separator with an equivalent UTF-7 Base64 sequence
+ if (!inB64sequence && c == hierarchySeparator)
+ {
+ out += "&" + hsUTF7 + "-";
+ continue;
+ }
+
+ switch (c)
+ {
+ // Beginning of Base64 sequence: replace '+' with '&'
+ case '+':
+ {
+ if (!inB64sequence)
+ {
+ inB64sequence = true;
+ out += '&';
+ }
+ else
+ {
+ out += '+';
+ }
+
+ break;
+ }
+ // End of Base64 sequence
+ case '-':
+ {
+ inB64sequence = false;
+ out += '-';
+ break;
+ }
+ // ',' is used instead of '/' in modified Base64
+ case '/':
+ {
+ out += inB64sequence ? ',' : '/';
+ break;
+ }
+ // '&' (0x26) is represented by the two-octet sequence "&-"
+ case '&':
+ {
+ if (!inB64sequence)
+ out += "&-";
+ else
+ out += '&';
+
+ break;
+ }
+ default:
+ {
+ out += c;
+ break;
+ }
+
+ }
+ }
+
+ return (out);
+}
+
+
+const folder::path::component IMAPUtils::fromModifiedUTF7(const string& text)
+{
+ // Transcode from modified UTF-7 (RFC-2060).
+ string out;
+ out.reserve(text.length());
+
+ bool inB64sequence = false;
+ unsigned char prev = 0;
+
+ for (string::const_iterator it = text.begin() ; it != text.end() ; ++it)
+ {
+ const unsigned char c = *it;
+
+ switch (c)
+ {
+ // Start of Base64 sequence
+ case '&':
+ {
+ if (!inB64sequence)
+ {
+ inB64sequence = true;
+ out += '+';
+ }
+ else
+ {
+ out += '&';
+ }
+
+ break;
+ }
+ // End of Base64 sequence (or "&-" --> "&")
+ case '-':
+ {
+ if (inB64sequence && prev == '&')
+ out += '&';
+ else
+ out += '-';
+
+ inB64sequence = false;
+ break;
+ }
+ // ',' is used instead of '/' in modified Base64
+ case ',':
+ {
+ out += (inB64sequence ? '/' : ',');
+ break;
+ }
+ default:
+ {
+ out += c;
+ break;
+ }
+
+ }
+
+ prev = c;
+ }
+
+ // Store it as UTF-8 by default
+ string cvt;
+ charset::convert(out, cvt,
+ charset(charsets::UTF_7), charset(charsets::UTF_8));
+
+ return (folder::path::component(cvt, charset(charsets::UTF_8)));
+}
+
+
+const int IMAPUtils::folderTypeFromFlags(const IMAPParser::mailbox_flag_list* list)
+{
+ // Get folder type
+ int type = folder::TYPE_CONTAINS_MESSAGES | folder::TYPE_CONTAINS_FOLDERS;
+ const std::vector <IMAPParser::mailbox_flag*>& flags = list->flags();
+
+ for (std::vector <IMAPParser::mailbox_flag*>::const_iterator it = flags.begin() ;
+ it != flags.end() ; ++it)
+ {
+ if ((*it)->type() == IMAPParser::mailbox_flag::NOSELECT)
+ type &= ~folder::TYPE_CONTAINS_MESSAGES;
+ }
+
+ if (type & folder::TYPE_CONTAINS_MESSAGES)
+ type &= ~folder::TYPE_CONTAINS_FOLDERS;
+
+ return (type);
+}
+
+
+const int IMAPUtils::folderFlagsFromFlags(const IMAPParser::mailbox_flag_list* list)
+{
+ // Get folder flags
+ int folderFlags = folder::FLAG_CHILDREN;
+ const std::vector <IMAPParser::mailbox_flag*>& flags = list->flags();
+
+ for (std::vector <IMAPParser::mailbox_flag*>::const_iterator it = flags.begin() ;
+ it != flags.end() ; ++it)
+ {
+ if ((*it)->type() == IMAPParser::mailbox_flag::NOSELECT)
+ folderFlags |= folder::FLAG_NO_OPEN;
+ else if ((*it)->type() == IMAPParser::mailbox_flag::NOINFERIORS)
+ folderFlags &= ~folder::FLAG_CHILDREN;
+ }
+
+ return (folderFlags);
+}
+
+
+const int IMAPUtils::messageFlagsFromFlags(const IMAPParser::flag_list* list)
+{
+ const std::vector <IMAPParser::flag*>& flagList = list->flags();
+ int flags = 0;
+
+ for (std::vector <IMAPParser::flag*>::const_iterator
+ it = flagList.begin() ; it != flagList.end() ; ++it)
+ {
+ switch ((*it)->type())
+ {
+ case IMAPParser::flag::ANSWERED:
+ flags |= message::FLAG_REPLIED;
+ break;
+ case IMAPParser::flag::FLAGGED:
+ flags |= message::FLAG_MARKED;
+ break;
+ case IMAPParser::flag::DELETED:
+ flags |= message::FLAG_DELETED;
+ break;
+ case IMAPParser::flag::SEEN:
+ flags |= message::FLAG_SEEN;
+ break;
+
+ default:
+ //case IMAPParser::flag::UNKNOWN:
+ //case IMAPParser::flag::DRAFT:
+ break;
+ }
+ }
+
+ return (flags);
+}
+
+
+const string IMAPUtils::messageFlagList(const int flags)
+{
+ std::vector <string> flagList;
+
+ if (flags & message::FLAG_REPLIED) flagList.push_back("\\Answered");
+ if (flags & message::FLAG_MARKED) flagList.push_back("\\Flagged");
+ if (flags & message::FLAG_DELETED) flagList.push_back("\\Deleted");
+ if (flags & message::FLAG_SEEN) flagList.push_back("\\Seen");
+
+ if (!flagList.empty())
+ {
+ std::ostringstream res;
+ res << "(";
+
+ if (flagList.size() >= 2)
+ {
+ std::copy(flagList.begin(), flagList.end() - 1,
+ std::ostream_iterator <string>(res, " "));
+ }
+
+ res << *(flagList.end() - 1) << ")";
+
+ return (res.str());
+ }
+
+ return "";
+}
+
+
+// This function builds a "IMAP set" given a list. Try to group consecutive
+// message numbers to reduce the list.
+//
+// Example:
+// IN = "1,2,3,4,5,7,8,13,15,16,17"
+// OUT = "1:5,7:8,13,15:*" for a mailbox with a total of 17 messages (max = 17)
+
+const string IMAPUtils::listToSet(const std::vector <int>& list, const int max,
+ const bool alreadySorted)
+{
+ // Sort a copy of the list (if not already sorted)
+ std::vector <int> temp;
+
+ if (!alreadySorted)
+ {
+ temp.resize(list.size());
+ std::copy(list.begin(), list.end(), temp.begin());
+
+ std::sort(temp.begin(), temp.end());
+ }
+
+ const std::vector <int>& theList = (alreadySorted ? list : temp);
+
+ // Build the set
+ std::ostringstream res;
+ int previous = -1, setBegin = -1;
+
+ for (std::vector <int>::const_iterator it = theList.begin() ;
+ it != theList.end() ; ++it)
+ {
+ const int current = *it;
+
+ if (previous == -1)
+ {
+ res << current;
+
+ previous = current;
+ setBegin = current;
+ }
+ else
+ {
+ if (current == previous + 1)
+ {
+ previous = current;
+ }
+ else
+ {
+ if (setBegin != previous)
+ {
+ res << ":" << previous << "," << current;
+
+ previous = current;
+ setBegin = current;
+ }
+ else
+ {
+ if (setBegin != current) // skip duplicates
+ res << "," << current;
+
+ previous = current;
+ setBegin = current;
+ }
+ }
+ }
+ }
+
+ if (previous != setBegin)
+ {
+ if (previous == max)
+ res << ":*";
+ else
+ res << ":" << previous;
+ }
+
+ return (res.str());
+}
+
+
+const string IMAPUtils::dateTime(const vmime::datetime& date)
+{
+ std::ostringstream res;
+
+ // date_time ::= <"> date_day_fixed "-" date_month "-" date_year
+ // SPACE time SPACE zone <">
+ //
+ // time ::= 2digit ":" 2digit ":" 2digit
+ // ;; Hours minutes seconds
+ // zone ::= ("+" / "-") 4digit
+ // ;; Signed four-digit value of hhmm representing
+ // ;; hours and minutes west of Greenwich
+ res << '"';
+
+ // Date
+ if (date.day() < 10) res << ' ';
+ res << date.day();
+
+ res << '-';
+
+ static const char* monthNames[12] =
+ { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+ res << monthNames[std::min(std::max(date.month() - 1, 0), 11)];
+
+ res << '-';
+
+ if (date.year() < 10) res << '0';
+ if (date.year() < 100) res << '0';
+ if (date.year() < 1000) res << '0';
+ res << date.year();
+
+ res << ' ';
+
+ // Time
+ if (date.hour() < 10) res << '0';
+ res << date.hour() << ':';
+
+ if (date.minute() < 10) res << '0';
+ res << date.minute() << ':';
+
+ if (date.second() < 10) res << '0';
+ res << date.second();
+
+ res << ' ';
+
+ // Zone
+ const int zs = (date.zone() < 0 ? -1 : 1);
+ const int zh = (date.zone() * zs) / 60;
+ const int zm = (date.zone() * zs) % 60;
+
+ res << (zs < 0 ? '-' : '+');
+
+ if (zh < 10) res << '0';
+ res << zh;
+
+ if (zm < 10) res << '0';
+ res << zm;
+
+ res << '"';
+
+
+ return (res.str());
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/IMAPUtils.hpp b/src/messaging/IMAPUtils.hpp
new file mode 100644
index 00000000..9d523eb7
--- /dev/null
+++ b/src/messaging/IMAPUtils.hpp
@@ -0,0 +1,65 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_IMAPUTILS_HPP_INCLUDED
+#define VMIME_MESSAGING_IMAPUTILS_HPP_INCLUDED
+
+
+#include "folder.hpp"
+#include "../types.hpp"
+#include "IMAPParser.hpp"
+#include "../dateTime.hpp"
+
+#include <vector>
+
+
+namespace vmime {
+namespace messaging {
+
+
+class IMAPUtils
+{
+public:
+
+ static const string pathToString(const char hierarchySeparator, const folder::path& path);
+ static const folder::path stringToPath(const char hierarchySeparator, const string& str);
+
+ static const string toModifiedUTF7(const char hierarchySeparator, const folder::path::component& text);
+ static const folder::path::component fromModifiedUTF7(const string& text);
+
+ static const string quoteString(const string& text);
+
+ static const int folderTypeFromFlags(const IMAPParser::mailbox_flag_list* list);
+ static const int folderFlagsFromFlags(const IMAPParser::mailbox_flag_list* list);
+
+ static const int messageFlagsFromFlags(const IMAPParser::flag_list* list);
+
+ static const string messageFlagList(const int flags);
+
+ static const string listToSet(const std::vector <int>& list, const int max = -1, const bool alreadySorted = false);
+
+ static const string dateTime(const vmime::datetime& date);
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_IMAPUTILS_HPP_INCLUDED
diff --git a/src/messaging/POP3Folder.cpp b/src/messaging/POP3Folder.cpp
new file mode 100644
index 00000000..663d03b5
--- /dev/null
+++ b/src/messaging/POP3Folder.cpp
@@ -0,0 +1,661 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "POP3Folder.hpp"
+
+#include "POP3Store.hpp"
+#include "POP3Message.hpp"
+
+#include "../exception.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+POP3Folder::POP3Folder(const folder::path& path, POP3Store* store)
+ : m_store(store), m_path(path), m_name(path.last()), m_mode(-1), m_open(false)
+{
+ m_store->registerFolder(this);
+}
+
+
+POP3Folder::~POP3Folder()
+{
+ if (m_store)
+ {
+ if (m_open)
+ close(false);
+
+ m_store->unregisterFolder(this);
+ }
+ else if (m_open)
+ {
+ onClose();
+ }
+}
+
+
+const int POP3Folder::mode() const
+{
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ return (m_mode);
+}
+
+
+const int POP3Folder::type()
+{
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ if (m_path.empty())
+ return (TYPE_CONTAINS_FOLDERS);
+ else if (m_path.size() == 1 && m_path[0].buffer() == "INBOX")
+ return (TYPE_CONTAINS_MESSAGES);
+ else
+ throw exceptions::folder_not_found();
+}
+
+
+const int POP3Folder::flags()
+{
+ return (0);
+}
+
+
+const folder::path::component POP3Folder::name() const
+{
+ return (m_name);
+}
+
+
+const folder::path POP3Folder::fullPath() const
+{
+ return (m_path);
+}
+
+
+void POP3Folder::open(const int mode, bool failIfModeIsNotAvailable)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+
+ if (m_path.empty())
+ {
+ if (mode != MODE_READ_ONLY && failIfModeIsNotAvailable)
+ throw exceptions::operation_not_supported();
+
+ m_open = true;
+ m_mode = mode;
+
+ m_messageCount = 0;
+ }
+ else if (m_path.size() == 1 && m_path[0].buffer() == "INBOX")
+ {
+ m_store->sendRequest("STAT");
+
+ string response;
+ m_store->readResponse(response, false);
+
+ if (!m_store->isSuccessResponse(response))
+ throw exceptions::command_error("STAT", response);
+
+ m_store->stripResponseCode(response, response);
+
+ std::istringstream iss(response);
+ iss >> m_messageCount;
+
+ if (iss.fail())
+ throw exceptions::invalid_response("STAT", response);
+
+ m_open = true;
+ m_mode = mode;
+ }
+ else
+ {
+ throw exceptions::folder_not_found();
+ }
+}
+
+void POP3Folder::close(const bool expunge)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ if (!expunge)
+ {
+ m_store->sendRequest("RSET");
+
+ string response;
+ m_store->readResponse(response, false);
+ }
+
+ m_open = false;
+ m_mode = -1;
+
+ onClose();
+}
+
+
+void POP3Folder::onClose()
+{
+ for (MessageMap::iterator it = m_messages.begin() ; it != m_messages.end() ; ++it)
+ (*it).first->onFolderClosed();
+
+ m_messages.clear();
+}
+
+
+void POP3Folder::create(const int /* type */)
+{
+ throw exceptions::operation_not_supported();
+}
+
+
+const bool POP3Folder::exists()
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+
+ return (m_path.empty() || (m_path.size() == 1 && m_path[0].buffer() == "INBOX"));
+}
+
+
+const bool POP3Folder::isOpen() const
+{
+ return (m_open);
+}
+
+
+message* POP3Folder::getMessage(const int num)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+ else if (num < 1 || num > m_messageCount)
+ throw exceptions::message_not_found();
+
+ return new POP3Message(this, num);
+}
+
+
+std::vector <message*> POP3Folder::getMessages(const int from, const int to)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+ else if (to < from || from < 1 || to < 1 || from > m_messageCount || to > m_messageCount)
+ throw exceptions::message_not_found();
+
+ std::vector <message*> v;
+
+ for (int i = from ; i <= to ; ++i)
+ v.push_back(new POP3Message(this, i));
+
+ return (v);
+}
+
+
+std::vector <message*> POP3Folder::getMessages(const std::vector <int>& nums)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ std::vector <message*> v;
+
+ try
+ {
+ for (std::vector <int>::const_iterator it = nums.begin() ; it != nums.end() ; ++it)
+ {
+ if (*it < 1|| *it > m_messageCount)
+ throw exceptions::message_not_found();
+
+ v.push_back(new POP3Message(this, *it));
+ }
+ }
+ catch (std::exception& e)
+ {
+ for (std::vector <message*>::iterator it = v.begin() ; it != v.end() ; ++it)
+ delete (*it);
+
+ throw;
+ }
+
+ return (v);
+}
+
+
+const int POP3Folder::getMessageCount()
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ return (m_messageCount);
+}
+
+
+folder* POP3Folder::getFolder(const folder::path::component& name)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+
+ return new POP3Folder(m_path / name, m_store);
+}
+
+
+std::vector <folder*> POP3Folder::getFolders(const bool /* recursive */)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+
+ if (m_path.empty())
+ {
+ std::vector <folder*> v;
+ v.push_back(new POP3Folder(folder::path::component("INBOX"), m_store));
+ return (v);
+ }
+ else
+ {
+ std::vector <folder*> v;
+ return (v);
+ }
+}
+
+
+void POP3Folder::fetchMessages(std::vector <message*>& msg, const int options,
+ progressionListener* progress)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ const int total = msg.size();
+ int current = 0;
+
+ if (progress)
+ progress->start(total);
+
+ for (std::vector <message*>::iterator it = msg.begin() ;
+ it != msg.end() ; ++it)
+ {
+ dynamic_cast <POP3Message*>(*it)->fetch(this, options);
+
+ if (progress)
+ progress->progress(++current, total);
+ }
+
+ if (options & FETCH_UID)
+ {
+ // Send the "UIDL" command
+ std::ostringstream command;
+ command << "UIDL";
+
+ m_store->sendRequest(command.str());
+
+ // Get the response
+ string response;
+ m_store->readResponse(response, true, NULL);
+
+ if (m_store->isSuccessResponse(response))
+ {
+ m_store->stripFirstLine(response, response, NULL);
+
+ // C: UIDL
+ // S: +OK
+ // S: 1 whqtswO00WBw418f9t5JxYwZ
+ // S: 2 QhdPYR:00WBw1Ph7x7
+ // S: .
+
+ std::istringstream iss(response);
+ std::map <int, string> ids;
+
+ string line;
+
+ while (std::getline(iss, line))
+ {
+ string::iterator it = line.begin();
+
+ while (it != line.end() && (*it == ' ' || *it == '\t'))
+ ++it;
+
+ if (it != line.end())
+ {
+ int number = 0;
+
+ while (it != line.end() && (*it >= '0' && *it <= '9'))
+ {
+ number = (number * 10) + (*it - '0');
+ ++it;
+ }
+
+ while (it != line.end() && !(*it == ' ' || *it == '\t')) ++it;
+ while (it != line.end() && (*it == ' ' || *it == '\t')) ++it;
+
+ if (it != line.end())
+ {
+ ids.insert(std::map <int, string>::value_type
+ (number, string(it, line.end())));
+ }
+ }
+ }
+
+ for (std::vector <message*>::iterator it = msg.begin() ;
+ it != msg.end() ; ++it)
+ {
+ POP3Message* m = dynamic_cast <POP3Message*>(*it);
+
+ std::map <int, string>::const_iterator id =
+ ids.find(m->m_num);
+
+ if (id != ids.end())
+ m->m_uid = (*id).second;
+ }
+ }
+ }
+
+ if (progress)
+ progress->stop(total);
+}
+
+
+void POP3Folder::fetchMessage(message* msg, const int options)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ dynamic_cast <POP3Message*>(msg)->fetch(this, options);
+
+ if (options & FETCH_UID)
+ {
+ // Send the "UIDL" command
+ std::ostringstream command;
+ command << "UIDL";
+
+ m_store->sendRequest(command.str());
+
+ // Get the response
+ string response;
+ m_store->readResponse(response, false, NULL);
+
+ if (m_store->isSuccessResponse(response))
+ {
+ m_store->stripResponseCode(response, response);
+
+ // C: UIDL 2
+ // S: +OK 2 QhdPYR:00WBw1Ph7x7
+ string::iterator it = response.begin();
+
+ while (it != response.end() && (*it == ' ' || *it == '\t')) ++it;
+ while (it != response.end() && !(*it == ' ' || *it == '\t')) ++it;
+ while (it != response.end() && (*it == ' ' || *it == '\t')) ++it;
+
+ if (it != response.end())
+ {
+ dynamic_cast <POP3Message*>(msg)->m_uid =
+ string(it, response.end());
+ }
+ }
+ }
+}
+
+
+const int POP3Folder::getFetchCapabilities() const
+{
+ return (FETCH_ENVELOPE | FETCH_CONTENT_INFO |
+ FETCH_SIZE | FETCH_FULL_HEADER | FETCH_UID);
+}
+
+
+folder* POP3Folder::getParent()
+{
+ return (m_path.empty() ? NULL : new POP3Folder(m_path.parent(), m_store));
+}
+
+
+const class store& POP3Folder::store() const
+{
+ return (*m_store);
+}
+
+
+class store& POP3Folder::store()
+{
+ return (*m_store);
+}
+
+
+void POP3Folder::registerMessage(POP3Message* msg)
+{
+ m_messages.insert(MessageMap::value_type(msg, msg->number()));
+}
+
+
+void POP3Folder::unregisterMessage(POP3Message* msg)
+{
+ m_messages.erase(msg);
+}
+
+
+void POP3Folder::onStoreDisconnected()
+{
+ m_store = NULL;
+}
+
+
+void POP3Folder::deleteMessage(const int num)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ std::ostringstream command;
+ command << "DELE " << num;
+
+ m_store->sendRequest(command.str());
+
+ string response;
+ m_store->readResponse(response, false);
+
+ if (!m_store->isSuccessResponse(response))
+ throw exceptions::command_error("DELE", response);
+}
+
+
+void POP3Folder::deleteMessages(const int from, const int to)
+{
+ if (from < 1 || (to < from && to != -1))
+ throw exceptions::invalid_argument();
+
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ for (int i = from ; i < to ; ++i)
+ {
+ std::ostringstream command;
+ command << "DELE " << i;
+
+ m_store->sendRequest(command.str());
+
+ string response;
+ m_store->readResponse(response, false);
+
+ if (!m_store->isSuccessResponse(response))
+ throw exceptions::command_error("DELE", response);
+ }
+}
+
+
+void POP3Folder::deleteMessages(const std::vector <int>& nums)
+{
+ if (nums.empty())
+ throw exceptions::invalid_argument();
+
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ for (std::vector <int>::const_iterator
+ it = nums.begin() ; it != nums.end() ; ++it)
+ {
+ std::ostringstream command;
+ command << "DELE " << (*it);
+
+ m_store->sendRequest(command.str());
+
+ string response;
+ m_store->readResponse(response, false);
+
+ if (!m_store->isSuccessResponse(response))
+ throw exceptions::command_error("DELE", response);
+ }
+}
+
+
+void POP3Folder::setMessageFlags(const int /* from */, const int /* to */,
+ const int /* flags */, const int /* mode */)
+{
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Folder::setMessageFlags(const std::vector <int>& /* nums */,
+ const int /* flags */, const int /* mode */)
+{
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Folder::rename(const folder::path& /* newPath */)
+{
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Folder::addMessage(vmime::message* /* msg */, const int /* flags */,
+ vmime::datetime* /* date */, progressionListener* /* progress */)
+{
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Folder::addMessage(utility::inputStream& /* is */, const int /* size */, const int /* flags */,
+ vmime::datetime* /* date */, progressionListener* /* progress */)
+{
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Folder::copyMessage(const folder::path& /* dest */, const int /* num */)
+{
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Folder::copyMessages(const folder::path& /* dest */, const int /* from */, const int /* to */)
+{
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Folder::copyMessages(const folder::path& /* dest */, const std::vector <int>& /* nums */)
+{
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Folder::status(int& count, int& unseen)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ m_store->sendRequest("STAT");
+
+ string response;
+ m_store->readResponse(response, false);
+
+ if (!m_store->isSuccessResponse(response))
+ throw exceptions::command_error("STAT", response);
+
+ m_store->stripResponseCode(response, response);
+
+ std::istringstream iss(response);
+ iss >> count;
+
+ unseen = count;
+
+ // Update local message count
+ if (m_messageCount != count)
+ {
+ const int oldCount = m_messageCount;
+
+ m_messageCount = count;
+
+ if (count > oldCount)
+ {
+ std::vector <int> nums;
+ nums.reserve(count - oldCount);
+
+ for (int i = oldCount + 1, j = 0 ; i <= count ; ++i, ++j)
+ nums[j] = i;
+
+ events::messageCountEvent event(this, events::messageCountEvent::TYPE_ADDED, nums);
+
+ for (std::list <POP3Folder*>::iterator it = m_store->m_folders.begin() ;
+ it != m_store->m_folders.end() ; ++it)
+ {
+ if ((*it)->fullPath() == m_path)
+ {
+ (*it)->m_messageCount = count;
+ (*it)->notifyMessageCount(event);
+ }
+ }
+ }
+ }
+}
+
+
+void POP3Folder::expunge()
+{
+ // Not supported by POP3 protocol (deleted messages are automatically
+ // expunged at the end of the session...).
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/POP3Folder.hpp b/src/messaging/POP3Folder.hpp
new file mode 100644
index 00000000..cfb83bef
--- /dev/null
+++ b/src/messaging/POP3Folder.hpp
@@ -0,0 +1,142 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_POP3FOLDER_HPP_INCLUDED
+#define VMIME_MESSAGING_POP3FOLDER_HPP_INCLUDED
+
+
+#include <vector>
+#include <map>
+
+#include "../types.hpp"
+#include "folder.hpp"
+#include "../config.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+class POP3Store;
+class POP3Message;
+
+
+/** POP3 folder implementation.
+ */
+
+class POP3Folder : public folder
+{
+protected:
+
+ friend class POP3Store;
+ friend class POP3Message;
+
+ POP3Folder(const folder::path& path, POP3Store* store);
+ POP3Folder(const POP3Folder&) : folder() { }
+
+ ~POP3Folder();
+
+public:
+
+ const int mode() const;
+
+ const int type();
+
+ const int flags();
+
+ const folder::path::component name() const;
+ const folder::path fullPath() const;
+
+ void open(const int mode, bool failIfModeIsNotAvailable = false);
+ void close(const bool expunge);
+ void create(const int type);
+
+ const bool exists();
+
+ const bool isOpen() const;
+
+ message* getMessage(const int num);
+ std::vector <message*> getMessages(const int from = 1, const int to = -1);
+ std::vector <message*> getMessages(const std::vector <int>& nums);
+ const int getMessageCount();
+
+ folder* getFolder(const folder::path::component& name);
+ std::vector <folder*> getFolders(const bool recursive = false);
+
+ void rename(const folder::path& newPath);
+
+ void deleteMessage(const int num);
+ void deleteMessages(const int from = 1, const int to = -1);
+ void deleteMessages(const std::vector <int>& nums);
+
+ void setMessageFlags(const int from, const int to, const int flags, const int mode = message::FLAG_MODE_SET);
+ void setMessageFlags(const std::vector <int>& nums, const int flags, const int mode = message::FLAG_MODE_SET);
+
+ void addMessage(vmime::message* msg, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, progressionListener* progress = NULL);
+ void addMessage(utility::inputStream& is, const int size, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, progressionListener* progress = NULL);
+
+ void copyMessage(const folder::path& dest, const int num);
+ void copyMessages(const folder::path& dest, const int from = 1, const int to = -1);
+ void copyMessages(const folder::path& dest, const std::vector <int>& nums);
+
+ void status(int& count, int& unseen);
+
+ void expunge();
+
+ folder* getParent();
+
+ const class store& store() const;
+ class store& store();
+
+
+ void fetchMessages(std::vector <message*>& msg, const int options, progressionListener* progress = NULL);
+ void fetchMessage(message* msg, const int options);
+
+ const int getFetchCapabilities() const;
+
+private:
+
+ void registerMessage(POP3Message* msg);
+ void unregisterMessage(POP3Message* msg);
+
+ void onStoreDisconnected();
+
+ void onClose();
+
+
+ POP3Store* m_store;
+
+ folder::path m_path;
+ folder::path::component m_name;
+
+ int m_mode;
+ bool m_open;
+
+ int m_messageCount;
+
+ typedef std::map <POP3Message*, int> MessageMap;
+ MessageMap m_messages;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_POP3FOLDER_HPP_INCLUDED
diff --git a/src/messaging/POP3Message.cpp b/src/messaging/POP3Message.cpp
new file mode 100644
index 00000000..66b3f466
--- /dev/null
+++ b/src/messaging/POP3Message.cpp
@@ -0,0 +1,220 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "POP3Message.hpp"
+#include "POP3Folder.hpp"
+#include "POP3Store.hpp"
+
+#include <sstream>
+
+
+namespace vmime {
+namespace messaging {
+
+
+
+class POP3header : public header
+{
+public:
+
+ POP3header(const string& str)
+ {
+ parse(str);
+ }
+};
+
+
+
+POP3Message::POP3Message(POP3Folder* folder, const int num)
+ : m_folder(folder), m_num(num), m_header(NULL)
+{
+ m_folder->registerMessage(this);
+}
+
+
+POP3Message::~POP3Message()
+{
+ if (m_folder)
+ m_folder->unregisterMessage(this);
+
+ delete dynamic_cast <POP3header*>(m_header);
+}
+
+
+void POP3Message::onFolderClosed()
+{
+ m_folder = NULL;
+}
+
+
+const int POP3Message::number() const
+{
+ return (m_num);
+}
+
+
+const message::uid POP3Message::uniqueId() const
+{
+ return (m_uid);
+}
+
+
+const int POP3Message::size() const
+{
+ if (!m_folder)
+ throw exceptions::illegal_state("Folder closed");
+
+ POP3Folder::MessageMap::const_iterator it =
+ m_folder->m_messages.find(const_cast <POP3Message*>(this));
+
+ return ((it != m_folder->m_messages.end()) ? (*it).second : 0);
+}
+
+
+const bool POP3Message::isExpunged() const
+{
+ return (false);
+}
+
+
+const int POP3Message::flags() const
+{
+ return (FLAG_RECENT);
+}
+
+
+const class structure& POP3Message::structure() const
+{
+ throw exceptions::operation_not_supported();
+}
+
+
+class structure& POP3Message::structure()
+{
+ throw exceptions::operation_not_supported();
+}
+
+
+const class header& POP3Message::header() const
+{
+ if (m_header == NULL)
+ throw exceptions::unfetched_object();
+
+ return (*m_header);
+}
+
+
+void POP3Message::extract(utility::outputStream& os, progressionListener* progress,
+ const int start, const int length) const
+{
+ if (!m_folder)
+ throw exceptions::illegal_state("Folder closed");
+ else if (!m_folder->m_store)
+ throw exceptions::illegal_state("Store disconnected");
+
+ if (start != 0 && length != -1)
+ throw exceptions::partial_fetch_not_supported();
+
+ // Emit the "RETR" command
+ std::ostringstream oss;
+ oss << "RETR " << m_num;
+
+ const_cast <POP3Folder*>(m_folder)->m_store->sendRequest(oss.str());
+
+ try
+ {
+ POP3Folder::MessageMap::const_iterator it =
+ m_folder->m_messages.find(const_cast <POP3Message*>(this));
+
+ const int totalSize = (it != m_folder->m_messages.end())
+ ? (*it).second : 0;
+
+ const_cast <POP3Folder*>(m_folder)->m_store->
+ readResponse(os, progress, totalSize);
+ }
+ catch (exceptions::command_error& e)
+ {
+ throw exceptions::command_error("RETR", e.response());
+ }
+}
+
+
+void POP3Message::extractPart
+ (const part& /* p */, utility::outputStream& /* os */, progressionListener* /* progress */,
+ const int /* start */, const int /* length */) const
+{
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Message::fetchPartHeader(part& /* p */)
+{
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Message::fetch(POP3Folder* folder, const int options)
+{
+ if (m_folder != folder)
+ throw exceptions::folder_not_found();
+
+ // FETCH_STRUCTURE and FETCH_FLAGS are not supported by POP3.
+ if (options & (folder::FETCH_STRUCTURE | folder::FETCH_FLAGS))
+ throw exceptions::operation_not_supported();
+
+ // Check for the real need to fetch the full header
+ if (!((options & folder::FETCH_ENVELOPE) ||
+ (options & folder::FETCH_CONTENT_INFO) ||
+ (options & folder::FETCH_FULL_HEADER)))
+ {
+ return;
+ }
+
+ // No need to differenciate between FETCH_ENVELOPE,
+ // FETCH_CONTENT_INFO, ... since POP3 only permits to
+ // retrieve the whole header and not fields in particular.
+
+ // Emit the "TOP" command
+ std::ostringstream oss;
+ oss << "TOP " << m_num << " 0";
+
+ m_folder->m_store->sendRequest(oss.str());
+
+ try
+ {
+ string buffer;
+ m_folder->m_store->readResponse(buffer, true);
+
+ m_header = new POP3header(buffer);
+ }
+ catch (exceptions::command_error& e)
+ {
+ throw exceptions::command_error("TOP", e.response());
+ }
+}
+
+
+void POP3Message::setFlags(const int /* flags */, const int /* mode */)
+{
+ throw exceptions::operation_not_supported();
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/POP3Message.hpp b/src/messaging/POP3Message.hpp
new file mode 100644
index 00000000..193624b8
--- /dev/null
+++ b/src/messaging/POP3Message.hpp
@@ -0,0 +1,88 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_POP3MESSAGE_HPP_INCLUDED
+#define VMIME_MESSAGING_POP3MESSAGE_HPP_INCLUDED
+
+
+#include "message.hpp"
+#include "folder.hpp"
+#include "../config.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+/** POP3 message implementation.
+ */
+
+class POP3Message : public message
+{
+protected:
+
+ friend class POP3Folder;
+
+ POP3Message(POP3Folder* folder, const int num);
+ POP3Message(const POP3Message&) : message() { }
+
+ ~POP3Message();
+
+public:
+
+ const int number() const;
+
+ const uid uniqueId() const;
+
+ const int size() const;
+
+ const bool isExpunged() const;
+
+ const class structure& structure() const;
+ class structure& structure();
+
+ const class header& header() const;
+
+ const int flags() const;
+ void setFlags(const int flags, const int mode = FLAG_MODE_SET);
+
+ void extract(utility::outputStream& os, progressionListener* progress = NULL, const int start = 0, const int length = -1) const;
+ void extractPart(const part& p, utility::outputStream& os, progressionListener* progress = NULL, const int start = 0, const int length = -1) const;
+
+ void fetchPartHeader(part& p);
+
+private:
+
+ void fetch(POP3Folder* folder, const int options);
+
+ void onFolderClosed();
+
+ POP3Folder* m_folder;
+ int m_num;
+ uid m_uid;
+
+ class header* m_header;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_POP3MESSAGE_HPP_INCLUDED
diff --git a/src/messaging/POP3Store.cpp b/src/messaging/POP3Store.cpp
new file mode 100644
index 00000000..c105bc4b
--- /dev/null
+++ b/src/messaging/POP3Store.cpp
@@ -0,0 +1,603 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "POP3Store.hpp"
+
+#include "../exception.hpp"
+#include "../platformDependant.hpp"
+#include "../messageId.hpp"
+#include "../utility/md5.hpp"
+
+#include "POP3Folder.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace messaging {
+
+
+POP3Store::POP3Store(class session& sess, class authenticator* auth)
+ : store(sess, infosInstance(), auth), m_socket(NULL),
+ m_authentified(false), m_timeoutHandler(NULL)
+{
+}
+
+
+POP3Store::~POP3Store()
+{
+ if (isConnected())
+ disconnect();
+ else if (m_socket)
+ internalDisconnect();
+}
+
+
+const string POP3Store::protocolName() const
+{
+ return "pop3";
+}
+
+
+folder* POP3Store::getDefaultFolder()
+{
+ if (!isConnected())
+ throw exceptions::illegal_state("Not connected");
+
+ return new POP3Folder(folder::path(folder::path::component("INBOX")), this);
+}
+
+
+folder* POP3Store::getRootFolder()
+{
+ if (!isConnected())
+ throw exceptions::illegal_state("Not connected");
+
+ return new POP3Folder(folder::path(), this);
+}
+
+
+folder* POP3Store::getFolder(const folder::path& path)
+{
+ if (!isConnected())
+ throw exceptions::illegal_state("Not connected");
+
+ return new POP3Folder(path, this);
+}
+
+
+void POP3Store::connect()
+{
+ if (isConnected())
+ throw exceptions::already_connected();
+
+ const string address = session().properties()[sm_infos.propertyPrefix() + "server.address"];
+ const port_t port = session().properties().get(sm_infos.propertyPrefix() + "server.port", sm_infos.defaultPort());
+
+ // Create the time-out handler
+ if (session().properties().exists
+ (sm_infos.propertyPrefix() + "timeout.factory"))
+ {
+ timeoutHandlerFactory* tof = platformDependant::getHandler()->
+ getTimeoutHandlerFactory(session().properties()
+ [sm_infos.propertyPrefix() + "timeout.factory"]);
+
+ m_timeoutHandler = tof->create();
+ }
+
+ // Create and connect the socket
+ socketFactory* sf = platformDependant::getHandler()->getSocketFactory
+ (session().properties().get(sm_infos.propertyPrefix() + "server.socket-factory", string("default")));
+
+ m_socket = sf->create();
+ m_socket->connect(address, port);
+
+ // Connection
+ //
+ // eg: C: <connection to server>
+ // --- S: +OK MailSite POP3 Server 5.3.4.0 Ready <[email protected]>
+
+ string response;
+ readResponse(response, false);
+
+ if (isSuccessResponse(response))
+ {
+ bool authentified = false;
+
+ const authenticationInfos auth = authenticator().requestAuthInfos();
+
+ // Secured authentication with APOP (if requested and if available)
+ //
+ // eg: C: APOP vincent <digest>
+ // --- S: +OK vincent is a valid mailbox
+ messageId mid(response);
+
+ if (session().properties().get(sm_infos.propertyPrefix() + "options.apop", false))
+ {
+ if (mid.left().length() && mid.right().length())
+ {
+ // <digest> is the result of MD5 applied to "<message-id>password"
+ sendRequest("APOP " + auth.username() + " "
+ + utility::md5(mid.generate() + auth.password()).hex());
+ readResponse(response, false);
+
+ if (isSuccessResponse(response))
+ {
+ authentified = true;
+ }
+ else
+ {
+ if (session().properties().get(sm_infos.propertyPrefix() +
+ "options.apop.fallback", false) == false)
+ {
+ internalDisconnect();
+ throw exceptions::authentication_error(response);
+ }
+ }
+ }
+ else
+ {
+ // APOP not supported
+ if (session().properties().get(sm_infos.propertyPrefix() +
+ "options.apop.fallback", false) == false)
+ {
+ // Can't fallback on basic authentification
+ internalDisconnect();
+ throw exceptions::unsupported_option();
+ }
+ }
+ }
+
+ if (!authentified)
+ {
+ // Basic authentication
+ //
+ // eg: C: USER vincent
+ // --- S: +OK vincent is a valid mailbox
+ //
+ // C: PASS couic
+ // S: +OK vincent's maildrop has 2 messages (320 octets)
+
+ sendRequest("USER " + auth.username());
+ readResponse(response, false);
+
+ if (isSuccessResponse(response))
+ {
+ sendRequest("PASS " + auth.password());
+ readResponse(response, false);
+
+ if (!isSuccessResponse(response))
+ {
+ internalDisconnect();
+ throw exceptions::authentication_error(response);
+ }
+ }
+ else
+ {
+ internalDisconnect();
+ throw exceptions::authentication_error(response);
+ }
+ }
+ }
+ else
+ {
+ internalDisconnect();
+ throw exceptions::connection_greeting_error(response);
+ }
+
+ m_authentified = true;
+}
+
+
+const bool POP3Store::isConnected() const
+{
+ return (m_socket && m_socket->isConnected() && m_authentified);
+}
+
+
+void POP3Store::disconnect()
+{
+ if (!isConnected())
+ throw exceptions::not_connected();
+
+ internalDisconnect();
+}
+
+
+void POP3Store::internalDisconnect()
+{
+ for (std::list <POP3Folder*>::iterator it = m_folders.begin() ;
+ it != m_folders.end() ; ++it)
+ {
+ (*it)->onStoreDisconnected();
+ }
+
+ m_folders.clear();
+
+
+ sendRequest("QUIT");
+
+ m_socket->disconnect();
+
+ delete (m_socket);
+ m_socket = NULL;
+
+ delete (m_timeoutHandler);
+ m_timeoutHandler = NULL;
+
+ m_authentified = false;
+}
+
+
+void POP3Store::noop()
+{
+ m_socket->send("NOOP");
+
+ string response;
+ readResponse(response, false);
+
+ if (!isSuccessResponse(response))
+ throw exceptions::command_error("NOOP", response);
+}
+
+
+const bool POP3Store::isSuccessResponse(const string& buffer)
+{
+ static const string OK("+OK");
+
+ return (buffer.length() >= 3 &&
+ std::equal(buffer.begin(), buffer.begin() + 3, OK.begin()));
+}
+
+
+const bool POP3Store::stripFirstLine(const string& buffer, string& result, string* firstLine)
+{
+ const string::size_type end = buffer.find('\n');
+
+ if (end != string::npos)
+ {
+ if (firstLine) *firstLine = buffer.substr(0, end);
+ result = buffer.substr(end + 1);
+ return (true);
+ }
+ else
+ {
+ result = buffer;
+ return (false);
+ }
+}
+
+
+void POP3Store::stripResponseCode(const string& buffer, string& result)
+{
+ const string::size_type pos = buffer.find_first_of(" \t");
+
+ if (pos != string::npos)
+ result = buffer.substr(pos + 1);
+ else
+ result = buffer;
+}
+
+
+void POP3Store::sendRequest(const string& buffer, const bool end)
+{
+ m_socket->send(buffer);
+ if (end) m_socket->send("\r\n");
+}
+
+
+void POP3Store::readResponse(string& buffer, const bool multiLine,
+ progressionListener* progress)
+{
+ bool foundTerminator = false;
+ int current = 0, total = 0;
+
+ if (progress)
+ progress->start(total);
+
+ if (m_timeoutHandler)
+ m_timeoutHandler->resetTimeOut();
+
+ buffer.clear();
+
+ string::value_type last1 = '\0', last2 = '\0';
+
+ for ( ; !foundTerminator ; )
+ {
+#if 0 // not supported
+ // Check for possible cancellation
+ if (progress && progress->cancel())
+ throw exceptions::operation_cancelled();
+#endif
+
+ // Check whether the time-out delay is elapsed
+ if (m_timeoutHandler && m_timeoutHandler->isTimeOut())
+ {
+ if (!m_timeoutHandler->handleTimeOut())
+ throw exceptions::operation_timed_out();
+ }
+
+ // Receive data from the socket
+ string receiveBuffer;
+ m_socket->receive(receiveBuffer);
+
+ if (receiveBuffer.empty()) // buffer is empty
+ {
+ platformDependant::getHandler()->wait();
+ continue;
+ }
+
+ // We have received data: reset the time-out counter
+ if (m_timeoutHandler)
+ m_timeoutHandler->resetTimeOut();
+
+ // Check for transparent characters: '\n..' becomes '\n.'
+ const string::value_type first = receiveBuffer[0];
+
+ if (first == '.' && last2 == '\n' && last1 == '.')
+ {
+ receiveBuffer.erase(receiveBuffer.begin());
+ }
+ else if (receiveBuffer.length() >= 2 && first == '.' &&
+ receiveBuffer[1] == '.' && last1 == '\n')
+ {
+ receiveBuffer.erase(receiveBuffer.begin());
+ }
+
+ for (string::size_type trans ;
+ string::npos != (trans = receiveBuffer.find("\n..")) ; )
+ {
+ receiveBuffer.replace(trans, 3, "\n.");
+ }
+
+ last1 = receiveBuffer[receiveBuffer.length() - 1];
+ last2 = (receiveBuffer.length() >= 2) ? receiveBuffer[receiveBuffer.length() - 2] : 0;
+
+ // Append the data to the response buffer
+ buffer += receiveBuffer;
+ current += receiveBuffer.length();
+
+ // Check for terminator string (and strip it if present)
+ foundTerminator = checkTerminator(buffer, multiLine);
+
+ // Notify progression
+ if (progress)
+ {
+ total = std::max(total, current);
+ progress->progress(current, total);
+ }
+
+ // If there is an error (-ERR) when executing a command that
+ // requires a multi-line response, the error response will
+ // include only one line, so we stop waiting for a multi-line
+ // terminator and check for a "normal" one.
+ if (multiLine && !foundTerminator && buffer.length() >= 4 && buffer[0] == '-')
+ {
+ foundTerminator = checkTerminator(buffer, false);
+ }
+ }
+
+ if (progress)
+ progress->stop(total);
+}
+
+
+void POP3Store::readResponse(utility::outputStream& os, progressionListener* progress,
+ const int predictedSize)
+{
+ bool foundTerminator = false;
+ int current = 0, total = predictedSize;
+
+ string temp;
+ bool codeDone = false;
+
+ if (progress)
+ progress->start(total);
+
+ if (m_timeoutHandler)
+ m_timeoutHandler->resetTimeOut();
+
+ string::value_type last1 = '\0', last2 = '\0';
+
+ for ( ; !foundTerminator ; )
+ {
+#if 0 // not supported
+ // Check for possible cancellation
+ if (progress && progress->cancel())
+ throw exceptions::operation_cancelled();
+#endif
+
+ // Check whether the time-out delay is elapsed
+ if (m_timeoutHandler && m_timeoutHandler->isTimeOut())
+ {
+ if (!m_timeoutHandler->handleTimeOut())
+ throw exceptions::operation_timed_out();
+ }
+
+ // Receive data from the socket
+ string receiveBuffer;
+ m_socket->receive(receiveBuffer);
+
+ if (receiveBuffer.empty()) // buffer is empty
+ {
+ platformDependant::getHandler()->wait();
+ continue;
+ }
+
+ // We have received data: reset the time-out counter
+ if (m_timeoutHandler)
+ m_timeoutHandler->resetTimeOut();
+
+ // Check for transparent characters: '\n..' becomes '\n.'
+ const string::value_type first = receiveBuffer[0];
+
+ if (first == '.' && last2 == '\n' && last1 == '.')
+ {
+ receiveBuffer.erase(receiveBuffer.begin());
+ }
+ else if (receiveBuffer.length() >= 2 && first == '.' &&
+ receiveBuffer[1] == '.' && last1 == '\n')
+ {
+ receiveBuffer.erase(receiveBuffer.begin());
+ }
+
+ for (string::size_type trans ;
+ string::npos != (trans = receiveBuffer.find("\n..")) ; )
+ {
+ receiveBuffer.replace(trans, 3, "\n.");
+ }
+
+ last1 = receiveBuffer[receiveBuffer.length() - 1];
+ last2 = (receiveBuffer.length() >= 2) ? receiveBuffer[receiveBuffer.length() - 2] : 0;
+
+ // If we don't have extracted the response code yet
+ if (!codeDone)
+ {
+ temp += receiveBuffer;
+
+ string firstLine;
+
+ if (stripFirstLine(temp, temp, &firstLine) == true)
+ {
+ if (!isSuccessResponse(firstLine))
+ throw exceptions::command_error("?", firstLine);
+
+ receiveBuffer = temp;
+ temp.clear();
+
+ codeDone = true;
+ }
+ }
+
+ if (codeDone)
+ {
+ // Check for terminator string (and strip it if present)
+ foundTerminator = checkTerminator(receiveBuffer, true);
+
+ // Inject the data into the output stream
+ os.write(receiveBuffer.data(), receiveBuffer.length());
+ current += receiveBuffer.length();
+
+ // Notify progression
+ if (progress)
+ {
+ total = std::max(total, current);
+ progress->progress(current, total);
+ }
+ }
+ }
+
+ if (progress)
+ progress->stop(total);
+}
+
+
+const bool POP3Store::checkTerminator(string& buffer, const bool multiLine)
+{
+ // Multi-line response
+ if (multiLine)
+ {
+ static const string term1("\r\n.\r\n");
+ static const string term2("\n.\n");
+
+ return (checkOneTerminator(buffer, term1) ||
+ checkOneTerminator(buffer, term2));
+ }
+ // Normal response
+ else
+ {
+ static const string term1("\r\n");
+ static const string term2("\n");
+
+ return (checkOneTerminator(buffer, term1) ||
+ checkOneTerminator(buffer, term2));
+ }
+
+ return (false);
+}
+
+
+const bool POP3Store::checkOneTerminator(string& buffer, const string& term)
+{
+ if (buffer.length() >= term.length() &&
+ std::equal(buffer.end() - term.length(), buffer.end(), term.begin()))
+ {
+ buffer.erase(buffer.end() - term.length(), buffer.end());
+ return (true);
+ }
+
+ return (false);
+}
+
+
+void POP3Store::registerFolder(POP3Folder* folder)
+{
+ m_folders.push_back(folder);
+}
+
+
+void POP3Store::unregisterFolder(POP3Folder* folder)
+{
+ std::list <POP3Folder*>::iterator it = std::find(m_folders.begin(), m_folders.end(), folder);
+ if (it != m_folders.end()) m_folders.erase(it);
+}
+
+
+
+// Service infos
+
+POP3Store::_infos POP3Store::sm_infos;
+
+
+const port_t POP3Store::_infos::defaultPort() const
+{
+ return (110);
+}
+
+
+const string POP3Store::_infos::propertyPrefix() const
+{
+ return "store.pop3.";
+}
+
+
+const std::vector <string> POP3Store::_infos::availableProperties() const
+{
+ std::vector <string> list;
+
+ // POP3-specific options
+ list.push_back("options.apop");
+ list.push_back("options.apop.fallback");
+
+ // Common properties
+ list.push_back("auth.username");
+ list.push_back("auth.password");
+
+ list.push_back("server.address");
+ list.push_back("server.port");
+ list.push_back("server.socket-factory");
+
+ list.push_back("timeout.factory");
+
+ return (list);
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/POP3Store.hpp b/src/messaging/POP3Store.hpp
new file mode 100644
index 00000000..b9d6bd87
--- /dev/null
+++ b/src/messaging/POP3Store.hpp
@@ -0,0 +1,110 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_POP3STORE_HPP_INCLUDED
+#define VMIME_MESSAGING_POP3STORE_HPP_INCLUDED
+
+
+#include "store.hpp"
+#include "socket.hpp"
+#include "../config.hpp"
+#include "timeoutHandler.hpp"
+#include "../utility/stream.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+/** POP3 store service.
+ */
+
+class POP3Store : public store
+{
+ friend class POP3Folder;
+ friend class POP3Message;
+
+public:
+
+ POP3Store(class session& sess, class authenticator* auth);
+ ~POP3Store();
+
+ const string protocolName() const;
+
+ folder* getDefaultFolder();
+ folder* getRootFolder();
+ folder* getFolder(const folder::path& path);
+
+ static const serviceInfos& infosInstance() { return (sm_infos); }
+ const serviceInfos& infos() const { return (sm_infos); }
+
+ void connect();
+ const bool isConnected() const;
+ void disconnect();
+
+ void noop();
+
+private:
+
+ static const bool isSuccessResponse(const string& buffer);
+ static const bool stripFirstLine(const string& buffer, string& result, string* firstLine = NULL);
+ static void stripResponseCode(const string& buffer, string& result);
+
+ void sendRequest(const string& buffer, const bool end = true);
+ void readResponse(string& buffer, const bool multiLine, progressionListener* progress = NULL);
+ void readResponse(utility::outputStream& os, progressionListener* progress = NULL, const int predictedSize = 0);
+
+ static const bool checkTerminator(string& buffer, const bool multiLine);
+ static const bool checkOneTerminator(string& buffer, const string& term);
+
+ void internalDisconnect();
+
+
+ void registerFolder(POP3Folder* folder);
+ void unregisterFolder(POP3Folder* folder);
+
+ std::list <POP3Folder*> m_folders;
+
+
+ socket* m_socket;
+ bool m_authentified;
+
+ timeoutHandler* m_timeoutHandler;
+
+
+ // Service infos
+ class _infos : public serviceInfos
+ {
+ public:
+
+ const port_t defaultPort() const;
+
+ const string propertyPrefix() const;
+ const std::vector <string> availableProperties() const;
+ };
+
+ static _infos sm_infos;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_POP3STORE_HPP_INCLUDED
diff --git a/src/messaging/SMTPTransport.cpp b/src/messaging/SMTPTransport.cpp
new file mode 100644
index 00000000..309f3e06
--- /dev/null
+++ b/src/messaging/SMTPTransport.cpp
@@ -0,0 +1,575 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "SMTPTransport.hpp"
+
+#include "../exception.hpp"
+#include "../platformDependant.hpp"
+#include "../encoderB64.hpp"
+#include "../message.hpp"
+#include "../mailboxList.hpp"
+#include "authHelper.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+SMTPTransport::SMTPTransport(class session& sess, class authenticator* auth)
+ : transport(sess, infosInstance(), auth), m_socket(NULL),
+ m_authentified(false), m_extendedSMTP(false), m_timeoutHandler(NULL)
+{
+}
+
+
+SMTPTransport::~SMTPTransport()
+{
+ if (isConnected())
+ disconnect();
+ else if (m_socket)
+ internalDisconnect();
+}
+
+
+const string SMTPTransport::protocolName() const
+{
+ return "smtp";
+}
+
+
+void SMTPTransport::connect()
+{
+ if (isConnected())
+ throw exceptions::already_connected();
+
+ const string address = session().properties()[sm_infos.propertyPrefix() + "server.address"];
+ const port_t port = session().properties().get(sm_infos.propertyPrefix() + "server.port", sm_infos.defaultPort());
+
+ // Create the time-out handler
+ if (session().properties().exists
+ (sm_infos.propertyPrefix() + "timeout.factory"))
+ {
+ timeoutHandlerFactory* tof = platformDependant::getHandler()->
+ getTimeoutHandlerFactory(session().properties()
+ [sm_infos.propertyPrefix() + "timeout.factory"]);
+
+ m_timeoutHandler = tof->create();
+ }
+
+ // Create and connect the socket
+ socketFactory* sf = platformDependant::getHandler()->getSocketFactory
+ (session().properties().get(sm_infos.propertyPrefix() + "server.socket-factory", string("default")));
+
+ m_socket = sf->create();
+ m_socket->connect(address, port);
+
+ // Connection
+ //
+ // eg: C: <connection to server>
+ // --- S: 220 smtp.domain.com Service ready
+
+ string response;
+ readResponse(response);
+
+ if (responseCode(response) != 220)
+ {
+ internalDisconnect();
+ throw exceptions::connection_greeting_error(response);
+ }
+
+ // Identification
+ // First, try Extended SMTP (ESMTP)
+ //
+ // eg: C: EHLO thismachine.ourdomain.com
+ // S: 250 OK
+
+ sendRequest("EHLO " + platformDependant::getHandler()->getHostName());
+ readResponse(response);
+
+ if (responseCode(response) != 250)
+ {
+ // Next, try "Basic" SMTP
+ //
+ // eg: C: HELO thismachine.ourdomain.com
+ // S: 250 OK
+
+ sendRequest("HELO " + platformDependant::getHandler()->getHostName());
+ readResponse(response);
+
+ if (responseCode(response) != 250)
+ {
+ internalDisconnect();
+ throw exceptions::connection_greeting_error(response);
+ }
+
+ m_extendedSMTP = false;
+ }
+ else
+ {
+ m_extendedSMTP = true;
+ }
+
+ // Authentication
+ if (session().properties().get
+ (sm_infos.propertyPrefix() + "options.need-authentication", false) == true)
+ {
+ if (!m_extendedSMTP)
+ {
+ internalDisconnect();
+ throw exceptions::command_error("AUTH", "ESMTP not supported.");
+ }
+
+ const authenticationInfos auth = authenticator().requestAuthInfos();
+ bool authentified = false;
+
+ enum AuthMethods
+ {
+ First = 0,
+ CRAM_MD5 = First,
+ // TODO: more authentication methods...
+ End
+ };
+
+ for (int currentMethod = First ; !authentified ; ++currentMethod)
+ {
+ switch (currentMethod)
+ {
+ case CRAM_MD5:
+ {
+ sendRequest("AUTH CRAM-MD5");
+ readResponse(response);
+
+ if (responseCode(response) == 334)
+ {
+ encoderB64 base64;
+
+ string challengeB64 = responseText(response);
+ string challenge, challengeHex;
+
+ {
+ utility::inputStreamStringAdapter in(challengeB64);
+ utility::outputStreamStringAdapter out(challenge);
+
+ base64.decode(in, out);
+ }
+
+ hmac_md5(challenge, auth.password(), challengeHex);
+
+ string decoded = auth.username() + " " + challengeHex;
+ string encoded;
+
+ {
+ utility::inputStreamStringAdapter in(decoded);
+ utility::outputStreamStringAdapter out(encoded);
+
+ base64.encode(in, out);
+ }
+
+ sendRequest(encoded);
+ readResponse(response);
+
+ if (responseCode(response) == 235)
+ {
+ authentified = true;
+ }
+ else
+ {
+ internalDisconnect();
+ throw exceptions::authentication_error(response);
+ }
+ }
+
+ break;
+ }
+ case End:
+ {
+ // All authentication methods have been tried and
+ // the server does not understand any.
+ throw exceptions::authentication_error(response);
+ }
+
+ }
+ }
+ }
+
+ m_authentified = true;
+}
+
+
+const bool SMTPTransport::isConnected() const
+{
+ return (m_socket && m_socket->isConnected() && m_authentified);
+}
+
+
+void SMTPTransport::disconnect()
+{
+ if (!isConnected())
+ throw exceptions::not_connected();
+
+ internalDisconnect();
+}
+
+
+void SMTPTransport::internalDisconnect()
+{
+ sendRequest("QUIT");
+
+ m_socket->disconnect();
+
+ delete (m_socket);
+ m_socket = NULL;
+
+ delete (m_timeoutHandler);
+ m_timeoutHandler = NULL;
+
+ m_authentified = false;
+ m_extendedSMTP = false;
+}
+
+
+void SMTPTransport::noop()
+{
+ m_socket->send("NOOP");
+
+ string response;
+ readResponse(response);
+
+ if (responseCode(response) != 250)
+ throw exceptions::command_error("NOOP", response);
+}
+
+
+static void extractMailboxes
+ (mailboxList& recipients, const addressList& list)
+{
+ for (addressList::const_iterator it = list.begin() ;
+ it != list.end() ; ++it)
+ {
+ recipients.append((*it));
+ }
+}
+
+
+void SMTPTransport::send(vmime::message* msg, progressionListener* progress)
+{
+ // Extract expeditor
+ mailbox expeditor;
+
+ try
+ {
+ const mailboxField& from = dynamic_cast <const mailboxField&>
+ (msg->header().fields.find(headerField::From));
+ expeditor = from.value();
+ }
+ catch (exceptions::no_such_field&)
+ {
+ throw exceptions::no_expeditor();
+ }
+
+ // Extract recipients
+ mailboxList recipients;
+
+ try
+ {
+ const addressListField& to = dynamic_cast <const addressListField&>
+ (msg->header().fields.find(headerField::To));
+ extractMailboxes(recipients, to.value());
+ }
+ catch (exceptions::no_such_field&) { }
+
+ try
+ {
+ const addressListField& cc = dynamic_cast <const addressListField&>
+ (msg->header().fields.find(headerField::Cc));
+ extractMailboxes(recipients, cc.value());
+ }
+ catch (exceptions::no_such_field&) { }
+
+ try
+ {
+ const addressListField& bcc = dynamic_cast <const addressListField&>
+ (msg->header().fields.find(headerField::Bcc));
+ extractMailboxes(recipients, bcc.value());
+ }
+ catch (exceptions::no_such_field&) { }
+
+ // Generate the message, "stream" it and delegate the sending
+ // to the generic send() function.
+ std::ostringstream oss;
+ utility::outputStreamAdapter ossAdapter(oss);
+
+ msg->generate(ossAdapter);
+
+ const string& str(oss.str());
+
+ utility::inputStreamStringAdapter isAdapter(str);
+
+ send(expeditor, recipients, isAdapter, str.length(), progress);
+}
+
+
+void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients,
+ utility::inputStream& is, const utility::stream::size_type size,
+ progressionListener* progress)
+{
+ // If no recipient/expeditor was found, throw an exception
+ if (recipients.empty())
+ throw exceptions::no_recipient();
+ else if (expeditor.empty())
+ throw exceptions::no_expeditor();
+
+ // Emit the "MAIL" command
+ string response;
+
+ sendRequest("MAIL FROM: <" + expeditor.email() + ">");
+ readResponse(response);
+
+ if (responseCode(response) != 250)
+ {
+ internalDisconnect();
+ throw exceptions::command_error("MAIL", response);
+ }
+
+ // Emit a "RCPT TO" command for each recipient
+ for (mailboxList::const_iterator it = recipients.begin() ;
+ it != recipients.end() ; ++it)
+ {
+ sendRequest("RCPT TO: <" + (*it).email() + ">");
+ readResponse(response);
+
+ if (responseCode(response) != 250)
+ {
+ internalDisconnect();
+ throw exceptions::command_error("RCPT TO", response);
+ }
+ }
+
+ // Send the message data
+ sendRequest("DATA");
+ readResponse(response);
+
+ if (responseCode(response) != 354)
+ {
+ internalDisconnect();
+ throw exceptions::command_error("DATA", response);
+ }
+
+ int current = 0, total = size;
+
+ if (progress)
+ progress->start(total);
+
+ char buffer[65536];
+
+ while (!is.eof())
+ {
+ const int read = is.read(buffer, sizeof(buffer));
+
+ // Transform '.' into '..' at the beginning of a line
+ char* start = buffer;
+ char* end = buffer + read;
+ char* pos = buffer;
+
+ while ((pos = std::find(pos, end, '.')) != end)
+ {
+ if (pos > buffer && *(pos - 1) == '\n')
+ {
+ m_socket->sendRaw(start, pos - start);
+ m_socket->sendRaw(".", 1);
+
+ start = pos;
+ }
+
+ ++pos;
+ }
+
+ // Send the remaining data
+ m_socket->sendRaw(start, end - start);
+
+ current += read;
+
+ // Notify progression
+ if (progress)
+ {
+ total = std::max(total, current);
+ progress->progress(current, total);
+ }
+ }
+
+ if (progress)
+ progress->stop(total);
+
+ m_socket->sendRaw("\r\n.\r\n", 5);
+ readResponse(response);
+
+ if (responseCode(response) != 250)
+ {
+ internalDisconnect();
+ throw exceptions::command_error("DATA", response);
+ }
+}
+
+
+void SMTPTransport::sendRequest(const string& buffer, const bool end)
+{
+ m_socket->send(buffer);
+ if (end) m_socket->send("\r\n");
+}
+
+
+const int SMTPTransport::responseCode(const string& response)
+{
+ int code = 0;
+
+ if (response.length() >= 3)
+ {
+ code = (response[0] - '0') * 100
+ + (response[1] - '0') * 10
+ + (response[2] - '0');
+ }
+
+ return (code);
+}
+
+
+const string SMTPTransport::responseText(const string& response)
+{
+ string text;
+
+ std::istringstream iss(response);
+ std::string line;
+
+ while (std::getline(iss, line))
+ {
+ if (line.length() >= 4)
+ text += line.substr(4);
+ else
+ text += line;
+
+ text += "\n";
+ }
+
+ return (text);
+}
+
+
+void SMTPTransport::readResponse(string& buffer)
+{
+ bool foundTerminator = false;
+
+ buffer.clear();
+
+ for ( ; !foundTerminator ; )
+ {
+ // Check whether the time-out delay is elapsed
+ if (m_timeoutHandler && m_timeoutHandler->isTimeOut())
+ {
+ if (!m_timeoutHandler->handleTimeOut())
+ throw exceptions::operation_timed_out();
+ }
+
+ // Receive data from the socket
+ string receiveBuffer;
+ m_socket->receive(receiveBuffer);
+
+ if (receiveBuffer.empty()) // buffer is empty
+ {
+ platformDependant::getHandler()->wait();
+ continue;
+ }
+
+ // We have received data: reset the time-out counter
+ if (m_timeoutHandler)
+ m_timeoutHandler->resetTimeOut();
+
+ // Append the data to the response buffer
+ buffer += receiveBuffer;
+
+ // Check for terminator string (and strip it if present)
+ if (buffer.length() >= 2 && buffer[buffer.length() - 1] == '\n')
+ {
+ string::size_type p = buffer.length() - 2;
+ bool end = false;
+
+ for ( ; !end ; --p)
+ {
+ if (p == 0 || buffer[p] == '\n')
+ {
+ end = true;
+
+ if (p + 4 < buffer.length())
+ foundTerminator = true;
+ }
+ }
+ }
+ }
+
+ // Remove [CR]LF at the end of the response
+ if (buffer.length() >= 2 && buffer[buffer.length() - 1] == '\n')
+ {
+ if (buffer[buffer.length() - 2] == '\r')
+ buffer.resize(buffer.length() - 2);
+ else
+ buffer.resize(buffer.length() - 1);
+ }
+}
+
+
+
+// Service infos
+
+SMTPTransport::_infos SMTPTransport::sm_infos;
+
+
+const port_t SMTPTransport::_infos::defaultPort() const
+{
+ return (25);
+}
+
+
+const string SMTPTransport::_infos::propertyPrefix() const
+{
+ return "transport.smtp.";
+}
+
+
+const std::vector <string> SMTPTransport::_infos::availableProperties() const
+{
+ std::vector <string> list;
+
+ // SMTP-specific options
+ list.push_back("options.need-authentication");
+
+ // Common properties
+ list.push_back("auth.username");
+ list.push_back("auth.password");
+
+ list.push_back("server.address");
+ list.push_back("server.port");
+ list.push_back("server.socket-factory");
+
+ list.push_back("timeout.factory");
+
+ return (list);
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/SMTPTransport.hpp b/src/messaging/SMTPTransport.hpp
new file mode 100644
index 00000000..fa5abfcf
--- /dev/null
+++ b/src/messaging/SMTPTransport.hpp
@@ -0,0 +1,95 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_SMTPTRANSPORT_HPP_INCLUDED
+#define VMIME_MESSAGING_SMTPTRANSPORT_HPP_INCLUDED
+
+
+#include "transport.hpp"
+#include "socket.hpp"
+#include "../config.hpp"
+#include "timeoutHandler.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+/** SMTP transport service.
+ */
+
+class SMTPTransport : public transport
+{
+public:
+
+ SMTPTransport(class session& sess, class authenticator* auth);
+ ~SMTPTransport();
+
+ const string protocolName() const;
+
+ static const serviceInfos& infosInstance() { return (sm_infos); }
+ const serviceInfos& infos() const { return (sm_infos); }
+
+ void connect();
+ const bool isConnected() const;
+ void disconnect();
+
+ void noop();
+
+ void send(vmime::message* msg, progressionListener* progress = NULL);
+ void send(const mailbox& expeditor, const mailboxList& recipients, utility::inputStream& is, const utility::stream::size_type size, progressionListener* progress = NULL);
+
+private:
+
+ static const int responseCode(const string& response);
+ static const string responseText(const string& response);
+
+ void sendRequest(const string& buffer, const bool end = true);
+
+ void readResponse(string& buffer);
+
+ void internalDisconnect();
+
+ socket* m_socket;
+ bool m_authentified;
+ bool m_extendedSMTP;
+
+ timeoutHandler* m_timeoutHandler;
+
+
+ // Service infos
+ class _infos : public serviceInfos
+ {
+ public:
+
+ const port_t defaultPort() const;
+
+ const string propertyPrefix() const;
+ const std::vector <string> availableProperties() const;
+ };
+
+ static _infos sm_infos;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_SMTPTRANSPORT_HPP_INCLUDED
diff --git a/src/messaging/authHelper.cpp b/src/messaging/authHelper.cpp
new file mode 100644
index 00000000..05c77d8a
--- /dev/null
+++ b/src/messaging/authHelper.cpp
@@ -0,0 +1,105 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "authHelper.hpp"
+
+#include "../config.hpp"
+#include "../utility/md5.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+//
+// This code is based on the Sample Code published in the Appendix of
+// the RFC-2104: "HMAC: Keyed-Hashing for Message Authentication".
+//
+
+void hmac_md5(const string& text, const string& key, string& hexDigest)
+{
+ vmime_uint8 digest[16];
+
+ unsigned char ipad[65]; // inner padding - key XORd with ipad
+ unsigned char opad[65]; // outer padding - key XORd with opad
+
+ unsigned char tkey[16];
+ int tkeyLen;
+
+ // If key is longer than 64 bytes reset it to key = MD5(key)
+ if (key.length() > 64)
+ {
+ utility::md5 keyMD5;
+ keyMD5.update((vmime_uint8*) key.data(), key.length());
+
+ std::copy(keyMD5.hash(), keyMD5.hash() + 16, tkey);
+ tkeyLen = 16;
+ }
+ else
+ {
+ std::copy(key.begin(), key.end(), tkey);
+ tkeyLen = key.length();
+ }
+
+ //
+ // the HMAC_MD5 transform looks like:
+ //
+ // MD5(K XOR opad, MD5(K XOR ipad, text))
+ //
+ // where K is an n byte key
+ // ipad is the byte 0x36 repeated 64 times
+ //
+ // opad is the byte 0x5c repeated 64 times
+ // and text is the data being protected
+ //
+
+ // Start out by storing key in pads
+ std::fill(ipad, ipad + sizeof(ipad), 0);
+ std::fill(opad, opad + sizeof(opad), 0);
+
+ std::copy(tkey, tkey + tkeyLen, ipad);
+ std::copy(tkey, tkey + tkeyLen, opad);
+
+ // XOR key with ipad and opad values
+ for (int i = 0 ; i < 64 ; ++i)
+ {
+ ipad[i] ^= 0x36;
+ opad[i] ^= 0x5c;
+ }
+
+ // Perform inner MD5
+ utility::md5 innerMD5;
+ innerMD5.update(ipad, 64);
+ innerMD5.update(text);
+
+ std::copy(innerMD5.hash(), innerMD5.hash() + 16, digest);
+
+ // Perform outer MD5
+ utility::md5 outerMD5;
+ outerMD5.update(opad, 64);
+ outerMD5.update(digest, 16);
+
+ //std::copy(outerMD5.hash(), outerMD5.hash() + 16, digest);
+
+ hexDigest = outerMD5.hex();
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/authHelper.hpp b/src/messaging/authHelper.hpp
new file mode 100644
index 00000000..1fad3ced
--- /dev/null
+++ b/src/messaging/authHelper.hpp
@@ -0,0 +1,38 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_AUTHHELPER_HPP_INCLUDED
+#define VMIME_MESSAGING_AUTHHELPER_HPP_INCLUDED
+
+
+#include "../types.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+void hmac_md5(const string& text, const string& key, string& hexDigest);
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_AUTHHELPER_HPP_INCLUDED
diff --git a/src/messaging/authenticationInfos.cpp b/src/messaging/authenticationInfos.cpp
new file mode 100644
index 00000000..3c5acca7
--- /dev/null
+++ b/src/messaging/authenticationInfos.cpp
@@ -0,0 +1,40 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "authenticationInfos.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+authenticationInfos::authenticationInfos(const string& username, const string& password)
+ : m_username(username), m_password(password)
+{
+}
+
+
+authenticationInfos::authenticationInfos(const authenticationInfos& infos)
+ : m_username(infos.m_username), m_password(infos.m_password)
+{
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/authenticationInfos.hpp b/src/messaging/authenticationInfos.hpp
new file mode 100644
index 00000000..fd2da2fa
--- /dev/null
+++ b/src/messaging/authenticationInfos.hpp
@@ -0,0 +1,64 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_AUTHENTICATIONINFOS_HPP_INCLUDED
+#define VMIME_MESSAGING_AUTHENTICATIONINFOS_HPP_INCLUDED
+
+
+#include "../types.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+/** This class encapsulates user credentials.
+ */
+
+class authenticationInfos
+{
+public:
+
+ authenticationInfos(const string& username, const string& password);
+ authenticationInfos(const authenticationInfos& infos);
+
+ /** Return the user account name.
+ *
+ * @return account name
+ */
+ const string& username() const { return (m_username); }
+
+ /** Return the user account password.
+ *
+ * @return account password
+ */
+ const string& password() const { return (m_password); }
+
+private:
+
+ string m_username;
+ string m_password;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_AUTHENTICATIONINFOS_HPP_INCLUDED
diff --git a/src/messaging/authenticator.cpp b/src/messaging/authenticator.cpp
new file mode 100644
index 00000000..91e488f8
--- /dev/null
+++ b/src/messaging/authenticator.cpp
@@ -0,0 +1,33 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "authenticator.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+authenticator::~authenticator()
+{
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/authenticator.hpp b/src/messaging/authenticator.hpp
new file mode 100644
index 00000000..2faed34c
--- /dev/null
+++ b/src/messaging/authenticator.hpp
@@ -0,0 +1,53 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_AUTHENTICATOR_HPP_INCLUDED
+#define VMIME_MESSAGING_AUTHENTICATOR_HPP_INCLUDED
+
+
+#include "authenticationInfos.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+/** This class is used to obtain user credentials.
+ */
+
+class authenticator
+{
+public:
+
+ virtual ~authenticator();
+
+ /** Called when the service needs to retrieve user credentials.
+ * It should return the user account name and password.
+ *
+ * @return user credentials (user name and password)
+ */
+ virtual const authenticationInfos requestAuthInfos() const = 0;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_AUTHENTICATOR_HPP_INCLUDED
diff --git a/src/messaging/builtinServices.inl b/src/messaging/builtinServices.inl
new file mode 100644
index 00000000..f1934ff9
--- /dev/null
+++ b/src/messaging/builtinServices.inl
@@ -0,0 +1,46 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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.
+//
+
+#define REGISTER_SERVICE(p_class, p_name) \
+ vmime::messaging::service::initializer <vmime::messaging::p_class> p_name(#p_name)
+
+
+#if VMIME_BUILTIN_MESSAGING_PROTO_POP3
+ #include "POP3Store.hpp"
+ REGISTER_SERVICE(POP3Store, pop3);
+#endif
+
+
+#if VMIME_BUILTIN_MESSAGING_PROTO_SMTP
+ #include "SMTPTransport.hpp"
+ REGISTER_SERVICE(SMTPTransport, smtp);
+#endif
+
+
+#if VMIME_BUILTIN_MESSAGING_PROTO_IMAP
+ #include "IMAPStore.hpp"
+ REGISTER_SERVICE(IMAPStore, imap);
+#endif
+
+
+#if VMIME_BUILTIN_MESSAGING_PROTO_MAILDIR
+ #include "maildirStore.hpp"
+ REGISTER_SERVICE(maildirStore, maildir);
+#endif
+
diff --git a/src/messaging/defaultAuthenticator.cpp b/src/messaging/defaultAuthenticator.cpp
new file mode 100644
index 00000000..c69b8c3e
--- /dev/null
+++ b/src/messaging/defaultAuthenticator.cpp
@@ -0,0 +1,41 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "defaultAuthenticator.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+defaultAuthenticator::defaultAuthenticator(const propertySet& props, const string& prefix)
+ : m_props(props), m_prefix(prefix)
+{
+}
+
+
+const authenticationInfos defaultAuthenticator::requestAuthInfos() const
+{
+ return (authenticationInfos
+ (m_props[m_prefix + "auth.username"], m_props[m_prefix + "auth.password"]));
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/defaultAuthenticator.hpp b/src/messaging/defaultAuthenticator.hpp
new file mode 100644
index 00000000..9480ec56
--- /dev/null
+++ b/src/messaging/defaultAuthenticator.hpp
@@ -0,0 +1,55 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_DEFAULTAUTHENTICATOR_HPP_INCLUDED
+#define VMIME_MESSAGING_DEFAULTAUTHENTICATOR_HPP_INCLUDED
+
+
+#include "authenticator.hpp"
+#include "../propertySet.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+/** An auhenticator that simply returns the credentials set in the
+ * session properties (named 'username' and 'password').
+ */
+
+class defaultAuthenticator : public authenticator
+{
+public:
+
+ defaultAuthenticator(const propertySet& props, const string& prefix);
+
+private:
+
+ const propertySet& m_props;
+ const string m_prefix;
+
+ const authenticationInfos requestAuthInfos() const;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_DEFAULTAUTHENTICATOR_HPP_INCLUDED
diff --git a/src/messaging/events.cpp b/src/messaging/events.cpp
new file mode 100644
index 00000000..d117cc82
--- /dev/null
+++ b/src/messaging/events.cpp
@@ -0,0 +1,110 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "events.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace messaging {
+namespace events {
+
+
+//
+// messageCountEvent
+//
+
+messageCountEvent::messageCountEvent
+ (class folder* folder, const Types type, const std::vector <int>& nums)
+ : m_folder(folder), m_type(type)
+{
+ m_nums.resize(nums.size());
+ std::copy(nums.begin(), nums.end(), m_nums.begin());
+}
+
+
+const folder* messageCountEvent::folder() const { return (const_cast <class folder*>(m_folder)); }
+const messageCountEvent::Types messageCountEvent::type() const { return (m_type); }
+const std::vector <int>& messageCountEvent::numbers() const { return (m_nums); }
+
+
+void messageCountEvent::dispatch(messageCountListener* listener) const
+{
+ if (m_type == TYPE_ADDED)
+ listener->messagesAdded(*this);
+ else
+ listener->messagesRemoved(*this);
+}
+
+
+//
+// messageChangedEvent
+//
+
+messageChangedEvent::messageChangedEvent
+ (class folder* folder, const Types type, const std::vector <int>& nums)
+ : m_folder(folder), m_type(type)
+{
+ m_nums.resize(nums.size());
+ std::copy(nums.begin(), nums.end(), m_nums.begin());
+}
+
+
+const folder* messageChangedEvent::folder() const { return (const_cast <class folder*>(m_folder)); }
+const messageChangedEvent::Types messageChangedEvent::type() const { return (m_type); }
+const std::vector <int>& messageChangedEvent::numbers() const { return (m_nums); }
+
+
+void messageChangedEvent::dispatch(messageChangedListener* listener) const
+{
+ listener->messageChanged(*this);
+}
+
+
+//
+// folderEvent
+//
+
+folderEvent::folderEvent
+ (class folder* folder, const Types type,
+ const utility::path& oldPath, const utility::path& newPath)
+ : m_folder(folder), m_type(type), m_oldPath(oldPath), m_newPath(newPath)
+{
+}
+
+
+const class folder* folderEvent::folder() const { return (m_folder); }
+const folderEvent::Types folderEvent::type() const { return (m_type); }
+
+
+void folderEvent::dispatch(class folderListener* listener) const
+{
+ switch (m_type)
+ {
+ case TYPE_CREATED: listener->folderCreated(*this); break;
+ case TYPE_RENAMED: listener->folderRenamed(*this); break;
+ case TYPE_DELETED: listener->folderDeleted(*this); break;
+ }
+}
+
+
+} // events
+} // messaging
+} // vmime
diff --git a/src/messaging/events.hpp b/src/messaging/events.hpp
new file mode 100644
index 00000000..d51ca2d0
--- /dev/null
+++ b/src/messaging/events.hpp
@@ -0,0 +1,174 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_EVENTS_HPP_INCLUDED
+#define VMIME_MESSAGING_EVENTS_HPP_INCLUDED
+
+
+#include <vector>
+
+#include "../utility/path.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+class folder;
+
+namespace events {
+
+
+//
+// messageCountEvent
+//
+
+class messageCountEvent
+{
+public:
+
+ enum Types
+ {
+ TYPE_ADDED, // new messages
+ TYPE_REMOVED // expunged messages: renumbering
+ };
+
+
+ messageCountEvent(class folder* folder, const Types type, const std::vector <int>& nums);
+
+ const class folder* folder() const;
+ const Types type() const;
+ const std::vector <int>& numbers() const;
+
+ void dispatch(class messageCountListener* listener) const;
+
+private:
+
+ class folder* m_folder;
+ const Types m_type;
+ std::vector <int> m_nums;
+};
+
+
+class messageCountListener
+{
+protected:
+
+ virtual ~messageCountListener() { }
+
+public:
+
+ virtual void messagesAdded(const messageCountEvent& event) = 0;
+ virtual void messagesRemoved(const messageCountEvent& event) = 0;
+};
+
+
+//
+// messageChangedEvent
+//
+
+class messageChangedEvent
+{
+public:
+
+ enum Types
+ {
+ TYPE_FLAGS // flags changed
+ };
+
+
+ messageChangedEvent(class folder* folder, const Types type, const std::vector <int>& nums);
+
+ const class folder* folder() const;
+ const Types type() const;
+ const std::vector <int>& numbers() const;
+
+ void dispatch(class messageChangedListener* listener) const;
+
+private:
+
+ class folder* m_folder;
+ const Types m_type;
+ std::vector <int> m_nums;
+};
+
+
+class messageChangedListener
+{
+protected:
+
+ virtual ~messageChangedListener() { }
+
+public:
+
+ virtual void messageChanged(const messageChangedEvent& event) = 0;
+};
+
+
+//
+// folderEvent
+//
+
+class folderEvent
+{
+public:
+
+ enum Types
+ {
+ TYPE_CREATED, // a folder was created
+ TYPE_DELETED, // a folder was deleted
+ TYPE_RENAMED // a folder was renamed
+ };
+
+
+ folderEvent(class folder* folder, const Types type, const utility::path& oldPath, const utility::path& newPath);
+
+ const class folder* folder() const;
+ const Types type() const;
+
+ void dispatch(class folderListener* listener) const;
+
+private:
+
+ class folder* m_folder;
+ const Types m_type;
+ const utility::path m_oldPath;
+ const utility::path m_newPath;
+};
+
+
+class folderListener
+{
+protected:
+
+ virtual ~folderListener() { }
+
+public:
+
+ virtual void folderCreated(const folderEvent& event) = 0;
+ virtual void folderRenamed(const folderEvent& event) = 0;
+ virtual void folderDeleted(const folderEvent& event) = 0;
+};
+
+
+} // events
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_EVENTS_HPP_INCLUDED
diff --git a/src/messaging/folder.cpp b/src/messaging/folder.cpp
new file mode 100644
index 00000000..e508389c
--- /dev/null
+++ b/src/messaging/folder.cpp
@@ -0,0 +1,96 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "folder.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace messaging {
+
+
+void folder::addMessageChangedListener(events::messageChangedListener* l)
+{
+ m_messageChangedListeners.push_back(l);
+}
+
+
+void folder::removeMessageChangedListener(events::messageChangedListener* l)
+{
+ std::remove(m_messageChangedListeners.begin(), m_messageChangedListeners.end(), l);
+}
+
+
+void folder::notifyMessageChanged(const events::messageChangedEvent& event)
+{
+ for (std::list <events::messageChangedListener*>::iterator
+ it = m_messageChangedListeners.begin() ; it != m_messageChangedListeners.end() ; ++it)
+ {
+ event.dispatch(*it);
+ }
+}
+
+
+void folder::addMessageCountListener(events::messageCountListener* l)
+{
+ m_messageCountListeners.push_back(l);
+}
+
+
+void folder::removeMessageCountListener(events::messageCountListener* l)
+{
+ std::remove(m_messageCountListeners.begin(), m_messageCountListeners.end(), l);
+}
+
+
+void folder::notifyMessageCount(const events::messageCountEvent& event)
+{
+ for (std::list <events::messageCountListener*>::iterator
+ it = m_messageCountListeners.begin() ; it != m_messageCountListeners.end() ; ++it)
+ {
+ event.dispatch(*it);
+ }
+}
+
+
+void folder::addFolderListener(events::folderListener* l)
+{
+ m_folderListeners.push_back(l);
+}
+
+
+void folder::removeFolderListener(events::folderListener* l)
+{
+ std::remove(m_folderListeners.begin(), m_folderListeners.end(), l);
+}
+
+
+void folder::notifyFolder(const events::folderEvent& event)
+{
+ for (std::list <events::folderListener*>::iterator
+ it = m_folderListeners.begin() ; it != m_folderListeners.end() ; ++it)
+ {
+ event.dispatch(*it);
+ }
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/folder.hpp b/src/messaging/folder.hpp
new file mode 100644
index 00000000..574ac1b0
--- /dev/null
+++ b/src/messaging/folder.hpp
@@ -0,0 +1,373 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_FOLDER_HPP_INCLUDED
+#define VMIME_MESSAGING_FOLDER_HPP_INCLUDED
+
+
+#include <vector>
+
+#include "../types.hpp"
+#include "../dateTime.hpp"
+#include "progressionListener.hpp"
+#include "message.hpp"
+#include "../message.hpp"
+#include "events.hpp"
+#include "../utility/path.hpp"
+#include "../utility/stream.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+/** Abstract representation of a folder in a message store.
+ */
+
+class folder
+{
+protected:
+
+ folder(const folder&) { }
+ folder() { }
+
+public:
+
+ virtual ~folder() { }
+
+ /** Type used for fully qualified path name of a folder.
+ */
+ typedef vmime::utility::path path;
+
+
+ /** Open mode.
+ */
+ enum Modes
+ {
+ MODE_READ_ONLY, /**< Read-only mode (no modification to folder or messages is possible). */
+ MODE_READ_WRITE /**< Full access mode (read and write). */
+ };
+
+ /** Folder types.
+ */
+ enum Types
+ {
+ TYPE_CONTAINS_FOLDERS = (1 << 0), /**< Folder can contain folders. */
+ TYPE_CONTAINS_MESSAGES = (1 << 1), /**< Folder can contain messages. */
+
+ TYPE_UNDEFINED = 9999 /**< Used internally (this should not be returned
+ by the type() function). */
+ };
+
+ /** Folder flags.
+ */
+ enum Flags
+ {
+ FLAG_CHILDREN = (1 << 0), /**< Folder contains subfolders. */
+ FLAG_NO_OPEN = (1 << 1), /**< Folder cannot be open. */
+
+ FLAG_UNDEFINED = 9999 /**< Used internally (this should not be returned
+ by the type() function). */
+ };
+
+ /** Return the type of this folder.
+ *
+ * @return folder type (see folder::Types)
+ */
+ virtual const int type() = 0;
+
+ /** Return the flags of this folder.
+ *
+ * @return folder flags (see folder::Flags)
+ */
+ virtual const int flags() = 0;
+
+ /** Return the mode in which the folder has been open.
+ *
+ * @return folder opening mode (see folder::Modes)
+ */
+ virtual const int mode() const = 0;
+
+ /** Return the name of this folder.
+ *
+ * @return folder name
+ */
+ virtual const folder::path::component name() const = 0;
+
+ /** Return the fully qualified path name of this folder.
+ *
+ * @return absolute path of the folder
+ */
+ virtual const folder::path fullPath() const = 0;
+
+ /** Open this folder.
+ *
+ * @param mode open mode (see folder::Modes)
+ * @param failIfModeIsNotAvailable if set to false and if the requested mode
+ * is not available, a more restricted mode will be selected automatically.
+ * If set to true and if the requested mode is not available, the opening
+ * will fail.
+ */
+ virtual void open(const int mode, bool failIfModeIsNotAvailable = false) = 0;
+
+ /** Close this folder.
+ *
+ * @param expunge if set to true, deleted messages are expunged
+ */
+ virtual void close(const bool expunge) = 0;
+
+ /** Create this folder.
+ *
+ * @param type folder type (see folder::Types)
+ */
+ virtual void create(const int type) = 0;
+
+ /** Test whether this folder exists.
+ *
+ * @return true if the folder exists, false otherwise
+ */
+ virtual const bool exists() = 0;
+
+ /** Test whether this folder is open.
+ *
+ * @return true if the folder is open, false otherwise
+ */
+ virtual const bool isOpen() const = 0;
+
+ /** Get a new reference to a message in this folder.
+ *
+ * @param num message sequence number
+ * @return a new object referencing the specified message
+ */
+ virtual message* getMessage(const int num) = 0;
+
+ /** Get new references to messages in this folder.
+ *
+ * @param from sequence number of the first message to get
+ * @param to sequence number of the last message to get
+ * @return new objects referencing the specified messages
+ */
+ virtual std::vector <message*> getMessages(const int from = 1, const int to = -1) = 0;
+
+ /** Get new references to messages in this folder.
+ *
+ * @param nums sequence numbers of the messages to delete
+ * @return new objects referencing the specified messages
+ */
+ virtual std::vector <message*> getMessages(const std::vector <int>& nums) = 0;
+
+ /** Return the number of messages in this folder.
+ *
+ * @return number of messages in the folder
+ */
+ virtual const int getMessageCount() = 0;
+
+ /** Get a new reference to a sub-folder in this folder.
+ *
+ * @param name sub-folder name
+ * @return a new object referencing the specified folder
+ */
+ virtual folder* getFolder(const folder::path::component& name) = 0;
+
+ /** Get the list of all sub-folders in this folder.
+ *
+ * @param recursive if set to true, all the descendant are returned.
+ * If set to false, only the direct children are returned.
+ * @return list of sub-folders
+ */
+ virtual std::vector <folder*> getFolders(const bool recursive = false) = 0;
+
+ /** Rename (move) this folder to another location.
+ *
+ * @param newPath new path of the folder
+ */
+ virtual void rename(const folder::path& newPath) = 0;
+
+ /** Remove a message in this folder.
+ *
+ * @param num sequence number of the message to delete
+ */
+ virtual void deleteMessage(const int num) = 0;
+
+ /** Remove one or more messages from this folder.
+ *
+ * @param from sequence number of the first message to delete
+ * @param to sequence number of the last message to delete
+ */
+ virtual void deleteMessages(const int from = 1, const int to = -1) = 0;
+
+ /** Remove one or more messages from this folder.
+ *
+ * @param nums sequence numbers of the messages to delete
+ */
+ virtual void deleteMessages(const std::vector <int>& nums) = 0;
+
+ /** Change the flags for one or more messages in this folder.
+ *
+ * @param from sequence number of the first message to modify
+ * @param to sequence number of the last message to modify
+ * @param flags set of flags (see message::Flags)
+ * @param mode indicate how to treat old and new flags (see message::FlagsModes)
+ */
+ virtual void setMessageFlags(const int from, const int to, const int flags, const int mode = message::FLAG_MODE_SET) = 0;
+
+ /** Change the flags for one or more messages in this folder.
+ *
+ * @param nums sequence numbers of the messages to modify
+ * @param flags set of flags (see message::Flags)
+ * @param mode indicate how to treat old and new flags (see message::FlagsModes)
+ */
+ virtual void setMessageFlags(const std::vector <int>& nums, const int flags, const int mode = message::FLAG_MODE_SET) = 0;
+
+ /** Add a message to this folder.
+ *
+ * @param msg message to add (data: header + body)
+ * @param flags flags for the new message
+ * @param date date/time for the new message (if NULL, the current time is used)
+ * @param progress progression listener, or NULL if not used
+ */
+ virtual void addMessage(vmime::message* msg, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, progressionListener* progress = NULL) = 0;
+
+ /** Add a message to this folder.
+ *
+ * @param is message to add (data: header + body)
+ * @param size size of the message to add (in bytes)
+ * @param flags flags for the new message
+ * @param date date/time for the new message (if NULL, the current time is used)
+ * @param progress progression listener, or NULL if not used
+ */
+ virtual void addMessage(utility::inputStream& is, const int size, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, progressionListener* progress = NULL) = 0;
+
+ /** Copy a message from this folder to another folder.
+ *
+ * @param dest destination folder path
+ * @param num sequence number of the message to copy
+ */
+ virtual void copyMessage(const folder::path& dest, const int num) = 0;
+
+ /** Copy messages from this folder to another folder.
+ *
+ * @param dest destination folder path
+ * @param from sequence number of the first message to copy
+ * @param to sequence number of the last message to copy
+ */
+ virtual void copyMessages(const folder::path& dest, const int from = 1, const int to = -1) = 0;
+
+ /** Copy messages from this folder to another folder.
+ *
+ * @param dest destination folder path
+ * @param nums sequence numbers of the messages to copy
+ */
+ virtual void copyMessages(const folder::path& dest, const std::vector <int>& nums) = 0;
+
+ /** Request folder status without opening it.
+ *
+ * @param count will receive the number of messages in the folder
+ * @param unseen will receive the number of unseen messages in the folder
+ */
+ virtual void status(int& count, int& unseen) = 0;
+
+ /** Expunge deleted messages.
+ */
+ virtual void expunge() = 0;
+
+ /** Return a new folder objet referencing the parent folder of this folder.
+ *
+ * @return parent folder object
+ */
+ virtual folder* getParent() = 0;
+
+ /** Return a reference to the store to which this folder belongs.
+ *
+ * @return the store object to which this folder is attached
+ */
+ virtual const class store& store() const = 0;
+
+ /** Return a reference to the store to which this folder belongs.
+ *
+ * @return the store object to which this folder is attached
+ */
+ virtual class store& store() = 0;
+
+ /** Possible fetchable objects.
+ */
+ enum FetchOptions
+ {
+ FETCH_ENVELOPE = (1 << 0), /**< Fetch sender, recipients, date, subject. */
+ FETCH_STRUCTURE = (1 << 1), /**< Fetch structure (body parts). */
+ FETCH_CONTENT_INFO = (1 << 2), /**< Fetch top-level content type. */
+ FETCH_FLAGS = (1 << 3), /**< Fetch message flags. */
+ FETCH_SIZE = (1 << 4), /**< Fetch message size (exact or estimated). */
+ FETCH_FULL_HEADER = (1 << 5), /**< Fetch full RFC-[2]822 header. */
+ FETCH_UID = (1 << 6), /**< Fetch unique identifier (protocol specific). */
+
+ FETCH_CUSTOM = (1 << 16) /**< Reserved for future use. */
+ };
+
+ /** Fetch objects for the specified messages.
+ *
+ * @param msg list of message sequence numbers
+ * @param options objects to fetch (combination of folder::FetchOptions flags)
+ * @param progress progression listener, or NULL if not used
+ */
+ virtual void fetchMessages(std::vector <message*>& msg, const int options, progressionListener* progress = NULL) = 0;
+
+ /** Fetch objects for the specified message.
+ *
+ * @param msg the message
+ * @param options objects to fetch (combination of folder::FetchOptions flags)
+ */
+ virtual void fetchMessage(message* msg, const int options) = 0;
+
+ /** Return the list of fetchable objects supported by
+ * the underlying protocol (see folder::FetchOptions).
+ *
+ * @return list of supported fetchable objects
+ */
+ virtual const int getFetchCapabilities() const = 0;
+
+ // Event listeners
+ void addMessageChangedListener(events::messageChangedListener* l);
+ void removeMessageChangedListener(events::messageChangedListener* l);
+
+ void addMessageCountListener(events::messageCountListener* l);
+ void removeMessageCountListener(events::messageCountListener* l);
+
+ void addFolderListener(events::folderListener* l);
+ void removeFolderListener(events::folderListener* l);
+
+protected:
+
+ void notifyMessageChanged(const events::messageChangedEvent& event);
+ void notifyMessageCount(const events::messageCountEvent& event);
+ void notifyFolder(const events::folderEvent& event);
+
+private:
+
+ std::list <events::messageChangedListener*> m_messageChangedListeners;
+ std::list <events::messageCountListener*> m_messageCountListeners;
+ std::list <events::folderListener*> m_folderListeners;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_FOLDER_HPP_INCLUDED
diff --git a/src/messaging/maildirFolder.cpp b/src/messaging/maildirFolder.cpp
new file mode 100644
index 00000000..903de91d
--- /dev/null
+++ b/src/messaging/maildirFolder.cpp
@@ -0,0 +1,552 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "maildirFolder.hpp"
+
+#include "maildirStore.hpp"
+#include "maildirMessage.hpp"
+#include "maildirUtils.hpp"
+
+#include "../exception.hpp"
+#include "../platformDependant.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+maildirFolder::maildirFolder(const folder::path& path, maildirStore* store)
+ : m_store(store), m_path(path), m_name(path.last()), m_mode(-1), m_open(false)
+{
+ m_store->registerFolder(this);
+}
+
+
+maildirFolder::~maildirFolder()
+{
+ if (m_store)
+ {
+ if (m_open)
+ close(false);
+
+ m_store->unregisterFolder(this);
+ }
+ else if (m_open)
+ {
+ close(false);
+ }
+}
+
+
+void maildirFolder::onStoreDisconnected()
+{
+ m_store = NULL;
+}
+
+
+const int maildirFolder::mode() const
+{
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ return (m_mode);
+}
+
+
+const int maildirFolder::type()
+{
+ if (m_path.empty())
+ return (TYPE_CONTAINS_FOLDERS);
+ else
+ return (TYPE_CONTAINS_FOLDERS | TYPE_CONTAINS_MESSAGES);
+}
+
+
+const int maildirFolder::flags()
+{
+ int flags = 0;
+
+ utility::fileSystemFactory* fsf = platformDependant::getHandler()->getFileSystemFactory();
+
+ utility::auto_ptr <utility::file> rootDir = fsf->create
+ (maildirUtils::getFolderFSPath(m_store, m_path, maildirUtils::FOLDER_PATH_CONTAINER));
+
+ utility::auto_ptr <utility::fileIterator> it = rootDir->getFiles();
+
+ while (it->hasMoreElements())
+ {
+ utility::auto_ptr <utility::file> file = it->nextElement();
+
+ if (maildirUtils::isSubfolderDirectory(*file))
+ {
+ flags |= FLAG_CHILDREN; // Contains at least one sub-folder
+ break;
+ }
+ }
+
+ return (flags);
+}
+
+
+const folder::path::component maildirFolder::name() const
+{
+ return (m_name);
+}
+
+
+const folder::path maildirFolder::fullPath() const
+{
+ return (m_path);
+}
+
+
+void maildirFolder::open(const int mode, bool /* failIfModeIsNotAvailable */)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (isOpen())
+ throw exceptions::illegal_state("Folder is already open");
+ else if (!exists())
+ throw exceptions::illegal_state("Folder already exists");
+
+ m_open = true;
+ m_mode = mode;
+}
+
+
+void maildirFolder::close(const bool expunge)
+{
+ // TODO
+}
+
+
+void maildirFolder::onClose()
+{
+ // TODO
+}
+
+
+void maildirFolder::create(const int type)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (isOpen())
+ throw exceptions::illegal_state("Folder is open");
+ else if (exists())
+ throw exceptions::illegal_state("Folder already exists");
+
+ // Folder name cannot start with '.'
+ if (!m_path.empty())
+ {
+ const path::component& comp = m_path.last();
+
+ const int length = comp.buffer().length();
+ int pos = 0;
+
+ while ((pos < length) && (comp.buffer()[pos] == '.'))
+ ++pos;
+
+ if (pos != 0)
+ throw exceptions::invalid_folder_name("Name cannot start with '.'");
+ }
+
+ // Create directory on file system
+ try
+ {
+ utility::fileSystemFactory* fsf = platformDependant::getHandler()->getFileSystemFactory();
+
+ utility::auto_ptr <utility::file> rootDir = fsf->create
+ (maildirUtils::getFolderFSPath(m_store, m_path, maildirUtils::FOLDER_PATH_ROOT));
+
+ utility::auto_ptr <utility::file> newDir = fsf->create
+ (maildirUtils::getFolderFSPath(m_store, m_path, maildirUtils::FOLDER_PATH_NEW));
+ utility::auto_ptr <utility::file> tmpDir = fsf->create
+ (maildirUtils::getFolderFSPath(m_store, m_path, maildirUtils::FOLDER_PATH_TMP));
+ utility::auto_ptr <utility::file> curDir = fsf->create
+ (maildirUtils::getFolderFSPath(m_store, m_path, maildirUtils::FOLDER_PATH_CUR));
+
+ rootDir->createDirectory(true);
+
+ newDir->createDirectory(false);
+ tmpDir->createDirectory(false);
+ curDir->createDirectory(false);
+ }
+ catch (exceptions::filesystem_exception& e)
+ {
+ throw exceptions::command_error("CREATE", e.what(), "File system exception");
+ }
+
+ // Notify folder created
+ events::folderEvent event(this, events::folderEvent::TYPE_CREATED, m_path, m_path);
+ notifyFolder(event);
+}
+
+
+const bool maildirFolder::exists()
+{
+ utility::fileSystemFactory* fsf = platformDependant::getHandler()->getFileSystemFactory();
+
+ utility::auto_ptr <utility::file> rootDir = fsf->create
+ (maildirUtils::getFolderFSPath(m_store, m_path, maildirUtils::FOLDER_PATH_ROOT));
+
+ utility::auto_ptr <utility::file> newDir = fsf->create
+ (maildirUtils::getFolderFSPath(m_store, m_path, maildirUtils::FOLDER_PATH_NEW));
+ utility::auto_ptr <utility::file> tmpDir = fsf->create
+ (maildirUtils::getFolderFSPath(m_store, m_path, maildirUtils::FOLDER_PATH_TMP));
+ utility::auto_ptr <utility::file> curDir = fsf->create
+ (maildirUtils::getFolderFSPath(m_store, m_path, maildirUtils::FOLDER_PATH_CUR));
+
+ return (rootDir->exists() && rootDir->isDirectory() &&
+ newDir->exists() && newDir->isDirectory() &&
+ tmpDir->exists() && tmpDir->isDirectory() &&
+ curDir->exists() && curDir->isDirectory());
+}
+
+
+const bool maildirFolder::isOpen() const
+{
+ return (m_open);
+}
+
+
+void maildirFolder::scanFolder()
+{
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ try
+ {
+ utility::fileSystemFactory* fsf = platformDependant::getHandler()->getFileSystemFactory();
+
+ utility::auto_ptr <utility::file> newDir = fsf->create
+ (maildirUtils::getFolderFSPath(m_store, m_path, maildirUtils::FOLDER_PATH_NEW));
+ utility::auto_ptr <utility::file> curDir = fsf->create
+ (maildirUtils::getFolderFSPath(m_store, m_path, maildirUtils::FOLDER_PATH_CUR));
+
+ // Unread messages (new/)
+ utility::auto_ptr <utility::fileIterator> nit = newDir->getFiles();
+ std::vector <utility::path::component> unreadMessageFilenames;
+
+ while (nit->hasMoreElements())
+ {
+ utility::auto_ptr <utility::file> file = nit->nextElement();
+ unreadMessageFilenames.push_back(file->fullPath().last());
+ }
+
+ // Seen messages (cur/)
+ utility::auto_ptr <utility::fileIterator> cit = curDir->getFiles();
+ std::vector <utility::path::component> messageFilenames;
+
+ while (cit->hasMoreElements())
+ {
+ utility::auto_ptr <utility::file> file = cit->nextElement();
+ messageFilenames.push_back(file->fullPath().last());
+ }
+
+ // TODO: update m_messageFilenames
+ // TODO: what to do with files which name has changed? (flag change, message deletion...)
+
+ m_unreadMessageCount = unreadMessageFilenames.size();
+ m_messageCount = messageFilenames.size();
+ }
+ catch (exceptions::filesystem_exception&)
+ {
+ // Should not happen...
+ }
+
+ /*
+ int m_unreadMessageCount;
+ int m_messageCount;
+
+ std::vector <folder::path::component> m_unreadMessageFilenames;
+ std::vector <folder::path::component> m_messageFilenames;
+
+ if (0)
+ {
+ m_messageFilenames.clear();
+
+ for (...)
+ {
+ m_messageFilenames.push_back(...);
+ }
+ }
+ */
+}
+
+
+message* maildirFolder::getMessage(const int num)
+{
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ if (num < 1 || num > m_messageCount)
+ throw exceptions::message_not_found();
+
+ return new maildirMessage(this, num);
+}
+
+
+std::vector <message*> maildirFolder::getMessages(const int from, const int to)
+{
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ std::vector <message*> v;
+
+ for (int i = from ; i <= to ; ++i)
+ v.push_back(new maildirMessage(this, i));
+
+ return (v);
+}
+
+
+std::vector <message*> maildirFolder::getMessages(const std::vector <int>& nums)
+{
+ if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+
+ std::vector <message*> v;
+
+ for (std::vector <int>::const_iterator it = nums.begin() ; it != nums.end() ; ++it)
+ v.push_back(new maildirMessage(this, *it));
+
+ return (v);
+}
+
+
+const int maildirFolder::getMessageCount()
+{
+ return (m_messageCount);
+}
+
+
+folder* maildirFolder::getFolder(const folder::path::component& name)
+{
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+
+ return new maildirFolder(m_path / name, m_store);
+}
+
+
+std::vector <folder*> maildirFolder::getFolders(const bool recursive)
+{
+ if (!isOpen() && !m_store)
+ throw exceptions::illegal_state("Store disconnected");
+
+ std::vector <folder*> list;
+
+ try
+ {
+ listFolders(list, recursive);
+ }
+ catch (std::exception&)
+ {
+ for (std::vector <folder*>::iterator it = list.begin() ; it != list.end() ; ++it)
+ delete (*it);
+
+ throw;
+ }
+
+ return (list);
+}
+
+
+void maildirFolder::listFolders(std::vector <folder*>& list, const bool recursive)
+{
+ try
+ {
+ utility::fileSystemFactory* fsf = platformDependant::getHandler()->getFileSystemFactory();
+
+ utility::auto_ptr <utility::file> rootDir = fsf->create
+ (maildirUtils::getFolderFSPath(m_store, m_path, maildirUtils::FOLDER_PATH_CONTAINER));
+ utility::auto_ptr <utility::fileIterator> it = rootDir->getFiles();
+
+ while (it->hasMoreElements())
+ {
+ utility::auto_ptr <utility::file> file = it->nextElement();
+
+ if (maildirUtils::isSubfolderDirectory(*file))
+ {
+ const utility::path subPath = m_path / file->fullPath().last();
+ maildirFolder* subFolder = new maildirFolder(subPath, m_store);
+
+ list.push_back(subFolder);
+
+ if (recursive)
+ subFolder->listFolders(list, true);
+ }
+ }
+ }
+ catch (exceptions::filesystem_exception& e)
+ {
+ throw exceptions::command_error("LIST", e.what());
+ }
+}
+
+
+void maildirFolder::rename(const folder::path& newPath)
+{
+ // TODO
+}
+
+
+void maildirFolder::deleteMessage(const int num)
+{
+ // TODO
+}
+
+
+void maildirFolder::deleteMessages(const int from, const int to)
+{
+ // TODO
+}
+
+
+void maildirFolder::deleteMessages(const std::vector <int>& nums)
+{
+ // TODO
+}
+
+
+void maildirFolder::setMessageFlags
+ (const int from, const int to, const int flags, const int mode)
+{
+ // TODO
+}
+
+
+void maildirFolder::setMessageFlags
+ (const std::vector <int>& nums, const int flags, const int mode)
+{
+ // TODO
+}
+
+
+void maildirFolder::addMessage(vmime::message* msg, const int flags,
+ vmime::datetime* date, progressionListener* progress)
+{
+ // TODO
+}
+
+
+void maildirFolder::addMessage(utility::inputStream& is, const int size,
+ const int flags, vmime::datetime* date, progressionListener* progress)
+{
+ // TODO
+}
+
+
+void maildirFolder::copyMessage(const folder::path& dest, const int num)
+{
+ // TODO
+}
+
+
+void maildirFolder::copyMessages(const folder::path& dest, const int from, const int to)
+{
+ // TODO
+}
+
+
+void maildirFolder::copyMessages(const folder::path& dest, const std::vector <int>& nums)
+{
+ // TODO
+}
+
+
+void maildirFolder::status(int& count, int& unseen)
+{
+ const int oldCount = m_messageCount;
+
+ scanFolder();
+
+ count = m_messageCount;
+ unseen = m_unreadMessageCount;
+
+ // Notify message count changed (new messages)
+ if (count > oldCount)
+ {
+ std::vector <int> nums;
+ nums.reserve(count - oldCount);
+
+ for (int i = oldCount + 1, j = 0 ; i <= count ; ++i, ++j)
+ nums[j] = i;
+
+ events::messageCountEvent event(this, events::messageCountEvent::TYPE_ADDED, nums);
+
+ for (std::list <maildirFolder*>::iterator it = m_store->m_folders.begin() ;
+ it != m_store->m_folders.end() ; ++it)
+ {
+ if ((*it)->fullPath() == m_path)
+ {
+ (*it)->m_messageCount = count;
+ (*it)->notifyMessageCount(event);
+ }
+ }
+ }
+}
+
+
+void maildirFolder::expunge()
+{
+ // TODO
+}
+
+
+folder* maildirFolder::getParent()
+{
+ return (m_path.empty() ? NULL : new maildirFolder(m_path.parent(), m_store));
+}
+
+
+const class store& maildirFolder::store() const
+{
+ return (*m_store);
+}
+
+
+class store& maildirFolder::store()
+{
+ return (*m_store);
+}
+
+
+void maildirFolder::fetchMessages(std::vector <message*>& msg,
+ const int options, progressionListener* progress)
+{
+ // TODO
+}
+
+
+void maildirFolder::fetchMessage(message* msg, const int options)
+{
+ // TODO
+}
+
+
+const int maildirFolder::getFetchCapabilities() const
+{
+ return (FETCH_ENVELOPE | FETCH_STRUCTURE | FETCH_CONTENT_INFO |
+ FETCH_FLAGS | FETCH_SIZE | FETCH_FULL_HEADER | FETCH_UID);
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/maildirFolder.hpp b/src/messaging/maildirFolder.hpp
new file mode 100644
index 00000000..37578157
--- /dev/null
+++ b/src/messaging/maildirFolder.hpp
@@ -0,0 +1,144 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_MAILDIRFOLDER_HPP_INCLUDED
+#define VMIME_MESSAGING_MAILDIRFOLDER_HPP_INCLUDED
+
+
+#include <vector>
+#include <map>
+
+#include "../types.hpp"
+#include "folder.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+class maildirStore;
+
+
+/** maildir folder implementation.
+ */
+
+class maildirFolder : public folder
+{
+protected:
+
+ friend class maildirStore;
+ friend class maildirMessage;
+
+
+ maildirFolder(const folder::path& path, maildirStore* store);
+ maildirFolder(const maildirFolder&) : folder() { }
+
+ ~maildirFolder();
+
+public:
+
+ const int mode() const;
+
+ const int type();
+
+ const int flags();
+
+ const folder::path::component name() const;
+ const folder::path fullPath() const;
+
+ void open(const int mode, bool failIfModeIsNotAvailable = false);
+ void close(const bool expunge);
+ void create(const int type);
+
+ const bool exists();
+
+ const bool isOpen() const;
+
+ message* getMessage(const int num);
+ std::vector <message*> getMessages(const int from = 1, const int to = -1);
+ std::vector <message*> getMessages(const std::vector <int>& nums);
+ const int getMessageCount();
+
+ folder* getFolder(const folder::path::component& name);
+ std::vector <folder*> getFolders(const bool recursive = false);
+
+ void rename(const folder::path& newPath);
+
+ void deleteMessage(const int num);
+ void deleteMessages(const int from = 1, const int to = -1);
+ void deleteMessages(const std::vector <int>& nums);
+
+ void setMessageFlags(const int from, const int to, const int flags, const int mode = message::FLAG_MODE_SET);
+ void setMessageFlags(const std::vector <int>& nums, const int flags, const int mode = message::FLAG_MODE_SET);
+
+ void addMessage(vmime::message* msg, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, progressionListener* progress = NULL);
+ void addMessage(utility::inputStream& is, const int size, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, progressionListener* progress = NULL);
+
+ void copyMessage(const folder::path& dest, const int num);
+ void copyMessages(const folder::path& dest, const int from = 1, const int to = -1);
+ void copyMessages(const folder::path& dest, const std::vector <int>& nums);
+
+ void status(int& count, int& unseen);
+
+ void expunge();
+
+ folder* getParent();
+
+ const class store& store() const;
+ class store& store();
+
+
+ void fetchMessages(std::vector <message*>& msg, const int options, progressionListener* progress = NULL);
+ void fetchMessage(message* msg, const int options);
+
+ const int getFetchCapabilities() const;
+
+private:
+
+ maildirStore* m_store;
+
+ folder::path m_path;
+ folder::path::component m_name;
+
+ int m_mode;
+ bool m_open;
+
+ int m_unreadMessageCount;
+ int m_messageCount;
+
+ std::vector <folder::path::component> m_unreadMessageFilenames;
+ std::vector <folder::path::component> m_messageFilenames;
+
+ void scanFolder();
+
+ void listFolders(std::vector <folder*>& list, const bool recursive);
+
+
+
+ void onStoreDisconnected();
+
+ void onClose();
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_MAILDIRFOLDER_HPP_INCLUDED
diff --git a/src/messaging/maildirMessage.cpp b/src/messaging/maildirMessage.cpp
new file mode 100644
index 00000000..c14831c3
--- /dev/null
+++ b/src/messaging/maildirMessage.cpp
@@ -0,0 +1,28 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "maildirMessage.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/maildirMessage.hpp b/src/messaging/maildirMessage.hpp
new file mode 100644
index 00000000..3ea6afbf
--- /dev/null
+++ b/src/messaging/maildirMessage.hpp
@@ -0,0 +1,78 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_MAILDIRMESSAGE_HPP_INCLUDED
+#define VMIME_MESSAGING_MAILDIRMESSAGE_HPP_INCLUDED
+
+
+#include "message.hpp"
+#include "folder.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+class maildirFolder;
+
+
+/** maildir message implementation.
+ */
+
+class maildirMessage : public message
+{
+ friend class maildirFolder;
+
+protected:
+
+ maildirMessage(maildirFolder* folder, const int num);
+ maildirMessage(const maildirMessage&) : message() { }
+
+ ~maildirMessage();
+
+public:
+
+ const int number() const;
+
+ const uid uniqueId() const;
+
+ const int size() const;
+
+ const bool isExpunged() const;
+
+ const class structure& structure() const;
+ class structure& structure();
+
+ const class header& header() const;
+
+ const int flags() const;
+ void setFlags(const int flags, const int mode = FLAG_MODE_SET);
+
+ void extract(utility::outputStream& os, progressionListener* progress = NULL, const int start = 0, const int length = -1) const;
+ void extractPart(const part& p, utility::outputStream& os, progressionListener* progress = NULL, const int start = 0, const int length = -1) const;
+
+ void fetchPartHeader(part& p);
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_MAILDIRMESSAGE_HPP_INCLUDED
diff --git a/src/messaging/maildirStore.cpp b/src/messaging/maildirStore.cpp
new file mode 100644
index 00000000..2e125109
--- /dev/null
+++ b/src/messaging/maildirStore.cpp
@@ -0,0 +1,165 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "maildirStore.hpp"
+
+#include "maildirFolder.hpp"
+
+#include "../exception.hpp"
+#include "../platformDependant.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+maildirStore::maildirStore(class session& sess, class authenticator* auth)
+ : store(sess, infosInstance(), auth), m_connected(false)
+{
+}
+
+
+maildirStore::~maildirStore()
+{
+ if (isConnected())
+ disconnect();
+}
+
+
+const string maildirStore::protocolName() const
+{
+ return "maildir";
+}
+
+
+folder* maildirStore::getRootFolder()
+{
+ if (!isConnected())
+ throw exceptions::illegal_state("Not connected");
+
+ return new maildirFolder(folder::path(), this);
+}
+
+
+folder* maildirStore::getDefaultFolder()
+{
+ if (!isConnected())
+ throw exceptions::illegal_state("Not connected");
+
+ return new maildirFolder(folder::path::component("inbox"), this);
+}
+
+
+folder* maildirStore::getFolder(const folder::path& path)
+{
+ if (!isConnected())
+ throw exceptions::illegal_state("Not connected");
+
+ return new maildirFolder(path, this);
+}
+
+
+void maildirStore::connect()
+{
+ if (isConnected())
+ throw exceptions::already_connected();
+
+ m_fsPath = platformDependant::getHandler()->getFileSystemFactory()->stringToPath
+ (session().properties()[infos().propertyPrefix() + "server.path"]);
+
+ m_connected = true;
+}
+
+
+const bool maildirStore::isConnected() const
+{
+ return (m_connected);
+}
+
+
+void maildirStore::disconnect()
+{
+ for (std::list <maildirFolder*>::iterator it = m_folders.begin() ;
+ it != m_folders.end() ; ++it)
+ {
+ (*it)->onStoreDisconnected();
+ }
+
+ m_folders.clear();
+
+ m_connected = false;
+}
+
+
+void maildirStore::noop()
+{
+ // Nothing to do.
+}
+
+
+void maildirStore::registerFolder(maildirFolder* folder)
+{
+ m_folders.push_back(folder);
+}
+
+
+void maildirStore::unregisterFolder(maildirFolder* folder)
+{
+ std::list <maildirFolder*>::iterator it = std::find(m_folders.begin(), m_folders.end(), folder);
+ if (it != m_folders.end()) m_folders.erase(it);
+}
+
+
+const utility::path& maildirStore::getFileSystemPath() const
+{
+ return (m_fsPath);
+}
+
+
+
+
+// Service infos
+
+maildirStore::_infos maildirStore::sm_infos;
+
+
+const port_t maildirStore::_infos::defaultPort() const
+{
+ return (0);
+}
+
+
+const string maildirStore::_infos::propertyPrefix() const
+{
+ return "store.maildir.";
+}
+
+
+const std::vector <string> maildirStore::_infos::availableProperties() const
+{
+ std::vector <string> list;
+
+ list.push_back("server.path");
+
+ return (list);
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/maildirStore.hpp b/src/messaging/maildirStore.hpp
new file mode 100644
index 00000000..62acb13e
--- /dev/null
+++ b/src/messaging/maildirStore.hpp
@@ -0,0 +1,102 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_MAILDIRSTORE_HPP_INCLUDED
+#define VMIME_MESSAGING_MAILDIRSTORE_HPP_INCLUDED
+
+
+#include "store.hpp"
+#include "socket.hpp"
+#include "folder.hpp"
+#include "../config.hpp"
+
+#include "utility/file.hpp"
+
+#include <ostream>
+
+
+namespace vmime {
+namespace messaging {
+
+
+class maildirFolder;
+
+
+/** maildir store service.
+ */
+
+class maildirStore : public store
+{
+ friend class maildirFolder;
+
+public:
+
+ maildirStore(class session& sess, class authenticator* auth);
+ ~maildirStore();
+
+ const string protocolName() const;
+
+ folder* getDefaultFolder();
+ folder* getRootFolder();
+ folder* getFolder(const folder::path& path);
+
+ static const serviceInfos& infosInstance() { return (sm_infos); }
+ const serviceInfos& infos() const { return (sm_infos); }
+
+ void connect();
+ const bool isConnected() const;
+ void disconnect();
+
+ void noop();
+
+ const utility::path& getFileSystemPath() const;
+
+private:
+
+ void registerFolder(maildirFolder* folder);
+ void unregisterFolder(maildirFolder* folder);
+
+
+ std::list <maildirFolder*> m_folders;
+
+ bool m_connected;
+
+ utility::path m_fsPath;
+
+
+ // Service infos
+ class _infos : public serviceInfos
+ {
+ public:
+
+ const port_t defaultPort() const;
+
+ const string propertyPrefix() const;
+ const std::vector <string> availableProperties() const;
+ };
+
+ static _infos sm_infos;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_MAILDIRSTORE_HPP_INCLUDED
diff --git a/src/messaging/maildirUtils.cpp b/src/messaging/maildirUtils.cpp
new file mode 100644
index 00000000..28df6902
--- /dev/null
+++ b/src/messaging/maildirUtils.cpp
@@ -0,0 +1,87 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "maildirUtils.hpp"
+#include "maildirStore.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+const vmime::word maildirUtils::TMP_DIR("tmp"); // ensure reliable delivery (not to be listed)
+const vmime::word maildirUtils::CUR_DIR("cur"); // no longer new messages
+const vmime::word maildirUtils::NEW_DIR("new"); // unread messages
+
+
+const utility::file::path maildirUtils::getFolderFSPath
+ (maildirStore* store, const utility::path& folderPath, const FolderFSPathMode mode)
+{
+ // Root path
+ utility::file::path path(store->getFileSystemPath());
+ const int count = (mode == FOLDER_PATH_CONTAINER ? folderPath.size() : folderPath.size() - 1);
+
+ // Parent folders
+ for (int i = 0 ; i < count ; ++i)
+ {
+ utility::file::path::component comp(folderPath[i]);
+
+ // TODO: may not work with all encodings...
+ comp.buffer() = "." + comp.buffer() + ".directory";
+
+ path /= comp;
+ }
+
+ // Last component
+ if (folderPath.size() != 0 &&
+ mode != FOLDER_PATH_CONTAINER)
+ {
+ path /= folderPath.last();
+
+ switch (mode)
+ {
+ case FOLDER_PATH_ROOT: break; // Nothing to do
+ case FOLDER_PATH_NEW: path /= NEW_DIR; break;
+ case FOLDER_PATH_CUR: path /= CUR_DIR; break;
+ case FOLDER_PATH_TMP: path /= TMP_DIR; break;
+ case FOLDER_PATH_CONTAINER: break; // Can't happen...
+ }
+ }
+
+ return (path);
+}
+
+
+const bool maildirUtils::isSubfolderDirectory(const utility::file& file)
+{
+ // A directory which name does not start with '.'
+ // is listed as a sub-folder...
+ if (file.isDirectory() &&
+ file.fullPath().last().buffer().size() >= 1 &&
+ file.fullPath().last().buffer()[0] != '.')
+ {
+ return (true);
+ }
+
+ return (false);
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/maildirUtils.hpp b/src/messaging/maildirUtils.hpp
new file mode 100644
index 00000000..44d36ad3
--- /dev/null
+++ b/src/messaging/maildirUtils.hpp
@@ -0,0 +1,72 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_MAILDIRUTILS_HPP_INCLUDED
+#define VMIME_MESSAGING_MAILDIRUTILS_HPP_INCLUDED
+
+
+#include "../utility/file.hpp"
+#include "../utility/path.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+class maildirStore;
+
+
+class maildirUtils
+{
+public:
+
+ /** Mode for return value of getFolderFSPath(). */
+ enum FolderFSPathMode
+ {
+ FOLDER_PATH_ROOT, /**< Root folder (eg. ~/Mail/MyFolder) */
+ FOLDER_PATH_NEW, /**< Folder containing unread messages (eg. ~/Mail/MyFolder/new) */
+ FOLDER_PATH_CUR, /**< Folder containing messages that have been seen (eg. ~/Mail/MyFolder/cur) */
+ FOLDER_PATH_TMP, /**< Temporary folder used for reliable delivery (eg. ~/Mail/MyFolder/tmp) */
+ FOLDER_PATH_CONTAINER /**< Container for sub-folders (eg. ~/Mail/.MyFolder.directory) */
+ };
+
+ /** Return the path on the filesystem for the folder in specified store.
+ *
+ * @param store parent store
+ * @param folderPath path of the folder
+ * @param mode type of path to return (see FolderFSPathMode)
+ * @return filesystem path for the specified folder
+ */
+ static const utility::file::path getFolderFSPath(maildirStore* store, const utility::path& folderPath, const FolderFSPathMode mode);
+
+ static const bool isSubfolderDirectory(const utility::file& file);
+
+private:
+
+ static const vmime::word TMP_DIR;
+ static const vmime::word CUR_DIR;
+ static const vmime::word NEW_DIR;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_MAILDIRUTILS_HPP_INCLUDED
diff --git a/src/messaging/message.cpp b/src/messaging/message.cpp
new file mode 100644
index 00000000..0bb1aaca
--- /dev/null
+++ b/src/messaging/message.cpp
@@ -0,0 +1,46 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "message.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+const part& part::operator[](const int x) const
+{
+ return (structure()[x]);
+}
+
+
+part& part::operator[](const int x)
+{
+ return (structure()[x]);
+}
+
+
+const int part::count() const
+{
+ return (structure().count());
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/message.hpp b/src/messaging/message.hpp
new file mode 100644
index 00000000..c07c9ca3
--- /dev/null
+++ b/src/messaging/message.hpp
@@ -0,0 +1,280 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_MESSAGE_HPP_INCLUDED
+#define VMIME_MESSAGING_MESSAGE_HPP_INCLUDED
+
+
+#include "../header.hpp"
+#include "progressionListener.hpp"
+#include "../utility/stream.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+/** A MIME part in a message.
+ */
+
+class part
+{
+protected:
+
+ part() { }
+ part(const part&) { }
+
+ virtual ~part() { }
+
+public:
+
+ /** Return the structure of this part.
+ *
+ * @return structure of the part
+ */
+ virtual const class structure& structure() const = 0;
+
+ /** Return the structure of this part.
+ *
+ * @return structure of the part
+ */
+ virtual class structure& structure() = 0;
+
+ /** Return the header section for this part (you must fetch header
+ * before using this function: see message::fetchPartHeader).
+ *
+ * @return header section
+ */
+ virtual const class header& header() const = 0;
+
+ /** Return the media-type of the content in this part.
+ *
+ * @return content media type
+ */
+ virtual const mediaType& type() const = 0;
+
+ /** Return the size of this part.
+ *
+ * @return size of the part (in bytes)
+ */
+ virtual const int size() const = 0;
+
+ /** Return the part sequence number (index)
+ *
+ * @return part number
+ */
+ virtual const int number() const = 0; // begin at 1
+
+ /** Return the sub-part at the specified position.
+ * This provide easy access to parts:
+ * Eg: "message->extract(message->structure()[3][1][2])".
+ *
+ * @param x index of the sub-part
+ * @return sub-part at position 'x'
+ */
+ const part& operator[](const int x) const;
+
+ /** Return the sub-part at the specified position.
+ * This provide easy access to parts:
+ * Eg: "message->extract(message->structure()[3][1][2])".
+ *
+ * @param x index of the sub-part
+ * @return sub-part at position 'x'
+ */
+ part& operator[](const int x);
+
+ /** Return the number of sub-parts in this part.
+ *
+ * @return number of sub-parts
+ */
+ const int count() const;
+};
+
+
+/** Structure of a MIME part/message.
+ */
+
+class structure
+{
+protected:
+
+ structure() { }
+ structure(const structure&) { }
+
+ virtual ~structure() { }
+
+public:
+
+ /** Return the part at the specified position.
+ *
+ * @param x position
+ * @return part at position 'x'
+ */
+ virtual const part& operator[](const int x) const = 0;
+
+ /** Return the part at the specified position.
+ *
+ * @param x position
+ * @return part at position 'x'
+ */
+ virtual part& operator[](const int x) = 0;
+
+ /** Return the number of parts in this part.
+ *
+ * @return number of parts
+ */
+ virtual const int count() const = 0;
+};
+
+
+/** Abstract representation of a message in a store/transport service.
+ */
+
+class message
+{
+protected:
+
+ message() { }
+ message(const message&) { }
+
+public:
+
+ virtual ~message() { }
+
+ /** The type for an unique message identifier.
+ */
+ typedef string uid;
+
+ /** Return the MIME structure of the message (must fetch before).
+ *
+ * @return MIME structure of the message
+ */
+ virtual const class structure& structure() const = 0;
+
+ /** Return the MIME structure of the message (must fetch before).
+ *
+ * @return MIME structure of the message
+ */
+ virtual class structure& structure() = 0;
+
+ /** Return a reference to the header fields of the message (must fetch before).
+ *
+ * @return header section of the message
+ */
+ virtual const class header& header() const = 0;
+
+ /** Return the sequence number of this message. This number is
+ * used to reference the message in the folder.
+ *
+ * @return sequence number of the message
+ */
+ virtual const int number() const = 0;
+
+ /** Return the unique identified of this message (must fetch before).
+ *
+ * @return UID of the message
+ */
+ virtual const uid uniqueId() const = 0;
+
+ /** Return the size of the message (must fetch before).
+ *
+ * @return size of the message (in bytes)
+ */
+ virtual const int size() const = 0;
+
+ /** Check whether this message has been expunged
+ * (ie: definitively deleted).
+ *
+ * @return true if the message is expunged, false otherwise
+ */
+ virtual const bool isExpunged() const = 0;
+
+ /** Possible flags for a message.
+ */
+ enum Flags
+ {
+ FLAG_SEEN = (1 << 0), /**< Message has been seen. */
+ FLAG_RECENT = (1 << 1), /**< Message has been recently received. */
+ FLAG_DELETED = (1 << 2), /**< Message is marked for deletion. */
+ FLAG_REPLIED = (1 << 3), /**< User replied to this message. */
+ FLAG_MARKED = (1 << 4), /**< Used-defined flag. */
+
+ FLAG_UNDEFINED = 9999 /**< Used internally (this should not be returned
+ by the flags() function). */
+ };
+
+ /** Methods for setting the flags.
+ */
+ enum FlagsModes
+ {
+ FLAG_MODE_SET, /**< Set (replace) the flags. */
+ FLAG_MODE_ADD, /**< Add the flags. */
+ FLAG_MODE_REMOVE /**< Remove the flags. */
+ };
+
+ /** Return the flags of this message.
+ *
+ * @return flags of the message
+ */
+ virtual const int flags() const = 0;
+
+ /** Set the flags of this message.
+ *
+ * @param flags set of flags (see Flags)
+ * @param mode indicate how to treat old and new flags (see FlagsModes)
+ */
+ virtual void setFlags(const int flags, const int mode = FLAG_MODE_SET) = 0;
+
+ /** Extract the whole message data (header + contents).
+ *
+ * WARNING: partial fetch might not be supported by the underlying protocol.
+ *
+ * @param os output stream in which to write message data
+ * @param progress progression listener, or NULL if not used
+ * @param start index of the first byte to retrieve (used for partial fetch)
+ * @param length number of bytes to retrieve (used for partial fetch)
+ */
+
+ virtual void extract(utility::outputStream& os, progressionListener* progress = NULL, const int start = 0, const int length = -1) const = 0;
+
+ /** Extract the specified (MIME) part of the message (header + contents).
+ *
+ * WARNING: partial fetch might not be supported by the underlying protocol.
+ *
+ * @param p part to extract
+ * @param os output stream in which to write part data
+ * @param progress progression listener, or NULL if not used
+ * @param start index of the first byte to retrieve (used for partial fetch)
+ * @param length number of bytes to retrieve (used for partial fetch)
+ */
+ virtual void extractPart(const part& p, utility::outputStream& os, progressionListener* progress = NULL, const int start = 0, const int length = -1) const = 0;
+
+ /** Fetch the MIME header for the specified part.
+ *
+ * @param p the part for which to fetch the header
+ */
+ virtual void fetchPartHeader(part& p) = 0;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_MESSAGE_HPP_INCLUDED
diff --git a/src/messaging/progressionListener.hpp b/src/messaging/progressionListener.hpp
new file mode 100644
index 00000000..1e75d862
--- /dev/null
+++ b/src/messaging/progressionListener.hpp
@@ -0,0 +1,75 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_PROGRESSIONLISTENER_HPP_INCLUDED
+#define VMIME_MESSAGING_PROGRESSIONLISTENER_HPP_INCLUDED
+
+
+namespace vmime {
+namespace messaging {
+
+
+/** An interface to implement if you want to be notified
+ * of a progression status by some objects.
+ */
+
+class progressionListener
+{
+protected:
+
+ virtual ~progressionListener() { }
+
+public:
+
+ /** Allow the caller object to cancel the current operation.
+ *
+ * @warning WARNING: this is implementation-dependant: the underlying
+ * messaging protocol may not support this).
+ *
+ * @return true to cancel the operation, false otherwise
+ */
+ virtual const bool cancel() const = 0;
+
+ /** Called at the beginning of the operation.
+ *
+ * @param predictedTotal predicted amount of units (this has
+ * no concrete meaning: they are not bytes, nor percentage...)
+ */
+ virtual void start(const int predictedTotal) = 0;
+
+ /** Called during the operation (can be called several times).
+ *
+ * @param current current position
+ * @param currentTotal adjusted total amount of units
+ */
+ virtual void progress(const int current, const int currentTotal) = 0;
+
+ /** Called at the end of the operation.
+ *
+ * @param total final total amount of units
+ */
+ virtual void stop(const int total) = 0;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_PROGRESSIONLISTENER_HPP_INCLUDED
diff --git a/src/messaging/service.cpp b/src/messaging/service.cpp
new file mode 100644
index 00000000..5a55fb4f
--- /dev/null
+++ b/src/messaging/service.cpp
@@ -0,0 +1,44 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "service.hpp"
+
+#include "defaultAuthenticator.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+service::service(class session& sess, const serviceInfos& infos, class authenticator* auth)
+ : m_deleteAuth(auth == NULL), m_session(sess), m_auth(auth ? auth :
+ new defaultAuthenticator(sess.properties(), infos.propertyPrefix()))
+{
+}
+
+
+service::~service()
+{
+ if (m_deleteAuth)
+ delete (m_auth);
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/service.hpp b/src/messaging/service.hpp
new file mode 100644
index 00000000..d4a59c7f
--- /dev/null
+++ b/src/messaging/service.hpp
@@ -0,0 +1,143 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_SERVICE_HPP_INCLUDED
+#define VMIME_MESSAGING_SERVICE_HPP_INCLUDED
+
+
+#include "../types.hpp"
+#include "session.hpp"
+
+#include "authenticator.hpp"
+#include "progressionListener.hpp"
+
+#include "serviceFactory.hpp"
+#include "serviceInfos.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+class service
+{
+protected:
+
+ service(class session& sess, const serviceInfos& infos, class authenticator* auth);
+
+public:
+
+ virtual ~service();
+
+ // Possible service types
+ enum Type
+ {
+ TYPE_STORE = 0, /**< The service is a message store. */
+ TYPE_TRANSPORT /**< The service sends messages. */
+ };
+
+ /** Return the type of service.
+ *
+ * @return type of service
+ */
+ virtual const Type type() const = 0;
+
+ /** Return the protocol name of this service.
+ *
+ * @return protocol name
+ */
+ virtual const string protocolName() const = 0;
+
+ /** Return the session object associated with this service instance.
+ *
+ * @return session object
+ */
+ const class session& session() const { return (m_session); }
+
+ /** Return the session object associated with this service instance.
+ *
+ * @return session object
+ */
+ class session& session() { return (m_session); }
+
+ /** Return information about this service.
+ *
+ * @return information about the service
+ */
+ virtual const serviceInfos& infos() const = 0;
+
+ /** Connect to service.
+ */
+ virtual void connect() = 0;
+
+ /** Disconnect from service.
+ */
+ virtual void disconnect() = 0;
+
+ /** Test whether this service is connected.
+ *
+ * @return true if the service is connected, false otherwise
+ */
+ virtual const bool isConnected() const = 0;
+
+ /** Do nothing but ensure the server do not disconnect (for
+ * example, this can reset the auto-logout timer on the
+ * server, if one exists).
+ */
+ virtual void noop() = 0;
+
+ /** Return the authenticator object used with this service instance.
+ *
+ * @return authenticator object
+ */
+ const class authenticator& authenticator() const { return (*m_auth); }
+
+ /** Return the authenticator object used with this service instance.
+ *
+ * @return authenticator object
+ */
+ class authenticator& authenticator() { return (*m_auth); }
+
+ // Basic service registerer
+ template <class S>
+ class initializer
+ {
+ public:
+
+ initializer(const string& protocol)
+ {
+ serviceFactory::getInstance()->
+ template registerName <S>(protocol);
+ }
+ };
+
+private:
+
+ bool m_deleteAuth;
+
+ class session& m_session;
+ class authenticator* m_auth;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_SERVICE_HPP_INCLUDED
diff --git a/src/messaging/serviceFactory.cpp b/src/messaging/serviceFactory.cpp
new file mode 100644
index 00000000..09bced01
--- /dev/null
+++ b/src/messaging/serviceFactory.cpp
@@ -0,0 +1,102 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "serviceFactory.hpp"
+#include "service.hpp"
+
+#include "../exception.hpp"
+#include "../config.hpp"
+
+#include "builtinServices.inl"
+
+
+namespace vmime {
+namespace messaging {
+
+
+serviceFactory::serviceFactory()
+{
+}
+
+
+serviceFactory::~serviceFactory()
+{
+ for (ProtoMap::iterator it = m_protoMap.begin() ; it != m_protoMap.end() ; ++it)
+ delete ((*it).second);
+}
+
+
+service* serviceFactory::create
+ (session& sess, const string& protocol, authenticator* auth)
+{
+ ProtoMap::const_iterator pos = m_protoMap.find(toLower(protocol));
+
+ if (pos != m_protoMap.end())
+ {
+ return ((*pos).second)->create(sess, auth);
+ }
+ else
+ {
+ throw exceptions::no_service_available();
+ return (NULL);
+ }
+}
+
+
+service* serviceFactory::create
+ (session& sess, const url& u, authenticator* auth)
+{
+ service* serv = create(sess, u.protocol(), auth);
+
+ sess.properties()[serv->infos().propertyPrefix() + "server.address"] = u.host();
+
+ if (u.port() != url::UNSPECIFIED_PORT)
+ sess.properties()[serv->infos().propertyPrefix() + "server.port"] = u.port();
+
+ if (!u.path().empty())
+ sess.properties()[serv->infos().propertyPrefix() + "server.path"] = u.path();
+
+ if (!u.username().empty())
+ {
+ sess.properties()[serv->infos().propertyPrefix() + "auth.username"] = u.username();
+ sess.properties()[serv->infos().propertyPrefix() + "auth.password"] = u.password();
+ }
+
+ return (serv);
+}
+
+
+const serviceFactory::registeredService& serviceFactory::operator[]
+ (const string& protocol) const
+{
+ ProtoMap::const_iterator pos = m_protoMap.find(toLower(protocol));
+
+ if (pos != m_protoMap.end())
+ {
+ return *((*pos).second);
+ }
+ else
+ {
+ throw exceptions::no_service_available();
+ }
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/serviceFactory.hpp b/src/messaging/serviceFactory.hpp
new file mode 100644
index 00000000..9aa8e46a
--- /dev/null
+++ b/src/messaging/serviceFactory.hpp
@@ -0,0 +1,207 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_SERVICEFACTORY_HPP_INCLUDED
+#define VMIME_MESSAGING_SERVICEFACTORY_HPP_INCLUDED
+
+
+#include <map>
+
+#include "../types.hpp"
+#include "../base.hpp"
+#include "../utility/singleton.hpp"
+
+#include "serviceInfos.hpp"
+#include "authenticator.hpp"
+#include "progressionListener.hpp"
+#include "timeoutHandler.hpp"
+#include "url.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+class service;
+class session;
+
+
+/** A factory to create 'service' objects for a specified protocol.
+ */
+
+class serviceFactory : public utility::singleton <serviceFactory>
+{
+ friend class utility::singleton <serviceFactory>;
+
+protected:
+
+ serviceFactory();
+ ~serviceFactory();
+
+public:
+
+ class registeredService
+ {
+ friend class serviceFactory;
+
+ protected:
+
+ virtual ~registeredService() { }
+
+ public:
+
+ virtual service* create(session& sess, authenticator* auth) = 0;
+
+ virtual const string& name() const = 0;
+ virtual const serviceInfos& infos() const = 0;
+ };
+
+private:
+
+ template <class S>
+ class registeredServiceImpl : public registeredService
+ {
+ friend class serviceFactory;
+
+ protected:
+
+ registeredServiceImpl(const string& name)
+ : m_name(name), m_servInfos(S::infosInstance())
+ {
+ }
+
+ public:
+
+ service* create(session& sess, authenticator* auth)
+ {
+ return new S(sess, auth);
+ }
+
+ const serviceInfos& infos() const
+ {
+ return (m_servInfos);
+ }
+
+ const string& name() const
+ {
+ return (m_name);
+ }
+
+ private:
+
+ const string m_name;
+ const serviceInfos& m_servInfos;
+ };
+
+ typedef std::map <string, registeredService*> ProtoMap;
+ ProtoMap m_protoMap;
+
+public:
+
+ template <class S>
+ void registerName(const string& protocol)
+ {
+ const string name = vmime::toLower(protocol);
+ m_protoMap.insert(ProtoMap::value_type(name,
+ new registeredServiceImpl <S>(name)));
+ }
+
+ service* create(session& sess, const string& protocol, authenticator* auth = NULL);
+ service* create(session& sess, const url& u, authenticator* auth = NULL);
+
+ const registeredService& operator[](const string& protocol) const;
+
+
+ class iterator;
+
+ class const_iterator
+ {
+ friend class serviceFactory;
+
+ public:
+
+ const_iterator() { }
+ const_iterator(const const_iterator& it) : m_it(it.m_it) { }
+ const_iterator(const iterator& it) : m_it(it.m_it) { }
+
+ const_iterator& operator=(const const_iterator& it) { m_it = it.m_it; return (*this); }
+
+ const registeredService& operator*() const { return (*(*m_it).second); }
+ const registeredService* operator->() const { return ((*m_it).second); }
+
+ const_iterator& operator++() { ++m_it; return (*this); }
+ const_iterator operator++(int) { return (m_it++); }
+
+ const_iterator& operator--() { --m_it; return (*this); }
+ const_iterator operator--(int) { return (m_it--); }
+
+ const bool operator==(const const_iterator& it) const { return (m_it == it.m_it); }
+ const bool operator!=(const const_iterator& it) const { return (m_it != it.m_it); }
+
+ private:
+
+ const_iterator(const ProtoMap::const_iterator it) : m_it(it) { }
+
+ ProtoMap::const_iterator m_it;
+ };
+
+ class iterator
+ {
+ friend class serviceFactory;
+ friend class serviceFactory::const_iterator;
+
+ public:
+
+ iterator() { }
+ iterator(const iterator& it) : m_it(it.m_it) { }
+
+ iterator& operator=(const iterator& it) { m_it = it.m_it; return (*this); }
+
+ registeredService& operator*() const { return (*(*m_it).second); }
+ registeredService* operator->() const { return ((*m_it).second); }
+
+ iterator& operator++() { ++m_it; return (*this); }
+ iterator operator++(int) { return (m_it++); }
+
+ iterator& operator--() { --m_it; return (*this); }
+ iterator operator--(int) { return (m_it--); }
+
+ const bool operator==(const iterator& it) const { return (m_it == it.m_it); }
+ const bool operator!=(const iterator& it) const { return (m_it != it.m_it); }
+
+ private:
+
+ iterator(const ProtoMap::iterator it) : m_it(it) { }
+
+ ProtoMap::iterator m_it;
+ };
+
+ iterator begin() { return iterator(m_protoMap.begin()); }
+ iterator end() { return iterator(m_protoMap.end()); }
+
+ const_iterator begin() const { return const_iterator(m_protoMap.begin()); }
+ const_iterator end() const { return const_iterator(m_protoMap.end()); }
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_SERVICEFACTORY_HPP_INCLUDED
diff --git a/src/messaging/serviceInfos.hpp b/src/messaging/serviceInfos.hpp
new file mode 100644
index 00000000..9da5ab26
--- /dev/null
+++ b/src/messaging/serviceInfos.hpp
@@ -0,0 +1,75 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_SERVICEINFOS_HPP_INCLUDED
+#define VMIME_MESSAGING_SERVICEINFOS_HPP_INCLUDED
+
+
+#include <vector>
+
+#include "../types.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+class serviceInfos
+{
+ friend class serviceFactory;
+
+protected:
+
+ serviceInfos() { }
+ serviceInfos(const serviceInfos&) { }
+
+private:
+
+ serviceInfos& operator=(const serviceInfos&) { return (*this); }
+
+public:
+
+ virtual ~serviceInfos() { }
+
+ /** Return the default port used for the underlying protocol.
+ *
+ * @return default port number
+ */
+ virtual const port_t defaultPort() const = 0;
+
+ /** Return the property prefix used by this service.
+ * Use this to set/get properties in the session object.
+ *
+ * @return property prefix
+ */
+ virtual const string propertyPrefix() const = 0;
+
+ /** Return a list of available properties for this service.
+ *
+ * @return list of property names
+ */
+ virtual const std::vector <string> availableProperties() const = 0;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_SERVICEINFOS_HPP_INCLUDED
diff --git a/src/messaging/session.cpp b/src/messaging/session.cpp
new file mode 100644
index 00000000..be1d8206
--- /dev/null
+++ b/src/messaging/session.cpp
@@ -0,0 +1,88 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "session.hpp"
+#include "serviceFactory.hpp"
+
+#include "store.hpp"
+#include "transport.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+session::session()
+{
+}
+
+
+session::session(const propertySet& props)
+ : m_props(props)
+{
+}
+
+
+session::~session()
+{
+}
+
+
+transport* session::getTransport(authenticator* auth)
+{
+ return (getTransport(m_props["transport.protocol"], auth));
+}
+
+
+transport* session::getTransport(const string& protocol, authenticator* auth)
+{
+ service* sv = serviceFactory::getInstance()->create(*this, protocol, auth);
+
+ if (sv->type() != service::TYPE_TRANSPORT)
+ {
+ delete (sv);
+ throw exceptions::no_service_available();
+ }
+
+ return static_cast<transport*>(sv);
+}
+
+
+store* session::getStore(authenticator* auth)
+{
+ return (getStore(m_props["store.protocol"], auth));
+}
+
+
+store* session::getStore(const string& protocol, authenticator* auth)
+{
+ service* sv = serviceFactory::getInstance()->create(*this, protocol, auth);
+
+ if (sv->type() != service::TYPE_STORE)
+ {
+ delete (sv);
+ throw exceptions::no_service_available();
+ }
+
+ return static_cast<store*>(sv);
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/session.hpp b/src/messaging/session.hpp
new file mode 100644
index 00000000..43bbe0b1
--- /dev/null
+++ b/src/messaging/session.hpp
@@ -0,0 +1,113 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_SESSION_HPP_INCLUDED
+#define VMIME_MESSAGING_SESSION_HPP_INCLUDED
+
+
+#include "authenticator.hpp"
+#include "progressionListener.hpp"
+
+#include "../propertySet.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+class store;
+class transport;
+
+
+/** An object that contains all the information needed
+ * for connection to a service.
+ */
+
+class session
+{
+public:
+
+ session();
+ session(const propertySet& props);
+
+ virtual ~session();
+
+ /** Return a transport service instance for the protocol specified
+ * in the session properties.
+ *
+ * The property "transport.protocol" specify the protocol to use.
+ *
+ * @param auth authenticator object to use for the new transport service. If
+ * NULL, a default one is used. The default authenticator simply return user
+ * credentials by reading the session properties "auth.username" and "auth.password".
+ * @return a new transport service
+ */
+ transport* getTransport(authenticator* auth = NULL);
+
+ /** Return a transport service instance for the specified protocol.
+ *
+ * @param protocol transport protocol to use (eg. "smtp")
+ * @param auth authenticator object to use for the new transport service. If
+ * NULL, a default one is used. The default authenticator simply return user
+ * credentials by reading the session properties "auth.username" and "auth.password".
+ * @return a new transport service
+ */
+ transport* getTransport(const string& protocol, authenticator* auth = NULL);
+
+ /** Return a transport service instance for the protocol specified
+ * in the session properties.
+ *
+ * The property "store.protocol" specify the protocol to use.
+ *
+ * @param auth authenticator object to use for the new store service. If
+ * NULL, a default one is used. The default authenticator simply return user
+ * credentials by reading the session properties "auth.username" and "auth.password".
+ * @return a new transport service
+ */
+ store* getStore(authenticator* auth = NULL);
+
+ /** Return a store service instance for the specified protocol.
+ *
+ * @param protocol store protocol to use (eg. "imap")
+ * @param auth authenticator object to use for the new store service. If
+ * NULL, a default one is used. The default authenticator simply return user
+ * credentials by reading the session properties "auth.username" and "auth.password".
+ * @return a new transport service
+ */
+ store* getStore(const string& protocol, authenticator* auth = NULL);
+
+ /** Properties for the session and for the services.
+ */
+ const propertySet& properties() const { return (m_props); }
+
+ /** Properties for the session and for the services.
+ */
+ propertySet& properties() { return (m_props); }
+
+private:
+
+ propertySet m_props;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_SESSION_HPP_INCLUDED
diff --git a/src/messaging/simpleAuthenticator.cpp b/src/messaging/simpleAuthenticator.cpp
new file mode 100644
index 00000000..557efd63
--- /dev/null
+++ b/src/messaging/simpleAuthenticator.cpp
@@ -0,0 +1,45 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "simpleAuthenticator.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+simpleAuthenticator::simpleAuthenticator()
+{
+}
+
+
+simpleAuthenticator::simpleAuthenticator(const string& username, const string& password)
+ : m_username(username), m_password(password)
+{
+}
+
+
+const authenticationInfos simpleAuthenticator::getAuthInfos() const
+{
+ return (authenticationInfos(m_username, m_password));
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/simpleAuthenticator.hpp b/src/messaging/simpleAuthenticator.hpp
new file mode 100644
index 00000000..9d19f4c6
--- /dev/null
+++ b/src/messaging/simpleAuthenticator.hpp
@@ -0,0 +1,59 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_SIMPLEAUTHENTICATOR_HPP_INCLUDED
+#define VMIME_MESSAGING_SIMPLEAUTHENTICATOR_HPP_INCLUDED
+
+
+#include "authenticator.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+class simpleAuthenticator : public authenticator
+{
+public:
+
+ simpleAuthenticator();
+ simpleAuthenticator(const string& username, const string& password);
+
+public:
+
+ const string& username() const { return (m_username); }
+ string& username() { return (m_username); }
+
+ const string& password() const { return (m_password); }
+ string& password() { return (m_password); }
+
+private:
+
+ string m_username;
+ string m_password;
+
+ const authenticationInfos getAuthInfos() const;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_SIMPLEAUTHENTICATOR_HPP_INCLUDED
diff --git a/src/messaging/socket.hpp b/src/messaging/socket.hpp
new file mode 100644
index 00000000..4cf69536
--- /dev/null
+++ b/src/messaging/socket.hpp
@@ -0,0 +1,98 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_SOCKET_HPP_INCLUDED
+#define VMIME_MESSAGING_SOCKET_HPP_INCLUDED
+
+
+#include "../base.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+class socket
+{
+public:
+
+ virtual ~socket() { }
+
+ /** Connect to the specified address and port.
+ *
+ * @param address server address (this can be a full qualified domain name
+ * or an IP address, doesn't matter)
+ * @param port server port
+ */
+ virtual void connect(const string& address, const port_t port) = 0;
+
+ /** Disconnect from the server.
+ */
+ virtual void disconnect() = 0;
+
+ /** Test whether this socket is connected.
+ *
+ * @return true if the socket is connected, false otherwise
+ */
+ virtual const bool isConnected() const = 0;
+
+ /** Receive (text) data from the socket.
+ *
+ * @param buffer buffer in which to write received data
+ */
+ virtual void receive(string& buffer) = 0;
+
+ /** Receive (raw) data from the socket.
+ *
+ * @param buffer buffer in which to write received data
+ * @param count maximum number of bytes to receive (size of buffer)
+ * @return number of bytes received/written into output buffer
+ */
+ virtual const int receiveRaw(char* buffer, const int count) = 0;
+
+ /** Send (text) data to the socket.
+ *
+ * @param buffer data to send
+ */
+ virtual void send(const string& buffer) = 0;
+
+ /** Send (raw) data to the socket.
+ *
+ * @param buffer data to send
+ * @param count number of bytes to send (size of buffer)
+ */
+ virtual void sendRaw(const char* buffer, const int count) = 0;
+};
+
+
+class socketFactory
+{
+public:
+
+ virtual ~socketFactory() { }
+
+ virtual socket* create() = 0;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_SOCKET_HPP_INCLUDED
diff --git a/src/messaging/store.hpp b/src/messaging/store.hpp
new file mode 100644
index 00000000..687975d3
--- /dev/null
+++ b/src/messaging/store.hpp
@@ -0,0 +1,75 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_STORE_HPP_INCLUDED
+#define VMIME_MESSAGING_STORE_HPP_INCLUDED
+
+
+#include "service.hpp"
+#include "folder.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+/** A store service.
+ * Encapsulate protocols that provide access to user's mail drop.
+ */
+
+class store : public service
+{
+protected:
+
+ store(class session& sess, const serviceInfos& infos, class authenticator* auth)
+ : service(sess, infos, auth) { }
+
+public:
+
+ /** Return the default folder. This is protocol dependant
+ * and usually is the INBOX folder.
+ *
+ * @return default folder
+ */
+ virtual folder* getDefaultFolder() = 0;
+
+ /** Return the root folder. This is protocol dependant
+ * and usually is the user's mail drop root folder
+ *
+ * @return root folder
+ */
+ virtual folder* getRootFolder() = 0;
+
+ /** Return the folder specified by the path.
+ *
+ * @param path absolute folder path
+ * @return folder at the specified path
+ */
+ virtual folder* getFolder(const folder::path& path) = 0;
+
+
+ const Type type() const { return (TYPE_STORE); }
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_STORE_HPP_INCLUDED
diff --git a/src/messaging/timeoutHandler.hpp b/src/messaging/timeoutHandler.hpp
new file mode 100644
index 00000000..a7675b79
--- /dev/null
+++ b/src/messaging/timeoutHandler.hpp
@@ -0,0 +1,71 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_TIMEOUTHANDLER_HPP_INCLUDED
+#define VMIME_MESSAGING_TIMEOUTHANDLER_HPP_INCLUDED
+
+
+namespace vmime {
+namespace messaging {
+
+
+/** A class to manage time-out in messaging services.
+ */
+
+class timeoutHandler
+{
+public:
+
+ virtual ~timeoutHandler() { }
+
+ /** Called to test if the time limit has been reached.
+ *
+ * @return true if the time-out delay is elapsed
+ */
+ virtual const bool isTimeOut() = 0;
+
+ /** Called to reset the time-out counter.
+ */
+ virtual void resetTimeOut() = 0;
+
+ /** Called when the time limit has been reached (when
+ * isTimeOut() returned true).
+ *
+ * @return true to continue (and reset the time-out)
+ * or false to cancel the current operation
+ */
+ virtual const bool handleTimeOut() = 0;
+};
+
+
+class timeoutHandlerFactory
+{
+public:
+
+ virtual ~timeoutHandlerFactory() { }
+
+ virtual timeoutHandler* create() = 0;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_TIMEOUTHANDLER_HPP_INCLUDED
diff --git a/src/messaging/transport.hpp b/src/messaging/transport.hpp
new file mode 100644
index 00000000..588eb24b
--- /dev/null
+++ b/src/messaging/transport.hpp
@@ -0,0 +1,76 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_TRANSPORT_HPP_INCLUDED
+#define VMIME_MESSAGING_TRANSPORT_HPP_INCLUDED
+
+
+#include "service.hpp"
+#include "../utility/stream.hpp"
+
+
+namespace vmime {
+
+class message;
+class mailbox;
+class mailboxList;
+
+namespace messaging {
+
+
+/** A transport service.
+ * Encapsulate protocols that can send messages.
+ */
+
+class transport : public service
+{
+protected:
+
+ transport(class session& sess, const serviceInfos& infos, class authenticator* auth)
+ : service(sess, infos, auth) { }
+
+public:
+
+ /** Send a message over this transport service.
+ *
+ * @param msg message to send
+ * @param progress progression listener, or NULL if not used
+ */
+ virtual void send(vmime::message* msg, progressionListener* progress = NULL) = 0;
+
+ /** Send a message over this transport service.
+ *
+ * @param expeditor expeditor mailbox
+ * @param recipients list of recipient mailboxes
+ * @param is input stream provding message data (header + body)
+ * @param size size of the message data
+ * @param progress progression listener, or NULL if not used
+ */
+ virtual void send(const mailbox& expeditor, const mailboxList& recipients, utility::inputStream& is, const utility::stream::size_type size, progressionListener* progress = NULL) = 0;
+
+
+ const Type type() const { return (TYPE_TRANSPORT); }
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_TRANSPORT_HPP_INCLUDED
diff --git a/src/messaging/url.cpp b/src/messaging/url.cpp
new file mode 100644
index 00000000..cd38c656
--- /dev/null
+++ b/src/messaging/url.cpp
@@ -0,0 +1,226 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "url.hpp"
+
+#include "parserHelpers.hpp"
+#include "urlUtils.hpp"
+#include "exception.hpp"
+
+#include <sstream>
+
+
+namespace vmime {
+namespace messaging {
+
+
+// Known protocols
+const string url::PROTOCOL_FILE = "file";
+const string url::PROTOCOL_HTTP = "http";
+const string url::PROTOCOL_FTP = "ftp";
+
+
+
+url::url(const string& s)
+{
+ parse(s);
+}
+
+
+url::url(const url& u)
+{
+ operator=(u);
+}
+
+
+url::url(const string& protocol, const string& host, const port_t port,
+ const string& path, const string& username, const string& password)
+ : m_protocol(protocol), m_username(username), m_password(password),
+ m_host(host), m_port(port), m_path(path)
+{
+}
+
+
+url& url::operator=(const url& u)
+{
+ m_protocol = u.m_protocol;
+
+ m_username = u.m_username;
+ m_password = u.m_password;
+
+ m_host = u.m_host;
+ m_port = u.m_port;
+
+ m_path = u.m_path;
+
+ return (*this);
+}
+
+
+url& url::operator=(const string& s)
+{
+ parse(s);
+
+ return (*this);
+}
+
+
+url::operator string() const
+{
+ return build();
+}
+
+
+const string url::build() const
+{
+ std::ostringstream oss;
+
+ oss << m_protocol << "://";
+
+ if (!m_username.empty())
+ {
+ oss << urlUtils::encode(m_username);
+
+ if (!m_password.empty())
+ {
+ oss << ":";
+ oss << urlUtils::encode(m_password);
+ }
+
+ oss << "@";
+ }
+
+ oss << urlUtils::encode(m_host);
+
+ if (m_port != UNSPECIFIED_PORT)
+ {
+ oss << ":";
+ oss << m_port;
+ }
+
+ if (!m_path.empty())
+ {
+ oss << "/";
+ oss << urlUtils::encode(m_path);
+ }
+
+ return (oss.str());
+}
+
+
+void url::parse(const string& str)
+{
+ // Protocol
+ const string::size_type protoEnd = str.find("://");
+ if (protoEnd == string::npos) throw exceptions::malformed_url("No protocol separator");
+
+ const string proto =
+ toLower(string(str.begin(), str.begin() + protoEnd));
+
+ // Username/password
+ string::size_type slashPos = str.find('/', protoEnd + 3);
+ if (slashPos == string::npos) slashPos = str.length();
+
+ string::size_type atPos = str.find('@', protoEnd + 3);
+ string hostPart;
+
+ string username;
+ string password;
+
+ if (atPos != string::npos && atPos < slashPos)
+ {
+ const string userPart(str.begin() + protoEnd, str.begin() + atPos);
+ const string::size_type colonPos = userPart.find(':');
+
+ if (colonPos == string::npos)
+ {
+ username = userPart;
+ }
+ else
+ {
+ username = string(userPart.begin(), userPart.begin() + colonPos);
+ password = string(userPart.begin() + colonPos + 1, userPart.end());
+ }
+
+ hostPart = string(str.begin() + atPos + 1, str.begin() + slashPos);
+ }
+ else
+ {
+ hostPart = string(str.begin() + protoEnd, str.begin() + slashPos);
+ }
+
+ // Host/port
+ const string::size_type colonPos = hostPart.find(':');
+
+ string host;
+ string port;
+
+ if (colonPos == string::npos)
+ {
+ host = hostPart;
+ }
+ else
+ {
+ host = string(hostPart.begin(), hostPart.begin() + colonPos);
+ port = string(hostPart.begin() + colonPos + 1, hostPart.end());
+ }
+
+ // Path
+ string path(str.begin() + slashPos, str.end());
+
+ if (path == "/")
+ path.clear();
+
+ // Some sanity check
+ if (proto.empty())
+ throw exceptions::malformed_url("No protocol specified");
+ else if (host.empty() && path.empty()) // Accept empty host (eg. "file:///home/vincent/mydoc")
+ throw exceptions::malformed_url("No host specified");
+
+ bool onlyDigit = true;
+
+ for (string::const_iterator it = port.begin() ;
+ onlyDigit && it != port.end() ; ++it)
+ {
+ onlyDigit = isdigit(*it);
+ }
+
+ if (!onlyDigit)
+ throw exceptions::malformed_url("Port can only contain digits");
+
+ std::istringstream iss(port);
+ port_t portNum = 0;
+
+ iss >> portNum;
+
+ // Now, save URL parts
+ m_protocol = proto;
+
+ m_username = urlUtils::decode(username);
+ m_password = urlUtils::decode(password);
+
+ m_host = urlUtils::decode(host);
+ m_port = portNum;
+
+ m_path = urlUtils::decode(path);
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/url.hpp b/src/messaging/url.hpp
new file mode 100644
index 00000000..8cef2d16
--- /dev/null
+++ b/src/messaging/url.hpp
@@ -0,0 +1,125 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_URL_HPP_INCLUDED
+#define VMIME_MESSAGING_URL_HPP_INCLUDED
+
+
+#include "../types.hpp"
+#include "../base.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+/** This class represents a Uniform Resource Locator (a pointer
+ * to a "resource" on the World Wide Web).
+ */
+
+class url
+{
+public:
+
+ /** Means "port not specified" (use default port).
+ */
+ static const port_t UNSPECIFIED_PORT = static_cast <port_t>(-1);
+
+ static const string PROTOCOL_FILE;
+ static const string PROTOCOL_HTTP;
+ static const string PROTOCOL_FTP;
+
+
+ /** Construct an URL from a string (parse the URL components).
+ *
+ * @param s full URL string (eg. http://vmime.sourceforge.net:80/download.html
+ */
+ url(const string& s);
+
+ /** Construct an URL from another URL object.
+ *
+ * @param u other URL object
+ */
+ url(const url& u);
+
+ /** Construct an URL from the components.
+ *
+ * @param protocol protocol (eg. "http", "ftp"...)
+ * @param host host name (eg. "vmime.sourceforge.net", "123.45.67.89")
+ * @param port optional port number (eg. 80, 110 or UNSPECIFIED_PORT to mean "default")
+ * @param path optional full path (eg. "download.html")
+ * @param username optional user name
+ * @param password optional user password
+ */
+ url(const string& protocol, const string& host, const port_t port = UNSPECIFIED_PORT,
+ const string& path = "", const string& username = "", const string& password = "");
+
+
+ const string& protocol() const { return (m_protocol); }
+ string& protocol() { return (m_protocol); }
+
+ const string& username() const { return (m_username); }
+ string& username() { return (m_username); }
+
+ const string& password() const { return (m_password); }
+ string& password() { return (m_password); }
+
+ const string& host() const { return (m_host); }
+ string& host() { return (m_host); }
+
+ const port_t port() const { return (m_port); }
+ port_t& port() { return (m_port); }
+
+ const string& path() const { return (m_path); }
+ string& path() { return (m_path); }
+
+
+ /** Build a string URL from this object.
+ */
+ operator string() const;
+
+ url& operator=(const url& u);
+ url& operator=(const string& s);
+
+private:
+
+ const string build() const;
+ void parse(const string& str);
+
+ // Format:
+ // "protocol://[username[:password]@]host[:port][/path]"
+
+ string m_protocol;
+
+ string m_username;
+ string m_password;
+
+ string m_host;
+
+ port_t m_port;
+
+ string m_path;
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_URL_HPP_INCLUDED
diff --git a/src/messaging/urlUtils.cpp b/src/messaging/urlUtils.cpp
new file mode 100644
index 00000000..b8e9cb91
--- /dev/null
+++ b/src/messaging/urlUtils.cpp
@@ -0,0 +1,93 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "urlUtils.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+const string urlUtils::encode(const string& s)
+{
+ string result;
+ result.reserve(s.length());
+
+ for (string::const_iterator it = s.begin() ; it != s.end() ; ++it)
+ {
+ const char_t c = *it;
+
+ if (isprint(c) && c != '%')
+ {
+ result += c;
+ }
+ else
+ {
+ char hex[4];
+
+ hex[0] = '%';
+ hex[1] = c / 16;
+ hex[2] = c % 16;
+ hex[3] = 0;
+
+ result += hex;
+ }
+ }
+
+ return (result);
+}
+
+
+const string urlUtils::decode(const string& s)
+{
+ string result;
+ result.reserve(s.length());
+
+ for (string::const_iterator it = s.begin() ; it != s.end() ; )
+ {
+ const char_t c = *it;
+
+ switch (c)
+ {
+ case '%':
+ {
+ const char_t p = (++it != s.end() ? *it : 0);
+ const char_t q = (++it != s.end() ? *it : 0);
+
+ result += static_cast <string::value_type>(p * 16 + q);
+
+ if (it != s.end())
+ ++it;
+
+ break;
+ }
+ default:
+
+ result += c;
+ ++it;
+ break;
+ }
+ }
+
+ return (result);
+}
+
+
+} // messaging
+} // vmime
diff --git a/src/messaging/urlUtils.hpp b/src/messaging/urlUtils.hpp
new file mode 100644
index 00000000..135d508e
--- /dev/null
+++ b/src/messaging/urlUtils.hpp
@@ -0,0 +1,51 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_MESSAGING_URLUTILS_HPP_INCLUDED
+#define VMIME_MESSAGING_URLUTILS_HPP_INCLUDED
+
+
+#include "../types.hpp"
+#include "../base.hpp"
+
+
+namespace vmime {
+namespace messaging {
+
+
+class urlUtils
+{
+public:
+
+ /** Encode extended characters in a URL string (ASCII characters
+ * are unmodified, other are encoded as '%' followed by hex code).
+ */
+ static const string encode(const string& s);
+
+ /** Decode an hex-encoded URL (see encode()).
+ */
+ static const string decode(const string& s);
+};
+
+
+} // messaging
+} // vmime
+
+
+#endif // VMIME_MESSAGING_URLUTILS_HPP_INCLUDED
diff --git a/src/options.cpp b/src/options.cpp
new file mode 100644
index 00000000..cd630a1d
--- /dev/null
+++ b/src/options.cpp
@@ -0,0 +1,27 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "options.hpp"
+
+
+namespace vmime
+{
+
+
+} // vmime
diff --git a/src/options.hpp b/src/options.hpp
new file mode 100644
index 00000000..bfc2f243
--- /dev/null
+++ b/src/options.hpp
@@ -0,0 +1,98 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_OPTIONS_HPP_INCLUDED
+#define VMIME_OPTIONS_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "utility/singleton.hpp"
+
+
+namespace vmime
+{
+
+
+/** A class to set global options for VMime.
+ */
+
+class options : public utility::singleton <options>
+{
+ friend class utility::singleton <options>;
+
+protected:
+
+ /** Message-related options.
+ */
+ class messageOptions
+ {
+ protected:
+
+ friend class options;
+
+ messageOptions()
+ : m_maxLineLength(lineLengthLimits::convenient)
+ {
+ }
+
+ string::size_type m_maxLineLength;
+
+ public:
+
+ const string::size_type& maxLineLength() const { return (m_maxLineLength); }
+ string::size_type& maxLineLength() { return (m_maxLineLength); }
+ };
+
+ /** Multipart-related options.
+ */
+ class multipartOptions
+ {
+ protected:
+
+ friend class options;
+
+ multipartOptions()
+ : m_prologText("This is a multi-part message in MIME format. Your mail reader does not understand MIME message format."),
+ m_epilogText("")
+ {
+ }
+
+ string m_prologText;
+ string m_epilogText;
+
+ public:
+
+ const string& prologText() const { return (m_prologText); }
+ string& prologText() { return (m_prologText); }
+
+ const string& epilogText() const { return (m_epilogText); }
+ string& epilogText() { return (m_epilogText); }
+ };
+
+public:
+
+ multipartOptions multipart;
+ messageOptions message;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_OPTIONS_HPP_INCLUDED
diff --git a/src/parameter.cpp b/src/parameter.cpp
new file mode 100644
index 00000000..98111cb0
--- /dev/null
+++ b/src/parameter.cpp
@@ -0,0 +1,43 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "parameter.hpp"
+#include "parameterFactory.hpp"
+
+
+namespace vmime
+{
+
+
+parameter* parameter::clone() const
+{
+ parameter* p = parameterFactory::getInstance()->create(m_name);
+ p->copyFrom(*this);
+
+ return (p);
+}
+
+
+void parameter::copyFrom(const parameter& param)
+{
+ m_name = param.m_name;
+}
+
+
+} // vmime
diff --git a/src/parameter.hpp b/src/parameter.hpp
new file mode 100644
index 00000000..57f130ba
--- /dev/null
+++ b/src/parameter.hpp
@@ -0,0 +1,55 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_PARAMETER_HPP_INCLUDED
+#define VMIME_PARAMETER_HPP_INCLUDED
+
+
+#include "component.hpp"
+
+
+namespace vmime
+{
+
+
+class parameter : public component
+{
+ friend class parameterFactory; // for "parse()"
+
+public:
+
+ parameter* clone() const;
+
+protected:
+
+ string m_name;
+
+public:
+
+ virtual void copyFrom(const parameter& param);
+
+ const string& name() const { return (m_name); }
+ string& name() { return (m_name); }
+};
+
+
+} // vmime
+
+
+#endif // VMIME_PARAMETER_HPP_INCLUDED
diff --git a/src/parameterFactory.cpp b/src/parameterFactory.cpp
new file mode 100644
index 00000000..e67a8ee3
--- /dev/null
+++ b/src/parameterFactory.cpp
@@ -0,0 +1,71 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "parameterFactory.hpp"
+#include "exception.hpp"
+
+#include "textParameter.hpp"
+#include "charsetParameter.hpp"
+#include "dateParameter.hpp"
+
+
+namespace vmime
+{
+
+
+parameterFactory::parameterFactory()
+{
+ // Register some default names
+ registerName <charsetParameter>("charset");
+ registerName <dateParameter>("creation-date");
+ registerName <dateParameter>("modification-date");
+ registerName <dateParameter>("read-date");
+}
+
+
+parameterFactory::~parameterFactory()
+{
+}
+
+
+parameter* parameterFactory::create
+ (const string& name, const string& value)
+{
+ const string _name = toLower(name);
+
+ NameMap::const_iterator pos = m_nameMap.find(_name);
+ parameter* param = NULL;
+
+ if (pos != m_nameMap.end())
+ {
+ param = ((*pos).second)();
+ }
+ else
+ {
+ param = new textParameter;
+ }
+
+ param->name() = _name;
+ if (value != NULL_STRING) param->parse(value);
+
+ return (param);
+}
+
+
+} // vmime
diff --git a/src/parameterFactory.hpp b/src/parameterFactory.hpp
new file mode 100644
index 00000000..8bff7e33
--- /dev/null
+++ b/src/parameterFactory.hpp
@@ -0,0 +1,73 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_PARAMETERFACTORY_HPP_INCLUDED
+#define VMIME_PARAMETERFACTORY_HPP_INCLUDED
+
+
+#include "parameter.hpp"
+#include "utility/singleton.hpp"
+
+
+namespace vmime
+{
+
+
+class parameterFactory : public utility::singleton <parameterFactory>
+{
+ friend class utility::singleton <parameterFactory>;
+
+protected:
+
+ parameterFactory();
+ ~parameterFactory();
+
+ typedef parameter* (*AllocFunc)(void);
+ typedef std::map <string, AllocFunc> NameMap;
+
+ NameMap m_nameMap;
+
+ template <class TYPE>
+ class registerer
+ {
+ public:
+
+ static parameter* creator()
+ {
+ // Allocate a new object
+ return new TYPE();
+ }
+ };
+
+public:
+
+ template <class T>
+ void registerName(const string& name)
+ {
+ m_nameMap.insert(NameMap::value_type(toLower(name), &registerer<T>::creator));
+ }
+
+ parameter* create(const string& name, const string& value = NULL_STRING);
+};
+
+
+} // vmime
+
+
+#endif // VMIME_PARAMETERFACTORY_HPP_INCLUDED
diff --git a/src/parameterizedHeaderField.cpp b/src/parameterizedHeaderField.cpp
new file mode 100644
index 00000000..ee00cd32
--- /dev/null
+++ b/src/parameterizedHeaderField.cpp
@@ -0,0 +1,335 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "parameterizedHeaderField.hpp"
+#include "parameterFactory.hpp"
+#include "text.hpp"
+#include "parserHelpers.hpp"
+
+
+namespace vmime
+{
+
+
+parameterizedHeaderField::parameterizedHeaderField()
+{
+}
+
+
+/*
+ This class handles field contents of the following form:
+ Field: VALUE; PARAM1="VALUE1"; PARAM2="VALUE2"...
+
+ eg. RFC-1521
+
+ content := "Content-Type" ":" type "/" subtype *(";" parameter)
+
+ parameter := attribute "=" value
+
+ attribute := token ; case-insensitive
+
+ value := token / quoted-string
+
+ token := 1*<any (ASCII) CHAR except SPACE, CTLs, or tspecials>
+
+ tspecials := "(" / ")" / "<" / ">" / "@"
+ / "," / ";" / ":" / "\" / <">
+ / "/" / "[" / "]" / "?" / "="
+ ; Must be in quoted-string,
+ ; to use within parameter values
+*/
+
+void parameterizedHeaderField::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ const string::value_type* const pend = buffer.data() + end;
+ const string::value_type* const pstart = buffer.data() + position;
+ const string::value_type* p = pstart;
+
+ const string::size_type start = position;
+
+ while (p < pend && *p != ';') ++p;
+
+ parseValue(buffer, start, position + (p - pstart));
+
+ // If there is one or more parameters following...
+ if (p < pend)
+ {
+ while (*p == ';')
+ {
+ // Skip ';'
+ ++p;
+
+ while (p < pend && isspace(*p)) ++p;
+
+ const string::size_type attrStart = position + (p - pstart);
+
+ while (p < pend && !(*p == ';' || *p == '='))
+ ++p;
+
+ if (p >= pend || *p == ';')
+ {
+ // Hmmmm... we didn't found an '=' sign.
+ // This parameter may not be valid so try to advance
+ // to the next one, if there is one.
+ while (p < pend && *p != ';')
+ ++p;
+ }
+ else
+ {
+ // Extract the attribute name
+ string::size_type attrEnd = position + (p - pstart);
+
+ while (attrEnd != attrStart && isspace(buffer[attrEnd - 1]))
+ --attrEnd;
+
+ // Skip '='
+ ++p;
+
+ // Skip white-spaces between '=' and the value
+ while (p < pend && isspace(*p)) ++p;
+
+ // Extract the value
+ string value;
+
+ // -- this is a quoted-string
+ if (*p == '"')
+ {
+ // Skip '"'
+ ++p;
+
+ // Extract quoted-string
+ bool escape = false;
+ bool stop = false;
+
+ std::ostringstream ss;
+ string::size_type start = position + (p - pstart);
+
+ for ( ; p < pend && !stop ; ++p)
+ {
+ if (escape)
+ {
+ escape = false;
+ start = position + (p - pstart);
+ }
+ else
+ {
+ switch (*p)
+ {
+ case '"':
+ {
+ ss << string(buffer.begin() + start,
+ buffer.begin() + position + (p - pstart));
+
+ stop = true;
+ break;
+ }
+ case '\\':
+ {
+ ss << string(buffer.begin() + start,
+ buffer.begin() + position + (p - pstart));
+
+ escape = true;
+ break;
+ }
+
+ }
+ }
+ }
+
+ if (!stop)
+ {
+ ss << string(buffer.begin() + start,
+ buffer.begin() + position + (p - pstart));
+ }
+
+ value = ss.str();
+ }
+ // -- the value is a simple token
+ else
+ {
+ const string::size_type valStart = position + (p - pstart);
+
+ while (p < pend && *p != ';')
+ ++p;
+
+ string::size_type valEnd = position + (p - pstart);
+
+ while (valEnd != valStart && isspace(buffer[valEnd - 1]))
+ --valEnd;
+
+ value = string(buffer.begin() + valStart,
+ buffer.begin() + valEnd);
+ }
+
+ // Don't allow ill-formed parameters
+ if (attrStart != attrEnd && value.length())
+ {
+ // Append this parameter to the list
+ parameters.m_params.push_back(parameterFactory::getInstance()->
+ create(string(buffer.begin() + attrStart,
+ buffer.begin() + attrEnd), value));
+ }
+
+ // Skip white-spaces after this parameter
+ while (p < pend && isspace(*p)) ++p;
+ }
+ }
+ }
+
+ if (newPosition)
+ *newPosition = end;
+}
+
+
+void parameterizedHeaderField::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ string::size_type pos = curLinePos;
+
+ // Parent header field
+ headerField::generate(os, maxLineLength, pos, &pos);
+
+ // Value
+ const string value = generateValue();
+
+ encodeAndFoldText(os, text(value), maxLineLength - 1,
+ pos, &pos, encodeAndFoldFlags::none);
+
+ // Parameters
+ for (std::vector <parameter*>::const_iterator
+ it = parameters.m_params.begin() ; it != parameters.m_params.end() ; ++it)
+ {
+ const parameter& param = **it;
+
+ os << "; ";
+ pos += 2;
+
+ param.generate(os, maxLineLength, pos, &pos);
+ }
+
+ if (newLinePos)
+ *newLinePos = pos;
+}
+
+
+void parameterizedHeaderField::copyFrom(const headerField& field)
+{
+ const parameterizedHeaderField& source = dynamic_cast<const parameterizedHeaderField&>(field);
+
+ parameters.clear();
+
+ for (std::vector <parameter*>::const_iterator i = source.parameters.m_params.begin() ;
+ i != source.parameters.m_params.end() ; ++i)
+ {
+ parameters.m_params.push_back((*i)->clone());
+ }
+
+ headerField::copyFrom(field);
+}
+
+
+
+//////////////////////
+// Params container //
+//////////////////////
+
+
+parameterizedHeaderField::paramsContainer::~paramsContainer()
+{
+ clear();
+}
+
+
+parameter& parameterizedHeaderField::paramsContainer::find(const string& name) const
+{
+ const string _name = toLower(name);
+
+ std::vector <parameter*>::const_iterator pos = m_params.begin();
+ const std::vector <parameter*>::const_iterator end = m_params.end();
+
+ for ( ; pos != end && (*pos)->name() != _name ; ++pos);
+
+ // No parameter with this name can be found
+ if (pos == end)
+ {
+ throw exceptions::no_such_parameter(name);
+ }
+ // Else, return a reference to the existing parameter
+ else
+ {
+ return (**pos);
+ }
+}
+
+
+parameter& parameterizedHeaderField::paramsContainer::get(const string& name)
+{
+ const string _name = toLower(name);
+
+ std::vector <parameter*>::iterator pos = m_params.begin();
+ const std::vector <parameter*>::iterator end = m_params.end();
+
+ for ( ; pos != end && (*pos)->name() != _name ; ++pos);
+
+ // If no parameter with this name can be found, create a new one
+ if (pos == end)
+ {
+ parameter* param = parameterFactory::getInstance()->create(_name);
+ m_params.push_back(param);
+
+ // Return a reference to the new parameter
+ return (*param);
+ }
+ // Else, return a reference to the existing parameter
+ else
+ {
+ return (**pos);
+ }
+}
+
+
+// Parameter insertion
+void parameterizedHeaderField::paramsContainer::append(const parameter& param)
+{
+ m_params.push_back(param.clone());
+}
+
+
+void parameterizedHeaderField::paramsContainer::insert(const iterator it, const parameter& param)
+{
+ m_params.insert(it.m_iterator, param.clone());
+}
+
+
+// Parameter removing
+void parameterizedHeaderField::paramsContainer::remove(const iterator it)
+{
+ delete (*it.m_iterator);
+ m_params.erase(it.m_iterator);
+}
+
+
+void parameterizedHeaderField::paramsContainer::clear()
+{
+ free_container(m_params);
+}
+
+
+} // vmime
diff --git a/src/parameterizedHeaderField.hpp b/src/parameterizedHeaderField.hpp
new file mode 100644
index 00000000..949aceb4
--- /dev/null
+++ b/src/parameterizedHeaderField.hpp
@@ -0,0 +1,201 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_PARAMETERIZEDHEADERFIELD_HPP_INCLUDED
+#define VMIME_PARAMETERIZEDHEADERFIELD_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "headerFieldFactory.hpp"
+#include "parameter.hpp"
+#include "exception.hpp"
+#include "parameterFactory.hpp"
+
+
+namespace vmime
+{
+
+
+class parameterizedHeaderField : public headerField
+{
+ friend class headerFieldFactory::registerer <parameterizedHeaderField>;
+
+protected:
+
+ parameterizedHeaderField();
+
+public:
+
+ void copyFrom(const headerField& field);
+
+ // A sub-class for parameter manipulation
+ class paramsContainer
+ {
+ friend class parameterizedHeaderField;
+
+ protected:
+
+ ~paramsContainer();
+
+ public:
+
+ // Find the first parameter with the specified name. If no parameter
+ // is found, an exception is thrown.
+ parameter& find(const string& name) const;
+
+ // Find the first parameter with the specified name
+ parameter& get(const string& name);
+
+ // Parameter iterator
+ class const_iterator;
+
+ class iterator
+ {
+ friend class parameterizedHeaderField::paramsContainer::const_iterator;
+ friend class parameterizedHeaderField::paramsContainer;
+
+ public:
+
+ typedef std::vector <parameter*>::iterator::difference_type difference_type;
+
+ iterator(std::vector <parameter*>::iterator it) : m_iterator(it) { }
+ iterator(const iterator& it) : m_iterator(it.m_iterator) { }
+
+ iterator& operator=(const iterator& it) { m_iterator = it.m_iterator; return (*this); }
+
+ parameter& operator*() const { return (**m_iterator); }
+ parameter* operator->() const { return (*m_iterator); }
+
+ iterator& operator++() { ++m_iterator; return (*this); }
+ iterator operator++(int) { iterator i(*this); ++m_iterator; return (i); }
+
+ iterator& operator--() { --m_iterator; return (*this); }
+ iterator operator--(int) { iterator i(*this); --m_iterator; return (i); }
+
+ iterator& operator+=(difference_type n) { m_iterator += n; return (*this); }
+ iterator& operator-=(difference_type n) { m_iterator -= n; return (*this); }
+
+ iterator operator-(difference_type x) const { return iterator(m_iterator - x); }
+
+ parameter& operator[](difference_type n) const { return *(m_iterator[n]); }
+
+ const bool operator==(const iterator& it) const { return (it.m_iterator == m_iterator); }
+ const bool operator!=(const iterator& it) const { return (!(*this == it)); }
+
+ protected:
+
+ std::vector <parameter*>::iterator m_iterator;
+ };
+
+ class const_iterator
+ {
+ public:
+
+ typedef std::vector <parameter*>::const_iterator::difference_type difference_type;
+
+ const_iterator(std::vector <parameter*>::const_iterator it) : m_iterator(it) { }
+ const_iterator(const iterator& it) : m_iterator(it.m_iterator) { }
+ const_iterator(const const_iterator& it) : m_iterator(it.m_iterator) { }
+
+ const_iterator& operator=(const const_iterator& it) { m_iterator = it.m_iterator; return (*this); }
+ const_iterator& operator=(const iterator& it) { m_iterator = it.m_iterator; return (*this); }
+
+ const parameter& operator*() const { return (**m_iterator); }
+ const parameter* operator->() const { return (*m_iterator); }
+
+ const_iterator& operator++() { ++m_iterator; return (*this); }
+ const_iterator operator++(int) { const_iterator i(*this); ++m_iterator; return (i); }
+
+ const_iterator& operator--() { --m_iterator; return (*this); }
+ const_iterator operator--(int) { const_iterator i(*this); --m_iterator; return (i); }
+
+ const_iterator& operator+=(difference_type n) { m_iterator += n; return (*this); }
+ const_iterator& operator-=(difference_type n) { m_iterator -= n; return (*this); }
+
+ const_iterator operator-(difference_type x) const { return const_iterator(m_iterator - x); }
+
+ const parameter& operator[](difference_type n) const { return *(m_iterator[n]); }
+
+ const bool operator==(const const_iterator& it) const { return (it.m_iterator == m_iterator); }
+ const bool operator!=(const const_iterator& it) const { return (!(*this == it)); }
+
+ protected:
+
+ std::vector <parameter*>::const_iterator m_iterator;
+ };
+
+ public:
+
+ iterator begin() { return (m_params.begin()); }
+ iterator end() { return (m_params.end()); }
+
+ const_iterator begin() const { return (const_iterator(m_params.begin())); }
+ const_iterator end() const { return (const_iterator(m_params.end())); }
+
+ // Parameter insertion
+ void append(const parameter& param);
+ void insert(const iterator it, const parameter& param);
+
+ // Parameter removing
+ void remove(const iterator it);
+ void clear();
+
+ // Parameter count
+ const size_t count() const { return (m_params.size()); }
+ const size_t size() const { return (m_params.size()); }
+
+ parameter& front() { return (*m_params.front()); }
+ const parameter& front() const { return (*m_params.front()); }
+ parameter& back() { return (*m_params.back()); }
+ const parameter& back() const { return (*m_params.back()); }
+
+ protected:
+
+ std::vector <parameter*> m_params;
+
+ } parameters;
+
+ typedef paramsContainer::iterator iterator;
+ typedef paramsContainer::const_iterator const_iterator;
+
+protected:
+
+ std::vector <parameter*> m_params;
+
+protected:
+
+ virtual void parseValue(const string& buffer, const string::size_type position, const string::size_type end) = 0;
+ virtual const string generateValue() const = 0;
+
+public:
+
+ using headerField::parse;
+ using headerField::generate;
+
+ // No need to override these (use "parseValue" and "generateValue" instead).
+ // For more information, see "defaultParameter.hpp".
+ 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_PARAMETERIZEDHEADERFIELD_HPP_INCLUDED
diff --git a/src/parserHelpers.hpp b/src/parserHelpers.hpp
new file mode 100644
index 00000000..41a9f13c
--- /dev/null
+++ b/src/parserHelpers.hpp
@@ -0,0 +1,80 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_PARSERHELPERS_HPP_INCLUDED
+#define VMIME_PARSERHELPERS_HPP_INCLUDED
+
+
+#include "types.hpp"
+
+#include <algorithm>
+
+
+
+namespace vmime
+{
+
+
+inline const bool isspace(const char_t c)
+{
+ return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
+}
+
+
+inline const bool isdigit(const char_t c)
+{
+ return (c >= '0' && c <= '9');
+}
+
+
+inline const bool isalpha(const char_t c)
+{
+ return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
+}
+
+
+inline const char_t tolower(const char_t c)
+{
+ if (c >= 'A' && c <= 'Z')
+ return ('a' + (c - 'A'));
+ else
+ return c;
+}
+
+
+// Checks whether a character is in the 7-bit US-ASCII charset
+
+inline const bool isascii(const char_t c)
+{
+ return (c <= 127);
+}
+
+
+// Checks whether a character has a visual representation
+
+inline const bool isprint(const char_t c)
+{
+ return (c >= 0x20 && c <= 0x7E);
+}
+
+
+} // vmime
+
+
+#endif // VMIME_PARSERHELPERS_HPP_INCLUDED
diff --git a/src/plainTextPart.cpp b/src/plainTextPart.cpp
new file mode 100644
index 00000000..141fb271
--- /dev/null
+++ b/src/plainTextPart.cpp
@@ -0,0 +1,80 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "plainTextPart.hpp"
+#include "header.hpp"
+#include "exception.hpp"
+
+
+namespace vmime
+{
+
+
+const mediaType plainTextPart::type() const
+{
+ return (mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN));
+}
+
+
+const int plainTextPart::getPartCount() const
+{
+ return (1);
+}
+
+
+void plainTextPart::generateIn(bodyPart& /* message */, bodyPart& parent) const
+{
+ // Create a new part
+ bodyPart* part = new bodyPart();
+ parent.body().parts.append(part);
+
+ // Set header fields
+ part->header().fields.ContentType() = mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN);
+ part->header().fields.ContentType().charset() = m_charset;
+ part->header().fields.ContentTransferEncoding() = encoding(encodingTypes::QUOTED_PRINTABLE);
+
+ // Set contents
+ part->body().contents() = m_text;
+}
+
+
+void plainTextPart::parse(const bodyPart& /* message */,
+ const bodyPart& /* parent */, const bodyPart& textPart)
+{
+ m_text = textPart.body().contents();
+
+ try
+ {
+ const contentTypeField& ctf = dynamic_cast<contentTypeField&>
+ (textPart.header().fields.find(headerField::ContentType));
+
+ m_charset = ctf.charset();
+ }
+ catch (exceptions::no_such_field)
+ {
+ // No "Content-type" field.
+ }
+ catch (exceptions::no_such_parameter)
+ {
+ // No "charset" parameter.
+ }
+}
+
+
+} // vmime
diff --git a/src/plainTextPart.hpp b/src/plainTextPart.hpp
new file mode 100644
index 00000000..324d2203
--- /dev/null
+++ b/src/plainTextPart.hpp
@@ -0,0 +1,58 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_PLAINTEXTPART_HPP_INCLUDED
+#define VMIME_PLAINTEXTPART_HPP_INCLUDED
+
+
+#include "textPart.hpp"
+
+
+namespace vmime
+{
+
+
+class plainTextPart : public textPart
+{
+public:
+
+ const mediaType type() const;
+
+ const class charset& charset() const { return (m_charset); }
+ class charset& charset() { return (m_charset); }
+
+ const contentHandler& text() const { return (m_text); }
+ contentHandler& text() { return (m_text); }
+
+protected:
+
+ contentHandler m_text;
+ class charset m_charset;
+
+ const int getPartCount() const;
+
+ void generateIn(bodyPart& message, bodyPart& parent) const;
+ void parse(const bodyPart& message, const bodyPart& parent, const bodyPart& textPart);
+};
+
+
+} // vmime
+
+
+#endif // VMIME_PLAINTEXTPART_HPP_INCLUDED
diff --git a/src/platformDependant.cpp b/src/platformDependant.cpp
new file mode 100644
index 00000000..cf1ed8c1
--- /dev/null
+++ b/src/platformDependant.cpp
@@ -0,0 +1,35 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "platformDependant.hpp"
+
+
+namespace vmime
+{
+
+
+platformDependant::handler* platformDependant::sm_handler = NULL;
+
+
+platformDependant::handler::~handler()
+{
+}
+
+
+} // vmime
diff --git a/src/platformDependant.hpp b/src/platformDependant.hpp
new file mode 100644
index 00000000..920e970b
--- /dev/null
+++ b/src/platformDependant.hpp
@@ -0,0 +1,155 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_PLATFORMDEPENDANT_HPP_INCLUDED
+#define VMIME_PLATFORMDEPENDANT_HPP_INCLUDED
+
+
+#include "config.hpp"
+#include "dateTime.hpp"
+#include "exception.hpp"
+#include "charset.hpp"
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+ #include "messaging/socket.hpp"
+ #include "messaging/timeoutHandler.hpp"
+#endif
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+ #include "utility/file.hpp"
+#endif
+
+
+namespace vmime
+{
+
+
+/** The link between your application and VMime. It offers an interface to
+ * access platform-dependant objects: sockets, date/time, file system, etc.
+ */
+
+class platformDependant
+{
+public:
+
+ class handler
+ {
+ public:
+
+ virtual ~handler();
+
+ /** Return the current UNIX time (Epoch time): the number of
+ * seconds elapsed since Jan, 1st 1970 00:00.
+ *
+ * @return UNIX Epoch time
+ */
+ virtual const unsigned int getUnixTime() const = 0;
+
+ /** Return the current date and time, in the local time zone.
+ *
+ * @return current date and time
+ */
+ virtual const datetime getCurrentLocalTime() const = 0;
+
+ /** Return the host name of the system.
+ * Used when generating message ids.
+ *
+ * @return host name
+ */
+ virtual const string getHostName() const = 0;
+
+ /** Return the current process identifier.
+ * Used when generating random strings (part boundaries or message ids).
+ *
+ * @return current process id
+ */
+ virtual const unsigned int getProcessId() const = 0;
+
+ /** Return the charset used on the system.
+ *
+ * @return locale charset
+ */
+ virtual const charset getLocaleCharset() const = 0;
+
+ /** This function is called when VMime library is waiting for
+ * something (for example, it is called when there is no data
+ * available in a socket). On POSIX-compliant systems, a
+ * simple call to sched_yield() should suffice.
+ */
+ virtual void wait() const = 0;
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+ /** Return a pointer to a socket factory for the specified socket
+ * type name (this is user-defined, and used for example when you
+ * want to set up a SSL connection to a server).
+ * The returned object will not be deleted by VMime, so it can be
+ * a pointer to a static object.
+ *
+ * @param name socket type name (user-dependant): this is usually
+ * the value of the property "server.socket-factory" set in the
+ * session object
+ * @return socket factory
+ */
+ virtual messaging::socketFactory* getSocketFactory(const string& name = "default") const = 0;
+
+ /** Return a pointer to a timeout-handler factory for the specified name.
+ * The returned object will not be deleted by VMime, so it can be a
+ * pointer to a static object.
+ *
+ * This is used when you want to handle a timeout-mechanism when
+ * connecting to messaging servers (please read the documentation to
+ * learn how to use it). If you are not using time-out handlers, you
+ * can safely return NULL here.
+ *
+ * @param name time-out type name
+ * @return time-out factory
+ */
+ virtual messaging::timeoutHandlerFactory* getTimeoutHandlerFactory(const string& name = "default") const = 0;
+#endif
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+ virtual utility::fileSystemFactory* getFileSystemFactory() const = 0;
+#endif
+ };
+
+
+ template <class TYPE>
+ static void setHandler()
+ {
+ delete (sm_handler);
+ sm_handler = new TYPE;
+ }
+
+ static const handler* const getHandler()
+ {
+ if (!sm_handler)
+ throw exceptions::no_platform_dependant_handler();
+
+ return (sm_handler);
+ }
+
+private:
+
+ static handler* sm_handler;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_PLATFORMDEPENDANT_HPP_INCLUDED
diff --git a/src/propertySet.cpp b/src/propertySet.cpp
new file mode 100644
index 00000000..664a2b43
--- /dev/null
+++ b/src/propertySet.cpp
@@ -0,0 +1,218 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "propertySet.hpp"
+
+
+namespace vmime
+{
+
+
+propertySet::propertySet()
+{
+}
+
+
+propertySet::propertySet(const string& props)
+{
+ parse(props);
+}
+
+
+propertySet::propertySet(const propertySet& set)
+{
+ for (std::list <property*>::const_iterator it = set.m_props.begin() ; it != set.m_props.end() ; ++it)
+ m_props.push_back(new property(**it));
+}
+
+
+propertySet::~propertySet()
+{
+ empty();
+}
+
+
+propertySet& propertySet::operator=(const propertySet& set)
+{
+ empty();
+
+ for (std::list <property*>::const_iterator it = set.m_props.begin() ; it != set.m_props.end() ; ++it)
+ m_props.push_back(new property(**it));
+
+ return (*this);
+}
+
+
+void propertySet::set(const string& props)
+{
+ parse(props);
+}
+
+
+void propertySet::empty()
+{
+ free_container(m_props);
+}
+
+
+void propertySet::clear(const string& name)
+{
+ std::list <property*>::iterator it = std::find_if
+ (m_props.begin(), m_props.end(), propFinder(name));
+
+ if (it != m_props.end())
+ {
+ delete (*it);
+ m_props.erase(it);
+ }
+}
+
+
+void propertySet::parse(const string& props)
+{
+ const string::const_iterator end = props.end();
+ string::const_iterator pos = props.begin();
+
+ for ( ; pos != end ; )
+ {
+ // Skip white-spaces
+ for ( ; pos != end && isspace(*pos) ; ++pos);
+
+ if (pos != end)
+ {
+ if (*pos == ';')
+ {
+ ++pos;
+ continue;
+ }
+
+ // Extract the property name
+ const string::const_iterator optStart = pos;
+
+ for ( ; pos != end && *pos != '=' ; ++pos);
+
+ string::const_iterator optEnd = pos;
+
+ for ( ; optEnd != optStart && isspace(*(optEnd - 1)) ; --optEnd);
+
+ const string option(optStart, optEnd);
+ string value = "1";
+
+ if (pos != end)
+ {
+ ++pos; // skip '='
+
+ // Extract the value
+ for ( ; pos != end && isspace(*pos) ; ++pos);
+
+ if (pos != end)
+ {
+ // A quoted-string
+ if (*pos == '"' || *pos == '\'')
+ {
+ value.reserve(50);
+
+ const std::string::value_type quoteChar = *pos;
+ bool theEnd = false;
+ bool escape = false;
+
+ for ( ; (pos != end) && !theEnd ; ++pos)
+ {
+ if (escape)
+ {
+ value += *pos;
+ escape = false;
+ }
+ else
+ {
+ if (*pos == '\\')
+ escape = true;
+ else if (*pos == quoteChar)
+ theEnd = true;
+ else
+ value += *pos;
+ }
+ }
+
+ if (pos != end)
+ ++pos;
+ }
+ // Simple value
+ else
+ {
+ const string::const_iterator valStart = pos;
+
+ for ( ; pos != end && !isspace(*pos) ; ++pos);
+
+ value = string(valStart, pos);
+ }
+
+ // Advance to the next ';'
+ for ( ; pos != end && (*pos != ';') ; ++pos);
+
+ if (pos != end)
+ ++pos; // skip ';'
+ }
+ }
+
+ m_props.push_back(new property(option, value));
+ }
+ }
+}
+
+
+template <>
+void propertySet::property::set(const string& value)
+{
+ m_value = value;
+}
+
+
+template <>
+void propertySet::property::set(const bool& value)
+{
+ m_value = value ? "true" : "false";
+}
+
+
+template <>
+const string propertySet::property::get() const
+{
+ return (m_value);
+}
+
+
+template <>
+const bool propertySet::property::get() const
+{
+ if (toLower(m_value) == "true")
+ return true;
+ else
+ {
+ int val = 0;
+
+ std::istringstream iss(m_value);
+ iss >> val;
+
+ return (!iss.fail() && val != 0);
+ }
+}
+
+
+} // vmime
diff --git a/src/propertySet.hpp b/src/propertySet.hpp
new file mode 100644
index 00000000..eb0ee7d7
--- /dev/null
+++ b/src/propertySet.hpp
@@ -0,0 +1,340 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_PROPERTY_HPP_INCLUDED
+#define VMIME_PROPERTY_HPP_INCLUDED
+
+
+#include <list>
+#include <functional>
+#include <algorithm>
+#include <sstream>
+
+#include "base.hpp"
+#include "exception.hpp"
+
+
+namespace vmime
+{
+
+
+class propertySet
+{
+private:
+
+ class property
+ {
+ public:
+
+ property(const string& name, const string& value) : m_name(name), m_value(value) { }
+ property(const string& name) : m_name(name) { }
+ property(const property& prop) : m_name(prop.m_name), m_value(prop.m_value) { }
+
+ const string& name() const { return (m_name); }
+ const string& value() const { return (m_value); }
+
+ template <class TYPE> void set(const TYPE& value);
+ template <class TYPE> const TYPE get() const;
+
+ private:
+
+ string m_name;
+ string m_value;
+ };
+
+
+ class propertyProxy
+ {
+ public:
+
+ propertyProxy(const string& name, propertySet* set)
+ : m_name(name), m_set(set)
+ {
+ }
+
+ template <class TYPE>
+ propertyProxy& operator=(const TYPE& value)
+ {
+ m_set->set(m_name, value);
+ return (*this);
+ }
+
+ template <class TYPE>
+ void set(const TYPE& value)
+ {
+ m_set->set(m_name, value);
+ }
+
+ template <class TYPE>
+ const TYPE get() const
+ {
+ return (m_set->get <TYPE>(m_name));
+ }
+
+ operator string() const
+ {
+ return (m_set->get <string>(m_name));
+ }
+
+ private:
+
+ const string m_name;
+ propertySet* m_set;
+ };
+
+ class constPropertyProxy
+ {
+ public:
+
+ constPropertyProxy(const string& name, const propertySet* set)
+ : m_name(name), m_set(set)
+ {
+ }
+
+ template <class TYPE>
+ const TYPE get() const
+ {
+ return (m_set->get <TYPE>(m_name));
+ }
+
+ operator string() const
+ {
+ return (m_set->get <string>(m_name));
+ }
+
+ private:
+
+ const string m_name;
+ const propertySet* m_set;
+ };
+
+public:
+
+ propertySet();
+ propertySet(const string& props);
+ propertySet(const propertySet& set);
+
+ ~propertySet();
+
+ propertySet& operator=(const propertySet& set);
+
+ void set(const string& props);
+
+ void empty();
+
+ void clear(const string& name);
+
+
+ const bool exists(const string& name) const
+ {
+ return (find(name) != NULL);
+ }
+
+ template <class TYPE>
+ const TYPE get(const string& name) const
+ {
+ const property* const prop = find(name);
+ if (!prop) throw exceptions::no_such_property(name);
+
+ return (prop->get <TYPE>());
+ }
+
+ template <class TYPE>
+ const TYPE get(const string& name, const TYPE defaultValue) const
+ {
+ const property* const prop = find(name);
+ return (prop ? prop->get <TYPE>() : defaultValue);
+ }
+
+ template <class TYPE>
+ void set(const string& name, const TYPE& value)
+ {
+ findOrCreate(name)->set(value);
+ }
+
+ propertyProxy operator[](const string& name)
+ {
+ return (propertyProxy(name, this));
+ }
+
+ const constPropertyProxy operator[](const string& name) const
+ {
+ return (constPropertyProxy(name, this));
+ }
+
+private:
+
+ void parse(const string& props);
+
+
+ class propFinder : public std::unary_function <property*, bool>
+ {
+ public:
+
+ propFinder(const string& name) : m_name(toLower(name)) { }
+
+ const bool operator()(property* const p) const
+ {
+ return (toLower(p->name()) == m_name);
+ }
+
+ private:
+
+ const std::string m_name;
+ };
+
+ property* find(const string& name) const
+ {
+ std::list <property*>::const_iterator it = std::find_if
+ (m_props.begin(), m_props.end(), propFinder(name));
+
+ return (it != m_props.end() ? *it : NULL);
+ }
+
+ property* findOrCreate(const string& name)
+ {
+ std::list <property*>::const_iterator it = std::find_if
+ (m_props.begin(), m_props.end(), propFinder(name));
+
+ if (it != m_props.end())
+ {
+ return (*it);
+ }
+ else
+ {
+ property* prop = new property(name, "");
+ m_props.push_back(prop);
+ return (prop);
+ }
+ }
+
+ typedef std::list <property*> list_type;
+ list_type m_props;
+
+public:
+
+ class iterator;
+
+ class const_iterator
+ {
+ friend class propertySet;
+
+ public:
+
+ const_iterator() { }
+ const_iterator(const const_iterator& it) : m_it(it.m_it) { }
+ const_iterator(const iterator& it) : m_it(it.m_it) { }
+
+ const_iterator& operator=(const const_iterator& it) { m_it = it.m_it; return (*this); }
+
+ const property& operator*() const { return (**m_it); }
+ const property* operator->() const { return (*m_it); }
+
+ const_iterator& operator++() { ++m_it; return (*this); }
+ const_iterator operator++(int) { return (m_it++); }
+
+ const_iterator& operator--() { --m_it; return (*this); }
+ const_iterator operator--(int) { return (m_it--); }
+
+ const bool operator==(const const_iterator& it) const { return (m_it == it.m_it); }
+ const bool operator!=(const const_iterator& it) const { return (m_it != it.m_it); }
+
+ private:
+
+ const_iterator(const list_type::const_iterator it) : m_it(it) { }
+
+ list_type::const_iterator m_it;
+ };
+
+ class iterator
+ {
+ friend class propertySet;
+ friend class propertySet::const_iterator;
+
+ public:
+
+ iterator() { }
+ iterator(const iterator& it) : m_it(it.m_it) { }
+
+ iterator& operator=(const iterator& it) { m_it = it.m_it; return (*this); }
+
+ property& operator*() const { return (**m_it); }
+ property* operator->() const { return (*m_it); }
+
+ iterator& operator++() { ++m_it; return (*this); }
+ iterator operator++(int) { return (m_it++); }
+
+ iterator& operator--() { --m_it; return (*this); }
+ iterator operator--(int) { return (m_it--); }
+
+ const bool operator==(const iterator& it) const { return (m_it == it.m_it); }
+ const bool operator!=(const iterator& it) const { return (m_it != it.m_it); }
+
+ private:
+
+ iterator(const list_type::iterator it) : m_it(it) { }
+
+ list_type::iterator m_it;
+ };
+
+ iterator begin() { return iterator(m_props.begin()); }
+ iterator end() { return iterator(m_props.end()); }
+
+ const_iterator begin() const { return const_iterator(m_props.begin()); }
+ const_iterator end() const { return const_iterator(m_props.end()); }
+};
+
+
+
+template <class TYPE>
+void propertySet::property::set(const TYPE& value)
+{
+ std::ostringstream oss;
+ oss << value;
+
+ m_value = oss.str();
+}
+
+
+template <class TYPE>
+const TYPE propertySet::property::get() const
+{
+ TYPE val = TYPE();
+
+ std::istringstream iss(m_value);
+ iss >> val;
+
+ if (iss.fail())
+ throw exceptions::invalid_property_type();
+
+ return (val);
+}
+
+
+template <> void propertySet::property::set(const string& value);
+template <> void propertySet::property::set(const bool& value);
+
+template <> const string propertySet::property::get() const;
+template <> const bool propertySet::property::get() const;
+
+
+} // vmime
+
+
+#endif // VMIME_PROPERTY_HPP_INCLUDED
diff --git a/src/relayField.cpp b/src/relayField.cpp
new file mode 100644
index 00000000..b7959547
--- /dev/null
+++ b/src/relayField.cpp
@@ -0,0 +1,239 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "relayField.hpp"
+#include "text.hpp"
+#include "parserHelpers.hpp"
+
+#include <sstream>
+
+
+namespace vmime
+{
+
+
+relayField::relayField()
+{
+}
+
+
+/*
+
+ RFC #2822:
+
+ received = "Received" ":" ; one per relay
+ ["from" domain] ; sending host
+ ["by" domain] ; receiving host
+ ["via" atom] ; physical path
+ *("with" atom) ; link/mail protocol
+ ["id" msg-id] ; receiver msg id
+ ["for" addr-spec] ; initial form
+*/
+
+void relayField::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ const string::value_type* const pend = buffer.data() + end;
+ const string::value_type* const pstart = buffer.data() + position;
+ const string::value_type* p = pend - 1;
+
+ // Find the beginning of the date part
+ while (p >= pstart && *p != ';')
+ --p;
+
+ if (p >= pstart)
+ {
+ // Parse the date/time part
+ m_date.parse(buffer, position + (p - pstart) + 1, end);
+
+ // Parse the components
+ std::istringstream iss(string
+ (buffer.begin() + position, buffer.begin() + position + (p - pstart)));
+
+ string word;
+ std::vector <string> previous;
+
+ enum Parts
+ {
+ Part_None,
+ Part_From, // The "from" part
+ Part_By, // The "by" part
+ Part_Via, // The "via" part
+ Part_With, // One "with" part
+ Part_Id, // The "id" part
+ Part_For, // The "for" part
+ Part_End
+ };
+
+ Parts part = Part_None;
+ bool cont = true;
+ bool inComment = false;
+
+ while (cont)
+ {
+ Parts newPart = Part_None;
+
+ if (cont = (iss >> word))
+ {
+ // A little hack for handling comments
+ if (inComment)
+ {
+ string::size_type par = word.find(')');
+
+ if (par != string::npos)
+ {
+ previous.push_back(string(word.begin(), word.begin() + par + 1));
+ word.erase(word.begin(), word.begin() + par + 1);
+ inComment = false;
+ }
+ }
+
+ bool keyword = false;
+
+ if (!inComment)
+ {
+ if (isStringEqualNoCase(word, "from", 4))
+ {
+ newPart = Part_From;
+ keyword = true;
+ }
+ else if (isStringEqualNoCase(word, "by", 2))
+ {
+ newPart = Part_By;
+ keyword = true;
+ }
+ else if (isStringEqualNoCase(word, "via", 2))
+ {
+ newPart = Part_Via;
+ keyword = true;
+ }
+ else if (isStringEqualNoCase(word, "with", 2))
+ {
+ newPart = Part_With;
+ keyword = true;
+ }
+ else if (isStringEqualNoCase(word, "id", 2))
+ {
+ newPart = Part_Id;
+ keyword = true;
+ }
+ else if (isStringEqualNoCase(word, "for", 2))
+ {
+ newPart = Part_For;
+ keyword = true;
+ }
+ }
+
+ if (!keyword)
+ {
+ if (word.find('(') != string::npos)
+ inComment = true;
+
+ previous.push_back(word);
+ }
+ }
+
+ if (!cont || newPart != Part_None)
+ {
+ if (part != Part_None)
+ {
+ std::ostringstream value;
+
+ for (std::vector <string>::const_iterator
+ it = previous.begin() ; it != previous.end() ; ++it)
+ {
+ if (it != previous.begin()) value << " ";
+ value << *it;
+ }
+
+ switch (part)
+ {
+ case Part_From: m_from = value.str(); break;
+ case Part_By: m_by = value.str(); break;
+ case Part_Via: m_via = value.str(); break;
+ case Part_With: m_with.push_back(value.str()); break;
+ case Part_Id: m_id = value.str(); break;
+ case Part_For: m_for = value.str(); break;
+ default: break; // Should never happen...
+ }
+ }
+
+ previous.clear();
+ part = newPart;
+ }
+ }
+ }
+
+ if (newPosition)
+ *newPosition = end;
+}
+
+
+void relayField::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ std::ostringstream oss;
+ int count = 0;
+
+ if (m_from.length()) oss << (count++ > 0 ? " " : "") << "from " << m_from;
+ if (m_by.length()) oss << (count++ > 0 ? " " : "") << "by " << m_by;
+ if (m_via.length()) oss << (count++ > 0 ? " " : "") << "via " << m_via;
+
+ for (std::vector <string>::const_iterator
+ it = m_with.begin() ; it != m_with.end() ; ++it)
+ {
+ oss << (count++ > 0 ? " " : "") << "with " << *it;
+ }
+
+ if (m_id.length()) oss << (count++ > 0 ? " " : "") << "id " << m_id;
+ if (m_for.length()) oss << (count++ > 0 ? " " : "") << "for " << m_for;
+
+ oss << "; " << m_date.generate();
+
+ string result(oss.str());
+
+ string::size_type pos = curLinePos;
+
+ headerField::generate(os, maxLineLength, pos, &pos);
+
+ encodeAndFoldText(os, text(result), maxLineLength,
+ pos, newLinePos, encodeAndFoldFlags::forceNoEncoding);
+}
+
+
+void relayField::copyFrom(const headerField& field)
+{
+ const relayField& source = dynamic_cast<const relayField&>(field);
+
+ m_from = source.m_from;
+ m_via = source.m_via;
+ m_by = source.m_by;
+ m_id = source.m_id;
+ m_for = source.m_for;
+
+ m_with.resize(source.m_with.size());
+ std::copy(source.m_with.begin(), source.m_with.end(), m_with.begin());
+
+ m_date = source.m_date;
+
+ headerField::copyFrom(field);
+}
+
+
+} // vmime
diff --git a/src/relayField.hpp b/src/relayField.hpp
new file mode 100644
index 00000000..f24be873
--- /dev/null
+++ b/src/relayField.hpp
@@ -0,0 +1,93 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_RELAYFIELD_HPP_INCLUDED
+#define VMIME_RELAYFIELD_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+
+#include "headerFieldFactory.hpp"
+#include "dateTime.hpp"
+
+
+namespace vmime
+{
+
+
+class relayField : public headerField
+{
+ friend class headerFieldFactory::registerer <relayField>;
+
+protected:
+
+ relayField();
+
+public:
+
+ void copyFrom(const headerField& field);
+
+ const string& from() const { return (m_from); }
+ string& from() { return (m_from); }
+
+ const string& via() const { return (m_via); }
+ string& via() { return (m_via); }
+
+ const string& by() const { return (m_by); }
+ string& by() { return (m_by); }
+
+ const string& id() const { return (m_id); }
+ string& id() { return (m_id); }
+
+ const string& for_() const { return (m_for); }
+ string& for_() { return (m_for); }
+
+ const datetime& date() const { return (m_date); }
+ datetime& date() { return (m_date); }
+
+ const std::vector <string>& with() const { return (m_with); }
+ std::vector <string>& with() { return (m_with); }
+
+protected:
+
+ string m_from;
+ string m_via;
+ string m_by;
+ string m_id;
+ string m_for;
+ std::vector <string> m_with;
+
+ datetime m_date;
+
+public:
+
+ using headerField::parse;
+ using headerField::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_RELAYFIELD_HPP_INCLUDED
diff --git a/src/text.cpp b/src/text.cpp
new file mode 100644
index 00000000..db993136
--- /dev/null
+++ b/src/text.cpp
@@ -0,0 +1,240 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "text.hpp"
+
+
+namespace vmime
+{
+
+
+text::text()
+{
+}
+
+
+text::text(const text& t)
+{
+ operator=(t);
+}
+
+
+text::text(const string& t, const charset& ch)
+{
+ makeWordsFromText(t, ch, *this);
+}
+
+
+text::text(const string& t)
+{
+ makeWordsFromText(t, charset::getLocaleCharset(), *this);
+}
+
+
+text::text(const word& w)
+{
+ append(w);
+}
+
+
+text::~text()
+{
+ clear();
+}
+
+
+#if VMIME_WIDE_CHAR_SUPPORT
+
+const wstring text::getDecodedText() const
+{
+ wstring out;
+
+ for (std::vector <word*>::const_iterator i = m_words.begin() ; i != m_words.end() ; ++i)
+ {
+ out += (*i)->getDecodedText();
+ }
+
+ return (out);
+}
+
+#endif
+
+
+void text::append(const word& w)
+{
+ m_words.push_back(new word(w));
+}
+
+
+void text::insert(const iterator it, const word& w)
+{
+ m_words.insert(it.m_iterator, new word(w));
+}
+
+
+void text::clear()
+{
+ free_container(m_words);
+
+ m_words.clear();
+}
+
+
+void text::remove(const iterator it)
+{
+ delete (*it.m_iterator);
+ m_words.erase(it.m_iterator);
+}
+
+
+text& text::operator=(const text& t)
+{
+ clear();
+
+ for (std::vector <word*>::const_iterator i = t.m_words.begin() ; i != t.m_words.end() ; ++i)
+ m_words.push_back(new word(**i));
+
+ return (*this);
+}
+
+
+const bool text::operator==(const text& t) const
+{
+ if (size() == t.size())
+ {
+ bool equal = false;
+
+ std::vector <word*>::const_iterator i = m_words.begin();
+ std::vector <word*>::const_iterator j = t.m_words.begin();
+
+ for ( ; equal && i != m_words.end() ; ++i, ++j)
+ equal = (*i == *j);
+
+ return (equal);
+ }
+
+ return (false);
+}
+
+
+const bool text::operator!=(const text& t) const
+{
+ return !(*this == t);
+}
+
+
+/** Return the text converted into the specified charset.
+ * The encoded-words are decoded and then converted in the
+ * destination charset.
+ *
+ * @param dest output charset
+ * @return text decoded in the specified charset
+ */
+
+const string text::getConvertedText(const charset& dest) const
+{
+ string out;
+
+ for (std::vector <word*>::const_iterator i = m_words.begin() ; i != m_words.end() ; ++i)
+ {
+ out += (*i)->getConvertedText(dest);
+ }
+
+ return (out);
+}
+
+
+/** Check whether the list of encoded-words is empty.
+ *
+ * @return true if the list contains no encoded-word, false otherwise
+ */
+
+const bool text::empty() const
+{
+ return (m_words.size() == 0);
+}
+
+
+/** Return the number of encoded-words in the list.
+ *
+ * @return number of encoded-words
+ */
+
+const size_t text::count() const
+{
+ return (m_words.size());
+}
+
+
+/** Return the number of encoded-words in the list.
+ *
+ * @return number of encoded-words
+ */
+
+const size_t text::size() const
+{
+ return (m_words.size());
+}
+
+
+/** Return the first encoded-word of the list.
+ *
+ * @return first encoded-word
+ */
+
+word& text::front()
+{
+ return (*m_words.front());
+}
+
+
+/** Return the first encoded-word of the list.
+ *
+ * @return first encoded-word
+ */
+
+const word& text::front() const
+{
+ return (*m_words.front());
+}
+
+
+/** Return the last encoded-word of the list.
+ *
+ * @return last encoded-word
+ */
+
+word& text::back()
+{
+ return (*m_words.back());
+}
+
+
+/** Return the last encoded-word of the list.
+ *
+ * @return last encoded-word
+ */
+
+const word& text::back() const
+{
+ return (*m_words.back());
+}
+
+
+} // vmime
diff --git a/src/text.hpp b/src/text.hpp
new file mode 100644
index 00000000..e6339ab9
--- /dev/null
+++ b/src/text.hpp
@@ -0,0 +1,176 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_TEXT_HPP_INCLUDED
+#define VMIME_TEXT_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "word.hpp"
+
+
+namespace vmime
+{
+
+
+/** A class representing a list of encoded-words, as defined
+ * in RFC-2047 (basic type).
+ */
+
+class text
+{
+public:
+
+ text();
+ text(const text& t);
+ text(const string& t, const charset& ch);
+ explicit text(const string& t);
+ explicit text(const word& w);
+ ~text();
+
+public:
+
+ text& operator=(const text& t);
+
+ const bool operator==(const text& t) const;
+ const bool operator!=(const text& t) const;
+
+ // Words iterator
+ class const_iterator;
+
+ class iterator
+ {
+ friend class text::const_iterator;
+ friend class text;
+
+ public:
+
+ typedef std::vector <word*>::iterator::difference_type difference_type;
+
+ iterator(std::vector <word*>::iterator it) : m_iterator(it) { }
+ iterator(const iterator& it) : m_iterator(it.m_iterator) { }
+
+ iterator& operator=(const iterator& it) { m_iterator = it.m_iterator; return (*this); }
+
+ word& operator*() const { return (**m_iterator); }
+ word* operator->() const { return (*m_iterator); }
+
+ iterator& operator++() { ++m_iterator; return (*this); }
+ iterator operator++(int) { iterator i(*this); ++m_iterator; return (i); }
+
+ iterator& operator--() { --m_iterator; return (*this); }
+ iterator operator--(int) { iterator i(*this); --m_iterator; return (i); }
+
+ iterator& operator+=(difference_type n) { m_iterator += n; return (*this); }
+ iterator& operator-=(difference_type n) { m_iterator -= n; return (*this); }
+
+ iterator operator+(difference_type x) const { return iterator(m_iterator + x); }
+ iterator operator-(difference_type x) const { return iterator(m_iterator - x); }
+
+ word& operator[](difference_type n) const { return *(m_iterator[n]); }
+
+ const bool operator==(const iterator& it) const { return (it.m_iterator == m_iterator); }
+ const bool operator!=(const iterator& it) const { return (!(*this == it)); }
+
+ protected:
+
+ std::vector <word*>::iterator m_iterator;
+ };
+
+ class const_iterator
+ {
+ public:
+
+ typedef std::vector <word*>::const_iterator::difference_type difference_type;
+
+ const_iterator(std::vector <word*>::const_iterator it) : m_iterator(it) { }
+ const_iterator(const iterator& it) : m_iterator(it.m_iterator) { }
+ const_iterator(const const_iterator& it) : m_iterator(it.m_iterator) { }
+
+ const_iterator& operator=(const const_iterator& it) { m_iterator = it.m_iterator; return (*this); }
+ const_iterator& operator=(const iterator& it) { m_iterator = it.m_iterator; return (*this); }
+
+ const word& operator*() const { return (**m_iterator); }
+ const word* operator->() const { return (*m_iterator); }
+
+ const_iterator& operator++() { ++m_iterator; return (*this); }
+ const_iterator operator++(int) { const_iterator i(*this); ++m_iterator; return (i); }
+
+ const_iterator& operator--() { --m_iterator; return (*this); }
+ const_iterator operator--(int) { const_iterator i(*this); --m_iterator; return (i); }
+
+ const_iterator& operator+=(difference_type n) { m_iterator += n; return (*this); }
+ const_iterator& operator-=(difference_type n) { m_iterator -= n; return (*this); }
+
+ const_iterator operator+(difference_type x) const { return const_iterator(m_iterator + x); }
+ const_iterator operator-(difference_type x) const { return const_iterator(m_iterator - x); }
+
+ const word& operator[](difference_type n) const { return *(m_iterator[n]); }
+
+ const bool operator==(const const_iterator& it) const { return (it.m_iterator == m_iterator); }
+ const bool operator!=(const const_iterator& it) const { return (!(*this == it)); }
+
+ protected:
+
+ std::vector <word*>::const_iterator m_iterator;
+ };
+
+
+ iterator begin() { return (m_words.begin()); }
+ iterator end() { return (m_words.end()); }
+
+ const_iterator begin() const { return (const_iterator(m_words.begin())); }
+ const_iterator end() const { return (const_iterator(m_words.end())); }
+
+ const word& operator[](const std::vector <word*>::size_type x) const { return (*m_words[x]); }
+ word& operator[](const std::vector <word*>::size_type x) { return (*m_words[x]); }
+
+ // Word manipulation
+ void append(const word& w);
+ void insert(const iterator it, const word& w);
+
+ void clear();
+ void remove(const iterator it);
+
+ // Word count
+ const bool empty() const;
+ const size_t count() const;
+ const size_t size() const;
+
+ word& front();
+ const word& front() const;
+ word& back();
+ const word& back() const;
+
+ // Decoding
+#if VMIME_WIDE_CHAR_SUPPORT
+ const wstring getDecodedText() const;
+#endif
+ const string getConvertedText(const charset& dest) const;
+
+protected:
+
+ std::vector <word*> m_words;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_TEXT_HPP_INCLUDED
diff --git a/src/textField.cpp b/src/textField.cpp
new file mode 100644
index 00000000..0a316af9
--- /dev/null
+++ b/src/textField.cpp
@@ -0,0 +1,69 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "textField.hpp"
+
+
+namespace vmime
+{
+
+
+textField::textField()
+{
+}
+
+
+void textField::parse(const string& buffer, const string::size_type position,
+ const string::size_type end, string::size_type* newPosition)
+{
+ decodeAndUnfoldText(buffer.begin() + position, buffer.begin() + end, m_text);
+
+ if (newPosition)
+ *newPosition = end;
+}
+
+
+void textField::generate(utility::outputStream& os, const string::size_type maxLineLength,
+ const string::size_type curLinePos, string::size_type* newLinePos) const
+{
+ string::size_type pos = curLinePos;
+
+ headerField::generate(os, maxLineLength, pos, &pos);
+
+ encodeAndFoldText(os, m_text, maxLineLength, pos, newLinePos, encodeAndFoldFlags::none);
+}
+
+
+void textField::copyFrom(const headerField& field)
+{
+ const textField& source = dynamic_cast<const textField&>(field);
+ m_text = source.m_text;
+
+ headerField::copyFrom(field);
+}
+
+
+textField& textField::operator=(const text& value)
+{
+ m_text = value;
+ return (*this);
+}
+
+
+} // vmime
diff --git a/src/textField.hpp b/src/textField.hpp
new file mode 100644
index 00000000..1e672202
--- /dev/null
+++ b/src/textField.hpp
@@ -0,0 +1,70 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_TEXTFIELD_HPP_INCLUDED
+#define VMIME_TEXTFIELD_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "component.hpp"
+
+#include "headerFieldFactory.hpp"
+#include "text.hpp"
+
+
+namespace vmime
+{
+
+
+class textField : public headerField
+{
+ friend class headerFieldFactory::registerer <textField>;
+
+protected:
+
+ textField();
+
+public:
+
+ void copyFrom(const headerField& field);
+
+ textField& operator=(const text& value);
+
+ const text& value() const { return (m_text); }
+ text& value() { return (m_text); }
+
+protected:
+
+ text m_text;
+
+public:
+
+ using headerField::parse;
+ using headerField::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_TEXTFIELD_HPP_INCLUDED
diff --git a/src/textParameter.cpp b/src/textParameter.cpp
new file mode 100644
index 00000000..402d8d1f
--- /dev/null
+++ b/src/textParameter.cpp
@@ -0,0 +1,50 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "textParameter.hpp"
+#include "parserHelpers.hpp"
+
+
+namespace vmime
+{
+
+
+void textParameter::parseValue(const string& buffer, const string::size_type position,
+ const string::size_type end)
+{
+ m_value = string(buffer.begin() + position, buffer.begin() + end);
+}
+
+
+const string textParameter::generateValue() const
+{
+ return (m_value);
+}
+
+
+void textParameter::copyFrom(const parameter& param)
+{
+ const textParameter& source = dynamic_cast<const textParameter&>(param);
+ m_value = source.m_value;
+
+ defaultParameter::copyFrom(param);
+}
+
+
+} // vmime
diff --git a/src/textParameter.hpp b/src/textParameter.hpp
new file mode 100644
index 00000000..a3332a84
--- /dev/null
+++ b/src/textParameter.hpp
@@ -0,0 +1,54 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_TEXTPARAMETER_HPP_INCLUDED
+#define VMIME_TEXTPARAMETER_HPP_INCLUDED
+
+
+#include "defaultParameter.hpp"
+
+
+namespace vmime
+{
+
+
+class textParameter : public defaultParameter
+{
+protected:
+
+ string m_value;
+
+public:
+
+ void copyFrom(const parameter& param);
+
+ const string& value() const { return (m_value); }
+ string& value() { return (m_value); }
+
+protected:
+
+ void parseValue(const string& buffer, const string::size_type position, const string::size_type end);
+ const string generateValue() const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_TEXTPARAMETER_HPP_INCLUDED
diff --git a/src/textPart.hpp b/src/textPart.hpp
new file mode 100644
index 00000000..ed07f0b7
--- /dev/null
+++ b/src/textPart.hpp
@@ -0,0 +1,66 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_TEXTPART_HPP_INCLUDED
+#define VMIME_TEXTPART_HPP_INCLUDED
+
+
+#include "bodyPart.hpp"
+
+#include "mediaType.hpp"
+#include "charset.hpp"
+#include "contentHandler.hpp"
+
+
+namespace vmime
+{
+
+
+class textPart
+{
+ friend class textPartFactory;
+ friend class messageBuilder; // for generateIn, getPartCount
+ friend class messageParser; // for parse
+
+public:
+
+ virtual ~textPart() { }
+
+
+ virtual const mediaType type() const = 0;
+
+ virtual const class charset& charset() const = 0;
+ virtual class charset& charset() = 0;
+
+ virtual const contentHandler& text() const = 0;
+ virtual contentHandler& text() = 0;
+
+protected:
+
+ virtual const int getPartCount() const = 0;
+
+ virtual void generateIn(bodyPart& message, bodyPart& parent) const = 0;
+ virtual void parse(const bodyPart& message, const bodyPart& parent, const bodyPart& textPart) = 0;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_TEXTPART_HPP_INCLUDED
diff --git a/src/textPartFactory.cpp b/src/textPartFactory.cpp
new file mode 100644
index 00000000..c8fc37eb
--- /dev/null
+++ b/src/textPartFactory.cpp
@@ -0,0 +1,60 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "textPartFactory.hpp"
+#include "exception.hpp"
+
+
+#include "plainTextPart.hpp"
+#include "htmlTextPart.hpp"
+
+
+namespace vmime
+{
+
+
+textPartFactory::textPartFactory()
+{
+ // Register some default names
+ registerType <plainTextPart>(mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN));
+ registerType <htmlTextPart>(mediaType(mediaTypes::TEXT, mediaTypes::TEXT_HTML));
+}
+
+
+textPartFactory::~textPartFactory()
+{
+}
+
+
+textPart* textPartFactory::create(const mediaType& type)
+{
+ NameMap::const_iterator pos = m_nameMap.find(type.generate());
+
+ if (pos != m_nameMap.end())
+ {
+ return ((*pos).second)();
+ }
+ else
+ {
+ throw exceptions::no_factory_available();
+ }
+}
+
+
+} // vmime
diff --git a/src/textPartFactory.hpp b/src/textPartFactory.hpp
new file mode 100644
index 00000000..15969c93
--- /dev/null
+++ b/src/textPartFactory.hpp
@@ -0,0 +1,74 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_TEXTPARTFACTORY_HPP_INCLUDED
+#define VMIME_TEXTPARTFACTORY_HPP_INCLUDED
+
+
+#include "textPart.hpp"
+#include "mediaType.hpp"
+#include "utility/singleton.hpp"
+
+
+namespace vmime
+{
+
+
+class textPartFactory : public utility::singleton <textPartFactory>
+{
+ friend class utility::singleton <textPartFactory>;
+
+protected:
+
+ textPartFactory();
+ ~textPartFactory();
+
+ typedef textPart* (*AllocFunc)(void);
+ typedef std::map <string, AllocFunc> NameMap;
+
+ NameMap m_nameMap;
+
+ template <class TYPE>
+ class registerer
+ {
+ public:
+
+ static textPart* creator()
+ {
+ // Allocate a new object
+ return new TYPE();
+ }
+ };
+
+public:
+
+ template <class T>
+ void registerType(const mediaType& type)
+ {
+ m_nameMap.insert(NameMap::value_type(toLower(type.generate()), &registerer<T>::creator));
+ }
+
+ textPart* create(const mediaType& type);
+};
+
+
+} // vmime
+
+
+#endif // VMIME_TEXTPARTFACTORY_HPP_INCLUDED
diff --git a/src/types.hpp b/src/types.hpp
new file mode 100644
index 00000000..fa37c6dc
--- /dev/null
+++ b/src/types.hpp
@@ -0,0 +1,43 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_TYPES_HPP_INCLUDED
+#define VMIME_TYPES_HPP_INCLUDED
+
+
+#include <string>
+#include <limits>
+
+#include "config.hpp"
+
+
+namespace vmime
+{
+ typedef std::string string;
+#if VMIME_WIDE_CHAR_SUPPORT
+ typedef std::wstring wstring;
+#endif
+
+ typedef unsigned short port_t;
+
+ typedef int char_t;
+}
+
+
+#endif // VMIME_TYPES_HPP_INCLUDED
diff --git a/src/utility/file.hpp b/src/utility/file.hpp
new file mode 100644
index 00000000..f4d63bc2
--- /dev/null
+++ b/src/utility/file.hpp
@@ -0,0 +1,218 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_UTILITY_FILE_HPP_INCLUDED
+#define VMIME_UTILITY_FILE_HPP_INCLUDED
+
+
+#include "path.hpp"
+#include "../config.hpp"
+
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+namespace vmime {
+namespace utility {
+
+
+class file;
+
+
+/** File list iterator (see file::getFiles).
+ */
+
+class fileIterator
+{
+public:
+
+ virtual ~fileIterator() { }
+
+ /** Check whether the cursor has reach the end of the list.
+ *
+ * @return true if you can call nextElement(), or false
+ * if no more file is available
+ */
+ virtual const bool hasMoreElements() const = 0;
+
+ /** Return the next file in the list.
+ *
+ * @return next file or NULL
+ */
+ virtual file* nextElement() = 0;
+};
+
+
+// TODO: fileWriter
+
+class fileWriter
+{
+public:
+
+ virtual ~fileWriter() { }
+
+ virtual utility::outputStream* getOutputStream() = 0;
+};
+
+
+// TODO: fileReader
+
+class fileReader
+{
+public:
+
+ virtual ~fileReader() { }
+
+ virtual utility::inputStream* getInputStream() = 0;
+};
+
+
+/** Abstract representation of a file or directory.
+ */
+
+class file
+{
+public:
+
+ typedef utility::path path;
+ typedef long length_type;
+
+
+ virtual ~file() { }
+
+
+ /** Create the file pointed by this file object.
+ */
+ virtual void createFile() = 0;
+
+ /** Create the directory pointed by this file object.
+ *
+ * @param createAll if set to true, recursively create all
+ * parent directories if they do not exist
+ */
+ virtual void createDirectory(const bool createAll = false) = 0;
+
+ /** Test whether this is a file.
+ *
+ * @return true if this is a file, false otherwise
+ */
+ virtual const bool isFile() const = 0;
+
+ /** Test whether this is a directory.
+ *
+ * @return true if this is a directory, false otherwise
+ */
+ virtual const bool isDirectory() const = 0;
+
+ /** Test whether this file is readible.
+ *
+ * @return true if we can read this file, false otherwise
+ */
+ virtual const bool canRead() const = 0;
+
+ /** Test whether this file is writeable.
+ *
+ * @return true if we can write to this file, false otherwise
+ */
+ virtual const bool canWrite() const = 0;
+
+ /** Return the length of this file.
+ *
+ * @return file size (in bytes)
+ */
+ virtual const length_type length() = 0;
+
+ /** Return the full path of this file/directory.
+ *
+ * @return full path of the file
+ */
+ virtual const path& fullPath() const = 0;
+
+ /** Test whether this file/directory exists.
+ *
+ * @return true if the file exists, false otherwise
+ */
+ virtual const bool exists() const = 0;
+
+ /** Return the parent directory of this file/directory.
+ *
+ * @return parent directory (or NULL if root)
+ */
+ virtual const file* getParent() const = 0;
+
+ /** Rename the file/directory.
+ *
+ * @param newName full path of the new file
+ */
+ virtual void rename(const path& newName) = 0;
+
+ /** Deletes this file/directory.
+ */
+ virtual void remove() = 0;
+
+
+ // TODO virtual fileWriter* getFileWriter() = 0;
+ // TODO virtual fileReader* getFileReader() = 0;
+
+ /** Enumerate files contained in this directory.
+ *
+ * @return file iterator to enumerate files
+ * @throw exceptions::not_a_directory if this is not a directory
+ */
+ virtual fileIterator* getFiles() const;
+};
+
+
+class fileSystemFactory
+{
+public:
+
+ virtual ~fileSystemFactory() { }
+
+ /** Create a new file object from the specified path.
+ *
+ * @param path full path (absolute) of the file
+ * @return new file object for the path
+ */
+ virtual file* create(const file::path& path) = 0;
+
+ /** Parse a path contained in a string.
+ *
+ * @param str string containing a path in a system-dependant representation
+ * @return path object (abstract representation)
+ */
+ virtual file::path stringToPath(const string& str) = 0;
+
+ /** Return the system-dependant string representation for the specified path.
+ *
+ * @param path abstract representation of the path
+ * @return string representation of the path
+ */
+ virtual string pathToString(const file::path& path) = 0;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+#endif // VMIME_UTILITY_FILE_HPP_INCLUDED
diff --git a/src/utility/md5.cpp b/src/utility/md5.cpp
new file mode 100644
index 00000000..e181a5d0
--- /dev/null
+++ b/src/utility/md5.cpp
@@ -0,0 +1,331 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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.
+//
+//
+// Derived from cryptoapi implementation, originally based on the
+// public domain implementation written by Colin Plumb in 1993.
+//
+// Copyright (C) Cryptoapi developers.
+//
+// Algorithm Copyright:
+//
+// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+// rights reserved.
+//
+// License to copy and use this software is granted provided that it
+// is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+// Algorithm" in all material mentioning or referencing this software
+// or this function.
+//
+// License is also granted to make and use derivative works provided
+// that such works are identified as "derived from the RSA Data
+// Security, Inc. MD5 Message-Digest Algorithm" in all material
+// mentioning or referencing the derived work.
+//
+// RSA Data Security, Inc. makes no representations concerning either
+// the merchantability of this software or the suitability of this
+// software forany particular purpose. It is provided "as is"
+// without express or implied warranty of any kind.
+// These notices must be retained in any copies of any part of this
+// documentation and/or software.
+
+#include "md5.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+md5::md5()
+ : m_finalized(false)
+{
+ init();
+}
+
+
+md5::md5(const vmime_uint8* const in, const unsigned long length)
+ : m_finalized(false)
+{
+ init();
+ update(in, length);
+}
+
+
+md5::md5(const string& in)
+ : m_finalized(false)
+{
+ init();
+ update((vmime_uint8*) in.c_str(), in.length());
+}
+
+
+void md5::init()
+{
+ m_hash[0] = 0x67452301;
+ m_hash[1] = 0xefcdab89;
+ m_hash[2] = 0x98badcfe;
+ m_hash[3] = 0x10325476;
+
+ m_byteCount = 0;
+}
+
+
+static void copyUint8Array(vmime_uint8* dest, const vmime_uint8* src, unsigned long count)
+{
+ for ( ; count >= 4 ; count -= 4, dest += 4, src += 4)
+ {
+ dest[0] = src[0];
+ dest[1] = src[1];
+ dest[2] = src[2];
+ dest[3] = src[3];
+ }
+
+ for ( ; count ; --count, ++dest, ++src)
+ dest[0] = src[0];
+}
+
+
+void md5::update(const string& in)
+{
+ update((vmime_uint8*) in.c_str(), in.length());
+}
+
+
+void md5::update(const vmime_uint8* data, unsigned long len)
+{
+ if (m_finalized)
+ return;
+
+ const unsigned long avail = 64 - (m_byteCount & 0x3f);
+
+ m_byteCount += len;
+
+ if (avail > len)
+ {
+ copyUint8Array(m_block + (64 - avail), data, len);
+ return;
+ }
+
+ copyUint8Array(m_block + (64 - avail), data, avail);
+ transformHelper();
+
+ data += avail;
+ len -= avail;
+
+ while (len >= 64)
+ {
+ copyUint8Array(m_block, data, 64);
+ transformHelper();
+
+ data += 64;
+ len -= 64;
+ }
+
+ copyUint8Array(m_block, data, len);
+}
+
+
+void md5::finalize()
+{
+ const long offset = m_byteCount & 0x3f;
+
+ vmime_uint8* p = m_block + offset;
+ long padding = 56 - (offset + 1);
+
+ *p++ = 0x80;
+
+ if (padding < 0)
+ {
+ memset(p, 0x00, padding + 8);
+ transformHelper();
+ p = m_block;
+ padding = 56;
+ }
+
+ memset(p, 0, padding);
+
+ ((vmime_uint32*) m_block)[14] = (m_byteCount << 3);
+ ((vmime_uint32*) m_block)[15] = (m_byteCount >> 29);
+
+#if VMIME_BYTE_ORDER_BIG_ENDIAN
+ swapUint32Array((vmime_uint32*) m_block, (64 - 8) / 4);
+#endif
+
+ transform();
+
+#if VMIME_BYTE_ORDER_BIG_ENDIAN
+ swapUint32Array((vmime_uint32*) m_hash, 4);
+#endif
+
+ m_finalized = true;
+}
+
+
+static inline vmime_uint32 swapUint32(const vmime_uint32 D)
+{
+ return ((D << 24) | ((D << 8) & 0x00FF0000) | ((D >> 8) & 0x0000FF00) | (D >> 24));
+}
+
+
+static inline void swapUint32Array(vmime_uint32* buf, unsigned long words)
+{
+ for ( ; words >= 4 ; words -= 4, buf += 4)
+ {
+ buf[0] = swapUint32(buf[0]);
+ buf[1] = swapUint32(buf[1]);
+ buf[2] = swapUint32(buf[2]);
+ buf[3] = swapUint32(buf[3]);
+ }
+
+ for ( ; words ; --words, ++buf)
+ buf[0] = swapUint32(buf[0]);
+}
+
+
+void md5::transformHelper()
+{
+#if VMIME_BYTE_ORDER_BIG_ENDIAN
+ swapUint32Array((vmime_uint32*) m_block, 64 / 4);
+#endif
+ transform();
+}
+
+
+void md5::transform()
+{
+ const vmime_uint32* const in = (vmime_uint32*) m_block;
+
+ vmime_uint32 a = m_hash[0];
+ vmime_uint32 b = m_hash[1];
+ vmime_uint32 c = m_hash[2];
+ vmime_uint32 d = m_hash[3];
+
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+#define MD5STEP(f, w, x, y, z, in, s) \
+ (w += f(x, y, z) + in, w = (w<<s | w>>(32-s)) + x)
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ m_hash[0] += a;
+ m_hash[1] += b;
+ m_hash[2] += c;
+ m_hash[3] += d;
+}
+
+
+const string md5::hex()
+{
+ if (!m_finalized)
+ finalize();
+
+ static const unsigned char hex[] = "0123456789abcdef";
+
+ std::ostringstream oss;
+ const vmime_uint8* const digest = (vmime_uint8*) m_hash;
+
+ for (int i = 0 ; i < 16 ; ++i)
+ {
+ oss << hex[(digest[i] & 0xf0) >> 4];
+ oss << hex[(digest[i] & 0x0f)];
+ }
+
+ return (oss.str());
+}
+
+
+const vmime_uint8* md5::hash()
+{
+ if (!m_finalized)
+ finalize();
+
+ return ((vmime_uint8*) m_hash);
+}
+
+
+} // utility
+} // vmime
diff --git a/src/utility/md5.hpp b/src/utility/md5.hpp
new file mode 100644
index 00000000..dc9bb384
--- /dev/null
+++ b/src/utility/md5.hpp
@@ -0,0 +1,68 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_UTILITY_MD5_HPP_INCLUDED
+#define VMIME_UTILITY_MD5_HPP_INCLUDED
+
+
+#include "base.hpp"
+#include "config.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+class md5
+{
+public:
+
+ md5();
+ md5(const vmime_uint8* const in, const unsigned long length);
+ md5(const string& in);
+
+public:
+
+ const string hex();
+ const vmime_uint8* hash();
+
+ void update(const vmime_uint8* data, unsigned long len);
+ void update(const string& in);
+
+protected:
+
+ void init();
+ void transformHelper();
+ void transform();
+ void finalize();
+
+ vmime_uint32 m_hash[4];
+
+ unsigned long m_byteCount;
+ vmime_uint8 m_block[64];
+
+ bool m_finalized;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_MD5_HPP_INCLUDED
diff --git a/src/utility/path.cpp b/src/utility/path.cpp
new file mode 100644
index 00000000..477f29dd
--- /dev/null
+++ b/src/utility/path.cpp
@@ -0,0 +1,196 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "path.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace utility {
+
+
+path::path()
+{
+}
+
+
+path::path(const component& c)
+{
+ m_list.push_back(c);
+}
+
+
+path::path(const path& p)
+{
+ m_list.resize(p.m_list.size());
+ std::copy(p.m_list.begin(), p.m_list.end(), m_list.begin());
+}
+
+
+path::path(const string& s)
+{
+ m_list.push_back(component(s));
+}
+
+
+path path::operator/(const path& p) const
+{
+ path pr(*this);
+ pr /= p;
+
+ return (pr);
+}
+
+
+path path::operator/(const component& c) const
+{
+ path pr(*this);
+ pr /= c;
+
+ return (pr);
+}
+
+
+path& path::operator/=(const path& p)
+{
+ const list::size_type size = m_list.size();
+
+ m_list.resize(size + p.m_list.size());
+ std::copy(p.m_list.begin(), p.m_list.end(), m_list.begin() + size);
+
+ return (*this);
+}
+
+
+path& path::operator/=(const component& c)
+{
+ m_list.push_back(c);
+ return (*this);
+}
+
+
+path path::parent() const
+{
+ path p;
+
+ if (!empty())
+ {
+ p.m_list.resize(m_list.size() - 1);
+ std::copy(m_list.begin(), m_list.end() - 1, p.m_list.begin());
+ }
+
+ return (p);
+}
+
+
+path& path::operator=(const path& p)
+{
+ m_list.resize(p.m_list.size());
+ std::copy(p.m_list.begin(), p.m_list.end(), m_list.begin());
+
+ return (*this);
+}
+
+
+path& path::operator=(const component& c)
+{
+ m_list.resize(1);
+ m_list[0] = c;
+
+ return (*this);
+}
+
+
+const bool path::operator==(const path& p) const
+{
+ if (m_list.size() != p.m_list.size())
+ return (false);
+
+ list::const_iterator i = m_list.begin();
+ list::const_iterator j = p.m_list.begin();
+
+ bool equal = true;
+
+ for ( ; equal && i != m_list.end() ; ++i, ++j)
+ //equal = (*i == *j);
+ equal = ((*i).buffer() == (*j).buffer());
+
+ return (equal);
+}
+
+
+const bool path::operator!=(const path& p) const
+{
+ return (!(*this == p));
+}
+
+
+const bool path::empty() const
+{
+ return (m_list.empty());
+}
+
+
+const path::component path::last() const
+{
+ return (empty() ? component("") : m_list[m_list.size() - 1]);
+}
+
+
+path::component& path::last()
+{
+ return (m_list[m_list.size() - 1]);
+}
+
+
+const int path::size() const
+{
+ return (m_list.size());
+}
+
+
+const path::component& path::operator[](const int x) const
+{
+ return (m_list[x]);
+}
+
+
+path::component& path::operator[](const int x)
+{
+ return (m_list[x]);
+}
+
+
+const bool path::isDirectParentOf(const path& p) const
+{
+ if (p.size() != size() + 1)
+ return (false);
+
+ bool equal = true;
+
+ for (int i = 0 ; equal && i < size() ; ++i)
+ equal = (m_list[i] == p.m_list[i]);
+
+ return (equal);
+}
+
+
+} // utility
+} // vmime
diff --git a/src/utility/path.hpp b/src/utility/path.hpp
new file mode 100644
index 00000000..bc980889
--- /dev/null
+++ b/src/utility/path.hpp
@@ -0,0 +1,124 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_UTILITY_PATH_HPP_INCLUDED
+#define VMIME_UTILITY_PATH_HPP_INCLUDED
+
+
+#include <vector>
+
+#include "../types.hpp"
+#include "../word.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** Abstract representation of a path (filesystem, mailbox, etc).
+ */
+
+class path
+{
+public:
+
+ typedef vmime::word component;
+ typedef std::vector <component> list;
+
+ // Construct a path
+ path();
+ path(const component& c);
+ path(const path& p);
+ path(const string& s);
+
+ // Append a component to a path
+ path operator/(const path& p) const;
+ path operator/(const component& c) const;
+
+ path& operator/=(const path& p);
+ path& operator/=(const component& c);
+
+ // Return the parent path
+ path parent() const;
+
+ // Assignment
+ path& operator=(const path& p);
+ path& operator=(const component& c);
+
+ // Path comparison
+ const bool operator==(const path& p) const;
+ const bool operator!=(const path& p) const;
+
+ /** Test whether this path is empty (root).
+ *
+ * @return true if the path is empty (no components = root)
+ */
+ const bool empty() const;
+
+ /** Return the last component of this path (const version).
+ *
+ * @return last component
+ */
+ const component last() const;
+
+ /** Return the last component of this path (non-const version).
+ *
+ * @return last component
+ */
+ component& last();
+
+ /** Return the number of components in this path.
+ *
+ * @return number of components
+ */
+ const int size() const;
+
+ /** Return the specified component of the path (const version).
+ *
+ * @param x index of the component
+ * @return component at the specified index
+ */
+ const component& operator[](const int x) const;
+
+ /** Return the specified component of the path (non-const version).
+ *
+ * @param x index of the component
+ * @return component at the specified index
+ */
+ component& operator[](const int x);
+
+ /** Test whether this path is a direct parent of another one.
+ *
+ * @param p other path
+ * @return true if the specified path is a child (direct or
+ * indirect) of this path, false otherwise
+ */
+ const bool isDirectParentOf(const path& p) const;
+
+private:
+
+ list m_list;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_PATH_HPP_INCLUDED
diff --git a/src/utility/random.cpp b/src/utility/random.cpp
new file mode 100644
index 00000000..6896d83c
--- /dev/null
+++ b/src/utility/random.cpp
@@ -0,0 +1,59 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "random.hpp"
+#include "platformDependant.hpp"
+
+#include <ctime>
+
+
+namespace vmime {
+namespace utility {
+
+
+unsigned int random::m_next(static_cast<unsigned int>(::std::time(NULL)));
+
+
+const unsigned int random::next()
+{
+ // Park and Miller's minimal standard generator:
+ // xn+1 = (a * xn + b) mod c
+ // xn+1 = (16807 * xn) mod (2^31 - 1)
+ static const unsigned long a = 16807;
+ static const unsigned long c = (1 << ((sizeof(int) << 3) - 1));
+
+ m_next = static_cast<unsigned int>((a * m_next) % c);
+ return (m_next);
+}
+
+
+const unsigned int random::time()
+{
+ return (platformDependant::getHandler()->getUnixTime());
+}
+
+
+const unsigned int random::process()
+{
+ return (platformDependant::getHandler()->getProcessId());
+}
+
+
+} // utility
+} // vmime
diff --git a/src/utility/random.hpp b/src/utility/random.hpp
new file mode 100644
index 00000000..0d9dd92a
--- /dev/null
+++ b/src/utility/random.hpp
@@ -0,0 +1,62 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_UTILITY_RANDOM_HPP_INCLUDED
+#define VMIME_UTILITY_RANDOM_HPP_INCLUDED
+
+
+namespace vmime {
+namespace utility {
+
+
+class random
+{
+public:
+
+ /** Return a new random number.
+ *
+ * @return random number
+ */
+ static const unsigned int next();
+
+ /** Return the current time as a number (may be used to
+ * build "random" strings).
+ *
+ * @return time as a number
+ */
+ static const unsigned int time();
+
+ /** Return the current process number (may be user to
+ * build "random" strings).
+ *
+ * @return process number
+ */
+ static const unsigned int process();
+
+protected:
+
+ static unsigned int m_next;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_RANDOM_HPP_INCLUDED
diff --git a/src/utility/singleton.cpp b/src/utility/singleton.cpp
new file mode 100644
index 00000000..c960a64a
--- /dev/null
+++ b/src/utility/singleton.cpp
@@ -0,0 +1,53 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "singleton.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+singletonManager::singletonManager()
+{
+}
+
+
+singletonManager::~singletonManager()
+{
+ for (std::list <abstractSingleton*>::iterator it = m_list.begin() ; it != m_list.end() ; ++it)
+ delete (*it);
+}
+
+
+singletonManager* singletonManager::getInstance()
+{
+ static singletonManager inst;
+ return (&inst);
+}
+
+
+void singletonManager::manage(abstractSingleton* s)
+{
+ m_list.push_back(s);
+}
+
+
+} // utility
+} // vmime
diff --git a/src/utility/singleton.hpp b/src/utility/singleton.hpp
new file mode 100644
index 00000000..33def75b
--- /dev/null
+++ b/src/utility/singleton.hpp
@@ -0,0 +1,92 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_UTILITY_SINGLETON_HPP_INCLUDED
+#define VMIME_UTILITY_SINGLETON_HPP_INCLUDED
+
+
+#include <list>
+
+
+namespace vmime {
+namespace utility {
+
+
+// Singleton abstract base class.
+
+class abstractSingleton
+{
+ friend class singletonManager;
+
+protected:
+
+ abstractSingleton() { }
+ virtual ~abstractSingleton() { }
+};
+
+
+// Singleton manager
+// (for automatic clean-up of all instanciated singletons).
+
+class singletonManager
+{
+public:
+
+ static singletonManager* getInstance();
+
+ void manage(abstractSingleton* s);
+
+private:
+
+ singletonManager();
+ ~singletonManager();
+
+ std::list <abstractSingleton*> m_list;
+};
+
+
+// A singleton template.
+
+template <class TYPE>
+class singleton : public abstractSingleton
+{
+protected:
+
+ singleton() { }
+ ~singleton() { }
+
+public:
+
+ static TYPE* getInstance()
+ {
+ static TYPE* inst = NULL;
+
+ if (!inst)
+ singletonManager::getInstance()->manage(inst = new TYPE());
+
+ return (inst);
+ }
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_SINGLETON_HPP_INCLUDED
diff --git a/src/utility/smartPtr.hpp b/src/utility/smartPtr.hpp
new file mode 100644
index 00000000..9905ae2f
--- /dev/null
+++ b/src/utility/smartPtr.hpp
@@ -0,0 +1,166 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_UTILITY_SMARTPTR_HPP_INCLUDED
+#define VMIME_UTILITY_SMARTPTR_HPP_INCLUDED
+
+
+namespace vmime {
+namespace utility {
+
+
+/** Simple auto-delete pointer.
+ */
+
+template <class T>
+class auto_ptr
+{
+private:
+
+ T* const m_ptr;
+
+public:
+
+ auto_ptr(T* const ptr) : m_ptr(ptr) { }
+ ~auto_ptr() { delete (m_ptr); }
+
+ operator T*() { return (m_ptr); }
+
+ T* const operator ->() { return (m_ptr); }
+ T& operator *() { return (*m_ptr); }
+};
+
+
+/** Smart auto-delete, referencable and copiable pointer.
+ */
+
+template <class T>
+class smart_ptr
+{
+private:
+
+ struct data
+ {
+ int refCount;
+ T* ptr;
+ };
+
+ data* m_data;
+
+
+ typedef std::map <T*, data*> MapType;
+ static MapType sm_map;
+
+public:
+
+ smart_ptr() : m_data(NULL) { }
+ smart_ptr(T* const ptr) : m_data(NULL) { if (ptr) { attach(ptr); } }
+ smart_ptr(smart_ptr& ptr) : m_data(NULL) { if (ptr.m_data) { attach(ptr); } }
+
+ ~smart_ptr() { detach(); }
+
+ smart_ptr& operator=(smart_ptr& ptr)
+ {
+ attach(ptr);
+ return (*this);
+ }
+
+ smart_ptr& operator=(T* const ptr)
+ {
+ if (!ptr)
+ detach();
+ else
+ attach(ptr);
+
+ return (*this);
+ }
+
+ operator T*() { return (m_data ? m_data->ptr : NULL); }
+ operator const T*() { return (m_data ? m_data->ptr : NULL); }
+
+ T& operator *() { return (*(m_data->ptr)); }
+ T* operator ->() { return (m_data->ptr); }
+
+ const T* const ptr() const { return (m_data ? m_data->ptr : NULL); }
+ T* const ptr() { return (m_data ? m_data->ptr : NULL); }
+
+private:
+
+ void detach()
+ {
+ if (m_data)
+ {
+ if (m_data->refCount == 1)
+ {
+ typename MapType::iterator it = sm_map.find(m_data->ptr);
+ if (it != sm_map.end()) sm_map.erase(it);
+
+ delete (m_data->ptr);
+ delete (m_data);
+ }
+ else
+ {
+ m_data->refCount--;
+ }
+
+ m_data = NULL;
+ }
+ }
+
+ void attach(T* const ptr)
+ {
+ detach();
+
+ typename MapType::iterator it = sm_map.find(ptr);
+
+ if (it != sm_map.end())
+ {
+ (*it).second->refCount++;
+ }
+ else
+ {
+ m_data = new data;
+ m_data->refCount = 1;
+ m_data->ptr = ptr;
+
+ sm_map.insert(typename MapType::value_type(ptr, m_data));
+ }
+ }
+
+ void attach(smart_ptr <T>& ptr)
+ {
+ data* newData = ptr.m_data;
+ if (newData) newData->refCount++;
+
+ detach();
+
+ m_data = newData;
+ }
+};
+
+
+template <class T>
+typename smart_ptr <T>::MapType smart_ptr <T>::sm_map;
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_SMARTPTR_HPP_INCLUDED
diff --git a/src/utility/stream.cpp b/src/utility/stream.cpp
new file mode 100644
index 00000000..06d4ba27
--- /dev/null
+++ b/src/utility/stream.cpp
@@ -0,0 +1,257 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "stream.hpp"
+#include "stringProxy.hpp"
+
+#include <algorithm> // for std::copy
+#include <iterator> // for std::back_inserter
+
+
+namespace vmime {
+namespace utility {
+
+
+// Helpers
+
+outputStream& operator<<(outputStream& os, const stream::value_type c)
+{
+ os.write(&c, 1);
+ return (os);
+}
+
+
+outputStream& operator<<(outputStream& os, const string& str)
+{
+ os.write(str.data(), str.length());
+ return (os);
+}
+
+
+const stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os)
+{
+ stream::value_type buffer[65536];
+ stream::size_type total = 0;
+
+ while (!is.eof())
+ {
+ const stream::size_type read = is.read(buffer, sizeof(buffer));
+
+ if (read != 0)
+ {
+ os.write(buffer, read);
+ total += read;
+ }
+ }
+
+ return (total);
+}
+
+
+
+// outputStreamAdapter
+
+outputStreamAdapter::outputStreamAdapter(std::ostream& os)
+ : m_stream(os)
+{
+}
+
+
+void outputStreamAdapter::write
+ (const value_type* const data, const size_type count)
+{
+ m_stream.write(data, count);
+}
+
+
+
+// outputStreamStringAdapter
+
+outputStreamStringAdapter::outputStreamStringAdapter(string& buffer)
+ : m_buffer(buffer)
+{
+ m_buffer.clear();
+}
+
+
+void outputStreamStringAdapter::write(const value_type* const data, const size_type count)
+{
+ // TODO: better way?
+ std::copy(data, data + count, std::back_inserter(m_buffer));
+}
+
+
+
+// inputStreamAdapter
+
+inputStreamAdapter::inputStreamAdapter(std::istream& is)
+ : m_stream(is)
+{
+}
+
+
+const bool inputStreamAdapter::eof() const
+{
+ return (m_stream.eof());
+}
+
+
+void inputStreamAdapter::reset()
+{
+ m_stream.seekg(0, std::ios::beg);
+ m_stream.clear();
+}
+
+
+const stream::size_type inputStreamAdapter::read
+ (value_type* const data, const size_type count)
+{
+ m_stream.read(data, count);
+ return (m_stream.gcount());
+}
+
+
+
+// inputStreamStringAdapter
+
+inputStreamStringAdapter::inputStreamStringAdapter(const string& buffer)
+ : m_buffer(buffer), m_begin(0), m_end(buffer.length()), m_pos(0)
+{
+}
+
+
+inputStreamStringAdapter::inputStreamStringAdapter(const string& buffer,
+ const string::size_type begin, const string::size_type end)
+ : m_buffer(buffer), m_begin(begin), m_end(end), m_pos(begin)
+{
+}
+
+
+const bool inputStreamStringAdapter::eof() const
+{
+ return (m_pos >= m_end);
+}
+
+
+void inputStreamStringAdapter::reset()
+{
+ m_pos = m_begin;
+}
+
+
+const stream::size_type inputStreamStringAdapter::read
+ (value_type* const data, const size_type count)
+{
+ if (m_pos + count >= m_end)
+ {
+ const size_type remaining = m_end - m_pos;
+
+ std::copy(m_buffer.begin() + m_pos, m_buffer.end(), data);
+ m_pos = m_end;
+ return (remaining);
+ }
+ else
+ {
+ std::copy(m_buffer.begin() + m_pos, m_buffer.begin() + m_pos + count, data);
+ m_pos += count;
+ return (count);
+ }
+}
+
+
+
+// inputStreamStringProxyAdapter
+
+inputStreamStringProxyAdapter::inputStreamStringProxyAdapter(const stringProxy& buffer)
+ : m_buffer(buffer), m_pos(0)
+{
+}
+
+
+const bool inputStreamStringProxyAdapter::eof() const
+{
+ return (m_pos >= m_buffer.length());
+}
+
+
+void inputStreamStringProxyAdapter::reset()
+{
+ m_pos = 0;
+}
+
+
+const stream::size_type inputStreamStringProxyAdapter::read
+ (value_type* const data, const size_type count)
+{
+ const size_type remaining = m_buffer.length() - m_pos;
+
+ if (count > remaining)
+ {
+ std::copy(m_buffer.it_begin() + m_pos, m_buffer.it_end(), data);
+ m_pos = m_buffer.length();
+ return (remaining);
+ }
+ else
+ {
+ std::copy(m_buffer.it_begin() + m_pos, m_buffer.it_begin() + m_pos + count, data);
+ m_pos += count;
+ return (count);
+ }
+}
+
+
+
+// inputStreamPointerAdapter
+
+inputStreamPointerAdapter::inputStreamPointerAdapter(std::istream* is, const bool own)
+ : m_stream(is), m_own(own)
+{
+}
+
+
+inputStreamPointerAdapter::~inputStreamPointerAdapter()
+{
+ if (m_own)
+ delete (m_stream);
+}
+
+
+const bool inputStreamPointerAdapter::eof() const
+{
+ return (m_stream->eof());
+}
+
+
+void inputStreamPointerAdapter::reset()
+{
+ m_stream->seekg(0, std::ios::beg);
+ m_stream->clear();
+}
+
+
+const stream::size_type inputStreamPointerAdapter::read
+ (value_type* const data, const size_type count)
+{
+ m_stream->read(data, count);
+ return (m_stream->gcount());
+}
+
+
+} // utility
+} // vmime
diff --git a/src/utility/stream.hpp b/src/utility/stream.hpp
new file mode 100644
index 00000000..8f8de54c
--- /dev/null
+++ b/src/utility/stream.hpp
@@ -0,0 +1,263 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_UTILITY_STREAM_HPP_INCLUDED
+#define VMIME_UTILITY_STREAM_HPP_INCLUDED
+
+
+#include <istream>
+#include <ostream>
+
+#include "../types.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+class stringProxy;
+
+
+/** Base class for input/output stream.
+ */
+
+class stream
+{
+public:
+
+ virtual ~stream() { }
+
+ /** Type used to read/write one byte in the stream.
+ */
+ typedef string::value_type value_type;
+
+ /** Type used for lengths in streams.
+ */
+ typedef string::size_type size_type;
+};
+
+
+
+/** Simple output stream.
+ */
+
+class outputStream : public stream
+{
+public:
+
+ /** Write data to the stream.
+ *
+ * @param data buffer containing data to write
+ * @param count number of bytes to write
+ */
+ virtual void write(const value_type* const data, const size_type count) = 0;
+};
+
+
+
+/** Simple input stream.
+ */
+
+class inputStream : public stream
+{
+public:
+
+ /** Test for end of stream (no more data to read).
+ *
+ * @return true if we have reached the end of stream, false otherwise
+ */
+ virtual const bool eof() const = 0;
+
+ /** Set the read pointer to the beginning of the stream.
+ *
+ * @warning WARNING: this may not work for all stream types.
+ */
+ virtual void reset() = 0;
+
+ /** Read data from the stream.
+ *
+ * @param data will receive the data read
+ * @param count maximum number of bytes to read
+ * @return number of bytes read
+ */
+ virtual const size_type read(value_type* const data, const size_type count) = 0;
+};
+
+
+
+// Helpers functions
+
+outputStream& operator<<(outputStream& os, const string& str);
+outputStream& operator<<(outputStream& os, const stream::value_type c);
+
+
+template <int N>
+outputStream& operator<<(outputStream& os, const char (&str)[N])
+{
+ os.write(str, N - 1);
+ return (os);
+}
+
+
+/** Copy data from one stream into another stream using a buffered method.
+ *
+ * @param is input stream (source data)
+ * @param os output stream (destination for data)
+ * @return number of bytes copied
+ */
+
+const stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os);
+
+
+
+// Adapters
+
+
+/** An adapter class for C++ standard output streams.
+ */
+
+class outputStreamAdapter : public outputStream
+{
+public:
+
+ /** @param os output stream to wrap
+ */
+ outputStreamAdapter(std::ostream& os);
+
+ void write(const value_type* const data, const size_type count);
+
+private:
+
+ std::ostream& m_stream;
+};
+
+
+/** An adapter class for string output.
+ */
+
+class outputStreamStringAdapter : public outputStream
+{
+public:
+
+ outputStreamStringAdapter(string& buffer);
+
+ void write(const value_type* const data, const size_type count);
+
+private:
+
+ string& m_buffer;
+};
+
+
+/** An adapter class for C++ standard input streams.
+ */
+
+class inputStreamAdapter : public inputStream
+{
+public:
+
+ /** @param is input stream to wrap
+ */
+ inputStreamAdapter(std::istream& is);
+
+ const bool eof() const;
+ void reset();
+ const size_type read(value_type* const data, const size_type count);
+
+private:
+
+ std::istream& m_stream;
+};
+
+
+/** An adapter class for string input.
+ */
+
+class inputStreamStringAdapter : public inputStream
+{
+public:
+
+ inputStreamStringAdapter(const string& buffer);
+ inputStreamStringAdapter(const string& buffer, const string::size_type begin, const string::size_type end);
+
+ const bool eof() const;
+ void reset();
+ const size_type read(value_type* const data, const size_type count);
+
+private:
+
+ const string m_buffer; // do _NOT_ keep a reference...
+ const string::size_type m_begin;
+ const string::size_type m_end;
+ string::size_type m_pos;
+};
+
+
+/** An adapter class for stringProxy input.
+ */
+
+class inputStreamStringProxyAdapter : public inputStream
+{
+public:
+
+ /** @param buffer stringProxy object to wrap
+ */
+ inputStreamStringProxyAdapter(const stringProxy& buffer);
+
+ const bool eof() const;
+ void reset();
+ const size_type read(value_type* const data, const size_type count);
+
+private:
+
+ const stringProxy& m_buffer;
+ string::size_type m_pos;
+};
+
+
+/** An adapter class for pointer to C++ standard input stream.
+ */
+
+class inputStreamPointerAdapter : public inputStream
+{
+public:
+
+ /** @param is input stream to wrap
+ * @param own if set to 'true', the pointer will be deleted when
+ * this object is destroyed
+ */
+ inputStreamPointerAdapter(std::istream* is, const bool own = true);
+ ~inputStreamPointerAdapter();
+
+ const bool eof() const;
+ void reset();
+ const size_type read(value_type* const data, const size_type count);
+
+private:
+
+ std::istream* m_stream;
+ const bool m_own;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_STREAM_HPP_INCLUDED
diff --git a/src/utility/stringProxy.cpp b/src/utility/stringProxy.cpp
new file mode 100644
index 00000000..f79e8a58
--- /dev/null
+++ b/src/utility/stringProxy.cpp
@@ -0,0 +1,131 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "stringProxy.hpp"
+
+#include <iterator>
+#include <algorithm>
+
+
+namespace vmime {
+namespace utility {
+
+
+stringProxy::stringProxy()
+ : m_start(0), m_end(0)
+{
+}
+
+
+stringProxy::stringProxy(const stringProxy& s)
+ : m_buffer(s.m_buffer), m_start(s.m_start), m_end(s.m_end)
+{
+}
+
+
+stringProxy::stringProxy(const string_type& s, const size_type start, const size_type end)
+ : m_buffer(s), m_start(start),
+ m_end(end == std::numeric_limits <size_type>::max() ? s.length() : end)
+{
+}
+
+
+void stringProxy::set(const string_type& s, const size_type start, const size_type end)
+{
+ m_buffer = s;
+ m_start = start;
+
+ if (end == std::numeric_limits <size_type>::max())
+ m_end = s.length();
+ else
+ m_end = end;
+}
+
+
+void stringProxy::detach()
+{
+ m_buffer.clear();
+ m_start = m_end = 0;
+}
+
+
+stringProxy& stringProxy::operator=(const stringProxy& s)
+{
+ m_buffer = s.m_buffer;
+ m_start = s.m_start;
+ m_end = s.m_end;
+
+ return (*this);
+}
+
+
+stringProxy& stringProxy::operator=(const string_type& s)
+{
+ m_buffer = s;
+ m_start = 0;
+ m_end = s.length();
+
+ return (*this);
+}
+
+
+void stringProxy::extract(outputStream& os, const size_type start, const size_type end) const
+{
+ if (end == std::numeric_limits <size_type>::max())
+ os.write(m_buffer.data() + m_start + start, m_end - start - m_start);
+ else
+ os.write(m_buffer.data() + m_start + start, end - start - m_start);
+}
+
+
+const stringProxy::size_type stringProxy::length() const
+{
+ return (m_end - m_start);
+}
+
+
+const stringProxy::size_type stringProxy::start() const
+{
+ return (m_start);
+}
+
+
+const stringProxy::size_type stringProxy::end() const
+{
+ return (m_end);
+}
+
+
+std::ostream& operator<<(std::ostream& os, const stringProxy& s)
+{
+ outputStreamAdapter adapter(os);
+ s.extract(adapter);
+ return (os);
+}
+
+
+outputStream& operator<<(outputStream& os, const stringProxy& s)
+{
+ s.extract(os);
+ return (os);
+}
+
+
+} // utility
+} // vmime
diff --git a/src/utility/stringProxy.hpp b/src/utility/stringProxy.hpp
new file mode 100644
index 00000000..e8001aed
--- /dev/null
+++ b/src/utility/stringProxy.hpp
@@ -0,0 +1,90 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_UTILITY_STRINGPROXY_HPP_INCLUDED
+#define VMIME_UTILITY_STRINGPROXY_HPP_INCLUDED
+
+
+#include <limits>
+
+#include "../types.hpp"
+#include "stream.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** This class is a proxy for the string class. This takes
+ * advantage of the COW (copy-on-write) system that might
+ * be used in "std::string" implementation.
+ */
+
+class stringProxy
+{
+public:
+
+ typedef string::size_type size_type;
+ typedef string string_type;
+
+
+ // Consruction
+ stringProxy();
+ stringProxy(const stringProxy& s);
+ stringProxy(const string_type& s, const size_type start = 0, const size_type end = std::numeric_limits <size_type>::max());
+
+ // Assignment
+ void set(const string_type& s, const size_type start = 0, const size_type end = std::numeric_limits <size_type>::max());
+ void detach();
+
+ stringProxy& operator=(const stringProxy& s);
+ stringProxy& operator=(const string_type& s);
+
+ // Extract some portion (or whole) of the string
+ // and output it into a stream.
+ void extract(outputStream& os, const size_type start = 0, const size_type end = std::numeric_limits <size_type>::max()) const;
+
+ // Return the "virtual" length of the string
+ const size_type length() const;
+
+ // Return the boundaries of the "virtual" string
+ const size_type start() const;
+ const size_type end() const;
+
+ string::const_iterator it_begin() const { return (m_buffer.begin() + m_start); }
+ string::const_iterator it_end() const { return (m_buffer.begin() + m_end); }
+
+private:
+
+ string_type m_buffer;
+
+ size_type m_start;
+ size_type m_end;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const stringProxy& s);
+outputStream& operator<<(outputStream& os, const stringProxy& s);
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_STRINGPROXY_HPP_INCLUDED
diff --git a/src/vmime b/src/vmime
new file mode 100644
index 00000000..4953d8fd
--- /dev/null
+++ b/src/vmime
@@ -0,0 +1,93 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_INCLUDED
+#define VMIME_INCLUDED
+
+
+// Configuration
+#include "config.hpp"
+
+// Base definitions
+#include "base.hpp"
+#include "exception.hpp"
+#include "options.hpp"
+#include "platformDependant.hpp"
+
+// Base components
+#include "dateTime.hpp"
+#include "message.hpp"
+#include "bodyPart.hpp"
+#include "charset.hpp"
+#include "text.hpp"
+#include "encoding.hpp"
+#include "disposition.hpp"
+#include "mailbox.hpp"
+#include "mailboxGroup.hpp"
+#include "mailboxList.hpp"
+#include "addressList.hpp"
+#include "mediaType.hpp"
+#include "messageId.hpp"
+
+// Message components
+#include "message.hpp"
+
+// Header fields
+#include "headerFieldFactory.hpp"
+#include "mailboxField.hpp"
+#include "defaultField.hpp"
+#include "addressListField.hpp"
+#include "parameterizedHeaderField.hpp"
+#include "relayField.hpp"
+
+// Encoders
+#include "encoderFactory.hpp"
+
+// Message builder/parser
+#include "messageBuilder.hpp"
+#include "messageParser.hpp"
+
+#include "fileAttachment.hpp"
+#include "defaultAttachment.hpp"
+
+#include "plainTextPart.hpp"
+#include "htmlTextPart.hpp"
+
+// Property set
+#include "propertySet.hpp"
+
+// Messaging features
+#if VMIME_HAVE_MESSAGING_FEATURES
+ #include "messaging/socket.hpp"
+
+ #include "messaging/service.hpp"
+ #include "messaging/store.hpp"
+ #include "messaging/transport.hpp"
+
+ #include "messaging/session.hpp"
+ #include "messaging/authenticator.hpp"
+ #include "messaging/defaultAuthenticator.hpp"
+ #include "messaging/simpleAuthenticator.hpp"
+
+ #include "messaging/folder.hpp"
+ #include "messaging/message.hpp"
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+
+#endif // VMIME_INCLUDED
diff --git a/src/word.cpp b/src/word.cpp
new file mode 100644
index 00000000..6578ec5f
--- /dev/null
+++ b/src/word.cpp
@@ -0,0 +1,102 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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 "word.hpp"
+
+
+namespace vmime
+{
+
+
+word::word()
+ : m_charset(charset::getLocaleCharset())
+{
+}
+
+
+word::word(const word& w)
+ : m_buffer(w.m_buffer), m_charset(w.m_charset)
+{
+}
+
+
+word::word(const string& buffer) // Defaults to locale charset
+ : m_buffer(buffer), m_charset(charset::getLocaleCharset())
+{
+}
+
+
+word::word(const string& buffer, const class charset& charset)
+ : m_buffer(buffer), m_charset(charset)
+{
+}
+
+
+#if VMIME_WIDE_CHAR_SUPPORT
+
+const wstring word::getDecodedText() const
+{
+ wstring out;
+
+ charset::decode(m_buffer, out, m_charset);
+
+ return (out);
+}
+
+#endif
+
+
+word& word::operator=(const word& w)
+{
+ m_buffer = w.m_buffer;
+ m_charset = w.m_charset;
+ return (*this);
+}
+
+
+word& word::operator=(const string& s)
+{
+ m_buffer = s;
+ return (*this);
+}
+
+
+const bool word::operator==(const word& w) const
+{
+ return (m_charset == w.m_charset && m_buffer == w.m_buffer);
+}
+
+
+const bool word::operator!=(const word& w) const
+{
+ return (m_charset != w.m_charset || m_buffer != w.m_buffer);
+}
+
+
+const string word::getConvertedText(const class charset& dest) const
+{
+ string out;
+
+ charset::convert(m_buffer, out, m_charset, dest);
+
+ return (out);
+}
+
+
+} // vmime
diff --git a/src/word.hpp b/src/word.hpp
new file mode 100644
index 00000000..e9321942
--- /dev/null
+++ b/src/word.hpp
@@ -0,0 +1,74 @@
+//
+// VMime library (http://vmime.sourceforge.net)
+// Copyright (C) 2002-2004 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 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_WORD_HPP_INCLUDED
+#define VMIME_WORD_HPP_INCLUDED
+
+
+#include "charset.hpp"
+
+
+namespace vmime
+{
+
+
+/** A class that encapsulates an encoded-word (RFC-2047):
+ * some text encoded into one specified charset.
+ */
+
+class word
+{
+public:
+
+ word();
+ word(const word& w);
+ word(const string& buffer); // Defaults to locale charset
+ word(const string& buffer, const class charset& charset);
+
+ const string& buffer() const { return (m_buffer); }
+ string& buffer() { return (m_buffer); }
+
+ const class charset& charset() const { return (m_charset); }
+ class charset& charset() { return (m_charset); }
+
+
+ word& operator=(const word& w);
+ word& operator=(const string& s);
+
+ const bool operator==(const word& w) const;
+ const bool operator!=(const word& w) const;
+
+#if VMIME_WIDE_CHAR_SUPPORT
+ const wstring getDecodedText() const;
+#endif
+ const string getConvertedText(const class charset& dest) const;
+
+protected:
+
+ // The "m_buffer" of this word holds the data, and this data is encoded
+ // in the specified "m_charset".
+ string m_buffer;
+ class charset m_charset;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_WORD_HPP_INCLUDED