static int MimeMessage_close_headers()

in mailnews/mime/src/mimemsg.cpp [224:482]


static int MimeMessage_close_headers(MimeObject* obj) {
  MimeMessage* msg = (MimeMessage*)obj;
  int status = 0;
  char* ct = 0; /* Content-Type header */
  MimeObject* body;

  // Do a proper decoding of the munged subject.
  if (obj->headers && msg->hdrs && msg->grabSubject &&
      obj->headers->munged_subject) {
    // nsMsgI18NConvertToUnicode wants nsAStrings...
    nsDependentCString orig(obj->headers->munged_subject);
    nsAutoString dest;
    // First, get the Content-Type, then extract the charset="whatever" part of
    // it.
    nsCString charset;
    nsCString contentType;
    contentType.Adopt(
        MimeHeaders_get(msg->hdrs, HEADER_CONTENT_TYPE, false, false));
    if (!contentType.IsEmpty())
      charset.Adopt(MimeHeaders_get_parameter(contentType.get(), "charset",
                                              nullptr, nullptr));

    // If we've got a charset, use nsMsgI18NConvertToUnicode to magically decode
    // the munged subject.
    if (!charset.IsEmpty()) {
      nsresult rv = nsMsgI18NConvertToUnicode(charset, orig, dest);
      // If we managed to convert the string, replace munged_subject with the
      // UTF8 version of it, otherwise, just forget about it (maybe there was an
      // improperly encoded string in there).
      PR_Free(obj->headers->munged_subject);
      if (NS_SUCCEEDED(rv))
        obj->headers->munged_subject = ToNewUTF8String(dest);
      else
        obj->headers->munged_subject = nullptr;
    } else {
      PR_Free(obj->headers->munged_subject);
      obj->headers->munged_subject = nullptr;
    }
  }

  if (msg->hdrs) {
    bool outer_p = !obj->headers; /* is this the outermost message? */

#ifdef MIME_DRAFTS
    if (outer_p && obj->options &&
        (obj->options->decompose_file_p ||
         obj->options->caller_need_root_headers) &&
        obj->options->decompose_headers_info_fn) {
#  ifdef ENABLE_SMIME
      if (obj->options->decrypt_p &&
          !mime_crypto_object_p(msg->hdrs, false, obj->options))
        obj->options->decrypt_p = false;
#  endif /* ENABLE_SMIME */
      if (!obj->options->caller_need_root_headers ||
          (obj == obj->options->state->root))
        status = obj->options->decompose_headers_info_fn(
            obj->options->stream_closure, msg->hdrs);
    }
#endif /* MIME_DRAFTS */

    /* If this is the outermost message, we need to run the
     `generate_header' callback.  This happens here instead of
     in `parse_begin', because it's only now that we've parsed
     our headers.  However, since this is the outermost message,
     we have yet to write any HTML, so that's fine.
     */
    if (outer_p && obj->output_p && obj->options &&
        obj->options->write_html_p && obj->options->generate_header_html_fn) {
      int lstatus = 0;
      char* html = 0;

      /* The generate_header_html_fn might return HTML, so it's important
       that the output stream be set up with the proper type before we
       make the MimeObject_write() call below. */
      if (!obj->options->state->first_data_written_p) {
        lstatus = MimeObject_output_init(obj, TEXT_HTML);
        if (lstatus < 0) return lstatus;
        PR_ASSERT(obj->options->state->first_data_written_p);
      }

      html = obj->options->generate_header_html_fn(
          NULL, obj->options->html_closure, msg->hdrs);
      if (html) {
        lstatus = MimeObject_write(obj, html, strlen(html), false);
        PR_Free(html);
        if (lstatus < 0) return lstatus;
      }
    }

    /* Find the content-type of the body of this message.
     */
    {
      bool ok = true;
      char* mv = MimeHeaders_get(msg->hdrs, HEADER_MIME_VERSION, true, false);

#ifdef REQUIRE_MIME_VERSION_HEADER
      /* If this is the outermost message, it must have a MIME-Version
         header with the value 1.0 for us to believe what might be in
         the Content-Type header.  If the MIME-Version header is not
         present, we must treat this message as untyped.
       */
      ok = (mv && !strcmp(mv, "1.0"));
#else
      /* #### actually, we didn't check this in Mozilla 2.0, and checking
         it now could cause some compatibility nonsense, so for now, let's
         just believe any Content-Type header we see.
       */
      ok = true;
#endif

      if (ok) {
        ct = MimeHeaders_get(msg->hdrs, HEADER_CONTENT_TYPE, true, false);

        /* If there is no Content-Type header, but there is a MIME-Version
           header, then assume that this *is* in fact a MIME message.
           (I've seen messages with

            MIME-Version: 1.0
            Content-Transfer-Encoding: quoted-printable

           and no Content-Type, and we should treat those as being of type
           MimeInlineTextPlain rather than MimeUntypedText.)
         */
        if (mv && !ct) ct = strdup(TEXT_PLAIN);
      }

      PR_FREEIF(mv); /* done with this now. */
    }

    /* If this message has a body which is encrypted and we're going to
       decrypt it (without converting it to HTML, since decrypt_p and
       write_html_p are never true at the same time)
    */
    if (obj->output_p && obj->options && obj->options->decrypt_p
#ifdef ENABLE_SMIME
        && !mime_crypto_object_p(msg->hdrs, false, obj->options)
#endif /* ENABLE_SMIME */
    ) {
      /* The body of this message is not an encrypted object, so we need
         to turn off the decrypt_p flag (to prevent us from s#$%ing the
         body of the internal object up into one.) In this case,
         our output will end up being identical to our input.
      */
      obj->options->decrypt_p = false;
    }

    /* Emit the HTML for this message's headers.  Do this before
     creating the object representing the body.
     */
    if (obj->output_p && obj->options && obj->options->write_html_p) {
      /* If citation headers are on, and this is not the outermost message,
       turn them off. */
      if (obj->options->headers == MimeHeadersCitation && !outer_p)
        obj->options->headers = MimeHeadersSome;

      /* Emit a normal header block. */
      status = MimeMessage_write_headers_html(obj);
      if (status < 0) {
        PR_FREEIF(ct);
        return status;
      }
    } else if (obj->output_p) {
      /* Dump the headers, raw. */
      status = MimeObject_write(obj, "", 0, false); /* initialize */
      if (status < 0) {
        PR_FREEIF(ct);
        return status;
      }
      status = MimeHeaders_write_raw_headers(msg->hdrs, obj->options,
                                             obj->options->decrypt_p);
      if (status < 0) {
        PR_FREEIF(ct);
        return status;
      }
    }

#ifdef XP_UNIX
    if (outer_p && obj->output_p) /* Kludge from mimehdrs.c */
      MimeHeaders_do_unix_display_hook_hack(msg->hdrs);
#endif /* XP_UNIX */
  }

  /* Never put out a separator after a message header block. */
  if (obj->options && obj->options->state)
    obj->options->state->separator_suppressed_p = true;

#ifdef MIME_DRAFTS
  if (!obj->headers && /* outer most message header */
      obj->options && obj->options->decompose_file_p && ct)
    obj->options->is_multipart_msg = PL_strcasestr(ct, "multipart/") != NULL;
#endif /* MIME_DRAFTS */

  body = mime_create(ct, msg->hdrs, obj->options);

  PR_FREEIF(ct);
  if (!body) return MIME_OUT_OF_MEMORY;
  status = ((MimeContainerClass*)obj->clazz)->add_child(obj, body);
  if (status < 0) {
    mime_free(body);
    return status;
  }

  // Only do this if this is a Text Object!
  if (mime_typep(body, (MimeObjectClass*)&mimeInlineTextClass)) {
    ((MimeInlineText*)body)->needUpdateMsgWinCharset = true;
  }

  /* Now that we've added this new object to our list of children,
   start its parser going. */
  status = body->clazz->parse_begin(body);
  if (status < 0) return status;

  // Now notify the emitter if this is the outer most message, unless
  // it is a part that is not the head of the message. If it's a part,
  // we need to figure out the content type/charset of the part
  //
  bool outer_p = !obj->headers; /* is this the outermost message? */

  if ((outer_p || obj->options->notify_nested_bodies) &&
      (!obj->options->part_to_load ||
       obj->options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay)) {
    // call SetMailCharacterSetToMsgWindow() to set a menu charset
    if (mime_typep(body, (MimeObjectClass*)&mimeInlineTextClass)) {
      MimeInlineText* text = (MimeInlineText*)body;
      if (text && text->charset && *text->charset)
        SetMailCharacterSetToMsgWindow(body, text->charset);
    }

    char* msgID = MimeHeaders_get(msg->hdrs, HEADER_MESSAGE_ID, false, false);

    const char* outCharset = NULL;
    if (!obj->options
             ->force_user_charset) /* Only convert if the user prefs is false */
      outCharset = "UTF-8";

    mimeEmitterStartBody(obj->options,
                         (obj->options->headers == MimeHeadersNone), msgID,
                         outCharset);
    PR_FREEIF(msgID);

    // setting up truncated message html fotter function
    char* xmoz =
        MimeHeaders_get(msg->hdrs, HEADER_X_MOZILLA_STATUS, false, false);
    if (xmoz) {
      uint32_t flags = 0;
      char dummy = 0;
      if (sscanf(xmoz, " %x %c", &flags, &dummy) == 1 &&
          flags & nsMsgMessageFlags::Partial) {
        obj->options->html_closure =
            MimeClosure(MimeClosure::isMimeMessage, obj);
        obj->options->generate_footer_html_fn =
            MimeMessage_partial_message_html;
      }
      PR_FREEIF(xmoz);
    }
  }

  return 0;
}