diff options
Diffstat (limited to 'vmime-master/src/vmime/mailbox.cpp')
-rw-r--r-- | vmime-master/src/vmime/mailbox.cpp | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/vmime-master/src/vmime/mailbox.cpp b/vmime-master/src/vmime/mailbox.cpp new file mode 100644 index 0000000..30a082e --- /dev/null +++ b/vmime-master/src/vmime/mailbox.cpp @@ -0,0 +1,476 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 3 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., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/mailbox.hpp" +#include "vmime/parserHelpers.hpp" +#include "vmime/utility/outputStreamStringAdapter.hpp" + + +namespace vmime { + + +mailbox::mailbox() { + +} + + +mailbox::mailbox(const mailbox& mbox) + : address(), + m_name(mbox.m_name), + m_email(mbox.m_email) { + +} + + +mailbox::mailbox(const emailAddress& email) + : m_email(email) { + +} + + +mailbox::mailbox(const text& name, const emailAddress& 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::parseImpl( + const parsingContext& ctx, + const string& buffer, + const size_t position, + const size_t end, + size_t* newPosition +) { + + const char* const pend = buffer.data() + end; + const char* const pstart = buffer.data() + position; + const char* p = pstart; + + // Current state for parsing machine + enum States { + State_None, + State_String, + State_Name, + State_Bracket, + State_Address_Bracketed, + State_Address_Unbracketed, + State_NameAt, + }; + + States state = State_None; + + // Temporary buffers for extracted name and address + string name, address; + unsigned int hold = 0; + bool hadBrackets = false; + + while (p < pend) { + if (state == State_None) { + while (p < pend && parserHelpers::isSpace(*p)) + ++p; + if (*p == ',' || *p == ';') + /* Completely new mailbox -- stop parsing this one. */ + break; + if (*p == '<') { + state = State_Bracket; + continue; + } + if (*p == '"') { // Quoted string + state = State_String; + ++p; + continue; + } + state = State_Name; + } else if (state == State_String) { + bool escaped = false; + + for (; p < pend; ++p) { + if (escaped) { + name += *p; + escaped = false; + continue; + } else if (*p == '\\') { + escaped = true; + continue; + } + if (*p == '"') { + ++p; + state = State_None; + break; + } + name += *p; + } + } else if (state == State_Address_Bracketed) { + bool escaped = false; + int comment = 0; + + for (; p < pend; ++p) { + if (escaped) { + if (!comment) { + address += *p; + name += *p; + ++hold; + } + 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 == '<') { + state = State_Bracket; + break; + } else if (*p == '>') { + hadBrackets = true; + name += *p++; + ++hold; + state = State_Name; + break; + } else if (parserHelpers::isSpace(*p)) { + name += *p; + ++hold; + } else { + address += *p; + name += *p; + ++hold; + } + } + } else if (state == State_Address_Unbracketed) { + bool escaped = false; + int comment = 0; + + for (; p < pend; ++p) { + if (escaped) { + if (!comment) { + address += *p; + name += *p; + ++hold; + } + 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 == '<') { + state = State_Bracket; + break; + } else if (*p == '>') { + name += *p++; + ++hold; + state = State_None; + break; + } else if (*p == ',' || *p == ';') { + state = State_None; + break; + } else if (parserHelpers::isSpace(*p)) { + state = State_Name; + break; + } else { + address += *p; + name += *p; + ++hold; + } + } + } else if (state == State_Name) { + bool escaped = false; + unsigned int comment = 0, at_hold = 0; + + for (; p < pend; ++p) { + if (escaped) { + if (!comment) { + name += *p; + ++at_hold; + } + 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 == '<') { + state = State_Bracket; + break; + } else if (*p == '@') { + hold = at_hold; + state = State_NameAt; + break; + } else if (parserHelpers::isSpace(*p)) { + name += *p; + ++hold; + at_hold = 1; + } else { + name += *p; + hold = 0; + ++at_hold; + } + } + } else if (state == State_Bracket) { + string::const_iterator q = name.cend(); + unsigned int nh = 0; + while (nh < hold && q != name.cbegin() && parserHelpers::isSpace(*(q - 1))) { + --q; + ++nh; + } + hold = nh; + name += *p++; + ++hold; + if (!address.empty()) + // 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! + address.clear(); + state = State_Address_Bracketed; + } else if (state == State_NameAt) { + name += *p++; + ++hold; + // (*) Actually, we were parsing the local-part of an address + // and not a display name... + // Back up to the last whitespace and treat as address + string::const_iterator q = name.cend(); + unsigned int nh = 0; + while (nh < hold && q != name.cbegin() && !parserHelpers::isSpace(*(q - 1))) { + --q; + ++nh; + } + address.assign(q, name.cend()); + while (nh < hold && q != name.cbegin() && parserHelpers::isSpace(*(q - 1))) { + --q; + ++nh; + } + hold = nh; + state = State_Address_Unbracketed; + } + } + + if (hold <= name.size()) + name.erase(name.size() - hold); + + // Swap name and address when no address was found + // (email address is mandatory, whereas name is optional). + if (address.empty() && !name.empty() && !hadBrackets) { + + m_name.removeAllWords(); + m_email.parse(ctx, name); + + } else { + + text::decodeAndUnfold(ctx, name, &m_name); + m_email.parse(ctx, address); + } + + setParsedBounds(position, position + (p - pstart)); + + if (newPosition) { + *newPosition = position + (p - pstart); + } +} + + +void mailbox::generateImpl( + const generationContext& ctx, + utility::outputStream& os, + const size_t curLinePos, + size_t* newLinePos +) const { + + string generatedEmail; + utility::outputStreamStringAdapter generatedEmailStream(generatedEmail); + m_email.generate(ctx, generatedEmailStream, 0, NULL); + + if (m_name.isEmpty()) { + + size_t pos = curLinePos; + + // No display name is specified, only email address. + if (curLinePos + generatedEmail.length() > ctx.getMaxLineLength()) { + + os << NEW_LINE_SEQUENCE; + pos = NEW_LINE_SEQUENCE.length(); + } + + os << generatedEmail; + pos += generatedEmail.length(); + + if (newLinePos) { + *newLinePos = pos; + } + + } 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: + // CR LF TAB " ; , < > ( ) @ / ? . = : + // these special chars only require quoting, not full encoding + // Check whether there are words that are not "US-ASCII" + // and/or contain the special chars. + bool forceEncode = false; + + for (size_t w = 0 ; !forceEncode && w != m_name.getWordCount() ; ++w) { + + if (m_name.getWordAt(w)->getCharset() != charset(charsets::US_ASCII)) { + forceEncode = true; + } + } + + size_t pos = curLinePos; + + m_name.encodeAndFold( + ctx, os, pos, &pos, + text::QUOTE_IF_POSSIBLE | (forceEncode ? text::FORCE_ENCODING : 0) + ); + + if (pos + generatedEmail.length() + 3 > ctx.getMaxLineLength()) { + + os << NEW_LINE_SEQUENCE; + pos = NEW_LINE_SEQUENCE.length(); + } + + os << " <" << generatedEmail << ">"; + pos += 2 + generatedEmail.length() + 1; + + if (newLinePos) { + *newLinePos = pos; + } + } +} + + +bool mailbox::operator==(const class mailbox& mailbox) const { + + return m_name == mailbox.m_name && m_email == mailbox.m_email; +} + + +bool mailbox::operator!=(const class mailbox& mailbox) const { + + return !(*this == mailbox); +} + + +void mailbox::copyFrom(const component& other) { + + const mailbox& source = dynamic_cast <const mailbox&>(other); + + m_name = source.m_name; + m_email = source.m_email; +} + + +mailbox& mailbox::operator=(const mailbox& other) { + + copyFrom(other); + return *this; +} + + +shared_ptr <component>mailbox::clone() const { + + return make_shared <mailbox>(*this); +} + + +bool mailbox::isEmpty() const { + + return m_email.isEmpty(); +} + + +void mailbox::clear() { + + m_name.removeAllWords(); + m_email = emailAddress(); +} + + +bool mailbox::isGroup() const { + + return false; +} + + +const text& mailbox::getName() const { + + return m_name; +} + + +void mailbox::setName(const text& name) { + + m_name = name; +} + + +const emailAddress& mailbox::getEmail() const { + + return m_email; +} + + +void mailbox::setEmail(const emailAddress& email) { + + m_email = email; +} + + +const std::vector <shared_ptr <component> > mailbox::getChildComponents() { + + return std::vector <shared_ptr <component> >(); +} + + +} // vmime |