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; }
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 MimeMultipartAlternative_display_cached_part(MimeObject *obj, MimeHeaders *hdrs, MimePartBufferData *buffer, bool do_display) { int status; char *ct = (hdrs ? MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, true, false) : 0); const char *dct = (((MimeMultipartClass *) obj->clazz)->default_part_type); MimeObject *body; /** Don't pass in NULL as the content-type (this means that the * auto-uudecode-hack won't ever be done for subparts of a * multipart, but only for untyped children of message/rfc822. */ const char *uct = (ct && *ct) ? ct : (dct ? dct: TEXT_PLAIN); // We always want to display the cached part inline. body = mime_create(uct, hdrs, obj->options, true); PR_FREEIF(ct); if (!body) return MIME_OUT_OF_MEMORY; body->output_p = do_display; status = ((MimeContainerClass *) obj->clazz)->add_child(obj, body); if (status < 0) { mime_free(body); return status; } /* We need to muck around with the options to prevent output when do_display is false. More about this below. */ /* add_child assigns body->options from obj->options, but that's just a pointer so if we muck with it in the child it'll modify the parent as well, which we definitely don't want. Therefore we need to make a copy. */ body->options = new MimeDisplayOptions; *body->options = *obj->options; /* But we have to be careful about getting into a situation where memory could be double-freed. All of this is a gross abstraction violation which could be avoided if it were possible to tell parse_begin what output_p should be. */ if (body->options->part_to_load) body->options->part_to_load = strdup(body->options->part_to_load); if (body->options->default_charset) body->options->default_charset = strdup(body->options->default_charset); /* parse_begin resets output_p. This is quite annoying. To convince it that we mean business, we set output_fn to null if we don't want output. */ if (! do_display) body->options->output_fn = nullptr; #ifdef MIME_DRAFTS /* if this object is a child of a multipart/related object, the parent is taking care of decomposing the whole part, don't need to do it at this level. However, we still have to call decompose_file_init_fn and decompose_file_close_fn in order to set the correct content-type. But don't call MimePartBufferRead */ bool multipartRelatedChild = mime_typep(obj->parent,(MimeObjectClass*)&mimeMultipartRelatedClass); bool decomposeFile = do_display && obj->options && obj->options->decompose_file_p && obj->options->decompose_file_init_fn && !mime_typep(body, (MimeObjectClass *) &mimeMultipartClass); if (decomposeFile) { status = obj->options->decompose_file_init_fn ( obj->options->stream_closure, hdrs); if (status < 0) return status; } #endif /* MIME_DRAFTS */ /* Now that we've added this new object to our list of children, notify emitters and start its parser going. */ MimeMultipart_notify_emitter(body); status = body->clazz->parse_begin(body); if (status < 0) return status; /* Now that parse_begin is done mucking with output_p, we can put body->options back to what it's supposed to be. Avoids a memory leak. */ delete body->options; body->options = obj->options; #ifdef MIME_DRAFTS if (decomposeFile && !multipartRelatedChild) status = MimePartBufferRead (buffer, obj->options->decompose_file_output_fn, obj->options->stream_closure); else #endif /* MIME_DRAFTS */ status = MimePartBufferRead (buffer, /* The MimeConverterOutputCallback cast is to turn the `void' argument into `MimeObject'. */ ((MimeConverterOutputCallback) body->clazz->parse_buffer), body); if (status < 0) return status; /* 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 (decomposeFile) { status = obj->options->decompose_file_close_fn ( obj->options->stream_closure ); if (status < 0) return status; } #endif /* MIME_DRAFTS */ return 0; }