static int MimeMultipartSigned_emit_child()

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;
}