2004-10-05 10:28:21 +00:00
|
|
|
//
|
|
|
|
// VMime library (http://vmime.sourceforge.net)
|
|
|
|
// Copyright (C) 2002-2004 Vincent Richard <vincent@vincent-richard.net>
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
// published by the Free Software Foundation; either version 2 of
|
|
|
|
// the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "mailbox.hpp"
|
|
|
|
#include "parserHelpers.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
namespace vmime
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
mailbox::mailbox()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-21 15:05:47 +00:00
|
|
|
mailbox::mailbox(const mailbox& mbox)
|
|
|
|
: address(), m_name(mbox.m_name), m_email(mbox.m_email)
|
2004-10-05 10:28:21 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-10-07 11:24:34 +00:00
|
|
|
// Swap name and address when no address was found
|
|
|
|
// (email address is mandatory, whereas name is optional).
|
|
|
|
if (address.empty() && !name.empty())
|
|
|
|
{
|
2004-11-06 10:46:02 +00:00
|
|
|
m_email.empty();
|
|
|
|
m_email.reserve(name.size());
|
2004-10-21 15:05:47 +00:00
|
|
|
m_name.removeAllWords();
|
2004-11-06 10:46:02 +00:00
|
|
|
|
|
|
|
for (string::size_type i = 0 ; i < name.size() ; ++i)
|
|
|
|
{
|
|
|
|
if (!isspace(name[i]))
|
|
|
|
m_email += name[i];
|
|
|
|
}
|
2004-10-07 11:24:34 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-11-07 10:33:01 +00:00
|
|
|
text::decodeAndUnfold(name, &m_name);
|
2004-11-06 10:46:02 +00:00
|
|
|
m_email.empty();
|
|
|
|
m_email.reserve(address.size());
|
|
|
|
|
|
|
|
for (string::size_type i = 0 ; i < address.size() ; ++i)
|
|
|
|
{
|
|
|
|
if (!isspace(address[i]))
|
|
|
|
m_email += address[i];
|
|
|
|
}
|
2004-10-07 11:24:34 +00:00
|
|
|
}
|
2004-10-05 10:28:21 +00:00
|
|
|
|
2004-12-15 20:28:09 +00:00
|
|
|
setParsedBounds(position, position + (p - pstart));
|
|
|
|
|
2004-10-05 10:28:21 +00:00
|
|
|
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
|
|
|
|
{
|
2004-10-21 15:05:47 +00:00
|
|
|
if (m_name.isEmpty())
|
2004-10-05 10:28:21 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2004-10-21 15:05:47 +00:00
|
|
|
for (int w = 0 ; !forceEncode && w != m_name.getWordCount() ; ++w)
|
2004-10-05 10:28:21 +00:00
|
|
|
{
|
2004-10-21 15:05:47 +00:00
|
|
|
if (m_name.getWordAt(w)->getCharset() == charset(charsets::US_ASCII))
|
2004-10-05 10:28:21 +00:00
|
|
|
{
|
2004-10-21 15:05:47 +00:00
|
|
|
const string& buffer = m_name.getWordAt(w)->getBuffer();
|
2004-10-05 10:28:21 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2004-11-07 10:33:01 +00:00
|
|
|
m_name.encodeAndFold(os, maxLineLength, pos, &pos,
|
|
|
|
forceEncode ? text::FORCE_ENCODING : 0);
|
2004-10-05 10:28:21 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-21 15:05:47 +00:00
|
|
|
void mailbox::copyFrom(const component& other)
|
2004-10-05 10:28:21 +00:00
|
|
|
{
|
2004-10-21 15:05:47 +00:00
|
|
|
const mailbox& source = dynamic_cast <const mailbox&>(other);
|
2004-10-05 10:28:21 +00:00
|
|
|
|
|
|
|
m_name = source.m_name;
|
|
|
|
m_email = source.m_email;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-21 15:05:47 +00:00
|
|
|
mailbox& mailbox::operator=(const mailbox& other)
|
|
|
|
{
|
|
|
|
copyFrom(other);
|
|
|
|
return (*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
mailbox* mailbox::clone() const
|
2004-10-05 10:28:21 +00:00
|
|
|
{
|
|
|
|
return new mailbox(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-21 15:05:47 +00:00
|
|
|
const bool mailbox::isEmpty() const
|
2004-10-05 10:28:21 +00:00
|
|
|
{
|
|
|
|
return (m_email.empty());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void mailbox::clear()
|
|
|
|
{
|
2004-10-21 15:05:47 +00:00
|
|
|
m_name.removeAllWords();
|
2004-10-05 10:28:21 +00:00
|
|
|
m_email.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const bool mailbox::isGroup() const
|
|
|
|
{
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-21 15:05:47 +00:00
|
|
|
const text& mailbox::getName() const
|
|
|
|
{
|
|
|
|
return (m_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void mailbox::setName(const text& name)
|
|
|
|
{
|
|
|
|
m_name = name;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const string& mailbox::getEmail() const
|
|
|
|
{
|
|
|
|
return (m_email);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void mailbox::setEmail(const string& email)
|
|
|
|
{
|
|
|
|
m_email = email;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-12-20 12:33:55 +00:00
|
|
|
const std::vector <const component*> mailbox::getChildComponents() const
|
|
|
|
{
|
|
|
|
return std::vector <const component*>();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-05 10:28:21 +00:00
|
|
|
} // vmime
|