static int MimeMultipartRelated_initialize(MimeObject* obj) { MimeMultipartRelated* relobj = (MimeMultipartRelated*) obj; relobj->base_url = MimeHeaders_get(obj->headers, HEADER_CONTENT_BASE, false, false); /* rhp: need this for supporting Content-Location */ if (!relobj->base_url) { relobj->base_url = MimeHeaders_get(obj->headers, HEADER_CONTENT_LOCATION, false, false); } /* rhp: need this for supporting Content-Location */ /* I used to have code here to test if the type was text/html. Then I added multipart/alternative as being OK, too. Then I found that the VCard spec seems to talk about having the first part of a multipart/related be an application/directory. At that point, I decided to punt. We handle anything as the first part, and stomp on the HTML it generates to adjust tags to point into the other parts. This probably works out to something reasonable in most cases. */ relobj->hash = PL_NewHashTable(20, PL_HashString, PL_CompareStrings, PL_CompareValues, (PLHashAllocOps *)NULL, NULL); if (!relobj->hash) return MIME_OUT_OF_MEMORY; relobj->input_file_stream = nullptr; relobj->output_file_stream = nullptr; return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(obj); }
// 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 MimeExternalBody_debug_print (MimeObject *obj, PRFileDesc *stream, PRInt32 depth) { MimeExternalBody *bod = (MimeExternalBody *) obj; int i; char *ct, *ct2; char *addr = mime_part_address(obj); if (obj->headers) ct = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE); if (bod->hdrs) ct2 = MimeHeaders_get (bod->hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE); for (i=0; i < depth; i++) PR_Write(stream, " ", 2); /*** fprintf(stream, "<%s %s\n" "\tcontent-type: %s\n" "\tcontent-type: %s\n" "\tBody:%s\n\t0x%08X>\n\n", obj->clazz->class_name, addr ? addr : "???", ct ? ct : "<none>", ct2 ? ct2 : "<none>", bod->body ? bod->body : "<none>", (PRUint32) obj); ***/ PR_FREEIF(addr); PR_FREEIF(ct); PR_FREEIF(ct2); return 0; }
/* 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; }
static int MimeMultCMS_sig_init (void *crypto_closure, MimeObject *multipart_object, MimeHeaders *signature_hdrs) { MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure; char *ct; int status = 0; nsresult rv; if (!signature_hdrs) { return -1; } ct = MimeHeaders_get (signature_hdrs, HEADER_CONTENT_TYPE, PR_TRUE, PR_FALSE); /* Verify that the signature object is of the right type. */ if (!ct || /* is not a signature type */ (PL_strcasecmp(ct, APPLICATION_XPKCS7_SIGNATURE) != 0 && PL_strcasecmp(ct, APPLICATION_PKCS7_SIGNATURE) != 0)) { status = -1; /* #### error msg about bogus message */ } PR_FREEIF(ct); if (status < 0) return status; data->sig_decoder_context = do_CreateInstance(NS_CMSDECODER_CONTRACTID, &rv); if (NS_FAILED(rv)) return 0; rv = data->sig_decoder_context->Start(nsnull, nsnull); if (NS_FAILED(rv)) { status = PR_GetError(); if (status >= 0) status = -1; } return status; }
nsresult nsMimeHeaders::ExtractHeader(const char *headerName, PRBool getAllOfThem, char **_retval) { if (! mHeaders) return NS_ERROR_NOT_INITIALIZED; *_retval = MimeHeaders_get(mHeaders, headerName, PR_FALSE, getAllOfThem); return NS_OK; }
nsresult nsMimeHeaders::ExtractHeader(const char *headerName, bool getAllOfThem, char **_retval) { NS_ENSURE_ARG_POINTER(_retval); NS_ENSURE_TRUE(mHeaders, NS_ERROR_NOT_INITIALIZED); *_retval = MimeHeaders_get(mHeaders, headerName, false, getAllOfThem); return NS_OK; }
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 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 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 MimeMultipartAlternative_display_part_p(MimeObject *self, MimeHeaders *sub_hdrs) { char *ct = MimeHeaders_get (sub_hdrs, HEADER_CONTENT_TYPE, true, false); if (!ct) return false; /* RFC 1521 says: Receiving user agents should pick and display the last format they are capable of displaying. In the case where one of the alternatives is itself of type "multipart" and contains unrecognized sub-parts, the user agent may choose either to show that alternative, an earlier alternative, or both. Ugh. If there is a multipart subtype of alternative, we simply show that, without descending into it to determine if any of its sub-parts are themselves unknown. */ // prefer_plaintext pref nsIPrefBranch *prefBranch = GetPrefBranch(self->options); bool prefer_plaintext = false; if (prefBranch) prefBranch->GetBoolPref("mailnews.display.prefer_plaintext", &prefer_plaintext); if (prefer_plaintext && self->options->format_out != nsMimeOutput::nsMimeMessageSaveAs && (!PL_strncasecmp(ct, "text/html", 9) || !PL_strncasecmp(ct, "text/enriched", 13) || !PL_strncasecmp(ct, "text/richtext", 13)) ) // if the user prefers plaintext and this is the "rich" (e.g. HTML) part... { return false; } MimeObjectClass *clazz = mime_find_class (ct, sub_hdrs, self->options, true); bool result = (clazz ? clazz->displayable_inline_p(clazz, sub_hdrs) : false); PR_FREEIF(ct); return result; }
static void* MimePgpe_init(MimeObject *obj, int (*output_fn) (const char *buf, int32_t buf_size, void *output_closure), void *output_closure) { if (!(obj && obj->options && output_fn)) return nullptr; MimePgpeData* data = new MimePgpeData(); NS_ENSURE_TRUE(data, nullptr); data->self = obj; data->output_fn = output_fn; data->output_closure = output_closure; data->mimeDecrypt = nullptr; nsresult rv; data->mimeDecrypt = do_CreateInstance(NS_PGPMIMEPROXY_CONTRACTID, &rv); if (NS_FAILED(rv)) return data; char *ct = MimeHeaders_get(obj->headers, HEADER_CONTENT_TYPE, false, false); rv = (ct ? data->mimeDecrypt->SetContentType(nsDependentCString(ct)) : data->mimeDecrypt->SetContentType(EmptyCString())); PR_Free(ct); if (NS_FAILED(rv)) return nullptr; mime_stream_data *msd = (mime_stream_data *) (data->self->options->stream_closure); nsIChannel *channel = msd->channel; nsCOMPtr<nsIURI> uri; if (channel) channel->GetURI(getter_AddRefs(uri)); if (NS_FAILED(data->mimeDecrypt->SetMimeCallback(output_fn, output_closure, uri))) return nullptr; return data; }
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 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 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 MimeMultipartSigned_parse_line (const char *line, PRInt32 length, MimeObject *obj) { MimeMultipart *mult = (MimeMultipart *) obj; MimeMultipartSigned *sig = (MimeMultipartSigned *) obj; MimeMultipartParseState old_state = mult->state; bool hash_line_p = true; bool no_headers_p = false; int status = 0; /* First do the parsing for normal multipart/ objects by handing it off to the superclass method. This includes calling the create_child and close_child methods. */ status = (((MimeObjectClass *)(&MIME_SUPERCLASS)) ->parse_line (line, length, obj)); if (status < 0) return status; /* The instance variable MimeMultipartClass->state tracks motion through the various stages of multipart/ parsing. The instance variable MimeMultipartSigned->state tracks the difference between the first part (the body) and the second part (the signature.) This second, more specific state variable is updated by noticing the transitions of the first, more general state variable. */ if (old_state != mult->state) /* there has been a state change */ { switch (mult->state) { case MimeMultipartPreamble: PR_ASSERT(0); /* can't move *in* to preamble state. */ sig->state = MimeMultipartSignedPreamble; break; case MimeMultipartHeaders: /* If we're moving in to the Headers state, then that means that this line is the preceeding boundary string (and we should ignore it.) */ hash_line_p = false; if (sig->state == MimeMultipartSignedPreamble) sig->state = MimeMultipartSignedBodyFirstHeader; else if (sig->state == MimeMultipartSignedBodyFirstLine || sig->state == MimeMultipartSignedBodyLine) sig->state = MimeMultipartSignedSignatureHeaders; else if (sig->state == MimeMultipartSignedSignatureFirstLine || sig->state == MimeMultipartSignedSignatureLine) sig->state = MimeMultipartSignedEpilogue; break; case MimeMultipartPartFirstLine: if (sig->state == MimeMultipartSignedBodyFirstHeader) { sig->state = MimeMultipartSignedBodyFirstLine; no_headers_p = true; } else if (sig->state == MimeMultipartSignedBodyHeaders) sig->state = MimeMultipartSignedBodyFirstLine; else if (sig->state == MimeMultipartSignedSignatureHeaders) sig->state = MimeMultipartSignedSignatureFirstLine; else sig->state = MimeMultipartSignedEpilogue; break; case MimeMultipartPartLine: PR_ASSERT(sig->state == MimeMultipartSignedBodyFirstLine || sig->state == MimeMultipartSignedBodyLine || sig->state == MimeMultipartSignedSignatureFirstLine || sig->state == MimeMultipartSignedSignatureLine); if (sig->state == MimeMultipartSignedBodyFirstLine) sig->state = MimeMultipartSignedBodyLine; else if (sig->state == MimeMultipartSignedSignatureFirstLine) sig->state = MimeMultipartSignedSignatureLine; break; case MimeMultipartEpilogue: sig->state = MimeMultipartSignedEpilogue; break; default: /* bad state */ NS_ERROR("bad state in MultipartSigned parse line"); return -1; break; } } /* Perform multipart/signed-related actions on this line based on the state of the parser. */ switch (sig->state) { case MimeMultipartSignedPreamble: /* Do nothing. */ break; case MimeMultipartSignedBodyFirstLine: /* We have just moved out of the MimeMultipartSignedBodyHeaders state, so cache away the headers that apply only to the body part. */ NS_ASSERTION(mult->hdrs, "null multipart hdrs"); NS_ASSERTION(!sig->body_hdrs, "signed part shouldn't have already have body_hdrs"); sig->body_hdrs = mult->hdrs; mult->hdrs = 0; /* fall through. */ case MimeMultipartSignedBodyFirstHeader: case MimeMultipartSignedBodyHeaders: case MimeMultipartSignedBodyLine: if (!sig->crypto_closure) { /* Set error change */ PR_SetError(0, 0); /* Initialize the signature verification library. */ sig->crypto_closure = (((MimeMultipartSignedClass *) obj->clazz) ->crypto_init) (obj); if (!sig->crypto_closure) { status = PR_GetError(); NS_ASSERTION(status < 0, "got non-negative status"); if (status >= 0) status = -1; return status; } } if (hash_line_p) { /* this is the first hashed line if this is the first header (that is, if it's the first line in the header state after a state change.) */ bool first_line_p = (no_headers_p || sig->state == MimeMultipartSignedBodyFirstHeader); if (sig->state == MimeMultipartSignedBodyFirstHeader) sig->state = MimeMultipartSignedBodyHeaders; /* The newline issues here are tricky, since both the newlines before and after the boundary string are to be considered part of the boundary: this is so that a part can be specified such that it does not end in a trailing newline. To implement this, we send a newline *before* each line instead of after, except for the first line, which is not preceeded by a newline. For purposes of cryptographic hashing, we always hash line breaks as CRLF -- the canonical, on-the-wire linebreaks, since we have no idea of knowing what line breaks were used on the originating system (SMTP rightly destroys that information.) */ /* Remove the trailing newline... */ if (length > 0 && line[length-1] == '\n') length--; if (length > 0 && line[length-1] == '\r') length--; PR_ASSERT(sig->crypto_closure); if (!first_line_p) { /* Push out a preceeding newline... */ char nl[] = CRLF; status = (((MimeMultipartSignedClass *) obj->clazz) ->crypto_data_hash (nl, 2, sig->crypto_closure)); if (status < 0) return status; } /* Now push out the line sans trailing newline. */ if (length > 0) status = (((MimeMultipartSignedClass *) obj->clazz) ->crypto_data_hash (line,length, sig->crypto_closure)); if (status < 0) return status; } break; case MimeMultipartSignedSignatureHeaders: if (sig->crypto_closure && old_state != mult->state) { /* We have just moved out of the MimeMultipartSignedBodyLine state, so tell the signature verification library that we've reached the end of the signed data. */ status = (((MimeMultipartSignedClass *) obj->clazz) ->crypto_data_eof) (sig->crypto_closure, false); if (status < 0) return status; } break; case MimeMultipartSignedSignatureFirstLine: /* We have just moved out of the MimeMultipartSignedSignatureHeaders state, so cache away the headers that apply only to the sig part. */ PR_ASSERT(mult->hdrs); PR_ASSERT(!sig->sig_hdrs); sig->sig_hdrs = mult->hdrs; mult->hdrs = 0; /* If the signature block has an encoding, set up a decoder for it. (Similar logic is in MimeLeafClass->parse_begin.) */ { MimeDecoderData *(*fn) (nsresult (*) (const char*, PRInt32,void*), void*) = 0; nsCString encoding; encoding.Adopt(MimeHeaders_get (sig->sig_hdrs, HEADER_CONTENT_TRANSFER_ENCODING, true, false)); if (encoding.IsEmpty()) ; else if (!PL_strcasecmp(encoding.get(), ENCODING_BASE64)) fn = &MimeB64DecoderInit; else if (!PL_strcasecmp(encoding.get(), ENCODING_QUOTED_PRINTABLE)) { sig->sig_decoder_data = MimeQPDecoderInit (((nsresult (*) (const char *, PRInt32, void *)) (((MimeMultipartSignedClass *) obj->clazz) ->crypto_signature_hash)), sig->crypto_closure); if (!sig->sig_decoder_data) return MIME_OUT_OF_MEMORY; } else if (!PL_strcasecmp(encoding.get(), ENCODING_UUENCODE) || !PL_strcasecmp(encoding.get(), ENCODING_UUENCODE2) || !PL_strcasecmp(encoding.get(), ENCODING_UUENCODE3) || !PL_strcasecmp(encoding.get(), ENCODING_UUENCODE4)) fn = &MimeUUDecoderInit; else if (!PL_strcasecmp(encoding.get(), ENCODING_YENCODE)) fn = &MimeYDecoderInit; if (fn) { sig->sig_decoder_data = fn (((nsresult (*) (const char *, PRInt32, void *)) (((MimeMultipartSignedClass *) obj->clazz) ->crypto_signature_hash)), sig->crypto_closure); if (!sig->sig_decoder_data) return MIME_OUT_OF_MEMORY; } } /* Show these headers to the crypto module. */ if (hash_line_p) { status = (((MimeMultipartSignedClass *) obj->clazz) ->crypto_signature_init) (sig->crypto_closure, obj, sig->sig_hdrs); if (status < 0) return status; } /* fall through. */ case MimeMultipartSignedSignatureLine: if (hash_line_p) { /* Feed this line into the signature verification routines. */ if (sig->sig_decoder_data) status = MimeDecoderWrite (sig->sig_decoder_data, line, length, nsnull); else status = (((MimeMultipartSignedClass *) obj->clazz) ->crypto_signature_hash (line, length, sig->crypto_closure)); if (status < 0) return status; } break; case MimeMultipartSignedEpilogue: /* Nothing special to do here. */ break; default: /* bad state */ PR_ASSERT(0); return -1; } return status; }
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; }
static char * MimeMessage_partial_message_html(const char *data, void *closure, MimeHeaders *headers) { MimeMessage *msg = (MimeMessage *)closure; nsAutoCString orig_url(data); char *uidl = MimeHeaders_get(headers, HEADER_X_UIDL, false, false); char *msgId = MimeHeaders_get(headers, HEADER_MESSAGE_ID, false, false); char *msgIdPtr = PL_strchr(msgId, '<'); int32_t pos = orig_url.Find("mailbox-message"); if (pos != -1) orig_url.Cut(pos + 7, 8); pos = orig_url.FindChar('#'); if (pos != -1) orig_url.Replace(pos, 1, "?number=", 8); if (msgIdPtr) msgIdPtr++; else msgIdPtr = msgId; char *gtPtr = PL_strchr(msgIdPtr, '>'); if (gtPtr) *gtPtr = 0; bool msgBaseTruncated = (msg->bodyLength > MSG_LINEBREAK_LEN); nsCString partialMsgHtml; nsCString item; partialMsgHtml.AppendLiteral("<div style=\"margin: 1em auto; border: 1px solid black; width: 80%\">"); partialMsgHtml.AppendLiteral("<div style=\"margin: 5px; padding: 10px; border: 1px solid gray; font-weight: bold; text-align: center;\">"); partialMsgHtml.AppendLiteral("<span style=\"font-size: 120%;\">"); if (msgBaseTruncated) item.Adopt(MimeGetStringByName(MOZ_UTF16("MIME_MSG_PARTIAL_TRUNCATED"))); else item.Adopt(MimeGetStringByName(MOZ_UTF16("MIME_MSG_PARTIAL_NOT_DOWNLOADED"))); partialMsgHtml += item; partialMsgHtml.AppendLiteral("</span><hr>"); if (msgBaseTruncated) item.Adopt(MimeGetStringByName(MOZ_UTF16("MIME_MSG_PARTIAL_TRUNCATED_EXPLANATION"))); else item.Adopt(MimeGetStringByName(MOZ_UTF16("MIME_MSG_PARTIAL_NOT_DOWNLOADED_EXPLANATION"))); partialMsgHtml += item; partialMsgHtml.AppendLiteral("<br><br>"); partialMsgHtml.AppendLiteral("<a href=\""); partialMsgHtml.Append(orig_url); if (msgIdPtr) { partialMsgHtml.AppendLiteral("&messageid="); MsgEscapeString(nsDependentCString(msgIdPtr), nsINetUtil::ESCAPE_URL_PATH, item); partialMsgHtml.Append(item); } if (uidl) { partialMsgHtml.AppendLiteral("&uidl="); MsgEscapeString(nsDependentCString(uidl), nsINetUtil::ESCAPE_XALPHAS, item); partialMsgHtml.Append(item); } partialMsgHtml.AppendLiteral("\">"); item.Adopt(MimeGetStringByName(MOZ_UTF16("MIME_MSG_PARTIAL_CLICK_FOR_REST"))); partialMsgHtml += item; partialMsgHtml.AppendLiteral("</a>"); partialMsgHtml.AppendLiteral("</div></div>"); return ToNewCString(partialMsgHtml); }
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 MimeMultipartRelated_parse_eof (MimeObject *obj, bool abort_p) { /* OK, all the necessary data has been collected. We now have to spew out the HTML. We let it go through all the normal mechanisms (which includes content-encoding handling), and intercept the output data to do translation of the tags. Whee. */ MimeMultipartRelated *relobj = (MimeMultipartRelated *) obj; MimeContainer *cont = (MimeContainer *)obj; int status = 0; MimeObject *body; char* ct; const char* dct; status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p); if (status < 0) goto FAIL; if (!relobj->headobj) return 0; ct = (relobj->buffered_hdrs ? MimeHeaders_get (relobj->buffered_hdrs, HEADER_CONTENT_TYPE, true, false) : 0); dct = (((MimeMultipartClass *) obj->clazz)->default_part_type); relobj->real_output_fn = obj->options->output_fn; relobj->real_output_closure = obj->options->output_closure; obj->options->output_fn = mime_multipart_related_output_fn; obj->options->output_closure = obj; body = mime_create(((ct && *ct) ? ct : (dct ? dct : TEXT_HTML)), relobj->buffered_hdrs, obj->options); PR_FREEIF(ct); if (!body) { status = MIME_OUT_OF_MEMORY; goto FAIL; } // replace the existing head object with the new object for (int iChild = 0; iChild < cont->nchildren; iChild++) { if (cont->children[iChild] == relobj->headobj) { // cleanup of the headobj is performed explicitly in our finalizer now // that it does not get cleaned up as a child. cont->children[iChild] = body; body->parent = obj; body->options = obj->options; } } if (!body->parent) { NS_WARNING("unexpected mime multipart related structure"); goto FAIL; } body->dontShowAsAttachment = body->clazz->displayable_inline_p(body->clazz, body->headers); #ifdef MIME_DRAFTS if ( obj->options && obj->options->decompose_file_p && obj->options->decompose_file_init_fn && (relobj->file_buffer || relobj->head_buffer)) { status = obj->options->decompose_file_init_fn ( obj->options->stream_closure, relobj->buffered_hdrs ); if (status < 0) return status; } #endif /* MIME_DRAFTS */ /* if the emitter wants to know about nested bodies, then it needs to know that we jumped back to this body part. */ if (obj->options->notify_nested_bodies) { char *part_path = mime_part_address(body); if (part_path) { mimeEmitterAddHeaderField(obj->options, "x-jsemitter-part-path", part_path); PR_Free(part_path); } } /* 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) goto FAIL; if (relobj->head_buffer) { /* Read it out of memory. */ PR_ASSERT(!relobj->file_buffer && !relobj->input_file_stream); status = body->clazz->parse_buffer(relobj->head_buffer, relobj->head_buffer_fp, body); } else if (relobj->file_buffer) { /* Read it off disk. */ char *buf; int32_t buf_size = 10 * 1024; /* 10k; tune this? */ PR_ASSERT(relobj->head_buffer_size == 0 && relobj->head_buffer_fp == 0); PR_ASSERT(relobj->file_buffer); if (!relobj->file_buffer) { status = -1; goto FAIL; } buf = (char *) PR_MALLOC(buf_size); if (!buf) { status = MIME_OUT_OF_MEMORY; goto FAIL; } // First, close the output file to open the input file! if (relobj->output_file_stream) relobj->output_file_stream->Close(); nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(relobj->input_file_stream), relobj->file_buffer); if (NS_FAILED(rv)) { PR_Free(buf); status = MIME_UNABLE_TO_OPEN_TMP_FILE; goto FAIL; } while(1) { uint32_t bytesRead = 0; rv = relobj->input_file_stream->Read(buf, buf_size - 1, &bytesRead); if (NS_FAILED(rv) || !bytesRead) { status = NS_FAILED(rv) ? -1 : 0; break; } else { /* It would be really nice to be able to yield here, and let some user events and other input sources get processed. Oh well. */ status = body->clazz->parse_buffer(buf, bytesRead, body); if (status < 0) break; } } PR_Free(buf); } if (status < 0) goto FAIL; /* Done parsing. */ status = body->clazz->parse_eof(body, false); if (status < 0) goto FAIL; status = body->clazz->parse_end(body, false); if (status < 0) goto FAIL; FAIL: #ifdef MIME_DRAFTS if ( obj->options && obj->options->decompose_file_p && obj->options->decompose_file_close_fn && (relobj->file_buffer || relobj->head_buffer)) { status = obj->options->decompose_file_close_fn ( obj->options->stream_closure ); if (status < 0) return status; } #endif /* MIME_DRAFTS */ obj->options->output_fn = relobj->real_output_fn; obj->options->output_closure = relobj->real_output_closure; return status; }
static int MimeObject_initialize (MimeObject *obj) { /* This is an abstract class; it shouldn't be directly instantiated. */ NS_ASSERTION(obj->clazz != &mimeObjectClass, "should directly instantiate abstract class"); /* Set up the content-type and encoding. */ if (!obj->content_type && obj->headers) obj->content_type = MimeHeaders_get (obj->headers, HEADER_CONTENT_TYPE, PR_TRUE, PR_FALSE); if (!obj->encoding && obj->headers) obj->encoding = MimeHeaders_get (obj->headers, HEADER_CONTENT_TRANSFER_ENCODING, PR_TRUE, PR_FALSE); /* Special case to normalize some types and encodings to a canonical form. (These are nonstandard types/encodings which have been seen to appear in multiple forms; we normalize them so that things like looking up icons and extensions has consistent behavior for the receiver, regardless of the "alias" type that the sender used.) */ if (!obj->content_type || !*(obj->content_type)) ; else if (!PL_strcasecmp(obj->content_type, APPLICATION_UUENCODE2) || !PL_strcasecmp(obj->content_type, APPLICATION_UUENCODE3) || !PL_strcasecmp(obj->content_type, APPLICATION_UUENCODE4)) { PR_Free(obj->content_type); obj->content_type = strdup(APPLICATION_UUENCODE); } else if (!PL_strcasecmp(obj->content_type, IMAGE_XBM2) || !PL_strcasecmp(obj->content_type, IMAGE_XBM3)) { PR_Free(obj->content_type); obj->content_type = strdup(IMAGE_XBM); } else { // MIME-types are case-insenitive, but let's make it lower case internally // to avoid some hassle later down the road. nsCAutoString lowerCaseContentType; ToLowerCase(nsDependentCString(obj->content_type), lowerCaseContentType); PR_Free(obj->content_type); obj->content_type = ToNewCString(lowerCaseContentType); } if (!obj->encoding) ; else if (!PL_strcasecmp(obj->encoding, ENCODING_UUENCODE2) || !PL_strcasecmp(obj->encoding, ENCODING_UUENCODE3) || !PL_strcasecmp(obj->encoding, ENCODING_UUENCODE4)) { PR_Free(obj->encoding); obj->encoding = strdup(ENCODING_UUENCODE); } else if (!PL_strcasecmp(obj->encoding, ENCODING_COMPRESS2)) { PR_Free(obj->encoding); obj->encoding = strdup(ENCODING_COMPRESS); } else if (!PL_strcasecmp(obj->encoding, ENCODING_GZIP2)) { PR_Free(obj->encoding); obj->encoding = strdup(ENCODING_GZIP); } 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 MimeMultipartAlternative_display_cached_part(MimeObject *obj, MimeHeaders *hdrs, MimePartBufferData *buffer, bool do_display) { int status; char *ct = (hdrs ? MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, true, false) : 0); const char *dct = (((MimeMultipartClass *) obj->clazz)->default_part_type); MimeObject *body; /** Don't pass in NULL as the content-type (this means that the * auto-uudecode-hack won't ever be done for subparts of a * multipart, but only for untyped children of message/rfc822. */ const char *uct = (ct && *ct) ? ct : (dct ? dct: TEXT_PLAIN); // We always want to display the cached part inline. body = mime_create(uct, hdrs, obj->options, true); PR_FREEIF(ct); if (!body) return MIME_OUT_OF_MEMORY; body->output_p = do_display; status = ((MimeContainerClass *) obj->clazz)->add_child(obj, body); if (status < 0) { mime_free(body); return status; } /* We need to muck around with the options to prevent output when do_display is false. More about this below. */ /* add_child assigns body->options from obj->options, but that's just a pointer so if we muck with it in the child it'll modify the parent as well, which we definitely don't want. Therefore we need to make a copy. */ body->options = new MimeDisplayOptions; *body->options = *obj->options; /* But we have to be careful about getting into a situation where memory could be double-freed. All of this is a gross abstraction violation which could be avoided if it were possible to tell parse_begin what output_p should be. */ if (body->options->part_to_load) body->options->part_to_load = strdup(body->options->part_to_load); if (body->options->default_charset) body->options->default_charset = strdup(body->options->default_charset); /* parse_begin resets output_p. This is quite annoying. To convince it that we mean business, we set output_fn to null if we don't want output. */ if (! do_display) body->options->output_fn = nullptr; #ifdef MIME_DRAFTS /* if this object is a child of a multipart/related object, the parent is taking care of decomposing the whole part, don't need to do it at this level. However, we still have to call decompose_file_init_fn and decompose_file_close_fn in order to set the correct content-type. But don't call MimePartBufferRead */ bool multipartRelatedChild = mime_typep(obj->parent,(MimeObjectClass*)&mimeMultipartRelatedClass); bool decomposeFile = do_display && obj->options && obj->options->decompose_file_p && obj->options->decompose_file_init_fn && !mime_typep(body, (MimeObjectClass *) &mimeMultipartClass); if (decomposeFile) { status = obj->options->decompose_file_init_fn ( obj->options->stream_closure, hdrs); if (status < 0) return status; } #endif /* MIME_DRAFTS */ /* Now that we've added this new object to our list of children, notify emitters and start its parser going. */ MimeMultipart_notify_emitter(body); status = body->clazz->parse_begin(body); if (status < 0) return status; /* Now that parse_begin is done mucking with output_p, we can put body->options back to what it's supposed to be. Avoids a memory leak. */ delete body->options; body->options = obj->options; #ifdef MIME_DRAFTS if (decomposeFile && !multipartRelatedChild) status = MimePartBufferRead (buffer, obj->options->decompose_file_output_fn, obj->options->stream_closure); else #endif /* MIME_DRAFTS */ status = MimePartBufferRead (buffer, /* The MimeConverterOutputCallback cast is to turn the `void' argument into `MimeObject'. */ ((MimeConverterOutputCallback) body->clazz->parse_buffer), body); if (status < 0) return status; /* 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 (decomposeFile) { status = obj->options->decompose_file_close_fn ( obj->options->stream_closure ); if (status < 0) return status; } #endif /* MIME_DRAFTS */ return 0; }
static int MimeMultipart_create_child(MimeObject *obj) { MimeMultipart *mult = (MimeMultipart *) obj; int status; char *ct = (mult->hdrs ? MimeHeaders_get (mult->hdrs, HEADER_CONTENT_TYPE, PR_TRUE, PR_FALSE) : 0); const char *dct = (((MimeMultipartClass *) obj->clazz)->default_part_type); MimeObject *body = NULL; mult->state = MimeMultipartPartFirstLine; /* Don't pass in NULL as the content-type (this means that the auto-uudecode-hack won't ever be done for subparts of a multipart, but only for untyped children of message/rfc822. */ body = mime_create(((ct && *ct) ? ct : (dct ? dct: TEXT_PLAIN)), mult->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; } #ifdef MIME_DRAFTS if ( obj->options && obj->options->decompose_file_p && obj->options->is_multipart_msg && obj->options->decompose_file_init_fn ) { if ( !mime_typep(obj,(MimeObjectClass*)&mimeMultipartRelatedClass) && !mime_typep(obj,(MimeObjectClass*)&mimeMultipartAlternativeClass) && !mime_typep(obj,(MimeObjectClass*)&mimeMultipartSignedClass) && #ifdef MIME_DETAIL_CHECK !mime_typep(body, (MimeObjectClass*)&mimeMultipartRelatedClass) && !mime_typep(body, (MimeObjectClass*)&mimeMultipartAlternativeClass) && !mime_typep(body,(MimeObjectClass*)&mimeMultipartSignedClass) #else /* bug 21869 -- due to the fact that we are not generating the correct mime class object for content-typ multipart/signed part the above check failed. to solve the problem in general and not to cause early temination when parsing message for opening as draft we can simply make sure that the child is not a multipart mime object. this way we could have a proper decomposing message part functions set correctly */ !mime_typep(body, (MimeObjectClass*) &mimeMultipartClass) #endif && ! (mime_typep(body, (MimeObjectClass*)&mimeExternalObjectClass) && !strcmp(body->content_type, "text/x-vcard")) ) { status = obj->options->decompose_file_init_fn ( obj->options->stream_closure, mult->hdrs ); if (status < 0) return status; } } #endif /* MIME_DRAFTS */ /* Now that we've added this new object to our list of children, start its parser going (if we want to display it.) */ body->output_p = (((MimeMultipartClass *) obj->clazz)->output_child_p(obj, body)); if (body->output_p) { status = body->clazz->parse_begin(body); #ifdef XP_MACOSX /* if we are saving an apple double attachment, we need to set correctly the conten type of the channel */ if (mime_typep(obj, (MimeObjectClass *) &mimeMultipartAppleDoubleClass)) { struct mime_stream_data *msd = (struct mime_stream_data *)body->options->stream_closure; if (!body->options->write_html_p && body->content_type && !PL_strcasecmp(body->content_type, APPLICATION_APPLEFILE)) { if (msd && msd->channel) msd->channel->SetContentType(NS_LITERAL_CSTRING(APPLICATION_APPLEFILE)); } } #endif if (status < 0) return status; } 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 char * MimeMessage_partial_message_html(const char *data, void *closure, MimeHeaders *headers) { MimeMessage *msg = (MimeMessage *)closure; nsCAutoString orig_url(data); char *uidl = MimeHeaders_get(headers, HEADER_X_UIDL, PR_FALSE, PR_FALSE); char *msgId = MimeHeaders_get(headers, HEADER_MESSAGE_ID, PR_FALSE, PR_FALSE); char *msgIdPtr = PL_strstr(msgId, "<"); int msgBase; PRInt32 pos = orig_url.Find("mailbox-message"); if (pos != -1) orig_url.Cut(pos + 7, 8); pos = orig_url.Find("#"); if (pos != -1) orig_url.Replace(pos, 1, "?number=", 8); if (msgIdPtr) msgIdPtr++; else msgIdPtr = msgId; char *gtPtr = PL_strstr(msgIdPtr, ">"); if (gtPtr) *gtPtr = 0; msgBase = (msg->bodyLength > MSG_LINEBREAK_LEN) ? MIME_MSG_PARTIAL_FMT_1 : MIME_MSG_PARTIAL_FMT2_1; nsCString partialMsgHtml; nsCString item; item.Adopt(MimeGetStringByID(msgBase)); partialMsgHtml += item; item.Adopt(MimeGetStringByID(msgBase+1)); partialMsgHtml += item; partialMsgHtml.Append(orig_url); if (msgIdPtr) { partialMsgHtml.AppendLiteral("&messageid="); MsgEscapeString(nsDependentCString(msgIdPtr), nsINetUtil::ESCAPE_URL_PATH, item); partialMsgHtml.Append(item); } if (uidl) { partialMsgHtml.AppendLiteral("&uidl="); MsgEscapeString(nsDependentCString(uidl), nsINetUtil::ESCAPE_XALPHAS, item); partialMsgHtml.Append(item); } item.Adopt(MimeGetStringByID(msgBase+2)); partialMsgHtml += item; return ToNewCString(partialMsgHtml); }
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 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 bool MimeMultipartRelated_output_child_p(MimeObject *obj, MimeObject* child) { MimeMultipartRelated *relobj = (MimeMultipartRelated *) obj; /* rhp - Changed from "if (relobj->head_loaded)" alone to support the start parameter */ if ( (relobj->head_loaded) || (MimeStartParamExists(obj, child) && !MimeThisIsStartPart(obj, child)) ) { /* This is a child part. Just remember the mapping between the URL it represents and the part-URL to get it back. */ char* location = MimeHeaders_get(child->headers, HEADER_CONTENT_LOCATION, false, false); if (!location) { char* tmp = MimeHeaders_get(child->headers, HEADER_CONTENT_ID, false, false); if (tmp) { char* tmp2 = tmp; if (*tmp2 == '<') { int length; tmp2++; length = strlen(tmp2); if (length > 0 && tmp2[length - 1] == '>') { tmp2[length - 1] = '\0'; } } location = PR_smprintf("cid:%s", tmp2); PR_Free(tmp); } } if (location) { char *absolute; char *base_url = MimeHeaders_get(child->headers, HEADER_CONTENT_BASE, false, false); absolute = MakeAbsoluteURL(base_url ? base_url : relobj->base_url, location); PR_FREEIF(base_url); PR_Free(location); if (absolute) { nsCAutoString partnum; nsCAutoString imappartnum; partnum.Adopt(mime_part_address(child)); if (!partnum.IsEmpty()) { if (obj->options->missing_parts) { char * imappart = mime_imap_part_address(child); if (imappart) imappartnum.Adopt(imappart); } /* AppleDouble part need special care: we need to output only the data fork part of it. The problem at this point is that we haven't yet decoded the children of the AppleDouble part therfore we will have to hope the datafork is the second one! */ if (mime_typep(child, (MimeObjectClass *) &mimeMultipartAppleDoubleClass)) partnum.Append(".2"); char* part; if (!imappartnum.IsEmpty()) part = mime_set_url_imap_part(obj->options->url, imappartnum.get(), partnum.get()); else { char *no_part_url = nullptr; if (obj->options->part_to_load && obj->options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay) no_part_url = mime_get_base_url(obj->options->url); if (no_part_url) { part = mime_set_url_part(no_part_url, partnum.get(), false); PR_Free(no_part_url); } else part = mime_set_url_part(obj->options->url, partnum.get(), false); } if (part) { char *name = MimeHeaders_get_name(child->headers, child->options); // let's stick the filename in the part so save as will work. if (name) { //char *savePart = part; //part = PR_smprintf("%s&filename=%s", savePart, name); //PR_Free(savePart); PR_Free(name); } char *temp = part; /* If there's a space in the url, escape the url. (This happens primarily on Windows and Unix.) */ if (PL_strchr(part, ' ') || PL_strchr(part, '>') || PL_strchr(part, '%')) temp = escape_for_mrel_subst(part); MimeHashValue * value = new MimeHashValue(child, temp); PL_HashTableAdd(relobj->hash, absolute, value); /* rhp - If this part ALSO has a Content-ID we need to put that into the hash table and this is what this code does */ { char *tloc; char *tmp = MimeHeaders_get(child->headers, HEADER_CONTENT_ID, false, false); if (tmp) { char* tmp2 = tmp; if (*tmp2 == '<') { int length; tmp2++; length = strlen(tmp2); if (length > 0 && tmp2[length - 1] == '>') { tmp2[length - 1] = '\0'; } } tloc = PR_smprintf("cid:%s", tmp2); PR_Free(tmp); if (tloc) { MimeHashValue *value; value = (MimeHashValue*)PL_HashTableLookup(relobj->hash, tloc); if (!value) { value = new MimeHashValue(child, temp); PL_HashTableAdd(relobj->hash, tloc, value); } else PR_smprintf_free(tloc); } } } /* rhp - End of putting more stuff into the hash table */ /* it's possible that temp pointer is the same than the part pointer, therefore be carefull to not freeing twice the same pointer */ if (temp && temp != part) PR_Free(temp); PR_Free(part); } } } } } else { /* Ah-hah! We're the head object. */ char* base_url; relobj->head_loaded = true; relobj->headobj = child; relobj->buffered_hdrs = MimeHeaders_copy(child->headers); base_url = MimeHeaders_get(child->headers, HEADER_CONTENT_BASE, false, false); /* rhp: need this for supporting Content-Location */ if (!base_url) { base_url = MimeHeaders_get(child->headers, HEADER_CONTENT_LOCATION, false, false); } /* rhp: need this for supporting Content-Location */ if (base_url) { /* If the head object has a base_url associated with it, use that instead of any base_url that may have been associated with the multipart/related. */ PR_FREEIF(relobj->base_url); relobj->base_url = base_url; } } if (obj->options && !obj->options->write_html_p #ifdef MIME_DRAFTS && !obj->options->decompose_file_p #endif /* MIME_DRAFTS */ ) { return true; } return false; /* Don't actually parse this child; we'll handle all that at eof time. */ }