static int MimeExternalBody_parse_line (const char *line, PRInt32 length, MimeObject *obj) { MimeExternalBody *bod = (MimeExternalBody *) obj; int status = 0; NS_ASSERTION(line && *line, "1.1 <*****@*****.**> 19 Mar 1999 12:00"); if (!line || !*line) return -1; if (!obj->output_p) return 0; /* If we're supposed to write this object, but aren't supposed to convert it to HTML, simply pass it through unaltered. */ if (obj->options && !obj->options->write_html_p && obj->options->output_fn) return MimeObject_write(obj, line, length, PR_TRUE); /* If we already have a `body' then we're done parsing headers, and all subsequent lines get tacked onto the body. */ if (bod->body) { int L = strlen(bod->body); char *new_str = (char *)PR_Realloc(bod->body, L + length + 1); if (!new_str) return MIME_OUT_OF_MEMORY; bod->body = new_str; memcpy(bod->body + L, line, length); bod->body[L + length] = 0; return 0; } /* Otherwise we don't yet have a body, which means we're not done parsing our headers. */ if (!bod->hdrs) { bod->hdrs = MimeHeaders_new(); if (!bod->hdrs) return MIME_OUT_OF_MEMORY; } status = MimeHeaders_parse_line(line, length, bod->hdrs); if (status < 0) return status; /* If this line is blank, we're now done parsing headers, and should create a dummy body to show that. Gag. */ if (*line == '\r' || *line == '\n') { bod->body = strdup(""); if (!bod->body) return MIME_OUT_OF_MEMORY; } return 0; }
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 int MimeHandleDecryptedOutputLine (char *line, PRInt32 length, MimeObject *obj) { /* Largely the same as MimeMessage_parse_line (the other MIME container type which contains exactly one child.) */ MimeEncrypted *enc = (MimeEncrypted *) obj; int status = 0; if (!line || !*line) 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) return MimeObject_write(obj, line, length, PR_TRUE); /* If we already have a child object in the buffer, then we're done parsing headers, and all subsequent lines get passed to the inferior object without further processing by us. (Our parent will stop feeding us lines when this MimeMessage part is out of data.) */ if (enc->part_buffer) return MimePartBufferWrite (enc->part_buffer, line, length); /* Otherwise we don't yet have a child object in the buffer, which means we're not done parsing our headers yet. */ if (!enc->hdrs) { enc->hdrs = MimeHeaders_new(); if (!enc->hdrs) return MIME_OUT_OF_MEMORY; } status = MimeHeaders_parse_line(line, length, enc->hdrs); if (status < 0) return status; /* If this line is blank, we're now done parsing headers, and should examine our content-type to create our "body" part. */ if (*line == nsCRT::CR || *line == nsCRT::LF) { status = MimeEncrypted_close_headers(obj); if (status < 0) return status; } return 0; }
static int MimeMessage_parse_line (const char *aLine, PRInt32 aLength, MimeObject *obj) { const char * line = aLine; PRInt32 length = aLength; MimeMessage *msg = (MimeMessage *) obj; int status = 0; PR_ASSERT(line && *line); if (!line || !*line) return -1; #ifdef MOZ_SECURITY HG11013 #endif /* MOZ_SECURITY */ if (msg->grabSubject) { if ( (!PL_strncasecmp(line, "Subject: ", 9)) && (obj->parent) ) { if ( (obj->headers) && (!obj->headers->munged_subject) ) { obj->headers->munged_subject = (char *) PL_strndup(line + 9, length - 9); char *tPtr = obj->headers->munged_subject; while (*tPtr) { if ( (*tPtr == '\r') || (*tPtr == '\n') ) { *tPtr = '\0'; break; } tPtr++; } } } } /* If we already have a child object, then we're done parsing headers, and all subsequent lines get passed to the inferior object without further processing by us. (Our parent will stop feeding us lines when this MimeMessage part is out of data.) */ if (msg->container.nchildren) { MimeObject *kid = msg->container.children[0]; PRBool nl; PR_ASSERT(kid); if (!kid) return -1; msg->bodyLength += length; /* Don't allow MimeMessage objects to not end in a newline, since it would be inappropriate for any following part to appear on the same line as the last line of the message. #### This assumes that the only time the `parse_line' method is called with a line that doesn't end in a newline is when that line is the last line. */ nl = (length > 0 && (line[length-1] == '\r' || line[length-1] == '\n')); #ifdef MIME_DRAFTS if ( !mime_typep (kid, (MimeObjectClass*) &mimeMessageClass) && obj->options && obj->options->decompose_file_p && ! obj->options->is_multipart_msg && obj->options->decompose_file_output_fn ) { if (!obj->options->decrypt_p) { //if we are processing a flowed plain text line, we need to remove any stuffed space if (length > 0 && ' ' == *line && mime_typep(kid, (MimeObjectClass *)&mimeInlineTextPlainFlowedClass)) { line ++; length --; } status = obj->options->decompose_file_output_fn (line, length, obj->options->stream_closure); if (status < 0) return status; if (!nl) { status = obj->options->decompose_file_output_fn (MSG_LINEBREAK, MSG_LINEBREAK_LEN, obj->options->stream_closure); if (status < 0) return status; } return status; } } #endif /* MIME_DRAFTS */ if (nl) return kid->clazz->parse_buffer (line, length, kid); else { /* Hack a newline onto the end. */ char *s = (char *)PR_MALLOC(length + MSG_LINEBREAK_LEN + 1); if (!s) return MIME_OUT_OF_MEMORY; memcpy(s, line, length); PL_strncpyz(s + length, MSG_LINEBREAK, MSG_LINEBREAK_LEN); status = kid->clazz->parse_buffer (s, length + MSG_LINEBREAK_LEN, kid); PR_Free(s); return status; } } /* Otherwise we don't yet have a child object, which means we're not done parsing our headers yet. */ if (!msg->hdrs) { msg->hdrs = MimeHeaders_new(); if (!msg->hdrs) return MIME_OUT_OF_MEMORY; } #ifdef MIME_DRAFTS if ( obj->options && obj->options->decompose_file_p && ! obj->options->is_multipart_msg && obj->options->done_parsing_outer_headers && obj->options->decompose_file_output_fn ) { status = obj->options->decompose_file_output_fn( line, length, obj->options->stream_closure ); if (status < 0) return status; } #endif /* MIME_DRAFTS */ status = MimeHeaders_parse_line(line, length, msg->hdrs); if (status < 0) return status; /* If this line is blank, we're now done parsing headers, and should examine our content-type to create our "body" part. */ if (*line == '\r' || *line == '\n') { status = MimeMessage_close_headers(obj); if (status < 0) return status; } 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 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; }
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; }