Bug 998191, part 2: Make nsIMsgCompFields support msgIWritableStructuredHeaders, r=Neil
authorJoshua Cranmer <Pidgeot18@gmail.com>
Wed, 07 Jan 2015 15:57:33 -0600
changeset 21597 67519bbca9702cfaa7f699b56c1f350673eebb14
parent 21596 feaf7e10ead5c4ae21c126dd660212f5cb838a01
child 21598 3b8fcc27ab8ac3b1c8711b08b98ccf38a6c7b089
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)
reviewersNeil
bugs998191
Bug 998191, part 2: Make nsIMsgCompFields support msgIWritableStructuredHeaders, r=Neil Note that, as of this patch, most headers are not emitted in the final MIME message.
mail/test/mozmill/composition/test-send-button.js
mailnews/compose/public/nsIMsgCompFields.idl
mailnews/compose/src/nsMsgCompFields.cpp
mailnews/compose/src/nsMsgCompFields.h
mailnews/compose/src/nsMsgCompose.cpp
mailnews/compose/src/nsMsgSend.cpp
mailnews/compose/test/unit/test_expandMailingLists.js
mailnews/compose/test/unit/test_nsIMsgCompFields.js
mailnews/compose/test/unit/test_nsMsgCompose1.js
mailnews/compose/test/unit/xpcshell.ini
mailnews/mime/src/mimeJSComponents.js
mailnews/mime/src/mimedrft.cpp
--- a/mail/test/mozmill/composition/test-send-button.js
+++ b/mail/test/mozmill/composition/test-send-button.js
@@ -61,18 +61,18 @@ function check_send_commands_state(aCwc,
  * Test that the Send buttons are properly enabled if an addressee is input
  * by the user.
  */
 function test_send_enabled_manual_address() {
   let cwc = open_compose_new_mail(); // compose controller
   // On an empty window, Send must be disabled.
   check_send_commands_state(cwc, false);
 
-  // On any (even invalid) "To:" addressee input, Send must be enabled.
-  setupComposeWin(cwc, "recipient", "", "");
+  // On valid "To:" addressee input, Send must be enabled.
+  setupComposeWin(cwc, "recipient@fake.invalid", "", "");
   check_send_commands_state(cwc, true);
 
   // When the addressee is not in To, Cc, Bcc or Newsgroup, disable Send again.
   let addrType = cwc.e("addressCol1#1");
   cwc.click_menus_in_sequence(addrType.menupopup, [ {value: "addr_reply"} ]);
   check_send_commands_state(cwc, false);
 
   close_compose_window(cwc);
--- a/mailnews/compose/public/nsIMsgCompFields.idl
+++ b/mailnews/compose/public/nsIMsgCompFields.idl
@@ -1,19 +1,23 @@
 /* -*- 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 "nsISupports.idl"
-#include "nsIMsgAttachment.idl"
-#include "nsISimpleEnumerator.idl"
+#include "msgIStructuredHeaders.idl"
+
+interface nsIMsgAttachment;
+interface nsISimpleEnumerator;
 
-[scriptable, uuid(4f803e7a-5bd5-4344-9901-7a9ee89be780)]
-interface nsIMsgCompFields : nsISupports {
+/**
+ * A collection of headers and other attributes for building a mail message.
+ */
+[scriptable, uuid(4508e23e-a059-4a7e-bec9-4c6bc90e1847)]
+interface nsIMsgCompFields : msgIWritableStructuredHeaders {
 
   attribute AString from;
   attribute AString replyTo;
   attribute AString to;
   attribute AString cc;
   attribute AString bcc;
   readonly attribute bool hasRecipients;
 
@@ -71,19 +75,16 @@ interface nsIMsgCompFields : nsISupports
    * @param aResult           An array of the recipients.
    */
   void splitRecipients(in AString aRecipients, in boolean aEmailAddressOnly,
                        out unsigned long aLength,
                        [array, size_is(aLength), retval] out wstring aResult);
 
   void ConvertBodyToPlainText();
 
-  // Check if the composing mail headers can be converted to a mail charset.
-  boolean checkCharsetConversion(out string fallbackCharset);
-
   /**
    * Indicates whether we need to check if the current |DocumentCharset|
    * can represent all the characters in the message body. It should be
    * initialized to true and set to false when 'Send Anyway' is selected
    * by a user. (bug 249530)
    */
   attribute boolean needToCheckCharset;
 
--- a/mailnews/compose/src/nsMsgCompFields.cpp
+++ b/mailnews/compose/src/nsMsgCompFields.cpp
@@ -4,29 +4,68 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsMsgCompFields.h"
 #include "nsMsgI18N.h"
 #include "nsMsgCompUtils.h"
 #include "nsMsgUtils.h"
 #include "prmem.h"
 #include "nsIFileChannel.h"
+#include "nsIMsgAttachment.h"
 #include "nsIMsgMdnGenerator.h"
 #include "nsServiceManagerUtils.h"
 #include "nsMsgMimeCID.h"
 #include "nsArrayEnumerator.h"
 #include "nsMemory.h"
+#include "mozilla/ArrayUtils.h"
 #include "mozilla/mailnews/MimeHeaderParser.h"
 
 using namespace mozilla::mailnews;
 
-/* the following macro actually implement addref, release and query interface for our component. */
-NS_IMPL_ISUPPORTS(nsMsgCompFields, nsIMsgCompFields)
+struct HeaderInfo {
+  /// Header name
+  const char *mName;
+  /// If true, nsMsgCompFields should reflect the raw header value instead of
+  /// the unstructured header value.
+  bool mStructured;
+};
 
+// This is a mapping of the m_headers local set to the actual header name we
+// store on the structured header object.
+static HeaderInfo kHeaders[] = {
+  { "From", true },
+  { "Reply-To", true },
+  { "To", true },
+  { "Cc", true },
+  { "Bcc", true },
+  { nullptr, false },
+  { nullptr, false },
+  { "Newsgroups", true },
+  { "Followup-To", true },
+  { "Subject", false },
+  { "Organization", false },
+  { "References", true },
+  { nullptr, false },
+  { "X-Mozilla-News-Host", false },
+  { "X-Priority", false },
+  { nullptr, false },
+  { "Message-Id", true },
+  { "X-Template", true },
+  { nullptr, false }
+};
+
+static_assert(MOZ_ARRAY_LENGTH(kHeaders) ==
+    nsMsgCompFields::MSG_MAX_HEADERS,
+  "These two arrays need to be kept in sync or bad things will happen!");
+
+NS_IMPL_ISUPPORTS(nsMsgCompFields, nsIMsgCompFields, msgIStructuredHeaders,
+  msgIWritableStructuredHeaders)
+ 
 nsMsgCompFields::nsMsgCompFields()
+: mStructuredHeaders(do_CreateInstance(NS_ISTRUCTUREDHEADERS_CONTRACTID))
 {
   m_body.Truncate();
 
   m_attachVCard = false;
   m_forcePlainText = false;
   m_useMultipartAlternative = false;
   m_returnReceipt = false;
   m_receiptHeaderType = nsIMsgMdnGenerator::eDntType;
@@ -49,25 +88,57 @@ nsMsgCompFields::~nsMsgCompFields()
 {
 }
 
 nsresult nsMsgCompFields::SetAsciiHeader(MsgHeaderID header, const char *value)
 {
   NS_ASSERTION(header >= 0 && header < MSG_MAX_HEADERS,
                "Invalid message header index!");
 
+  // If we are storing this on the structured header object, we need to set the
+  // value on that object as well. Note that the value may be null, which we'll
+  // take as an attempt to delete the header.
+  const char *headerName = kHeaders[header].mName;
+  if (headerName)
+  {
+    if (!value || !*value)
+      return mStructuredHeaders->DeleteHeader(headerName);
+
+    return mStructuredHeaders->SetRawHeader(headerName,
+      nsDependentCString(value), "UTF-8");
+  }
+
+  // Not on the structurd header object, so save it locally.
   m_headers[header] = value;
+
   return NS_OK;
 }
 
 const char* nsMsgCompFields::GetAsciiHeader(MsgHeaderID header)
 {
   NS_ASSERTION(header >= 0 && header < MSG_MAX_HEADERS,
                "Invalid message header index!");
 
+  const char *headerName = kHeaders[header].mName;
+  if (headerName)
+  {
+    // We may be out of sync with the structured header object. Retrieve the
+    // header value.
+    if (kHeaders[header].mStructured)
+    {
+      mStructuredHeaders->GetRawHeader(headerName, m_headers[header]);
+    }
+    else
+    {
+      nsString value;
+      mStructuredHeaders->GetUnstructuredHeader(headerName, value);
+      CopyUTF16toUTF8(value, m_headers[header]);
+    }
+  }
+
   return m_headers[header].get();
 }
 
 nsresult nsMsgCompFields::SetUnicodeHeader(MsgHeaderID header, const nsAString& value)
 {
   return SetAsciiHeader(header, NS_ConvertUTF16toUTF8(value).get());
 }
 
@@ -490,17 +561,17 @@ nsMsgCompFields::SplitRecipients(const n
   *aResult = nullptr;
 
   nsCOMArray<msgIAddressObject> header(EncodedHeader(NS_ConvertUTF16toUTF8(aRecipients)));
   nsTArray<nsString> results;
   if (aEmailAddressOnly)
     ExtractEmails(header, results);
   else
     ExtractDisplayAddresses(header, results);
-  
+
   uint32_t count = results.Length();
   char16_t **result = (char16_t **)NS_Alloc(sizeof(char16_t *) * count);
   for (uint32_t i = 0; i < count; ++i)
     result[i] = ToNewUnicode(results[i]);
 
   *aResult = result;
   *aLength = count;
   return NS_OK;
@@ -561,31 +632,16 @@ NS_IMETHODIMP nsMsgCompFields::SetSecuri
 
 NS_IMETHODIMP nsMsgCompFields::GetDefaultCharacterSet(char * *aDefaultCharacterSet)
 {
   NS_ENSURE_ARG_POINTER(aDefaultCharacterSet);
   *aDefaultCharacterSet = ToNewCString(m_DefaultCharacterSet);
   return *aDefaultCharacterSet ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
-NS_IMETHODIMP nsMsgCompFields::CheckCharsetConversion(char **fallbackCharset, bool *_retval)
-{
-  NS_ENSURE_ARG_POINTER(_retval);
-
-  nsAutoCString headers;
-  for (int16_t i = 0; i < MSG_MAX_HEADERS; i++)
-    headers.Append(m_headers[i]);
-
-  // charset conversion check
-  *_retval = nsMsgI18Ncheck_data_in_charset_range(GetCharacterSet(), NS_ConvertUTF8toUTF16(headers.get()).get(),
-                                                  fallbackCharset);
-
-  return NS_OK;
-}
-
 NS_IMETHODIMP nsMsgCompFields::GetNeedToCheckCharset(bool *_retval)
 {
   NS_ENSURE_ARG_POINTER(_retval);
   *_retval = m_needToCheckCharset;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsMsgCompFields::SetNeedToCheckCharset(bool aCheck)
--- a/mailnews/compose/src/nsMsgCompFields.h
+++ b/mailnews/compose/src/nsMsgCompFields.h
@@ -28,16 +28,18 @@ struct nsMsgRecipient
    to NULL.  This makes it real handy for the callers. */
 
 class nsMsgCompFields : public nsIMsgCompFields {
 public:
   nsMsgCompFields();
 
   /* this macro defines QueryInterface, AddRef and Release for this class */
   NS_DECL_THREADSAFE_ISUPPORTS
+  NS_FORWARD_MSGISTRUCTUREDHEADERS(mStructuredHeaders->)
+  NS_FORWARD_MSGIWRITABLESTRUCTUREDHEADERS(mStructuredHeaders->)
   NS_DECL_NSIMSGCOMPFIELDS
 
   typedef enum MsgHeaderID
   {
     MSG_FROM_HEADER_ID        = 0,
     MSG_REPLY_TO_HEADER_ID,
     MSG_TO_HEADER_ID,
     MSG_CC_HEADER_ID,
@@ -151,12 +153,13 @@ protected:
   bool        m_DSN;
   bool        m_bodyIsAsciiOnly;
   bool        m_forceMsgEncoding;
   int32_t     m_receiptHeaderType;        /* receipt header type */
   nsCString   m_DefaultCharacterSet;
   bool        m_needToCheckCharset;
 
   nsCOMPtr<nsISupports> mSecureCompFields;
+  nsCOMPtr<msgIWritableStructuredHeaders> mStructuredHeaders;
 };
 
 
 #endif /* _MsgCompFields_H_ */
--- a/mailnews/compose/src/nsMsgCompose.cpp
+++ b/mailnews/compose/src/nsMsgCompose.cpp
@@ -58,16 +58,17 @@
 #include "nsUnicharUtils.h"
 #include "nsNetUtil.h"
 #include "nsIContentViewer.h"
 #include "nsIMsgMdnGenerator.h"
 #include "plbase64.h"
 #include "nsUConvCID.h"
 #include "nsIUnicodeNormalizer.h"
 #include "nsIMsgAccountManager.h"
+#include "nsIMsgAttachment.h"
 #include "nsIMsgProgress.h"
 #include "nsMsgFolderFlags.h"
 #include "nsIMsgDatabase.h"
 #include "nsStringStream.h"
 #include "nsIMutableArray.h"
 #include "nsArrayUtils.h"
 #include "nsIMsgWindow.h"
 #include "nsITextToSubURI.h"
@@ -5371,44 +5372,22 @@ nsMsgCompose::SetIdentity(nsIMsgIdentity
   return rv;
 }
 
 NS_IMETHODIMP nsMsgCompose::CheckCharsetConversion(nsIMsgIdentity *identity, char **fallbackCharset, bool *_retval)
 {
   NS_ENSURE_ARG_POINTER(identity);
   NS_ENSURE_ARG_POINTER(_retval);
 
-  nsresult rv = m_compFields->CheckCharsetConversion(fallbackCharset, _retval);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (*_retval)
-  {
-    nsString fullName;
-    nsString organization;
-    nsAutoString identityStrings;
-
-    rv = identity->GetFullName(fullName);
-    NS_ENSURE_SUCCESS(rv, rv);
-    if (!fullName.IsEmpty())
-      identityStrings.Append(fullName);
-
-    rv = identity->GetOrganization(organization);
-    NS_ENSURE_SUCCESS(rv, rv);
-    if (!organization.IsEmpty())
-      identityStrings.Append(organization);
-
-    if (!identityStrings.IsEmpty())
-    {
-      // use fallback charset if that's already set
-      const char *charset = (fallbackCharset && *fallbackCharset) ? *fallbackCharset : m_compFields->GetCharacterSet();
-      *_retval = nsMsgI18Ncheck_data_in_charset_range(charset, identityStrings.get(),
-                                                      fallbackCharset);
-    }
-  }
-
+  // Kept around for legacy reasons. This method is supposed to check that the
+  // headers can be converted to the appropriate charset, but we don't support
+  // encoding headers to non-UTF-8, so this is now moot.
+  if (fallbackCharset)
+    *fallbackCharset = nullptr;
+  *_retval = true;
   return NS_OK;
 }
 
 nsMsgMailList::nsMsgMailList(nsIAbDirectory* directory) :
   mDirectory(directory)
 {
   mDirectory->GetDirName(mName);
   mDirectory->GetDescription(mDescription);
--- a/mailnews/compose/src/nsMsgSend.cpp
+++ b/mailnews/compose/src/nsMsgSend.cpp
@@ -59,16 +59,17 @@
 #include "nsMsgUtils.h"
 #include "nsIMsgMdnGenerator.h"
 #include "nsISmtpServer.h"
 #include "nsIRDFService.h"
 #include "nsRDFCID.h"
 #include "nsIMsgAccountManager.h"
 #include "nsNativeCharsetUtils.h"
 #include "nsIAbCard.h"
+#include "nsIMsgAttachment.h"
 #include "nsIMsgProgress.h"
 #include "nsIMsgMessageService.h"
 #include "nsIMsgHdr.h"
 #include "nsIMsgFolder.h"
 #include "nsComposeStrings.h"
 #include "nsStringGlue.h"
 #include "nsMsgUtils.h"
 #include "nsIArray.h"
--- a/mailnews/compose/test/unit/test_expandMailingLists.js
+++ b/mailnews/compose/test/unit/test_expandMailingLists.js
@@ -49,20 +49,20 @@ function run_test() {
   // Copy the file to the profile directory for a PAB
   testAB.copyTo(do_get_profile(), kPABData.fileName);
 
   // XXX Getting all directories ensures we create all ABs because mailing
   // lists need help initialising themselves
   MailServices.ab.directories;
 
   // Test expansion of list with no description.
-  checkPopulate("simpson <simpson>", "Simpson <homer@example.com>,Marge <marge@example.com>,Bart <bart@foobar.invalid>,\"lisa@example.com\" <lisa@example.com>");
+  checkPopulate("simpson <simpson>", "Simpson <homer@example.com>, Marge <marge@example.com>, Bart <bart@foobar.invalid>, \"lisa@example.com\" <lisa@example.com>");
 
   // Test expansion fo list with description.
-  checkPopulate("marge <marges own list>", "Simpson <homer@example.com>,Marge <marge@example.com>");
+  checkPopulate("marge <marges own list>", "Simpson <homer@example.com>, Marge <marge@example.com>");
 
   // Test we don't mistake an email address for a list, with a few variations.
   checkPopulate("Simpson <homer@example.com>", "Simpson <homer@example.com>");
   checkPopulate("simpson <homer@example.com>", "simpson <homer@example.com>");
   checkPopulate("simpson <homer@not-in-ab.invalid>", "simpson <homer@not-in-ab.invalid>");
 
   checkPopulate("Marge <marge@example.com>", "Marge <marge@example.com>");
   checkPopulate("marge <marge@example.com>", "marge <marge@example.com>");
new file mode 100644
--- /dev/null
+++ b/mailnews/compose/test/unit/test_nsIMsgCompFields.js
@@ -0,0 +1,61 @@
+/* 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/. */
+
+/// Test that nsIMsgCompFields works properly
+
+let Ci = Components.interfaces;
+
+let nsMsgCompFields = Components.Constructor(
+  "@mozilla.org/messengercompose/composefields;1",
+  Ci.nsIMsgCompFields);
+
+function check_headers(enumerator, container) {
+  let checkValues = new Set([for (header of container) header.toLowerCase()]);
+  while (enumerator.hasMore()) {
+    let value = enumerator.getNext().toLowerCase();
+    do_check_true(checkValues.has(value));
+    checkValues.delete(value);
+  }
+  do_check_eq(checkValues.size, 0);
+}
+
+function run_test() {
+  let fields = new nsMsgCompFields;
+  do_check_true(fields instanceof Ci.nsIMsgCompFields);
+  do_check_true(fields instanceof Ci.msgIStructuredHeaders);
+  do_check_true(fields instanceof Ci.msgIWritableStructuredHeaders);
+  check_headers(fields.headerNames, []);
+  do_check_false(fields.hasRecipients);
+
+  // Try some basic headers
+  fields.setHeader("From", [{name: "", email: "a@test.invalid"}]);
+  let from = fields.getHeader("from");
+  do_check_eq(from.length, 1);
+  do_check_eq(from[0].email, "a@test.invalid");
+  check_headers(fields.headerNames, ["From"]);
+  do_check_false(fields.hasRecipients);
+
+  // Add a To header
+  fields.setHeader("To", [{name: "", email: "b@test.invalid"}]);
+  check_headers(fields.headerNames, ["From", "To"]);
+  do_check_true(fields.hasRecipients);
+
+  // Delete a header...
+  fields.deleteHeader("from");
+  do_check_eq(fields.getHeader("From"), undefined);
+  check_headers(fields.headerNames, ["To"]);
+
+  // Subject should work and not convert to RFC 2047.
+  fields.subject = "\u79c1\u306f\u4ef6\u540d\u5348\u524d";
+  do_check_eq(fields.subject, "\u79c1\u306f\u4ef6\u540d\u5348\u524d");
+  do_check_eq(fields.getHeader("Subject"),
+    "\u79c1\u306f\u4ef6\u540d\u5348\u524d");
+
+  // Check header synchronization.
+  fields.from = "a@test.invalid";
+  do_check_eq(fields.from, "a@test.invalid");
+  do_check_eq(fields.getHeader("From")[0].email, "a@test.invalid");
+  fields.from = null;
+  do_check_eq(fields.getHeader("From"), undefined);
+}
--- a/mailnews/compose/test/unit/test_nsMsgCompose1.js
+++ b/mailnews/compose/test/unit/test_nsMsgCompose1.js
@@ -33,17 +33,23 @@ function checkPopulate(aTo, aCheckTo)
   var params = Components.classes[MsgComposeParamsContractID]
                          .createInstance(nsIMsgComposeParams);
 
   params.composeFields = fields;
 
   msgCompose.initialize(params);
 
   msgCompose.expandMailingLists();
-  do_check_eq(fields.to, aCheckTo);
+  let addresses = fields.getHeader("To");
+  let checkEmails = MailServices.headerParser.parseDecodedHeader(aCheckTo);
+  do_check_eq(addresses.length, checkEmails.length);
+  for (let i = 0; i < addresses.length; i++) {
+    do_check_eq(addresses[i].name, checkEmails[i].name);
+    do_check_eq(addresses[i].email, checkEmails[i].email);
+  }
 }
 
 function run_test() {
   // Test setup - copy the data files into place
   var testAB = do_get_file("../../../data/abLists1.mab");
 
   // Copy the file to the profile directory for a PAB
   testAB.copyTo(do_get_profile(), kPABData.fileName);
--- a/mailnews/compose/test/unit/xpcshell.ini
+++ b/mailnews/compose/test/unit/xpcshell.ini
@@ -7,16 +7,17 @@ support-files = data/*
 [test_attachment_intl.js]
 [test_bug155172.js]
 [test_bug235432.js]
 [test_bug474774.js]
 [test_detectAttachmentCharset.js]
 [test_expandMailingLists.js]
 [test_mailtoURL.js]
 [test_messageHeaders.js]
+[test_nsIMsgCompFields.js]
 [test_nsMsgCompose1.js]
 [test_nsMsgCompose2.js]
 [test_nsMsgCompose3.js]
 [test_nsMsgCompose4.js]
 [test_nsSmtpService1.js]
 [test_saveDraft.js]
 [test_sendBackground.js]
 [test_sendMailAddressIDN.js]
--- a/mailnews/mime/src/mimeJSComponents.js
+++ b/mailnews/mime/src/mimeJSComponents.js
@@ -417,17 +417,17 @@ MimeConverter.prototype = {
     let emitter = new jsmime.headeremitter.makeStreamingEmitter(handler,
       options);
 
     // Add the text to the be encoded.
     emitter.addHeaderName(fakeHeader);
     if (aStructured) {
       // Structured really means "this is an addressing header"
       let addresses = MimeParser.parseHeaderField(aHeader,
-        MimeParser.HEADER_ADDRESS);
+        MimeParser.HEADER_ADDRESS | MimeParser.HEADER_OPTION_DECODE_2047);
       // This happens in one of our tests if there is a "bare" email but no
       // @ sign. Without it, the result disappears since our emission code
       // assumes that an empty email is not worth emitting.
       if (addresses.length === 1 && addresses[0].email === "" &&
           addresses[0].name !== "") {
         addresses[0].email = addresses[0].name;
         addresses[0].name = "";
       }
--- a/mailnews/mime/src/mimedrft.cpp
+++ b/mailnews/mime/src/mimedrft.cpp
@@ -28,16 +28,17 @@
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "msgCore.h"
 #include "nsIMsgSend.h"
 #include "nsMimeStringResources.h"
 #include "nsIIOService.h"
 #include "nsNetUtil.h"
 #include "comi18n.h"
+#include "nsIMsgAttachment.h"
 #include "nsIMsgCompFields.h"
 #include "nsMsgCompCID.h"
 #include "nsIMsgComposeService.h"
 #include "nsMsgAttachmentData.h"
 #include "nsMsgI18N.h"
 #include "nsNativeCharsetUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIMsgMessageService.h"