diff options
| author | Vincent Richard <[email protected]> | 2013-12-29 10:02:12 +0100 |
|---|---|---|
| committer | Vincent Richard <[email protected]> | 2013-12-29 10:02:12 +0100 |
| commit | 152c6bed75598a6ca5efb7914701157270155833 (patch) | |
| tree | 8faced1d75a45c819630323da256248415992ed0 /src/parameter.cpp | |
| parent | Merge branch 'master' of https://github.com/kisli/vmime (diff) | |
| download | vmime-152c6bed75598a6ca5efb7914701157270155833.tar.gz vmime-152c6bed75598a6ca5efb7914701157270155833.zip | |
Merged source and header files in directory structure. Got rid of SConstruct build.
Diffstat (limited to 'src/parameter.cpp')
| -rw-r--r-- | src/parameter.cpp | 603 |
1 files changed, 0 insertions, 603 deletions
diff --git a/src/parameter.cpp b/src/parameter.cpp deleted file mode 100644 index b8d5b36e..00000000 --- a/src/parameter.cpp +++ /dev/null @@ -1,603 +0,0 @@ -// -// VMime library (http://www.vmime.org) -// Copyright (C) 2002-2013 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 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/parameter.hpp" -#include "vmime/parserHelpers.hpp" - -#include "vmime/text.hpp" -#include "vmime/encoding.hpp" - -#include "vmime/utility/outputStreamAdapter.hpp" -#include "vmime/utility/outputStreamStringAdapter.hpp" - - -namespace vmime -{ - - -parameter::parameter(const string& name) - : m_name(name), m_value(make_shared <word>()) -{ -} - - -parameter::parameter(const string& name, const word& value) - : m_name(name), m_value(make_shared <word>(value)) -{ -} - - -parameter::parameter(const string& name, const string& value) - : m_name(name), m_value(make_shared <word>(value)) -{ -} - - -parameter::parameter(const parameter&) - : component() -{ -} - - -shared_ptr <component> parameter::clone() const -{ - shared_ptr <parameter> p = make_shared <parameter>(m_name); - p->copyFrom(*this); - - return (p); -} - - -void parameter::copyFrom(const component& other) -{ - const parameter& param = dynamic_cast <const parameter&>(other); - - m_name = param.m_name; - m_value->copyFrom(*param.m_value); -} - - -parameter& parameter::operator=(const parameter& other) -{ - copyFrom(other); - return (*this); -} - - -const string& parameter::getName() const -{ - return m_name; -} - - -const word& parameter::getValue() const -{ - return *m_value; -} - - -void parameter::setValue(const component& value) -{ - std::ostringstream oss; - utility::outputStreamAdapter vos(oss); - - value.generate(vos); - - setValue(word(oss.str(), vmime::charsets::US_ASCII)); -} - - -void parameter::setValue(const word& value) -{ - *m_value = value; -} - - -void parameter::parseImpl - (const parsingContext& ctx, const string& buffer, const size_t position, - const size_t end, size_t* newPosition) -{ - m_value->setBuffer(string(buffer.begin() + position, buffer.begin() + end)); - - if (ctx.getInternationalizedEmailSupport()) - m_value->setCharset(charset(charsets::UTF_8)); - else - m_value->setCharset(charset(charsets::US_ASCII)); - - if (newPosition) - *newPosition = end; -} - - -void parameter::parse(const parsingContext& ctx, const std::vector <valueChunk>& chunks) -{ - bool foundCharsetChunk = false; - - charset ch(charsets::US_ASCII); - - std::ostringstream value; - value.imbue(std::locale::classic()); - - for (std::vector <valueChunk>::size_type i = 0 ; i < chunks.size() ; ++i) - { - const valueChunk& chunk = chunks[i]; - - // Decode following data - if (chunk.encoded) - { - const size_t len = chunk.data.length(); - size_t pos = 0; - - // If this is the first encoded chunk, extract charset - // and language information - if (!foundCharsetChunk) - { - // Eg. "us-ascii'en'This%20is%20even%20more%20" - size_t q = chunk.data.find_first_of('\''); - - if (q != string::npos) - { - const string chs = chunk.data.substr(0, q); - - if (!chs.empty()) - ch = charset(chs); - - ++q; - pos = q; - } - - q = chunk.data.find_first_of('\'', pos); - - if (q != string::npos) - { - // Ignore language - ++q; - pos = q; - } - - foundCharsetChunk = true; - } - - for (size_t i = pos ; i < len ; ++i) - { - const char c = chunk.data[i]; - - if (c == '%' && i + 2 < len) - { - unsigned int v = 0; - - // First char - switch (chunk.data[i + 1]) - { - case 'a': case 'A': v += 10; break; - case 'b': case 'B': v += 11; break; - case 'c': case 'C': v += 12; break; - case 'd': case 'D': v += 13; break; - case 'e': case 'E': v += 14; break; - case 'f': case 'F': v += 15; break; - default: // assume 0-9 - - v += (chunk.data[i + 1] - '0'); - break; - } - - v *= 16; - - // Second char - switch (chunk.data[i + 2]) - { - case 'a': case 'A': v += 10; break; - case 'b': case 'B': v += 11; break; - case 'c': case 'C': v += 12; break; - case 'd': case 'D': v += 13; break; - case 'e': case 'E': v += 14; break; - case 'f': case 'F': v += 15; break; - default: // assume 0-9 - - v += (chunk.data[i + 2] - '0'); - break; - } - - value << static_cast <char>(v); - - i += 2; // skip next 2 chars - } - else - { - value << c; - } - } - } - // Simply copy data, as it is not encoded - else - { - // This syntax is non-standard (expressly prohibited - // by RFC-2047), but is used by Mozilla: - // - // Content-Type: image/png; - // name="=?us-ascii?Q?Logo_VMime=2Epng?=" - - // Using 'vmime::text' to parse the data is safe even - // if the data is not encoded, because it can recover - // from parsing errors. - vmime::text t; - t.parse(ctx, chunk.data); - - if (t.getWordCount() != 0) - { - value << t.getWholeBuffer(); - - if (!foundCharsetChunk) - { - // This is still wrong. Each word can have it's own charset, and can - // be mixed (eg. iso-8859-1 and iso-2022-jp), but very unlikely. Real - // fix is to have parameters store a vmime::text instead of a - // vmime::word in m_value. But that changes the interface. - for (size_t i = 0 ; i < t.getWordCount() ; ++i) - { - if (t.getWordAt(i)->getCharset() != ch && ch == charsets::US_ASCII) - { - ch = t.getWordAt(i)->getCharset(); - break; - } - } - } - } - } - } - - m_value->setBuffer(value.str()); - m_value->setCharset(ch); -} - - -void parameter::generateImpl - (const generationContext& ctx, utility::outputStream& os, - const size_t curLinePos, size_t* newLinePos) const -{ - const string& name = m_name; - const string& value = m_value->getBuffer(); - - // For compatibility with implementations that do not understand RFC-2231, - // also generate a normal "7bit/us-ascii" parameter - - // [By Eugene A. Shatokhin] - // Note that if both the normal "7bit/us-ascii" value and the extended - // value are present, the latter can be ignored by mail processing systems. - // This may lead to annoying problems, for example, with strange names of - // attachments with all but 7-bit ascii characters removed, etc. To avoid - // this, I would suggest not to create "7bit/us-ascii" value if the extended - // value is to be generated. - - // A stream for a temporary storage - string sevenBitBuffer; - utility::outputStreamStringAdapter sevenBitStream(sevenBitBuffer); - - size_t pos = curLinePos; - - if (pos + name.length() + 10 + value.length() > ctx.getMaxLineLength()) - { - sevenBitStream << NEW_LINE_SEQUENCE; - pos = NEW_LINE_SEQUENCE_LENGTH; - } - - bool needQuoting = false; - bool needQuotedPrintable = false; - size_t valueLength = 0; - - // Use worst-case length name.length()+2 for 'name=' part of line - for (size_t i = 0 ; (i < value.length()) && (pos + name.length() + 2 + valueLength < ctx.getMaxLineLength() - 4) ; ++i, ++valueLength) - { - switch (value[i]) - { - // Characters that need to be quoted _and_ escaped - case '"': - case '\\': - // Other characters that need quoting - case ' ': - case '\t': - case '(': - case ')': - case '<': - case '>': - case '@': - case ',': - case ';': - case ':': - case '/': - case '[': - case ']': - case '?': - case '=': - - needQuoting = true; - break; - - default: - - if (!parserHelpers::isAscii(value[i])) - { - needQuotedPrintable = true; - needQuoting = true; - } - - break; - } - } - - const bool cutValue = (valueLength != value.length()); // has the value been cut? - - if (needQuoting) - { - sevenBitStream << name << "=\""; - pos += name.length() + 2; - } - else - { - sevenBitStream << name << "="; - pos += name.length() + 1; - } - - // Check whether there is a recommended encoding for this charset. - // If so, the whole buffer will be encoded. Else, the number of - // 7-bit (ASCII) bytes in the input will be used to determine if - // we need to encode the whole buffer. - encoding recommendedEnc; - const bool alwaysEncode = m_value->getCharset().getRecommendedEncoding(recommendedEnc); - bool extended = alwaysEncode; - - if (needQuotedPrintable) - { - // Send the name in quoted-printable, so outlook express et.al. - // will understand the real filename - size_t oldLen = sevenBitBuffer.length(); - m_value->generate(sevenBitStream); - pos += sevenBitBuffer.length() - oldLen; - extended = true; // also send with RFC-2231 encoding - } - else - { - // Do not chop off this value, but just add the complete name as one header line. - for (size_t i = 0 ; i < value.length() ; ++i) - { - const char_t c = value[i]; - - if (/* needQuoting && */ (c == '"' || c == '\\')) // 'needQuoting' is implicit - { - sevenBitStream << '\\' << value[i]; // escape 'x' with '\x' - pos += 2; - } - else if (parserHelpers::isAscii(c)) - { - sevenBitStream << value[i]; - ++pos; - } - else - { - extended = true; - } - } - - } // !needQuotedPrintable - - if (needQuoting) - { - sevenBitStream << '"'; - ++pos; - } - -#if VMIME_ALWAYS_GENERATE_7BIT_PARAMETER - os << sevenBitBuffer; -#endif // !VMIME_ALWAYS_GENERATE_7BIT_PARAMETER - - // Also generate an extended parameter if the value contains 8-bit characters - // or is too long for a single line - if (extended || cutValue) - { - -#if VMIME_ALWAYS_GENERATE_7BIT_PARAMETER - - os << ';'; - ++pos; - -#else // !VMIME_ALWAYS_GENERATE_7BIT_PARAMETER - - // The data output to 'sevenBitBuffer' will be discarded in this case - pos = curLinePos; - -#endif // VMIME_ALWAYS_GENERATE_7BIT_PARAMETER - - /* RFC-2231 - * ======== - * - * Content-Type: message/external-body; access-type=URL; - * URL*0="ftp://"; - * URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar" - * - * Content-Type: application/x-stuff; - * title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A - * - * Content-Type: application/x-stuff; - * title*0*=us-ascii'en'This%20is%20even%20more%20 - * title*1*=%2A%2A%2Afun%2A%2A%2A%20 - * title*2="isn't it!" - */ - - // Check whether there is enough space for the first section: - // parameter name, section identifier, charset and separators - // + at least 5 characters for the value - const size_t firstSectionLength = - name.length() + 4 /* *0*= */ + 2 /* '' */ - + m_value->getCharset().getName().length(); - - if (pos + firstSectionLength + 5 >= ctx.getMaxLineLength()) - { - os << NEW_LINE_SEQUENCE; - pos = NEW_LINE_SEQUENCE_LENGTH; - } - - // Split text into multiple sections that fit on one line - int sectionCount = 0; - std::vector <string> sectionText; - - string currentSection; - size_t currentSectionLength = firstSectionLength; - - for (size_t i = 0 ; i < value.length() ; ++i) - { - // Check whether we should start a new line (taking into - // account the next character will be encoded = worst case) - if (currentSectionLength + 3 >= ctx.getMaxLineLength()) - { - sectionText.push_back(currentSection); - sectionCount++; - - currentSection.clear(); - currentSectionLength = NEW_LINE_SEQUENCE_LENGTH - + name.length() + 6; - } - - // Output next character - const char_t c = value[i]; - bool encode = false; - - switch (c) - { - // special characters - case ' ': - case '\t': - case '\r': - case '\n': - case '%': - case '"': - case ';': - case ',': - case '(': - case ')': - case '<': - case '>': - case '@': - case ':': - case '/': - case '[': - case ']': - case '?': - case '=': - - encode = true; - break; - - default: - - encode = (!parserHelpers::isPrint(c) || - !parserHelpers::isAscii(c) || - alwaysEncode); - - break; - } - - if (encode) // need encoding - { - const int h1 = static_cast <unsigned char>(c) / 16; - const int h2 = static_cast <unsigned char>(c) % 16; - - currentSection += '%'; - currentSection += "0123456789ABCDEF"[h1]; - currentSection += "0123456789ABCDEF"[h2]; - - pos += 3; - currentSectionLength += 3; - } - else - { - currentSection += value[i]; - - ++pos; - ++currentSectionLength; - } - } - - if (!currentSection.empty()) - { - sectionText.push_back(currentSection); - sectionCount++; - } - - // Output sections - for (int sectionNumber = 0 ; sectionNumber < sectionCount ; ++sectionNumber) - { - os << name; - - if (sectionCount != 1) // no section specifier when only a single one - { - os << '*'; - os << sectionNumber; - } - - os << "*="; - - if (sectionNumber == 0) - { - os << m_value->getCharset().getName(); - os << '\'' << /* No language */ '\''; - } - - os << sectionText[sectionNumber]; - - if (sectionNumber + 1 < sectionCount) - { - os << ';'; - os << NEW_LINE_SEQUENCE; - pos = NEW_LINE_SEQUENCE_LENGTH; - } - } - } -#if !VMIME_ALWAYS_GENERATE_7BIT_PARAMETER - else - { - // The value does not contain 8-bit characters and - // is short enough for a single line. - // "7bit/us-ascii" will suffice in this case. - - // Output what has been stored in temporary buffer so far - os << sevenBitBuffer; - } -#endif // !VMIME_ALWAYS_GENERATE_7BIT_PARAMETER - - if (newLinePos) - *newLinePos = pos; -} - - -const std::vector <shared_ptr <component> > parameter::getChildComponents() -{ - std::vector <shared_ptr <component> > list; - - list.push_back(m_value); - - return list; -} - - -} // vmime - |
