diff options
Diffstat (limited to 'vmime-master/src/vmime/parameterizedHeaderField.cpp')
-rw-r--r-- | vmime-master/src/vmime/parameterizedHeaderField.cpp | 634 |
1 files changed, 634 insertions, 0 deletions
diff --git a/vmime-master/src/vmime/parameterizedHeaderField.cpp b/vmime-master/src/vmime/parameterizedHeaderField.cpp new file mode 100644 index 0000000..6815fad --- /dev/null +++ b/vmime-master/src/vmime/parameterizedHeaderField.cpp @@ -0,0 +1,634 @@ +// +// 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/parameterizedHeaderField.hpp" +#include "vmime/text.hpp" +#include "vmime/parserHelpers.hpp" + + +namespace vmime { + + +parameterizedHeaderField::parameterizedHeaderField() { + +} + + +parameterizedHeaderField::~parameterizedHeaderField() { + + removeAllParameters(); +} + + +/* + 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 +*/ + + +#ifndef VMIME_BUILDING_DOC + +struct paramInfo { + + bool extended; + std::vector <parameter::valueChunk> value; + size_t start; + size_t end; +}; + +#endif // VMIME_BUILDING_DOC + + +void parameterizedHeaderField::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; + + // Skip non-significant whitespaces + size_t valueStart = position; + + while (p < pend && parserHelpers::isSpace(*p)) { + ++p; + ++valueStart; + } + + // Advance up to ';', if any + size_t valueLength = 0; + + while (p < pend && *p != ';' && (!parserHelpers::isSpace(*p))) { // FIXME: support ";" inside quoted or RFC-2047-encoded text + + ++p; + ++valueLength; + } + + // Trim whitespaces at the end of the value + while (valueLength > 0 && parserHelpers::isSpace(buffer[valueStart + valueLength - 1])) { + --valueLength; + } + + // Parse value + getValue()->parse(ctx, buffer, valueStart, valueStart + valueLength); + + // Reset parameters + removeAllParameters(); + + // If there is one or more parameters following... + if (p < pend) { + + std::map <string, paramInfo> params; + + if (*p != ';') { + + while (p < pend && *p != ';') { // FIXME: support ";" inside quoted or RFC-2047-encoded text + ++p; + } + } + + while (*p == ';') { + + // Skip ';' + ++p; + + while (p < pend && parserHelpers::isSpace(*p)) ++p; + + const size_t 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 + size_t attrEnd = position + (p - pstart); + + while (attrEnd != attrStart && parserHelpers::isSpace(buffer[attrEnd - 1])) { + --attrEnd; + } + + // Skip '=' + ++p; + + // Skip white-spaces between '=' and the value + while (p < pend && parserHelpers::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; + size_t 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 size_t valStart = position + (p - pstart); + + while (p < pend && *p != ';') { + ++p; + } + + size_t valEnd = position + (p - pstart); + + while (valEnd != valStart && parserHelpers::isSpace(buffer[valEnd - 1])) { + --valEnd; + } + + value = string( + buffer.begin() + valStart, + buffer.begin() + valEnd + ); + } + + // Don't allow ill-formed parameters + if (attrStart != attrEnd && value.length()) { + + string name(buffer.begin() + attrStart, buffer.begin() + attrEnd); + + // Check for RFC-2231 extended parameters + bool extended = false; + bool encoded = false; + + if (name[name.length() - 1] == '*') { + + name.erase(name.end() - 1, name.end()); + + extended = true; + encoded = true; + } + + // Check for RFC-2231 multi-section parameters + const size_t star = name.find_last_of('*'); + + if (star != string::npos) { + + bool allDigits = true; + + for (size_t i = star + 1 ; allDigits && (i < name.length()) ; ++i) { + allDigits = parserHelpers::isDigit(name[i]); + } + + if (allDigits) { + name.erase(name.begin() + star, name.end()); + extended = true; + } + + // NOTE: we ignore section number, and we suppose that + // the sequence is correct (ie. the sections appear + // in order: param*0, param*1...) + } + + // Add/replace/modify the parameter + const std::map <string, paramInfo>::iterator it = params.find(name); + + if (it != params.end()) { + + paramInfo& info = (*it).second; + + // An extended parameter replaces a normal one + if (!info.extended) { + + info.extended = extended; + info.value.clear(); + info.start = attrStart; + } + + // Append a new section for a multi-section parameter + parameter::valueChunk chunk; + chunk.encoded = encoded; + chunk.data = value; + + info.value.push_back(chunk); + info.end = position + (p - pstart); + + } else { + + parameter::valueChunk chunk; + chunk.encoded = encoded; + chunk.data = value; + + paramInfo info; + info.extended = extended; + info.value.push_back(chunk); + info.start = attrStart; + info.end = position + (p - pstart); + + // Insert a new parameter + params.insert(std::map <string, paramInfo>::value_type(name, info)); + } + } + + // Skip white-spaces after this parameter + while (p < pend && parserHelpers::isSpace(*p)) ++p; + } + } + + for (std::map <string, paramInfo>::const_iterator it = params.begin() ; + it != params.end() ; ++it) { + + const paramInfo& info = (*it).second; + + // Append this parameter to the list + shared_ptr <parameter> param = make_shared <parameter>((*it).first); + + param->parse(ctx, info.value); + param->setParsedBounds(info.start, info.end); + + appendParameter(param); + } + } + + if (newPosition) { + *newPosition = end; + } +} + + +void parameterizedHeaderField::generateImpl( + const generationContext& ctx, + utility::outputStream& os, + const size_t curLinePos, + size_t* newLinePos +) const { + + size_t pos = curLinePos; + + // Parent header field + headerField::generateImpl(ctx, os, pos, &pos); + + // Parameters + for (std::vector <shared_ptr <parameter> >::const_iterator + it = m_params.begin() ; it != m_params.end() ; ++it) { + + os << "; "; + pos += 2; + + (*it)->generate(ctx, os, pos, &pos); + } + + if (newLinePos) { + *newLinePos = pos; + } +} + + +size_t parameterizedHeaderField::getGeneratedSize(const generationContext& ctx) +{ + size_t size = headerField::getGeneratedSize(ctx); + + for (std::vector <shared_ptr <parameter> >::const_iterator + it = m_params.begin() ; it != m_params.end() ; ++it) { + + size += 2; // "; " + size += (*it)->getGeneratedSize(ctx); + } + + return size; +} + + +void parameterizedHeaderField::copyFrom(const component& other) { + + headerField::copyFrom(other); + + const parameterizedHeaderField& source = dynamic_cast<const parameterizedHeaderField&>(other); + + removeAllParameters(); + + for (std::vector <shared_ptr <parameter> >::const_iterator i = source.m_params.begin() ; + i != source.m_params.end() ; ++i) { + + appendParameter(vmime::clone(*i)); + } +} + + +parameterizedHeaderField& parameterizedHeaderField::operator=(const parameterizedHeaderField& other) { + + copyFrom(other); + return *this; +} + + +bool parameterizedHeaderField::hasParameter(const string& paramName) const { + + const string name = utility::stringUtils::toLower(paramName); + + std::vector <shared_ptr <parameter> >::const_iterator pos = m_params.begin(); + const std::vector <shared_ptr <parameter> >::const_iterator end = m_params.end(); + + for ( ; pos != end && utility::stringUtils::toLower((*pos)->getName()) != name ; ++pos) {} + + return pos != end; +} + + +shared_ptr <parameter> parameterizedHeaderField::findParameter(const string& paramName) const { + + const string name = utility::stringUtils::toLower(paramName); + + // Find the first parameter that matches the specified name + std::vector <shared_ptr <parameter> >::const_iterator pos = m_params.begin(); + const std::vector <shared_ptr <parameter> >::const_iterator end = m_params.end(); + + for ( ; pos != end && utility::stringUtils::toLower((*pos)->getName()) != name ; ++pos) {} + + // No parameter with this name can be found + if (pos == end) { + return null; + } + + // Else, return a reference to the existing parameter + return *pos; +} + + +shared_ptr <parameter> parameterizedHeaderField::getParameter(const string& paramName) { + + const string name = utility::stringUtils::toLower(paramName); + + // Find the first parameter that matches the specified name + std::vector <shared_ptr <parameter> >::const_iterator pos = m_params.begin(); + const std::vector <shared_ptr <parameter> >::const_iterator end = m_params.end(); + + for ( ; pos != end && utility::stringUtils::toLower((*pos)->getName()) != name ; ++pos) {} + + // If no parameter with this name can be found, create a new one + if (pos == end) { + + shared_ptr <parameter> param = make_shared <parameter>(paramName); + + appendParameter(param); + + // Return a reference to the new parameter + return param; + + // Else, return a reference to the existing parameter + } else { + + return *pos; + } +} + + +void parameterizedHeaderField::appendParameter(const shared_ptr <parameter>& param) { + + m_params.push_back(param); +} + + +void parameterizedHeaderField::insertParameterBefore( + const shared_ptr <parameter>& beforeParam, + const shared_ptr <parameter>& param +) { + + const std::vector <shared_ptr <parameter> >::iterator it = + std::find(m_params.begin(), m_params.end(), beforeParam); + + if (it == m_params.end()) { + throw std::out_of_range("Invalid position"); + } + + m_params.insert(it, param); +} + + +void parameterizedHeaderField::insertParameterBefore( + const size_t pos, + const shared_ptr <parameter>& param +) { + + if (pos >= m_params.size()) { + throw std::out_of_range("Invalid position"); + } + + m_params.insert(m_params.begin() + pos, param); +} + + +void parameterizedHeaderField::insertParameterAfter( + const shared_ptr <parameter>& afterParam, + const shared_ptr <parameter>& param +) { + + const std::vector <shared_ptr <parameter> >::iterator it = + std::find(m_params.begin(), m_params.end(), afterParam); + + if (it == m_params.end()) { + throw std::out_of_range("Invalid position"); + } + + m_params.insert(it + 1, param); +} + + +void parameterizedHeaderField::insertParameterAfter( + const size_t pos, + const shared_ptr <parameter>& param +) { + + if (pos >= m_params.size()) { + throw std::out_of_range("Invalid position"); + } + + m_params.insert(m_params.begin() + pos + 1, param); +} + + +void parameterizedHeaderField::removeParameter(const shared_ptr <parameter>& param) { + + const std::vector <shared_ptr <parameter> >::iterator it = + std::find(m_params.begin(), m_params.end(), param); + + if (it == m_params.end()) { + throw std::out_of_range("Invalid position"); + } + + m_params.erase(it); +} + + +void parameterizedHeaderField::removeParameter(const size_t pos) { + + const std::vector <shared_ptr <parameter> >::iterator it = m_params.begin() + pos; + + m_params.erase(it); +} + + +void parameterizedHeaderField::removeAllParameters() { + + m_params.clear(); +} + + +size_t parameterizedHeaderField::getParameterCount() const { + + return m_params.size(); +} + + +bool parameterizedHeaderField::isEmpty() const { + + return m_params.empty(); +} + + +const shared_ptr <parameter> parameterizedHeaderField::getParameterAt(const size_t pos) { + + return m_params[pos]; +} + + +const shared_ptr <const parameter> parameterizedHeaderField::getParameterAt(const size_t pos) const { + + return m_params[pos]; +} + + +const std::vector <shared_ptr <const parameter> > parameterizedHeaderField::getParameterList() const { + + std::vector <shared_ptr <const parameter> > list; + + list.reserve(m_params.size()); + + for (std::vector <shared_ptr <parameter> >::const_iterator it = m_params.begin() ; + it != m_params.end() ; ++it) { + + list.push_back(*it); + } + + return list; +} + + +const std::vector <shared_ptr <parameter> > parameterizedHeaderField::getParameterList() { + + return m_params; +} + + +const std::vector <shared_ptr <component> > parameterizedHeaderField::getChildComponents() { + + std::vector <shared_ptr <component> > list = headerField::getChildComponents(); + + for (std::vector <shared_ptr <parameter> >::iterator it = m_params.begin() ; + it != m_params.end() ; ++it) { + + list.push_back(*it); + } + + return list; +} + + +} // vmime + |