Added support for RFC-2231.
This commit is contained in:
parent
18dacf00af
commit
f879a9794c
@ -2,6 +2,13 @@
|
|||||||
VERSION 0.6.4cvs
|
VERSION 0.6.4cvs
|
||||||
================
|
================
|
||||||
|
|
||||||
|
2005-04-12 Vincent Richard <vincent@vincent-richard.net>
|
||||||
|
|
||||||
|
* parameter.{cpp|hpp}, contentDispositionField.{cpp|hpp}: added support
|
||||||
|
for RFC-2231 (encoded word extensions). Changed 'filename' parameter
|
||||||
|
type from 'vmime::string' to 'vmime::word'. Default parameter type is
|
||||||
|
now vmime::word, and not vmime::string.
|
||||||
|
|
||||||
2005-04-09 Vincent Richard <vincent@vincent-richard.net>
|
2005-04-09 Vincent Richard <vincent@vincent-richard.net>
|
||||||
|
|
||||||
* encoderB64.cpp: fixed a bug in Base64 decoding. Bytes to be decoded
|
* encoderB64.cpp: fixed a bug in Base64 decoding. Bytes to be decoded
|
||||||
|
@ -94,6 +94,7 @@ libvmime_sources = [
|
|||||||
'contentTypeField.cpp', 'contentTypeField.hpp',
|
'contentTypeField.cpp', 'contentTypeField.hpp',
|
||||||
'dateTime.cpp', 'dateTime.hpp',
|
'dateTime.cpp', 'dateTime.hpp',
|
||||||
'defaultAttachment.cpp', 'defaultAttachment.hpp',
|
'defaultAttachment.cpp', 'defaultAttachment.hpp',
|
||||||
|
'defaultParameter.cpp', 'defaultParameter.hpp',
|
||||||
'disposition.cpp', 'disposition.hpp',
|
'disposition.cpp', 'disposition.hpp',
|
||||||
'emptyContentHandler.cpp', 'emptyContentHandler.hpp',
|
'emptyContentHandler.cpp', 'emptyContentHandler.hpp',
|
||||||
'encoder.cpp', 'encoder.hpp',
|
'encoder.cpp', 'encoder.hpp',
|
||||||
@ -328,6 +329,7 @@ libvmimetest_sources = [
|
|||||||
[ 'tests/parser/messageIdTest', [ 'tests/parser/messageIdTest.cpp' ] ],
|
[ 'tests/parser/messageIdTest', [ 'tests/parser/messageIdTest.cpp' ] ],
|
||||||
[ 'tests/parser/messageIdSequenceTest', [ 'tests/parser/messageIdSequenceTest.cpp' ] ],
|
[ 'tests/parser/messageIdSequenceTest', [ 'tests/parser/messageIdSequenceTest.cpp' ] ],
|
||||||
[ 'tests/parser/pathTest', [ 'tests/parser/pathTest.cpp' ] ],
|
[ 'tests/parser/pathTest', [ 'tests/parser/pathTest.cpp' ] ],
|
||||||
|
[ 'tests/parser/parameterTest', [ 'tests/parser/parameterTest.cpp' ] ],
|
||||||
[ 'tests/parser/textTest', [ 'tests/parser/textTest.cpp' ] ],
|
[ 'tests/parser/textTest', [ 'tests/parser/textTest.cpp' ] ],
|
||||||
[ 'tests/utility/md5Test', [ 'tests/utility/md5Test.cpp' ] ],
|
[ 'tests/utility/md5Test', [ 'tests/utility/md5Test.cpp' ] ],
|
||||||
[ 'tests/utility/stringProxyTest', [ 'tests/utility/stringProxyTest.cpp' ] ],
|
[ 'tests/utility/stringProxyTest', [ 'tests/utility/stringProxyTest.cpp' ] ],
|
||||||
|
@ -74,13 +74,13 @@ void contentDispositionField::setReadDate(const datetime& readDate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const string contentDispositionField::getFilename() const
|
const word contentDispositionField::getFilename() const
|
||||||
{
|
{
|
||||||
return (dynamic_cast <const defaultParameter&>(*findParameter("filename")).getValue());
|
return (dynamic_cast <const defaultParameter&>(*findParameter("filename")).getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void contentDispositionField::setFilename(const string& filename)
|
void contentDispositionField::setFilename(const word& filename)
|
||||||
{
|
{
|
||||||
dynamic_cast <defaultParameter&>(*getParameter("filename")).setValue(filename);
|
dynamic_cast <defaultParameter&>(*getParameter("filename")).setValue(filename);
|
||||||
}
|
}
|
||||||
@ -88,13 +88,13 @@ void contentDispositionField::setFilename(const string& filename)
|
|||||||
|
|
||||||
const string contentDispositionField::getSize() const
|
const string contentDispositionField::getSize() const
|
||||||
{
|
{
|
||||||
return (dynamic_cast <const defaultParameter&>(*findParameter("size")).getValue());
|
return (dynamic_cast <const defaultParameter&>(*findParameter("size")).getValue().getBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void contentDispositionField::setSize(const string& size)
|
void contentDispositionField::setSize(const string& size)
|
||||||
{
|
{
|
||||||
dynamic_cast <defaultParameter&>(*getParameter("size")).setValue(size);
|
dynamic_cast <defaultParameter&>(*getParameter("size")).setValue(word(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,13 +40,13 @@ contentTypeField::contentTypeField(contentTypeField&)
|
|||||||
|
|
||||||
const string contentTypeField::getBoundary() const
|
const string contentTypeField::getBoundary() const
|
||||||
{
|
{
|
||||||
return (dynamic_cast <const defaultParameter&>(*findParameter("boundary")).getValue());
|
return (dynamic_cast <const defaultParameter&>(*findParameter("boundary")).getValue().getBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void contentTypeField::setBoundary(const string& boundary)
|
void contentTypeField::setBoundary(const string& boundary)
|
||||||
{
|
{
|
||||||
dynamic_cast <defaultParameter&>(*getParameter("boundary")).setValue(boundary);
|
dynamic_cast <defaultParameter&>(*getParameter("boundary")).setValue(word(boundary));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -64,13 +64,13 @@ void contentTypeField::setCharset(const charset& ch)
|
|||||||
|
|
||||||
const string contentTypeField::getReportType() const
|
const string contentTypeField::getReportType() const
|
||||||
{
|
{
|
||||||
return (dynamic_cast <const defaultParameter&>(*findParameter("report-type")).getValue());
|
return (dynamic_cast <const defaultParameter&>(*findParameter("report-type")).getValue().getBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void contentTypeField::setReportType(const string& reportType)
|
void contentTypeField::setReportType(const string& reportType)
|
||||||
{
|
{
|
||||||
dynamic_cast <defaultParameter&>(*getParameter("report-type")).setValue(reportType);
|
dynamic_cast <defaultParameter&>(*getParameter("report-type")).setValue(word(reportType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
416
src/defaultParameter.cpp
Normal file
416
src/defaultParameter.cpp
Normal file
@ -0,0 +1,416 @@
|
|||||||
|
//
|
||||||
|
// VMime library (http://www.vmime.org)
|
||||||
|
// Copyright (C) 2002-2005 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 "vmime/defaultParameter.hpp"
|
||||||
|
#include "vmime/parserHelpers.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace vmime
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
defaultParameter::defaultParameter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
defaultParameter& defaultParameter::operator=(const defaultParameter& other)
|
||||||
|
{
|
||||||
|
copyFrom(other);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const word& defaultParameter::getValue() const
|
||||||
|
{
|
||||||
|
return (m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
word& defaultParameter::getValue()
|
||||||
|
{
|
||||||
|
return (m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void defaultParameter::setValue(const word& value)
|
||||||
|
{
|
||||||
|
m_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void defaultParameter::setValue(const component& value)
|
||||||
|
{
|
||||||
|
const word& v = dynamic_cast <const word&>(value);
|
||||||
|
m_value = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void defaultParameter::parse(const string& buffer, const string::size_type position,
|
||||||
|
const string::size_type end, string::size_type* newPosition)
|
||||||
|
{
|
||||||
|
m_value = word(string(buffer.begin() + position, buffer.begin() + end),
|
||||||
|
charset(charsets::US_ASCII));
|
||||||
|
|
||||||
|
if (newPosition)
|
||||||
|
*newPosition = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void defaultParameter::parse(const std::vector <valueChunk>& chunks)
|
||||||
|
{
|
||||||
|
bool foundCharsetChunk = false;
|
||||||
|
|
||||||
|
charset ch(charsets::US_ASCII);
|
||||||
|
std::ostringstream value;
|
||||||
|
|
||||||
|
for (std::vector <valueChunk>::size_type i = 0 ; i < chunks.size() ; ++i)
|
||||||
|
{
|
||||||
|
const valueChunk& chunk = chunks[i];
|
||||||
|
|
||||||
|
// Decode following data
|
||||||
|
if (chunk.encoded)
|
||||||
|
{
|
||||||
|
const string::size_type len = chunk.data.length();
|
||||||
|
string::size_type 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"
|
||||||
|
string::size_type 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 (string::size_type i = pos ; i < len ; ++i)
|
||||||
|
{
|
||||||
|
const string::value_type c = chunk.data[i];
|
||||||
|
|
||||||
|
if (c == '%' && i + 2 < len)
|
||||||
|
{
|
||||||
|
string::value_type 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 << v;
|
||||||
|
|
||||||
|
i += 2; // skip next 2 chars
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value << c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Simply copy data, as it is not encoded
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value << chunk.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_value = word(value.str(), ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void defaultParameter::generate(utility::outputStream& os, const string::size_type maxLineLength,
|
||||||
|
const string::size_type curLinePos, string::size_type* newLinePos) const
|
||||||
|
{
|
||||||
|
const string& name = getName();
|
||||||
|
const string& value = m_value.getBuffer();
|
||||||
|
|
||||||
|
// For compatibility with implementations that do not understand RFC-2231,
|
||||||
|
// also generate a normal "7bit/us-ascii" parameter
|
||||||
|
string::size_type pos = curLinePos;
|
||||||
|
|
||||||
|
if (pos + name.length() + 10 > maxLineLength)
|
||||||
|
{
|
||||||
|
os << NEW_LINE_SEQUENCE;
|
||||||
|
pos = NEW_LINE_SEQUENCE_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool needQuoting = false;
|
||||||
|
|
||||||
|
for (string::size_type i = 0 ; (i < value.length()) && (pos < maxLineLength - 4) ; ++i)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needQuoting)
|
||||||
|
{
|
||||||
|
os << name << "=\"";
|
||||||
|
pos += name.length() + 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
os << name << "=";
|
||||||
|
pos += name.length() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool extended = false;
|
||||||
|
|
||||||
|
for (string::size_type i = 0 ; (i < value.length()) && (pos < maxLineLength - 4) ; ++i)
|
||||||
|
{
|
||||||
|
const char_t c = value[i];
|
||||||
|
|
||||||
|
if (/* needQuoting && */ (c == '"' || c == '\\')) // 'needQuoting' is implicit
|
||||||
|
{
|
||||||
|
os << '\\' << value[i]; // escape 'x' with '\x'
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
else if (parserHelpers::isAscii(c))
|
||||||
|
{
|
||||||
|
os << value[i];
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
extended = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needQuoting)
|
||||||
|
{
|
||||||
|
os << '"';
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also generate an extended parameter if the value contains 8-bit characters
|
||||||
|
// or is too long for a single line
|
||||||
|
if (extended || (value.length() >= (maxLineLength - name.length() + 3)))
|
||||||
|
{
|
||||||
|
os << ';';
|
||||||
|
++pos;
|
||||||
|
|
||||||
|
/* 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 string::size_type firstSectionLength =
|
||||||
|
name.length() + 4 /* *0*= */ + 2 /* '' */
|
||||||
|
+ m_value.getCharset().getName().length();
|
||||||
|
|
||||||
|
if (pos + firstSectionLength + 5 >= maxLineLength)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
string::size_type currentSectionLength = firstSectionLength;
|
||||||
|
|
||||||
|
for (string::size_type 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 >= maxLineLength)
|
||||||
|
{
|
||||||
|
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 ',':
|
||||||
|
|
||||||
|
encode = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
encode = (!parserHelpers::isPrint(c) ||
|
||||||
|
!parserHelpers::isAscii(c));
|
||||||
|
|
||||||
|
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 (newLinePos)
|
||||||
|
*newLinePos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // vmime
|
@ -63,6 +63,23 @@ void parameter::parse(const string& buffer, const string::size_type position,
|
|||||||
getValue().parse(buffer, position, end, newPosition);
|
getValue().parse(buffer, position, end, newPosition);
|
||||||
|
|
||||||
setParsedBounds(position, end);
|
setParsedBounds(position, end);
|
||||||
|
|
||||||
|
if (newPosition)
|
||||||
|
*newPosition = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void parameter::parse(const std::vector <valueChunk>& chunks)
|
||||||
|
{
|
||||||
|
string value;
|
||||||
|
|
||||||
|
for (std::vector <valueChunk>::const_iterator it = chunks.begin() ;
|
||||||
|
it != chunks.end() ; ++it)
|
||||||
|
{
|
||||||
|
value += (*it).data;
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue().parse(value, 0, value.length(), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -87,10 +104,13 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL
|
|||||||
void parameter::generateValue(utility::outputStream& os, const string::size_type /* maxLineLength */,
|
void parameter::generateValue(utility::outputStream& os, const string::size_type /* maxLineLength */,
|
||||||
const string::size_type curLinePos, string::size_type* newLinePos) const
|
const string::size_type curLinePos, string::size_type* newLinePos) const
|
||||||
{
|
{
|
||||||
|
// NOTE: This default implementation does not support parameter
|
||||||
|
// values that span on several lines ('defaultParameter' can do
|
||||||
|
// that, following rules specified in RFC-2231).
|
||||||
|
|
||||||
std::ostringstream valueStream;
|
std::ostringstream valueStream;
|
||||||
utility::outputStreamAdapter valueStreamV(valueStream);
|
utility::outputStreamAdapter valueStreamV(valueStream);
|
||||||
|
|
||||||
// TODO: can we imagine having values that span on multiple lines?
|
|
||||||
getValue().generate(valueStreamV, lineLengthLimits::infinite, 0, NULL);
|
getValue().generate(valueStreamV, lineLengthLimits::infinite, 0, NULL);
|
||||||
|
|
||||||
const string value(valueStream.str());
|
const string value(valueStream.str());
|
||||||
|
@ -73,4 +73,27 @@ parameter* parameterFactory::create
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
parameter* parameterFactory::create(const string& name, const component& value)
|
||||||
|
{
|
||||||
|
const string lcName = utility::stringUtils::toLower(name);
|
||||||
|
|
||||||
|
NameMap::const_iterator pos = m_nameMap.find(lcName);
|
||||||
|
parameter* param = NULL;
|
||||||
|
|
||||||
|
if (pos != m_nameMap.end())
|
||||||
|
{
|
||||||
|
param = ((*pos).second)();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
param = registerer <defaultParameter>::creator();
|
||||||
|
}
|
||||||
|
|
||||||
|
param->m_name = name;
|
||||||
|
param->setValue(value);
|
||||||
|
|
||||||
|
return (param);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // vmime
|
} // vmime
|
||||||
|
@ -55,6 +55,20 @@ parameterizedHeaderField::parameterizedHeaderField()
|
|||||||
; to use within parameter values
|
; to use within parameter values
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef VMIME_BUILDING_DOC
|
||||||
|
|
||||||
|
struct paramInfo
|
||||||
|
{
|
||||||
|
bool extended;
|
||||||
|
std::vector <parameter::valueChunk> value;
|
||||||
|
string::size_type start;
|
||||||
|
string::size_type end;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VMIME_BUILDING_DOC
|
||||||
|
|
||||||
|
|
||||||
void parameterizedHeaderField::parse(const string& buffer, const string::size_type position,
|
void parameterizedHeaderField::parse(const string& buffer, const string::size_type position,
|
||||||
const string::size_type end, string::size_type* newPosition)
|
const string::size_type end, string::size_type* newPosition)
|
||||||
{
|
{
|
||||||
@ -73,6 +87,8 @@ void parameterizedHeaderField::parse(const string& buffer, const string::size_ty
|
|||||||
// If there is one or more parameters following...
|
// If there is one or more parameters following...
|
||||||
if (p < pend)
|
if (p < pend)
|
||||||
{
|
{
|
||||||
|
std::map <string, paramInfo> params;
|
||||||
|
|
||||||
while (*p == ';')
|
while (*p == ';')
|
||||||
{
|
{
|
||||||
// Skip ';'
|
// Skip ';'
|
||||||
@ -183,20 +199,99 @@ void parameterizedHeaderField::parse(const string& buffer, const string::size_ty
|
|||||||
// Don't allow ill-formed parameters
|
// Don't allow ill-formed parameters
|
||||||
if (attrStart != attrEnd && value.length())
|
if (attrStart != attrEnd && value.length())
|
||||||
{
|
{
|
||||||
// Append this parameter to the list
|
string name(buffer.begin() + attrStart, buffer.begin() + attrEnd);
|
||||||
parameter* param = parameterFactory::getInstance()->
|
|
||||||
create(string(buffer.begin() + attrStart,
|
|
||||||
buffer.begin() + attrEnd), value);
|
|
||||||
|
|
||||||
param->setParsedBounds(attrStart, position + (p - pstart));
|
// Check for RFC-2231 extended parameters
|
||||||
|
bool extended = false;
|
||||||
|
bool encoded = false;
|
||||||
|
|
||||||
appendParameter(param);
|
if (name[name.length() - 1] == '*')
|
||||||
|
{
|
||||||
|
name.erase(name.end() - 1, name.end());
|
||||||
|
|
||||||
|
extended = true;
|
||||||
|
encoded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for RFC-2231 multi-section parameters
|
||||||
|
const string::size_type star = name.find_last_of('*');
|
||||||
|
|
||||||
|
if (star != string::npos)
|
||||||
|
{
|
||||||
|
bool allDigits = true;
|
||||||
|
|
||||||
|
for (string::size_type 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
|
// Skip white-spaces after this parameter
|
||||||
while (p < pend && parserHelpers::isSpace(*p)) ++p;
|
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
|
||||||
|
parameter* param = parameterFactory::getInstance()->create((*it).first);
|
||||||
|
|
||||||
|
param->parse(info.value);
|
||||||
|
param->setParsedBounds(info.start, info.end);
|
||||||
|
|
||||||
|
appendParameter(param);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newPosition)
|
if (newPosition)
|
||||||
|
249
tests/parser/parameterTest.cpp
Normal file
249
tests/parser/parameterTest.cpp
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
//
|
||||||
|
// VMime library (http://www.vmime.org)
|
||||||
|
// Copyright (C) 2002-2005 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 "../lib/unit++/unit++.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
#include "vmime/vmime.hpp"
|
||||||
|
#include "vmime/platforms/posix/posixHandler.hpp"
|
||||||
|
|
||||||
|
#include "tests/parser/testUtils.hpp"
|
||||||
|
|
||||||
|
using namespace unitpp;
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// HACK: parameterizedHeaderField constructor is private
|
||||||
|
class parameterizedHeaderField : public vmime::parameterizedHeaderField
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
vmime::typeAdapter <vmime::string> m_value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
parameterizedHeaderField() : headerField("F"), m_value("X") { }
|
||||||
|
|
||||||
|
const vmime::component& getValue() const { return m_value; }
|
||||||
|
vmime::component& getValue() { return m_value; }
|
||||||
|
|
||||||
|
void setValue(const vmime::component&) { /* Do nothing */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define PARAM_VALUE(p, n) (p.getParameterAt(n)->getValue().generate())
|
||||||
|
#define PARAM_NAME(p, n) (p.getParameterAt(n)->getName())
|
||||||
|
#define PARAM_CHARSET(p, n) (static_cast <vmime::defaultParameter*> \
|
||||||
|
(p.getParameterAt(n))->getValue().getCharset().generate())
|
||||||
|
#define PARAM_BUFFER(p, n) (static_cast <vmime::defaultParameter*> \
|
||||||
|
(p.getParameterAt(n))->getValue().getBuffer())
|
||||||
|
|
||||||
|
|
||||||
|
class parameterTest : public suite
|
||||||
|
{
|
||||||
|
void testParse()
|
||||||
|
{
|
||||||
|
// Simple parameter
|
||||||
|
parameterizedHeaderField p1;
|
||||||
|
p1.parse("X; param1=value1;\r\n");
|
||||||
|
|
||||||
|
assert_eq("1.1", 1, p1.getParameterCount());
|
||||||
|
assert_eq("1.2", "param1", PARAM_NAME(p1, 0));
|
||||||
|
assert_eq("1.3", "value1", PARAM_VALUE(p1, 0));
|
||||||
|
|
||||||
|
// Multi-section parameters (1/2)
|
||||||
|
parameterizedHeaderField p2a;
|
||||||
|
p2a.parse("X; param1=value1;\r\n"
|
||||||
|
" param2*0=\"val\";\r\n"
|
||||||
|
" param2*1=\"ue2\";");
|
||||||
|
|
||||||
|
assert_eq("2a.1", 2, p2a.getParameterCount());
|
||||||
|
assert_eq("2a.2", "param1", PARAM_NAME(p2a, 0));
|
||||||
|
assert_eq("2a.3", "value1", PARAM_VALUE(p2a, 0));
|
||||||
|
assert_eq("2a.4", "param2", PARAM_NAME(p2a, 1));
|
||||||
|
assert_eq("2a.5", "value2", PARAM_VALUE(p2a, 1));
|
||||||
|
|
||||||
|
// Multi-section parameters (2/2)
|
||||||
|
parameterizedHeaderField p2b;
|
||||||
|
p2b.parse("X; param1=value1;\r\n"
|
||||||
|
" param2=\"should be ignored\";\r\n"
|
||||||
|
" param2*0=\"val\";\r\n"
|
||||||
|
" param2*1=\"ue2\";");
|
||||||
|
|
||||||
|
assert_eq("2b.1", 2, p2b.getParameterCount());
|
||||||
|
assert_eq("2b.2", "param1", PARAM_NAME(p2b, 0));
|
||||||
|
assert_eq("2b.3", "value1", PARAM_VALUE(p2b, 0));
|
||||||
|
assert_eq("2b.4", "param2", PARAM_NAME(p2b, 1));
|
||||||
|
assert_eq("2b.5", "value2", PARAM_VALUE(p2b, 1));
|
||||||
|
|
||||||
|
// Extended parameter (charset and language information)
|
||||||
|
parameterizedHeaderField p3;
|
||||||
|
p3.parse("X; param1*=charset'language'value1;\r\n");
|
||||||
|
|
||||||
|
assert_eq("3.1", 1, p3.getParameterCount());
|
||||||
|
assert_eq("3.2", "param1", PARAM_NAME(p3, 0));
|
||||||
|
assert_eq("3.3", "charset", PARAM_CHARSET(p3, 0));
|
||||||
|
assert_eq("3.4", "value1", PARAM_BUFFER(p3, 0));
|
||||||
|
|
||||||
|
// Encoded characters in extended parameter values
|
||||||
|
parameterizedHeaderField p4;
|
||||||
|
p4.parse("X; param1*=a%20value%20with%20multiple%20word%73"); // 0x73 = 's'
|
||||||
|
|
||||||
|
assert_eq("4.1", 1, p4.getParameterCount());
|
||||||
|
assert_eq("4.2", "param1", PARAM_NAME(p4, 0));
|
||||||
|
assert_eq("4.3", "a value with multiple words", PARAM_VALUE(p4, 0));
|
||||||
|
|
||||||
|
// Invalid encoded character
|
||||||
|
parameterizedHeaderField p5;
|
||||||
|
p5.parse("X; param1*=test%20value%");
|
||||||
|
|
||||||
|
assert_eq("5.1", 1, p5.getParameterCount());
|
||||||
|
assert_eq("5.2", "param1", PARAM_NAME(p5, 0));
|
||||||
|
assert_eq("5.3", "test value%", PARAM_VALUE(p5, 0));
|
||||||
|
|
||||||
|
// Spaces before and after '='
|
||||||
|
parameterizedHeaderField p6;
|
||||||
|
p6.parse("X; param1\t= \"value1\"");
|
||||||
|
|
||||||
|
assert_eq("6.1", 1, p6.getParameterCount());
|
||||||
|
assert_eq("6.2", "param1", PARAM_NAME(p6, 0));
|
||||||
|
assert_eq("6.3", "value1", PARAM_VALUE(p6, 0));
|
||||||
|
|
||||||
|
// Quoted strings and escaped chars
|
||||||
|
parameterizedHeaderField p7;
|
||||||
|
p7.parse("X; param1=\"this is a slash: \\\"\\\\\\\"\""); // \"\\\"
|
||||||
|
|
||||||
|
assert_eq("7.1", 1, p7.getParameterCount());
|
||||||
|
assert_eq("7.2", "param1", PARAM_NAME(p7, 0));
|
||||||
|
assert_eq("7.3", "this is a slash: \"\\\"", PARAM_VALUE(p7, 0));
|
||||||
|
|
||||||
|
// Extended parameter with charset specified in more than one
|
||||||
|
// section (this is forbidden by RFC, but is should not fail)
|
||||||
|
parameterizedHeaderField p8;
|
||||||
|
p8.parse("X; param1*0*=charset1'language1'value1;\r\n"
|
||||||
|
" param1*1*=charset2'language2'value2;");
|
||||||
|
|
||||||
|
assert_eq("8.1", 1, p8.getParameterCount());
|
||||||
|
assert_eq("8.2", "param1", PARAM_NAME(p8, 0));
|
||||||
|
assert_eq("8.3", "charset1", PARAM_CHARSET(p8, 0));
|
||||||
|
assert_eq("8.4", "value1charset2'language2'value2", PARAM_BUFFER(p8, 0));
|
||||||
|
|
||||||
|
// Charset not specified in the first section (that is not encoded),
|
||||||
|
// but specified in the second one (legal)
|
||||||
|
parameterizedHeaderField p9;
|
||||||
|
p9.parse("X; param1*0=value1;\r\n"
|
||||||
|
" param1*1*=charset'language'value2;");
|
||||||
|
|
||||||
|
assert_eq("9.1", 1, p9.getParameterCount());
|
||||||
|
assert_eq("9.2", "param1", PARAM_NAME(p9, 0));
|
||||||
|
assert_eq("9.3", "charset", PARAM_CHARSET(p9, 0));
|
||||||
|
assert_eq("9.4", "value1value2", PARAM_BUFFER(p9, 0));
|
||||||
|
|
||||||
|
// Characters prefixed with '%' in a simple (not extended) section
|
||||||
|
// should not be decoded
|
||||||
|
parameterizedHeaderField p10;
|
||||||
|
p10.parse("X; param1=val%20ue1");
|
||||||
|
|
||||||
|
assert_eq("10.1", 1, p10.getParameterCount());
|
||||||
|
assert_eq("10.2", "param1", PARAM_NAME(p10, 0));
|
||||||
|
assert_eq("10.3", "val%20ue1", PARAM_VALUE(p10, 0));
|
||||||
|
|
||||||
|
// Multiple sections + charset specified and encoding
|
||||||
|
parameterizedHeaderField p11;
|
||||||
|
p11.parse("X; param1*0*=charset'language'value1a%20;"
|
||||||
|
" param1*1*=value1b%20;"
|
||||||
|
" param1*2=value1c");
|
||||||
|
|
||||||
|
assert_eq("11.1", 1, p11.getParameterCount());
|
||||||
|
assert_eq("11.2", "param1", PARAM_NAME(p11, 0));
|
||||||
|
assert_eq("11.3", "charset", PARAM_CHARSET(p11, 0));
|
||||||
|
assert_eq("11.4", "value1a value1b value1c", PARAM_BUFFER(p11, 0));
|
||||||
|
|
||||||
|
// No charset specified: defaults to US-ASCII
|
||||||
|
parameterizedHeaderField p12;
|
||||||
|
p12.parse("X; param1*='language'value1");
|
||||||
|
|
||||||
|
assert_eq("12.1", 1, p12.getParameterCount());
|
||||||
|
assert_eq("12.2", "param1", PARAM_NAME(p12, 0));
|
||||||
|
assert_eq("12.3", "us-ascii", PARAM_CHARSET(p12, 0));
|
||||||
|
assert_eq("12.4", "value1", PARAM_BUFFER(p12, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void testGenerate()
|
||||||
|
{
|
||||||
|
// Simple parameter/value
|
||||||
|
parameterizedHeaderField p1;
|
||||||
|
p1.appendParameter(vmime::parameterFactory::getInstance()->create("param1", "value1"));
|
||||||
|
|
||||||
|
assert_eq("1", "F: X; param1=value1", p1.generate());
|
||||||
|
|
||||||
|
// Value that needs quoting (1/2)
|
||||||
|
parameterizedHeaderField p2a;
|
||||||
|
p2a.appendParameter(vmime::parameterFactory::getInstance()->create("param1", "value1a;value1b"));
|
||||||
|
|
||||||
|
assert_eq("2a", "F: X; param1=\"value1a;value1b\"", p2a.generate());
|
||||||
|
|
||||||
|
// Value that needs quoting (2/2)
|
||||||
|
parameterizedHeaderField p2b;
|
||||||
|
p2b.appendParameter(vmime::parameterFactory::getInstance()->create("param1", "va\\lue\"1"));
|
||||||
|
|
||||||
|
assert_eq("2b", "F: X; param1=\"va\\\\lue\\\"1\"", p2b.generate());
|
||||||
|
|
||||||
|
// Extended parameter with charset specifier
|
||||||
|
parameterizedHeaderField p3;
|
||||||
|
p3.appendParameter(vmime::parameterFactory::getInstance()->create("param1",
|
||||||
|
vmime::word("value 1\xe9", vmime::charset("charset"))));
|
||||||
|
|
||||||
|
assert_eq("3", "F: X; param1=\"value 1\";param1*=charset''value%201%E9", p3.generate());
|
||||||
|
|
||||||
|
// Value that spans on multiple lines
|
||||||
|
parameterizedHeaderField p4;
|
||||||
|
p4.appendParameter(vmime::parameterFactory::getInstance()->create("param1",
|
||||||
|
vmime::word("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||||
|
vmime::charset("charset"))));
|
||||||
|
|
||||||
|
assert_eq("4", "F: X; param1=abcdefgh;\r\n "
|
||||||
|
"param1*0*=charset''abc;\r\n "
|
||||||
|
"param1*1*=defghijkl;\r\n "
|
||||||
|
"param1*2*=mnopqrstu;\r\n "
|
||||||
|
"param1*3*=vwxyzABCD;\r\n "
|
||||||
|
"param1*4*=EFGHIJKLM;\r\n "
|
||||||
|
"param1*5*=NOPQRSTUV;\r\n "
|
||||||
|
"param1*6*=WXYZ", p4.generate(25)); // max line length = 25
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
parameterTest() : suite("vmime::path")
|
||||||
|
{
|
||||||
|
vmime::platformDependant::setHandler<vmime::platforms::posix::posixHandler>();
|
||||||
|
|
||||||
|
add("Parse", testcase(this, "Parse", ¶meterTest::testParse));
|
||||||
|
add("Generate", testcase(this, "Generate", ¶meterTest::testGenerate));
|
||||||
|
|
||||||
|
suite::main().add("vmime::parameter", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
parameterTest* theTest = new parameterTest();
|
||||||
|
}
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include "vmime/contentDisposition.hpp"
|
#include "vmime/contentDisposition.hpp"
|
||||||
#include "vmime/dateTime.hpp"
|
#include "vmime/dateTime.hpp"
|
||||||
|
#include "vmime/word.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace vmime
|
namespace vmime
|
||||||
@ -52,8 +53,8 @@ public:
|
|||||||
const datetime& getReadDate() const;
|
const datetime& getReadDate() const;
|
||||||
void setReadDate(const datetime& readDate);
|
void setReadDate(const datetime& readDate);
|
||||||
|
|
||||||
const string getFilename() const;
|
const word getFilename() const;
|
||||||
void setFilename(const string& filename);
|
void setFilename(const word& filename);
|
||||||
|
|
||||||
const string getSize() const;
|
const string getSize() const;
|
||||||
void setSize(const string& size);
|
void setSize(const string& size);
|
||||||
|
70
vmime/defaultParameter.hpp
Normal file
70
vmime/defaultParameter.hpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
//
|
||||||
|
// VMime library (http://www.vmime.org)
|
||||||
|
// Copyright (C) 2002-2005 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef VMIME_DEFAULTPARAMETER_HPP_INCLUDED
|
||||||
|
#define VMIME_DEFAULTPARAMETER_HPP_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include "vmime/parameter.hpp"
|
||||||
|
#include "vmime/parameterFactory.hpp"
|
||||||
|
|
||||||
|
#include "vmime/word.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace vmime
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/** Default parameter implementation (with support for RFC-2231).
|
||||||
|
*/
|
||||||
|
|
||||||
|
class defaultParameter : public parameter
|
||||||
|
{
|
||||||
|
friend class parameterFactory::registerer <defaultParameter>;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
defaultParameter();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
defaultParameter& operator=(const defaultParameter& other);
|
||||||
|
|
||||||
|
const word& getValue() const;
|
||||||
|
word& getValue();
|
||||||
|
|
||||||
|
void setValue(const word& value);
|
||||||
|
void setValue(const component& value);
|
||||||
|
|
||||||
|
void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
|
||||||
|
void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void parse(const std::vector <valueChunk>& chunks);
|
||||||
|
|
||||||
|
|
||||||
|
word m_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // vmime
|
||||||
|
|
||||||
|
|
||||||
|
#endif // VMIME_DEFAULTPARAMETER_HPP_INCLUDED
|
@ -36,6 +36,20 @@ class parameter : public component
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
#ifndef VMIME_BUILDING_DOC
|
||||||
|
|
||||||
|
/** A single section of a multi-section parameter,
|
||||||
|
* as defined in RFC-2231/3. This is used when
|
||||||
|
* calling parse() on the parameter.
|
||||||
|
*/
|
||||||
|
struct valueChunk
|
||||||
|
{
|
||||||
|
bool encoded;
|
||||||
|
string data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VMIME_BUILDING_DOC
|
||||||
|
|
||||||
parameter* clone() const;
|
parameter* clone() const;
|
||||||
void copyFrom(const component& other);
|
void copyFrom(const component& other);
|
||||||
parameter& operator=(const parameter& other);
|
parameter& operator=(const parameter& other);
|
||||||
@ -79,6 +93,8 @@ private:
|
|||||||
string m_name;
|
string m_name;
|
||||||
|
|
||||||
void generateValue(utility::outputStream& os, const string::size_type maxLineLength, const string::size_type curLinePos, string::size_type* newLinePos) const;
|
void generateValue(utility::outputStream& os, const string::size_type maxLineLength, const string::size_type curLinePos, string::size_type* newLinePos) const;
|
||||||
|
|
||||||
|
virtual void parse(const std::vector <valueChunk>& chunks);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,7 +67,23 @@ public:
|
|||||||
(utility::stringUtils::toLower(name), ®isterer<T>::creator));
|
(utility::stringUtils::toLower(name), ®isterer<T>::creator));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Create a new parameter and parse its value. The returned parameter
|
||||||
|
* can then be added in a vmime::parameterizedHeaderField object.
|
||||||
|
*
|
||||||
|
* @param name parameter name (ASCII characters only)
|
||||||
|
* @param value value to be parsed
|
||||||
|
* @return created parameter
|
||||||
|
*/
|
||||||
parameter* create(const string& name, const string& value = NULL_STRING);
|
parameter* create(const string& name, const string& value = NULL_STRING);
|
||||||
|
|
||||||
|
/** Create a new parameter and set its value. The returned parameter
|
||||||
|
* can then be added in a vmime::parameterizedHeaderField object.
|
||||||
|
*
|
||||||
|
* @param name parameter name (ASCII characters only)
|
||||||
|
* @param value value to be set
|
||||||
|
* @return created parameter
|
||||||
|
*/
|
||||||
|
parameter* create(const string& name, const component& value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,6 +32,10 @@ namespace vmime
|
|||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/** A header field that can also contain parameters (name=value pairs).
|
||||||
|
* Parameters can be created using vmime::parameterFactory.
|
||||||
|
*/
|
||||||
|
|
||||||
class parameterizedHeaderField : virtual public headerField
|
class parameterizedHeaderField : virtual public headerField
|
||||||
{
|
{
|
||||||
friend class headerFieldFactory::registerer <parameterizedHeaderField>;
|
friend class headerFieldFactory::registerer <parameterizedHeaderField>;
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "vmime/genericParameter.hpp"
|
#include "vmime/genericParameter.hpp"
|
||||||
|
#include "vmime/defaultParameter.hpp"
|
||||||
|
|
||||||
// Inclusion for field value types
|
// Inclusion for field value types
|
||||||
#include "vmime/dateTime.hpp"
|
#include "vmime/dateTime.hpp"
|
||||||
@ -42,7 +43,6 @@ namespace vmime
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DECLARE_STANDARD_PARAM(defaultParameter, string);
|
|
||||||
DECLARE_STANDARD_PARAM(dateParameter, datetime);
|
DECLARE_STANDARD_PARAM(dateParameter, datetime);
|
||||||
DECLARE_STANDARD_PARAM(charsetParameter, charset);
|
DECLARE_STANDARD_PARAM(charsetParameter, charset);
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "vmime/types.hpp"
|
#include "vmime/types.hpp"
|
||||||
|
|
||||||
@ -122,6 +123,18 @@ outputStream& operator<<(outputStream& os, const char (&str)[N])
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
outputStream& operator<<(outputStream& os, const T& t)
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << t;
|
||||||
|
|
||||||
|
os << oss.str();
|
||||||
|
|
||||||
|
return (os);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Copy data from one stream into another stream using a buffered method.
|
/** Copy data from one stream into another stream using a buffered method.
|
||||||
*
|
*
|
||||||
* @param is input stream (source data)
|
* @param is input stream (source data)
|
||||||
|
Loading…
Reference in New Issue
Block a user