/* Pull the name out of some header or another. Order is: Content-Disposition: XXX; filename=NAME (RFC 1521/1806) Content-Type: XXX; name=NAME (RFC 1341) Content-Name: NAME (no RFC, but seen to occur) X-Sun-Data-Name: NAME (no RFC, but used by MailTool) */ char * MimeHeaders_get_name(MimeHeaders *hdrs, MimeDisplayOptions *opt) { char *s = 0, *name = 0, *cvt = 0; char *charset = nullptr; // for RFC2231 support s = MimeHeaders_get(hdrs, HEADER_CONTENT_DISPOSITION, false, false); if (s) { name = MimeHeaders_get_parameter(s, HEADER_PARM_FILENAME, &charset, NULL); PR_Free(s); } if (! name) { s = MimeHeaders_get(hdrs, HEADER_CONTENT_TYPE, false, false); if (s) { nsMemory::Free(charset); name = MimeHeaders_get_parameter(s, HEADER_PARM_NAME, &charset, NULL); PR_Free(s); } } if (! name) name = MimeHeaders_get (hdrs, HEADER_CONTENT_NAME, false, false); if (! name) name = MimeHeaders_get (hdrs, HEADER_X_SUN_DATA_NAME, false, false); if (name) { /* First remove continuation delimiters (CR+LF+space), then remove escape ('\\') characters, then attempt to decode mime-2 encoded-words. The latter two are done in mime_decode_filename. */ MIME_StripContinuations(name); /* Argh. What we should do if we want to be robust is to decode qtext in all appropriate headers. Unfortunately, that would be too scary at this juncture. So just decode qtext/mime2 here. */ cvt = mime_decode_filename(name, charset, opt); nsMemory::Free(charset); if (cvt && cvt != name) { PR_Free(name); name = cvt; } } return name; }
// This is necessary to determine which charset to use for a reply/forward char * DetermineMailCharset(MimeMessage *msg) { char *retCharset = nsnull; if ( (msg) && (msg->hdrs) ) { char *ct = MimeHeaders_get (msg->hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE); if (ct) { retCharset = MimeHeaders_get_parameter (ct, "charset", NULL, NULL); PR_Free(ct); } if (!retCharset) { // If we didn't find "Content-Type: ...; charset=XX" then look // for "X-Sun-Charset: XX" instead. (Maybe this should be done // in MimeSunAttachmentClass, but it's harder there than here.) retCharset = MimeHeaders_get (msg->hdrs, HEADER_X_SUN_CHARSET, PR_FALSE, PR_FALSE); } } if (!retCharset) return strdup("ISO-8859-1"); else return retCharset; }
static int MimeInlineTextHTMLSanitized_parse_begin (MimeObject *obj) { #ifdef DEBUG_BenB printf("parse_begin\n"); #endif MimeInlineTextHTMLSanitized *textHTMLSan = (MimeInlineTextHTMLSanitized *) obj; textHTMLSan->complete_buffer = new nsString(); #ifdef DEBUG_BenB printf(" B1\n"); printf(" cbp: %d\n", textHTMLSan->complete_buffer); #endif int status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj); if (status < 0) return status; #ifdef DEBUG_BenB printf(" B2\n"); #endif // charset /* honestly, I don't know how that charset stuff works in libmime. The part in mimethtm doesn't make much sense to me either. I'll just dump the charset we get in the mime headers into a HTML meta http-equiv. XXX Not sure, if that is correct, though. */ char *content_type = (obj->headers ? MimeHeaders_get(obj->headers, HEADER_CONTENT_TYPE, false, false) : 0); if (content_type) { char* charset = MimeHeaders_get_parameter(content_type, HEADER_PARM_CHARSET, NULL, NULL); PR_Free(content_type); if (charset) { nsAutoCString charsetline( "\n<meta http-equiv=\"Context-Type\" content=\"text/html; charset="); charsetline += charset; charsetline += "\">\n"; int status = MimeObject_write(obj, charsetline.get(), charsetline.Length(), true); PR_Free(charset); if (status < 0) return status; } } #ifdef DEBUG_BenB printf("/parse_begin\n"); #endif return 0; }
static bool MimeStartParamExists(MimeObject *obj, MimeObject* child) { char *ct = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE, false, false); char *st = (ct ? MimeHeaders_get_parameter(ct, HEADER_PARM_START, NULL, NULL) : 0); PR_FREEIF(ct); if (!st) return false; PR_FREEIF(st); return true; }
static int MimeMultipart_initialize (MimeObject *object) { MimeMultipart *mult = (MimeMultipart *) object; char *ct; /* This is an abstract class; it shouldn't be directly instantiated. */ PR_ASSERT(object->clazz != (MimeObjectClass *) &mimeMultipartClass); ct = MimeHeaders_get (object->headers, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE); mult->boundary = (ct ? MimeHeaders_get_parameter (ct, HEADER_PARM_BOUNDARY, NULL, NULL) : 0); PR_FREEIF(ct); mult->state = MimeMultipartPreamble; return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(object); }
static bool MimeThisIsStartPart(MimeObject *obj, MimeObject* child) { bool rval = false; char *ct, *st, *cst; ct = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE, false, false); st = (ct ? MimeHeaders_get_parameter(ct, HEADER_PARM_START, NULL, NULL) : 0); PR_FREEIF(ct); if (!st) return false; cst = MimeHeaders_get(child->headers, HEADER_CONTENT_ID, false, false); if (!cst) rval = false; else { char *tmp = cst; if (*tmp == '<') { int length; tmp++; length = strlen(tmp); if (length > 0 && tmp[length - 1] == '>') { tmp[length - 1] = '\0'; } } rval = (!strcmp(st, tmp)); } PR_FREEIF(st); PR_FREEIF(cst); return rval; }
static bool MimeExternalBody_displayable_inline_p (MimeObjectClass *clazz, MimeHeaders *hdrs) { char *ct = MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE); char *at = MimeHeaders_get_parameter(ct, "access-type", NULL, NULL); bool inline_p = false; if (!at) ; else if (!PL_strcasecmp(at, "ftp") || !PL_strcasecmp(at, "anon-ftp") || !PL_strcasecmp(at, "local-file") || !PL_strcasecmp(at, "mail-server") || !PL_strcasecmp(at, "url")) inline_p = PR_TRUE; #ifdef XP_UNIX else if (!PL_strcasecmp(at, "afs")) /* only if there is a /afs/ directory */ { nsCOMPtr <nsILocalFile> fs = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); bool exists = false; if (fs) { fs->InitWithNativePath(NS_LITERAL_CSTRING("/afs/.")); fs->Exists(&exists); } if (!exists) return 0; inline_p = PR_TRUE; } #endif /* XP_UNIX */ PR_FREEIF(ct); PR_FREEIF(at); return inline_p; }
static int MimeInlineTextPlainFlowed_parse_begin (MimeObject *obj) { int status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj); if (status < 0) return status; status = MimeObject_write(obj, "", 0, PR_TRUE); /* force out any separators... */ if(status<0) return status; PRBool quoting = ( obj->options && ( obj->options->format_out == nsMimeOutput::nsMimeMessageQuoting || obj->options->format_out == nsMimeOutput::nsMimeMessageBodyQuoting ) ); // The output will be inserted in the composer as quotation PRBool plainHTML = quoting || (obj->options && obj->options->format_out == nsMimeOutput::nsMimeMessageSaveAs); // Just good(tm) HTML. No reliance on CSS. // Setup the data structure that is connected to the actual document // Saved in a linked list in case this is called with several documents // at the same time. /* This memory is freed when parse_eof is called. So it better be! */ struct MimeInlineTextPlainFlowedExData *exdata = (MimeInlineTextPlainFlowedExData *)PR_MALLOC(sizeof(struct MimeInlineTextPlainFlowedExData)); if(!exdata) return MIME_OUT_OF_MEMORY; MimeInlineTextPlainFlowed *text = (MimeInlineTextPlainFlowed *) obj; // Link it up. exdata->next = MimeInlineTextPlainFlowedExDataList; MimeInlineTextPlainFlowedExDataList = exdata; // Initialize data exdata->ownerobj = obj; exdata->inflow = PR_FALSE; exdata->quotelevel = 0; exdata->isSig = PR_FALSE; // check for DelSp=yes (RFC 3676) char *content_type_row = (obj->headers ? MimeHeaders_get(obj->headers, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE) : 0); char *content_type_delsp = (content_type_row ? MimeHeaders_get_parameter(content_type_row, "delsp", NULL,NULL) : 0); ((MimeInlineTextPlainFlowed *)obj)->delSp = content_type_delsp && !PL_strcasecmp(content_type_delsp, "yes"); PR_Free(content_type_delsp); PR_Free(content_type_row); // Get Prefs for viewing exdata->fixedwidthfont = PR_FALSE; // Quotes text->mQuotedSizeSetting = 0; // mail.quoted_size text->mQuotedStyleSetting = 0; // mail.quoted_style text->mCitationColor = nsnull; // mail.citation_color nsIPrefBranch *prefBranch = GetPrefBranch(obj->options); if (prefBranch) { prefBranch->GetIntPref("mail.quoted_size", &(text->mQuotedSizeSetting)); prefBranch->GetIntPref("mail.quoted_style", &(text->mQuotedStyleSetting)); prefBranch->GetCharPref("mail.citation_color", &(text->mCitationColor)); nsresult rv = prefBranch->GetBoolPref("mail.fixed_width_messages", &(exdata->fixedwidthfont)); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get pref"); // Check at least the success of one } // Get font // only used for viewing (!plainHTML) nsCAutoString fontstyle; nsCAutoString fontLang; // langgroup of the font // generic font-family name ( -moz-fixed for fixed font and NULL for // variable font ) is sufficient now that bug 105199 has been fixed. if (exdata->fixedwidthfont) fontstyle = "font-family: -moz-fixed"; if (nsMimeOutput::nsMimeMessageBodyDisplay == obj->options->format_out || nsMimeOutput::nsMimeMessagePrintOutput == obj->options->format_out) { PRInt32 fontSize; // default font size PRInt32 fontSizePercentage; // size percentage nsresult rv = GetMailNewsFont(obj, exdata->fixedwidthfont, &fontSize, &fontSizePercentage, fontLang); if (NS_SUCCEEDED(rv)) { if ( ! fontstyle.IsEmpty() ) { fontstyle += "; "; } fontstyle += "font-size: "; fontstyle.AppendInt(fontSize); fontstyle += "px;"; } } // Opening <div>. if (!quoting) /* 4.x' editor can't break <div>s (e.g. to interleave comments). We'll add the class to the <blockquote type=cite> later. */ { nsCAutoString openingDiv("<div class=\"moz-text-flowed\""); // We currently have to add formatting here. :-( if (!plainHTML && !fontstyle.IsEmpty()) { openingDiv += " style=\""; openingDiv += fontstyle; openingDiv += '"'; } if (!plainHTML && !fontLang.IsEmpty()) { openingDiv += " lang=\""; openingDiv += fontLang; openingDiv += '\"'; } openingDiv += ">"; status = MimeObject_write(obj, openingDiv.get(), openingDiv.Length(), PR_FALSE); if (status < 0) return status; } 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 MimeInlineText_initializeCharset(MimeObject *obj) { MimeInlineText *text = (MimeInlineText *) obj; text->inputAutodetect = false; text->charsetOverridable = false; /* Figure out an appropriate charset for this object. */ if (!text->charset && obj->headers) { if (obj->options && obj->options->override_charset) { text->charset = strdup(obj->options->default_charset); } else { char *ct = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE, false, false); if (ct) { text->charset = MimeHeaders_get_parameter (ct, "charset", NULL, NULL); PR_Free(ct); } if (!text->charset) { /* If we didn't find "Content-Type: ...; charset=XX" then look for "X-Sun-Charset: XX" instead. (Maybe this should be done in MimeSunAttachmentClass, but it's harder there than here.) */ text->charset = MimeHeaders_get (obj->headers, HEADER_X_SUN_CHARSET, false, false); } /* iMIP entities without an explicit charset parameter default to US-ASCII (RFC 2447, section 2.4). However, Microsoft Outlook generates UTF-8 but omits the charset parameter. When no charset is defined by the container (e.g. iMIP), iCalendar files default to UTF-8 (RFC 2445, section 4.1.4). */ if (!text->charset && obj->content_type && !PL_strcasecmp(obj->content_type, TEXT_CALENDAR)) text->charset = strdup("UTF-8"); if (!text->charset) { nsresult res; text->charsetOverridable = true; nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &res)); if (NS_SUCCEEDED(res)) { nsCOMPtr<nsIPrefLocalizedString> str; if (NS_SUCCEEDED(prefBranch->GetComplexValue("intl.charset.detector", NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(str)))) { //only if we can get autodetector name correctly, do we set this to true text->inputAutodetect = true; } } if (obj->options && obj->options->default_charset) text->charset = strdup(obj->options->default_charset); else { if (NS_SUCCEEDED(res)) { nsString value; NS_GetLocalizedUnicharPreferenceWithDefault(prefBranch, "mailnews.view_default_charset", EmptyString(), value); text->charset = ToNewUTF8String(value); } else text->charset = strdup(""); } } } } if (text->inputAutodetect) { //we need to prepare lineDam for charset detection text->lineDamBuffer = (char*)PR_Malloc(DAM_MAX_BUFFER_SIZE); text->lineDamPtrs = (char**)PR_Malloc(DAM_MAX_LINES*sizeof(char*)); text->curDamOffset = 0; text->lastLineInDam = 0; if (!text->lineDamBuffer || !text->lineDamPtrs) { text->inputAutodetect = false; PR_FREEIF(text->lineDamBuffer); PR_FREEIF(text->lineDamPtrs); } } text->initializeCharset = true; return 0; }
int MimeHeaders_write_all_headers (MimeHeaders *hdrs, MimeDisplayOptions *opt, bool attachment) { int status = 0; int i; bool wrote_any_p = false; NS_ASSERTION(hdrs, "1.1 <*****@*****.**> 19 Mar 1999 12:00"); if (!hdrs) return -1; /* One shouldn't be trying to read headers when one hasn't finished parsing them yet... but this can happen if the message ended prematurely, and has no body at all (as opposed to a null body, which is more normal.) So, if we try to read from the headers, let's assume that the headers are now finished. If they aren't in fact finished, then a later attempt to write to them will assert. */ if (!hdrs->done_p) { hdrs->done_p = true; status = MimeHeaders_build_heads_list(hdrs); if (status < 0) return 0; } char *charset = nullptr; if (opt->format_out == nsMimeOutput::nsMimeMessageSaveAs) { if (opt->override_charset) charset = PL_strdup(opt->default_charset); else { char *contentType = MimeHeaders_get(hdrs, HEADER_CONTENT_TYPE, false, false); if (contentType) charset = MimeHeaders_get_parameter(contentType, HEADER_PARM_CHARSET, nullptr, nullptr); PR_FREEIF(contentType); } } 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]); char *colon, *ocolon; char *contents = end; /* Hack for BSD Mailbox delimiter. */ if (i == 0 && head[0] == 'F' && !strncmp(head, "From ", 5)) { /* For now, we don't really want this header to be output so we are going to just continue */ continue; /* colon = head + 4; contents = colon + 1; */ } else { /* Find the colon. */ for (colon = head; colon < end && *colon != ':'; colon++) ; /* Back up over whitespace before the colon. */ ocolon = colon; for (; colon > head && IS_SPACE(colon[-1]); colon--) ; contents = ocolon + 1; } /* Skip over whitespace after colon. */ while (contents < end && IS_SPACE(*contents)) contents++; /* Take off trailing whitespace... */ while (end > contents && IS_SPACE(end[-1])) end--; nsCAutoString name(Substring(head, colon)); nsCAutoString hdr_value; if ( (end - contents) > 0 ) { hdr_value = Substring(contents, end); } // MW Fixme: more? bool convert_charset_only = MsgLowerCaseEqualsLiteral(name, "to") || MsgLowerCaseEqualsLiteral(name, "from") || MsgLowerCaseEqualsLiteral(name, "cc") || MsgLowerCaseEqualsLiteral(name, "bcc") || MsgLowerCaseEqualsLiteral(name, "reply-to") || MsgLowerCaseEqualsLiteral(name, "sender"); MimeHeaders_convert_header_value(opt, hdr_value, convert_charset_only); // if we're saving as html, we need to convert headers from utf8 to message charset, if any if (opt->format_out == nsMimeOutput::nsMimeMessageSaveAs && charset) { nsCAutoString convertedStr; if (NS_SUCCEEDED(ConvertFromUnicode(charset, NS_ConvertUTF8toUTF16(hdr_value), convertedStr))) { hdr_value = convertedStr; } } if (attachment) status = mimeEmitterAddAttachmentField(opt, name.get(), hdr_value.get()); else status = mimeEmitterAddHeaderField(opt, name.get(), hdr_value.get()); if (status < 0) return status; if (!wrote_any_p) wrote_any_p = (status > 0); } mimeEmitterAddAllHeaders(opt, hdrs->all_headers, hdrs->all_headers_fp); PR_FREEIF(charset); return 1; }
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 MimeMessage_close_headers (MimeObject *obj) { MimeMessage *msg = (MimeMessage *) obj; int status = 0; char *ct = 0; /* Content-Type header */ MimeObject *body; // Do a proper decoding of the munged subject. if (obj->headers && msg->hdrs && msg->grabSubject && obj->headers->munged_subject) { // nsMsgI18NConvertToUnicode wants nsAStrings... nsDependentCString orig(obj->headers->munged_subject); nsAutoString dest; // First, get the Content-Type, then extract the charset="whatever" part of // it. nsCString charset; nsCString contentType; contentType.Adopt(MimeHeaders_get(msg->hdrs, HEADER_CONTENT_TYPE, false, false)); if (!contentType.IsEmpty()) charset.Adopt(MimeHeaders_get_parameter(contentType.get(), "charset", nullptr, nullptr)); // If we've got a charset, use nsMsgI18NConvertToUnicode to magically decode // the munged subject. if (!charset.IsEmpty()) { nsresult rv = nsMsgI18NConvertToUnicode(charset.get(), orig, dest); // If we managed to convert the string, replace munged_subject with the // UTF8 version of it, otherwise, just forget about it (maybe there was an // improperly encoded string in there). PR_Free(obj->headers->munged_subject); if (NS_SUCCEEDED(rv)) obj->headers->munged_subject = ToNewUTF8String(dest); else obj->headers->munged_subject = nullptr; } else { PR_Free(obj->headers->munged_subject); obj->headers->munged_subject = nullptr; } } if (msg->hdrs) { bool outer_p = !obj->headers; /* is this the outermost message? */ #ifdef MIME_DRAFTS if (outer_p && obj->options && (obj->options->decompose_file_p || obj->options->caller_need_root_headers) && obj->options->decompose_headers_info_fn) { #ifdef ENABLE_SMIME if (obj->options->decrypt_p && !mime_crypto_object_p (msg->hdrs, false)) obj->options->decrypt_p = false; #endif /* ENABLE_SMIME */ if (!obj->options->caller_need_root_headers || (obj == obj->options->state->root)) status = obj->options->decompose_headers_info_fn ( obj->options->stream_closure, msg->hdrs ); } #endif /* MIME_DRAFTS */ /* If this is the outermost message, we need to run the `generate_header' callback. This happens here instead of in `parse_begin', because it's only now that we've parsed our headers. However, since this is the outermost message, we have yet to write any HTML, so that's fine. */ if (outer_p && obj->output_p && obj->options && obj->options->write_html_p && obj->options->generate_header_html_fn) { int lstatus = 0; char *html = 0; /* The generate_header_html_fn might return HTML, so it's important that the output stream be set up with the proper type before we make the MimeObject_write() call below. */ if (!obj->options->state->first_data_written_p) { lstatus = MimeObject_output_init (obj, TEXT_HTML); if (lstatus < 0) return lstatus; PR_ASSERT(obj->options->state->first_data_written_p); } html = obj->options->generate_header_html_fn(NULL, obj->options->html_closure, msg->hdrs); if (html) { lstatus = MimeObject_write(obj, html, strlen(html), false); PR_Free(html); if (lstatus < 0) return lstatus; } } /* Find the content-type of the body of this message. */ { bool ok = true; char *mv = MimeHeaders_get (msg->hdrs, HEADER_MIME_VERSION, true, false); #ifdef REQUIRE_MIME_VERSION_HEADER /* If this is the outermost message, it must have a MIME-Version header with the value 1.0 for us to believe what might be in the Content-Type header. If the MIME-Version header is not present, we must treat this message as untyped. */ ok = (mv && !strcmp(mv, "1.0")); #else /* #### actually, we didn't check this in Mozilla 2.0, and checking it now could cause some compatibility nonsense, so for now, let's just believe any Content-Type header we see. */ ok = true; #endif if (ok) { ct = MimeHeaders_get (msg->hdrs, HEADER_CONTENT_TYPE, true, false); /* If there is no Content-Type header, but there is a MIME-Version header, then assume that this *is* in fact a MIME message. (I've seen messages with MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable and no Content-Type, and we should treat those as being of type MimeInlineTextPlain rather than MimeUntypedText.) */ if (mv && !ct) ct = strdup(TEXT_PLAIN); } PR_FREEIF(mv); /* done with this now. */ } /* If this message has a body which is encrypted and we're going to decrypt it (whithout converting it to HTML, since decrypt_p and write_html_p are never true at the same time) */ if (obj->output_p && obj->options && obj->options->decrypt_p #ifdef ENABLE_SMIME && !mime_crypto_object_p (msg->hdrs, false) #endif /* ENABLE_SMIME */ ) { /* The body of this message is not an encrypted object, so we need to turn off the decrypt_p flag (to prevent us from s#$%ing the body of the internal object up into one.) In this case, our output will end up being identical to our input. */ obj->options->decrypt_p = false; } /* Emit the HTML for this message's headers. Do this before creating the object representing the body. */ if (obj->output_p && obj->options && obj->options->write_html_p) { /* If citation headers are on, and this is not the outermost message, turn them off. */ if (obj->options->headers == MimeHeadersCitation && !outer_p) obj->options->headers = MimeHeadersSome; /* Emit a normal header block. */ status = MimeMessage_write_headers_html(obj); if (status < 0) return status; } else if (obj->output_p) { /* Dump the headers, raw. */ status = MimeObject_write(obj, "", 0, false); /* initialize */ if (status < 0) return status; status = MimeHeaders_write_raw_headers(msg->hdrs, obj->options, obj->options->decrypt_p); if (status < 0) return status; } #ifdef XP_UNIX if (outer_p && obj->output_p) /* Kludge from mimehdrs.c */ MimeHeaders_do_unix_display_hook_hack(msg->hdrs); #endif /* XP_UNIX */ } /* Never put out a separator after a message header block. */ if (obj->options && obj->options->state) obj->options->state->separator_suppressed_p = true; #ifdef MIME_DRAFTS if ( !obj->headers && /* outer most message header */ obj->options && obj->options->decompose_file_p && ct ) obj->options->is_multipart_msg = PL_strcasestr(ct, "multipart/") != NULL; #endif /* MIME_DRAFTS */ body = mime_create(ct, msg->hdrs, obj->options); 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; } // Only do this if this is a Text Object! if ( mime_typep(body, (MimeObjectClass *) &mimeInlineTextClass) ) { ((MimeInlineText *) body)->needUpdateMsgWinCharset = true; } /* 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; // Now notify the emitter if this is the outer most message, unless // it is a part that is not the head of the message. If it's a part, // we need to figure out the content type/charset of the part // bool outer_p = !obj->headers; /* is this the outermost message? */ if ( (outer_p || obj->options->notify_nested_bodies) && (!obj->options->part_to_load || obj->options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay)) { // call SetMailCharacterSetToMsgWindow() to set a menu charset if (mime_typep(body, (MimeObjectClass *) &mimeInlineTextClass)) { MimeInlineText *text = (MimeInlineText *) body; if (text && text->charset && *text->charset) SetMailCharacterSetToMsgWindow(body, text->charset); } char *msgID = MimeHeaders_get (msg->hdrs, HEADER_MESSAGE_ID, false, false); const char *outCharset = NULL; if (!obj->options->force_user_charset) /* Only convert if the user prefs is false */ outCharset = "UTF-8"; mimeEmitterStartBody(obj->options, (obj->options->headers == MimeHeadersNone), msgID, outCharset); PR_FREEIF(msgID); // setting up truncated message html fotter function char *xmoz = MimeHeaders_get(msg->hdrs, HEADER_X_MOZILLA_STATUS, false, false); if (xmoz) { uint32_t flags = 0; char dummy = 0; if (sscanf(xmoz, " %x %c", &flags, &dummy) == 1 && flags & nsMsgMessageFlags::Partial) { obj->options->html_closure = obj; obj->options->generate_footer_html_fn = MimeMessage_partial_message_html; } PR_FREEIF(xmoz); } } return 0; }
void nsEnigMimeListener::ParseHeader(const char* header, PRUint32 count) { //DEBUG_LOG(("nsEnigMimeListener::ParseHeader: header='%s'\n", header)); if (!header || (count <= 0) ) return; // Create header string nsCAutoString headerStr(header, count); //DEBUG_LOG(("nsEnigMimeListener::ParseHeader: header='%s'\n", headerStr.get())); PRInt32 colonOffset; colonOffset = headerStr.FindChar(':'); if (colonOffset < 0) return; // Null header key not allowed if (colonOffset == 0) return; // Extract header key (not case-sensitive) nsCAutoString headerKey = (nsCString) nsDependentCSubstring (headerStr, 0, colonOffset); ToLowerCase(headerKey); // Extract header value, trimming leading/trailing whitespace nsCAutoString buf = (nsCString) nsDependentCSubstring (headerStr, colonOffset+1, headerStr.Length() - colonOffset); buf.Trim(" ", PR_TRUE, PR_TRUE); //DEBUG_LOG(("nsEnigMimeListener::ParseHeader: '%s': %s\n", headerKey.get(), buf.get())); PRInt32 semicolonOffset = buf.FindChar(';'); nsCString headerValue; if (semicolonOffset < 0) { // No parameters headerValue = ((nsCString)buf).get(); } else { // Extract value to left of parameters headerValue = nsDependentCSubstring (buf, 0, semicolonOffset); } // Trim leading and trailing spaces in header value headerValue.Trim(" ", PR_TRUE, PR_TRUE); if (headerKey.Equals("content-type")) { mContentType = headerValue; DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentType=%s\n", mContentType.get())); if (!buf.IsEmpty()) { char *charset = MimeHeaders_get_parameter(buf.get(), HEADER_PARM_CHARSET, NULL, NULL); char *boundary = MimeHeaders_get_parameter(buf.get(), HEADER_PARM_BOUNDARY, NULL, NULL); char *protocol = MimeHeaders_get_parameter(buf.get(), PARAM_PROTOCOL, NULL, NULL); char *micalg = MimeHeaders_get_parameter(buf.get(), PARAM_MICALG, NULL, NULL); if (charset) mContentCharset = charset; if (boundary) mContentBoundary = boundary; if (protocol) mContentProtocol = protocol; if (micalg) mContentMicalg = micalg; PR_FREEIF(charset); PR_FREEIF(boundary); PR_FREEIF(protocol); PR_FREEIF(micalg); DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentCharset=%s\n", mContentCharset.get())); DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentBoundary=%s\n", mContentBoundary.get())); DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentProtocol=%s\n", mContentProtocol.get())); DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentMicalg=%s\n", mContentMicalg.get())); } } else if (headerKey.Equals("content-transfer-encoding")) { mContentEncoding = buf; ToLowerCase(mContentEncoding); DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentEncoding=%s\n", mContentEncoding.get())); } else if (headerKey.Equals("content-disposition")) { mContentDisposition = buf; DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentDisposition=%s\n", mContentDisposition.get())); } else if (headerKey.Equals("content-length")) { nsresult status; PRInt32 value = headerValue.ToInteger(&status); if (NS_SUCCEEDED(status)) mContentLength = value; DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContenLengtht=%d\n", mContentLength)); } return; }
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 void * MimeMultCMS_init (MimeObject *obj) { MimeHeaders *hdrs = obj->headers; MimeMultCMSdata *data = 0; char *ct, *micalg; PRInt16 hash_type; nsresult rv; ct = MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE); if (!ct) return 0; /* #### bogus message? out of memory? */ micalg = MimeHeaders_get_parameter (ct, PARAM_MICALG, NULL, NULL); PR_Free(ct); ct = 0; if (!micalg) return 0; /* #### bogus message? out of memory? */ if (!PL_strcasecmp(micalg, PARAM_MICALG_MD5) || !PL_strcasecmp(micalg, PARAM_MICALG_MD5_2)) hash_type = nsICryptoHash::MD5; else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA1) || !PL_strcasecmp(micalg, PARAM_MICALG_SHA1_2) || !PL_strcasecmp(micalg, PARAM_MICALG_SHA1_3) || !PL_strcasecmp(micalg, PARAM_MICALG_SHA1_4) || !PL_strcasecmp(micalg, PARAM_MICALG_SHA1_5)) hash_type = nsICryptoHash::SHA1; else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA256) || !PL_strcasecmp(micalg, PARAM_MICALG_SHA256_2) || !PL_strcasecmp(micalg, PARAM_MICALG_SHA256_3)) hash_type = nsICryptoHash::SHA256; else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA384) || !PL_strcasecmp(micalg, PARAM_MICALG_SHA384_2) || !PL_strcasecmp(micalg, PARAM_MICALG_SHA384_3)) hash_type = nsICryptoHash::SHA384; else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA512) || !PL_strcasecmp(micalg, PARAM_MICALG_SHA512_2) || !PL_strcasecmp(micalg, PARAM_MICALG_SHA512_3)) hash_type = nsICryptoHash::SHA512; else if (!PL_strcasecmp(micalg, PARAM_MICALG_MD2)) hash_type = nsICryptoHash::MD2; else hash_type = -1; PR_Free(micalg); micalg = 0; if (hash_type == -1) return 0; /* #### bogus message? */ data = new MimeMultCMSdata; if (!data) return 0; data->self = obj; data->hash_type = hash_type; data->data_hash_context = do_CreateInstance("@mozilla.org/security/hash;1", &rv); if (NS_FAILED(rv)) { delete data; return 0; } rv = data->data_hash_context->Init(data->hash_type); if (NS_FAILED(rv)) { delete data; return 0; } PR_SetError(0,0); data->parent_holds_stamp_p = (obj->parent && mime_crypto_stamped_p(obj->parent)); data->parent_is_encrypted_p = (obj->parent && MimeEncryptedCMS_encrypted_p (obj->parent)); /* If the parent of this object is a crypto-blob, then it's the grandparent who would have written out the headers and prepared for a stamp... (This s##t s$%#s.) */ if (data->parent_is_encrypted_p && !data->parent_holds_stamp_p && obj->parent && obj->parent->parent) data->parent_holds_stamp_p = mime_crypto_stamped_p (obj->parent->parent); mime_stream_data *msd = (mime_stream_data *) (data->self->options->stream_closure); if (msd) { nsIChannel *channel = msd->channel; // note the lack of ref counting... if (channel) { nsCOMPtr<nsIURI> uri; nsCOMPtr<nsIMsgWindow> msgWindow; nsCOMPtr<nsIMsgHeaderSink> headerSink; nsCOMPtr<nsIMsgMailNewsUrl> msgurl; nsCOMPtr<nsISupports> securityInfo; channel->GetURI(getter_AddRefs(uri)); if (uri) { nsCAutoString urlSpec; rv = uri->GetSpec(urlSpec); // We only want to update the UI if the current mime transaction // is intended for display. // If the current transaction is intended for background processing, // we can learn that by looking at the additional header=filter // string contained in the URI. // // If we find something, we do not set smimeHeaderSink, // which will prevent us from giving UI feedback. // // If we do not find header=filter, we assume the result of the // processing will be shown in the UI. if (!strstr(urlSpec.get(), "?header=filter") && !strstr(urlSpec.get(), "&header=filter")&& !strstr(urlSpec.get(), "?header=attach") && !strstr(urlSpec.get(), "&header=attach")) { msgurl = do_QueryInterface(uri); if (msgurl) msgurl->GetMsgWindow(getter_AddRefs(msgWindow)); if (msgWindow) msgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink)); if (headerSink) headerSink->GetSecurityInfo(getter_AddRefs(securityInfo)); if (securityInfo) data->smimeHeaderSink = do_QueryInterface(securityInfo); } } } // if channel } // if msd return data; }