summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/mime/src/mimehdrs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/mime/src/mimehdrs.cpp')
-rw-r--r--comm/mailnews/mime/src/mimehdrs.cpp785
1 files changed, 785 insertions, 0 deletions
diff --git a/comm/mailnews/mime/src/mimehdrs.cpp b/comm/mailnews/mime/src/mimehdrs.cpp
new file mode 100644
index 0000000000..6df9028765
--- /dev/null
+++ b/comm/mailnews/mime/src/mimehdrs.cpp
@@ -0,0 +1,785 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "nsCOMPtr.h"
+#include "msgCore.h"
+#include "mimei.h"
+#include "prmem.h"
+#include "prlog.h"
+#include "plstr.h"
+#include "mimebuf.h"
+#include "mimemoz2.h"
+#include "comi18n.h"
+#include "nsMailHeaders.h"
+#include "msgCore.h"
+#include "nsMimeStringResources.h"
+#include "mimemoz2.h"
+#include "nsMsgI18N.h"
+#include "mimehdrs.h"
+#include "nsIMIMEHeaderParam.h"
+#include "nsNetCID.h"
+#include "nsServiceManagerUtils.h"
+#include "nsMemory.h"
+#include <ctype.h>
+#include "nsMsgUtils.h"
+#include "mozilla/Unused.h"
+
+// Forward declares...
+int32_t MimeHeaders_build_heads_list(MimeHeaders* hdrs);
+
+void MimeHeaders_convert_header_value(MimeDisplayOptions* opt, nsCString& value,
+ bool convert_charset_only) {
+ if (value.IsEmpty()) return;
+
+ if (convert_charset_only) {
+ nsAutoCString output;
+ nsMsgI18NConvertRawBytesToUTF8(
+ value,
+ opt->default_charset ? nsDependentCString(opt->default_charset)
+ : EmptyCString(),
+ output);
+ value.Assign(output);
+ return;
+ }
+
+ if (opt && opt->rfc1522_conversion_p) {
+ nsAutoCString temporary;
+ MIME_DecodeMimeHeader(value.get(), opt->default_charset,
+ opt->override_charset, true, temporary);
+
+ if (!temporary.IsEmpty()) {
+ value = temporary;
+ }
+ } else {
+ // This behavior, though highly unusual, was carefully preserved
+ // from the previous implementation. It may be that this is dead
+ // code, in which case opt->rfc1522_conversion_p is no longer
+ // needed.
+ value.Truncate();
+ }
+}
+
+MimeHeaders* MimeHeaders_new(void) {
+ MimeHeaders* hdrs = (MimeHeaders*)PR_MALLOC(sizeof(MimeHeaders));
+ if (!hdrs) return 0;
+
+ memset(hdrs, 0, sizeof(*hdrs));
+ hdrs->done_p = false;
+
+ return hdrs;
+}
+
+void MimeHeaders_free(MimeHeaders* hdrs) {
+ if (!hdrs) return;
+ PR_FREEIF(hdrs->all_headers);
+ PR_FREEIF(hdrs->heads);
+ PR_FREEIF(hdrs->obuffer);
+ PR_FREEIF(hdrs->munged_subject);
+ hdrs->obuffer_fp = 0;
+ hdrs->obuffer_size = 0;
+
+#ifdef DEBUG__
+ {
+ int i, size = sizeof(*hdrs);
+ uint32_t* array = (uint32_t*)hdrs;
+ for (i = 0; i < (size / sizeof(*array)); i++)
+ array[i] = (uint32_t)0xDEADBEEF;
+ }
+#endif /* DEBUG */
+
+ PR_Free(hdrs);
+}
+
+int MimeHeaders_parse_line(const char* buffer, int32_t size,
+ MimeHeaders* hdrs) {
+ int status = 0;
+ int desired_size;
+
+ NS_ASSERTION(hdrs, "1.22 <rhp@netscape.com> 22 Aug 1999 08:48");
+ if (!hdrs) return -1;
+
+ /* Don't try and feed me more data after having fed me a blank line... */
+ NS_ASSERTION(!hdrs->done_p, "1.22 <rhp@netscape.com> 22 Aug 1999 08:48");
+ if (hdrs->done_p) return -1;
+
+ if (!buffer || size == 0 || *buffer == '\r' || *buffer == '\n') {
+ /* If this is a blank line, we're done.
+ */
+ hdrs->done_p = true;
+ return MimeHeaders_build_heads_list(hdrs);
+ }
+
+ /* Tack this data on to the end of our copy.
+ */
+ desired_size = hdrs->all_headers_fp + size + 1;
+ if (desired_size >= hdrs->all_headers_size) {
+ status = mime_GrowBuffer(desired_size, sizeof(char), 255,
+ &hdrs->all_headers, &hdrs->all_headers_size);
+ if (status < 0) return status;
+ }
+ memcpy(hdrs->all_headers + hdrs->all_headers_fp, buffer, size);
+ hdrs->all_headers_fp += size;
+
+ return 0;
+}
+
+MimeHeaders* MimeHeaders_copy(MimeHeaders* hdrs) {
+ MimeHeaders* hdrs2;
+ if (!hdrs) return 0;
+
+ hdrs2 = (MimeHeaders*)PR_MALLOC(sizeof(*hdrs));
+ if (!hdrs2) return 0;
+ memset(hdrs2, 0, sizeof(*hdrs2));
+
+ if (hdrs->all_headers) {
+ hdrs2->all_headers = (char*)PR_MALLOC(hdrs->all_headers_fp);
+ if (!hdrs2->all_headers) {
+ PR_Free(hdrs2);
+ return 0;
+ }
+ memcpy(hdrs2->all_headers, hdrs->all_headers, hdrs->all_headers_fp);
+
+ hdrs2->all_headers_fp = hdrs->all_headers_fp;
+ hdrs2->all_headers_size = hdrs->all_headers_fp;
+ }
+
+ hdrs2->done_p = hdrs->done_p;
+
+ if (hdrs->heads) {
+ int i;
+ hdrs2->heads = (char**)PR_MALLOC(hdrs->heads_size * sizeof(*hdrs->heads));
+ if (!hdrs2->heads) {
+ PR_FREEIF(hdrs2->all_headers);
+ PR_Free(hdrs2);
+ return 0;
+ }
+ hdrs2->heads_size = hdrs->heads_size;
+ for (i = 0; i < hdrs->heads_size; i++) {
+ hdrs2->heads[i] =
+ (hdrs2->all_headers + (hdrs->heads[i] - hdrs->all_headers));
+ }
+ }
+ return hdrs2;
+}
+
+static bool find_header_starts(MimeHeaders* hdrs, bool counting) {
+ const char* end = hdrs->all_headers + hdrs->all_headers_fp;
+ char* s = hdrs->all_headers;
+ int i = 0;
+
+ if (counting) {
+ // For the start pointer
+ hdrs->heads_size = 1;
+ } else {
+ hdrs->heads[i++] = hdrs->all_headers;
+ }
+
+ while (s < end) {
+ SEARCH_NEWLINE:
+ while (s < end && *s != '\r' && *s != '\n') s++;
+
+ if (s >= end) break;
+
+ /* If "\r\n " or "\r\n\t" is next, that doesn't terminate the header. */
+ else if (s + 2 < end && (s[0] == '\r' && s[1] == '\n') &&
+ (s[2] == ' ' || s[2] == '\t')) {
+ s += 3;
+ goto SEARCH_NEWLINE;
+ }
+ /* If "\r " or "\r\t" or "\n " or "\n\t" is next, that doesn't terminate
+ the header either. */
+ else if (s + 1 < end && (s[0] == '\r' || s[0] == '\n') &&
+ (s[1] == ' ' || s[1] == '\t')) {
+ s += 2;
+ goto SEARCH_NEWLINE;
+ }
+
+ /* At this point, `s' points before a header-terminating newline.
+ Move past that newline, and store that new position in `heads'.
+ */
+ if (*s == '\r') s++;
+
+ if (s >= end) break;
+
+ if (*s == '\n') s++;
+
+ if (s < end) {
+ if (counting) {
+ hdrs->heads_size++;
+ } else {
+ NS_ASSERTION(i < hdrs->heads_size,
+ "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
+ if (i >= hdrs->heads_size) return false;
+ hdrs->heads[i++] = s;
+ }
+ }
+ }
+ if (!counting) {
+ NS_ASSERTION(i == hdrs->heads_size, "unexpected");
+ }
+ return true;
+}
+
+int MimeHeaders_build_heads_list(MimeHeaders* hdrs) {
+ NS_ASSERTION(hdrs, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
+ if (!hdrs) return -1;
+
+ NS_ASSERTION(hdrs->done_p && !hdrs->heads,
+ "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
+ if (!hdrs->done_p || hdrs->heads) return -1;
+
+ if (hdrs->all_headers_fp == 0) {
+ /* Must not have been any headers (we got the blank line right away.) */
+ PR_FREEIF(hdrs->all_headers);
+ hdrs->all_headers_size = 0;
+ return 0;
+ }
+
+ /* At this point, we might as well realloc all_headers back down to the
+ minimum size it must be (it could be up to 1k bigger.) But don't
+ bother if we're only off by a tiny bit. */
+ NS_ASSERTION(hdrs->all_headers_fp <= hdrs->all_headers_size,
+ "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
+ if (hdrs->all_headers_fp + 60 <= hdrs->all_headers_size) {
+ char* ls = (char*)PR_Realloc(hdrs->all_headers, hdrs->all_headers_fp);
+ if (ls) /* can this ever fail? we're making it smaller... */
+ {
+ hdrs->all_headers = ls; /* in case it got relocated */
+ hdrs->all_headers_size = hdrs->all_headers_fp;
+ }
+ }
+
+ find_header_starts(hdrs, true);
+
+ /* Now allocate storage for the pointers to each of those headers.
+ */
+ hdrs->heads = (char**)PR_MALLOC((hdrs->heads_size) * sizeof(char*));
+ if (!hdrs->heads) return MIME_OUT_OF_MEMORY;
+ memset(hdrs->heads, 0, (hdrs->heads_size) * sizeof(char*));
+
+ /* Now make another pass through the headers, and this time, record the
+ starting position of each header.
+ */
+ if (!find_header_starts(hdrs, false)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+char* MimeHeaders_get(MimeHeaders* hdrs, const char* header_name, bool strip_p,
+ bool all_p) {
+ int i;
+ int name_length;
+ char* result = 0;
+
+ if (!hdrs) return 0;
+ NS_ASSERTION(header_name, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
+ if (!header_name) return 0;
+
+ /* Specifying strip_p and all_p at the same time doesn't make sense... */
+ NS_ASSERTION(!(strip_p && all_p), "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
+
+ /* 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) {
+ int status;
+ hdrs->done_p = true;
+ status = MimeHeaders_build_heads_list(hdrs);
+ if (status < 0) return 0;
+ }
+
+ if (!hdrs->heads) /* Must not have been any headers. */
+ {
+ NS_ASSERTION(hdrs->all_headers_fp == 0,
+ "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
+ return 0;
+ }
+
+ name_length = strlen(header_name);
+
+ 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;
+
+ NS_ASSERTION(head, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
+ if (!head) continue;
+ size_t headLen = end - head;
+
+ /* Quick hack to skip over BSD Mailbox delimiter. */
+ if (i == 0 && head[0] == 'F' && headLen >= 5 && !strncmp(head, "From ", 5))
+ continue;
+
+ /* Find the colon. */
+ for (colon = head; colon < end; colon++)
+ if (*colon == ':') break;
+
+ if (colon >= end) continue;
+
+ /* Back up over whitespace before the colon. */
+ ocolon = colon;
+ for (; colon > head && IS_SPACE(colon[-1]); colon--)
+ ;
+
+ /* If the strings aren't the same length, it doesn't match. */
+ if (name_length != colon - head) continue;
+
+ /* If the strings differ, it doesn't match. */
+ if (PL_strncasecmp(header_name, head, name_length)) continue;
+
+ /* Otherwise, we've got a match. */
+ {
+ char* contents = ocolon + 1;
+ char* s;
+
+ /* Skip over whitespace after colon. */
+ while (contents < end && IS_SPACE(contents[0])) {
+ /* Mac or Unix style line break, followed by space or tab. */
+ if (contents < (end - 1) &&
+ (contents[0] == '\r' || contents[0] == '\n') &&
+ (contents[1] == ' ' || contents[1] == '\t'))
+ contents += 2;
+ /* Windows style line break, followed by space or tab. */
+ else if (contents < (end - 2) && contents[0] == '\r' &&
+ contents[1] == '\n' &&
+ (contents[2] == ' ' || contents[2] == '\t'))
+ contents += 3;
+ /* Any space or tab. */
+ else if (contents[0] == ' ' || contents[0] == '\t')
+ contents++;
+ /* If we get here, it's because this character is a line break
+ followed by non-whitespace, or a line break followed by
+ another line break
+ */
+ else {
+ end = contents;
+ break;
+ }
+ }
+
+ /* If we're supposed to strip at the first token, pull `end' back to
+ the first whitespace or ';' after the first token.
+ */
+ if (strip_p) {
+ for (s = contents; s < end && *s != ';' && *s != ',' && !IS_SPACE(*s);
+ s++)
+ ;
+ end = s;
+ }
+
+ /* Now allocate some storage.
+ If `result' already has a value, enlarge it.
+ Otherwise, just allocate a block.
+ `s' gets set to the place where the new data goes.
+ */
+ if (!result) {
+ result = (char*)PR_MALLOC(end - contents + 1);
+ if (!result) return 0;
+ s = result;
+ } else {
+ int32_t L = strlen(result);
+ s = (char*)PR_Realloc(result, (L + (end - contents + 10)));
+ if (!s) {
+ PR_Free(result);
+ return 0;
+ }
+ result = s;
+ s = result + L;
+
+ /* Since we are tacking more data onto the end of the header
+ field, we must make it be a well-formed continuation line,
+ by separating the old and new data with CR-LF-TAB.
+ */
+ *s++ = ','; /* #### only do this for addr headers? */
+ *s++ = MSG_LINEBREAK[0];
+#if (MSG_LINEBREAK_LEN == 2)
+ *s++ = MSG_LINEBREAK[1];
+#endif
+ *s++ = '\t';
+ }
+
+ /* Take off trailing whitespace... */
+ while (end > contents && IS_SPACE(end[-1])) end--;
+
+ if (end > contents) {
+ /* Now copy the header's contents in...
+ */
+ memcpy(s, contents, end - contents);
+ s[end - contents] = 0;
+ } else {
+ s[0] = 0;
+ }
+
+ /* If we only wanted the first occurrence of this header, we're done. */
+ if (!all_p) break;
+ }
+ }
+
+ if (result && !*result) /* empty string */
+ {
+ PR_Free(result);
+ return 0;
+ }
+
+ return result;
+}
+
+char* MimeHeaders_get_parameter(const char* header_value, const char* parm_name,
+ char** charset, char** language) {
+ if (!header_value || !parm_name || !*header_value || !*parm_name)
+ return nullptr;
+
+ nsresult rv;
+ nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
+ do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
+
+ if (NS_FAILED(rv)) return nullptr;
+
+ nsCString result;
+ rv = mimehdrpar->GetParameterInternal(nsDependentCString(header_value),
+ parm_name, charset, language,
+ getter_Copies(result));
+ return NS_SUCCEEDED(rv) ? PL_strdup(result.get()) : nullptr;
+}
+
+#define MimeHeaders_write(HDRS, OPT, DATA, LENGTH) \
+ MimeOptions_write((HDRS), (OPT), (DATA), (LENGTH), true);
+
+#define MimeHeaders_grow_obuffer(hdrs, desired_size) \
+ ((((long)(desired_size)) >= ((long)(hdrs)->obuffer_size)) \
+ ? mime_GrowBuffer((desired_size), sizeof(char), 255, &(hdrs)->obuffer, \
+ &(hdrs)->obuffer_size) \
+ : 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 <rhp@netscape.com> 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;
+ size_t headLen = end - head;
+
+ /* Hack for BSD Mailbox delimiter. */
+ if (i == 0 && head[0] == 'F' && headLen >= 5 &&
+ !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--;
+
+ nsAutoCString name(Substring(head, colon));
+ nsAutoCString hdr_value;
+
+ if ((end - contents) > 0) {
+ hdr_value = Substring(contents, end);
+ }
+
+ // MW Fixme: more?
+ bool convert_charset_only = name.LowerCaseEqualsLiteral("to") ||
+ name.LowerCaseEqualsLiteral("from") ||
+ name.LowerCaseEqualsLiteral("cc") ||
+ name.LowerCaseEqualsLiteral("bcc") ||
+ name.LowerCaseEqualsLiteral("reply-to") ||
+ name.LowerCaseEqualsLiteral("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) {
+ nsAutoCString convertedStr;
+ if (NS_SUCCEEDED(nsMsgI18NConvertFromUnicode(
+ nsDependentCString(charset), NS_ConvertUTF8toUTF16(hdr_value),
+ convertedStr))) {
+ hdr_value = convertedStr;
+ }
+ }
+
+ if (attachment) {
+ if (NS_FAILED(
+ mimeEmitterAddAttachmentField(opt, name.get(), hdr_value.get())))
+ status = -1;
+ } else {
+ if (NS_FAILED(
+ mimeEmitterAddHeaderField(opt, name.get(), hdr_value.get())))
+ status = -1;
+ }
+
+ 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;
+}
+
+/* Strip CR+LF runs within (original).
+ Since the string at (original) can only shrink,
+ this conversion is done in place. (original)
+ is returned. */
+extern "C" char* MIME_StripContinuations(char* original) {
+ char *p1, *p2;
+
+ /* If we were given a null string, return it as is */
+ if (!original) return NULL;
+
+ /* Start source and dest pointers at the beginning */
+ p1 = p2 = original;
+
+ while (*p2) {
+ /* p2 runs ahead at (CR and/or LF) */
+ if ((p2[0] == '\r') || (p2[0] == '\n'))
+ p2++;
+ else if (p2 > p1)
+ *p1++ = *p2++;
+ else {
+ p1++;
+ p2++;
+ }
+ }
+ *p1 = '\0';
+
+ return original;
+}
+
+extern int16_t INTL_DefaultMailToWinCharSetID(int16_t csid);
+
+/* Given text purporting to be a qtext header value, strip backslashes that
+ may be escaping other chars in the string. */
+char* mime_decode_filename(const char* name, const char* charset,
+ MimeDisplayOptions* opt) {
+ nsresult rv;
+ nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
+ do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
+
+ if (NS_FAILED(rv)) return nullptr;
+ nsAutoCString result;
+ rv = mimehdrpar->DecodeParameter(nsDependentCString(name), charset,
+ opt ? opt->default_charset : nullptr,
+ opt ? opt->override_charset : false, result);
+ return NS_SUCCEEDED(rv) ? PL_strdup(result.get()) : nullptr;
+}
+
+/* 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) {
+ 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);
+
+ free(charset);
+
+ if (cvt && cvt != name) {
+ PR_Free(name);
+ name = cvt;
+ }
+ }
+
+ return name;
+}
+
+#ifdef XP_UNIX
+/* This piece of junk is so that I can use BBDB with Mozilla.
+ = Put bbdb-srv.perl on your path.
+ = Put bbdb-srv.el on your lisp path.
+ = Make sure gnudoit (comes with xemacs) is on your path.
+ = Put (gnuserv-start) in ~/.emacs
+ = setenv NS_MSG_DISPLAY_HOOK bbdb-srv.perl
+ */
+void MimeHeaders_do_unix_display_hook_hack(MimeHeaders* hdrs) {
+ static const char* cmd = 0;
+ if (!cmd) {
+ /* The first time we're invoked, look up the command in the
+ environment. Use "" as the `no command' tag. */
+ cmd = getenv("NS_MSG_DISPLAY_HOOK");
+ if (!cmd) cmd = "";
+ }
+
+ /* Invoke "cmd" at the end of a pipe, and give it the headers on stdin.
+ The command is expected to be safe from hostile input!!
+ */
+ if (cmd && *cmd) {
+ FILE* fp = popen(cmd, "w");
+ if (fp) {
+ mozilla::Unused << fwrite(hdrs->all_headers, 1, hdrs->all_headers_fp, fp);
+ pclose(fp);
+ }
+ }
+}
+#endif /* XP_UNIX */
+
+static void MimeHeaders_compact(MimeHeaders* hdrs) {
+ NS_ASSERTION(hdrs, "1.22 <rhp@netscape.com> 22 Aug 1999 08:48");
+ if (!hdrs) return;
+
+ PR_FREEIF(hdrs->obuffer);
+ hdrs->obuffer_fp = 0;
+ hdrs->obuffer_size = 0;
+
+ /* These really shouldn't have gotten out of whack again. */
+ NS_ASSERTION(hdrs->all_headers_fp <= hdrs->all_headers_size &&
+ hdrs->all_headers_fp + 100 > hdrs->all_headers_size,
+ "1.22 <rhp@netscape.com> 22 Aug 1999 08:48");
+}
+
+/* Writes the headers as text/plain.
+ This writes out a blank line after the headers, unless
+ dont_write_content_type is true, in which case the header-block
+ is not closed off, and none of the Content- headers are written.
+ */
+int MimeHeaders_write_raw_headers(MimeHeaders* hdrs, MimeDisplayOptions* opt,
+ bool dont_write_content_type) {
+ int status;
+
+ if (hdrs && !hdrs->done_p) {
+ hdrs->done_p = true;
+ status = MimeHeaders_build_heads_list(hdrs);
+ if (status < 0) return 0;
+ }
+
+ if (!dont_write_content_type) {
+ char nl[] = MSG_LINEBREAK;
+ if (hdrs) {
+ status =
+ MimeHeaders_write(hdrs, opt, hdrs->all_headers, hdrs->all_headers_fp);
+ if (status < 0) return status;
+ }
+ status = MimeHeaders_write(hdrs, opt, nl, strlen(nl));
+ if (status < 0) return status;
+ } else if (hdrs) {
+ int32_t i;
+ for (i = 0; i < hdrs->heads_size; i++) {
+ char* head = hdrs->heads[i];
+ char* end =
+ (i == hdrs->heads_size - 1 ? hdrs->all_headers + hdrs->all_headers_fp
+ : hdrs->heads[i + 1]);
+
+ NS_ASSERTION(head, "1.22 <rhp@netscape.com> 22 Aug 1999 08:48");
+ if (!head) continue;
+
+ /* Don't write out any Content- header. */
+ if (!PL_strncasecmp(head, "Content-", 8)) continue;
+
+ /* Write out this (possibly multi-line) header. */
+ status = MimeHeaders_write(hdrs, opt, head, end - head);
+ if (status < 0) return status;
+ }
+ }
+
+ if (hdrs) MimeHeaders_compact(hdrs);
+
+ return 0;
+}
+
+// XXX Fix this XXX //
+char* MimeHeaders_open_crypto_stamp(void) { return nullptr; }
+
+char* MimeHeaders_finish_open_crypto_stamp(void) { return nullptr; }
+
+char* MimeHeaders_close_crypto_stamp(void) { return nullptr; }
+
+char* MimeHeaders_make_crypto_stamp(bool encrypted_p, bool signed_p,
+ bool good_p, bool unverified_p,
+ bool close_parent_stamp_p,
+ const char* stamp_url) {
+ return nullptr;
+}