static int MimeInlineTextPlain_parse_eof (MimeObject *obj, bool abort_p) { int status; // Has this method already been called for this object? // In that case return. if (obj->closed_p) return 0; nsCString citationColor; MimeInlineTextPlain *text = (MimeInlineTextPlain *) obj; if (text && text->mCitationColor) citationColor.Adopt(text->mCitationColor); bool quoting = ( obj->options && ( obj->options->format_out == nsMimeOutput::nsMimeMessageQuoting || obj->options->format_out == nsMimeOutput::nsMimeMessageBodyQuoting ) ); // see above bool rawPlainText = obj->options && (obj->options->format_out == nsMimeOutput::nsMimeMessageFilterSniffer || obj->options->format_out == nsMimeOutput::nsMimeMessageAttach); /* Run parent method first, to flush out any buffered data. */ status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p); if (status < 0) return status; if (!obj->output_p) return 0; if (obj->options && obj->options->write_html_p && obj->options->output_fn && !abort_p && !rawPlainText) { MimeInlineTextPlain *text = (MimeInlineTextPlain *) obj; if (text->mIsSig && !quoting) { status = MimeObject_write(obj, "</div>", 6, false); // .moz-txt-sig if (status < 0) return status; } status = MimeObject_write(obj, "</pre>", 6, false); if (status < 0) return status; if (!quoting) { status = MimeObject_write(obj, "</div>", 6, false); // .moz-text-plain if (status < 0) return status; } /* text/plain objects always have separators before and after them. Note that this is not the case for text/enriched objects. */ status = MimeObject_write_separator(obj); if (status < 0) return status; } return 0; }
static int MimeMessage_parse_begin (MimeObject *obj) { MimeMessage *msg = (MimeMessage *)obj; int status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj); if (status < 0) return status; if (obj->parent) { msg->grabSubject = PR_TRUE; } /* Messages have separators before the headers, except for the outermost message. */ return MimeObject_write_separator(obj); }
static int MimeInlineTextPlain_parse_eof (MimeObject *obj, PRBool abort_p) { int status; // Has this method already been called for this object? // In that case return. if (obj->closed_p) return 0; nsXPIDLCString citationColor; MimeInlineTextPlain *text = (MimeInlineTextPlain *) obj; if (text && text->mCitationColor) citationColor.Adopt(text->mCitationColor); PRBool quoting = ( obj->options && ( obj->options->format_out == nsMimeOutput::nsMimeMessageQuoting || obj->options->format_out == nsMimeOutput::nsMimeMessageBodyQuoting ) ); // see above PRBool rawPlainText = obj->options && (obj->options->format_out == nsMimeOutput::nsMimeMessageFilterSniffer || obj->options->format_out == nsMimeOutput::nsMimeMessageAttach); /* Run parent method first, to flush out any buffered data. */ status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p); if (status < 0) return status; // if this part has a name and it's not a message/rfc822, don't quote if (quoting && obj->headers && MimeHeaders_get_name(obj->headers, obj->options) && PL_strcasecmp(obj->content_type, MESSAGE_RFC822)) return 0; if (!obj->output_p) return 0; if (obj->options && obj->options->write_html_p && obj->options->output_fn && !abort_p && !rawPlainText) { MimeInlineTextPlain *text = (MimeInlineTextPlain *) obj; if (text->mIsSig && !quoting) { status = MimeObject_write(obj, "</div>", 6, PR_FALSE); // .moz-txt-sig if (status < 0) return status; } status = MimeObject_write(obj, "</pre>", 6, PR_FALSE); if (status < 0) return status; if (!quoting) { status = MimeObject_write(obj, "</div>", 6, PR_FALSE); // .moz-text-plain if (status < 0) return status; } /* text/plain objects always have separators before and after them. Note that this is not the case for text/enriched objects. */ status = MimeObject_write_separator(obj); if (status < 0) return status; } return 0; }
static int MimeInlineTextPlain_parse_begin (MimeObject *obj) { int status = 0; PRBool quoting = ( obj->options && ( obj->options->format_out == nsMimeOutput::nsMimeMessageQuoting || obj->options->format_out == nsMimeOutput::nsMimeMessageBodyQuoting ) ); // The output will be inserted in the composer as quotation PRBool plainHTML = quoting || (obj->options && (obj->options->format_out == nsMimeOutput::nsMimeMessageSaveAs)); // Just good(tm) HTML. No reliance on CSS. PRBool rawPlainText = obj->options && (obj->options->format_out == nsMimeOutput::nsMimeMessageFilterSniffer || obj->options->format_out == nsMimeOutput::nsMimeMessageAttach); status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj); if (status < 0) return status; if (!obj->output_p) return 0; if (obj->options && obj->options->write_html_p && obj->options->output_fn) { MimeInlineTextPlain *text = (MimeInlineTextPlain *) obj; text->mCiteLevel = 0; // Get the prefs // Quoting text->mBlockquoting = PR_TRUE; // mail.quoteasblock // Viewing text->mQuotedSizeSetting = 0; // mail.quoted_size text->mQuotedStyleSetting = 0; // mail.quoted_style text->mCitationColor = nsnull; // mail.citation_color PRBool graphicalQuote = PR_TRUE; // mail.quoted_graphical nsIPrefBranch *prefBranch = GetPrefBranch(obj->options); if (prefBranch) { prefBranch->GetIntPref("mail.quoted_size", &(text->mQuotedSizeSetting)); prefBranch->GetIntPref("mail.quoted_style", &(text->mQuotedStyleSetting)); prefBranch->GetCharPref("mail.citation_color", &(text->mCitationColor)); prefBranch->GetBoolPref("mail.quoted_graphical", &graphicalQuote); prefBranch->GetBoolPref("mail.quoteasblock", &(text->mBlockquoting)); } if (!rawPlainText) { // Get font // only used for viewing (!plainHTML) nsCAutoString fontstyle; nsCAutoString fontLang; // langgroup of the font // generic font-family name ( -moz-fixed for fixed font and NULL for // variable font ) is sufficient now that bug 105199 has been fixed. if (!obj->options->variable_width_plaintext_p) fontstyle = "font-family: -moz-fixed"; if (nsMimeOutput::nsMimeMessageBodyDisplay == obj->options->format_out || nsMimeOutput::nsMimeMessagePrintOutput == obj->options->format_out) { PRInt32 fontSize; // default font size PRInt32 fontSizePercentage; // size percentage nsresult rv = GetMailNewsFont(obj, !obj->options->variable_width_plaintext_p, &fontSize, &fontSizePercentage, fontLang); if (NS_SUCCEEDED(rv)) { if ( ! fontstyle.IsEmpty() ) { fontstyle += "; "; } fontstyle += "font-size: "; fontstyle.AppendInt(fontSize); fontstyle += "px;"; } } // Opening <div>. We currently have to add formatting here. :-( nsCAutoString openingDiv; if (!quoting) /* 4.x' editor can't break <div>s (e.g. to interleave comments). We'll add the class to the <blockquote type=cite> later. */ { openingDiv = "<div class=\"moz-text-plain\""; if (!plainHTML) { if (obj->options->wrap_long_lines_p) openingDiv += " wrap=true"; else openingDiv += " wrap=false"; if (graphicalQuote) openingDiv += " graphical-quote=true"; else openingDiv += " graphical-quote=false"; if (!fontstyle.IsEmpty()) { openingDiv += " style=\""; openingDiv += fontstyle; openingDiv += '\"'; } if (!fontLang.IsEmpty()) { openingDiv += " lang=\""; openingDiv += fontLang; openingDiv += '\"'; } } openingDiv += "><pre wrap>"; } else openingDiv = "<pre wrap>"; status = MimeObject_write(obj, openingDiv.get(), openingDiv.Length(), PR_FALSE); if (status < 0) return status; /* text/plain objects always have separators before and after them. Note that this is not the case for text/enriched objects. */ status = MimeObject_write_separator(obj); if (status < 0) return status; } } return 0; }
static int MimeMessage_parse_eof (MimeObject *obj, PRBool abort_p) { int status; PRBool outer_p; MimeMessage *msg = (MimeMessage *)obj; if (obj->closed_p) return 0; /* Run parent method first, to flush out any buffered data. */ status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p); if (status < 0) return status; outer_p = !obj->headers; /* is this the outermost message? */ // Hack for messages with truncated headers (bug 244722) // If there is no empty line in a message, the parser can't figure out where // the headers end, causing parsing to hang. So we insert an extra newline // to keep it happy. This is OK, since a message without any empty lines is // broken anyway... if(outer_p && msg->hdrs && ! msg->hdrs->done_p) { MimeMessage_parse_line("\n", 1, obj); } // Once we get to the end of parsing the message, we will notify // the emitter that we are done the the body. // Mark the end of the mail body if we are actually emitting the // body of the message (i.e. not Header ONLY) if (outer_p && obj->options && obj->options->write_html_p) { if (obj->options->generate_footer_html_fn) { mime_stream_data *msd = (mime_stream_data *) obj->options->stream_closure; if (msd) { char *html = obj->options->generate_footer_html_fn (msd->orig_url_name, obj->options->html_closure, msg->hdrs); if (html) { int lstatus = MimeObject_write(obj, html, strlen(html), PR_FALSE); PR_Free(html); if (lstatus < 0) return lstatus; } } } if ((!obj->options->part_to_load || obj->options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay) && obj->options->headers != MimeHeadersOnly) mimeEmitterEndBody(obj->options); } #ifdef MIME_DRAFTS if ( obj->options && obj->options->decompose_file_p && obj->options->done_parsing_outer_headers && ! obj->options->is_multipart_msg && ! mime_typep(obj, (MimeObjectClass*) &mimeEncryptedClass) && obj->options->decompose_file_close_fn ) { status = obj->options->decompose_file_close_fn ( obj->options->stream_closure ); if ( status < 0 ) return status; } #endif /* MIME_DRAFTS */ /* Put out a separator after every message/rfc822 object. */ if (!abort_p && !outer_p) { status = MimeObject_write_separator(obj); if (status < 0) return status; } return 0; }
static int MimeEncrypted_emit_buffered_child(MimeObject *obj) { MimeEncrypted *enc = (MimeEncrypted *) obj; int status = 0; char *ct = 0; MimeObject *body; NS_ASSERTION(enc->crypto_closure, "1.2 <*****@*****.**> 01 Nov 2001 17:59"); /* Emit some HTML saying whether the signature was cool. But don't emit anything if in FO_QUOTE_MESSAGE mode. Also, don't emit anything if the enclosed object is itself a signed object -- in the case of an encrypted object which contains a signed object, we only emit the HTML once (since the normal way of encrypting and signing is to nest the signature inside the crypto envelope.) */ if (enc->crypto_closure && obj->options && obj->options->headers != MimeHeadersCitation && obj->options->write_html_p && obj->options->output_fn) // && !mime_crypto_object_p(enc->hdrs, PR_TRUE)) // XXX fix later XXX // { char *html; #if 0 // XXX Fix this later XXX // char *html = (((MimeEncryptedClass *) obj->clazz)->crypto_generate_html (enc->crypto_closure)); if (!html) return -1; /* MK_OUT_OF_MEMORY? */ status = MimeObject_write(obj, html, nsCRT::strlen(html), PR_FALSE); PR_FREEIF(html); if (status < 0) return status; #endif /* 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 = nsnull; MimeObject *p; for (p = obj; p->parent; p = p->parent) outer_headers = p->headers; NS_ASSERTION(obj->options->state->first_data_written_p, "1.2 <*****@*****.**> 01 Nov 2001 17:59"); html = obj->options->generate_post_header_html_fn(NULL, obj->options->html_closure, outer_headers); obj->options->state->post_header_html_run_p = PR_TRUE; if (html) { status = MimeObject_write(obj, html, strlen(html), PR_FALSE); PR_FREEIF(html); if (status < 0) return status; } } } else if (enc->crypto_closure && obj->options && obj->options->decrypt_p) { /* Do this just to cause `mime_set_crypto_stamp' to be called, and to cause the various `decode_error' and `verify_error' slots to be set: we don't actually use the returned HTML, because we're not emitting HTML. It's maybe not such a good thing that the determination of whether it was encrypted or not is tied up with generating HTML, but oh well. */ char *html = (((MimeEncryptedClass *) obj->clazz)->crypto_generate_html (enc->crypto_closure)); PR_FREEIF(html); } if (enc->hdrs) ct = MimeHeaders_get (enc->hdrs, HEADER_CONTENT_TYPE, PR_TRUE, PR_FALSE); body = mime_create((ct ? ct : TEXT_PLAIN), enc->hdrs, obj->options); #ifdef MIME_DRAFTS if (obj->options->decompose_file_p) { if (mime_typep (body, (MimeObjectClass*) &mimeMultipartClass) ) obj->options->is_multipart_msg = PR_TRUE; else if (obj->options->decompose_file_init_fn) obj->options->decompose_file_init_fn(obj->options->stream_closure, enc->hdrs); } #endif /* MIME_DRAFTS */ 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; } /* 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; /* If this object (or the parent) is being output, then by definition the child is as well. (This is only necessary because this is such a funny sort of container...) */ if (!body->output_p && (obj->output_p || (obj->parent && obj->parent->output_p))) body->output_p = PR_TRUE; /* If the body is being written raw (not as HTML) then make sure to write its headers as well. */ if (body->output_p && obj->output_p && !obj->options->write_html_p) { status = MimeObject_write(body, "", 0, PR_FALSE); /* initialize */ if (status < 0) return status; status = MimeHeaders_write_raw_headers(body->headers, obj->options, PR_FALSE); if (status < 0) return status; } if (enc->part_buffer) /* part_buffer is 0 for 0-length encrypted data. */ #ifdef MIME_DRAFTS if (obj->options->decompose_file_p && !obj->options->is_multipart_msg) status = MimePartBufferRead(enc->part_buffer, /* The (nsresult (*) ...) cast is to turn the `void' argument into `MimeObject'. */ ((nsresult (*) (const char *, PRInt32, void *)) obj->options->decompose_file_output_fn), obj->options->stream_closure); else #endif /* MIME_DRAFTS */ status = MimePartBufferRead(enc->part_buffer, /* The (nsresult (*) ...) cast is to turn the `void' argument into `MimeObject'. */ ((nsresult (*) (const char *, PRInt32, void *)) body->clazz->parse_buffer), body); if (status < 0) return status; /* The child has been fully processed. Close it off. */ status = body->clazz->parse_eof(body, PR_FALSE); if (status < 0) return status; status = body->clazz->parse_end(body, PR_FALSE); if (status < 0) return status; #ifdef MIME_DRAFTS if (obj->options->decompose_file_p && !obj->options->is_multipart_msg) obj->options->decompose_file_close_fn(obj->options->stream_closure); #endif /* MIME_DRAFTS */ /* Put out a separator after every encrypted object. */ status = MimeObject_write_separator(obj); if (status < 0) return status; MimeEncrypted_cleanup (obj, PR_FALSE); return 0; }
static int MimeInlineImage_parse_begin (MimeObject *obj) { MimeInlineImage *img = (MimeInlineImage *) obj; MimeInlineImageClass *clazz; int status; status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj); if (status < 0) return status; if (!obj->output_p) return 0; if (!obj->options || !obj->options->output_fn || // don't bother processing if the consumer doesn't want us // gunking the body up. obj->options->write_pure_bodies) return 0; clazz = (MimeInlineImageClass *) obj->clazz; if (obj->options && obj->options->image_begin && obj->options->write_html_p && obj->options->image_write_buffer) { char *html, *part, *image_url; const char *ct; part = mime_part_address(obj); if (!part) return MIME_OUT_OF_MEMORY; char *no_part_url = nullptr; if (obj->options->part_to_load && obj->options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay) no_part_url = mime_get_base_url(obj->options->url); if (no_part_url) { image_url = mime_set_url_part(no_part_url, part, true); PR_Free(no_part_url); } else image_url = mime_set_url_part(obj->options->url, part, true); if (!image_url) { PR_Free(part); return MIME_OUT_OF_MEMORY; } PR_Free(part); ct = obj->content_type; if (!ct) ct = IMAGE_GIF; /* Can't happen? Close enough. */ // Fill in content type and attachment name here. nsCAutoString url_with_filename(image_url); url_with_filename += "&type="; url_with_filename += ct; char * filename = MimeHeaders_get_name ( obj->headers, obj->options ); if (filename) { nsCString escapedName; MsgEscapeString(nsDependentCString(filename), nsINetUtil::ESCAPE_URL_PATH, escapedName); url_with_filename += "&filename="; url_with_filename += escapedName; PR_Free(filename); } // We need to separate images with HR's... MimeObject_write_separator(obj); img->image_data = obj->options->image_begin(url_with_filename.get(), ct, obj->options->stream_closure); PR_Free(image_url); if (!img->image_data) return MIME_OUT_OF_MEMORY; html = obj->options->make_image_html(img->image_data); if (!html) return MIME_OUT_OF_MEMORY; status = MimeObject_write(obj, html, strlen(html), true); PR_Free(html); if (status < 0) return status; } // // Now we are going to see if we should set the content type in the // URI for the url being run... // if (obj->options && obj->options->stream_closure && obj->content_type) { mime_stream_data *msd = (mime_stream_data *) (obj->options->stream_closure); if ( (msd) && (msd->channel) ) { msd->channel->SetContentType(nsDependentCString(obj->content_type)); } } return 0; }
static int MimeMultipartSigned_emit_child (MimeObject *obj) { MimeMultipartSigned *sig = (MimeMultipartSigned *) obj; MimeMultipart *mult = (MimeMultipart *) obj; MimeContainer *cont = (MimeContainer *) obj; int status = 0; MimeObject *body; NS_ASSERTION(sig->crypto_closure, "no crypto closure"); /* 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 && obj->options->headers != MimeHeadersCitation && sig->crypto_closure) { char *html = (((MimeMultipartSignedClass *) obj->clazz) ->crypto_generate_html (sig->crypto_closure)); #if 0 // XXX For the moment, no HTML output. Fix this XXX // if (!html) return -1; /* MIME_OUT_OF_MEMORY? */ status = MimeObject_write(obj, html, strlen(html), false); PR_Free(html); if (status < 0) return status; #endif /* 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=nsnull; 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); } } } } // 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; #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, /* The (nsresult (*) ...) cast is to turn the `void' argument into `MimeObject'. */ ((nsresult (*) (const char *, PRInt32, void *)) body->options->decompose_file_output_fn), body->options->stream_closure); else #endif /* MIME_DRAFTS */ status = MimePartBufferRead (sig->part_buffer, /* The (nsresult (*) ...) cast is to turn the `void' argument into `MimeObject'. */ ((nsresult (*) (const char *, PRInt32, void *)) body->clazz->parse_buffer), 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; }