Bug 998191, part 4: Add a method to convert structured headers to MIME-encoded text, r=irving, sr=Neil
authorJoshua Cranmer <Pidgeot18@gmail.com>
Wed, 07 Jan 2015 15:57:48 -0600
changeset 21599 45ccfc058277e081883f440f1b0aa22be05652b6
parent 21598 3b8fcc27ab8ac3b1c8711b08b98ccf38a6c7b089
child 21600 a913648f41152f36acc2fd3bd061f060f85594e1
push id1305
push usermbanner@mozilla.com
push dateMon, 23 Feb 2015 19:48:12 +0000
treeherdercomm-beta@3ae4f13858fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersirving, Neil
bugs998191
Bug 998191, part 4: Add a method to convert structured headers to MIME-encoded text, r=irving, sr=Neil
mailnews/compose/public/nsIMsgCompFields.idl
mailnews/mime/public/msgIStructuredHeaders.idl
mailnews/mime/public/nsIMimeHeaders.idl
mailnews/mime/src/mimeJSComponents.js
mailnews/mime/test/unit/test_structured_headers.js
--- a/mailnews/compose/public/nsIMsgCompFields.idl
+++ b/mailnews/compose/public/nsIMsgCompFields.idl
@@ -6,17 +6,17 @@
 #include "msgIStructuredHeaders.idl"
 
 interface nsIMsgAttachment;
 interface nsISimpleEnumerator;
 
 /**
  * A collection of headers and other attributes for building a mail message.
  */
-[scriptable, uuid(4508e23e-a059-4a7e-bec9-4c6bc90e1847)]
+[scriptable, uuid(095fd3b3-41e1-448e-8f9a-534a5f8e5407)]
 interface nsIMsgCompFields : msgIWritableStructuredHeaders {
 
   attribute AString from;
   attribute AString replyTo;
   attribute AString to;
   attribute AString cc;
   attribute AString bcc;
   readonly attribute bool hasRecipients;
--- a/mailnews/mime/public/msgIStructuredHeaders.idl
+++ b/mailnews/mime/public/msgIStructuredHeaders.idl
@@ -30,17 +30,17 @@ interface nsIUTF8StringEnumerator;
  * since the To header is not an unstructured header but an addressing header.
  * They are provided mostly as a convenience to C++ which is much less able to
  * utilize a fully generic format.
  *
  * With the exception of mismatched headers, the methods do not throw an
  * exception if the header is missing but rather return an appropriate default
  * value as indicated in their documentation.
  */
-[scriptable, uuid(6c105b83-fb73-4282-bd00-05eaf0f4da1d)]
+[scriptable, uuid(e109bf4f-788f-47ba-bfa8-1236ede05597)]
 interface msgIStructuredHeaders : nsISupports {
   /**
    * Retrieve the value of the header stored in this set of headers. If the
    * header is not present, then undefined is returned.
    *
    * @param aHeaderName     The name of the header to retrieve.
    */
   jsval getHeader(in string aHeaderName);
@@ -92,16 +92,29 @@ interface msgIStructuredHeaders : nsISup
   /**
    * Retrieve an enumerator of the names of all headers in this set of headers.
    * The header names returned may be in different cases depending on the
    * precise implementation of this interface, so implementations should not
    * rely on an exact kind of case being returned.
    */
   readonly attribute nsIUTF8StringEnumerator headerNames;
 
+  /**
+   * Retrieve the MIME representation of all of the headers.
+   *
+   * The header values are emitted in an ASCII form, unless internationalized
+   * email addresses are involved. The extra CRLF indicating the end of headers
+   * is not included in this representation.
+   *
+   * This accessor is provided mainly for the benefit of C++ consumers of this
+   * interface, since the JSMime headeremitter functionality allows more
+   * fine-grained customization of the results.
+   */
+   AUTF8String buildMimeText();
+
 %{C++
   /**
    * A special variant of getAddressingHeader that is specialized better for C++
    * users of this API.
    */
   nsresult GetAddressingHeader(const char *aPropertyName,
                                nsCOMArray<msgIAddressObject> &addrs,
                                bool aPreserveGroups = false)
@@ -117,17 +130,17 @@ interface msgIStructuredHeaders : nsISup
 %}
 
 };
 
 /**
  * An interface that enhances msgIStructuredHeaders by allowing the values of
  * headers to be modified.
  */
-[scriptable, uuid(de109a13-47e5-4b69-8784-854b66a88da6)]
+[scriptable, uuid(5dcbbef6-2356-45d8-86d7-b3e73f9c9a0c)]
 interface msgIWritableStructuredHeaders : msgIStructuredHeaders {
   /**
    * Store the given value for the given header, overwriting any previous value
    * that was stored for said header.
    *
    * @param aHeaderName     The name of the header to store.
    * @param aValue          The rich, structured value of the header to store.
    */
--- a/mailnews/mime/public/nsIMimeHeaders.idl
+++ b/mailnews/mime/public/nsIMimeHeaders.idl
@@ -8,27 +8,34 @@
 %{C++
 #define NS_IMIMEHEADERS_CONTRACTID \
   "@mozilla.org/messenger/mimeheaders;1"
 %}
 
 /**
  * An interface that can extract individual headers from a body of headers.
  */
-[scriptable, uuid(8a570955-c641-4471-8cc1-1bc1bca65561)]
+[scriptable, uuid(a9222679-b991-4786-8314-f8819c3a2ba3)]
 interface nsIMimeHeaders : msgIStructuredHeaders {
   /// Feed in the text of headers
   void initialize(in ACString allHeaders);
 
   /**
    * Get the text of a header.
    *
    * Leading and trailing whitespace from headers will be stripped from the
    * return value. If getAllOfThem is set to true, then the returned string will
    * have all of the values of the header, in order, joined with the ',\r\n\t'.
    *
    * If the header is not present, then the returned value is NULL.
    */
   ACString extractHeader(in string headerName, in boolean getAllOfThem);
 
-  /// The current text of all header data.
+  /**
+   * The current text of all header data.
+   *
+   * Unlike the asMimeText property, this result preserves the original
+   * representation of the header text, including alternative line endings or
+   * custom, non-8-bit text. For instances of this interface, this attribute is
+   * usually preferable to asMimeText.
+   */
   readonly attribute ACString allHeaders;
 };
--- a/mailnews/mime/src/mimeJSComponents.js
+++ b/mailnews/mime/src/mimeJSComponents.js
@@ -83,17 +83,32 @@ MimeStructuredHeaders.prototype = {
     value = value.substring(aHeaderName.length + 2).trim();
     // ... as well as embedded newlines.
     value = value.replace(/\r\n/g, '');
     return value;
   },
 
   get headerNames() {
     return new StringEnumerator(this._headers.keys());
-  }
+  },
+
+  buildMimeText: function () {
+    if (this._headers.size == 0) {
+      return "";
+    }
+    let handler = new HeaderHandler();
+    let emitter = jsmime.headeremitter.makeStreamingEmitter(handler, {
+      useASCII: true
+    });
+    for (let [value, header] of this._headers) {
+      emitter.addStructuredHeader(value, header);
+    }
+    emitter.finish();
+    return handler.value;
+  },
 };
 
 
 function MimeHeaders() {
 }
 MimeHeaders.prototype = {
   __proto__: MimeStructuredHeaders.prototype,
   classDescription: "Mime headers implementation",
--- a/mailnews/mime/test/unit/test_structured_headers.js
+++ b/mailnews/mime/test/unit/test_structured_headers.js
@@ -157,11 +157,35 @@ add_task(function* check_nsIMimeHeaders(
     "Content-Type", "Content-Transfer-Encoding"];
   let enumerator = headers.headerNames;
   while (enumerator.hasMore()) {
     let value = enumerator.getNext();
     do_check_eq(value.toLowerCase(), headerList.shift().toLowerCase());
   }
 });
 
