Browse Source

merge MIME-13 into default branch.

MIME-14
Roker 2 years ago
parent
commit
9492771941
11 changed files with 173 additions and 134 deletions
  1. +4
    -2
      src/attachment.cc
  2. +10
    -3
      src/attachment.hh
  3. +19
    -18
      src/bodygenerator.cc
  4. +4
    -4
      src/bodygenerator.hh
  5. +28
    -28
      src/header_generator.cc
  6. +4
    -4
      src/header_generator.hh
  7. +11
    -11
      src/headerparser.cc
  8. +1
    -1
      src/headerparser.hh
  9. +5
    -36
      src/pEpEngine_mime.cc
  10. +83
    -23
      src/pEpMIME.cc
  11. +4
    -4
      src/pEpMIME.hh

+ 4
- 2
src/attachment.cc View File

@ -91,13 +91,15 @@ void Attachment::write_mime_headers(std::string& out) const
}
SAttachments parse_attachments(const bloblist_t* b)
SAttachments parse_attachments(const bloblist_t* b, bool has_pEp_msg_attachment)
{
unsigned nr_in_bloblist = 0;
SAttachments ret;
while(b)
{
ret.emplace_back(b);
ret.emplace_back(b, nr_in_bloblist, has_pEp_msg_attachment);
b = b->next;
++nr_in_bloblist;
}
return ret;
}


+ 10
- 3
src/attachment.hh View File

@ -17,7 +17,7 @@ namespace pEpMIME
// refers to data in a bloblist_t. Does NOT any data!
struct Attachment
{
explicit Attachment(const bloblist_t* b)
explicit Attachment(const bloblist_t* b, unsigned nr_in_bloblist, bool has_pEp_msg_attachment)
: data{b->size ? sv{b->value, b->size} : sv{}}
, mime_type{b->mime_type}
, filename{exists(b->filename) ? b->filename : sv{}}
@ -28,6 +28,11 @@ namespace pEpMIME
{
dtype = PEP_CONTENT_DISP_INLINE;
}
if((mime_type=="message/rfc822") && (nr_in_bloblist==0) && has_pEp_msg_attachment)
{
mime_type += "; forwarded=\"no\"";
}
}
Attachment(sv _data, sv _mime_type)
@ -47,7 +52,7 @@ namespace pEpMIME
}
sv data;
sv mime_type;
std::string mime_type;
sv filename;
content_disposition_type dtype;
bool need_te; // need transport encoding
@ -55,7 +60,7 @@ namespace pEpMIME
typedef std::vector<Attachment> SAttachments;
SAttachments parse_attachments(const bloblist_t* att);
SAttachments parse_attachments(const bloblist_t* att, bool has_pEp_msg_attachment);
inline
bool all(const Attachment&) { return true; }
@ -66,6 +71,8 @@ namespace pEpMIME
inline
bool is_not_inline(const Attachment& att) { return att.is_inline() == false; }
// serialize all attachments, with the given delimiter
// NOTA BENE: It closes this multipart/* subtree by adding the proper final delimiter.
void generate_attachments(std::string& out, const SAttachments& att, sv delimiter, bool(*filter)(const Attachment&) = all);
}


+ 19
- 18
src/bodygenerator.cc View File

