/* Writes the headers as text/plain. This writes out a blank line after the headers, unless dont_write_content_type is true, in which case the header-block is not closed off, and none of the Content- headers are written. */ int MimeHeaders_write_raw_headers (MimeHeaders *hdrs, MimeDisplayOptions *opt, bool dont_write_content_type) { int status; if (hdrs && !hdrs->done_p) { hdrs->done_p = true; status = MimeHeaders_build_heads_list(hdrs); if (status < 0) return 0; } nsCString name; name.Adopt(MimeHeaders_get_name(hdrs, opt)); MimeHeaders_convert_header_value(opt, name, false); if (!dont_write_content_type) { char nl[] = MSG_LINEBREAK; if (hdrs) { status = MimeHeaders_write(opt, name, hdrs->all_headers, hdrs->all_headers_fp); if (status < 0) return status; } status = MimeHeaders_write(opt, name, nl, strlen(nl)); if (status < 0) return status; } else if (hdrs) { int32_t i; for (i = 0; i < hdrs->heads_size; i++) { char *head = hdrs->heads[i]; char *end = (i == hdrs->heads_size-1 ? hdrs->all_headers + hdrs->all_headers_fp : hdrs->heads[i+1]); NS_ASSERTION(head, "1.22 <*****@*****.**> 22 Aug 1999 08:48"); if (!head) continue; /* Don't write out any Content- header. */ if (!PL_strncasecmp(head, "Content-", 8)) continue; /* Write out this (possibly multi-line) header. */ status = MimeHeaders_write(opt, name, head, end - head); if (status < 0) return status; } } if (hdrs) MimeHeaders_compact(hdrs); return 0; }
static int MimeInlineTextPlain_parse_line (char *line, PRInt32 length, MimeObject *obj) { int status; PRBool quoting = ( obj->options && ( obj->options->format_out == nsMimeOutput::nsMimeMessageQuoting || obj->options->format_out == nsMimeOutput::nsMimeMessageBodyQuoting ) ); // see above PRBool plainHTML = quoting || (obj->options && obj->options->format_out == nsMimeOutput::nsMimeMessageSaveAs); // see above PRBool rawPlainText = obj->options && (obj->options->format_out == nsMimeOutput::nsMimeMessageFilterSniffer || obj->options->format_out == nsMimeOutput::nsMimeMessageAttach); // this routine gets called for every line of data that comes through the // mime converter. It's important to make sure we are efficient with // how we allocate memory in this routine. be careful if you go to add // more to this routine. NS_ASSERTION(length > 0, "zero length"); if (length <= 0) return 0; mozITXTToHTMLConv *conv = GetTextConverter(obj->options); MimeInlineTextPlain *text = (MimeInlineTextPlain *) obj; PRBool skipConversion = !conv || rawPlainText || (obj->options && obj->options->force_user_charset); char *mailCharset = NULL; nsresult rv; // 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 (!skipConversion) { nsDependentCString inputStr(line, length); nsAutoString lineSourceStr; // For 'SaveAs', |line| is in |mailCharset|. // convert |line| to UTF-16 before 'html'izing (calling ScanTXT()) if (obj->options->format_out == nsMimeOutput::nsMimeMessageSaveAs) { // Get the mail charset of this message. MimeInlineText *inlinetext = (MimeInlineText *) obj; if (!inlinetext->initializeCharset) ((MimeInlineTextClass*)&mimeInlineTextClass)->initialize_charset(obj); mailCharset = inlinetext->charset; if (mailCharset && *mailCharset) { rv = nsMsgI18NConvertToUnicode(mailCharset, inputStr, lineSourceStr); NS_ENSURE_SUCCESS(rv, -1); } else // this probably never happens ... CopyUTF8toUTF16(inputStr, lineSourceStr); } else // line is in UTF-8 CopyUTF8toUTF16(inputStr, lineSourceStr); nsCAutoString prefaceResultStr; // Quoting stuff before the real text // Recognize quotes PRUint32 oldCiteLevel = text->mCiteLevel; PRUint32 logicalLineStart = 0; rv = conv->CiteLevelTXT(lineSourceStr.get(), &logicalLineStart, &(text->mCiteLevel)); NS_ENSURE_SUCCESS(rv, -1); // Find out, which recognitions to do PRBool whattodo = obj->options->whattodo; if (plainHTML) { if (quoting) whattodo = 0; // This is done on Send. Don't do it twice. else whattodo = whattodo & ~mozITXTToHTMLConv::kGlyphSubstitution; /* Do recognition for the case, the result is viewed in Mozilla, but not GlyphSubstitution, because other UAs might not be able to display the glyphs. */ if (!text->mBlockquoting) text->mCiteLevel = 0; } // Write blockquote if (text->mCiteLevel > oldCiteLevel) { prefaceResultStr += "</pre>"; for (PRUint32 i = 0; i < text->mCiteLevel - oldCiteLevel; i++) { nsCAutoString style; MimeTextBuildPrefixCSS(text->mQuotedSizeSetting, text->mQuotedStyleSetting, text->mCitationColor, style); if (!plainHTML && !style.IsEmpty()) { prefaceResultStr += "<blockquote type=cite style=\""; prefaceResultStr += style; prefaceResultStr += "\">"; } else prefaceResultStr += "<blockquote type=cite>"; } prefaceResultStr += "<pre wrap>"; } else if (text->mCiteLevel < oldCiteLevel) { prefaceResultStr += "</pre>"; for (PRUint32 i = 0; i < oldCiteLevel - text->mCiteLevel; i++) prefaceResultStr += "</blockquote>"; prefaceResultStr += "<pre wrap>"; if (text->mCiteLevel == 0) prefaceResultStr += "<!---->"; /* Make sure, NGLayout puts out a linebreak */ } // Write plain text quoting tags if (logicalLineStart != 0 && !(plainHTML && text->mBlockquoting)) { if (!plainHTML) prefaceResultStr += "<span class=\"moz-txt-citetags\">"; nsAutoString citeTagsSource; lineSourceStr.Mid(citeTagsSource, 0, logicalLineStart); // Convert to HTML nsXPIDLString citeTagsResultUnichar; rv = conv->ScanTXT(citeTagsSource.get(), 0 /* no recognition */, getter_Copies(citeTagsResultUnichar)); if (NS_FAILED(rv)) return -1; AppendUTF16toUTF8(citeTagsResultUnichar, prefaceResultStr); if (!plainHTML) prefaceResultStr += "</span>"; } // recognize signature if ((lineSourceStr.Length() >= 4) && lineSourceStr.First() == '-' && Substring(lineSourceStr, 0, 3).EqualsLiteral("-- ") && (lineSourceStr[3] == '\r' || lineSourceStr[3] == '\n') ) { text->mIsSig = PR_TRUE; if (!quoting) prefaceResultStr += "<div class=\"moz-txt-sig\">"; } /* This is the main TXT to HTML conversion: escaping (very important), eventually recognizing etc. */ nsXPIDLString lineResultUnichar; rv = conv->ScanTXT(lineSourceStr.get() + logicalLineStart, whattodo, getter_Copies(lineResultUnichar)); NS_ENSURE_SUCCESS(rv, -1); if (!(text->mIsSig && quoting)) { status = MimeObject_write(obj, prefaceResultStr.get(), prefaceResultStr.Length(), PR_TRUE); if (status < 0) return status; nsCAutoString outString; if (obj->options->format_out != nsMimeOutput::nsMimeMessageSaveAs || !mailCharset || !*mailCharset) CopyUTF16toUTF8(lineResultUnichar, outString); else { // convert back to mailCharset before writing. rv = nsMsgI18NConvertFromUnicode(mailCharset, lineResultUnichar, outString); NS_ENSURE_SUCCESS(rv, -1); } status = MimeObject_write(obj, outString.get(), outString.Length(), PR_TRUE); } else { status = NS_OK; } } else { status = MimeObject_write(obj, line, length, PR_TRUE); } return status; }
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 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 bool MimeMultipartRelated_output_child_p(MimeObject *obj, MimeObject* child) { MimeMultipartRelated *relobj = (MimeMultipartRelated *) obj; /* rhp - Changed from "if (relobj->head_loaded)" alone to support the start parameter */ if ( (relobj->head_loaded) || (MimeStartParamExists(obj, child) && !MimeThisIsStartPart(obj, child)) ) { /* This is a child part. Just remember the mapping between the URL it represents and the part-URL to get it back. */ char* location = MimeHeaders_get(child->headers, HEADER_CONTENT_LOCATION, false, false); if (!location) { char* tmp = MimeHeaders_get(child->headers, HEADER_CONTENT_ID, false, false); if (tmp) { char* tmp2 = tmp; if (*tmp2 == '<') { int length; tmp2++; length = strlen(tmp2); if (length > 0 && tmp2[length - 1] == '>') { tmp2[length - 1] = '\0'; } } location = PR_smprintf("cid:%s", tmp2); PR_Free(tmp); } } if (location) { char *absolute; char *base_url = MimeHeaders_get(child->headers, HEADER_CONTENT_BASE, false, false); absolute = MakeAbsoluteURL(base_url ? base_url : relobj->base_url, location); PR_FREEIF(base_url); PR_Free(location); if (absolute) { nsCAutoString partnum; nsCAutoString imappartnum; partnum.Adopt(mime_part_address(child)); if (!partnum.IsEmpty()) { if (obj->options->missing_parts) { char * imappart = mime_imap_part_address(child); if (imappart) imappartnum.Adopt(imappart); } /* AppleDouble part need special care: we need to output only the data fork part of it. The problem at this point is that we haven't yet decoded the children of the AppleDouble part therfore we will have to hope the datafork is the second one! */ if (mime_typep(child, (MimeObjectClass *) &mimeMultipartAppleDoubleClass)) partnum.Append(".2"); char* part; if (!imappartnum.IsEmpty()) part = mime_set_url_imap_part(obj->options->url, imappartnum.get(), partnum.get()); else { 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) { part = mime_set_url_part(no_part_url, partnum.get(), false); PR_Free(no_part_url); } else part = mime_set_url_part(obj->options->url, partnum.get(), false); } if (part) { char *name = MimeHeaders_get_name(child->headers, child->options); // let's stick the filename in the part so save as will work. if (name) { //char *savePart = part; //part = PR_smprintf("%s&filename=%s", savePart, name); //PR_Free(savePart); PR_Free(name); } char *temp = part; /* If there's a space in the url, escape the url. (This happens primarily on Windows and Unix.) */ if (PL_strchr(part, ' ') || PL_strchr(part, '>') || PL_strchr(part, '%')) temp = escape_for_mrel_subst(part); MimeHashValue * value = new MimeHashValue(child, temp); PL_HashTableAdd(relobj->hash, absolute, value); /* rhp - If this part ALSO has a Content-ID we need to put that into the hash table and this is what this code does */ { char *tloc; char *tmp = MimeHeaders_get(child->headers, HEADER_CONTENT_ID, false, false); if (tmp) { char* tmp2 = tmp; if (*tmp2 == '<') { int length; tmp2++; length = strlen(tmp2); if (length > 0 && tmp2[length - 1] == '>') { tmp2[length - 1] = '\0'; } } tloc = PR_smprintf("cid:%s", tmp2); PR_Free(tmp); if (tloc) { MimeHashValue *value; value = (MimeHashValue*)PL_HashTableLookup(relobj->hash, tloc); if (!value) { value = new MimeHashValue(child, temp); PL_HashTableAdd(relobj->hash, tloc, value); } else PR_smprintf_free(tloc); } } } /* rhp - End of putting more stuff into the hash table */ /* it's possible that temp pointer is the same than the part pointer, therefore be carefull to not freeing twice the same pointer */ if (temp && temp != part) PR_Free(temp); PR_Free(part); } } } } } else { /* Ah-hah! We're the head object. */ char* base_url; relobj->head_loaded = true; relobj->headobj = child; relobj->buffered_hdrs = MimeHeaders_copy(child->headers); base_url = MimeHeaders_get(child->headers, HEADER_CONTENT_BASE, false, false); /* rhp: need this for supporting Content-Location */ if (!base_url) { base_url = MimeHeaders_get(child->headers, HEADER_CONTENT_LOCATION, false, false); } /* rhp: need this for supporting Content-Location */ if (base_url) { /* If the head object has a base_url associated with it, use that instead of any base_url that may have been associated with the multipart/related. */ PR_FREEIF(relobj->base_url); relobj->base_url = base_url; } } if (obj->options && !obj->options->write_html_p #ifdef MIME_DRAFTS && !obj->options->decompose_file_p #endif /* MIME_DRAFTS */ ) { return true; } return false; /* Don't actually parse this child; we'll handle all that at eof time. */ }
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; }