p≡p MIME library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

131 lines
3.3 KiB

#include "bodyparser.hh"
#include "pEpMIME_internal.hh"
#include "rules.hh"
#include "base64.hxx"
#include "quoted_printable.hxx"
#include <pEp/pEp_string.h>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
namespace qi = boost::spirit::qi;
struct ContentType
{
std::string type;
std::string subtype;
std::vector<pEpMIME::NameValue> params;
void tolower(); // only for ASCII chars, but that's sufficient here.
};
BOOST_FUSION_ADAPT_STRUCT(
ContentType,
(std::string, type)
(std::string, subtype)
(std::vector<pEpMIME::NameValue>, params)
)
// that boost::fusion magic seems to work only in the actual TU
// so it has to be defined here, instead of at the end of pEpMIME_internal.cc *sigh*
BOOST_FUSION_ADAPT_STRUCT(
pEpMIME::NameValue,
(std::string, name)
(std::string, value)
)
void ascii_tolower(std::string& s)
{
for(char& c : s)
{
if(c>='A' && c<='Z')
{
c += 32;
}
}
}
void ContentType::tolower()
{
ascii_tolower(type);
ascii_tolower(subtype);
}
std::ostream& operator<<(std::ostream& o, const ContentType& ct)
{
return o << "CT:{" << ct.type << "/" << ct.subtype << ". params=" << ct.params << " } ";
}
namespace pEpMIME
{
char* base64_decode(const BodyLines& bl, size_t& output_size)
{
size_t out_size = 0;
for(const auto& line : bl)
{
out_size += (line.size()+3)/4 * 3;
}
char* out_string = new_string(nullptr, out_size);
char* out_begin = out_string;
char* out_end = out_string + out_size;
base64::decode_iter( BodyIterator{bl}, BodyIterator{}, out_begin, out_end);
output_size = out_begin - out_string;
return out_string;
}
char* qp_decode(const BodyLines& bl, size_t& output_size)
{
size_t out_size = 0;
for(const auto& line : bl)
{
out_size += line.size();
}
char* out_string = new_string(nullptr, out_size);
char* out_begin = out_string;
char* out_end = out_string + out_size;
qp::decode_iter( BodyIterator{bl}, BodyIterator{}, out_begin, out_end);
output_size = out_begin - out_string;
return out_string;
}
// Tokens from RFC 2045
Rule token = +( vchar - qi::char_("]()<>@,;:\\\"/?=["));
TRule<NameValue> parameter = token >> '=' >> (token | quoted_string.alias());
TRule<ContentType> content_type = token >> '/' >> token >> *( qi::omit[*cfws] >> ';' >> qi::omit[*cfws] >> parameter);
// parses the header and fill the parts in msg
void parse_body(message* msg, const HeaderSection& headers, const std::deque<sv>& body)
{
if( header_value(headers, "MIME-Version") == "1.0" ) // TODO: According to RFC 2048 there can be comments in the header field value. -.-
{
// 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);
if(!okay)
{
throw std::runtime_error( "Cannot parse \"" + std::string{cts} + "\" as ContentType");
}
ct.tolower();
std::cerr << ct << std::endl;
}else{ // Non-MIME mail
std::cerr << "<<< NO_MIME_MAIL >>>\n";
}
}
} // end of namespace pEpMIME