diff options
Diffstat (limited to 'src/mailbox.cpp')
-rw-r--r-- | src/mailbox.cpp | 450 |
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 |