static int MimeInlineTextPlain_parse_eof (MimeObject *obj, bool abort_p) { int status; // Has this method already been called for this object? // In that case return. if (obj->closed_p) return 0; nsCString citationColor; MimeInlineTextPlain *text = (MimeInlineTextPlain *) obj; if (text && text->mCitationColor) citationColor.Adopt(text->mCitationColor); bool quoting = ( obj->options && ( obj->options->format_out == nsMimeOutput::nsMimeMessageQuoting || obj->options->format_out == nsMimeOutput::nsMimeMessageBodyQuoting ) ); // see above bool 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 (!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, false); // .moz-txt-sig if (status < 0) return status; } status = MimeObject_write(obj, "</pre>", 6, false); if (status < 0) return status; if (!quoting) { status = MimeObject_write(obj, "</div>", 6, 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 MimeInlineText_parse_decoded_buffer (const char *buf, int32_t size, MimeObject *obj) { PR_ASSERT(!obj->closed_p); if (obj->closed_p) return -1; /* MimeLeaf takes care of this. */ PR_ASSERT(obj->output_p && obj->options && obj->options->output_fn); if (!obj->options) 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->options->write_html_p && obj->options->format_out != nsMimeOutput::nsMimeMessageAttach) return MimeObject_write(obj, buf, size, true); /* This is just like the parse_decoded_buffer method we inherit from the MimeLeaf class, except that we line-buffer to our own wrapper on the `parse_line' method instead of calling the `parse_line' method directly. */ return mime_LineBuffer (buf, size, &obj->ibuffer, &obj->ibuffer_size, &obj->ibuffer_fp, true, ((int (*) (char *, int32_t, void *)) /* This cast is to turn void into MimeObject */ MimeInlineText_rotate_convert_and_parse_line), obj); }
static int MimeExternalObject_parse_decoded_buffer (const char *buf, PRInt32 size, MimeObject *obj) { /* This is called (by MimeLeafClass->parse_buffer) with blocks of data that have already been base64-decoded. This will only be called in the case where we're not emitting HTML, and want access to the raw data itself. We override the `parse_decoded_buffer' method provided by MimeLeaf because, unlike most children of MimeLeaf, we do not want to line- buffer the decoded data -- we want to simply pass it along to the backend, without going through our `parse_line' method. */ /* Don't do a roundtrip through XPConnect when we're only interested in * metadata and size. This includes when we are writing HTML (otherwise, the * contents of binary attachments will just get dumped into messages when * reading them) and the JS emitter (which doesn't care about attachment data * at all). 0 means ok, the caller just checks for negative return value. */ if (obj->options && (obj->options->metadata_only || obj->options->write_html_p)) return 0; else return MimeObject_write(obj, buf, size, true); }
static int MimeInlineTextRichtext_parse_begin (MimeObject *obj) { int status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj); char s[] = ""; if (status < 0) return status; return MimeObject_write(obj, s, 0, PR_TRUE); /* force out any separators... */ }
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 int MimeInlineImage_parse_decoded_buffer (const char *buf, PRInt32 size, MimeObject *obj) { /* This is called (by MimeLeafClass->parse_buffer) with blocks of data that have already been base64-decoded. Pass this raw image data along to the backend-specific image display code. */ MimeInlineImage *img = (MimeInlineImage *) obj; int status; if (obj->output_p && obj->options && !obj->options->write_html_p) { /* in this case, we just want the raw data... Make the stream, if it's not made, and dump the data out. */ if (!obj->options->state->first_data_written_p) { status = MimeObject_output_init(obj, 0); if (status < 0) return status; NS_ASSERTION(obj->options->state->first_data_written_p, "1.1 <*****@*****.**> 19 Mar 1999 12:00"); } return MimeObject_write(obj, buf, size, PR_TRUE); } if (!obj->options || !obj->options->image_write_buffer) return 0; /* If we don't have any image data, the image_end method must have already been called, so don't call image_write_buffer again. */ if (!img->image_data) return 0; /* Hand this data off to the backend-specific image display stream. */ status = obj->options->image_write_buffer (buf, size, img->image_data); /* If the image display stream fails, then close the stream - but do not return the failure status, and do not give up on parsing this object. Just because the image data was corrupt doesn't mean we need to give up on the whole document; we can continue by just skipping over the rest of this part, and letting our parent continue. */ if (status < 0) { obj->options->image_end (img->image_data, status); img->image_data = 0; status = 0; } return status; }
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; }
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 MimeExternalObject_parse_decoded_buffer (const char *buf, PRInt32 size, MimeObject *obj) { /* This is called (by MimeLeafClass->parse_buffer) with blocks of data that have already been base64-decoded. This will only be called in the case where we're not emitting HTML, and want access to the raw data itself. We override the `parse_decoded_buffer' method provided by MimeLeaf because, unlike most children of MimeLeaf, we do not want to line- buffer the decoded data -- we want to simply pass it along to the backend, without going through our `parse_line' method. */ if (!obj->output_p || !obj->options || obj->options->write_html_p) { NS_ASSERTION(0, "1.1 <*****@*****.**> 19 Mar 1999 12:00"); return -1; } return MimeObject_write(obj, buf, size, PR_TRUE); }
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 MimeInlineTextPlain_parse_begin (MimeObject *obj) { int status = 0; 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. PRBool rawPlainText = obj->options && (obj->options->format_out == nsMimeOutput::nsMimeMessageFilterSniffer || obj->options->format_out == nsMimeOutput::nsMimeMessageAttach); status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj); if (status < 0) return status; if (!obj->output_p) return 0; if (obj->options && obj->options->write_html_p && obj->options->output_fn) { MimeInlineTextPlain *text = (MimeInlineTextPlain *) obj; text->mCiteLevel = 0; // Get the prefs // Quoting text->mBlockquoting = PR_TRUE; // mail.quoteasblock // Viewing text->mQuotedSizeSetting = 0; // mail.quoted_size text->mQuotedStyleSetting = 0; // mail.quoted_style text->mCitationColor = nsnull; // mail.citation_color PRBool graphicalQuote = PR_TRUE; // mail.quoted_graphical 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)); prefBranch->GetBoolPref("mail.quoted_graphical", &graphicalQuote); prefBranch->GetBoolPref("mail.quoteasblock", &(text->mBlockquoting)); } if (!rawPlainText) { // 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 (!obj->options->variable_width_plaintext_p) 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, !obj->options->variable_width_plaintext_p, &fontSize, &fontSizePercentage, fontLang); if (NS_SUCCEEDED(rv)) { if ( ! fontstyle.IsEmpty() ) { fontstyle += "; "; } fontstyle += "font-size: "; fontstyle.AppendInt(fontSize); fontstyle += "px;"; } } // Opening <div>. We currently have to add formatting here. :-( nsCAutoString openingDiv; 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. */ { openingDiv = "<div class=\"moz-text-plain\""; if (!plainHTML) { if (obj->options->wrap_long_lines_p) openingDiv += " wrap=true"; else openingDiv += " wrap=false"; if (graphicalQuote) openingDiv += " graphical-quote=true"; else openingDiv += " graphical-quote=false"; if (!fontstyle.IsEmpty()) { openingDiv += " style=\""; openingDiv += fontstyle; openingDiv += '\"'; } if (!fontLang.IsEmpty()) { openingDiv += " lang=\""; openingDiv += fontLang; openingDiv += '\"'; } } openingDiv += "><pre wrap>"; } else openingDiv = "<pre wrap>"; status = MimeObject_write(obj, openingDiv.get(), openingDiv.Length(), PR_FALSE); 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 MimeMessage_write_headers_html (MimeObject *obj) { MimeMessage *msg = (MimeMessage *) obj; int status; #ifdef MOZ_SECURITY HG33391 #endif /* MOZ_SECURITY */ if (!obj->options || !obj->options->output_fn) return 0; PR_ASSERT(obj->output_p && obj->options->write_html_p); // To support the no header option! Make sure we are not // suppressing headers on included email messages... if ( (obj->options->headers == MimeHeadersNone) && (obj == obj->options->state->root) ) { // Ok, we are going to kick the Emitter for a StartHeader // operation ONLY WHEN THE CHARSET OF THE ORIGINAL MESSAGE IS // NOT US-ASCII ("ISO-8859-1") // // This is only to notify the emitter of the charset of the // original message char *mailCharset = DetermineMailCharset(msg); if ( (mailCharset) && (PL_strcasecmp(mailCharset, "US-ASCII")) && (PL_strcasecmp(mailCharset, "ISO-8859-1")) ) mimeEmitterUpdateCharacterSet(obj->options, mailCharset); PR_FREEIF(mailCharset); return 0; } if (!obj->options->state->first_data_written_p) { status = MimeObject_output_init (obj, TEXT_HTML); if (status < 0) { mimeEmitterEndHeader(obj->options); return status; } PR_ASSERT(obj->options->state->first_data_written_p); } // Start the header parsing by the emitter char *msgID = MimeHeaders_get (msg->hdrs, HEADER_MESSAGE_ID, PR_FALSE, PR_FALSE); PRBool outer_p = !obj->headers; /* is this the outermost message? */ if (!outer_p && obj->options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay && obj->options->part_to_load) { //Maybe we are displaying a embedded message as outer part! char *id = mime_part_address(obj); if (id) { outer_p = !strcmp(id, obj->options->part_to_load); PR_Free(id); } } // Ok, we should really find out the charset of this part. We always // output UTF-8 for display, but the original charset is necessary for // reply and forward operations. // char *mailCharset = DetermineMailCharset(msg); mimeEmitterStartHeader(obj->options, outer_p, (obj->options->headers == MimeHeadersOnly), msgID, mailCharset); // Change the default_charset by the charset of the original message // ONLY WHEN THE CHARSET OF THE ORIGINAL MESSAGE IS NOT US-ASCII // ("ISO-8859-1") and defailt_charset and mailCharset are different. if ( (mailCharset) && (PL_strcasecmp(mailCharset, "US-ASCII")) && (PL_strcasecmp(mailCharset, "ISO-8859-1")) && (PL_strcasecmp(obj->options->default_charset, mailCharset)) && !obj->options->override_charset ) { PR_FREEIF(obj->options->default_charset); obj->options->default_charset = strdup(mailCharset); } PR_FREEIF(msgID); PR_FREEIF(mailCharset); #ifdef MOZ_SECURITY HG00919 #endif /* MOZ_SECURITY */ status = MimeHeaders_write_all_headers (msg->hdrs, obj->options, PR_FALSE); if (status < 0) { mimeEmitterEndHeader(obj->options); return status; } if (msg->crypto_stamped_p) { #ifdef MOZ_SECURITY HG11995 #endif /* MOZ_SECURITY */ } else { /* If we're not writing a xlation stamp, and this is the outermost message, then now is the time to run the post_header_html_fn. (Otherwise, it will be run when the xlation-stamp is finally closed off, in MimeXlateed_emit_buffered_child() or MimeMultipartSigned_emit_child().) */ if (obj->options && obj->options->state && obj->options->generate_post_header_html_fn && !obj->options->state->post_header_html_run_p) { char *html = 0; PR_ASSERT(obj->options->state->first_data_written_p); html = obj->options->generate_post_header_html_fn(NULL, obj->options->html_closure, msg->hdrs); obj->options->state->post_header_html_run_p = PR_TRUE; if (html) { status = MimeObject_write(obj, html, strlen(html), PR_FALSE); PR_Free(html); if (status < 0) { mimeEmitterEndHeader(obj->options); return status; } } } } mimeEmitterEndHeader(obj->options); // rhp: // For now, we are going to parse the entire message, even if we are // only interested in headers...why? Well, because this is the only // way to build the attachment list. Now we will have the attachment // list in the output being created by the XML emitter. If we ever // want to go back to where we were before, just uncomment the conditional // and it will stop at header parsing. // // if (obj->options->headers == MimeHeadersOnly) // return -1; // else return 0; }
static int MimeMessage_parse_eof (MimeObject *obj, PRBool abort_p) { int status; PRBool outer_p; MimeMessage *msg = (MimeMessage *)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; outer_p = !obj->headers; /* is this the outermost message? */ // Hack for messages with truncated headers (bug 244722) // If there is no empty line in a message, the parser can't figure out where // the headers end, causing parsing to hang. So we insert an extra newline // to keep it happy. This is OK, since a message without any empty lines is // broken anyway... if(outer_p && msg->hdrs && ! msg->hdrs->done_p) { MimeMessage_parse_line("\n", 1, obj); } // Once we get to the end of parsing the message, we will notify // the emitter that we are done the the body. // Mark the end of the mail body if we are actually emitting the // body of the message (i.e. not Header ONLY) if (outer_p && obj->options && obj->options->write_html_p) { if (obj->options->generate_footer_html_fn) { mime_stream_data *msd = (mime_stream_data *) obj->options->stream_closure; if (msd) { char *html = obj->options->generate_footer_html_fn (msd->orig_url_name, obj->options->html_closure, msg->hdrs); if (html) { int lstatus = MimeObject_write(obj, html, strlen(html), PR_FALSE); PR_Free(html); if (lstatus < 0) return lstatus; } } } if ((!obj->options->part_to_load || obj->options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay) && obj->options->headers != MimeHeadersOnly) mimeEmitterEndBody(obj->options); } #ifdef MIME_DRAFTS if ( obj->options && obj->options->decompose_file_p && obj->options->done_parsing_outer_headers && ! obj->options->is_multipart_msg && ! mime_typep(obj, (MimeObjectClass*) &mimeEncryptedClass) && obj->options->decompose_file_close_fn ) { status = obj->options->decompose_file_close_fn ( obj->options->stream_closure ); if ( status < 0 ) return status; } #endif /* MIME_DRAFTS */ /* Put out a separator after every message/rfc822 object. */ if (!abort_p && !outer_p) { status = MimeObject_write_separator(obj); if (status < 0) return status; } return 0; }
static int MimeMessage_close_headers (MimeObject *obj) { MimeMessage *msg = (MimeMessage *) obj; int status = 0; char *ct = 0; /* Content-Type header */ MimeObject *body; if (msg->hdrs) { PRBool 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, PR_FALSE)) obj->options->decrypt_p = PR_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), PR_FALSE); PR_Free(html); if (lstatus < 0) return lstatus; } } /* Find the content-type of the body of this message. */ { PRBool ok = PR_TRUE; char *mv = MimeHeaders_get (msg->hdrs, HEADER_MIME_VERSION, PR_TRUE, PR_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 = PR_TRUE; #endif if (ok) { ct = MimeHeaders_get (msg->hdrs, HEADER_CONTENT_TYPE, PR_TRUE, PR_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, PR_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 = PR_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, PR_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 = PR_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 = PR_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 // PRBool outer_p = !obj->headers; /* is this the outermost message? */ if ( outer_p && (!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, PR_FALSE, PR_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, PR_FALSE, PR_FALSE); if (xmoz) { PRUint32 flags = 0; char dummy = 0; if (sscanf(xmoz, " %lx %c", &flags, &dummy) == 1 && flags & MSG_FLAG_PARTIAL) { obj->options->html_closure = obj; obj->options->generate_footer_html_fn = MimeMessage_partial_message_html; } PR_FREEIF(xmoz); } } return 0; }
static int MimeEncrypted_emit_buffered_child(MimeObject *obj) { MimeEncrypted *enc = (MimeEncrypted *) obj; int status = 0; char *ct = 0; MimeObject *body; NS_ASSERTION(enc->crypto_closure, "1.2 <*****@*****.**> 01 Nov 2001 17:59"); /* Emit some HTML saying whether the signature was cool. But don't emit anything if in FO_QUOTE_MESSAGE mode. Also, don't emit anything if the enclosed object is itself a signed object -- in the case of an encrypted object which contains a signed object, we only emit the HTML once (since the normal way of encrypting and signing is to nest the signature inside the crypto envelope.) */ if (enc->crypto_closure && obj->options && obj->options->headers != MimeHeadersCitation && obj->options->write_html_p && obj->options->output_fn) // && !mime_crypto_object_p(enc->hdrs, PR_TRUE)) // XXX fix later XXX // { char *html; #if 0 // XXX Fix this later XXX // char *html = (((MimeEncryptedClass *) obj->clazz)->crypto_generate_html (enc->crypto_closure)); if (!html) return -1; /* MK_OUT_OF_MEMORY? */ status = MimeObject_write(obj, html, nsCRT::strlen(html), PR_FALSE); PR_FREEIF(html); if (status < 0) return status; #endif /* Now that we have written out the crypto stamp, the outermost header block is well and truly closed. If this is in fact the outermost message, then run the post_header_html_fn now. */ if (obj->options && obj->options->state && obj->options->generate_post_header_html_fn && !obj->options->state->post_header_html_run_p) { MimeHeaders *outer_headers = nsnull; MimeObject *p; for (p = obj; p->parent; p = p->parent) outer_headers = p->headers; NS_ASSERTION(obj->options->state->first_data_written_p, "1.2 <*****@*****.**> 01 Nov 2001 17:59"); html = obj->options->generate_post_header_html_fn(NULL, obj->options->html_closure, outer_headers); obj->options->state->post_header_html_run_p = PR_TRUE; if (html) { status = MimeObject_write(obj, html, strlen(html), PR_FALSE); PR_FREEIF(html); if (status < 0) return status; } } } else if (enc->crypto_closure && obj->options && obj->options->decrypt_p) { /* Do this just to cause `mime_set_crypto_stamp' to be called, and to cause the various `decode_error' and `verify_error' slots to be set: we don't actually use the returned HTML, because we're not emitting HTML. It's maybe not such a good thing that the determination of whether it was encrypted or not is tied up with generating HTML, but oh well. */ char *html = (((MimeEncryptedClass *) obj->clazz)->crypto_generate_html (enc->crypto_closure)); PR_FREEIF(html); } if (enc->hdrs) ct = MimeHeaders_get (enc->hdrs, HEADER_CONTENT_TYPE, PR_TRUE, PR_FALSE); body = mime_create((ct ? ct : TEXT_PLAIN), enc->hdrs, obj->options); #ifdef MIME_DRAFTS if (obj->options->decompose_file_p) { if (mime_typep (body, (MimeObjectClass*) &mimeMultipartClass) ) obj->options->is_multipart_msg = PR_TRUE; else if (obj->options->decompose_file_init_fn) obj->options->decompose_file_init_fn(obj->options->stream_closure, enc->hdrs); } #endif /* MIME_DRAFTS */ PR_FREEIF(ct); if (!body) return MIME_OUT_OF_MEMORY; status = ((MimeContainerClass *) obj->clazz)->add_child (obj, body); if (status < 0) { mime_free(body); return status; } /* Now that we've added this new object to our list of children, start its parser going. */ status = body->clazz->parse_begin(body); if (status < 0) return status; /* If this object (or the parent) is being output, then by definition the child is as well. (This is only necessary because this is such a funny sort of container...) */ if (!body->output_p && (obj->output_p || (obj->parent && obj->parent->output_p))) body->output_p = PR_TRUE; /* If the body is being written raw (not as HTML) then make sure to write its headers as well. */ if (body->output_p && obj->output_p && !obj->options->write_html_p) { status = MimeObject_write(body, "", 0, PR_FALSE); /* initialize */ if (status < 0) return status; status = MimeHeaders_write_raw_headers(body->headers, obj->options, PR_FALSE); if (status < 0) return status; } if (enc->part_buffer) /* part_buffer is 0 for 0-length encrypted data. */ #ifdef MIME_DRAFTS if (obj->options->decompose_file_p && !obj->options->is_multipart_msg) status = MimePartBufferRead(enc->part_buffer, /* The (nsresult (*) ...) cast is to turn the `void' argument into `MimeObject'. */ ((nsresult (*) (const char *, PRInt32, void *)) obj->options->decompose_file_output_fn), obj->options->stream_closure); else #endif /* MIME_DRAFTS */ status = MimePartBufferRead(enc->part_buffer, /* The (nsresult (*) ...) cast is to turn the `void' argument into `MimeObject'. */ ((nsresult (*) (const char *, PRInt32, void *)) body->clazz->parse_buffer), body); if (status < 0) return status; /* The child has been fully processed. Close it off. */ status = body->clazz->parse_eof(body, PR_FALSE); if (status < 0) return status; status = body->clazz->parse_end(body, PR_FALSE); if (status < 0) return status; #ifdef MIME_DRAFTS if (obj->options->decompose_file_p && !obj->options->is_multipart_msg) obj->options->decompose_file_close_fn(obj->options->stream_closure); #endif /* MIME_DRAFTS */ /* Put out a separator after every encrypted object. */ status = MimeObject_write_separator(obj); if (status < 0) return status; MimeEncrypted_cleanup (obj, PR_FALSE); return 0; }
static int MimeInlineTextPlainFlowed_parse_line (const char *aLine, 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 struct MimeInlineTextPlainFlowedExData *exdata; exdata = MimeInlineTextPlainFlowedExDataList; while(exdata && (exdata->ownerobj != obj)) { exdata = exdata->next; } NS_ASSERTION(exdata, "The extra data has disappeared!"); NS_ASSERTION(length > 0, "zero length"); if (length <= 0) return 0; uint32 linequotelevel = 0; nsCAutoString real_line(aLine, length); char *line = real_line.BeginWriting(); const char *linep = real_line.BeginReading(); // Space stuffed? if(' ' == *linep) { linep++; } else { // count '>':s before the first non-'>' while('>' == *linep) { linep++; linequotelevel++; } // Space stuffed? if(' ' == *linep) { linep++; } } // Look if the last character (after stripping ending end // of lines and quoting stuff) is a SPACE. If it is, we are looking at a // flowed line. Normally we assume that the last two chars // are CR and LF as said in RFC822, but that doesn't seem to // be the case always. PRBool flowed = PR_FALSE; PRBool sigSeparator = PR_FALSE; PRInt32 index = length-1; while(index >= 0 && ('\r' == line[index] || '\n' == line[index])) { index--; } if (index > linep - line && ' ' == line[index]) /* Ignore space stuffing, i.e. lines with just (quote marks and) a space count as empty */ { flowed = PR_TRUE; sigSeparator = (index - (linep - line) + 1 == 3) && !strncmp(linep, "-- ", 3); if (((MimeInlineTextPlainFlowed *) obj)->delSp && ! sigSeparator) /* If line is flowed and DelSp=yes, logically delete trailing space. Line consisting of dash dash space ("-- "), commonly used as signature separator, gets special handling (RFC 3676) */ { length--; line[index] = '\0'; } } mozITXTToHTMLConv *conv = GetTextConverter(obj->options); PRBool skipConversion = !conv || (obj->options && obj->options->force_user_charset); nsAutoString lineSource; nsString lineResult; char *mailCharset = NULL; nsresult rv; if (!skipConversion) { // Convert only if the source string is not empty if (length - (linep - line) > 0) { PRBool whattodo = obj->options->whattodo; if (plainHTML) { if (quoting) whattodo = 0; 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. */ } const nsDependentCSubstring& inputStr = Substring(linep, linep + (length - (linep - line))); // 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, PromiseFlatCString(inputStr), lineSource); NS_ENSURE_SUCCESS(rv, -1); } else // this probably never happens... CopyUTF8toUTF16(inputStr, lineSource); } else // line is in UTF-8 CopyUTF8toUTF16(inputStr, lineSource); // This is the main TXT to HTML conversion: // escaping (very important), eventually recognizing etc. rv = conv->ScanTXT(lineSource.get(), whattodo, getter_Copies(lineResult)); NS_ENSURE_SUCCESS(rv, -1); } } else { CopyUTF8toUTF16(nsDependentCString(line, length), lineResult); status = NS_OK; } nsCAutoString preface; /* Correct number of blockquotes */ int32 quoteleveldiff=linequotelevel - exdata->quotelevel; if((quoteleveldiff != 0) && flowed && exdata->inflow) { // From RFC 2646 4.5 // The receiver SHOULD handle this error by using the 'quote-depth-wins' rule, // which is to ignore the flowed indicator and treat the line as fixed. That // is, the change in quote depth ends the paragraph. // We get that behaviour by just going on. } while(quoteleveldiff>0) { quoteleveldiff--; preface += "<blockquote type=cite"; // This is to have us observe the user pref settings for citations MimeInlineTextPlainFlowed *tObj = (MimeInlineTextPlainFlowed *) obj; nsCAutoString style; MimeTextBuildPrefixCSS(tObj->mQuotedSizeSetting, tObj->mQuotedStyleSetting, tObj->mCitationColor, style); if (!plainHTML && !style.IsEmpty()) { preface += " style=\""; preface += style; preface += '"'; } preface += '>'; } while(quoteleveldiff<0) { quoteleveldiff++; preface += "</blockquote>"; } exdata->quotelevel = linequotelevel; nsAutoString lineResult2; if(flowed) { // Check RFC 2646 "4.3. Usenet Signature Convention": "-- "+CRLF is // not a flowed line if (sigSeparator) { if (linequotelevel > 0 || exdata->isSig) { preface += "-- <br>"; } else { exdata->isSig = PR_TRUE; preface += "<div class=\"moz-txt-sig\"><span class=\"moz-txt-tag\">" "-- <br></span>"; } } else { Line_convert_whitespace(lineResult, PR_FALSE /* Allow wraps */, lineResult2); } exdata->inflow=PR_TRUE; } else { // Fixed paragraph. Line_convert_whitespace(lineResult, !plainHTML && !obj->options->wrap_long_lines_p /* If wrap, convert all spaces but the last in a row into nbsp, otherwise all. */, lineResult2); lineResult2.AppendLiteral("<br>"); exdata->inflow = PR_FALSE; } // End Fixed line if (!(exdata->isSig && quoting)) { status = MimeObject_write(obj, preface.get(), preface.Length(), PR_TRUE); if (status < 0) return status; nsCAutoString outString; if (obj->options->format_out != nsMimeOutput::nsMimeMessageSaveAs || !mailCharset || !*mailCharset) CopyUTF16toUTF8(lineResult2, outString); else { // convert back to mailCharset before writing. rv = nsMsgI18NConvertFromUnicode(mailCharset, lineResult2, outString); NS_ENSURE_SUCCESS(rv, -1); } status = MimeObject_write(obj, outString.get(), outString.Length(), PR_TRUE); return status; } else return NS_OK; }
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 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 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; }
int MimeWriteAString(MimeObject *obj, const nsACString &string) { const nsCString &flatString = PromiseFlatCString(string); return MimeObject_write(obj, flatString.get(), flatString.Length(), PR_TRUE); }
/* This function has this clunky interface because it needs to be called from outside this module (no MimeObject, etc.) */ int MimeRichtextConvert (const char *line, PRInt32 length, MimeObject *obj, char **obufferP, PRInt32 *obuffer_sizeP, bool enriched_p) { /* RFC 1341 (the original MIME spec) defined text/richtext. RFC 1563 superceded text/richtext with text/enriched. The changes from text/richtext to text/enriched are: - CRLF semantics are different - << maps to < - These tags were added: <VERBATIM>, <NOFILL>, <PARAM>, <FLUSHBOTH> - These tags were removed: <COMMENT>, <OUTDENT>, <OUTDENTRIGHT>, <SAMEPAGE>, <SUBSCRIPT>, <SUPERSCRIPT>, <HEADING>, <FOOTING>, <PARAGRAPH>, <SIGNATURE>, <LT>, <NL>, <NP> This method implements them both. draft-resnick-text-enriched-03.txt is a proposed update to 1563. - These tags were added: <FONTFAMILY>, <COLOR>, <PARAINDENT>, <LANG>. However, all of these rely on the magic <PARAM> tag, which we don't implement, so we're ignoring all of these. Interesting fact: it's by Peter W. Resnick from Qualcomm (Eudora). And it also says "It is fully expected that other text formatting standards like HTML and SGML will supplant text/enriched in Internet mail." */ int status = 0; char *out; const char *data_end; const char *last_end; const char *this_start; const char *this_end; unsigned int desired_size; // The code below must never expand the input by more than 5x; // if it does, the desired_size multiplier (5) below must be changed too #define BGROWTH 5 if ( (PRUint32)length >= ( (PRUint32) 0xfffffffe)/BGROWTH ) return -1; desired_size = (length * BGROWTH) + 1; #undef BGROWTH if (desired_size >= (PRUint32) *obuffer_sizeP) status = mime_GrowBuffer (desired_size, sizeof(char), 1024, obufferP, obuffer_sizeP); if (status < 0) return status; if (enriched_p) { for (this_start = line; this_start < line + length; this_start++) if (!IS_SPACE (*this_start)) break; if (this_start >= line + length) /* blank line */ { PL_strncpyz (*obufferP, "<BR>", *obuffer_sizeP); return MimeObject_write(obj, *obufferP, strlen(*obufferP), true); } } PRUint32 outlen = (PRUint32) *obuffer_sizeP; out = *obufferP; *out = 0; data_end = line + length; last_end = line; this_start = last_end; this_end = this_start; PRUint32 addedlen = 0; while (this_end < data_end) { /* Skip forward to next special character. */ while (this_start < data_end && *this_start != '<' && *this_start != '>' && *this_start != '&') this_start++; this_end = this_start; /* Skip to the end of the tag. */ if (this_start < data_end && *this_start == '<') { this_end++; while (this_end < data_end && !IS_SPACE(*this_end) && *this_end != '<' && *this_end != '>' && *this_end != '&') this_end++; } this_end++; /* Push out the text preceeding the tag. */ if (last_end && last_end != this_start) { memcpy (out, last_end, this_start - last_end); out += this_start - last_end; *out = 0; outlen -= (this_start - last_end); } if (this_start >= data_end) break; else if (*this_start == '&') { PL_strncpyz (out, "&", outlen); addedlen = strlen(out); outlen -= addedlen; out += addedlen; } else if (*this_start == '>') { PL_strncpyz (out, ">", outlen); addedlen = strlen(out); outlen -= addedlen; out += addedlen; } else if (enriched_p && this_start < data_end + 1 && this_start[0] == '<' && this_start[1] == '<') { PL_strncpyz (out, "<", outlen); addedlen = strlen(out); outlen -= addedlen; out += addedlen; } else if (this_start != this_end) { /* Push out this ID. */ const char *old = this_start + 1; const char *tag_open = 0; const char *tag_close = 0; if (*old == '/') { /* This is </tag> */ old++; } switch (*old) { case 'b': case 'B': if (!PL_strncasecmp ("BIGGER>", old, 7)) tag_open = "<FONT SIZE=\"+1\">", tag_close = "</FONT>"; else if (!PL_strncasecmp ("BLINK>", old, 5)) /* Of course, both text/richtext and text/enriched must be enhanced *somehow*... Or else what would people think. */ tag_open = "<BLINK>", tag_close = "</BLINK>"; else if (!PL_strncasecmp ("BOLD>", old, 5)) tag_open = "<B>", tag_close = "</B>"; break; case 'c': case 'C': if (!PL_strncasecmp ("CENTER>", old, 7)) tag_open = "<CENTER>", tag_close = "</CENTER>"; else if (!enriched_p && !PL_strncasecmp ("COMMENT>", old, 8)) tag_open = "<!-- ", tag_close = " -->"; break; case 'e': case 'E': if (!PL_strncasecmp ("EXCERPT>", old, 8)) tag_open = "<BLOCKQUOTE>", tag_close = "</BLOCKQUOTE>"; break; case 'f': case 'F': if (!PL_strncasecmp ("FIXED>", old, 6)) tag_open = "<TT>", tag_close = "</TT>"; else if (enriched_p && !PL_strncasecmp ("FLUSHBOTH>", old, 10)) tag_open = "<P ALIGN=LEFT>", tag_close = "</P>"; else if (!PL_strncasecmp ("FLUSHLEFT>", old, 10)) tag_open = "<P ALIGN=LEFT>", tag_close = "</P>"; else if (!PL_strncasecmp ("FLUSHRIGHT>", old, 11)) tag_open = "<P ALIGN=RIGHT>", tag_close = "</P>"; else if (!enriched_p && !PL_strncasecmp ("FOOTING>", old, 8)) tag_open = "<H6>", tag_close = "</H6>"; break; case 'h': case 'H': if (!enriched_p && !PL_strncasecmp ("HEADING>", old, 8)) tag_open = "<H6>", tag_close = "</H6>"; break; case 'i': case 'I': if (!PL_strncasecmp ("INDENT>", old, 7)) tag_open = "<UL>", tag_close = "</UL>"; else if (!PL_strncasecmp ("INDENTRIGHT>", old, 12)) tag_open = 0, tag_close = 0; /* else if (!enriched_p && !PL_strncasecmp ("ISO-8859-", old, 9)) tag_open = 0, tag_close = 0; */ else if (!PL_strncasecmp ("ITALIC>", old, 7)) tag_open = "<I>", tag_close = "</I>"; break; case 'l': case 'L': if (!enriched_p && !PL_strncasecmp ("LT>", old, 3)) tag_open = "<", tag_close = 0; break; case 'n': case 'N': if (!enriched_p && !PL_strncasecmp ("NL>", old, 3)) tag_open = "<BR>", tag_close = 0; if (enriched_p && !PL_strncasecmp ("NOFILL>", old, 7)) tag_open = "<NOBR>", tag_close = "</NOBR>"; /* else if (!enriched_p && !PL_strncasecmp ("NO-OP>", old, 6)) tag_open = 0, tag_close = 0; */ /* else if (!enriched_p && !PL_strncasecmp ("NP>", old, 3)) tag_open = 0, tag_close = 0; */ break; case 'o': case 'O': if (!enriched_p && !PL_strncasecmp ("OUTDENT>", old, 8)) tag_open = 0, tag_close = 0; else if (!enriched_p && !PL_strncasecmp ("OUTDENTRIGHT>", old, 13)) tag_open = 0, tag_close = 0; break; case 'p': case 'P': if (enriched_p && !PL_strncasecmp ("PARAM>", old, 6)) tag_open = "<!-- ", tag_close = " -->"; else if (!enriched_p && !PL_strncasecmp ("PARAGRAPH>", old, 10)) tag_open = "<P>", tag_close = 0; break; case 's': case 'S': if (!enriched_p && !PL_strncasecmp ("SAMEPAGE>", old, 9)) tag_open = 0, tag_close = 0; else if (!enriched_p && !PL_strncasecmp ("SIGNATURE>", old, 10)) tag_open = "<I><FONT SIZE=\"-1\">", tag_close = "</FONT></I>"; else if (!PL_strncasecmp ("SMALLER>", old, 8)) tag_open = "<FONT SIZE=\"-1\">", tag_close = "</FONT>"; else if (!enriched_p && !PL_strncasecmp ("SUBSCRIPT>", old, 10)) tag_open = "<SUB>", tag_close = "</SUB>"; else if (!enriched_p && !PL_strncasecmp ("SUPERSCRIPT>", old, 12)) tag_open = "<SUP>", tag_close = "</SUP>"; break; case 'u': case 'U': if (!PL_strncasecmp ("UNDERLINE>", old, 10)) tag_open = "<U>", tag_close = "</U>"; /* else if (!enriched_p && !PL_strncasecmp ("US-ASCII>", old, 10)) tag_open = 0, tag_close = 0; */ break; case 'v': case 'V': if (enriched_p && !PL_strncasecmp ("VERBATIM>", old, 9)) tag_open = "<PRE>", tag_close = "</PRE>"; break; } if (this_start[1] == '/') { if (tag_close) PL_strncpyz (out, tag_close, outlen); addedlen = strlen (out); outlen -= addedlen; out += addedlen; } else { if (tag_open) PL_strncpyz (out, tag_open, outlen); addedlen = strlen (out); outlen -= addedlen; out += addedlen; } } /* now go around again */ last_end = this_end; this_start = last_end; } *out = 0; return MimeObject_write(obj, *obufferP, out - *obufferP, true); }
static int MimeInlineTextPlainFlowed_parse_eof (MimeObject *obj, PRBool abort_p) { int status = 0; struct MimeInlineTextPlainFlowedExData *exdata = nsnull; PRBool quoting = ( obj->options && ( obj->options->format_out == nsMimeOutput::nsMimeMessageQuoting || obj->options->format_out == nsMimeOutput::nsMimeMessageBodyQuoting ) ); // see above // Has this method already been called for this object? // In that case return. 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) goto EarlyOut; // Look up and unlink "our" extended data structure // We do it in the beginning so that if an error occur, we can // just free |exdata|. struct MimeInlineTextPlainFlowedExData **prevexdata; prevexdata = &MimeInlineTextPlainFlowedExDataList; while ((exdata = *prevexdata) != nsnull) { if (exdata->ownerobj == obj) { // Fill hole *prevexdata = exdata->next; break; } prevexdata = &exdata->next; } NS_ASSERTION (exdata, "The extra data has disappeared!"); if (!obj->output_p) { status = 0; goto EarlyOut; } for(; exdata->quotelevel > 0; exdata->quotelevel--) { status = MimeObject_write(obj, "</blockquote>", 13, PR_FALSE); if(status<0) goto EarlyOut; } if (exdata->isSig && !quoting) { status = MimeObject_write(obj, "</div>", 6, PR_FALSE); // .moz-txt-sig if (status<0) goto EarlyOut; } if (!quoting) // HACK (see above) { status = MimeObject_write(obj, "</div>", 6, PR_FALSE); // .moz-text-flowed if (status<0) goto EarlyOut; } status = 0; EarlyOut: PR_Free(exdata); // Free mCitationColor MimeInlineTextPlainFlowed *text = (MimeInlineTextPlainFlowed *) obj; PR_FREEIF(text->mCitationColor); text->mCitationColor = nsnull; return status; }
static int MimeUntypedText_parse_line(const char *line, int32_t length, MimeObject *obj) { MimeUntypedText *uty = (MimeUntypedText *)obj; int status = 0; char *name = 0, *type = 0; bool begin_line_p = false; NS_ASSERTION(line && *line, "empty line in mime untyped parse_line"); 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, true); /* Open a new sub-part if this line demands it. */ if (line[0] == 'b' && MimeUntypedText_uu_begin_line_p( line, length, obj->options, &type, &name)) { /* Close the old part and open a new one. */ status = MimeUntypedText_open_subpart(obj, MimeUntypedTextSubpartTypeUUE, type, ENCODING_UUENCODE, name, NULL); PR_FREEIF(name); PR_FREEIF(type); if (status < 0) return status; begin_line_p = true; } else if (line[0] == '=' && MimeUntypedText_yenc_begin_line_p( line, length, obj->options, &type, &name)) { /* Close the old part and open a new one. */ status = MimeUntypedText_open_subpart(obj, MimeUntypedTextSubpartTypeYEnc, type, ENCODING_YENCODE, name, NULL); PR_FREEIF(name); PR_FREEIF(type); if (status < 0) return status; begin_line_p = true; } else if (line[0] == '(' && line[1] == 'T' && MimeUntypedText_binhex_begin_line_p(line, length, obj->options)) { /* Close the old part and open a new one. */ status = MimeUntypedText_open_subpart(obj, MimeUntypedTextSubpartTypeBinhex, APPLICATION_BINHEX, NULL, NULL, NULL); if (status < 0) return status; begin_line_p = true; } /* Open a text/plain sub-part if there is no sub-part open. */ if (!uty->open_subpart) { // rhp: If we get here and we are being fed a line ending, we should // just eat it and continue and if we really get more data, we'll open // up the subpart then. // if (line[0] == '\r') return 0; if (line[0] == '\n') return 0; PR_ASSERT(!begin_line_p); status = MimeUntypedText_open_subpart(obj, MimeUntypedTextSubpartTypeText, TEXT_PLAIN, NULL, NULL, NULL); PR_ASSERT(uty->open_subpart); if (!uty->open_subpart) return -1; if (status < 0) return status; } /* Hand this line to the currently-open sub-part. */ status = uty->open_subpart->clazz->parse_buffer(line, length, uty->open_subpart); if (status < 0) return status; /* Close this sub-part if this line demands it. */ if (begin_line_p) ; else if (line[0] == 'e' && uty->type == MimeUntypedTextSubpartTypeUUE && MimeUntypedText_uu_end_line_p(line, length)) { status = MimeUntypedText_close_subpart(obj); if (status < 0) return status; NS_ASSERTION(!uty->open_subpart, "no open subpart"); } else if (line[0] == '=' && uty->type == MimeUntypedTextSubpartTypeYEnc && MimeUntypedText_yenc_end_line_p(line, length)) { status = MimeUntypedText_close_subpart(obj); if (status < 0) return status; NS_ASSERTION(!uty->open_subpart, "no open subpart"); } else if (uty->type == MimeUntypedTextSubpartTypeBinhex && MimeUntypedText_binhex_end_line_p(line, length)) { status = MimeUntypedText_close_subpart(obj); if (status < 0) return status; NS_ASSERTION(!uty->open_subpart, "no open subpart"); } return 0; }
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 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; }