|
|
@ -35,8 +35,15 @@ using qi::_1; |
|
|
|
struct Rfc2231ParamName |
|
|
|
{ |
|
|
|
std::string name; |
|
|
|
unsigned count; |
|
|
|
bool with_charset; |
|
|
|
int count = -1; |
|
|
|
bool with_charset = false; |
|
|
|
}; |
|
|
|
|
|
|
|
struct Rfc2231ParamValue |
|
|
|
{ |
|
|
|
std::string charset; |
|
|
|
// language is ignored
|
|
|
|
std::string value; |
|
|
|
}; |
|
|
|
|
|
|
|
BOOST_FUSION_ADAPT_STRUCT( |
|
|
@ -81,28 +88,90 @@ void ContentType::tolower() |
|
|
|
ascii_tolower(subtype); |
|
|
|
} |
|
|
|
|
|
|
|
qi::uint_parser<unsigned char, 16,2,2> hex_octet; |
|
|
|
|
|
|
|
pEpMIME::TRule<char> ext_octet = qi::lit('%') >> hex_octet; |
|
|
|
pEpMIME::TRule<char> attrib_char = qi::ascii::print - qi::char_("]*'%()<>@,:\\\"/?=["); |
|
|
|
|
|
|
|
pEpMIME::TRule<Rfc2231ParamName> param_name = |
|
|
|
(+(qi::char_ - '*')) [ &(_val)->*&Rfc2231ParamName::name <<= _1 ] |
|
|
|
>> -(qi::lit('*') >> qi::uint_[ &(_val)->*&Rfc2231ParamName::count = _1] ) |
|
|
|
>> -(qi::lit('*')[ &(_val)->*&Rfc2231ParamName::with_charset = true] ); |
|
|
|
|
|
|
|
|
|
|
|
pEpMIME::TRule<Rfc2231ParamValue> param_value = |
|
|
|
-( |
|
|
|
(+qi::char_("A-Za-z0-9_./-"))[ &(_val)->*&Rfc2231ParamValue::charset <<= _1 ] |
|
|
|
>> '\'' |
|
|
|
>> qi::omit[ *(qi::char_ - '\'') ] // language is ignored
|
|
|
|
>> '\'' |
|
|
|
) // charset & language is optional and normally only present in the 1st part
|
|
|
|
>> ( +(ext_octet | attrib_char))[ &(_val)->*&Rfc2231ParamValue::value <<= _1 ]; |
|
|
|
|
|
|
|
std::string convert(std::string& charset, const std::string& input) |
|
|
|
{ |
|
|
|
Rfc2231ParamValue pv; |
|
|
|
std::string::const_iterator begin = input.begin(); |
|
|
|
if(qi::parse(begin, input.end(), param_value, pv)) |
|
|
|
{ |
|
|
|
if(pv.charset.size()) |
|
|
|
{ |
|
|
|
charset = pv.charset; |
|
|
|
} |
|
|
|
return to_utf8(charset, pv.value); |
|
|
|
} |
|
|
|
return to_utf8(charset, input); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void ContentType::unwrap() |
|
|
|
{ |
|
|
|
std::vector<pEpMIME::NameValue> params; |
|
|
|
std::vector<pEpMIME::NameValue> new_params; |
|
|
|
std::string name, value; |
|
|
|
for(const auto& p:params) |
|
|
|
std::string charset = "UTF-8"; |
|
|
|
int old_count = -1; |
|
|
|
for(auto& p:params) |
|
|
|
{ |
|
|
|
Rfc2231ParamName pn; |
|
|
|
auto begin = p.name.begin(); |
|
|
|
if(qi::parse(begin, p.name.end(), param_name, pn)) |
|
|
|
std::string::const_iterator begin = p.name.cbegin(); |
|
|
|
if(qi::parse(begin, p.name.cend(), param_name, pn)) |
|
|
|
{ |
|
|
|
if(pn.name == name) |
|
|
|
switch(pn.count) |
|
|
|
{ |
|
|
|
case -1 : // has charset but no multi-line value
|
|
|
|
new_params.emplace_back( pn.name, convert(charset, p.value ) ); |
|
|
|
break; |
|
|
|
case 0 : // start of a multi-line value
|
|
|
|
if(!name.empty()) |
|
|
|
{ |
|
|
|
new_params.emplace_back( name, value); |
|
|
|
} |
|
|
|
name = pn.name; |
|
|
|
value = convert( charset, p.value ); |
|
|
|
old_count = 0; |
|
|
|
break; |
|
|
|
default: |
|
|
|
if(pn.name == name && pn.count == old_count+1) |
|
|
|
{ |
|
|
|
value += convert( charset, p.value ); |
|
|
|
old_count = pn.count; |
|
|
|
}else{ |
|
|
|
// non-contiguous counter -> discard it.
|
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
}else{ |
|
|
|
if(!name.empty()) |
|
|
|
{ |
|
|
|
value += p.value; // TODO: decode encoded values!
|
|
|
|
new_params.emplace_back( name, value); |
|
|
|
name.clear(); value.clear(); |
|
|
|
} |
|
|
|
// "legacy" parameter:
|
|
|
|
new_params.emplace_back( std::move(p) ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
params.swap(new_params); |
|
|
|
} |
|
|
|
|
|
|
|
std::ostream& operator<<(std::ostream& o, const ContentType& ct) |
|
|
|