in mailnews/mime/src/mimemsig.cpp [524:733]
static int MimeMultipartSigned_emit_child(MimeObject* obj) {
MimeMultipartSigned* sig = (MimeMultipartSigned*)obj;
MimeMultipart* mult = (MimeMultipart*)obj;
MimeContainer* cont = (MimeContainer*)obj;
int status = 0;
MimeObject* body;
if (!sig->crypto_closure) {
// We might have decided to skip processing this part.
return 0;
}
NS_ASSERTION(sig->crypto_closure, "no crypto closure");
const char* my_address = mime_part_address(obj);
if (!strcmp(my_address, "1")) {
char* ct =
(sig->body_hdrs
? MimeHeaders_get(sig->body_hdrs, HEADER_CONTENT_TYPE, true, false)
: 0);
char* ctp =
(sig->body_hdrs ? MimeHeaders_get(sig->body_hdrs, HEADER_CONTENT_TYPE,
false, false)
: 0);
char* st =
ctp ? MimeHeaders_get_parameter(ctp, "smime-type", nullptr, nullptr)
: nullptr;
if (ct && st &&
(!PL_strcasecmp(ct, APPLICATION_XPKCS7_MIME) ||
!PL_strcasecmp(ct, APPLICATION_PKCS7_MIME)) &&
!PL_strcasecmp(st, "enveloped-data")) {
(((MimeMultipartSignedClass*)obj->clazz)->crypto_signature_ignore)(
((MimeMultipartSigned*)obj)->crypto_closure);
}
PR_FREEIF(st);
PR_FREEIF(ctp);
PR_FREEIF(ct);
}
PR_Free((void*)my_address);
/* Emit some HTML saying whether the signature was cool.
But don't emit anything if in FO_QUOTE_MESSAGE mode.
*/
if (obj->options && obj->options->headers != MimeHeadersCitation &&
obj->options->write_html_p && obj->options->output_fn &&
sig->crypto_closure) {
// Calling crypto_generate_html may trigger wanted side effects,
// but we're no longer using its results.
char* html = (((MimeMultipartSignedClass*)obj->clazz)
->crypto_generate_html(sig->crypto_closure));
PR_FREEIF(html);
/* Now that we have written out the crypto stamp, the outermost header
block is well and truly closed. If this is in fact the outermost
message, then run the post_header_html_fn now.
*/
if (obj->options && obj->options->state &&
obj->options->generate_post_header_html_fn &&
!obj->options->state->post_header_html_run_p) {
MimeHeaders* outer_headers = nullptr;
MimeObject* p;
for (p = obj; p->parent; p = p->parent) outer_headers = p->headers;
NS_ASSERTION(obj->options->state->first_data_written_p,
"should have already written some data");
html = obj->options->generate_post_header_html_fn(
NULL, obj->options->html_closure, outer_headers);
obj->options->state->post_header_html_run_p = true;
if (html) {
status = MimeObject_write(obj, html, strlen(html), false);
PR_Free(html);
if (status < 0) return status;
}
}
}
/* Oh, this is fairly nasty. We're skipping over our "create child" method
and using the one our superclass defines. Perhaps instead we should add
a new method on this class, and initialize that method to be the
create_child method of the superclass. Whatever.
*/
/* The superclass method expects to find the headers for the part that it's
to create in mult->hdrs, so ensure that they're there. */
NS_ASSERTION(!mult->hdrs, "shouldn't already have hdrs for multipart");
if (mult->hdrs) MimeHeaders_free(mult->hdrs);
mult->hdrs = sig->body_hdrs;
sig->body_hdrs = 0;
/* Run the superclass create_child method.
*/
status = (((MimeMultipartClass*)(&MIME_SUPERCLASS))->create_child(obj));
if (status < 0) return status;
// Notify the charset of the first part.
if (obj->options && !(obj->options->override_charset)) {
MimeObject* firstChild = ((MimeContainer*)obj)->children[0];
char* disposition = MimeHeaders_get(
firstChild->headers, HEADER_CONTENT_DISPOSITION, true, false);
// check if need to show as inline
if (!disposition) {
const char* content_type = firstChild->content_type;
if (!PL_strcasecmp(content_type, TEXT_PLAIN) ||
!PL_strcasecmp(content_type, TEXT_HTML) ||
!PL_strcasecmp(content_type, TEXT_MDL) ||
!PL_strcasecmp(content_type, MULTIPART_ALTERNATIVE) ||
!PL_strcasecmp(content_type, MULTIPART_RELATED) ||
!PL_strcasecmp(content_type, MESSAGE_NEWS) ||
!PL_strcasecmp(content_type, MESSAGE_RFC822)) {
char* ct =
MimeHeaders_get(mult->hdrs, HEADER_CONTENT_TYPE, false, false);
if (ct) {
char* cset = MimeHeaders_get_parameter(ct, "charset", NULL, NULL);
if (cset) {
mimeEmitterUpdateCharacterSet(obj->options, cset);
SetMailCharacterSetToMsgWindow(obj, cset);
PR_Free(cset);
}
PR_Free(ct);
}
}
}
PR_Free(disposition);
}
// The js emitter wants to know about the newly created child. Because
// MimeMultipartSigned dummies out its create_child operation, the logic
// in MimeMultipart_parse_line that would normally provide this notification
// does not get to fire.
if (obj->options && obj->options->notify_nested_bodies) {
MimeObject* kid = ((MimeContainer*)obj)->children[0];
// The emitter is expecting the content type with parameters; not the fully
// parsed thing, so get it from raw. (We do not do it in the charset
// notification block that just happened because it already has complex
// if-checks that do not jive with us.
char* ct = MimeHeaders_get(mult->hdrs, HEADER_CONTENT_TYPE, false, false);
mimeEmitterAddHeaderField(obj->options, HEADER_CONTENT_TYPE,
ct ? ct : "text/plain");
PR_Free(ct);
char* part_path = mime_part_address(kid);
if (part_path) {
mimeEmitterAddHeaderField(obj->options, "x-jsemitter-part-path",
part_path);
PR_Free(part_path);
}
}
/* Retrieve the child that it created.
*/
NS_ASSERTION(cont->nchildren == 1, "should only have one child");
if (cont->nchildren != 1) return -1;
body = cont->children[0];
NS_ASSERTION(body, "missing body");
if (!body) return -1;
if (mime_typep(body, (MimeObjectClass*)&mimeSuppressedCryptoClass)) {
((MimeMultipartSignedClass*)obj->clazz)
->crypto_notify_suppressed_child(sig->crypto_closure);
}
#ifdef MIME_DRAFTS
if (body->options->decompose_file_p) {
body->options->signed_p = true;
if (!mime_typep(body, (MimeObjectClass*)&mimeMultipartClass) &&
body->options->decompose_file_init_fn)
body->options->decompose_file_init_fn(body->options->stream_closure,
body->headers);
}
#endif /* MIME_DRAFTS */
/* If there's no part_buffer, this is a zero-length signed message? */
if (sig->part_buffer) {
#ifdef MIME_DRAFTS
if (body->options->decompose_file_p &&
!mime_typep(body, (MimeObjectClass*)&mimeMultipartClass) &&
body->options->decompose_file_output_fn)
status = MimePartBufferRead(sig->part_buffer,
body->options->decompose_file_output_fn,
body->options->stream_closure);
else
#endif /* MIME_DRAFTS */
status = MimePartBufferRead(sig->part_buffer, body->clazz->parse_buffer,
MimeClosure(MimeClosure::isMimeObject, body));
if (status < 0) return status;
}
MimeMultipartSigned_cleanup(obj, false);
/* Done parsing. */
status = body->clazz->parse_eof(body, false);
if (status < 0) return status;
status = body->clazz->parse_end(body, false);
if (status < 0) return status;
#ifdef MIME_DRAFTS
if (body->options->decompose_file_p &&
!mime_typep(body, (MimeObjectClass*)&mimeMultipartClass) &&
body->options->decompose_file_close_fn)
body->options->decompose_file_close_fn(body->options->stream_closure);
#endif /* MIME_DRAFTS */
/* Put out a separator after every multipart/signed object. */
status = MimeObject_write_separator(obj);
if (status < 0) return status;
return 0;
}