|
|
@ -36,7 +36,7 @@ using qi::_1; |
|
|
|
{ |
|
|
|
std::string name; |
|
|
|
int count = -1; |
|
|
|
bool with_charset = false; |
|
|
|
bool ext_value = false; // extended value: charset'language'encoded_value
|
|
|
|
}; |
|
|
|
|
|
|
|
struct Rfc2231ParamValue |
|
|
@ -96,16 +96,16 @@ 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] ); |
|
|
|
>> -(qi::lit('*')[ &(_val)->*&Rfc2231ParamName::ext_value = true] ); |
|
|
|
|
|
|
|
|
|
|
|
pEpMIME::TRule<Rfc2231ParamValue> param_value = |
|
|
|
-( |
|
|
|
-qi::hold[ |
|
|
|
(+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
|
|
|
|
] // 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) |
|
|
@ -127,7 +127,7 @@ std::string convert(std::string& charset, const std::string& input) |
|
|
|
void ContentType::unwrap() |
|
|
|
{ |
|
|
|
std::vector<pEpMIME::NameValue> new_params; |
|
|
|
std::string name, value; |
|
|
|
std::string ml_name, ml_value; // multiline parameters
|
|
|
|
std::string charset = "UTF-8"; |
|
|
|
int old_count = -1; |
|
|
|
for(auto& p:params) |
|
|
@ -136,24 +136,25 @@ void ContentType::unwrap() |
|
|
|
std::string::const_iterator begin = p.name.cbegin(); |
|
|
|
if(qi::parse(begin, p.name.cend(), param_name, pn)) |
|
|
|
{ |
|
|
|
const std::string& value = pn.ext_value ? convert(charset, p.value ) : p.value; |
|
|
|
switch(pn.count) |
|
|
|
{ |
|
|
|
case -1 : // has charset but no multi-line value
|
|
|
|
new_params.emplace_back( pn.name, convert(charset, p.value ) ); |
|
|
|
new_params.emplace_back( pn.name, value ); |
|
|
|
break; |
|
|
|
case 0 : // start of a multi-line value
|
|
|
|
if(!name.empty()) |
|
|
|
if(!ml_name.empty()) |
|
|
|
{ |
|
|
|
new_params.emplace_back( name, value); |
|
|
|
new_params.emplace_back( ml_name, ml_value); |
|
|
|
} |
|
|
|
name = pn.name; |
|
|
|
value = convert( charset, p.value ); |
|
|
|
ml_name = pn.name; |
|
|
|
ml_value = value; |
|
|
|
old_count = 0; |
|
|
|
break; |
|
|
|
default: |
|
|
|
if(pn.name == name && pn.count == old_count+1) |
|
|
|
if(pn.name == ml_name && pn.count == old_count+1) |
|
|
|
{ |
|
|
|
value += convert( charset, p.value ); |
|
|
|
ml_value += value; |
|
|
|
old_count = pn.count; |
|
|
|
}else{ |
|
|
|
// non-contiguous counter -> discard it.
|
|
|
@ -161,10 +162,10 @@ void ContentType::unwrap() |
|
|
|
break; |
|
|
|
} |
|
|
|
}else{ |
|
|
|
if(!name.empty()) |
|
|
|
if(!ml_name.empty()) |
|
|
|
{ |
|
|
|
new_params.emplace_back( name, value); |
|
|
|
name.clear(); value.clear(); |
|
|
|
new_params.emplace_back( ml_name, ml_value); |
|
|
|
ml_name.clear(); ml_value.clear(); |
|
|
|
} |
|
|
|
// "legacy" parameter:
|
|
|
|
new_params.emplace_back( std::move(p) ); |
|
|
@ -241,7 +242,7 @@ Decoder getDecoder(const sv transfer_encoding) |
|
|
|
} |
|
|
|
|
|
|
|
// Tokens from RFC 2045
|
|
|
|
Rule token = +( vchar - qi::char_("]()<>@,;:\\\"/?=[")); |
|
|
|
Rule token = +( vchar.alias() - qi::char_("]()<>@,;:\\\"/?=[")); |
|
|
|
|
|
|
|
TRule<NameValue> parameter = token >> '=' >> (token | quoted_string.alias()); |
|
|
|
TRule<ContentType> content_type = token >> '/' >> token >> *( qi::omit[*cfws] >> ';' >> qi::omit[*cfws] >> parameter); |
|
|
@ -278,6 +279,7 @@ void parse_body(message* msg, const HeaderSection& headers, const BodyLines& bod |
|
|
|
// TODO: for whatever reason "string_view cts" does not work with qi::parse(). WTF!
|
|
|
|
const std::string cts = header_value(headers, "Content-Type").to_string(); |
|
|
|
ContentType ct; |
|
|
|
|
|
|
|
auto begin = cts.cbegin(); |
|
|
|
|
|
|
|
const bool okay = qi::parse(begin, cts.cend(), content_type, ct); |
|
|
@ -285,8 +287,9 @@ void parse_body(message* msg, const HeaderSection& headers, const BodyLines& bod |
|
|
|
{ |
|
|
|
throw std::runtime_error( "Cannot parse \"" + std::string{cts} + "\" as ContentType"); |
|
|
|
} |
|
|
|
std::cerr << "<<< CT raw: " << ct << ">>>\n"; |
|
|
|
ct.sanitize(); |
|
|
|
std::cerr << ct << std::endl; |
|
|
|
std::cerr << "<<< CT san: " << ct << ">>>\n"; |
|
|
|
if(ct.type == "text") |
|
|
|
{ |
|
|
|
const sv charset = header_value( ct.params, "charset" ); |
|
|
|