aboutsummaryrefslogtreecommitdiffstats
path: root/src/mailbox.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mailbox.cpp')
-rw-r--r--src/mailbox.cpp450
1 files changed, 450 insertions, 0 deletions
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