#include "bodyparser.hh" #include "pEpMIME_internal.hh" #include "rules.hh" #include "base64.hxx" #include "quoted_printable.hxx" #include #include #include #include namespace qi = boost::spirit::qi; struct ContentType { std::string type; std::string subtype; std::vector 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, 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 parameter = token >> '=' >> (token | quoted_string.alias()); TRule 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& 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