make backend base and db [noscript] methods scriptable, bug 661682, r=rkent, sr=standard8
authorDavid Bienvenu <bienvenu@nventure.com>
Fri, 24 Jun 2011 16:58:10 -0700
changeset 8228 8f6268c4dc0a33c1428dce9ba8a0abd448996499
parent 8227 c6ae532c6e61dc60545982e05005c13a3877b860
child 8229 8a841fad97059c903a75e300fd3b6c88ff3326ef
push id84
push userbugzilla@standard8.plus.com
push dateTue, 16 Aug 2011 21:25:04 +0000
treeherdercomm-beta@6970c86be3cd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrkent, standard8
bugs661682
make backend base and db [noscript] methods scriptable, bug 661682, r=rkent, sr=standard8
mailnews/base/public/Makefile.in
mailnews/base/public/nsIMsgHdr.idl
mailnews/base/public/nsIMsgKeyArray.idl
mailnews/base/public/nsIMsgMessageService.idl
mailnews/base/public/nsMsgBaseCID.h
mailnews/base/src/nsMsgDBView.cpp
mailnews/base/src/nsMsgFolderCompactor.cpp
mailnews/base/src/nsMsgFolderCompactor.h
mailnews/base/util/Makefile.in
mailnews/base/util/nsMsgDBFolder.cpp
mailnews/base/util/nsMsgDBFolder.h
mailnews/base/util/nsMsgKeyArray.cpp
mailnews/base/util/nsMsgKeyArray.h
mailnews/base/util/nsMsgReadStateTxn.cpp
mailnews/base/util/nsMsgReadStateTxn.h
mailnews/build/nsMailModule.cpp
mailnews/db/msgdb/public/nsIMsgDatabase.idl
mailnews/db/msgdb/public/nsMsgDatabase.h
mailnews/db/msgdb/public/nsNewsDatabase.h
mailnews/db/msgdb/src/nsMsgDatabase.cpp
mailnews/db/msgdb/src/nsMsgHdr.cpp
mailnews/db/msgdb/src/nsNewsDatabase.cpp
mailnews/imap/src/nsAutoSyncState.cpp
mailnews/imap/src/nsImapMailFolder.cpp
mailnews/imap/src/nsImapService.cpp
mailnews/local/src/nsLocalMailFolder.cpp
mailnews/local/src/nsMailboxService.cpp
mailnews/local/src/nsPop3IncomingServer.cpp
mailnews/mapi/mapihook/src/msgMapiImp.cpp
mailnews/news/src/nsNNTPArticleList.cpp
mailnews/news/src/nsNewsFolder.cpp
mailnews/news/src/nsNntpService.cpp
--- a/mailnews/base/public/Makefile.in
+++ b/mailnews/base/public/Makefile.in
@@ -62,16 +62,17 @@ XPIDLSRCS	= \
 		nsIMsgAccount.idl \
 		nsIMsgAccountManager.idl \
 		nsIMsgFolder.idl \
 		nsIMsgFolderCache.idl \
 		nsIMsgFolderCacheElement.idl \
 		nsIMsgFolderCompactor.idl \
 		nsIMsgIdentity.idl \
 		nsIMsgIncomingServer.idl \
+		nsIMsgKeyArray.idl \
 		nsIMsgMailSession.idl \
 		nsIMsgMessageService.idl \
 		nsIMsgTagService.idl \
 		nsIMsgThread.idl \
 		nsIUrlListener.idl \
 		nsIMsgBiffManager.idl \
 		nsIStatusBarBiffManager.idl \
 		nsIMsgPurgeService.idl \
--- a/mailnews/base/public/nsIMsgHdr.idl
+++ b/mailnews/base/public/nsIMsgHdr.idl
@@ -32,28 +32,22 @@
  * 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 ***** */
 
 #include "nsISupports.idl"
 
-%{C++
-#include "MailNewsTypes.h"
-%}
-
 #include "MailNewsTypes2.idl"
 
-[ptr] native octetPtr(PRUint8);
-
 interface nsIMsgFolder;
 interface nsIUTF8StringEnumerator;
 
-[scriptable, uuid(574611fe-f170-4eb4-a30c-a26e2c62703a)]
+[scriptable, uuid(36adf826-73f4-48e7-a444-318242ea8a8e)]
 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);
@@ -114,20 +108,23 @@ interface nsIMsgDBHdr : nsISupports
                         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);
-    
+    void getAuthorCollationKey(out unsigned long aCount,
+                              [array, size_is(aCount)] out octet aKey);
+    void getSubjectCollationKey(out unsigned long aCount,
+                                [array, size_is(aCount)] out octet aKey);
+    void getRecipientsCollationKey(out unsigned long aCount,
+                                  [array, size_is(aCount)] out octet aKey);
+
     attribute string Charset;
     attribute nsMsgLabelValue label;
     attribute string accountKey;
     readonly attribute nsIMsgFolder folder;
 
     /// Enumerator for names of all database properties in the header.
     readonly attribute nsIUTF8StringEnumerator propertyEnumerator;
 };
new file mode 100644
--- /dev/null
+++ b/mailnews/base/public/nsIMsgKeyArray.idl
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   David Bienvenu <bienvenu@mozilla.com>
+ *
+ * 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 ***** */
+
+
+/**
+ * This interface wraps an nsTArray<nsMsgKey> so that we can pass arrays
+ * back and forth between c++ and js (or via xpconnect generally).
+ */
+
+#include "nsISupports.idl"
+#include "MailNewsTypes2.idl"
+
+[scriptable, uuid(e8fcaada-64b7-4e39-9f1d-10ddb0f1de64)]
+interface nsIMsgKeyArray : nsISupports {
+  /**
+   * Get the key at the specified 0-based array index.
+   *
+   * @param aIndex 0-based index.
+   * @returns key at the specified index.
+   */
+  nsMsgKey getKeyAt(in long aIndex);
+
+  readonly attribute unsigned long length;
+
+  void setCapacity(in unsigned long aCapacity);
+  /**
+   * Adds a key to the end of the array
+   * @param key to append to the array.
+   */
+  void appendElement(in nsMsgKey aMsgKey);
+
+  /**
+   * Sort the array by key.
+   */
+  void sort();
+
+  /**
+   * Retrieves the entire array in such a way that xpconnect can easily
+   * create a js array of the keys.
+   *
+   * @returns array of the keys
+   */
+  void getArray(out unsigned long aCount,
+           [array, size_is(aCount)] out nsMsgKey aKeys);
+};
+
--- a/mailnews/base/public/nsIMsgMessageService.idl
+++ b/mailnews/base/public/nsIMsgMessageService.idl
@@ -31,37 +31,33 @@
  * 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 ***** */
 
 #include "nsISupports.idl"
-
+#include "MailNewsTypes2.idl"
 interface nsIURI;
 interface nsIUrlListener;
 interface nsIStreamListener;
 interface nsIMsgWindow;
 interface nsIFile;
 interface nsIMsgFolder;
 interface nsIMsgSearchSession;
 interface nsIMsgDBHdr;
 interface nsIStreamConverter;
 interface nsICacheEntryDescriptor;
 
 %{C++
 #include "MailNewsTypes.h"
-#include "nsTArray.h"
 %}
 
