summaryrefslogtreecommitdiff
path: root/mailnews/mime/src/mimehdrs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/mime/src/mimehdrs.cpp')
-rw-r--r--mailnews/mime/src/mimehdrs.cpp888
1 files changed, 888 insertions, 0 deletions
diff --git a/mailnews/mime/src/mimehdrs.cpp b/mailnews/mime/src/mimehdrs.cpp
new file mode 100644
index 0000000000..6d187ed529
--- /dev/null
+++ b/mailnews/mime/src/mimehdrs.cpp
@@ -0,0 +1,888 @@
+/* -*- Mode: C; tab-width: 4; 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 "nsIMimeEmitter.h"
+#include "nsMsgMessageFlags.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"
+
+// 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;
+ ConvertRawBytesToUTF8(value, opt->default_charset, 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;
+}
+
+int
+MimeHeaders_build_heads_list(MimeHeaders *hdrs)
+{
+ char *s;
+ char *end;
+ int i;
+ 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;
+ }
+ }
+
+ /* First go through and count up the number of headers in the block.
+ */
+ end = hdrs->all_headers + hdrs->all_headers_fp;
+ for (s = hdrs->all_headers; s < end; s++)
+ {
+ if (s < (end-1) && s[0] == '\r' && s[1] == '\n') /* CRLF -> LF */
+ s++;
+
+ if ((s[0] == '\r' || s[0] == '\n') && /* we're at a newline, and */
+ (s >= (end-1) || /* we're at EOF, or */
+ !(s[1] == ' ' || s[1] == '\t'))) /* next char is nonwhite */
+ hdrs->heads_size++;
+ }
+
+ /* Now allocate storage for the pointers to each of those headers.
+ */
+ hdrs->heads = (char **) PR_MALLOC((hdrs->heads_size + 1) * sizeof(char *));
+ if (!hdrs->heads)
+ return MIME_OUT_OF_MEMORY;
+ memset(hdrs->heads, 0, (hdrs->heads_size + 1) * sizeof(char *));
+
+ /* Now make another pass through the headers, and this time, record the
+ starting position of each header.
+ */
+
+ i = 0;
+ hdrs->heads[i++] = hdrs->all_headers;
+ s = 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)
+ {
+ NS_ASSERTION(! (i > hdrs->heads_size), "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
+ if (i > hdrs->heads_size)
+ return -1;
+ hdrs->heads[i++] = s;
+ }
+ }
+
+ 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;
+
+ /* Quick hack to skip over BSD Mailbox delimiter. */
+ if (i == 0 && head[0] == 'F' && !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 occurence 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(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;
+
+ /* 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--;
+
+ nsAutoCString name(Substring(head, colon));
+ nsAutoCString 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)
+ {
+ nsAutoCString convertedStr;
+ if (NS_SUCCEEDED(ConvertFromUnicode(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)
+ {
+ 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;
+}