+add_task(function* checkBuildMimeText() {
+  let headers = new StructuredHeaders();
+  headers.setHeader("To", [{name: "François Smith", email: "user@☃.invalid"}]);
+  headers.setHeader("From", [{name: "John Doe", email: "jdoe@test.invalid"}]);
+  headers.setHeader("Subject", "A subject that spans a distance quite in " +
+    "excess of 80 characters so as to force an intermediary CRLF");
+  let mimeText =
+    "To: =?UTF-8?Q?Fran=c3=a7ois_Smith?= <user@☃.invalid>\r\n" +
+    "From: John Doe <jdoe@test.invalid>\r\n" +
+    "Subject: A subject that spans a distance quite in excess of 80 characters so\r\n" +
+    " as to force an intermediary CRLF\r\n";
+  do_check_eq(headers.buildMimeText(), mimeText);
+
+  // Check the version used for the nsIMimeHeaders implementation. This requires
+  // initializing with a UTF-8 version.
+  let utf8Text = mimeText.replace("☃", "\xe2\x98\x83");
+  let mimeHeaders = Cc["@mozilla.org/messenger/mimeheaders;1"]
+                      .createInstance(Ci.nsIMimeHeaders);
+  mimeHeaders.initialize(utf8Text);
+  do_check_eq(mimeHeaders.getHeader("To")[0].email, "user@☃.invalid");
+  do_check_eq(mimeHeaders.buildMimeText(), mimeText);
+  do_check_eq(mimeHeaders.allHeaders, utf8Text);
+});
+
 function run_test() {
   run_next_test();
 }