-[ref] native nsMsgKeyArrayRef(nsTArray<nsMsgKey>);
-
-
-[scriptable, uuid(5f173e8d-0046-4eec-b178-b850a7211654)]
+[scriptable, uuid(ac7b56c2-cf42-4ee3-a3b1-9ae64a90861c)]
 interface nsIMsgMessageService : nsISupports {
      
   /**
    * If you want a handle on the running task, pass in a valid nsIURI 
    * ptr. You can later interrupt this action by asking the netlib 
    * service manager to interrupt the url you are given back. 
    * Remember to release aURL when you are done with it. Pass nsnull
    * in for aURL if you don't care about the returned URL.
@@ -86,20 +82,25 @@ interface nsIMsgMessageService : nsISupp
    * Copy multiple messages at a time 
    *
    * @param keys
    * @param srcFolder
    * @param aCopyListener
    * @param aMoveMessage
    * @param aUrlListener
    * @param aMsgWindow
-   * @param aURL
+   * @returns URI that's run to perform the copy
    */
-  [noscript] void CopyMessages(in nsMsgKeyArrayRef keys, in nsIMsgFolder srcFolder, in nsIStreamListener aCopyListener, in boolean aMoveMessage,
-               in nsIUrlListener aUrlListener, in nsIMsgWindow aMsgWindow, out nsIURI aURL);
+  nsIURI CopyMessages(in unsigned long aNumKeys,
+                      [array, size_is (aNumKeys)] in nsMsgKey aKeys,
+                      in nsIMsgFolder srcFolder,
+                      in nsIStreamListener aCopyListener,
+                      in boolean aMoveMessage,
+                      in nsIUrlListener aUrlListener,
+                      in nsIMsgWindow aMsgWindow);
 
     
   /**
    * When you want a message displayed....
    *
    * @param aMessageURI Is a uri representing the message to display.
    * @param aDisplayConsumer Is (for now) an nsIDocShell which we'll use to load 
    *                         the message into.
--- a/mailnews/base/public/nsMsgBaseCID.h
+++ b/mailnews/base/public/nsMsgBaseCID.h
@@ -279,16 +279,27 @@
   "@mozilla.org/messenger/statusfeedback;1"
 
 /* B1AA0820-D04B-11d2-8069-006008128C4E */
 #define NS_MSGSTATUSFEEDBACK_CID \
 { 0xbd85a417, 0x5433, 0x11d3, \
   {0x8a, 0xc5, 0x0, 0x60, 0xb0, 0xfc, 0x4, 0xd2} }
 
 //
+// nsMsgKeyArray
+//
+#define NS_MSGKEYARRAY_CONTRACTID \
+  "@mozilla.org/messenger/msgkeyarray;1"
+
+/* 86989d1d-c8a1-4e8e-aae6-d0dabcacd8c2 */
+#define NS_MSGKEYARRAY_CID \
+{ 0x86989d1d, 0xc8a1, 0x4e8e, \
+  {0xaa, 0xe6, 0xd0, 0xda, 0xbc, 0xac, 0xd8, 0xc2 }}
+
+//
 //nsMsgWindow
 //
 #define NS_MSGWINDOW_CONTRACTID \
 	"@mozilla.org/messenger/msgwindow;1"
 
 /* BB460DFF-8BF0-11d3-8AFE-0060B0FC04D2*/
 #define NS_MSGWINDOW_CID \
 { 0xbb460dff, 0x8bf0, 0x11d3, \
--- a/mailnews/base/src/nsMsgDBView.cpp
+++ b/mailnews/base/src/nsMsgDBView.cpp
@@ -3760,17 +3760,18 @@ nsMsgDBView::FnSortIdKey(const void *pIt
     nsresult rv;
     viewSortInfo* sortInfo = (viewSortInfo *) privateData;
 
     IdKey** p1 = (IdKey**)pItem1;
     IdKey** p2 = (IdKey**)pItem2;
 
     nsIMsgDatabase *db = sortInfo->db;
 
-    rv = db->CompareCollationKeys((*p1)->key, (*p1)->dword, (*p2)->key, (*p2)->dword, &retVal);
+    rv = db->CompareCollationKeys((*p1)->dword, (*p1)->key, (*p2)->dword,
+                                  (*p2)->key, &retVal);
     NS_ASSERTION(NS_SUCCEEDED(rv),"compare failed");
 
     if (retVal)
       return sortInfo->ascendingSort ? retVal : -retVal;
     if (sortInfo->view->m_secondarySort == nsMsgViewSortType::byId)
       return (sortInfo->view->m_secondarySortOrder == nsMsgViewSortOrder::ascending &&
               (*p1)->id >= (*p2)->id) ? 1 : -1;
     else
@@ -3785,17 +3786,18 @@ nsMsgDBView::FnSortIdKeyPtr(const void *
   nsresult rv;
 
   IdKeyPtr** p1 = (IdKeyPtr**)pItem1;
   IdKeyPtr** p2 = (IdKeyPtr**)pItem2;
   viewSortInfo* sortInfo = (viewSortInfo *) privateData;
 
   nsIMsgDatabase *db = sortInfo->db;
 
-  rv = db->CompareCollationKeys((*p1)->key, (*p1)->dword, (*p2)->key, (*p2)->dword, &retVal);
+  rv = db->CompareCollationKeys((*p1)->dword, (*p1)->key, (*p2)->dword,
+                                (*p2)->key, &retVal);
   NS_ASSERTION(NS_SUCCEEDED(rv),"compare failed");
 
   if (retVal)
     return sortInfo->ascendingSort ? retVal : -retVal;
 
   if (sortInfo->view->m_secondarySort == nsMsgViewSortType::byId)
     return (sortInfo->view->m_secondarySortOrder == nsMsgViewSortOrder::ascending &&
             (*p1)->id >= (*p2)->id) ? 1 : -1;
@@ -4117,59 +4119,59 @@ nsMsgDBView::GetCollationKey(nsIMsgDBHdr
 {
   nsresult rv;
   NS_ENSURE_ARG_POINTER(msgHdr);
   NS_ENSURE_ARG_POINTER(result);
 
   switch (sortType)
   {
     case nsMsgViewSortType::bySubject:
-        rv = msgHdr->GetSubjectCollationKey(result, len);
+        rv = msgHdr->GetSubjectCollationKey(len, result);
         break;
     case nsMsgViewSortType::byLocation:
         rv = GetLocationCollationKey(msgHdr, result, len);
         break;
     case nsMsgViewSortType::byRecipient:
-        rv = msgHdr->GetRecipientsCollationKey(result, len);
+        rv = msgHdr->GetRecipientsCollationKey(len, result);
         break;
     case nsMsgViewSortType::byAuthor:
-        rv = msgHdr->GetAuthorCollationKey(result, len);
+        rv = msgHdr->GetAuthorCollationKey(len, result);
         break;
     case nsMsgViewSortType::byAccount:
     case nsMsgViewSortType::byTags:
       {
         nsString str;
         nsCOMPtr <nsIMsgDatabase> dbToUse = m_db;
 
         if (!dbToUse) // probably search view
           GetDBForViewIndex(0, getter_AddRefs(dbToUse));
 
         rv = (sortType == nsMsgViewSortType::byAccount)
             ? FetchAccount(msgHdr, str)
             : FetchTags(msgHdr, str);
 
         if (NS_SUCCEEDED(rv) && dbToUse)
-          rv = dbToUse->CreateCollationKey(str, result, len);
+          rv = dbToUse->CreateCollationKey(str, len, result);
       }
       break;
     case nsMsgViewSortType::byCustom:
       if (colHandler != nsnull)
       {
         nsAutoString strKey;
         rv = colHandler->GetSortStringForRow(msgHdr, strKey);
         NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get sort string for custom row");
         nsAutoString strTemp(strKey);
 
         nsCOMPtr <nsIMsgDatabase> dbToUse = m_db;
         if (!dbToUse) // probably search view
         {
           rv = GetDBForHeader(msgHdr, getter_AddRefs(dbToUse));
           NS_ENSURE_SUCCESS(rv,rv);
         }
-        rv = dbToUse->CreateCollationKey(strKey, result, len);
+        rv = dbToUse->CreateCollationKey(strKey, len, result);
       }
       else
       {
         NS_ASSERTION(PR_FALSE,"should not be here (Sort Type: byCustom (String), but no custom handler)");
         //rv = NS_ERROR_UNEXPECTED;
       }
       break;
     default:
@@ -4200,17 +4202,17 @@ nsMsgDBView::GetLocationCollationKey(nsI
   nsCOMPtr <nsIMsgDatabase> dbToUse;
   rv = folder->GetMsgDatabase(getter_AddRefs(dbToUse));
   NS_ENSURE_SUCCESS(rv,rv);
 
   nsString locationString;
   rv = folder->GetPrettiestName(locationString);
   NS_ENSURE_SUCCESS(rv,rv);
 
-  return dbToUse->CreateCollationKey(locationString, result, len);
+  return dbToUse->CreateCollationKey(locationString, len, result);
 }
 
 nsresult nsMsgDBView::SaveSortInfo(nsMsgViewSortTypeValue sortType, nsMsgViewSortOrderValue sortOrder)
 {
   if (m_viewFolder)
   {
     nsCOMPtr <nsIDBFolderInfo> folderInfo;
     nsCOMPtr <nsIMsgDatabase> db;
--- a/mailnews/base/src/nsMsgFolderCompactor.cpp
+++ b/mailnews/base/src/nsMsgFolderCompactor.cpp
@@ -33,41 +33,42 @@
  * 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 ***** */
 
 #include "msgCore.h"    // precompiled header...
 #include "nsCOMPtr.h"
 #include "nsIMsgFolder.h"
+#include "nsAutoPtr.h"
 #include "nsILocalFile.h"
 #include "nsNetUtil.h"
 #include "nsIMsgHdr.h"
 #include "nsIStreamListener.h"
 #include "nsIMsgMessageService.h"
 #include "nsMsgDBCID.h"
 #include "nsMsgUtils.h"
 #include "nsISeekableStream.h"
 #include "nsIDBFolderInfo.h"
 #include "nsIDocShell.h"
-#include "nsMsgFolderCompactor.h"
 #include "nsIPrompt.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIMsgLocalMailFolder.h"
 #include "nsIMsgImapMailFolder.h"
 #include "nsMailHeaders.h"
 #include "nsMsgI18N.h"
 #include "prprf.h"
 #include "nsMsgLocalFolderHdrs.h"
 #include "nsIMsgDatabase.h"
 #include "nsArrayUtils.h"
 #include "nsMsgMessageFlags.h"
 #include "nsIMsgStatusFeedback.h"
 #include "nsMsgBaseCID.h"
 #include "nsIMsgFolderNotificationService.h"
+#include "nsMsgFolderCompactor.h"
 
 //////////////////////////////////////////////////////////////////////////////
 // nsFolderCompactState
 //////////////////////////////////////////////////////////////////////////////
 
 NS_IMPL_ISUPPORTS5(nsFolderCompactState, nsIMsgFolderCompactor, nsIRequestObserver, nsIStreamListener, nsICopyMessageStreamListener, nsIUrlListener)
 
 nsFolderCompactState::nsFolderCompactState()
@@ -83,17 +84,16 @@ nsFolderCompactState::nsFolderCompactSta
   m_folderIndex = 0;
   m_startOfMsg = PR_TRUE;
   m_needStatusLine = PR_FALSE;
 }
 
 nsFolderCompactState::~nsFolderCompactState()
 {
   CloseOutputStream();
-
   if (NS_FAILED(m_status))
   {
     CleanupTempFilesAfterError();
     // if for some reason we failed remove the temp folder and database
   }
 }
 
 void nsFolderCompactState::CloseOutputStream()
@@ -125,19 +125,20 @@ nsresult nsFolderCompactState::BuildMess
   return NS_OK;
 }
 
 
 nsresult
 nsFolderCompactState::InitDB(nsIMsgDatabase *db)
 {
   nsCOMPtr<nsIMsgDatabase> mailDBFactory;
+  nsresult rv = db->ListAllKeys(m_keyArray);
+  NS_ENSURE_SUCCESS(rv, rv);
+  m_size = m_keyArray->m_keys.Length();
 
-  db->ListAllKeys(m_keyArray);
-  nsresult rv;
   nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID, &rv);
   if (msgDBService) 
   {
     nsresult folderOpen = msgDBService->OpenMailDBFromFile(m_file, PR_TRUE,
                                      PR_FALSE,
                                      getter_AddRefs(m_db));
 
     if(NS_FAILED(folderOpen) &&
@@ -297,28 +298,28 @@ nsFolderCompactState::Init(nsIMsgFolder 
   m_file->InitWithFile(path);
   // need to make sure the temp file goes in the same real directory
   // as the original file, so resolve sym links.
   m_file->SetFollowLinks(PR_TRUE);
 
   m_file->SetNativeLeafName(NS_LITERAL_CSTRING("nstmp"));
   m_file->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 00600);   //make sure we are not crunching existing nstmp file
   m_window = aMsgWindow;
-  m_keyArray.Clear();
+  m_keyArray = new nsMsgKeyArray;
+  m_size = 0;
   m_totalMsgSize = 0;
   rv = InitDB(db);
   if (NS_FAILED(rv))
   {
     CleanupTempFilesAfterError();
     return rv;
   }
 
-  m_size = m_keyArray.Length();
   m_curIndex = 0;
-  
+
   rv = MsgNewBufferedFileOutputStream(getter_AddRefs(m_fileStream), m_file, -1, 00600);
   if (NS_FAILED(rv)) 
     m_folder->ThrowAlertMsg("compactFolderWriteFailed", m_window);
   else
     rv = GetMessageServiceFromURI(nsDependentCString(baseMsgUri),
                                 getter_AddRefs(m_messageService));
   if (NS_FAILED(rv))
   {
@@ -375,22 +376,23 @@ nsresult nsFolderCompactState::StartComp
   nsCOMPtr<nsIMsgFolderNotificationService>
     notifier(do_GetService(NS_MSGNOTIFICATIONSERVICE_CONTRACTID));
   if (notifier)
     notifier->NotifyItemEvent(m_folder,
                               NS_LITERAL_CSTRING("FolderCompactStart"),
                               nsnull);
   if (m_size > 0)
   {
-
+    nsCOMPtr<nsIURI> notUsed;
     ShowCompactingStatusMsg();
     AddRef();
-    rv = m_messageService->CopyMessages(m_keyArray, m_folder, this, PR_FALSE, nsnull, m_window, nsnull);
-    // m_curIndex = m_size;  // advance m_curIndex to the end - we're done
-
+    rv = m_messageService->CopyMessages(m_size, m_keyArray->m_keys.Elements(),
+                                        m_folder, this,
+                                        PR_FALSE, nsnull, m_window,
+                                        getter_AddRefs(notUsed));
   }
   else
   { // no messages to copy with
     FinishCompact();
 //    Release(); // we don't "own" ourselves yet.
   }
   return rv;
 }
@@ -661,17 +663,17 @@ nsFolderCompactState::OnDataAvailable(ns
   PRUint32 statusOffset;
   nsCString msgHdrKeywords;
 
   if (m_startOfMsg)
   {
     m_statusOffset = 0;
     m_addedHeaderSize = 0;
     m_messageUri.Truncate(); // clear the previous message uri
-    if (NS_SUCCEEDED(BuildMessageURI(m_baseMessageUri.get(), m_keyArray[m_curIndex],
+    if (NS_SUCCEEDED(BuildMessageURI(m_baseMessageUri.get(), m_keyArray->m_keys[m_curIndex],
                                 m_messageUri)))
     {
       rv = GetMessage(getter_AddRefs(m_curSrcHdr));
       NS_ENSURE_SUCCESS(rv, rv);
       if (m_curSrcHdr)
       {
         (void) m_curSrcHdr->GetFlags(&msgFlags);
         (void) m_curSrcHdr->GetStatusOffset(&statusOffset);
@@ -882,52 +884,51 @@ nsOfflineStoreCompactState::~nsOfflineSt
 }
 
 
 nsresult
 nsOfflineStoreCompactState::InitDB(nsIMsgDatabase *db)
 {
   // Start with the list of messages we have offline as the possible
   // message to keep when compacting the offline store.
-  db->ListAllOfflineMsgs(&m_keyArray);
-  // Filter out msgs that have the "pendingRemoval" attribute set.
-  nsCOMPtr<nsIMsgDBHdr> hdr;
-  nsString pendingRemoval;
-  for (PRInt32 i = m_keyArray.Length() - 1; i >= 0; i--)
-  {
-    nsresult rv = db->GetMsgHdrForKey(m_keyArray[i], getter_AddRefs(hdr));
-    NS_ENSURE_SUCCESS(rv, rv);
-    hdr->GetProperty("pendingRemoval", pendingRemoval);
-    if (!pendingRemoval.IsEmpty())
-    {
-      m_keyArray.RemoveElementAt(i);
-      // Turn off offline flag for message, since after the compact is completed;
-      // we won't have the message in the offline store.
-      PRUint32 resultFlags;
-      hdr->AndFlags(~nsMsgMessageFlags::Offline, &resultFlags);
-      // We need to clear this in case the user changes the offline retention
-      // settings.
-      hdr->SetStringProperty("pendingRemoval", "");
-    }
-  }
+  db->ListAllOfflineMsgs(m_keyArray);
+  m_size = m_keyArray->m_keys.Length();
   m_db = db;
   return NS_OK;
 }
 
 /**
  * This will copy one message to the offline store, but if it fails to
  * copy the next message, it will keep trying messages until it finds one
  * it can copy, or it runs out of messages.
  */
 nsresult nsOfflineStoreCompactState::CopyNextMessage(PRBool &done)
 {
   while (m_curIndex < m_size)
   {
+    // Filter out msgs that have the "pendingRemoval" attribute set.
+    nsCOMPtr<nsIMsgDBHdr> hdr;
+    nsString pendingRemoval;
+    nsresult rv = m_db->GetMsgHdrForKey(m_keyArray->m_keys[m_curIndex], getter_AddRefs(hdr));
+    NS_ENSURE_SUCCESS(rv, rv);
+    hdr->GetProperty("pendingRemoval", pendingRemoval);
+    if (!pendingRemoval.IsEmpty())
+    {
+      m_curIndex++;
+      // Turn off offline flag for message, since after the compact is completed;
+      // we won't have the message in the offline store.
+      PRUint32 resultFlags;
+      hdr->AndFlags(~nsMsgMessageFlags::Offline, &resultFlags);
+      // We need to clear this in case the user changes the offline retention
+      // settings.
+      hdr->SetStringProperty("pendingRemoval", "");
+      continue;
+    }
     m_messageUri.Truncate(); // clear the previous message uri
-    nsresult rv = BuildMessageURI(m_baseMessageUri.get(), m_keyArray[m_curIndex],
+    rv = BuildMessageURI(m_baseMessageUri.get(), m_keyArray->m_keys[m_curIndex],
                                   m_messageUri);
     NS_ENSURE_SUCCESS(rv, rv);
     m_startOfMsg = PR_TRUE;
     nsCOMPtr<nsISupports> thisSupports;
     QueryInterface(NS_GET_IID(nsISupports), getter_AddRefs(thisSupports));
     rv = m_messageService->StreamMessage(m_messageUri.get(), thisSupports, m_window, nsnull,
                                     PR_FALSE, EmptyCString(), PR_TRUE, nsnull);
     // if copy fails, we clear the offline flag on the source message.
@@ -1178,17 +1179,17 @@ nsOfflineStoreCompactState::OnDataAvaila
 
   nsresult rv = NS_OK;
 
   if (m_startOfMsg)
   {
     m_statusOffset = 0;
     m_offlineMsgSize = 0;
     m_messageUri.Truncate(); // clear the previous message uri
-    if (NS_SUCCEEDED(BuildMessageURI(m_baseMessageUri.get(), m_keyArray[m_curIndex],
+    if (NS_SUCCEEDED(BuildMessageURI(m_baseMessageUri.get(), m_keyArray->m_keys[m_curIndex],
                                 m_messageUri)))
     {
       rv = GetMessage(getter_AddRefs(m_curSrcHdr));
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
   PRUint32 maxReadCount, readCount, writeCount;
   PRUint32 bytesWritten;
--- a/mailnews/base/src/nsMsgFolderCompactor.h
+++ b/mailnews/base/src/nsMsgFolderCompactor.h
@@ -38,16 +38,17 @@
 #ifndef _nsMsgFolderCompactor_h
 #define _nsMsgFolderCompactor_h
 
 #include "nsCOMPtr.h"
 #include "nsIMsgFolder.h"
 #include "nsIStreamListener.h"
 #include "nsIMsgFolderCompactor.h"
 #include "nsICopyMsgStreamListener.h"
+#include "nsMsgKeyArray.h"
 #include "nsIMsgWindow.h"
 #include "nsIStringBundle.h"
 #include "nsIMsgMessageService.h"
 
 #define COMPACTOR_READ_BUFF_SIZE 16384
 
 class nsFolderCompactState : public nsIMsgFolderCompactor,
                              public nsIStreamListener,
@@ -83,18 +84,19 @@ protected:
   nsresult CompactNextFolder();
 
   nsCString m_baseMessageUri; // base message uri
   nsCString m_messageUri; // current message uri being copy
   nsCOMPtr<nsIMsgFolder> m_folder; // current folder being compact
   nsCOMPtr<nsIMsgDatabase> m_db; // new database for the compact folder
   nsCOMPtr <nsILocalFile> m_file; // new mailbox for the compact folder
   nsCOMPtr <nsIOutputStream> m_fileStream; // output file stream for writing
-  nsTArray<nsMsgKey> m_keyArray; // all message keys need to be copied over
-  PRInt32 m_size; // size of the message key array
+  // all message keys that need to be copied over
+  nsRefPtr<nsMsgKeyArray> m_keyArray;
+  PRUint32 m_size;
 
    // sum of the sizes of the messages, accumulated as we visit each msg.
   PRUint32 m_totalMsgSize;
 
   PRInt32 m_curIndex; // index of the current copied message key in key array
   PRUint64 m_startOfNewMsg; // offset in mailbox of new message
   char m_dataBuffer[COMPACTOR_READ_BUFF_SIZE + 1]; // temp data buffer for copying message
   nsresult m_status; // the status of the copying operation
--- a/mailnews/base/util/Makefile.in
+++ b/mailnews/base/util/Makefile.in
@@ -47,16 +47,17 @@ LIBRARY_NAME	= msgbsutl_s
 ifndef MOZ_INCOMPLETE_EXTERNAL_LINKAGE
 MOZILLA_INTERNAL_API = 1
 LIBXUL_LIBRARY = 1
 endif
 
 CPPSRCS		= \
 		nsMsgLineBuffer.cpp \
 		nsMsgDBFolder.cpp \
+		nsMsgKeyArray.cpp \
 		nsMsgKeySet.cpp \
 		nsMsgIdentity.cpp \
 		nsMsgIncomingServer.cpp \
 		nsMsgUtils.cpp \
 		nsMsgProtocol.cpp \
 		nsMsgMailNewsUrl.cpp \
 		nsMsgTxn.cpp \
 		nsMsgI18N.cpp \
@@ -65,16 +66,17 @@ CPPSRCS		= \
 		nsMsgCompressIStream.cpp \
 		nsMsgCompressOStream.cpp \
 		nsMsgReadStateTxn.cpp \
 		nsStopwatch.cpp \
 		$(NULL)
 
 EXPORTS		= \
 		nsMsgLineBuffer.h \
+		nsMsgKeyArray.h \
 		nsMsgKeySet.h \
 		nsMsgDBFolder.h \
 		nsMsgDBFolderAtomList.h \
 		nsMsgIdentity.h \
 		nsMsgIncomingServer.h \
 		nsMsgUtils.h \
 		nsMsgProtocol.h \
 		nsMsgMailNewsUrl.h \
--- a/mailnews/base/util/nsMsgDBFolder.cpp
+++ b/mailnews/base/util/nsMsgDBFolder.cpp
@@ -1410,62 +1410,74 @@ nsMsgDBFolder::AddMessageDispositionStat
 
   if (aDispositionFlag == nsIMsgFolder::nsMsgDispositionState_Replied)
     mDatabase->MarkReplied(msgKey, PR_TRUE, nsnull);
   else if (aDispositionFlag == nsIMsgFolder::nsMsgDispositionState_Forwarded)
     mDatabase->MarkForwarded(msgKey, PR_TRUE, nsnull);
   return NS_OK;
 }
 
+nsresult nsMsgDBFolder::AddMarkAllReadUndoAction(nsIMsgWindow *msgWindow,
+                                                 nsMsgKey *thoseMarked,
+                                                 PRUint32 numMarked)
+{
+  nsRefPtr<nsMsgReadStateTxn> readStateTxn = new nsMsgReadStateTxn();
+  if (!readStateTxn)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  nsresult rv = readStateTxn->Init(this, numMarked, thoseMarked);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = readStateTxn->SetTransactionType(nsIMessenger::eMarkAllMsg);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsITransactionManager> txnMgr;
+  rv = msgWindow->GetTransactionManager(getter_AddRefs(txnMgr));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = txnMgr->DoTransaction(readStateTxn);
+  NS_ENSURE_SUCCESS(rv, rv);
+  return rv;
+}
+
 NS_IMETHODIMP
 nsMsgDBFolder::MarkAllMessagesRead(nsIMsgWindow *aMsgWindow)
 {
   nsresult rv = GetDatabase();
   m_newMsgs.Clear();
-  
+
   if (NS_SUCCEEDED(rv))
   {
     EnableNotifications(allMessageCountNotifications, PR_FALSE, PR_TRUE /*dbBatching*/);
-    nsTArray<nsMsgKey> thoseMarked;
-    rv = mDatabase->MarkAllRead(&thoseMarked);
+    nsMsgKey *thoseMarked;
+    PRUint32 numMarked;
+    rv = mDatabase->MarkAllRead(&numMarked, &thoseMarked);
     NS_ENSURE_SUCCESS(rv, rv);
     EnableNotifications(allMessageCountNotifications, PR_TRUE, PR_TRUE /*dbBatching*/);
 
     // Setup a undo-state
     if (aMsgWindow)
-    {
-      nsRefPtr<nsMsgReadStateTxn> readStateTxn = new nsMsgReadStateTxn();
-      if (!readStateTxn)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-      rv = readStateTxn->Init(this, thoseMarked);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      rv = readStateTxn->SetTransactionType(nsIMessenger::eMarkAllMsg);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      nsCOMPtr<nsITransactionManager> txnMgr;
-      rv = aMsgWindow->GetTransactionManager(getter_AddRefs(txnMgr));
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      rv = txnMgr->DoTransaction(readStateTxn);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
+      rv = AddMarkAllReadUndoAction(aMsgWindow, thoseMarked, numMarked);
+    nsMemory::Free(thoseMarked);
   }
 
   SetHasNewMessages(PR_FALSE);
- 
   return rv;
 }
 
 NS_IMETHODIMP nsMsgDBFolder::MarkThreadRead(nsIMsgThread *thread)
 {
   nsresult rv = GetDatabase();
   if(NS_SUCCEEDED(rv))
-    return mDatabase->MarkThreadRead(thread, nsnull, nsnull);
+  {
+    nsMsgKey *keys;
+    PRUint32 numKeys;
+    rv = mDatabase->MarkThreadRead(thread, nsnull, &numKeys, &keys);
+    nsMemory::Free(keys);
+  }
   return rv;
 }
 
 NS_IMETHODIMP
 nsMsgDBFolder::OnStartRunningUrl(nsIURI *aUrl)
 {
   return NS_OK;
 }
--- a/mailnews/base/util/nsMsgDBFolder.h
+++ b/mailnews/base/util/nsMsgDBFolder.h
@@ -163,16 +163,18 @@ protected:
   nsresult CompactOfflineStore(nsIMsgWindow *inWindow, nsIUrlListener *aUrlListener);
   nsresult AutoCompact(nsIMsgWindow *aWindow);
   // this is a helper routine that ignores whether nsMsgMessageFlags::Offline is set for the folder
   nsresult MsgFitsDownloadCriteria(nsMsgKey msgKey, PRBool *result);
   nsresult GetPromptPurgeThreshold(PRBool *aPrompt);
   nsresult GetPurgeThreshold(PRInt32 *aThreshold);
   nsresult ApplyRetentionSettings(PRBool deleteViaFolder);
   PRBool   VerifyOfflineMessage(nsIMsgDBHdr *msgHdr, nsIInputStream *fileStream);
+  nsresult AddMarkAllReadUndoAction(nsIMsgWindow *msgWindow,
+                                    nsMsgKey *thoseMarked, PRUint32 numMarked);
 
   nsresult PerformBiffNotifications(void); // if there are new, non spam messages, do biff
   nsresult CloseDBIfFolderNotOpen();
 
   virtual nsresult SpamFilterClassifyMessage(const char *aURI, nsIMsgWindow *aMsgWindow, nsIJunkMailPlugin *aJunkMailPlugin);
   virtual nsresult SpamFilterClassifyMessages(const char **aURIArray, PRUint32 aURICount, nsIMsgWindow *aMsgWindow, nsIJunkMailPlugin *aJunkMailPlugin);
   // Helper function for Move code to call to update the MRU and MRM time.
   void    UpdateTimestamps(PRBool allowUndo);
new file mode 100644
--- /dev/null
+++ b/mailnews/base/util/nsMsgKeyArray.cpp
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** 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 MailNews nsMsgKeyArray
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   David Bienvenu <bienvenu@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#include "nsMsgKeyArray.h"
+#include "nsMemory.h"
+
+NS_IMPL_ISUPPORTS1(nsMsgKeyArray, nsIMsgKeyArray)
+
+nsMsgKeyArray::nsMsgKeyArray()
+{
+}
+
+nsMsgKeyArray::~nsMsgKeyArray()
+{
+}
+
+NS_IMETHODIMP nsMsgKeyArray::Sort()
+{
+  m_keys.Sort();
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgKeyArray::GetKeyAt(PRInt32 aIndex, nsMsgKey *aKey)
+{
+  NS_ENSURE_ARG_POINTER(aKey);
+  *aKey = m_keys[aIndex];
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgKeyArray::GetLength(PRUint32 *aLength)
+{
+  NS_ENSURE_ARG_POINTER(aLength);
+  *aLength = m_keys.Length();
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgKeyArray::SetCapacity(PRUint32 aCapacity)
+{
+  m_keys.SetCapacity(aCapacity);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgKeyArray::AppendElement(nsMsgKey aKey)
+{
+  m_keys.AppendElement(aKey);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgKeyArray::GetArray(PRUint32 *aCount, nsMsgKey **aKeys)
+{
+  NS_ENSURE_ARG_POINTER(aCount);
+  NS_ENSURE_ARG_POINTER(aKeys);
+  *aCount = m_keys.Length();
+  *aKeys =
+    (nsMsgKey *) nsMemory::Clone(&m_keys[0],
+                                 m_keys.Length() * sizeof(nsMsgKey));
+  return (*aKeys) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+}
+
new file mode 100644
--- /dev/null
+++ b/mailnews/base/util/nsMsgKeyArray.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** 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 MailNews nsMsgKeyArray
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   David Bienvenu <bienvenu@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of 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 ***** */
+
+#ifndef nsMsgKeyArray_h__
+#define nsMsgKeyArray_h__
+
+#include "nsIMsgKeyArray.h"
+#include "nsTArray.h"
+
+/*
+ * This class is a thin wrapper around an nsTArray<nsMsgKey>
+ */
+class nsMsgKeyArray : public nsIMsgKeyArray
+{
+public:
+  nsMsgKeyArray();
+  virtual ~nsMsgKeyArray();
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIMSGKEYARRAY
+
+  nsTArray<nsMsgKey> m_keys;
+};
+
+#endif
--- a/mailnews/base/util/nsMsgReadStateTxn.cpp
+++ b/mailnews/base/util/nsMsgReadStateTxn.cpp
@@ -47,23 +47,24 @@ nsMsgReadStateTxn::nsMsgReadStateTxn()
 {
 }
 
 nsMsgReadStateTxn::~nsMsgReadStateTxn()
 {
 }
 
 nsresult
-nsMsgReadStateTxn::Init(nsIMsgFolder *aParentFolder, 
-                        nsTArray<nsMsgKey> & aMsgKeyArray)
+nsMsgReadStateTxn::Init(nsIMsgFolder *aParentFolder,
+                        PRUint32 aNumKeys,
+                        nsMsgKey *aMsgKeyArray)
 {
   NS_ENSURE_ARG_POINTER(aParentFolder);
 
   mParentFolder = aParentFolder;
-  aMsgKeyArray.SwapElements(mMarkedMessages);
+  mMarkedMessages.AppendElements(aMsgKeyArray, aNumKeys);
 
   return nsMsgTxn::Init();
 }
 
 NS_IMETHODIMP 
 nsMsgReadStateTxn::UndoTransaction()
 {
   return MarkMessages(PR_FALSE);
--- a/mailnews/base/util/nsMsgReadStateTxn.h
+++ b/mailnews/base/util/nsMsgReadStateTxn.h
@@ -57,18 +57,19 @@
 // A mark-all transaction handler. Helper for redo/undo of message read states.
 //------------------------------------------------------------------------------
 class NS_MSG_BASE nsMsgReadStateTxn : public nsMsgTxn
 {
 public:
   nsMsgReadStateTxn();
   virtual ~nsMsgReadStateTxn();
 
-  nsresult Init(nsIMsgFolder *aParentFolder, 
-                nsTArray<nsMsgKey> & aMsgKeyArray);
+  nsresult Init(nsIMsgFolder *aParentFolder,
+                PRUint32 aNumKeys,
+                nsMsgKey *aMsgKeyArray);
   NS_IMETHOD UndoTransaction();
   NS_IMETHOD RedoTransaction();
 
 protected:
   NS_IMETHOD MarkMessages(PRBool aAsRead);
 
 private:
   nsCOMPtr<nsIMsgFolder> mParentFolder;
--- a/mailnews/build/nsMailModule.cpp
+++ b/mailnews/build/nsMailModule.cpp
@@ -94,16 +94,17 @@
 #include "nsMsgAccountManager.h"
 #include "nsMsgIdentity.h"
 #include "nsMsgIncomingServer.h"
 #include "nsMsgFolderDataSource.h"
 #include "nsMsgAccountManagerDS.h"
 #include "nsMsgBiffManager.h"
 #include "nsMsgPurgeService.h"
 #include "nsStatusBarBiffManager.h"
+#include "nsMsgKeyArray.h"
 #include "nsCopyMessageStreamListener.h"
 #include "nsMsgCopyService.h"
 #include "nsMsgFolderCache.h"
 #include "nsMsgStatusFeedback.h"
 #include "nsMsgFilterService.h"
 #include "nsMsgWindow.h"
 #include "nsMsgServiceProvider.h"
 #include "nsSubscribeDataSource.h"
@@ -346,16 +347,17 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgSear
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgFilterService)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMsgBiffManager, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgPurgeService)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsStatusBarBiffManager, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsCopyMessageStreamListener)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgCopyService)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgFolderCache)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgStatusFeedback)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgKeyArray)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMsgWindow,Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMsgServiceProviderService, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSubscribeDataSource, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSubscribableServer, Init)
 #ifdef NS_PRINTING
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgPrintEngine)
 #endif
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFolderCompactState)
@@ -411,16 +413,17 @@ NS_DEFINE_NAMED_CID(NS_MSGSEARCHVALIDITY
 NS_DEFINE_NAMED_CID(NS_MSGBIFFMANAGER_CID);
 NS_DEFINE_NAMED_CID(NS_MSGPURGESERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_STATUSBARBIFFMANAGER_CID);
 NS_DEFINE_NAMED_CID(NS_COPYMESSAGESTREAMLISTENER_CID);
 NS_DEFINE_NAMED_CID(NS_MSGCOPYSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_MSGFOLDERCACHE_CID);
 NS_DEFINE_NAMED_CID(NS_MSGSTATUSFEEDBACK_CID);
 NS_DEFINE_NAMED_CID(NS_MSGWINDOW_CID);
+NS_DEFINE_NAMED_CID(NS_MSGKEYARRAY_CID);
 #ifdef NS_PRINTING
 NS_DEFINE_NAMED_CID(NS_MSG_PRINTENGINE_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_MSGSERVICEPROVIDERSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_SUBSCRIBEDATASOURCE_CID);
 NS_DEFINE_NAMED_CID(NS_SUBSCRIBABLESERVER_CID);
 NS_DEFINE_NAMED_CID(NS_MSGLOCALFOLDERCOMPACTOR_CID);
 NS_DEFINE_NAMED_CID(NS_MSG_OFFLINESTORECOMPACTOR_CID);
@@ -806,16 +809,17 @@ const mozilla::Module::CIDEntry kMailNew
   { &kNS_MSGSEARCHVALIDITYMANAGER_CID, false, NULL, nsMsgSearchValidityManagerConstructor},
   { &kNS_MSGBIFFMANAGER_CID, false, NULL, nsMsgBiffManagerConstructor},
   { &kNS_MSGPURGESERVICE_CID, false, NULL, nsMsgPurgeServiceConstructor},
   { &kNS_STATUSBARBIFFMANAGER_CID, false, NULL, nsStatusBarBiffManagerConstructor},
   { &kNS_COPYMESSAGESTREAMLISTENER_CID, false, NULL, nsCopyMessageStreamListenerConstructor},
   { &kNS_MSGCOPYSERVICE_CID, false, NULL, nsMsgCopyServiceConstructor},
   { &kNS_MSGFOLDERCACHE_CID, false, NULL, nsMsgFolderCacheConstructor},
   { &kNS_MSGSTATUSFEEDBACK_CID, false, NULL, nsMsgStatusFeedbackConstructor},
+  { &kNS_MSGKEYARRAY_CID, false, NULL, nsMsgKeyArrayConstructor},
   { &kNS_MSGWINDOW_CID, false, NULL, nsMsgWindowConstructor},
 #ifdef NS_PRINTING
   { &kNS_MSG_PRINTENGINE_CID, false, NULL, nsMsgPrintEngineConstructor},
 #endif
   { &kNS_MSGSERVICEPROVIDERSERVICE_CID, false, NULL, nsMsgServiceProviderServiceConstructor},
   { &kNS_SUBSCRIBEDATASOURCE_CID, false, NULL, nsSubscribeDataSourceConstructor},
   { &kNS_SUBSCRIBABLESERVER_CID, false, NULL, nsSubscribableServerConstructor},
   { &kNS_MSGLOCALFOLDERCOMPACTOR_CID, false, NULL, nsFolderCompactStateConstructor},
@@ -1002,16 +1006,17 @@ const mozilla::Module::ContractIDEntry k
   { NS_MSGSEARCHVALIDITYMANAGER_CONTRACTID, &kNS_MSGSEARCHVALIDITYMANAGER_CID },
   { NS_MSGBIFFMANAGER_CONTRACTID, &kNS_MSGBIFFMANAGER_CID },
   { NS_MSGPURGESERVICE_CONTRACTID, &kNS_MSGPURGESERVICE_CID },
   { NS_STATUSBARBIFFMANAGER_CONTRACTID, &kNS_STATUSBARBIFFMANAGER_CID },
   { NS_COPYMESSAGESTREAMLISTENER_CONTRACTID, &kNS_COPYMESSAGESTREAMLISTENER_CID },
   { NS_MSGCOPYSERVICE_CONTRACTID, &kNS_MSGCOPYSERVICE_CID },
   { NS_MSGFOLDERCACHE_CONTRACTID, &kNS_MSGFOLDERCACHE_CID },
   { NS_MSGSTATUSFEEDBACK_CONTRACTID, &kNS_MSGSTATUSFEEDBACK_CID },
+  { NS_MSGKEYARRAY_CONTRACTID, &kNS_MSGKEYARRAY_CID },
   { NS_MSGWINDOW_CONTRACTID, &kNS_MSGWINDOW_CID },
 #ifdef NS_PRINTING
   { NS_MSGPRINTENGINE_CONTRACTID, &kNS_MSG_PRINTENGINE_CID },
 #endif
   { NS_MSGSERVICEPROVIDERSERVICE_CONTRACTID, &kNS_MSGSERVICEPROVIDERSERVICE_CID },
   { NS_SUBSCRIBEDATASOURCE_CONTRACTID, &kNS_SUBSCRIBEDATASOURCE_CID },
   { NS_SUBSCRIBABLESERVER_CONTRACTID, &kNS_SUBSCRIBABLESERVER_CID },
   { NS_MSGLOCALFOLDERCOMPACTOR_CONTRACTID, &kNS_MSGLOCALFOLDERCOMPACTOR_CID },
--- a/mailnews/db/msgdb/public/nsIMsgDatabase.idl
+++ b/mailnews/db/msgdb/public/nsIMsgDatabase.idl
@@ -64,23 +64,22 @@
 
 interface nsIDBChangeListener;
 interface nsIMsgDBHdr;
 interface nsISimpleEnumerator;
 interface nsIMsgThread;
 interface nsIDBFolderInfo;
 interface nsIMsgOfflineImapOperation;
 interface nsIMsgFolder;
+interface nsIMsgKeyArray;
 interface nsIOutputStream;
 interface nsIUrlListener;
 interface nsILocalFile;
 interface nsIArray;
 
-[ptr] native octetPtr(PRUint8);
-
 typedef unsigned long nsMsgRetainByPreference;
 
 
 [scriptable, uuid(b01d6b3b-78c2-4958-b836-2259c76dbc24)]
 
 interface nsIMsgRetentionSettings : nsISupports
 {
   const unsigned long nsMsgRetainAll = 1;
@@ -262,17 +261,17 @@ interface nsIMsgDBService : nsISupports
    *
    * @param aFolder   The folder to get the cached (open) db for.
    *
    * @returns         null if the db isn't open, otherwise the db.
    */
   nsIMsgDatabase cachedDBForFolder(in nsIMsgFolder aFolder);
 };
 
-[scriptable, uuid(2DDC3EFE-743D-4b8c-B761-6ED75ED06737)]
+[scriptable, uuid(19719187-6a85-4807-aeb6-421115240ba1)]
 interface nsIMsgDatabase : nsIDBChangeAnnouncer {
   /**
    * Opens a database folder.
    *
    * @param aFolderName     The name of the folder to create.
    * @param aCreate         Whether or not the file should be created.
    * @param aLeaveInvalidDB Set to true if you do not want the database to be
    *                        deleted if it is invalid.
@@ -310,17 +309,17 @@ interface nsIMsgDatabase : nsIDBChangeAn
   // a new header, fill in its properties, and then call AddNewHdrToDB.
   // AddNewHdrToDB will send notifications to any listeners.
   nsIMsgDBHdr CreateNewHdr(in nsMsgKey key);
 
   void AddNewHdrToDB(in nsIMsgDBHdr newHdr, in boolean notify);
 
   nsIMsgDBHdr CopyHdrFromExistingHdr(in nsMsgKey key, in nsIMsgDBHdr existingHdr, in boolean addHdrToDB);
 
-  [noscript] void ListAllKeys(in nsMsgKeyArrayRef outputKeys);
+  void ListAllKeys(in nsIMsgKeyArray array);
 
   nsISimpleEnumerator EnumerateMessages();
   nsISimpleEnumerator ReverseEnumerateMessages();
   nsISimpleEnumerator EnumerateThreads();
 
   /**
    * Get an enumerator for use with nextMatchingHdrs. The enumerator
    * will only return messages that match the passed-in search terms.
@@ -398,34 +397,34 @@ interface nsIMsgDatabase : nsIDBChangeAn
                          in nsIDBChangeListener instigator);
 
   void MarkForwarded(in nsMsgKey key, in boolean bForwarded, 
                            in nsIDBChangeListener instigator);
 
   void MarkHasAttachments(in nsMsgKey key, in boolean bHasAttachments, 
                                 in nsIDBChangeListener instigator);
 
-  [noscript] void MarkThreadRead(in nsIMsgThread thread, 
-					in nsIDBChangeListener instigator, in nsMsgKeyArrayPtr thoseMarked);
+  void MarkThreadRead(in nsIMsgThread thread, in nsIDBChangeListener instigator,
+                      out unsigned long aCount,
+                      [array, size_is(aCount)] out nsMsgKey aKeys);
 
   void MarkThreadIgnored(in nsIMsgThread thread, in nsMsgKey threadKey, in boolean bIgnored,
                                in nsIDBChangeListener instigator);
   void MarkThreadWatched(in nsIMsgThread thread, in nsMsgKey threadKey, in boolean bWatched,
                                in nsIDBChangeListener instigator);
   void MarkHeaderKilled(in nsIMsgDBHdr msg, in boolean bIgnored,
                         in nsIDBChangeListener instigator);
 
   boolean IsRead(in nsMsgKey key);
   boolean IsIgnored(in nsMsgKey key);
   boolean IsMarked(in nsMsgKey key);
   boolean HasAttachments(in nsMsgKey key);
 
-  [noscript] void MarkAllRead(in nsMsgKeyArrayPtr thoseMarked);
-
-  [noscript] void MarkReadByDate (in PRTime startDate, in PRTime endDate, in nsMsgKeyArrayPtr markedIds);
+  void MarkAllRead(out unsigned long aCount,
+                   [array, size_is(aCount)] out nsMsgKey aKeys);
 
   void deleteMessages(in unsigned long aNumKeys,
                       [array, size_is(aNumKeys)] in nsMsgKey nsMsgKeys,
                       in nsIDBChangeListener instigator);
   void DeleteMessage(in nsMsgKey key, 
                            in nsIDBChangeListener instigator,
                            in boolean commit);
   void DeleteHeader(in nsIMsgDBHdr msgHdr, in nsIDBChangeListener instigator,
@@ -492,17 +491,17 @@ interface nsIMsgDatabase : nsIDBChangeAn
   void EndBatch();
   // offline operations - we could move these into an offline operation interface
   // but it would have to be in nsMailDatabase, since local folders can be move destinations
   nsIMsgOfflineImapOperation GetOfflineOpForKey(in nsMsgKey messageKey, in boolean create);
   void  RemoveOfflineOp(in nsIMsgOfflineImapOperation op);
   nsISimpleEnumerator EnumerateOfflineOps();
   [noscript] void ListAllOfflineOpIds(in nsMsgKeyArrayPtr offlineOpIds);
   [noscript] void ListAllOfflineDeletes(in nsMsgKeyArrayPtr offlineDeletes);
-  [noscript] void ListAllOfflineMsgs(in nsMsgKeyArrayPtr offlineMsgs);
+  void ListAllOfflineMsgs(in nsIMsgKeyArray aKeys);
 
   void setAttributeOnPendingHdr(in nsIMsgDBHdr pendingHdr, in string property,
                                   in string propertyVal);
 
   void setUint32AttributeOnPendingHdr(in nsIMsgDBHdr pendingHdr, in string property,
                                   in unsigned long propertyVal);
 
   /**
@@ -530,18 +529,22 @@ interface nsIMsgDatabase : nsIDBChangeAn
    */
   void updatePendingAttributes(in nsIMsgDBHdr aNewHdr);
 
   readonly attribute nsMsgKey lowWaterArticleNum;
   readonly attribute nsMsgKey highWaterArticleNum;
   attribute nsMsgKey nextPseudoMsgKey;   //for undo-redo of move pop->imap
   readonly attribute nsMsgKey nextFakeOfflineMsgKey; // for saving "fake" offline msg hdrs
   // for sorting
-  [noscript] void createCollationKey(in AString sourceString, out octetPtr key, out unsigned long len);
-  [noscript] long compareCollationKeys(in octetPtr key1, in unsigned long len1, in octetPtr key2, in unsigned long len2);
+  void createCollationKey(in AString sourceString, out unsigned long aCount,
+                          [array, size_is(aCount)] out octet aKey);
+  long compareCollationKeys(in unsigned long aLen1,
+                            [array, size_is(aLen1)] in octet key1,
+                            in unsigned long aLen2,
+                            [array, size_is(aLen2)] in octet key2);
 
   // when creating a view, the default sort order and view flags 
   // use these for the default.  (this allows news to override, so that
   // news can be threaded by default)
   readonly attribute nsMsgViewFlagsTypeValue defaultViewFlags;
   readonly attribute nsMsgViewSortTypeValue  defaultSortType;
   readonly attribute nsMsgViewSortOrderValue defaultSortOrder;
 
--- a/mailnews/db/msgdb/public/nsMsgDatabase.h
+++ b/mailnews/db/msgdb/public/nsMsgDatabase.h
@@ -36,31 +36,31 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _nsMsgDatabase_H_
 #define _nsMsgDatabase_H_
 
 #include "nsIMsgDatabase.h"
 #include "nsMsgHdr.h"
 #include "nsStringGlue.h"
+#include "nsAutoPtr.h"
 #include "nsIDBChangeListener.h"
 #include "nsIDBChangeAnnouncer.h"
 #include "nsMsgMessageFlags.h"
 #include "nsIMsgFolder.h"
 #include "nsIMutableArray.h"
 #include "nsDBFolderInfo.h"
 #include "nsICollation.h"
 #include "nsIMsgSearchSession.h"
 #include "nsIMimeConverter.h"
 #include "nsCOMPtr.h"
 #include "nsCOMArray.h"
 #include "pldhash.h"
 #include "nsTArray.h"
 #include "nsTObserverArray.h"
-#include "nsAutoPtr.h"
 class ListContext;
 class nsMsgKeySet;
 class nsMsgThread;
 class nsIMsgThread;
 class nsIDBFolderInfo;
 class nsIMsgHeaderParser;
 
 const PRInt32 kMsgDBVersion = 1;
--- a/mailnews/db/msgdb/public/nsNewsDatabase.h
+++ b/mailnews/db/msgdb/public/nsNewsDatabase.h
@@ -61,17 +61,17 @@ public:
   virtual PRUint32 GetCurVersion();
 
   // methods to get and set docsets for ids.
   NS_IMETHOD  IsRead(nsMsgKey key, PRBool *pRead);
   virtual nsresult  IsHeaderRead(nsIMsgDBHdr *msgHdr, PRBool *pRead);
 
   NS_IMETHOD         GetHighWaterArticleNum(nsMsgKey *key);
   NS_IMETHOD         GetLowWaterArticleNum(nsMsgKey *key);
-  NS_IMETHOD         MarkAllRead(nsTArray<nsMsgKey> *thoseMarked);
+  NS_IMETHOD         MarkAllRead(PRUint32 *aNumMarked, nsMsgKey **thoseMarked);
 
   virtual nsresult    ExpireUpTo(nsMsgKey expireKey);
   virtual nsresult    ExpireRange(nsMsgKey startRange, nsMsgKey endRange);
  
   virtual PRBool      SetHdrReadFlag(nsIMsgDBHdr *msgHdr, PRBool bRead);
  
   virtual nsresult  AdjustExpungedBytesOnDelete(nsIMsgDBHdr *msgHdr);
   nsresult          SyncWithReadSet();
--- a/mailnews/db/msgdb/src/nsMsgDatabase.cpp
+++ b/mailnews/db/msgdb/src/nsMsgDatabase.cpp
@@ -64,16 +64,17 @@
 #include "nsMsgMimeCID.h"
 #include "nsILocaleService.h"
 #include "nsMsgFolderFlags.h"
 #include "nsIMsgAccountManager.h"
 #include "nsIMsgFolderCache.h"
 #include "nsIMsgFolderCacheElement.h"
 #include "MailNewsTypes2.h"
 #include "nsMsgUtils.h"
+#include "nsMsgKeyArray.h"
 #include "nsIMutableArray.h"
 #include "nsComponentManagerUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsMemory.h"
 #include "nsICollation.h"
 #include "nsCollationCID.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
@@ -2158,45 +2159,51 @@ NS_IMETHODIMP nsMsgDatabase::MarkForward
 
 NS_IMETHODIMP nsMsgDatabase::MarkHasAttachments(nsMsgKey key, PRBool bHasAttachments,
                                                 nsIDBChangeListener *instigator)
 {
   return SetKeyFlag(key, bHasAttachments, nsMsgMessageFlags::Attachment, instigator);
 }
 
 NS_IMETHODIMP
-nsMsgDatabase::MarkThreadRead(nsIMsgThread *thread, nsIDBChangeListener *instigator, nsTArray<nsMsgKey> *thoseMarked)
-{
-  if (!thread)
-    return NS_ERROR_NULL_POINTER;
+nsMsgDatabase::MarkThreadRead(nsIMsgThread *thread, nsIDBChangeListener *instigator,
+                              PRUint32 *aNumMarked, nsMsgKey **aThoseMarked)
+{
+  NS_ENSURE_ARG_POINTER(thread);
+  NS_ENSURE_ARG_POINTER(aNumMarked);
+  NS_ENSURE_ARG_POINTER(aThoseMarked);
   nsresult rv = NS_OK;
 
   PRUint32 numChildren;
+  nsTArray<nsMsgKey> thoseMarked;
   thread->GetNumChildren(&numChildren);
   for (PRUint32 curChildIndex = 0; curChildIndex < numChildren; curChildIndex++)
   {
     nsCOMPtr <nsIMsgDBHdr> child;
 
     rv = thread->GetChildHdrAt(curChildIndex, getter_AddRefs(child));
     if (NS_SUCCEEDED(rv) && child)
     {
       PRBool isRead = PR_TRUE;
       IsHeaderRead(child, &isRead);
       if (!isRead)
       {
-        if (thoseMarked)
-        {
-          nsMsgKey key;
-          if (NS_SUCCEEDED(child->GetMessageKey(&key)))
-            thoseMarked->AppendElement(key);
-        }
+        nsMsgKey key;
+        if (NS_SUCCEEDED(child->GetMessageKey(&key)))
+          thoseMarked.AppendElement(key);
         MarkHdrRead(child, PR_TRUE, instigator);
       }
     }
   }
+  *aThoseMarked =
+    (nsMsgKey *) nsMemory::Clone(&thoseMarked[0],
+                                 thoseMarked.Length() * sizeof(nsMsgKey));
+  *aNumMarked = thoseMarked.Length();
+  if (!*aThoseMarked)
+    return NS_ERROR_OUT_OF_MEMORY;
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsMsgDatabase::MarkThreadIgnored(nsIMsgThread *thread, nsMsgKey threadKey, PRBool bIgnored,
                                  nsIDBChangeListener *instigator)
 {
@@ -2582,104 +2589,64 @@ nsMsgDatabase::MarkHdrNotNew(nsIMsgDBHdr
 {
   NS_ENSURE_ARG_POINTER(aMsgHdr);
   nsMsgKey msgKey;
   aMsgHdr->GetMessageKey(&msgKey);
   m_newSet.RemoveElement(msgKey);
   return SetMsgHdrFlag(aMsgHdr, PR_FALSE, nsMsgMessageFlags::New, aInstigator);
 }
 
-NS_IMETHODIMP nsMsgDatabase::MarkAllRead(nsTArray<nsMsgKey> *thoseMarked)
-{
-  nsresult    rv;
+NS_IMETHODIMP nsMsgDatabase::MarkAllRead(PRUint32 *aNumKeys, nsMsgKey **aThoseMarked)
+{
+  NS_ENSURE_ARG_POINTER(aNumKeys);
+  NS_ENSURE_ARG_POINTER(aThoseMarked);
   nsMsgHdr  *pHeader;
 
-  nsCOMPtr <nsISimpleEnumerator> hdrs;
-  rv = EnumerateMessages(getter_AddRefs(hdrs));
+  nsCOMPtr<nsISimpleEnumerator> hdrs;
+  nsTArray<nsMsgKey> thoseMarked;
+  nsresult rv = EnumerateMessages(getter_AddRefs(hdrs));
   if (NS_FAILED(rv))
     return rv;
   PRBool hasMore = PR_FALSE;
 
   while (NS_SUCCEEDED(rv = hdrs->HasMoreElements(&hasMore)) && hasMore)
   {
     rv = hdrs->GetNext((nsISupports**)&pHeader);
     NS_ASSERTION(NS_SUCCEEDED(rv), "nsMsgDBEnumerator broken");
     if (NS_FAILED(rv))
       break;
 
     PRBool isRead;
     IsHeaderRead(pHeader, &isRead);
 
     if (!isRead)
     {
-      if (thoseMarked)
-      {
-        nsMsgKey key;
-        (void)pHeader->GetMessageKey(&key);
-        thoseMarked->AppendElement(key);
-      }
+      nsMsgKey key;
+      (void)pHeader->GetMessageKey(&key);
+      thoseMarked.AppendElement(key);
       rv = MarkHdrRead(pHeader, PR_TRUE, nsnull);   // ### dmb - blow off error?
     }
     NS_RELEASE(pHeader);
   }
+  *aThoseMarked = (nsMsgKey *) nsMemory::Clone(&thoseMarked[0],
+                                       thoseMarked.Length() * sizeof(nsMsgKey));
+  if (!*aThoseMarked)
+    return NS_ERROR_OUT_OF_MEMORY;
+  *aNumKeys = thoseMarked.Length();
 
   // force num new to 0.
   PRInt32 numUnreadMessages;
 
   rv = m_dbFolderInfo->GetNumUnreadMessages(&numUnreadMessages);
   if (rv == NS_OK)
     m_dbFolderInfo->ChangeNumUnreadMessages(-numUnreadMessages);
   // caller will Commit the db, so no need to do it here.
   return rv;
 }
 
-NS_IMETHODIMP nsMsgDatabase::MarkReadByDate (PRTime startDate, PRTime endDate, nsTArray<nsMsgKey> *markedIds)
-{
-  nsresult rv;
-  nsMsgHdr  *pHeader;
-  PRInt32 numChanged = 0;
-
-  nsISimpleEnumerator* hdrs;
-  rv = EnumerateMessages(&hdrs);
-  if (NS_FAILED(rv))
-    return rv;
-
-  PRBool hasMore = PR_FALSE;
-
-  while (NS_SUCCEEDED(rv = hdrs->HasMoreElements(&hasMore)) && hasMore)
-  {
-    rv = hdrs->GetNext((nsISupports**)&pHeader);
-    NS_ASSERTION(NS_SUCCEEDED(rv), "nsMsgDBEnumerator broken");
-    if (NS_FAILED(rv)) break;
-
-    PRTime headerDate;
-    (void)pHeader->GetDate(&headerDate);
-
-    if (headerDate > startDate && headerDate <= endDate)
-    {
-      PRBool isRead;
-      nsMsgKey key;
-      (void)pHeader->GetMessageKey(&key);
-      IsRead(key, &isRead);
-      if (!isRead)
-      {
-        numChanged++;
-        if (markedIds)
-          markedIds->AppendElement(key);
-        rv = MarkHdrRead(pHeader, PR_TRUE, NULL);  // ### dmb - blow off error?
-      }
-    }
-    NS_RELEASE(pHeader);
-  }
-  if (numChanged > 0)
-    Commit(nsMsgDBCommitType::kSmallCommit);
-  return rv;
-}
-
-
 NS_IMETHODIMP nsMsgDatabase::AddToNewList(nsMsgKey key)
 {
   // we add new keys in increasing order...
   if (m_newSet.IsEmpty() || (m_newSet[m_newSet.Length() - 1] < key))
     m_newSet.AppendElement(key);
   return NS_OK;
 }
 
@@ -3073,41 +3040,44 @@ nsMsgDatabase::SyncCounts()
   (void) m_dbFolderInfo->GetNumMessages(&oldTotal);
   if (oldUnread != numUnread)
     m_dbFolderInfo->ChangeNumUnreadMessages(numUnread - oldUnread);
   if (oldTotal != numHdrs)
     m_dbFolderInfo->ChangeNumMessages(numHdrs - oldTotal);
   return NS_OK;
 }
 
-
 // resulting output array is sorted by key.
-NS_IMETHODIMP nsMsgDatabase::ListAllKeys(nsTArray<nsMsgKey> &outputKeys)
-{
-  nsresult  err = NS_OK;
-  nsIMdbTableRowCursor *rowCursor;
+NS_IMETHODIMP nsMsgDatabase::ListAllKeys(nsIMsgKeyArray *aKeys)
+{
+  NS_ENSURE_ARG_POINTER(aKeys);
+  nsresult  rv = NS_OK;
+  nsCOMPtr<nsIMdbTableRowCursor> rowCursor;
   if (m_mdbAllMsgHeadersTable)
   {
-    err = m_mdbAllMsgHeadersTable->GetTableRowCursor(GetEnv(), -1, &rowCursor);
-    while (err == NS_OK && rowCursor)
+    PRUint32 numMsgs = 0;
+    m_mdbAllMsgHeadersTable->GetCount(GetEnv(), &numMsgs);
+    aKeys->SetCapacity(numMsgs);
+    rv = m_mdbAllMsgHeadersTable->GetTableRowCursor(GetEnv(), -1,
+                                                     getter_AddRefs(rowCursor));
+    while (NS_SUCCEEDED(rv) && rowCursor)
     {
       mdbOid outOid;
       mdb_pos  outPos;
 
-      err = rowCursor->NextRowOid(GetEnv(), &outOid, &outPos);
+      rv = rowCursor->NextRowOid(GetEnv(), &outOid, &outPos);
       // is this right? Mork is returning a 0 id, but that should valid.
       if (outPos < 0 || outOid.mOid_Id == (mdb_id) -1)
         break;
-      if (err == NS_OK)
-        outputKeys.AppendElement(outOid.mOid_Id);
+      if (NS_SUCCEEDED(rv))
+        aKeys->AppendElement(outOid.mOid_Id);
     }
-    rowCursor->Release();
+    aKeys->Sort();
   }
-  outputKeys.Sort();
-  return err;
+  return rv;
 }
 
 class nsMsgDBThreadEnumerator : public nsISimpleEnumerator, public nsIDBChangeListener
 {
 public:
     NS_DECL_ISUPPORTS
 
     // nsISimpleEnumerator methods:
@@ -3568,17 +3538,17 @@ nsresult nsMsgDatabase::RowCellColumnToA
                                             getter_Copies(resultStr));
   if (NS_SUCCEEDED(rv) && !resultStr.IsEmpty())
     rv = headerParser->ExtractHeaderAddressName(resultStr, name);
   else
     rv = headerParser->ExtractHeaderAddressName(nsDependentCString(cSender),
                                                      name);
 
   if (NS_SUCCEEDED(rv))
-    return CreateCollationKey(NS_ConvertUTF8toUTF16(name), result, len);
+    return CreateCollationKey(NS_ConvertUTF8toUTF16(name), len, result);
 
   return rv;
 }
 
 nsresult nsMsgDatabase::GetCollationKeyGenerator()
 {
   nsresult err = NS_OK;
   if (!m_collationKeyGenerator)
@@ -3631,36 +3601,38 @@ nsresult nsMsgDatabase::RowCellColumnToC
       {
         m_dbFolderInfo->GetEffectiveCharacterSet(charSet);
       }
 
       err = m_mimeConverter->DecodeMimeHeaderToCharPtr(nakedString,
         charSet.get(), characterSetOverride, PR_TRUE,
         getter_Copies(decodedStr));
       if (NS_SUCCEEDED(err))
-        err = CreateCollationKey(NS_ConvertUTF8toUTF16(decodedStr), result, len);
+        err = CreateCollationKey(NS_ConvertUTF8toUTF16(decodedStr), len, result);
     }
   }
   return err;
 }
 
 NS_IMETHODIMP
-nsMsgDatabase::CompareCollationKeys(PRUint8 *key1, PRUint32 len1, PRUint8 *key2, PRUint32 len2, PRInt32 *result)
+nsMsgDatabase::CompareCollationKeys(PRUint32 len1, PRUint8 *key1, PRUint32 len2,
+                                    PRUint8 *key2, PRInt32 *result)
 {
   nsresult rv = GetCollationKeyGenerator();
   NS_ENSURE_SUCCESS(rv,rv);
   if (!m_collationKeyGenerator) return NS_ERROR_FAILURE;
 
   rv = m_collationKeyGenerator->CompareRawSortKey(key1,len1,key2,len2,result);
   NS_ENSURE_SUCCESS(rv,rv);
   return rv;
 }
 
 NS_IMETHODIMP
-nsMsgDatabase::CreateCollationKey(const nsAString& sourceString, PRUint8 **result, PRUint32 *len)
+nsMsgDatabase::CreateCollationKey(const nsAString& sourceString, PRUint32 *len,
+                                  PRUint8 **result)
 {
   nsresult err = GetCollationKeyGenerator();
   NS_ENSURE_SUCCESS(err,err);
   if (!m_collationKeyGenerator) return NS_ERROR_FAILURE;
 
   err = m_collationKeyGenerator->AllocateRawSortKey(nsICollation::kCollationCaseInSensitive, sourceString, result, len);
   NS_ENSURE_SUCCESS(err,err);
   return err;
@@ -4801,18 +4773,19 @@ NS_IMETHODIMP nsMsgDatabase::GetOfflineO
 
 NS_IMETHODIMP  nsMsgDatabase::RemoveOfflineOp(nsIMsgOfflineImapOperation *op)
 {
   NS_ASSERTION(PR_FALSE, "overridden by nsMailDatabase");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 
-NS_IMETHODIMP nsMsgDatabase::ListAllOfflineMsgs(nsTArray<nsMsgKey> *outputKeys)
-{
+NS_IMETHODIMP nsMsgDatabase::ListAllOfflineMsgs(nsIMsgKeyArray *aKeys)
+{
+  NS_ENSURE_ARG_POINTER(aKeys);
   nsCOMPtr <nsISimpleEnumerator> enumerator;
   PRUint32 flag = nsMsgMessageFlags::Offline;
   // if we change this routine to return an enumerator that generates the keys
   // one by one, we'll need to somehow make a copy of flag for the enumerator
   // to own, since the enumerator will persist past the life of flag on the stack.
   nsresult rv = EnumerateMessagesWithFlag(getter_AddRefs(enumerator), &flag);
   if (NS_SUCCEEDED(rv) && enumerator)
   {
@@ -4825,22 +4798,21 @@ NS_IMETHODIMP nsMsgDatabase::ListAllOffl
         return rv;
 
       // clear out db hdr, because it won't be valid when we get rid of the .msf file
       nsCOMPtr<nsIMsgDBHdr> dbMessage(do_QueryInterface(childSupports, &rv));
       if(NS_SUCCEEDED(rv) && dbMessage)
       {
         nsMsgKey msgKey;
         dbMessage->GetMessageKey(&msgKey);
-        outputKeys->AppendElement(msgKey);
+        aKeys->AppendElement(msgKey);
       }
     }
   }
-  outputKeys->Sort();
-
+  aKeys->Sort();
   return rv;
 }
 
 NS_IMETHODIMP nsMsgDatabase::EnumerateOfflineOps(nsISimpleEnumerator **enumerator)
 {
   NS_ASSERTION(PR_FALSE, "overridden by nsMailDatabase");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
@@ -4908,20 +4880,24 @@ NS_IMETHODIMP nsMsgDatabase::GetNextFake
 }
 
 #ifdef DEBUG
 nsresult nsMsgDatabase::DumpContents()
 {
   nsMsgKey key;
   PRUint32 i;
 
-  nsTArray<nsMsgKey> keys;
+  nsRefPtr<nsMsgKeyArray> keys = new nsMsgKeyArray;
+  if (!keys)
+    return NS_ERROR_OUT_OF_MEMORY;
   nsresult rv = ListAllKeys(keys);
-  for (i = 0; i < keys.Length(); i++) {
-    key = keys[i];
+  PRUint32 numKeys;
+  keys->GetLength(&numKeys);
+  for (i = 0; i < numKeys; i++) {
+    key = keys->m_keys[i];
     nsIMsgDBHdr *msg = NULL;
     rv = GetMsgHdrForKey(key, &msg);
     nsMsgHdr* msgHdr = static_cast<nsMsgHdr*>(msg);      // closed system, cast ok
     if (NS_SUCCEEDED(rv))
     {
       nsCString author;
       nsCString subject;
 
--- a/mailnews/db/msgdb/src/nsMsgHdr.cpp
+++ b/mailnews/db/msgdb/src/nsMsgHdr.cpp
@@ -719,27 +719,27 @@ NS_IMETHODIMP nsMsgHdr::GetMime2DecodedS
 }
 
 NS_IMETHODIMP nsMsgHdr::GetMime2DecodedRecipients(nsAString &resultRecipients)
 {
   return m_mdb->RowCellColumnToMime2DecodedString(GetMDBRow(), m_mdb->m_recipientsColumnToken, resultRecipients);
 }
 
 
-NS_IMETHODIMP nsMsgHdr::GetAuthorCollationKey(PRUint8 **resultAuthor, PRUint32 *len)
+NS_IMETHODIMP nsMsgHdr::GetAuthorCollationKey(PRUint32 *len, PRUint8 **resultAuthor)
 {
   return m_mdb->RowCellColumnToAddressCollationKey(GetMDBRow(), m_mdb->m_senderColumnToken, resultAuthor, len);
 }
 
-NS_IMETHODIMP nsMsgHdr::GetSubjectCollationKey(PRUint8 **resultSubject, PRUint32 *len)
+NS_IMETHODIMP nsMsgHdr::GetSubjectCollationKey(PRUint32 *len, PRUint8 **resultSubject)
 {
   return m_mdb->RowCellColumnToCollationKey(GetMDBRow(), m_mdb->m_subjectColumnToken, resultSubject, len);
 }
 
-NS_IMETHODIMP nsMsgHdr::GetRecipientsCollationKey(PRUint8 **resultRecipients, PRUint32 *len)
+NS_IMETHODIMP nsMsgHdr::GetRecipientsCollationKey(PRUint32 *len, PRUint8 **resultRecipients)
 {
   return m_mdb->RowCellColumnToCollationKey(GetMDBRow(), m_mdb->m_recipientsColumnToken, resultRecipients, len);
 }
 
 NS_IMETHODIMP nsMsgHdr::GetCharset(char **aCharset)
 {
   return m_mdb->RowCellColumnToCharPtr(GetMDBRow(), m_mdb->m_messageCharSetColumnToken, aCharset);
 }
--- a/mailnews/db/msgdb/src/nsNewsDatabase.cpp
+++ b/mailnews/db/msgdb/src/nsNewsDatabase.cpp
@@ -248,17 +248,18 @@ PRBool nsNewsDatabase::SetHdrReadFlag(ns
 
         rv = NotifyReadChanged(nsnull);
         if (NS_FAILED(rv)) return PR_FALSE;
       }
     }
     return PR_TRUE;
 }
 
-NS_IMETHODIMP nsNewsDatabase::MarkAllRead(nsTArray<nsMsgKey> *thoseMarked)
+NS_IMETHODIMP nsNewsDatabase::MarkAllRead(PRUint32 *aNumMarked,
+                                          nsMsgKey **aThoseMarked)
 {
   nsMsgKey lowWater = nsMsgKey_None, highWater;
   nsCString knownArts;
   if (m_dbFolderInfo)
   {
     m_dbFolderInfo->GetKnownArtsSet(getter_Copies(knownArts));
     nsMsgKeySet *knownKeys = nsMsgKeySet::Create(knownArts.get());
     if (knownKeys)
@@ -266,17 +267,17 @@ NS_IMETHODIMP nsNewsDatabase::MarkAllRea
 
     delete knownKeys;
   }
   if (lowWater == nsMsgKey_None)
     GetLowWaterArticleNum(&lowWater);
   GetHighWaterArticleNum(&highWater);
   if (lowWater > 2)
     m_readSet->AddRange(1, lowWater - 1);
-  nsresult err = nsMsgDatabase::MarkAllRead(thoseMarked);
+  nsresult err = nsMsgDatabase::MarkAllRead(aNumMarked, aThoseMarked);
   if (NS_SUCCEEDED(err) && 1 <= highWater)
     m_readSet->AddRange(1, highWater); // mark everything read in newsrc.
 
   return err;
 }
 
 nsresult nsNewsDatabase::SyncWithReadSet()
 {
--- a/mailnews/imap/src/nsAutoSyncState.cpp
+++ b/mailnews/imap/src/nsAutoSyncState.cpp
@@ -33,16 +33,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsAutoSyncState.h"
 #include "nsImapMailFolder.h"
 #include "nsMsgImapCID.h"
 #include "nsIMsgMailNewsUrl.h"
+#include "nsMsgKeyArray.h"
 #include "nsIMsgWindow.h"
 #include "nsIMsgMailSession.h"
 #include "nsMsgFolderFlags.h"
 #include "nsIAutoSyncManager.h"
 #include "nsIAutoSyncMsgStrategy.h"
 #include "nsServiceManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 
@@ -363,18 +364,20 @@ NS_IMETHODIMP nsAutoSyncState::ProcessEx
   nsCOMPtr<nsIMsgDatabase> database;
   rv = folder->GetMsgDatabase(getter_AddRefs(database));
   if (!database)
     return NS_ERROR_FAILURE;
 
   // create a queue to process existing headers for the first time
   if (mExistingHeadersQ.IsEmpty())
   {
-    rv = database->ListAllKeys(mExistingHeadersQ);
+    nsRefPtr<nsMsgKeyArray> keys = new nsMsgKeyArray;
+    rv = database->ListAllKeys(keys);
     NS_ENSURE_SUCCESS(rv, rv);
+    mExistingHeadersQ.AppendElements(keys->m_keys);
     mProcessPointer = 0;
   }
 
   // process the existing headers and find the messages not downloaded yet
   PRUint32 lastIdx = mProcessPointer;
   nsTArray<nsMsgKey> msgKeys;
   PRUint32 keyCount = mExistingHeadersQ.Length();
   for (; mProcessPointer < (lastIdx + aNumOfHdrsToProcess) && mProcessPointer < keyCount; mProcessPointer++)
--- a/mailnews/imap/src/nsImapMailFolder.cpp
+++ b/mailnews/imap/src/nsImapMailFolder.cpp
@@ -59,16 +59,17 @@
 #include "nsMsgFolderFlags.h"
 #include "nsImapFlagAndUidState.h"
 #include "nsISeekableStream.h"
 #include "nsThreadUtils.h"
 #include "nsIImapUrl.h"
 #include "nsImapUtils.h"
 #include "nsMsgUtils.h"
 #include "nsIMsgMailSession.h"
+#include "nsMsgKeyArray.h"
 #include "nsMsgBaseCID.h"
 #include "nsMsgLocalCID.h"
 #include "nsImapUndoTxn.h"
 #include "nsIIMAPHostSessionList.h"
 #include "nsIMsgCopyService.h"
 #include "nsICopyMsgStreamListener.h"
 #include "nsImapStringBundle.h"
 #include "nsIMsgFolderCacheElement.h"
@@ -1949,63 +1950,49 @@ nsImapMailFolder::SetLabelForMessages(ns
 }
 
 NS_IMETHODIMP
 nsImapMailFolder::MarkAllMessagesRead(nsIMsgWindow *aMsgWindow)
 {
   nsresult rv = GetDatabase();
   if(NS_SUCCEEDED(rv))
   {
-    nsTArray<nsMsgKey> thoseMarked;
+    nsMsgKey *thoseMarked;
+    PRUint32 numMarked;
     EnableNotifications(allMessageCountNotifications, PR_FALSE, PR_TRUE /*dbBatching*/);
-    rv = mDatabase->MarkAllRead(&thoseMarked);
+    rv = mDatabase->MarkAllRead(&numMarked, &thoseMarked);
     EnableNotifications(allMessageCountNotifications, PR_TRUE, PR_TRUE /*dbBatching*/);
     if (NS_SUCCEEDED(rv))
     {
-      rv = StoreImapFlags(kImapMsgSeenFlag, PR_TRUE, thoseMarked.Elements(),
-                          thoseMarked.Length(), nsnull);
+      rv = StoreImapFlags(kImapMsgSeenFlag, PR_TRUE, thoseMarked,
+                          numMarked, nsnull);
       mDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
-      
+
       // Setup a undo-state
       if (aMsgWindow)
-      {
-        nsRefPtr<nsMsgReadStateTxn> readStateTxn = new nsMsgReadStateTxn();    
-        if (!readStateTxn)
-          return NS_ERROR_OUT_OF_MEMORY;
-        
-        rv = readStateTxn->Init(this, thoseMarked);
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        rv = readStateTxn->SetTransactionType(nsIMessenger::eMarkAllMsg);
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        nsCOMPtr<nsITransactionManager> txnMgr;
-        rv = aMsgWindow->GetTransactionManager(getter_AddRefs(txnMgr));
-        NS_ENSURE_SUCCESS(rv, rv);
-        
-        rv = txnMgr->DoTransaction(readStateTxn);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
+        rv = AddMarkAllReadUndoAction(aMsgWindow, thoseMarked, numMarked);
+      nsMemory::Free(thoseMarked);
     }
   }
   return rv;
 }
 
 NS_IMETHODIMP nsImapMailFolder::MarkThreadRead(nsIMsgThread *thread)
 {
   nsresult rv = GetDatabase();
   if(NS_SUCCEEDED(rv))
   {
-    nsTArray<nsMsgKey> thoseMarked;
-    rv = mDatabase->MarkThreadRead(thread, nsnull, &thoseMarked);
+    nsMsgKey *keys;
+    PRUint32 numKeys;
+    rv = mDatabase->MarkThreadRead(thread, nsnull, &numKeys, &keys);
     if (NS_SUCCEEDED(rv))
     {
-      rv = StoreImapFlags(kImapMsgSeenFlag, PR_TRUE, thoseMarked.Elements(),
-                          thoseMarked.Length(), nsnull);
+      rv = StoreImapFlags(kImapMsgSeenFlag, PR_TRUE, keys, numKeys, nsnull);
       mDatabase->Commit(nsMsgDBCommitType::kLargeCommit);
+      nsMemory::Free(keys);
     }
   }
   return rv;
 }
 
 
 NS_IMETHODIMP nsImapMailFolder::ReadFromFolderCacheElem(nsIMsgFolderCacheElement *element)
 {
@@ -2721,18 +2708,23 @@ NS_IMETHODIMP nsImapMailFolder::UpdateIm
     {
       dbFolderInfo->GetImapUidValidity(&imapUIDValidity);
       PRUint64 mailboxHighestModSeq;
       aSpec->GetHighestModSeq(&mailboxHighestModSeq);
       char intStrBuf[40];
       PR_snprintf(intStrBuf, sizeof(intStrBuf), "%llu",  mailboxHighestModSeq);
       dbFolderInfo->SetCharProperty(kModSeqPropertyName, nsDependentCString(intStrBuf));
     }
-    mDatabase->ListAllKeys(existingKeys);
-    PRInt32 keyCount = existingKeys.Length();
+    nsRefPtr<nsMsgKeyArray> keys = new nsMsgKeyArray;
+    if (!keys)
+      return NS_ERROR_OUT_OF_MEMORY;
+    rv = mDatabase->ListAllKeys(keys);
+    NS_ENSURE_SUCCESS(rv, rv);
+    existingKeys.AppendElements(keys->m_keys);
+    PRUint32 keyCount = existingKeys.Length();
     mDatabase->ListAllOfflineDeletes(&existingKeys);
     if (keyCount < existingKeys.Length())
       existingKeys.Sort();
   }
   PRInt32 folderValidity;
   aSpec->GetFolder_UIDVALIDITY(&folderValidity);
   nsCOMPtr <nsIImapFlagAndUidState> flagState;
   aSpec->GetFlagState(getter_AddRefs(flagState));
--- a/mailnews/imap/src/nsImapService.cpp
+++ b/mailnews/imap/src/nsImapService.cpp
@@ -764,25 +764,27 @@ NS_IMETHODIMP nsImapService::CopyMessage
         imapAction = nsIImapUrl::nsImapOnlineToOfflineMove; 
       rv = FetchMessage(imapUrl,imapAction, folder, imapMessageSink,aMsgWindow, 
                         streamSupport, msgKey, PR_FALSE, EmptyCString(), aURL);
     } // if we got an imap message sink
   } // if we decomposed the imap message 
   return rv;
 }
 
-NS_IMETHODIMP nsImapService::CopyMessages(nsTArray<nsMsgKey> &keys, 
-                                          nsIMsgFolder *srcFolder, 
-                                          nsIStreamListener *aMailboxCopy, 
+NS_IMETHODIMP nsImapService::CopyMessages(PRUint32 aNumKeys,
+                                          nsMsgKey*aKeys,
+                                          nsIMsgFolder *srcFolder,
+                                          nsIStreamListener *aMailboxCopy,
                                           PRBool moveMessage,
-                                          nsIUrlListener *aUrlListener, 
+                                          nsIUrlListener *aUrlListener,
                                           nsIMsgWindow *aMsgWindow, 
                                           nsIURI **aURL)
 {
   NS_ENSURE_ARG_POINTER(aMailboxCopy);
+  NS_ENSURE_ARG_POINTER(aKeys);
 
   nsresult rv;
   nsCOMPtr<nsISupports> streamSupport = do_QueryInterface(aMailboxCopy, &rv);
   if (!streamSupport || NS_FAILED(rv)) 
     return rv;
   
   nsCOMPtr<nsIMsgFolder> folder = srcFolder;
   nsCAutoString msgKey;
@@ -790,21 +792,20 @@ NS_IMETHODIMP nsImapService::CopyMessage
   {
     nsCOMPtr<nsIImapMessageSink> imapMessageSink(do_QueryInterface(folder, &rv));
     if (NS_SUCCEEDED(rv))
     {
       // we generate the uri for the first message so that way on down the line,
       // GetMessage in nsCopyMessageStreamListener will get an unescaped username
       // and be able to find the msg hdr. See bug 259656 for details
       nsCString uri;
-      srcFolder->GenerateMessageURI(keys[0], uri);
+      srcFolder->GenerateMessageURI(aKeys[0], uri);
 
       nsCString messageIds;
-      PRUint32 numKeys = keys.Length();
-      AllocateImapUidString(keys.Elements(), numKeys, nsnull, messageIds);
+      AllocateImapUidString(aKeys, aNumKeys, nsnull, messageIds);
       nsCOMPtr<nsIImapUrl> imapUrl;
       nsCAutoString urlSpec;
       char hierarchyDelimiter = GetHierarchyDelimiter(folder);
       rv = CreateStartOfImapUrl(uri, getter_AddRefs(imapUrl), folder, aUrlListener, urlSpec, hierarchyDelimiter);
       nsImapAction action;
       if (moveMessage) // don't use ?: syntax here, it seems to break the Mac.
         action = nsIImapUrl::nsImapOnlineToOfflineMove;
       else
--- a/mailnews/local/src/nsLocalMailFolder.cpp
+++ b/mailnews/local/src/nsLocalMailFolder.cpp
@@ -3016,17 +3016,21 @@ nsresult nsMsgLocalMailFolder::CopyMessa
     // before starting the next message. Only do this if the source folder
     // is a local folder, however. IMAP will handle calling StartMessage for
     // each message that gets downloaded, and news doesn't go through here
     // because news only downloads one message at a time, and this routine
     // is for multiple message copy.
     nsCOMPtr <nsIMsgLocalMailFolder> srcLocalFolder = do_QueryInterface(srcFolder);
     if (srcLocalFolder)
       StartMessage();
-    rv = mCopyState->m_messageService->CopyMessages(keyArray, srcFolder, streamListener, isMove, nsnull, aMsgWindow, nsnull);
+    rv = mCopyState->m_messageService->CopyMessages(keyArray.Length(),
+                                                    keyArray.Elements(),
+                                                    srcFolder, streamListener,
+                                                    isMove, nsnull, aMsgWindow,
+                                                    nsnull);
   }
   return rv;
 }
 
 nsresult nsMsgLocalMailFolder::CopyMessageTo(nsISupports *message,
                                              nsIMsgFolder *dstFolder /* dst same as "this" */,
                                              nsIMsgWindow *aMsgWindow,
                                              PRBool isMove)
--- a/mailnews/local/src/nsMailboxService.cpp
+++ b/mailnews/local/src/nsMailboxService.cpp
@@ -120,52 +120,54 @@ nsresult nsMailboxService::CopyMessage(c
                               nsIURI **aURL)
 {
     nsMailboxAction mailboxAction = nsIMailboxUrl::ActionMoveMessage;
     if (!moveMessage)
         mailboxAction = nsIMailboxUrl::ActionCopyMessage;
   return FetchMessage(aSrcMailboxURI, aMailboxCopyHandler, aMsgWindow, aUrlListener, nsnull, mailboxAction, nsnull, aURL);
 }
 
-nsresult nsMailboxService::CopyMessages(nsTArray<nsMsgKey> &msgKeys,
-                              nsIMsgFolder *srcFolder,
-                              nsIStreamListener * aMailboxCopyHandler,
-                              PRBool moveMessage,
-                              nsIUrlListener * aUrlListener,
-                              nsIMsgWindow *aMsgWindow,
-                              nsIURI **aURL)
+nsresult nsMailboxService::CopyMessages(PRUint32 aNumKeys,
+                                        nsMsgKey* aMsgKeys,
+                                        nsIMsgFolder *srcFolder,
+                                        nsIStreamListener * aMailboxCopyHandler,
+                                        PRBool moveMessage,
+                                        nsIUrlListener * aUrlListener,
+                                        nsIMsgWindow *aMsgWindow,
+                                        nsIURI **aURL)
 {
   nsresult rv = NS_OK;
   NS_ENSURE_ARG(srcFolder);
+  NS_ENSURE_ARG(aMsgKeys);
   nsCOMPtr<nsIMailboxUrl> mailboxurl;
 
   nsMailboxAction actionToUse = nsIMailboxUrl::ActionMoveMessage;
   if (!moveMessage)
      actionToUse = nsIMailboxUrl::ActionCopyMessage;
 
   nsCOMPtr <nsIMsgDBHdr> msgHdr;
   nsCOMPtr <nsIMsgDatabase> db;
   srcFolder->GetMsgDatabase(getter_AddRefs(db));
   if (db)
   {
-    db->GetMsgHdrForKey(msgKeys[0], getter_AddRefs(msgHdr));
+    db->GetMsgHdrForKey(aMsgKeys[0], getter_AddRefs(msgHdr));
     if (msgHdr)
     {
       nsCString uri;
       srcFolder->GetUriForMsg(msgHdr, uri);
       rv = PrepareMessageUrl(uri.get(), aUrlListener, actionToUse , getter_AddRefs(mailboxurl), aMsgWindow);
 
       if (NS_SUCCEEDED(rv))
       {
         nsCOMPtr<nsIURI> url = do_QueryInterface(mailboxurl);
         nsCOMPtr<nsIMsgMailNewsUrl> msgUrl (do_QueryInterface(url));
         nsCOMPtr<nsIMailboxUrl> mailboxUrl (do_QueryInterface(url));
         msgUrl->SetMsgWindow(aMsgWindow);
 
-        mailboxUrl->SetMoveCopyMsgKeys(msgKeys.Elements(), msgKeys.Length());
+        mailboxUrl->SetMoveCopyMsgKeys(aMsgKeys, aNumKeys);
         rv = RunMailboxUrl(url, aMailboxCopyHandler);
       }
     }
   }
   if (aURL && mailboxurl)
     CallQueryInterface(mailboxurl, aURL);
 
   return rv;
--- a/mailnews/local/src/nsPop3IncomingServer.cpp
+++ b/mailnews/local/src/nsPop3IncomingServer.cpp
@@ -43,16 +43,18 @@
 #include "nsIStringBundle.h"
 #include "nsIPop3IncomingServer.h"
 #include "nsPop3IncomingServer.h"
 #include "nsIPop3Service.h"
 #include "nsMsgBaseCID.h"
 #include "nsMsgLocalCID.h"
 #include "nsMsgFolderFlags.h"
 #include "nsPop3Protocol.h"
+#include "nsAutoPtr.h"
+#include "nsMsgKeyArray.h"
 #include "nsIMsgLocalMailFolder.h"
 #include "nsIMsgAccountManager.h"
 #include "nsIMsgMailNewsUrl.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIMutableArray.h"
 #include "nsMsgUtils.h"
 #include "nsComponentManagerUtils.h"
 
@@ -188,20 +190,20 @@ NS_IMETHODIMP nsPop3IncomingServer::GetD
               if (subFolder)
               {
                 nsCOMPtr<nsIMsgDatabase> subFolderDB;
                 subFolder->GetMsgDatabase(getter_AddRefs(subFolderDB));
                 if (subFolderDB)
                 {
                   // Copy any messages in this sub-folder of the hidden
                   // account to the corresponding folder in Local Folders.
-                  nsTArray<nsMsgKey> keys;
+                  nsRefPtr<nsMsgKeyArray> keys = new nsMsgKeyArray;
                   rv = subFolderDB->ListAllKeys(keys);
                   nsCOMPtr<nsIMutableArray> hdrsToCopy(do_CreateInstance(NS_ARRAY_CONTRACTID));
-                  MsgGetHeadersFromKeys(subFolderDB, keys, hdrsToCopy);
+                  MsgGetHeadersFromKeys(subFolderDB, keys->m_keys, hdrsToCopy);
                   PRUint32 numHdrs = 0;
                   if (hdrsToCopy)
                     hdrsToCopy->GetLength(&numHdrs);
                   if (numHdrs)
                   {
                     // Look for a folder with the same name in Local Folders.
                     nsCOMPtr<nsIMsgFolder> dest;
                     nsString folderName;
--- a/mailnews/mapi/mapihook/src/msgMapiImp.cpp
+++ b/mailnews/mapi/mapihook/src/msgMapiImp.cpp
@@ -52,16 +52,17 @@
 #include "msgMapiHook.h"
 #include "nsStringGlue.h"
 #include "nsCOMPtr.h"
 #include "nsISupports.h"
 #include "nsMsgCompCID.h"
 #include "nsIMsgDatabase.h"
 #include "nsMsgFolderFlags.h"
 #include "nsIMsgHdr.h"
+#include "MailNewsTypes.h"
 #include "nsMsgBaseCID.h"
 #include "nsIMsgAccountManager.h"
 #include "nsIMsgFolder.h"
 #include "nsIMsgImapMailFolder.h"
 #include <time.h>
 #include "nsIInputStream.h"
 #include "nsIMsgHeaderParser.h"
 #include "nsILineInputStream.h"
--- a/mailnews/news/src/nsNNTPArticleList.cpp
+++ b/mailnews/news/src/nsNNTPArticleList.cpp
@@ -35,16 +35,18 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "msgCore.h"    // precompiled header...
 
 #include "nsCOMPtr.h"
 #include "nsNNTPArticleList.h"
 #include "nsIMsgFolder.h"
+#include "nsAutoPtr.h"
+#include "nsMsgKeyArray.h"
 
 NS_IMPL_ISUPPORTS1(nsNNTPArticleList, nsINNTPArticleList)
 
 nsNNTPArticleList::nsNNTPArticleList()
 {
 }
 
 nsNNTPArticleList::~nsNNTPArticleList()
@@ -70,18 +72,20 @@ nsNNTPArticleList::Initialize(nsIMsgNews
 
     nsCOMPtr <nsIMsgFolder> folder = do_QueryInterface(m_newsFolder, &rv);
     NS_ENSURE_SUCCESS(rv,rv);
 
     rv = folder->GetMsgDatabase(getter_AddRefs(m_newsDB));
     NS_ENSURE_SUCCESS(rv,rv);
     if (!m_newsDB) return NS_ERROR_UNEXPECTED;
 
-    rv = m_newsDB->ListAllKeys(m_idsInDB);
+    nsRefPtr<nsMsgKeyArray> keys = new nsMsgKeyArray;
+    rv = m_newsDB->ListAllKeys(keys);
     NS_ENSURE_SUCCESS(rv,rv);
+    m_idsInDB.AppendElements(keys->m_keys);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNNTPArticleList::AddArticleKey(PRInt32 key)
 {
 #ifdef DEBUG
--- a/mailnews/news/src/nsNewsFolder.cpp
+++ b/mailnews/news/src/nsNewsFolder.cpp
@@ -1678,17 +1678,17 @@ NS_IMETHODIMP nsMsgNewsFolder::RemoveMes
   }
   return mDatabase->DeleteMessage(key, nsnull, PR_FALSE);
 }
 
 NS_IMETHODIMP nsMsgNewsFolder::RemoveMessages(nsTArray<nsMsgKey> &aMsgKeys)
 {
   nsresult rv = GetDatabase();
   NS_ENSURE_SUCCESS(rv, rv); // if GetDatabase succeeds, mDatabase will be non-null
-  
+
   // Notify listeners of a multiple message delete
   nsCOMPtr<nsIMsgFolderNotificationService> notifier(do_GetService(NS_MSGNOTIFICATIONSERVICE_CONTRACTID));
 
   if (notifier)
   {
     nsCOMPtr<nsIMutableArray> msgHdrs(do_CreateInstance(NS_ARRAY_CONTRACTID));
     rv = MsgGetHeadersFromKeys(mDatabase, aMsgKeys, msgHdrs);
     NS_ENSURE_SUCCESS(rv, rv);
--- a/mailnews/news/src/nsNntpService.cpp
+++ b/mailnews/news/src/nsNntpService.cpp
@@ -711,18 +711,23 @@ nsNntpService::CopyMessage(const char * 
   nsCOMPtr<nsISupports> streamSupport = do_QueryInterface(aMailboxCopyHandler, &rv);
   NS_ENSURE_SUCCESS(rv,rv);
 
   rv = DisplayMessage(aSrcMessageURI, streamSupport, aMsgWindow, aUrlListener, nsnull, aURL);
   return rv;
 }
 
 NS_IMETHODIMP
-nsNntpService::CopyMessages(nsTArray<nsMsgKey> &keys, nsIMsgFolder *srcFolder, nsIStreamListener * aMailboxCopyHandler, PRBool moveMessage,
-               nsIUrlListener * aUrlListener, nsIMsgWindow *aMsgWindow, nsIURI **aURL)
+nsNntpService::CopyMessages(PRUint32 aNumKeys, nsMsgKey *akeys,
+                            nsIMsgFolder *srcFolder,
+                            nsIStreamListener * aMailboxCopyHandler,
+                            PRBool moveMessage,
+                            nsIUrlListener * aUrlListener,
+                            nsIMsgWindow *aMsgWindow,
+                            nsIURI **aURL)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 struct findNewsServerEntry {
   const char *newsgroup;
   nsINntpIncomingServer *server;
 };