Bug 481667 - "Support BCC in message summary files" [r=Neil sr=bienvenu]
authorKent James <kent@caspia.com>
Mon, 16 Mar 2009 20:24:04 +0000
changeset 2227 74ee211f58c07d7c61a40c82e94a154a0926f614
parent 2226 ff6f8e4dcb736118ede92f52564594a826175271
child 2228 358ec16450f3b7c058276e06e448e80ebc800c16
push idunknown
push userunknown
push dateunknown
reviewersNeil, bienvenu
bugs481667
Bug 481667 - "Support BCC in message summary files" [r=Neil sr=bienvenu]
mailnews/base/public/nsIMsgHdr.idl
mailnews/base/test/unit/test_bccInDatabase.js
mailnews/db/msgdb/public/nsMsgDatabase.h
mailnews/db/msgdb/src/nsMsgDatabase.cpp
mailnews/db/msgdb/src/nsMsgHdr.cpp
mailnews/local/src/nsParseMailbox.cpp
mailnews/local/src/nsParseMailbox.h
mailnews/test/data/draft1
--- a/mailnews/base/public/nsIMsgHdr.idl
+++ b/mailnews/base/public/nsIMsgHdr.idl
@@ -42,17 +42,17 @@
 %}
 
 #include "MailNewsTypes2.idl"
 
 [ptr] native octetPtr(PRUint8);
 
 interface nsIMsgFolder;
 
