static int MimeUntypedText_close_subpart(MimeObject *obj) { MimeUntypedText *uty = (MimeUntypedText *)obj; int status; if (uty->open_subpart) { status = uty->open_subpart->clazz->parse_eof(uty->open_subpart, false); uty->open_subpart = 0; PR_ASSERT(uty->open_hdrs); if (uty->open_hdrs) { MimeHeaders_free(uty->open_hdrs); uty->open_hdrs = 0; } uty->type = MimeUntypedTextSubpartTypeText; if (status < 0) return status; /* Never put out a separator between sub-parts of UntypedText. (This bypasses the rule that text/plain subparts always have separators before and after them.) */ if (obj->options && obj->options->state) obj->options->state->separator_suppressed_p = true; } PR_ASSERT(!uty->open_hdrs); return 0; }
static void MimeEncrypted_cleanup (MimeObject *obj, PRBool finalizing_p) { MimeEncrypted *enc = (MimeEncrypted *) obj; if (enc->part_buffer) { MimePartBufferDestroy(enc->part_buffer); enc->part_buffer = 0; } if (finalizing_p && enc->crypto_closure) { /* Don't free these until this object is really going away -- keep them around for the lifetime of the MIME object, so that we can get at the security info of sub-parts of the currently-displayed message. */ ((MimeEncryptedClass *) obj->clazz)->crypto_free (enc->crypto_closure); enc->crypto_closure = 0; } /* (Duplicated from MimeLeaf, see comments in mimecryp.h.) Free the decoder data, if it's still around. */ if (enc->decoder_data) { MimeDecoderDestroy(enc->decoder_data, PR_TRUE); enc->decoder_data = 0; } if (enc->hdrs) { MimeHeaders_free(enc->hdrs); enc->hdrs = 0; } }
static void MimeObject_finalize (MimeObject *obj) { obj->clazz->parse_eof (obj, PR_FALSE); obj->clazz->parse_end (obj, PR_FALSE); if (obj->headers) { MimeHeaders_free(obj->headers); obj->headers = 0; } /* Should have been freed by parse_eof, but just in case... */ NS_ASSERTION(!obj->ibuffer, "buffer not freed"); NS_ASSERTION(!obj->obuffer, "buffer not freed"); PR_FREEIF (obj->ibuffer); PR_FREEIF (obj->obuffer); PR_FREEIF(obj->content_type); PR_FREEIF(obj->encoding); if (obj->options && obj->options->state) { delete obj->options->state; obj->options->state = nsnull; } }
static int MimeMultipartSigned_close_child (MimeObject *obj) { /* The close_child method on MimeMultipartSigned doesn't actually do anything to the children list, since the create_child method also doesn't do anything. */ MimeMultipart *mult = (MimeMultipart *) obj; MimeContainer *cont = (MimeContainer *) obj; MimeMultipartSigned *msig = (MimeMultipartSigned *) obj; if (msig->part_buffer) /* Closes the tmp file, if there is one: doesn't free the part_buffer. */ MimePartBufferClose(msig->part_buffer); if (mult->hdrs) /* duplicated from MimeMultipart_close_child, ugh. */ { MimeHeaders_free(mult->hdrs); mult->hdrs = 0; } /* Should be no kids yet. */ PR_ASSERT(cont->nchildren == 0); if (cont->nchildren != 0) return -1; return 0; }
static void MimeMessage_finalize (MimeObject *object) { MimeMessage *msg = (MimeMessage *)object; if (msg->hdrs) MimeHeaders_free(msg->hdrs); msg->hdrs = 0; ((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object); }
nsresult nsMimeHeaders::Initialize(const char * aAllHeaders, PRInt32 allHeadersSize) { /* just in case we want to reuse the object, cleanup...*/ if (mHeaders) MimeHeaders_free(mHeaders); mHeaders = MimeHeaders_new(); if (mHeaders) return MimeHeaders_parse_line(aAllHeaders, allHeadersSize, mHeaders); return NS_ERROR_OUT_OF_MEMORY; }
static void MimeExternalBody_finalize (MimeObject *object) { MimeExternalBody *bod = (MimeExternalBody *) object; if (bod->hdrs) { MimeHeaders_free(bod->hdrs); bod->hdrs = 0; } PR_FREEIF(bod->body); ((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object); }
static void MimeMultipart_finalize (MimeObject *object) { MimeMultipart *mult = (MimeMultipart *) object; object->clazz->parse_eof(object, PR_FALSE); PR_FREEIF(mult->boundary); if (mult->hdrs) MimeHeaders_free(mult->hdrs); mult->hdrs = 0; ((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object); }
static void MimeMultipartSigned_cleanup (MimeObject *obj, bool finalizing_p) { MimeMultipart *mult = (MimeMultipart *) obj; /* #58075. Fix suggested by jwz */ MimeMultipartSigned *sig = (MimeMultipartSigned *) obj; if (sig->part_buffer) { MimePartBufferDestroy(sig->part_buffer); sig->part_buffer = 0; } if (sig->body_hdrs) { MimeHeaders_free (sig->body_hdrs); sig->body_hdrs = 0; } if (sig->sig_hdrs) { MimeHeaders_free (sig->sig_hdrs); sig->sig_hdrs = 0; } mult->state = MimeMultipartEpilogue; /* #58075. Fix suggested by jwz */ sig->state = MimeMultipartSignedEpilogue; if (finalizing_p && sig->crypto_closure) { /* Don't free these until this object is really going away -- keep them around for the lifetime of the MIME object, so that we can get at the security info of sub-parts of the currently-displayed message. */ ((MimeMultipartSignedClass *) obj->clazz)->crypto_free (sig->crypto_closure); sig->crypto_closure = 0; } if (sig->sig_decoder_data) { MimeDecoderDestroy(sig->sig_decoder_data, true); sig->sig_decoder_data = 0; } }
static void MimeMultipartAlternative_cleanup(MimeObject *obj) { MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj; int32_t i; for (i = 0; i < malt->pending_parts; i++) { MimeHeaders_free(malt->buffered_hdrs[i]); MimePartBufferDestroy(malt->part_buffers[i]); } PR_FREEIF(malt->buffered_hdrs); PR_FREEIF(malt->part_buffers); malt->pending_parts = 0; }
static void MimeUntypedText_finalize(MimeObject *object) { MimeUntypedText *uty = (MimeUntypedText *)object; if (uty->open_hdrs) { /* Oops, those shouldn't still be here... */ MimeHeaders_free(uty->open_hdrs); uty->open_hdrs = 0; } /* What about the open_subpart? We're going to have to assume that it is also on the MimeContainer->children list, and will get cleaned up by that class. */ ((MimeObjectClass *)&MIME_SUPERCLASS)->finalize(object); }
static int MimeMultipartAlternative_close_child(MimeObject *obj) { MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj; MimeMultipart *mult = (MimeMultipart *) obj; /* PR_ASSERT(malt->part_buffer); Some Mac brokenness trips this... if (!malt->part_buffer) return -1; */ if (malt->pending_parts) MimePartBufferClose(malt->part_buffers[malt->pending_parts-1]); /* PR_ASSERT(mult->hdrs); I expect the Mac trips this too */ if (mult->hdrs) { MimeHeaders_free(mult->hdrs); mult->hdrs = 0; } return 0; }
nsMimeHeaders::~nsMimeHeaders() { if (mHeaders) MimeHeaders_free(mHeaders); }
static int MimeMultipart_close_child(MimeObject *object) { MimeMultipart *mult = (MimeMultipart *) object; MimeContainer *cont = (MimeContainer *) object; if (!mult->hdrs) return 0; MimeHeaders_free(mult->hdrs); mult->hdrs = 0; NS_ASSERTION(cont->nchildren > 0, "badly formed mime message"); if (cont->nchildren > 0) { MimeObject *kid = cont->children[cont->nchildren-1]; // If we have a child and it has not already been closed, process it. // The kid would be already be closed if we encounter a multipart section // that did not have a fully delineated header block. No header block means // no creation of a new child, but the termination case still happens and // we still end up here. Obviously, we don't want to close the child a // second time and the best thing we can do is nothing. if (kid && !kid->closed_p) { int status; status = kid->clazz->parse_eof(kid, PR_FALSE); if (status < 0) return status; status = kid->clazz->parse_end(kid, PR_FALSE); if (status < 0) return status; #ifdef MIME_DRAFTS if ( object->options && object->options->decompose_file_p && object->options->is_multipart_msg && object->options->decompose_file_close_fn ) { if ( !mime_typep(object,(MimeObjectClass*)&mimeMultipartRelatedClass) && !mime_typep(object,(MimeObjectClass*)&mimeMultipartAlternativeClass) && !mime_typep(object,(MimeObjectClass*)&mimeMultipartSignedClass) && #ifdef MIME_DETAIL_CHECK !mime_typep(kid,(MimeObjectClass*)&mimeMultipartRelatedClass) && !mime_typep(kid,(MimeObjectClass*)&mimeMultipartAlternativeClass) && !mime_typep(kid,(MimeObjectClass*)&mimeMultipartSignedClass) #else /* bug 21869 -- due to the fact that we are not generating the correct mime class object for content-typ multipart/signed part the above check failed. to solve the problem in general and not to cause early temination when parsing message for opening as draft we can simply make sure that the child is not a multipart mime object. this way we could have a proper decomposing message part functions set correctly */ !mime_typep(kid,(MimeObjectClass*) &mimeMultipartClass) #endif && !(mime_typep(kid, (MimeObjectClass*)&mimeExternalObjectClass) && !strcmp(kid->content_type, "text/x-vcard")) ) { status = object->options->decompose_file_close_fn ( object->options->stream_closure ); if (status < 0) return status; } } #endif /* MIME_DRAFTS */ } } return 0; }
static int MimeUntypedText_open_subpart(MimeObject *obj, MimeUntypedTextSubpartType ttype, const char *type, const char *enc, const char *name, const char *desc) { MimeUntypedText *uty = (MimeUntypedText *)obj; int status = 0; char *h = 0; if (!type || !*type || !PL_strcasecmp(type, UNKNOWN_CONTENT_TYPE)) type = APPLICATION_OCTET_STREAM; if (enc && !*enc) enc = 0; if (desc && !*desc) desc = 0; if (name && !*name) name = 0; if (uty->open_subpart) { status = MimeUntypedText_close_subpart(obj); if (status < 0) return status; } NS_ASSERTION(!uty->open_subpart, "no open subpart"); NS_ASSERTION(!uty->open_hdrs, "no open headers"); /* To make one of these implicitly-typed sub-objects, we make up a fake header block, containing only the minimum number of MIME headers needed. We could do most of this (Type and Encoding) by making a null header block, and simply setting obj->content_type and obj->encoding; but making a fake header block is better for two reasons: first, it means that something will actually be displayed when in `Show All Headers' mode; and second, it's the only way to communicate the filename parameter, aside from adding a new slot to MimeObject (which is something to be avoided when possible.) */ uty->open_hdrs = MimeHeaders_new(); if (!uty->open_hdrs) return MIME_OUT_OF_MEMORY; uint32_t hlen = strlen(type) + (enc ? strlen(enc) : 0) + (desc ? strlen(desc) : 0) + (name ? strlen(name) : 0) + 100; h = (char *)PR_MALLOC(hlen); if (!h) return MIME_OUT_OF_MEMORY; PL_strncpyz(h, HEADER_CONTENT_TYPE ": ", hlen); PL_strcatn(h, hlen, type); PL_strcatn(h, hlen, MSG_LINEBREAK); status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs); if (status < 0) goto FAIL; if (enc) { PL_strncpyz(h, HEADER_CONTENT_TRANSFER_ENCODING ": ", hlen); PL_strcatn(h, hlen, enc); PL_strcatn(h, hlen, MSG_LINEBREAK); status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs); if (status < 0) goto FAIL; } if (desc) { PL_strncpyz(h, HEADER_CONTENT_DESCRIPTION ": ", hlen); PL_strcatn(h, hlen, desc); PL_strcatn(h, hlen, MSG_LINEBREAK); status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs); if (status < 0) goto FAIL; } if (name) { PL_strncpyz(h, HEADER_CONTENT_DISPOSITION ": inline; filename=\"", hlen); PL_strcatn(h, hlen, name); PL_strcatn(h, hlen, "\"" MSG_LINEBREAK); status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs); if (status < 0) goto FAIL; } /* push out a blank line. */ PL_strncpyz(h, MSG_LINEBREAK, hlen); status = MimeHeaders_parse_line(h, strlen(h), uty->open_hdrs); if (status < 0) goto FAIL; /* Create a child... */ { bool horrid_kludge = (obj->options && obj->options->state && obj->options->state->first_part_written_p); if (horrid_kludge) obj->options->state->first_part_written_p = false; uty->open_subpart = mime_create(type, uty->open_hdrs, obj->options); if (horrid_kludge) obj->options->state->first_part_written_p = true; if (!uty->open_subpart) { status = MIME_OUT_OF_MEMORY; goto FAIL; } } /* Add it to the list... */ status = ((MimeContainerClass *)obj->clazz)->add_child(obj, uty->open_subpart); if (status < 0) { mime_free(uty->open_subpart); uty->open_subpart = 0; goto FAIL; } /* And start its parser going. */ status = uty->open_subpart->clazz->parse_begin(uty->open_subpart); if (status < 0) { /* MimeContainer->finalize will take care of shutting it down now. */ uty->open_subpart = 0; goto FAIL; } uty->type = ttype; FAIL: PR_FREEIF(h); if (status < 0 && uty->open_hdrs) { MimeHeaders_free(uty->open_hdrs); uty->open_hdrs = 0; } return status; }
static int MimeMultipartAlternative_flush_children(MimeObject *obj, bool finished, bool next_is_displayable) { /* Possible states: 1. Cache contains nothing: do nothing. 2. Finished, and the cache contains one displayable body followed by zero or more non-displayable bodies: 3. Finished, and the cache contains one non-displayable body: create it with output off. 4. Not finished, and the cache contains one displayable body followed by zero or more non-displayable bodies, and the new body we're about to create is displayable: create all cached bodies with output off. 5. Not finished, and the cache contains one displayable body followed by zero or more non-displayable bodies, and the new body we're about to create is non-displayable: do nothing. 6. Not finished, and the cache contains one non-displayable body: create it with output off. */ MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj; bool have_displayable, do_flush, do_display; /* Case 1 */ if (! malt->pending_parts) return 0; have_displayable = MimeMultipartAlternative_display_part_p(obj, malt->buffered_hdrs[0]); if (finished && have_displayable) { /* Case 2 */ do_flush = true; do_display = true; } else if (finished && ! have_displayable) { /* Case 3 */ do_flush = true; do_display = false; } else if (! finished && have_displayable && next_is_displayable) { /* Case 4 */ do_flush = true; do_display = false; } else if (! finished && have_displayable && ! next_is_displayable) { /* Case 5 */ do_flush = false; do_display = false; } else if (! finished && ! have_displayable) { /* Case 6 */ do_flush = true; do_display = false; } else { NS_ERROR("mimemalt.cpp: logic error in flush_children"); return -1; } if (do_flush) { int32_t i; for (i = 0; i < malt->pending_parts; i++) { MimeMultipartAlternative_display_cached_part(obj, malt->buffered_hdrs[i], malt->part_buffers[i], do_display && (i == 0)); MimeHeaders_free(malt->buffered_hdrs[i]); MimePartBufferDestroy(malt->part_buffers[i]); } malt->pending_parts = 0; } 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; }
static int MimeMultipart_parse_line (const char *line, PRInt32 length, MimeObject *obj) { MimeMultipart *mult = (MimeMultipart *) obj; int status = 0; MimeMultipartBoundaryType boundary; NS_ASSERTION(line && *line, "empty line in multipart parse_line"); if (!line || !*line) return -1; NS_ASSERTION(!obj->closed_p, "obj shouldn't already be closed"); if (obj->closed_p) return -1; /* If we're supposed to write this object, but aren't supposed to convert it to HTML, simply pass it through unaltered. */ if (obj->output_p && obj->options && !obj->options->write_html_p && obj->options->output_fn && obj->options->format_out != nsMimeOutput::nsMimeMessageAttach) return MimeObject_write(obj, line, length, PR_TRUE); if (mult->state == MimeMultipartEpilogue) /* already done */ boundary = MimeMultipartBoundaryTypeNone; else boundary = ((MimeMultipartClass *)obj->clazz)->check_boundary(obj, line, length); if (boundary == MimeMultipartBoundaryTypeTerminator || boundary == MimeMultipartBoundaryTypeSeparator) { /* Match! Close the currently-open part, move on to the next state, and discard this line. */ PRBool endOfPart = (mult->state != MimeMultipartPreamble); if (endOfPart) status = ((MimeMultipartClass *)obj->clazz)->close_child(obj); if (status < 0) return status; if (boundary == MimeMultipartBoundaryTypeTerminator) mult->state = MimeMultipartEpilogue; else { mult->state = MimeMultipartHeaders; /* Reset the header parser for this upcoming part. */ NS_ASSERTION(!mult->hdrs, "mult->hdrs should be null here"); if (mult->hdrs) MimeHeaders_free(mult->hdrs); mult->hdrs = MimeHeaders_new(); if (!mult->hdrs) return MIME_OUT_OF_MEMORY; if (obj->options && obj->options->state && obj->options->state->partsToStrip.Length() > 0) { nsCAutoString newPart(mime_part_address(obj)); MimeContainer *container = (MimeContainer*) obj; newPart.Append('.'); newPart.AppendInt(container->nchildren + 1); obj->options->state->strippingPart = PR_FALSE; // check if this is a sub-part of a part we're stripping. for (PRUint32 partIndex = 0; partIndex < obj->options->state->partsToStrip.Length(); partIndex++) { nsCString &curPartToStrip = obj->options->state->partsToStrip[partIndex]; if (newPart.Find(curPartToStrip) == 0 && (newPart.Length() == curPartToStrip.Length() || newPart.CharAt(curPartToStrip.Length()) == '.')) { obj->options->state->strippingPart = PR_TRUE; if (partIndex < obj->options->state->detachToFiles.Length()) obj->options->state->detachedFilePath = obj->options->state->detachToFiles[partIndex]; break; } } } } // if stripping out attachments, write the boundary line. Otherwise, return // to ignore it. if (obj->options && obj->options->format_out == nsMimeOutput::nsMimeMessageAttach) { // Because MimeMultipart_parse_child_line strips out the // the CRLF of the last line before the end of a part, we need to add that // back in here. if (endOfPart) MimeWriteAString(obj, NS_LITERAL_CSTRING(MSG_LINEBREAK)); status = MimeObject_write(obj, line, length, PR_TRUE); } return 0; } /* Otherwise, this isn't a boundary string. So do whatever it is we should do with this line (parse it as a header, feed it to the child part, ignore it, etc.) */ switch (mult->state) { case MimeMultipartPreamble: case MimeMultipartEpilogue: /* Ignore this line. */ break; case MimeMultipartHeaders: /* Parse this line as a header for the sub-part. */ { status = MimeHeaders_parse_line(line, length, mult->hdrs); if (status < 0) return status; // If this line is blank, we're now done parsing headers, and should // now examine the content-type to create this "body" part. // if (*line == '\r' || *line == '\n') { if (obj->options && obj->options->state && obj->options->state->strippingPart) { PRBool detachingPart = obj->options->state->detachedFilePath.Length() > 0; nsCAutoString fileName; fileName.Adopt(MimeHeaders_get_name(mult->hdrs, obj->options)); if (detachingPart) { char *contentType = MimeHeaders_get(mult->hdrs, "Content-Type", PR_FALSE, PR_FALSE); if (contentType) { MimeWriteAString(obj, NS_LITERAL_CSTRING("Content-Type: ")); MimeWriteAString(obj, nsDependentCString(contentType)); PR_Free(contentType); } MimeWriteAString(obj, NS_LITERAL_CSTRING(MSG_LINEBREAK)); MimeWriteAString(obj, NS_LITERAL_CSTRING("Content-Disposition: attachment; filename=\"")); MimeWriteAString(obj, fileName); MimeWriteAString(obj, NS_LITERAL_CSTRING("\""MSG_LINEBREAK)); MimeWriteAString(obj, NS_LITERAL_CSTRING("X-Mozilla-External-Attachment-URL: ")); MimeWriteAString(obj, obj->options->state->detachedFilePath); MimeWriteAString(obj, NS_LITERAL_CSTRING(MSG_LINEBREAK)); MimeWriteAString(obj, NS_LITERAL_CSTRING("X-Mozilla-Altered: AttachmentDetached; date=\"")); } else { nsCAutoString header("Content-Type: text/x-moz-deleted; name=\"Deleted: "); header.Append(fileName); status = MimeWriteAString(obj, header); if (status < 0) return status; status = MimeWriteAString(obj, NS_LITERAL_CSTRING("\""MSG_LINEBREAK"Content-Transfer-Encoding: 8bit"MSG_LINEBREAK)); MimeWriteAString(obj, NS_LITERAL_CSTRING("Content-Disposition: inline; filename=\"Deleted: ")); MimeWriteAString(obj, fileName); MimeWriteAString(obj, NS_LITERAL_CSTRING("\""MSG_LINEBREAK"X-Mozilla-Altered: AttachmentDeleted; date=\"")); } nsCString result; char timeBuffer[128]; PRExplodedTime now; PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &now); PR_FormatTimeUSEnglish(timeBuffer, sizeof(timeBuffer), "%a %b %d %H:%M:%S %Y", &now); MimeWriteAString(obj, nsDependentCString(timeBuffer)); MimeWriteAString(obj, NS_LITERAL_CSTRING("\""MSG_LINEBREAK)); MimeWriteAString(obj, NS_LITERAL_CSTRING(MSG_LINEBREAK"You deleted an attachment from this message. The original MIME headers for the attachment were:"MSG_LINEBREAK)); MimeHeaders_write_raw_headers(mult->hdrs, obj->options, PR_FALSE); } status = ((MimeMultipartClass *) obj->clazz)->create_child(obj); if (status < 0) return status; NS_ASSERTION(mult->state != MimeMultipartHeaders, "mult->state shouldn't be MimeMultipartHeaders"); // Ok, at this point, we need to examine the headers and see if there // is a special charset (i.e. non US-ASCII) for this message. If so, // we need to tell the emitter that this is the case for use in in any // possible reply or forward operation. // PRBool isBody = PR_FALSE; PRBool isAlternative = PR_FALSE; MimeContainer *container = (MimeContainer*) obj; // check if we're stripping the part of this newly created child. if (container->children && container->nchildren > 0) { MimeObject *kid = container->children[container->nchildren-1]; if (kid->output_p) kid->output_p = !(obj->options && obj->options->state && obj->options->state->strippingPart); } if (container->children && container->nchildren == 1) { PRBool isAlternativeOrRelated = PR_FALSE; isBody = MimeObjectChildIsMessageBody(obj, &isAlternativeOrRelated); // MimeObjectChildIsMessageBody returns false for "multipart/related" // but we want to use the first part charset if that's a body. // I don't want to change the behavior of MimeObjectChildIsMessageBody // which is used by other places, so do the body check here. if (!isBody && isAlternativeOrRelated && mime_subclass_p(obj->clazz, (MimeObjectClass*) &mimeMultipartRelatedClass)) { MimeObject *firstChild = container->children[0]; char *disposition = MimeHeaders_get (firstChild->headers, HEADER_CONTENT_DISPOSITION, PR_TRUE, PR_FALSE); if (!disposition) { if (!PL_strcasecmp (firstChild->content_type, TEXT_PLAIN) || !PL_strcasecmp (firstChild->content_type, TEXT_HTML) || !PL_strcasecmp (firstChild->content_type, TEXT_MDL) || !PL_strcasecmp (firstChild->content_type, MULTIPART_ALTERNATIVE) || !PL_strcasecmp (firstChild->content_type, MULTIPART_RELATED) || !PL_strcasecmp (firstChild->content_type, MESSAGE_NEWS) || !PL_strcasecmp (firstChild->content_type, MESSAGE_RFC822)) isBody = PR_TRUE; } } } else isAlternative = mime_subclass_p(obj->clazz, (MimeObjectClass*) &mimeMultipartAlternativeClass); // If "multipart/alternative" or the first part is a message body // then we should check for a charset and notify the emitter // if one exists. if (obj->options && ((isAlternative && mult->state != MimeMultipartSkipPartLine) || isBody || obj->options->notify_nested_bodies)) { { char *ct = MimeHeaders_get(mult->hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE); if (ct) { if (obj->options->notify_nested_bodies) mimeEmitterAddHeaderField(obj->options, HEADER_CONTENT_TYPE, ct); char *cset = MimeHeaders_get_parameter (ct, "charset", NULL, NULL); if (cset) { mimeEmitterUpdateCharacterSet(obj->options, cset); if (!(obj->options->override_charset)) // Also set this charset to msgWindow SetMailCharacterSetToMsgWindow(obj, cset); } PR_FREEIF(ct); PR_FREEIF(cset); } // no content type means text/plain. else if (obj->options->notify_nested_bodies) { mimeEmitterAddHeaderField(obj->options, HEADER_CONTENT_TYPE, "text/plain"); } if (obj->options->notify_nested_bodies && container->nchildren) { MimeObject *kid = container->children[container->nchildren-1]; char *part_path = mime_part_address(kid); if (part_path) { mimeEmitterAddHeaderField(obj->options, "x-jsemitter-part-path", part_path); PR_Free(part_path); } } } } } break; } case MimeMultipartPartFirstLine: /* Hand this line off to the sub-part. */ status = (((MimeMultipartClass *) obj->clazz)->parse_child_line(obj, line, length, PR_TRUE)); if (status < 0) return status; mult->state = MimeMultipartPartLine; break; case MimeMultipartPartLine: /* Hand this line off to the sub-part. */ status = (((MimeMultipartClass *) obj->clazz)->parse_child_line(obj, line, length, PR_FALSE)); if (status < 0) return status; break; case MimeMultipartSkipPartLine: /* we are skipping that part, therefore just ignore the line */ break; default: NS_ERROR("unexpected state in parse line"); return -1; } if (obj->options && obj->options->format_out == nsMimeOutput::nsMimeMessageAttach && (!(obj->options->state && obj->options->state->strippingPart) && mult->state != MimeMultipartPartLine)) return MimeObject_write(obj, line, length, PR_FALSE); return 0; }
static int MimeExternalBody_parse_eof (MimeObject *obj, bool abort_p) { int status = 0; MimeExternalBody *bod = (MimeExternalBody *) 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; #ifdef XP_MACOSX if (obj->parent && mime_typep(obj->parent, (MimeObjectClass*) &mimeMultipartAppleDoubleClass)) goto done; #endif /* XP_MACOSX */ if (!abort_p && obj->output_p && obj->options && obj->options->write_html_p) { bool all_headers_p = obj->options->headers == MimeHeadersAll; MimeDisplayOptions *newopt = obj->options; /* copy it */ char *ct = MimeHeaders_get(obj->headers, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE); char *at, *lexp, *size, *perm; char *url, *dir, *mode, *name, *site, *svr, *subj; char *h = 0, *lname = 0, *lurl = 0, *body = 0; MimeHeaders *hdrs = 0; if (!ct) return MIME_OUT_OF_MEMORY; at = MimeHeaders_get_parameter(ct, "access-type", NULL, NULL); lexp = MimeHeaders_get_parameter(ct, "expiration", NULL, NULL); size = MimeHeaders_get_parameter(ct, "size", NULL, NULL); perm = MimeHeaders_get_parameter(ct, "permission", NULL, NULL); dir = MimeHeaders_get_parameter(ct, "directory", NULL, NULL); mode = MimeHeaders_get_parameter(ct, "mode", NULL, NULL); name = MimeHeaders_get_parameter(ct, "name", NULL, NULL); site = MimeHeaders_get_parameter(ct, "site", NULL, NULL); svr = MimeHeaders_get_parameter(ct, "server", NULL, NULL); subj = MimeHeaders_get_parameter(ct, "subject", NULL, NULL); url = MimeHeaders_get_parameter(ct, "url", NULL, NULL); PR_FREEIF(ct); /* the *internal* content-type */ ct = MimeHeaders_get(bod->hdrs, HEADER_CONTENT_TYPE, PR_TRUE, PR_FALSE); PRUint32 hlen = ((at ? strlen(at) : 0) + (lexp ? strlen(lexp) : 0) + (size ? strlen(size) : 0) + (perm ? strlen(perm) : 0) + (dir ? strlen(dir) : 0) + (mode ? strlen(mode) : 0) + (name ? strlen(name) : 0) + (site ? strlen(site) : 0) + (svr ? strlen(svr) : 0) + (subj ? strlen(subj) : 0) + (ct ? strlen(ct) : 0) + (url ? strlen(url) : 0) + 100); h = (char *) PR_MALLOC(hlen); if (!h) { status = MIME_OUT_OF_MEMORY; goto FAIL; } /* If there's a URL parameter, remove all whitespace from it. (The URL parameter to one of these headers is stored with lines broken every 40 characters or less; it's assumed that all significant whitespace was URL-hex-encoded, and all the rest of it was inserted just to keep the lines short.) */ if (url) { char *in, *out; for (in = url, out = url; *in; in++) if (!IS_SPACE(*in)) *out++ = *in; *out = 0; } hdrs = MimeHeaders_new(); if (!hdrs) { status = MIME_OUT_OF_MEMORY; goto FAIL; } # define FROB(STR,VAR) \ if (VAR) \ { \ PL_strncpyz(h, STR ": ", hlen); \ PL_strcatn(h, hlen, VAR); \ PL_strcatn(h, hlen, MSG_LINEBREAK); \ status = MimeHeaders_parse_line(h, strlen(h), hdrs); \ if (status < 0) goto FAIL; \ } FROB("Access-Type", at); FROB("URL", url); FROB("Site", site); FROB("Server", svr); FROB("Directory", dir); FROB("Name", name); FROB("Type", ct); FROB("Size", size); FROB("Mode", mode); FROB("Permission", perm); FROB("Expiration", lexp); FROB("Subject", subj); # undef FROB PL_strncpyz(h, MSG_LINEBREAK, hlen); status = MimeHeaders_parse_line(h, strlen(h), hdrs); if (status < 0) goto FAIL; lurl = MimeExternalBody_make_url(ct, at, lexp, size, perm, dir, mode, name, url, site, svr, subj, bod->body); if (lurl) { lname = MimeGetStringByID(MIME_MSG_LINK_TO_DOCUMENT); } else { lname = MimeGetStringByID(MIME_MSG_DOCUMENT_INFO); all_headers_p = PR_TRUE; } all_headers_p = PR_TRUE; /* #### just do this all the time? */ if (bod->body && all_headers_p) { char *s = bod->body; while (IS_SPACE(*s)) s++; if (*s) { char *s2; const char *pre = "<P><PRE>"; const char *suf = "</PRE>"; PRInt32 i; for(i = strlen(s)-1; i >= 0 && IS_SPACE(s[i]); i--) s[i] = 0; s2 = MsgEscapeHTML(s); if (!s2) goto FAIL; body = (char *) PR_MALLOC(strlen(pre) + strlen(s2) + strlen(suf) + 1); if (!body) { NS_Free(s2); goto FAIL; } PL_strcpy(body, pre); PL_strcat(body, s2); PL_strcat(body, suf); } } newopt->fancy_headers_p = PR_TRUE; newopt->headers = (all_headers_p ? MimeHeadersAll : MimeHeadersSome); FAIL: if (hdrs) MimeHeaders_free(hdrs); PR_FREEIF(h); PR_FREEIF(lname); PR_FREEIF(lurl); PR_FREEIF(body); PR_FREEIF(ct); PR_FREEIF(at); PR_FREEIF(lexp); PR_FREEIF(size); PR_FREEIF(perm); PR_FREEIF(dir); PR_FREEIF(mode); PR_FREEIF(name); PR_FREEIF(url); PR_FREEIF(site); PR_FREEIF(svr); PR_FREEIF(subj); } #ifdef XP_MACOSX done: #endif return status; }