@ -56,11 +56,11 @@ std::string longmsg_mimetype(const message* msg)
}
void generate_body(std::string& smsg, sv mime_type, sv body, bool transport_encode)
void generate_body(std::string& smsg, sv mime_type, sv body)
{
smsg += "Content-Type: "s + mime_type + "; charset=UTF-8;\r\n"s;
if(transport_encode==false || need_transport_encoding(body)==false)
if(need_transport_encoding(body)==false)
{
smsg += "\r\n"; // end of header section
smsg += body;
@ -72,10 +72,10 @@ void generate_body(std::string& smsg, sv mime_type, sv body, bool transport_enco
}
void generate_ma_body(std::string& smsg, sv plain_mimetype, sv plain, sv html, bool transport_encode)
void generate_ma_body(std::string& smsg, sv plain_mimetype, sv plain, sv html)
{
const bool encode_plain = transport_encode && need_transport_encoding(plain);
const bool encode_html = transport_encode && need_transport_encoding(html);
const bool encode_plain = need_transport_encoding(plain);
const bool encode_html = need_transport_encoding(html);
unsigned long long counter=0;
std::string delimiter = generate_delimiter(counter);
@ -91,14 +91,14 @@ void generate_ma_body(std::string& smsg, sv plain_mimetype, sv plain, sv html, b
"\r\n"; // end of header section
smsg += "--" + delimiter + "\r\n";
generate_body(smsg, plain_mimetype, plain, transport_encode);
generate_body(smsg, plain_mimetype, plain);
smsg += "--" + delimiter + "\r\n";
generate_body(smsg, "text/html", html, transport_encode);
generate_body(smsg, "text/html", html);
smsg += "--" + delimiter + "--\r\n";
}
void generate_mm_body(std::string& smsg, sv mime_type, sv body, const std::vector<Attachment>& a, bool transport_encode)
void generate_mm_body(std::string& smsg, sv mime_type, sv body, const std::vector<Attachment>& a)
{
std::vector<Attachment> a2{a};
a2.emplace_back(body, mime_type);
@ -111,7 +111,7 @@ void generate_mm_body(std::string& smsg, sv mime_type, sv body, const std::vecto
if(mime_type.size())
{
smsg += "--" + delimiter + "\r\n";
generate_body(smsg, mime_type, body, transport_encode);
generate_body(smsg, mime_type, body);
}
generate_attachments(smsg, a, delimiter);
@ -120,7 +120,7 @@ void generate_mm_body(std::string& smsg, sv mime_type, sv body, const std::vecto
// complex MIME structures, depending on "det"
// see: https://dev.pep.foundation/libpEpMIME
void generate_complex_body(std::string& smsg, unsigned det, const message* msg, const std::vector<Attachment>& a, bool transport_encode)
void generate_complex_body(std::string& smsg, unsigned det, const message* msg, const std::vector<Attachment>& a)
{
const std::string longmsg_mimetype = pEpMIME::longmsg_mimetype(msg);
@ -139,7 +139,7 @@ void generate_complex_body(std::string& smsg, unsigned det, const message* msg,
case 6: smsg += "Content-Type: multipart/related; boundary=\"" + delimiter + "\";\r\n"
"\r\n" // end of header section
"--" + delimiter + "\r\n";
generate_body(smsg, "text/html", msg->longmsg_formatted, transport_encode);
generate_body(smsg, "text/html", msg->longmsg_formatted);
generate_attachments(smsg, a, delimiter);
break;
case 7:
@ -148,13 +148,13 @@ void generate_complex_body(std::string& smsg, unsigned det, const message* msg,
smsg += "Content-Type: multipart/alternative; boundary=\"" + delimiter_A + "\";\r\n"
"\r\n"
"--" + delimiter_A + "\r\n";
generate_body(smsg, longmsg_mimetype, msg->longmsg, transport_encode);
generate_body(smsg, longmsg_mimetype, msg->longmsg);
smsg += "--" + delimiter_A + "\r\n";
const std::string delimiter_R = delimiter + "R=";
smsg += "Content-Type: multipart/related; boundary=\"" + delimiter_R + "\";\r\n"
"\r\n"
"--" + delimiter_R + "\r\n";
generate_body(smsg, "text/html", msg->longmsg_formatted, transport_encode);
generate_body(smsg, "text/html", msg->longmsg_formatted);
generate_attachments(smsg, a, delimiter_R);
smsg += "--" + delimiter_A + "--\r\n";
break;
@ -169,9 +169,9 @@ void generate_complex_body(std::string& smsg, unsigned det, const message* msg,
smsg += "Content-Type: multipart/alternative; boundary=\"" + delimiter_A + "\";\r\n"
"\r\n"
"--" + delimiter_A + "\r\n";
generate_body(smsg, longmsg_mimetype, msg->longmsg, transport_encode);
generate_body(smsg, longmsg_mimetype, msg->longmsg);
smsg += "--" + delimiter_A + "\r\n";
generate_body(smsg, "text/html", msg->longmsg_formatted, transport_encode);
generate_body(smsg, "text/html", msg->longmsg_formatted);
smsg += "--" + delimiter_A + "--\r\n"
"\r\n";
generate_attachments(smsg, a, delimiter_M);
@ -187,8 +187,9 @@ void generate_complex_body(std::string& smsg, unsigned det, const message* msg,
smsg += "Content-Type: multipart/related; boundary=\"" + delimiter_R + "\";\r\n"
"\r\n"
"--" + delimiter_R + "\r\n";
generate_body(smsg, "text/html", msg->longmsg_formatted, transport_encode);
generate_body(smsg, "text/html", msg->longmsg_formatted);
generate_attachments(smsg, a, delimiter_R, &is_inline );
// closing of delimiter_R is done in generate_attachments()
generate_attachments(smsg, a, delimiter_M, &is_not_inline );
break;
}
@ -203,12 +204,12 @@ void generate_complex_body(std::string& smsg, unsigned det, const message* msg,
smsg += "Content-Type: multipart/alternative; boundary=\"" + delimiter_A + "\";\r\n"
"\r\n"
"--" + delimiter_A + "\r\n";
generate_body(smsg, longmsg_mimetype, msg->longmsg, transport_encode);
generate_body(smsg, longmsg_mimetype, msg->longmsg);
smsg += "--" + delimiter_A + "\r\n"
"Content-Type: multipart/related; boundary=\"" + delimiter_R + "\";\r\n"
"\r\n"
"--" + delimiter_R + "\r\n";
generate_body(smsg, "text/html", msg->longmsg_formatted, transport_encode);
generate_body(smsg, "text/html", msg->longmsg_formatted);
generate_attachments(smsg, a, delimiter_R, &is_inline );
// closing of delimiter_R is done in generate_attachments()
smsg += "--" + delimiter_A + "--\r\n";


+ 4
- 4
src/bodygenerator.hh View File

@ -9,17 +9,17 @@ namespace pEpMIME
// is "text/plain", optionally annotated with format=... and delsp=...
std::string longmsg_mimetype(const message* msg);
void generate_body(std::string& smsg, sv mime_type, sv body, bool transport_encode);
void generate_body(std::string& smsg, sv mime_type, sv body);
// generate "multipart/alternative" body with "text/plain" and "text/html" parts
void generate_ma_body(std::string& smsg, sv plain_mimetype, sv plain, sv html, bool transport_encode);
void generate_ma_body(std::string& smsg, sv plain_mimetype, sv plain, sv html);
// generate "multipart/mixed" body
void generate_mm_body(std::string& smsg, sv mime_type, sv body, const std::vector<Attachment>& a, bool transport_encode);
void generate_mm_body(std::string& smsg, sv mime_type, sv body, const std::vector<Attachment>& a);
// complex MIME structures, depending on "det"
// see: https://dev.pep.foundation/libpEpMIME
void generate_complex_body(std::string& smsg, unsigned det, const message* msg, const std::vector<Attachment>& a, bool transport_encode);
void generate_complex_body(std::string& smsg, unsigned det, const message* msg, const std::vector<Attachment>& a);
} // end of namespace pEpMIME


+ 28
- 28
src/header_generator.cc View File

@ -54,7 +54,7 @@ namespace
}
std::string encode_if_necessary(const Rule& rule, sv name, sv value, HeaderType type)
std::string encode_header_if_necessary(const Rule& rule, sv name, sv value, HeaderType type)
{
if(value.empty())
return std::string();
@ -81,18 +81,18 @@ namespace
return s;
}
static const TransportEncoder encoder[2] = { &dont_encode, &encode_if_necessary };
// static const TransportEncoder encoder[2] = { &dont_encode, &encode_header_if_necessary };
static const std::string CRLF = "\r\n"s;
}
void generate(std::string& out, sv header_name, const pEp_identity* id, bool transport_encode)
void generate(std::string& out, sv header_name, const pEp_identity* id)
{
LOG << "GEN_ID: " << id->username << " | " << id->address << std::endl;
static BasicRules br;
out += exists(id->username) ? encoder[transport_encode](br.phrase, header_name, id->username, qp::Word) + " " : std::string() ;
out += exists(id->username) ? encode_header_if_necessary(br.phrase, header_name, id->username, qp::Word) + " " : std::string() ;
if(!exists(id->address))
return;
@ -112,40 +112,40 @@ void generate(std::string& out, sv header_name, const pEp_identity* id, bool tra
}
void generate(std::string& out, sv header_name, const identity_list* il, bool transport_encode)
void generate(std::string& out, sv header_name, const identity_list* il)
{
LOG << "GEN_IDList: " << identity_list_length(il) << " entries. " << std::endl;
if( identity_list_length(il) == 0)
return;
generate(out, header_name, il->ident, transport_encode);
generate(out, header_name, il->ident);
il = il->next;
while(il)
{
out += (transport_encode ? ",\r\n\t" : ", ");
generate(out, std::string(), il->ident, transport_encode);
out += ",\r\n\t";
generate(out, sv{}, il->ident);
il = il->next;
}
}
void generate(std::string& out, const Rule& rule, sv header_name, const stringlist_t* sl, bool transport_encode)
void generate(std::string& out, const Rule& rule, sv header_name, const stringlist_t* sl)
{
if( stringlist_length(sl) == 0)
return;
out += encoder[transport_encode](rule, header_name, sl->value, qp::Word);
out += encode_header_if_necessary(rule, header_name, sl->value, qp::Word);
sl = sl->next;
while(sl)
{
out += (transport_encode ? ",\r\n\t" : ", ") + encoder[transport_encode](rule, "", sl->value, qp::Word);
out += ",\r\n\t" + encode_header_if_necessary(rule, "", sl->value, qp::Word);
sl = sl->next;
}
}
void generate_msgids(std::string& out, sv header_name, const stringlist_t* sl, bool transport_encode)
void generate_msgids(std::string& out, sv header_name, const stringlist_t* sl)
{
if( stringlist_length(sl) == 0)
return;
@ -157,38 +157,37 @@ void generate_msgids(std::string& out, sv header_name, const stringlist_t* sl, b
sl = sl->next;
while(sl)
{
out += std::string(transport_encode ? "\r\n\t<" : " <") + sl->value + ">";
out += std::string("\r\n\t<") + sl->value + ">";
sl = sl->next;
}
}
void generate_header(std::string& smsg, const message* msg, bool transport_encode)
void generate_header(std::string& smsg, const message* msg)
{
TransportEncoder E = transport_encode ? &encode_if_necessary : &dont_encode;
LOG << "GEN_HDR: te = " << transport_encode << std::endl;
LOG << "GEN_HDR:" << std::endl;
static BasicRules br;
if(msg->id) smsg += "Message-ID: <"s + msg->id + ">\r\n";
if(msg->shortmsg) smsg += E(br.phrase, "Subject", msg->shortmsg, qp::Text) + CRLF;
if(msg->shortmsg) smsg += encode_header_if_necessary(br.phrase, "Subject", msg->shortmsg, qp::Text) + CRLF;
LOG << "\t smsg so far: " << smsg << std::endl;
// FIXME: msg->sent , msg->received
if(msg->from) { generate(smsg, "From", msg->from, transport_encode); smsg += CRLF; }
if(msg->to) { generate(smsg, "To" , msg->to , transport_encode); smsg += CRLF; }
if(msg->cc) { generate(smsg, "Cc" , msg->cc , transport_encode); smsg += CRLF; }
if(msg->bcc) { generate(smsg, "Bcc" , msg->bcc , transport_encode); smsg += CRLF; }
if(msg->from) { generate(smsg, "From", msg->from); smsg += CRLF; }
if(msg->to) { generate(smsg, "To" , msg->to ); smsg += CRLF; }
if(msg->cc) { generate(smsg, "Cc" , msg->cc ); smsg += CRLF; }
if(msg->bcc) { generate(smsg, "Bcc" , msg->bcc ); smsg += CRLF; }
LOG << "\t smgs2 so far: " << smsg << std::endl;
if(msg->recv_by) { generate(smsg, "Received-By", msg->recv_by , transport_encode); smsg += CRLF; }
if(msg->reply_to) { generate(smsg, "Reply-To" , msg->reply_to , transport_encode); smsg += CRLF; }
if(msg->in_reply_to) { generate_msgids(smsg, "In-Reply-To", msg->in_reply_to, transport_encode); smsg += CRLF; }
if(msg->references ) { generate_msgids(smsg, "References" , msg->references , transport_encode); smsg += CRLF; }
if(msg->keywords) { generate(smsg, br.phrase, "Keywords" , msg->keywords , transport_encode); smsg += CRLF; }
if(msg->recv_by) { generate(smsg, "Received-By", msg->recv_by ); smsg += CRLF; }
if(msg->reply_to) { generate(smsg, "Reply-To" , msg->reply_to ); smsg += CRLF; }
if(msg->in_reply_to) { generate_msgids(smsg, "In-Reply-To", msg->in_reply_to); smsg += CRLF; }
if(msg->references ) { generate_msgids(smsg, "References" , msg->references ); smsg += CRLF; }
if(msg->keywords) { generate(smsg, br.phrase, "Keywords" , msg->keywords); smsg += CRLF; }
const stringpair_list_t* spl = msg->opt_fields;
LOG << "GEN_HDR: " << stringpair_list_length( spl ) << " opt_fields.\n";
@ -196,6 +195,7 @@ void generate_header(std::string& smsg, const message* msg, bool transport_encod
while(spl)
{
const char* const key = spl->value->key;
// header keys starting with ':' are pseudo headers for pEp-internal use only.
// Don't emit them in the MIME output
if(key[0]==':')
@ -209,11 +209,11 @@ void generate_header(std::string& smsg, const message* msg, bool transport_encod
{
// unknown header: only encode if contained control characters or non-ASCII characters
LOG << "\t UNKNWON HDR: " << spl->value->key << " :: " << spl->value->value << " <<< \n";
smsg += E( *(br.vchar | br.ws), spl->value->key, spl->value->value, qp::Text);
smsg += encode_header_if_necessary( *(br.vchar | br.ws), spl->value->key, spl->value->value, qp::Text);
smsg += CRLF;
}else{
LOG << "\t KNWON HDR: " << spl->value->key << " :: low_key: " << q->first << " name(): " << q->second->name() << " <<< \n";
q->second->output(smsg, msg, transport_encode);
q->second->output(smsg, msg);
}
}


+ 4
- 4
src/header_generator.hh View File

@ -8,13 +8,13 @@
namespace pEpMIME
{
void generate(std::string& out, sv header_name, const pEp_identity* id , bool transport_encode);
void generate(std::string& out, sv header_name, const identity_list* il, bool transport_encode);
void generate(std::string& out, sv header_name, const pEp_identity* id );
void generate(std::string& out, sv header_name, const identity_list* il);
// different header fields must fulfill different syntax rules. :-/
void generate(std::string& out, const Rule& rule, sv header_name, const stringlist_t* sl , bool transport_encode);
void generate(std::string& out, const Rule& rule, sv header_name, const stringlist_t* sl);
void generate_header(std::string& smsg, const message* msg, bool transport_encode);
void generate_header(std::string& smsg, const message* msg);
} // end of namespace pEpMIME


+ 11
- 11
src/headerparser.cc View File

@ -90,7 +90,7 @@ struct Discard : public HeaderBase
// Do nothing, intentionally. So this header is discarded.
}
virtual void output(std::string&, const message*, bool) override
virtual void output(std::string&, const message*) override
{
// do nothing.
}
@ -100,17 +100,17 @@ template<class TM>
struct OutputHeader : HeaderBase
{
TM message::* member;
void (*out_fn)(std::string&, const TM& data, bool transport_encode);
void (*out_fn)(std::string&, const TM& data);
OutputHeader(sv name, TM message::* m, void(*out)(std::string&, const TM&, bool))
OutputHeader(sv name, TM message::* m, void(*out)(std::string&, const TM&))
: HeaderBase(name)
, member{m}
, out_fn{out}
{}
virtual void output(std::string& out, const message* msg, bool transport_encode) override
virtual void output(std::string& out, const message* msg) override
{
out_fn(out, msg->*member, transport_encode);
out_fn(out, msg->*member);
}
};
@ -122,7 +122,7 @@ struct SimpleHeader : public OutputHeader<TM>
typedef OutputHeader<TM> Base;
TM (*in_fn)(sv);
SimpleHeader(sv name, TM message::* m, TM(*in)(sv), void(*out)(std::string&, const TM&, bool))
SimpleHeader(sv name, TM message::* m, TM(*in)(sv), void(*out)(std::string&, const TM&))
: Base(name, m, out)
, in_fn{in}
{}
@ -145,7 +145,7 @@ struct RuleHeader : public OutputHeader<TM>
TM (*in_fn)(const TP&);
const rule_t& rule;
RuleHeader(sv name, TM message::* m, const rule_t& r, TM(*in)(const TP&), void(*out)(std::string&, const TM&, bool) )
RuleHeader(sv name, TM message::* m, const rule_t& r, TM(*in)(const TP&), void(*out)(std::string&, const TM&) )
: Base(name, m, out)
, in_fn(in)
, rule{r}
@ -169,7 +169,7 @@ struct RuleHeader : public OutputHeader<TM>
};
void just_copy(std::string& out, const std::string& value, bool transport_encode)
void just_copy(std::string& out, const std::string& value)
{
out += value;
}
@ -179,7 +179,7 @@ void just_copy(std::string& out, const std::string& value, bool transport_encode
struct AuxHeader : public HeaderBase
{
// typedef qi::rule<sv::const_iterator, std::string()> rule_t;
typedef void (*out_fn_t)(std::string&, const std::string& value, bool transport_encode);
typedef void (*out_fn_t)(std::string&, const std::string& value);
out_fn_t out_fn;
@ -193,7 +193,7 @@ struct AuxHeader : public HeaderBase
add_opt_field(msg, HeaderBase::name(), s);
}
virtual void output(std::string& out, const message* msg, bool transport_encode) override
virtual void output(std::string& out, const message* msg) override
{
if(out_fn)
{
@ -202,7 +202,7 @@ struct AuxHeader : public HeaderBase
if(spl)
{
out += name_s + ": ";
out_fn(out, spl->value->value, transport_encode);
out_fn(out, spl->value->value);
out += "\r\n";
}
}


+ 1
- 1
src/headerparser.hh View File

@ -15,7 +15,7 @@ namespace pEpMIME
HeaderBase(sv _name) : m_name(_name) {}
virtual ~HeaderBase() = default;
virtual void assign(message* msg, sv) = 0;
virtual void output(std::string& out, const message* msg, bool transport_encode) = 0;
virtual void output(std::string& out, const message* msg) = 0;
sv name() const { return m_name; }


+ 5
- 36
src/pEpEngine_mime.cc View File

@ -14,41 +14,10 @@
extern "C"
{
DYNAMIC_API PEP_STATUS mime_decode_message(
const char *mimetext,
size_t size,
message **msg
)
{
assert(msg);
assert(mimetext);
if (!(msg && mimetext))
return PEP_ILLEGAL_VALUE;
PEP_STATUS status = PEP_STATUS_OK;
*msg = nullptr;
try{
message* m = pEpMIME::parse_message(mimetext, size);
if(m)
{
*msg = m;
}else{
status = PEP_OUT_OF_MEMORY;
}
}catch(...)
{
status = PEP_UNKNOWN_ERROR;
}
return status;
}
DYNAMIC_API PEP_STATUS _mime_decode_message_internal(
const char *mimetext,
size_t size,
message **msg,
bool* raise_msg_attachment
bool* has_possible_pEp_msg
)
{
assert(msg);
@ -61,7 +30,7 @@ extern "C"
*msg = nullptr;
try{
message* m = pEpMIME::parse_message(mimetext, size, raise_msg_attachment);
message* m = pEpMIME::parse_message(mimetext, size, has_possible_pEp_msg);
if(!m)
{
*msg = m;
@ -76,11 +45,11 @@ extern "C"
}
PEP_STATUS _mime_encode_message_internal(
PEP_STATUS mime_encode_message(
const message * msg,
bool omit_fields,
char **mimetext,
bool transport_encode
bool has_pEp_msg_attachment
)
{
assert(msg);
@ -93,7 +62,7 @@ extern "C"
*mimetext = nullptr;
try{
char* t = pEpMIME::generate_message(msg, omit_fields, transport_encode);
char* t = pEpMIME::generate_message(msg, omit_fields, has_pEp_msg_attachment);
if (t)
{
*mimetext = t;


+ 83
- 23
src/pEpMIME.cc View File

@ -84,7 +84,61 @@ namespace pEpMIME
return o;
}
}
// a shallow copy of pEpEngine's struct message with own opt_fields
class MessageCopy
{
public:
MessageCopy(const message* _msg_orig)
: msg_orig(_msg_orig)
, msg_copy(*msg_orig)
{
if(msg_orig->opt_fields)
{
msg_copy.opt_fields = stringpair_list_dup(msg_orig->opt_fields);
}
}
void add_header(sv key, sv value)
{
stringpair_t* sp = new_stringpair(key.data(), value.data());
if(sp==nullptr)
{
throw std::runtime_error("Out of memory. new_stringpair() in add_header() fails.");
}
auto success = stringpair_list_add(msg_copy.opt_fields, sp);
if(!success)
{
free_stringpair(sp);
throw std::runtime_error("Out of memory. stringpair_list_add() in add_header() fails.");
}
// there were no opt_fields, yet? So set them to the "last" (and only) element:
if(msg_copy.opt_fields == nullptr)
{
msg_copy.opt_fields = success;
}
}
// Neither copy nor move!
MessageCopy(const MessageCopy&) = delete;
MessageCopy(MessageCopy&&) = delete;
~MessageCopy()
{
free_stringpair_list(msg_copy.opt_fields);
msg_copy.opt_fields = nullptr;
}
operator const message* () const { return &msg_copy; }
const message* operator->() const { return &msg_copy; }
private:
const message* msg_orig;
message msg_copy;
};
} // end of anonymous namespace
template<class LineEnding>
@ -153,14 +207,20 @@ message* parse_message(const char* mime_text, size_t length, bool* raise_attachm
}
char* generate_message(const message* msg, bool omit_fields, bool transport_encode)
char* generate_message(const message* msg_orig, bool omit_fields, bool has_pEp_msg_attachment)
{
if(msg == nullptr)
if(msg_orig == nullptr)
return nullptr;
LOG << "GEN_MSG omit=" << omit_fields << ", te=" << transport_encode << std::endl;
LOG << "GEN_MSG omit=" << omit_fields << ", has_pEp_msg_att=" << has_pEp_msg_attachment << std::endl;
MessageCopy msg{msg_orig};
if(has_pEp_msg_attachment)
{
msg.add_header(Pseudo_Header_Forwarded, "no");
}
const auto attachments = parse_attachments(msg->attachments);
const auto attachments = parse_attachments(msg->attachments, has_pEp_msg_attachment);
const unsigned inline_attachments = std::count_if(
attachments.cbegin(), attachments.cend(),
[](const Attachment& a) { return a.is_inline(); }
@ -176,37 +236,37 @@ char* generate_message(const message* msg, bool omit_fields, bool transport_enco
std::string smsg;
if(omit_fields == false)
{
generate_header(smsg, msg, transport_encode);
generate_header(smsg, msg);
}
const std::string longmsg_mimetype = ::pEpMIME::longmsg_mimetype(msg);
switch(det)
{
case 0 : generate_body(smsg, "text/plain" , "", transport_encode); break; // empty text/plain body
case 1 : generate_body(smsg, longmsg_mimetype , msg->longmsg, transport_encode); break;
case 2 : generate_body(smsg, "text/html" , msg->longmsg_formatted, transport_encode); break;
case 3 : generate_ma_body(smsg, longmsg_mimetype, msg->longmsg, msg->longmsg_formatted, transport_encode); break;
case 0 : generate_body(smsg, "text/plain" , "" ); break; // empty text/plain body
case 1 : generate_body(smsg, longmsg_mimetype , msg->longmsg ); break;
case 2 : generate_body(smsg, "text/html" , msg->longmsg_formatted ); break;
case 3 : generate_ma_body(smsg, longmsg_mimetype, msg->longmsg, msg->longmsg_formatted); break;
case 4 : generate_mm_body(smsg, sv{}, sv{} , attachments, transport_encode); break;
case 5 : generate_mm_body(smsg, longmsg_mimetype, msg->longmsg , attachments, transport_encode); break;
case 6 : generate_complex_body(smsg, det, msg, attachments, transport_encode); break; // FIXME!
case 7 : generate_complex_body(smsg, det, msg, attachments, transport_encode); break; // FIXME!
case 4 : generate_mm_body(smsg, sv{}, sv{} , attachments); break;
case 5 : generate_mm_body(smsg, longmsg_mimetype, msg->longmsg , attachments); break;
case 6 : generate_complex_body(smsg, det, msg, attachments); break; // FIXME!
case 7 : generate_complex_body(smsg, det, msg, attachments); break; // FIXME!
case 8 : generate_mm_body(smsg, sv{}, sv{} , attachments, transport_encode); break;
case 9 : generate_mm_body(smsg, longmsg_mimetype, msg->longmsg , attachments, transport_encode); break;
case 10 : generate_mm_body(smsg, "text/html", msg->longmsg_formatted, attachments, transport_encode); break;
case 11 : generate_complex_body(smsg, det, msg, attachments, transport_encode); break; // FIXME!
case 8 : generate_mm_body(smsg, sv{}, sv{} , attachments); break;
case 9 : generate_mm_body(smsg, longmsg_mimetype, msg->longmsg , attachments); break;
case 10 : generate_mm_body(smsg, "text/html", msg->longmsg_formatted, attachments); break;
case 11 : generate_complex_body(smsg, det, msg, attachments); break; // FIXME!
case 12 : generate_mm_body(smsg, sv{}, sv{} , attachments, transport_encode); break;
case 13 : generate_mm_body(smsg, longmsg_mimetype, msg->longmsg , attachments, transport_encode); break;
case 14 : generate_complex_body(smsg, det, msg, attachments, transport_encode); break; // FIXME!
case 15 : generate_complex_body(smsg, det, msg, attachments, transport_encode); break; // FIXME!
case 12 : generate_mm_body(smsg, sv{}, sv{} , attachments); break;
case 13 : generate_mm_body(smsg, longmsg_mimetype, msg->longmsg , attachments); break;
case 14 : generate_complex_body(smsg, det, msg, attachments); break; // FIXME!
case 15 : generate_complex_body(smsg, det, msg, attachments); break; // FIXME!
default:
throw std::logic_error("Determinant ouf of range 0...15: det=" + std::to_string(det) );
}
return new_string( smsg.data(), smsg.size() ); // make a C-compatible copy allocated by the "right" allocator. *sigh*
}


+ 4
- 4
src/pEpMIME.hh View File

@ -31,12 +31,12 @@ const unsigned MaxMultipartNestingLevel = 100;
// parameters:
// mime_text (in) : an "Internet Message"
// length (in) : length of the mime_text, because it might contain NUL bytes
// raise_attachment(out): if not nullptr, the value is set to true if the attachment needs to be raised (pEp message format 2.x)
// has_possible_pEp_msg(out): if not nullptr, the value is set to true if the attachment needs to be raised (pEp message format 2.x)
//
// return value:
// a message struct that must be freed via free_message() or NULL on error.
//
message* parse_message(const char* mime_text, size_t length, bool* raise_attachment = nullptr);
message* parse_message(const char* mime_text, size_t length, bool* has_possible_pEp_msg = nullptr);
// Generates an RFC 5322 compliant Internet Message from the given message struct.
@ -44,13 +44,13 @@ message* parse_message(const char* mime_text, size_t length, bool* raise_attachm
// parameters:
// msg (in) : the message that shall be serialized.
// omit_fields(in) : only encode message body and attachments
// transport_encode (in) : apply transport encoding (UTF-8 otherwise)
// has_pEp_msg_attachment(in) : set forwared="no" to 1st attachment, if mime_type=="message/rfc822"
//
// return value:
// a string holding an RFC-compliant "Internet Message", or NULL on error.
// the string must be freed via pEp_free().
//
char* generate_message(const message* msg, bool omit_fields, bool transport_encode=true);
char* generate_message(const message* msg, bool omit_fields, bool has_pEp_msg_attachment=false);
} // end of namespace pEpMIME


Loading…
Cancel
Save