-[scriptable, uuid(211b9eef-5f48-4135-aebb-0ac4e7738159)]
+[scriptable, uuid(EA75203B-2218-4e96-9979-567DFFBEACC2)]
 interface nsIMsgDBHdr : nsISupports
 {
     /* general property routines - I think this can retrieve any
        header in the db */
     AString getProperty(in string propertyName);
     void setProperty(in string propertyName, in AString propertyStr);
     void setStringProperty(in string propertyName, in string propertyValue);
     string getStringProperty(in string propertyName);
@@ -91,29 +91,32 @@ interface nsIMsgDBHdr : nsISupports
     attribute unsigned long statusOffset;
     attribute unsigned long messageOffset;
     attribute unsigned long offlineMessageSize;
     /* common headers */
     attribute PRTime date;
     readonly attribute unsigned long dateInSeconds;
     attribute string messageId;
     attribute string ccList;
+    attribute string bccList;
     attribute string author;
     attribute string subject;
     attribute string recipients;
     
     /* anything below here still has to be fixed */
     void setReferences(in string references);
     readonly attribute unsigned short numReferences;
     ACString getStringReference(in long refNum);
 
     void setRecipientsArray(in string names, in string addresses,
                             in unsigned long numAddresses);
     void setCCListArray(in string names, in string addresses,
                         in unsigned long numAddresses);
+    void setBCCListArray(in string names, in string addresses,
+                         in unsigned long numAddresses);
 
     readonly attribute AString mime2DecodedAuthor;
     readonly attribute AString mime2DecodedSubject;
     readonly attribute AString mime2DecodedRecipients;
 
     [noscript] void getAuthorCollationKey(out octetPtr key, out unsigned long len);
     [noscript] void getSubjectCollationKey(out octetPtr key, out unsigned long len);
     [noscript] void getRecipientsCollationKey(out octetPtr key, out unsigned long len);
new file mode 100644
--- /dev/null
+++ b/mailnews/base/test/unit/test_bccInDatabase.js
@@ -0,0 +1,76 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Kent James <kent@caspia.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Testing of bcc in message summary file added in bug 481667
+ */
+
+const copyService = Cc["@mozilla.org/messenger/messagecopyservice;1"]
+                      .getService(Ci.nsIMsgCopyService);
+
+var hdr;
+
+function run_test()
+{
+  loadLocalMailAccount();
+
+  var copyListener = 
+  {
+    OnStartCopy: function() {},
+    OnProgress: function(aProgress, aProgressMax) {},
+    SetMessageKey: function(aKey) { hdr = gLocalInboxFolder.GetMessageHeader(aKey);},
+    SetMessageId: function(aMessageId) {},
+    OnStopCopy: function(aStatus) { continueTest();}
+  };
+
+  // Get a message into the local filestore.
+  var draft = do_get_file("../mailnews/test/data/draft1");
+  do_test_pending();
+  copyService.CopyFileMessage(draft, gLocalInboxFolder, null, false, 0,
+                              "", copyListener, null);
+}
+
+function continueTest()
+{
+  //dump("\nbccList >" + hdr.bccList);
+  //dump("\nccList >" + hdr.ccList);
+  //dump("\n");
+  do_check_true(hdr.bccList.indexOf("Another Person") >= 0);
+  do_check_true(hdr.bccList.indexOf("<u1@example.com>") >= 0);
+  do_check_false(hdr.bccList.indexOf("IDoNotExist") >=0);
+  do_test_finished();
+}
+
--- a/mailnews/db/msgdb/public/nsMsgDatabase.h
+++ b/mailnews/db/msgdb/public/nsMsgDatabase.h
@@ -262,16 +262,17 @@ protected:
   mdb_token     m_dateColumnToken;
   mdb_token     m_messageSizeColumnToken;
   mdb_token     m_flagsColumnToken;
   mdb_token     m_priorityColumnToken;
   mdb_token     m_labelColumnToken;
   mdb_token     m_statusOffsetColumnToken;
   mdb_token     m_numLinesColumnToken;
   mdb_token     m_ccListColumnToken;
+  mdb_token     m_bccListColumnToken;
   mdb_token     m_threadFlagsColumnToken;
   mdb_token     m_threadIdColumnToken;
   mdb_token     m_threadChildrenColumnToken;
   mdb_token     m_threadUnreadChildrenColumnToken;
   mdb_token     m_messageThreadIdColumnToken;
   mdb_token     m_threadSubjectColumnToken;
   mdb_token     m_messageCharSetColumnToken;
   mdb_token     m_threadParentColumnToken;
--- a/mailnews/db/msgdb/src/nsMsgDatabase.cpp
+++ b/mailnews/db/msgdb/src/nsMsgDatabase.cpp
@@ -850,16 +850,17 @@ nsMsgDatabase::nsMsgDatabase()
         m_dateColumnToken(0),
         m_messageSizeColumnToken(0),
         m_flagsColumnToken(0),
         m_priorityColumnToken(0),
         m_labelColumnToken(0),
         m_statusOffsetColumnToken(0),
         m_numLinesColumnToken(0),
         m_ccListColumnToken(0),
+        m_bccListColumnToken(0),
         m_threadFlagsColumnToken(0),
         m_threadIdColumnToken(0),
         m_threadChildrenColumnToken(0),
         m_threadUnreadChildrenColumnToken(0),
         m_messageThreadIdColumnToken(0),
         m_threadSubjectColumnToken(0),
         m_messageCharSetColumnToken(0),
         m_threadParentColumnToken(0),
@@ -1359,16 +1360,17 @@ const char *kRecipientsColumnName = "rec
 const char *kDateColumnName = "date";
 const char *kMessageSizeColumnName = "size";
 const char *kFlagsColumnName = "flags";
 const char *kPriorityColumnName = "priority";
 const char *kLabelColumnName = "label";
 const char *kStatusOffsetColumnName = "statusOfset";
 const char *kNumLinesColumnName = "numLines";
 const char *kCCListColumnName = "ccList";
+const char *kBCCListColumnName = "bccList";
 const char *kMessageThreadIdColumnName = "msgThreadId";
 const char *kThreadFlagsColumnName = "threadFlags";
 const char *kThreadIdColumnName = "threadId";
 const char *kThreadChildrenColumnName = "children";
 const char *kThreadUnreadChildrenColumnName = "unreadChildren";
 const char *kThreadSubjectColumnName = "threadSubject";
 const char *kMessageCharSetColumnName = "msgCharSet";
 const char *kThreadParentColumnName = "threadParent";
@@ -1560,16 +1562,17 @@ nsresult nsMsgDatabase::InitMDBInfo()
       GetStore()->StringToToken(GetEnv(),  kDateColumnName, &m_dateColumnToken);
       GetStore()->StringToToken(GetEnv(),  kMessageSizeColumnName, &m_messageSizeColumnToken);
       GetStore()->StringToToken(GetEnv(),  kFlagsColumnName, &m_flagsColumnToken);
       GetStore()->StringToToken(GetEnv(),  kPriorityColumnName, &m_priorityColumnToken);
       GetStore()->StringToToken(GetEnv(),  kLabelColumnName, &m_labelColumnToken);
       GetStore()->StringToToken(GetEnv(),  kStatusOffsetColumnName, &m_statusOffsetColumnToken);
       GetStore()->StringToToken(GetEnv(),  kNumLinesColumnName, &m_numLinesColumnToken);
       GetStore()->StringToToken(GetEnv(),  kCCListColumnName, &m_ccListColumnToken);
+      GetStore()->StringToToken(GetEnv(),  kBCCListColumnName, &m_bccListColumnToken);
       GetStore()->StringToToken(GetEnv(),  kMessageThreadIdColumnName, &m_messageThreadIdColumnToken);
       GetStore()->StringToToken(GetEnv(),  kThreadIdColumnName, &m_threadIdColumnToken);
       GetStore()->StringToToken(GetEnv(),  kThreadFlagsColumnName, &m_threadFlagsColumnToken);
       GetStore()->StringToToken(GetEnv(),  kThreadNewestMsgDateColumnName, &m_threadNewestMsgDateColumnToken);
       GetStore()->StringToToken(GetEnv(),  kThreadChildrenColumnName, &m_threadChildrenColumnToken);
       GetStore()->StringToToken(GetEnv(),  kThreadUnreadChildrenColumnName, &m_threadUnreadChildrenColumnToken);
       GetStore()->StringToToken(GetEnv(),  kThreadSubjectColumnName, &m_threadSubjectColumnToken);
       GetStore()->StringToToken(GetEnv(),  kMessageCharSetColumnName, &m_messageCharSetColumnToken);
--- a/mailnews/db/msgdb/src/nsMsgHdr.cpp
+++ b/mailnews/db/msgdb/src/nsMsgHdr.cpp
@@ -494,16 +494,34 @@ NS_IMETHODIMP nsMsgHdr::SetCCListArray(c
     ret = BuildRecipientsFromArray(names, addresses, numAddresses, allRecipients);
     if (NS_FAILED(ret))
         return ret;
 
 	ret = SetCcList(allRecipients.get());
 	return ret;
 }
 
+NS_IMETHODIMP nsMsgHdr::SetBccList(const char *bccList)
+{
+  return SetStringColumn(bccList, m_mdb->m_bccListColumnToken);
+}
+
+NS_IMETHODIMP
+nsMsgHdr::SetBCCListArray(const char *names,
+                          const char *addresses,
+                          PRUint32 numAddresses)
+{
+  nsCAutoString allRecipients;
+
+  nsresult rv = BuildRecipientsFromArray(names, addresses, numAddresses,
+                                         allRecipients);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return SetBccList(allRecipients.get());
+}
 
 NS_IMETHODIMP nsMsgHdr::SetMessageSize(PRUint32 messageSize)
 {
   SetUInt32Column(messageSize, m_mdb->m_messageSizeColumnToken);
   m_messageSize = messageSize;
   return NS_OK;
 }
 
@@ -669,16 +687,21 @@ NS_IMETHODIMP nsMsgHdr::GetRecipients(ch
   return m_mdb->RowCellColumnToCharPtr(GetMDBRow(), m_mdb->m_recipientsColumnToken, resultRecipients);
 }
 
 NS_IMETHODIMP nsMsgHdr::GetCcList(char * *resultCCList)
 {
   return m_mdb->RowCellColumnToCharPtr(GetMDBRow(), m_mdb->m_ccListColumnToken, resultCCList);
 }
 
+NS_IMETHODIMP nsMsgHdr::GetBccList(char * *resultBCCList)
+{
+  return m_mdb->RowCellColumnToCharPtr(GetMDBRow(), m_mdb->m_bccListColumnToken, resultBCCList);
+}
+
 NS_IMETHODIMP nsMsgHdr::GetMessageId(char * *resultMessageId)
 {
   return m_mdb->RowCellColumnToCharPtr(GetMDBRow(), m_mdb->m_messageIdColumnToken, resultMessageId);
 }
 
 NS_IMETHODIMP nsMsgHdr::GetMime2DecodedAuthor(nsAString &resultAuthor)
 {
   return m_mdb->RowCellColumnToMime2DecodedString(GetMDBRow(), m_mdb->m_senderColumnToken, resultAuthor);
--- a/mailnews/local/src/nsParseMailbox.cpp
+++ b/mailnews/local/src/nsParseMailbox.cpp
@@ -595,16 +595,17 @@ NS_IMETHODIMP nsParseMailMessageState::C
   m_keywords.length = 0;
   m_mdn_dnt.length = 0;
   m_return_path.length = 0;
   m_account_key.length = 0;
   m_in_reply_to.length = 0;
   m_replyTo.length = 0;
   m_content_type.length = 0;
   m_mdn_original_recipient.length = 0;
+  m_bccList.length = 0;
   m_body_lines = 0;
   m_newMsgHdr = nsnull;
   m_envelope_pos = 0;
   ClearAggregateHeader (m_toList);
   ClearAggregateHeader (m_ccList);
   m_headers.ResetWritePos();
   m_envelope.ResetWritePos();
   m_receivedTime = LL_ZERO;
@@ -950,16 +951,20 @@ int nsParseMailMessageState::ParseHeader
       break;
 
     end = colon;
     while (end > buf && (*end == ' ' || *end == '\t'))
       end--;
 
     switch (buf [0])
     {
+    case 'B': case 'b':
+      if (!PL_strncasecmp ("BCC", buf, end - buf))
+        header = &m_bccList;
+      break;
     case 'C': case 'c':
       if (!PL_strncasecmp ("CC", buf, end - buf))
         header = GetNextHeaderInAggregate(m_ccList);
       else if (!PL_strncasecmp ("Content-Type", buf, end - buf))
         header = &m_content_type;
       break;
     case 'D': case 'd':
       if (!PL_strncasecmp ("Date", buf, end - buf))
@@ -1244,16 +1249,17 @@ int nsParseMailMessageState::FinalizeHea
   struct message_header *deliveryDate;
   struct message_header *statush;
   struct message_header *mozstatus;
   struct message_header *mozstatus2;
   struct message_header *priority;
   struct message_header *keywords;
   struct message_header *account_key;
   struct message_header *ccList;
+  struct message_header *bccList;
   struct message_header *mdn_dnt;
   struct message_header md5_header;
   struct message_header *content_type;
   char md5_data [50];
 
   const char *s;
   PRUint32 flags = 0;
   PRUint32 delta = 0;
@@ -1262,26 +1268,29 @@ int nsParseMailMessageState::FinalizeHea
 
   if (!m_mailDB)    // if we don't have a valid db, skip the header.
     return 0;
 
   struct message_header to;
   GetAggregateHeader (m_toList, &to);
   struct message_header cc;
   GetAggregateHeader (m_ccList, &cc);
+  // we don't aggregate bcc, as we only generate it locally,
+  // and we don't use multiple lines
 
   sender     = (m_from.length          ? &m_from :
   m_sender.length        ? &m_sender :
   m_envelope_from.length ? &m_envelope_from :
   0);
   recipient  = (to.length         ? &to :
   cc.length         ? &cc :
   m_newsgroups.length ? &m_newsgroups :
   sender);
   ccList     = (cc.length ? &cc : 0);
+  bccList    = (m_bccList.length    ? &m_bccList    : 0);
   subject    = (m_subject.length    ? &m_subject    : 0);
   id         = (m_message_id.length ? &m_message_id : 0);
   references = (m_references.length ? &m_references : 0);
   statush    = (m_status.length     ? &m_status     : 0);
   mozstatus  = (m_mozstatus.length  ? &m_mozstatus  : 0);
   mozstatus2 = (m_mozstatus2.length  ? &m_mozstatus2  : 0);
   date       = (m_date.length       ? &m_date :
   m_envelope_date.length ? &m_envelope_date :
@@ -1450,16 +1459,36 @@ int nsParseMailMessageState::FinalizeHea
         {
           m_newMsgHdr->SetCCListArray(names, addresses, numAddresses);
           PR_Free(addresses);
           PR_Free(names);
         }
         else  // hmm, should we just use the original string?
           m_newMsgHdr->SetCcList(ccList->value);
       }
+
+      if (bccList)
+      {
+        PRUint32 numAddresses;
+        char  *names;
+        char  *addresses;
+
+        ret = m_HeaderAddressParser->ParseHeaderAddresses(bccList->value,
+                                                          &names, &addresses,
+                                                          &numAddresses);
+        if (NS_SUCCEEDED(ret))
+        {
+          m_newMsgHdr->SetBCCListArray(names, addresses, numAddresses);
+          PR_Free(addresses);
+          PR_Free(names);
+        }
+        else  // hmm, should we just use the original string?
+          m_newMsgHdr->SetBccList(bccList->value);
+      }
+
       status = InternSubject (subject);
       if (status >= 0)
       {
         if (! id)
         {
           // what to do about this? we used to do a hash of all the headers...
           nsCAutoString hash;
           const char *md5_b64 = "dummy.message.id";
--- a/mailnews/local/src/nsParseMailbox.h
+++ b/mailnews/local/src/nsParseMailbox.h
@@ -123,16 +123,17 @@ public:
   struct message_header m_newsgroups;
   struct message_header m_subject;
   struct message_header m_status;
   struct message_header m_mozstatus;
   struct message_header m_mozstatus2;
   struct message_header m_in_reply_to;
   struct message_header m_replyTo;
   struct message_header m_content_type;
+  struct message_header m_bccList;
 
   // Support for having multiple To or Cc header lines in a message
   nsVoidArray m_toList;
   nsVoidArray m_ccList;
   struct message_header *GetNextHeaderInAggregate (nsVoidArray &list);
   void GetAggregateHeader (nsVoidArray &list, struct message_header *);
   void ClearAggregateHeader (nsVoidArray &list);
 
--- a/mailnews/test/data/draft1
+++ b/mailnews/test/data/draft1
@@ -1,13 +1,14 @@
 From - Sat Jun 07 04:23:42 2008
 X-Mozilla-Status: 0000
 X-Mozilla-Status2: 00000000
 X-Mozilla-Keys:                                                                                 
 FCC: mailbox://nobody@Local%20Folders/Sent
+BCC: Some User <u1@example.com>, Another Person <u2@example.com>
 X-Identity-Key: id2
 Message-ID: <4849BF7B.2030800@example.com>
 Date: Sat, 07 Jun 2008 04:23:42 +0530
 From: Some User <example@example.com>
 X-Mozilla-Draft-Info: internal/draft; vcard=0; receipt=0; DSN=0; uuencode=0
 User-Agent: Thunderbird 3.0a2pre (Windows/2008060416)
 MIME-Version: 1.0
 To: bugmail@example.org