Bug 430716 part 4, add MsgFolder to JsAccount, r=aceman
authorR Kent James <rkent@caspia.com>
Wed, 22 Jun 2016 11:30:53 -0700
changeset 19322 bae6bffb1690d4471dd184559fdcfa4f0ca4bc8c
parent 19321 8aeec6f9db8949f2d6913624d227f0dd688d7049
child 19323 0a57791823f5e60794cb19d657ca80be374aa559
push id1725
push userclokep@gmail.com
push dateMon, 19 Sep 2016 17:35:08 +0000
treeherdercomm-esr52@c616ae59d075 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaceman
bugs430716
Bug 430716 part 4, add MsgFolder to JsAccount, r=aceman
mailnews/base/public/nsIMsgIncomingServer.idl
mailnews/base/util/nsMsgIncomingServer.cpp
mailnews/build/nsMailModule.cpp
mailnews/db/msgdb/src/nsMsgDatabase.cpp
mailnews/imap/src/nsImapIncomingServer.cpp
mailnews/imap/src/nsImapIncomingServer.h
mailnews/jsaccount/public/msgJsAccountCID.h
mailnews/jsaccount/src/JaMsgFolder.cpp
mailnews/jsaccount/src/JaMsgFolder.h
mailnews/jsaccount/src/moz.build
mailnews/jsaccount/test/moz.build
mailnews/jsaccount/test/unit/resources/testComponents.manifest
mailnews/jsaccount/test/unit/resources/testJaBaseIncomingServer.jsm
mailnews/jsaccount/test/unit/resources/testJaBaseIncomingServerComponent.js
mailnews/jsaccount/test/unit/resources/testJaBaseMsgFolder.jsm
mailnews/jsaccount/test/unit/resources/testJaBaseMsgFolderComponent.js
mailnews/jsaccount/test/unit/resources/testJaMsgProtocolInfoComponent.js
mailnews/jsaccount/test/unit/test_componentsExist.js
mailnews/jsaccount/test/unit/test_jaMsgFolder.js
mailnews/jsaccount/test/unit/xpcshell.ini
mailnews/local/src/nsMailboxServer.cpp
mailnews/local/src/nsMailboxServer.h
mailnews/local/src/nsNoIncomingServer.cpp
mailnews/local/src/nsNoIncomingServer.h
mailnews/news/src/nsNntpIncomingServer.cpp
mailnews/news/src/nsNntpIncomingServer.h
--- a/mailnews/base/public/nsIMsgIncomingServer.idl
+++ b/mailnews/base/public/nsIMsgIncomingServer.idl
@@ -22,17 +22,17 @@ interface nsIURI;
 interface nsIMsgPluggableStore;
 
 /*
  * Interface for incoming mail/news host
  * this is the base interface for all mail server types (imap, pop, nntp, etc)
  * often you will want to add extra interfaces that give you server-specific
  * attributes and methods.
  */
-[scriptable, uuid(92f4ee31-a14d-48dc-8676-22417caefa84)]
+[scriptable, uuid(aa9a3389-9dac-41f1-9ec5-18287cfaa47c)]
 interface nsIMsgIncomingServer : nsISupports {
 
   /**
    * internal pref key - guaranteed to be unique across all servers
    */
   attribute ACString key;
 
   /**
@@ -79,22 +79,30 @@ interface nsIMsgIncomingServer : nsISupp
   /**
    * The proper instance of nsIMsgProtocolInfo corresponding to this server type.
    */
   readonly attribute nsIMsgProtocolInfo protocolInfo;
 
   readonly attribute AString accountManagerChrome;
 
   /**
-   * the schema for the local mail store, such
-   * as "mailbox", "imap", or "news"
-   * used to construct URIs
+   * The schema for the local mail store, such as "mailbox", "imap", or "news"
+   * used to construct URIs. The contractID for the nsIMsgMessageService
+   * implementation that will manage access to messages associated with this
+   * server is constructed using this type.
    */
   readonly attribute ACString localStoreType;
 
+  /**
+   * The schema for the nsIMsgDatabase implementation, such as "mailbox" or
+   * "imap", that will be used to construct the database instance used by
+   * message folders associated with this server.
+   */
+  readonly attribute ACString localDatabaseType;
+
   // Perform specific tasks (reset flags, remove files, etc) for account user/server name changes.
   void onUserOrHostNameChanged(in ACString oldName, in ACString newName,
                                in bool hostnameChanged);
 
   /* cleartext version of the password */
   attribute ACString password;
 
   /**
--- a/mailnews/base/util/nsMsgIncomingServer.cpp
+++ b/mailnews/base/util/nsMsgIncomingServer.cpp
@@ -969,16 +969,23 @@ nsMsgIncomingServer::SetLocalPath(nsIFil
 NS_IMETHODIMP
 nsMsgIncomingServer::GetLocalStoreType(nsACString& aResult)
 {
   NS_NOTYETIMPLEMENTED("nsMsgIncomingServer superclass not implementing GetLocalStoreType!");
   return NS_ERROR_UNEXPECTED;
 }
 
 NS_IMETHODIMP
+nsMsgIncomingServer::GetLocalDatabaseType(nsACString& aResult)
+{
+  NS_NOTYETIMPLEMENTED("nsMsgIncomingServer superclass not implementing GetLocalDatabaseType!");
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
 nsMsgIncomingServer::GetAccountManagerChrome(nsAString& aResult)
 {
   aResult.AssignLiteral("am-main.xul");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsMsgIncomingServer::Equals(nsIMsgIncomingServer *server, bool *_retval)
--- a/mailnews/build/nsMailModule.cpp
+++ b/mailnews/build/nsMailModule.cpp
@@ -191,16 +191,17 @@
 #include "nsMsgCompUtils.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 //  jsAccount includes
 ////////////////////////////////////////////////////////////////////////////////
 #include "msgJsAccountCID.h"
 #include "JaAbDirectory.h"
 #include "JaIncomingServer.h"
+#include "JaMsgFolder.h"
 #include "JaUrl.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 // imap includes
 ////////////////////////////////////////////////////////////////////////////////
 #include "nsMsgImapCID.h"
 #include "nsIMAPHostSessionList.h"
 #include "nsImapIncomingServer.h"
@@ -593,20 +594,22 @@ NS_DEFINE_NAMED_CID(NS_MSGQUOTELISTENER_
 NS_DEFINE_NAMED_CID(NS_URLFETCHER_CID);
 NS_DEFINE_NAMED_CID(NS_MSGCOMPUTILS_CID);
 
 ////////////////////////////////////////////////////////////////////////////////
 // jsAccount factories
 ////////////////////////////////////////////////////////////////////////////////
 NS_GENERIC_FACTORY_CONSTRUCTOR(JaCppAbDirectoryDelegator)
 NS_GENERIC_FACTORY_CONSTRUCTOR(JaCppIncomingServerDelegator)
+NS_GENERIC_FACTORY_CONSTRUCTOR(JaCppMsgFolderDelegator)
 NS_GENERIC_FACTORY_CONSTRUCTOR(JaCppUrlDelegator)
 
 NS_DEFINE_NAMED_CID(JACPPABDIRECTORYDELEGATOR_CID);
 NS_DEFINE_NAMED_CID(JACPPINCOMINGSERVERDELEGATOR_CID);
+NS_DEFINE_NAMED_CID(JACPPMSGFOLDERDELEGATOR_CID);
 NS_DEFINE_NAMED_CID(JACPPURLDELEGATOR_CID);
 
 ////////////////////////////////////////////////////////////////////////////////
 // imap factories
 ////////////////////////////////////////////////////////////////////////////////
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsImapUrl)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsImapProtocol)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsIMAPHostSessionList, Init)
@@ -986,16 +989,17 @@ const mozilla::Module::CIDEntry kMailNew
   { &kNS_MSGQUOTE_CID, false, NULL, nsMsgQuoteConstructor},
   { &kNS_MSGQUOTELISTENER_CID, false, NULL, nsMsgQuoteListenerConstructor},
   { &kNS_URLFETCHER_CID, false, NULL, nsURLFetcherConstructor},
   { &kNS_MSGCOMPUTILS_CID, false, NULL, nsMsgCompUtilsConstructor},
   // JsAccount Entries
   { &kJACPPURLDELEGATOR_CID, false, nullptr, JaCppUrlDelegatorConstructor },
   { &kJACPPABDIRECTORYDELEGATOR_CID, false, nullptr, JaCppAbDirectoryDelegatorConstructor },
   { &kJACPPINCOMINGSERVERDELEGATOR_CID, false, nullptr, JaCppIncomingServerDelegatorConstructor },
+  { &kJACPPMSGFOLDERDELEGATOR_CID, false, nullptr, JaCppMsgFolderDelegatorConstructor },
   // Imap Entries
   { &kNS_IMAPURL_CID, false, NULL, nsImapUrlConstructor },
   { &kNS_IMAPPROTOCOL_CID, false, nullptr, nsImapProtocolConstructor },
   { &kNS_IMAPMOCKCHANNEL_CID, false, nullptr, nsImapMockChannelConstructor },
   { &kNS_IIMAPHOSTSESSIONLIST_CID, false, nullptr, nsIMAPHostSessionListConstructor },
   { &kNS_IMAPINCOMINGSERVER_CID, false, nullptr, nsImapIncomingServerConstructor },
   { &kNS_IMAPRESOURCE_CID, false, nullptr, nsImapMailFolderConstructor },
   { &kNS_IMAPSERVICE_CID, false, nullptr, nsImapServiceConstructor },
@@ -1206,16 +1210,17 @@ const mozilla::Module::ContractIDEntry k
   { NS_MSGQUOTE_CONTRACTID, &kNS_MSGQUOTE_CID },
   { NS_MSGQUOTELISTENER_CONTRACTID, &kNS_MSGQUOTELISTENER_CID },
   { NS_URLFETCHER_CONTRACTID, &kNS_URLFETCHER_CID },
   { NS_MSGCOMPUTILS_CONTRACTID, &kNS_MSGCOMPUTILS_CID },
   // JsAccount Entries
   { JACPPURLDELEGATOR_CONTRACTID, &kJACPPURLDELEGATOR_CID },
   { JACPPABDIRECTORYDELEGATOR_CONTRACTID, &kJACPPABDIRECTORYDELEGATOR_CID },
   { JACPPINCOMINGSERVERDELEGATOR_CONTRACTID, &kJACPPINCOMINGSERVERDELEGATOR_CID },
+  { JACPPMSGFOLDERDELEGATOR_CONTRACTID, &kJACPPMSGFOLDERDELEGATOR_CID },
   // Imap Entries
   { NS_IMAPINCOMINGSERVER_CONTRACTID, &kNS_IMAPINCOMINGSERVER_CID },
   { NS_RDF_RESOURCE_FACTORY_CONTRACTID_PREFIX "imap", &kNS_IMAPRESOURCE_CID },
   { "@mozilla.org/messenger/messageservice;1?type=imap-message", &kNS_IMAPSERVICE_CID },
   { "@mozilla.org/messenger/messageservice;1?type=imap", &kNS_IMAPSERVICE_CID },
   { NS_IMAPSERVICE_CONTRACTID, &kNS_IMAPSERVICE_CID },
   { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "imap", &kNS_IMAPSERVICE_CID },
   { NS_IMAPPROTOCOLINFO_CONTRACTID, &kNS_IMAPSERVICE_CID },
--- a/mailnews/db/msgdb/src/nsMsgDatabase.cpp
+++ b/mailnews/db/msgdb/src/nsMsgDatabase.cpp
@@ -116,20 +116,20 @@ NS_IMETHODIMP nsMsgDBService::OpenFolder
     *_retval = cacheDB; // FindInCache already addRefed.
     // if m_thumb is set, someone is asynchronously opening the db. But our
     // caller wants to synchronously open it, so just do it.
     if (cacheDB->m_thumb)
       return cacheDB->Open(this, summaryFilePath, false, aLeaveInvalidDB);
     return NS_OK;
   }
 
-  nsCString localStoreType;
-  incomingServer->GetLocalStoreType(localStoreType);
+  nsCString localDatabaseType;
+  incomingServer->GetLocalDatabaseType(localDatabaseType);
   nsAutoCString dbContractID(NS_MSGDB_CONTRACTID);
-  dbContractID.Append(localStoreType.get());
+  dbContractID.Append(localDatabaseType.get());
   nsCOMPtr <nsIMsgDatabase> msgDB = do_CreateInstance(dbContractID.get(), &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Don't try to create the database yet--let the createNewDB call do that.
   nsMsgDatabase *msgDatabase = static_cast<nsMsgDatabase *>(msgDB.get());
   msgDatabase->m_folder = aFolder;
   rv = msgDatabase->Open(this, summaryFilePath, false, aLeaveInvalidDB);
   if (NS_FAILED(rv) && rv != NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE)
@@ -179,20 +179,20 @@ NS_IMETHODIMP nsMsgDBService::AsyncOpenF
     // We don't care if an other consumer is thumbing the store. In that
     // case, they'll both thumb the store.
     return NS_OK;
   }
 
   nsCOMPtr <nsIMsgIncomingServer> incomingServer;
   rv = aFolder->GetServer(getter_AddRefs(incomingServer));
   NS_ENSURE_SUCCESS(rv, rv);
-  nsCString localStoreType;
-  incomingServer->GetLocalStoreType(localStoreType);
+  nsCString localDatabaseType;
+  incomingServer->GetLocalDatabaseType(localDatabaseType);
   nsAutoCString dbContractID(NS_MSGDB_CONTRACTID);
-  dbContractID.Append(localStoreType.get());
+  dbContractID.Append(localDatabaseType.get());
   nsCOMPtr <nsIMsgDatabase> msgDB = do_CreateInstance(dbContractID.get(), &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsMsgDatabase *msgDatabase = static_cast<nsMsgDatabase *>(msgDB.get());
   rv = msgDatabase->OpenInternal(this, summaryFilePath, false, aLeaveInvalidDB,
                                  false /* open asynchronously */);
 
   NS_ADDREF(*_retval = msgDB);
@@ -373,20 +373,20 @@ NS_IMETHODIMP nsMsgDBService::CreateNewD
   nsCOMPtr <nsIMsgIncomingServer> incomingServer;
   nsresult rv = aFolder->GetServer(getter_AddRefs(incomingServer));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIFile> summaryFilePath;
   rv = aFolder->GetSummaryFile(getter_AddRefs(summaryFilePath));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCString localStoreType;
-  incomingServer->GetLocalStoreType(localStoreType);
+  nsCString localDatabaseType;
+  incomingServer->GetLocalDatabaseType(localDatabaseType);
   nsAutoCString dbContractID(NS_MSGDB_CONTRACTID);
-  dbContractID.Append(localStoreType.get());
+  dbContractID.Append(localDatabaseType.get());
   
   nsCOMPtr <nsIMsgDatabase> msgDB = do_CreateInstance(dbContractID.get(), &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsMsgDatabase *msgDatabase = static_cast<nsMsgDatabase *>(msgDB.get());
 
   msgDatabase->m_folder = aFolder;
   rv = msgDatabase->Open(this, summaryFilePath, true, true);
--- a/mailnews/imap/src/nsImapIncomingServer.cpp
+++ b/mailnews/imap/src/nsImapIncomingServer.cpp
@@ -180,16 +180,22 @@ nsImapIncomingServer::GetConstructedPret
 
 
 NS_IMETHODIMP nsImapIncomingServer::GetLocalStoreType(nsACString& type)
 {
   type.AssignLiteral("imap");
   return NS_OK;
 }
 
+NS_IMETHODIMP nsImapIncomingServer::GetLocalDatabaseType(nsACString& type)
+{
+  type.AssignLiteral("imap");
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 nsImapIncomingServer::GetServerDirectory(nsACString& serverDirectory)
 {
   return GetCharValue("server_sub_directory", serverDirectory);
 }
 
 NS_IMETHODIMP
 nsImapIncomingServer::SetServerDirectory(const nsACString& serverDirectory)
--- a/mailnews/imap/src/nsImapIncomingServer.h
+++ b/mailnews/imap/src/nsImapIncomingServer.h
@@ -31,16 +31,17 @@ class nsImapIncomingServer : public nsMs
 public:
     NS_DECL_ISUPPORTS_INHERITED
 
     nsImapIncomingServer();
 
     // overriding nsMsgIncomingServer methods
   NS_IMETHOD SetKey(const nsACString& aKey) override;  // override nsMsgIncomingServer's implementation...
   NS_IMETHOD GetLocalStoreType(nsACString& type) override;
+  NS_IMETHOD GetLocalDatabaseType(nsACString& type) override;
 
   NS_DECL_NSIIMAPINCOMINGSERVER
   NS_DECL_NSIIMAPSERVERSINK
   NS_DECL_NSISUBSCRIBABLESERVER
   NS_DECL_NSIURLLISTENER
 
   NS_IMETHOD PerformBiff(nsIMsgWindow *aMsgWindow) override;
   NS_IMETHOD PerformExpand(nsIMsgWindow *aMsgWindow) override;
--- a/mailnews/jsaccount/public/msgJsAccountCID.h
+++ b/mailnews/jsaccount/public/msgJsAccountCID.h
@@ -16,9 +16,14 @@
 #define JACPPABDIRECTORYDELEGATOR_CID \
 { 0x77b5592c, 0x5018, 0x436d, { 0xa4, 0x66, 0xc4, 0xe5, 0x44, 0x3a, 0x16, 0x69 } }
 #define JACPPABDIRECTORYDELEGATOR_CONTRACTID "@mozilla.org/jacppabdirectorydelegator;1"
 
 #define JACPPINCOMINGSERVERDELEGATOR_CID \
 { 0x7aa11dd3, 0x5590, 0x4e01, { 0xbd, 0x87, 0x91, 0xf6, 0x02, 0x72, 0xd0, 0x1a } }
 #define JACPPINCOMINGSERVERDELEGATOR_CONTRACTID "@mozilla.org/jacppincomingserverdelegator;1"
 
+#define JACPPMSGFOLDERDELEGATOR_CID \
+{ 0xd6bd81fa, 0xb1d4, 0x424a, { 0x88, 0xea, 0xbb, 0x3e, 0xa8, 0x38, 0x1d, 0x50 } }
+#define JACPPMSGFOLDERDELEGATOR_CONTRACTID "@mozilla.org/jacppmsgfolderdelegator;1"
+
+
 #endif
new file mode 100644
--- /dev/null
+++ b/mailnews/jsaccount/src/JaMsgFolder.cpp
@@ -0,0 +1,207 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "JaMsgFolder.h"
+#include "nsISupportsUtils.h"
+#include "nsMsgBaseCID.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIUUIDGenerator.h"
+#include "nsIComponentRegistrar.h"
+#include "nsMsgDBCID.h"
+
+#define MAILDATABASE_CONTRACTID_BASE "@mozilla.org/nsMsgDatabase/msgDB-"
+
+namespace mozilla {
+namespace mailnews {
+
+NS_IMPL_ISUPPORTS_INHERITED(JaBaseCppMsgFolder, nsMsgDBFolder,
+                            nsIInterfaceRequestor)
+
+// nsIInterfaceRequestor implementation
+NS_IMETHODIMP
+JaBaseCppMsgFolder::GetInterface(const nsIID & aIID, void **aSink)
+{
+  return QueryInterface(aIID, aSink);
+}
+
+// Definition of abstract nsMsgDBFolder methods.
+nsresult
+JaBaseCppMsgFolder::GetDatabase()
+{
+  nsresult rv = NS_OK;
+  if (!mDatabase)
+  {
+
+    nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Create the database, keeping it if it is "out of date"
+    rv = msgDBService->OpenFolderDB(this, true, getter_AddRefs(mDatabase));
+    if (rv == NS_MSG_ERROR_FOLDER_SUMMARY_MISSING)
+    {
+      rv = msgDBService->CreateNewDB(this, getter_AddRefs(mDatabase));
+      NS_ENSURE_STATE(mDatabase);
+      // not sure about this ... the issue is that if the summary is not valid, then
+      //  the db does not get added to the cache in the future, and reindexes
+      //  do not show all of the messages.
+      //mDatabase->SetSummaryValid(true);
+      mDatabase->SetSummaryValid(false);
+      CreateDummyFile(this);
+    }
+
+    if (rv != NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE)
+      NS_ENSURE_SUCCESS(rv, rv);
+    else if (mDatabase)
+    {
+      // Not going to warn here, because on initialization we set all
+      //  databases as invalid.
+      //NS_WARNING("Mail Summary database is out of date");
+      // Grrr, the only way to get this into the cache is to set the db as valid,
+      //  close, reopen, then set as invalid.
+      mDatabase->SetSummaryValid(true);
+      msgDBService->ForceFolderDBClosed(this);
+      rv = msgDBService->OpenFolderDB(this, true, getter_AddRefs(mDatabase));
+      if (mDatabase)
+        mDatabase->SetSummaryValid(false);
+    }
+
+    if (mDatabase)
+    {
+      //
+      // When I inadvertently deleted the out-of-date database, I hit this code with
+      //  the db's m_dbFolderInfo as null from the delete, yet the local mDatabase
+      //  reference kept the database alive. So I hit an assert when I tried to open
+      //  the database. Be careful if you try to fix the out-of-date issues!
+      //
+      //UpdateNewMessages();
+      if(mAddListener)
+        mDatabase->AddListener(this);
+      // UpdateSummaryTotals can null mDatabase during initialization, so we save a local copy
+      nsCOMPtr<nsIMsgDatabase> database(mDatabase);
+      UpdateSummaryTotals(true);
+      mDatabase = database;
+
+    }
+  }
+
+  return rv;
+}
+
+/*
+ * The utility function GetSummaryFileLocation takes a folder file,
+ *  then appends .msf to come up with the name of the database file. So
+ *  we need a placeholder file with simply the folder name. This method
+ *  creates an appropriate file as a placeholder, or you may use the file if
+ *  appropriate.
+ */
+nsresult
+JaBaseCppMsgFolder::CreateDummyFile(nsIMsgFolder* aMailFolder)
+{
+  nsresult rv;
+  if (!aMailFolder)
+    return NS_OK;
+  nsCOMPtr <nsIFile> path;
+  // need to make sure folder exists...
+  aMailFolder->GetFilePath(getter_AddRefs(path));
+  if (path)
+  {
+    bool exists;
+    rv = path->Exists(&exists);
+    if (!exists)
+    {
+      rv = path->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+  }
+  return NS_OK;
+}
+
+// AFAICT this is unused in mailnews code.
+nsresult
+JaBaseCppMsgFolder::CreateChildFromURI(const nsCString &uri, nsIMsgFolder **folder)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+// Delegator object to bypass JS method override.
+
+JaCppMsgFolderDelegator::JaCppMsgFolderDelegator() :
+  mCppBase(new Super(this)),
+  mMethods(nullptr)
+{ }
+
+NS_IMPL_ISUPPORTS_INHERITED(JaCppMsgFolderDelegator, JaBaseCppMsgFolder,
+                            msgIOverride)
+
+NS_IMPL_ISUPPORTS(JaCppMsgFolderDelegator::Super,
+                  nsIMsgFolder,
+                  nsIRDFResource,
+                  nsIRDFNode,
+                  nsIDBChangeListener,
+                  nsIUrlListener,
+                  nsIJunkMailClassificationListener,
+                  nsIMsgTraitClassificationListener,
+                  nsIInterfaceRequestor)
+
+NS_IMETHODIMP
+JaCppMsgFolderDelegator::SetMethodsToDelegate(msgIDelegateList* aDelegateList)
+{
+  if (!aDelegateList)
+  {
+    NS_WARNING("Null delegate list");
+    return NS_ERROR_NULL_POINTER;
+  }
+  // We static_cast since we want to use the hash object directly.
+  mDelegateList = static_cast<DelegateList*> (aDelegateList);
+  mMethods = &(mDelegateList->mMethods);
+  return NS_OK;
+}
+NS_IMETHODIMP
+JaCppMsgFolderDelegator::GetMethodsToDelegate(msgIDelegateList** aDelegateList)
+{
+  if (!mDelegateList)
+    mDelegateList = new DelegateList("mozilla::mailnews::JaCppMsgFolderDelegator::");
+  mMethods = &(mDelegateList->mMethods);
+  NS_ADDREF(*aDelegateList = mDelegateList);
+  return NS_OK;
+}
+
+NS_IMETHODIMP JaCppMsgFolderDelegator::SetJsDelegate(nsISupports* aJsDelegate)
+{
+  // If these QIs fail, then overrides are not provided for methods in that
+  // interface, which is OK.
+  mJsISupports = aJsDelegate;
+  mJsIMsgFolder = do_QueryInterface(aJsDelegate);
+  mJsIDBChangeListener = do_QueryInterface(aJsDelegate);
+  mJsIUrlListener = do_QueryInterface(aJsDelegate);
+  mJsIJunkMailClassificationListener = do_QueryInterface(aJsDelegate);
+  mJsIMsgTraitClassificationListener = do_QueryInterface(aJsDelegate);
+  mJsIInterfaceRequestor = do_QueryInterface(aJsDelegate);
+  return NS_OK;
+}
+NS_IMETHODIMP JaCppMsgFolderDelegator::GetJsDelegate(nsISupports **aJsDelegate)
+{
+  NS_ENSURE_ARG_POINTER(aJsDelegate);
+  if (mJsISupports)
+  {
+    NS_ADDREF(*aJsDelegate = mJsISupports);
+    return NS_OK;
+  }
+  return NS_ERROR_NOT_INITIALIZED;
+}
+
+NS_IMETHODIMP JaCppMsgFolderDelegator::GetCppBase(nsISupports** aCppBase)
+{
+  nsCOMPtr<nsISupports> cppBaseSupports;
+  cppBaseSupports = NS_ISUPPORTS_CAST(nsIMsgFolder*, mCppBase);
+  NS_ENSURE_STATE(cppBaseSupports);
+  cppBaseSupports.forget(aCppBase);
+
+  return NS_OK;
+}
+
+} // namespace mailnews
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/mailnews/jsaccount/src/JaMsgFolder.h
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _JaMsgFolder_H_
+#define _JaMsgFolder_H_
+
+#include "DelegateList.h"
+#include "msgIOverride.h"
+#include "nsMsgDBFolder.h"
+#include "nsAutoPtr.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsDataHashtable.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsWeakReference.h"
+#include "nsNetUtil.h"
+
+namespace mozilla {
+namespace mailnews {
+
+/* Header file */
+
+// This class is an XPCOM component, usable in JS, that calls the methods
+// in the C++ base class (bypassing any JS override).
+class JaBaseCppMsgFolder : public nsMsgDBFolder,
+                           public nsIInterfaceRequestor
+
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIINTERFACEREQUESTOR
+  JaBaseCppMsgFolder() { }
+
+  // nsMsgDBFolder overrides
+
+  nsresult CreateChildFromURI(const nsCString &uri, nsIMsgFolder **folder);
+  nsresult GetDatabase();
+
+  // Local Utility Functions
+
+  // Create a placeholder file to represent a folder.
+  nsresult CreateDummyFile(nsIMsgFolder* aMailFolder);
+
+protected:
+  virtual ~JaBaseCppMsgFolder() { }
+
+};
+
+class JaCppMsgFolderDelegator : public JaBaseCppMsgFolder,
+                                public msgIOverride
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_MSGIOVERRIDE
+
+  // Note that we do not support override of RDF methods.
+  NS_FORWARD_NSIRDFRESOURCE(JaBaseCppMsgFolder::)
+  NS_FORWARD_NSIRDFNODE(JaBaseCppMsgFolder::)
+  NS_FORWARD_NSIMSGFOLDER(DELEGATE_JS(nsIMsgFolder, mJsIMsgFolder)->)
+  NS_FORWARD_NSIDBCHANGELISTENER(
+    DELEGATE_JS(nsIDBChangeListener, mJsIDBChangeListener)->)
+  NS_FORWARD_NSIURLLISTENER(DELEGATE_JS(nsIUrlListener, mJsIUrlListener)->)
+  NS_FORWARD_NSIJUNKMAILCLASSIFICATIONLISTENER(
+      DELEGATE_JS(nsIJunkMailClassificationListener,
+                  mJsIJunkMailClassificationListener)->)
+  NS_FORWARD_NSIMSGTRAITCLASSIFICATIONLISTENER(
+      DELEGATE_JS(nsIMsgTraitClassificationListener,
+                  mJsIMsgTraitClassificationListener)->)
+  NS_FORWARD_NSIINTERFACEREQUESTOR(
+      DELEGATE_JS(nsIInterfaceRequestor, mJsIInterfaceRequestor)->)
+
+  JaCppMsgFolderDelegator();
+
+private:
+  virtual ~JaCppMsgFolderDelegator() {
+  }
+
+  class Super : public nsIMsgFolder,
+                public nsIRDFResource,
+                public nsIDBChangeListener,
+                public nsIUrlListener,
+                public nsIJunkMailClassificationListener,
+                public nsIMsgTraitClassificationListener,
+                public nsIInterfaceRequestor
+  {
+    public:
+      // Why fake this? Because this method is fully owned by
+      // JaCppMsgFolderDelegator, and this reference is to the "this" of the
+      // main method. But it is not really the local "this".
+      Super(JaCppMsgFolderDelegator* aFakeThis) {mFakeThis = aFakeThis;}
+      NS_DECL_ISUPPORTS
+      NS_FORWARD_NSIMSGFOLDER(mFakeThis->JaBaseCppMsgFolder::)
+      NS_FORWARD_NSIRDFRESOURCE(mFakeThis->JaBaseCppMsgFolder::)
+      NS_FORWARD_NSIRDFNODE(mFakeThis->JaBaseCppMsgFolder::)
+      NS_FORWARD_NSIDBCHANGELISTENER(mFakeThis->JaBaseCppMsgFolder::)
+      NS_FORWARD_NSIURLLISTENER(mFakeThis->JaBaseCppMsgFolder::)
+      NS_FORWARD_NSIJUNKMAILCLASSIFICATIONLISTENER(mFakeThis->JaBaseCppMsgFolder::)
+      NS_FORWARD_NSIMSGTRAITCLASSIFICATIONLISTENER(mFakeThis->JaBaseCppMsgFolder::)
+      NS_FORWARD_NSIINTERFACEREQUESTOR(mFakeThis->JaBaseCppMsgFolder::)
+    private:
+      virtual ~Super() {}
+      JaCppMsgFolderDelegator* mFakeThis;
+  };
+
+  // Interfaces that may be overridden by JS.
+  nsCOMPtr<nsIMsgFolder> mJsIMsgFolder;
+  nsCOMPtr<nsIDBChangeListener> mJsIDBChangeListener;
+  nsCOMPtr<nsIUrlListener> mJsIUrlListener;
+  nsCOMPtr<nsIJunkMailClassificationListener> mJsIJunkMailClassificationListener;
+  nsCOMPtr<nsIMsgTraitClassificationListener> mJsIMsgTraitClassificationListener;
+  nsCOMPtr<nsIInterfaceRequestor> mJsIInterfaceRequestor;
+
+  nsCOMPtr<nsISupports> mJsISupports;
+
+  nsCOMPtr<nsIMsgFolder> mCppBase;
+  RefPtr<DelegateList> mDelegateList;
+  nsDataHashtable<nsCStringHashKey, bool>* mMethods;
+
+};
+
+} // namespace mailnews
+} // namespace mozilla
+
+#endif
--- a/mailnews/jsaccount/src/moz.build
+++ b/mailnews/jsaccount/src/moz.build
@@ -3,20 +3,22 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 SOURCES += [
     'DelegateList.cpp',
     'JaAbDirectory.cpp',
     'JaIncomingServer.cpp',
+    'JaMsgFolder.cpp',
     'JaUrl.cpp',
 ]
 
 EXPORTS += [
     'DelegateList.h',
     'JaAbDirectory.h',
     'JaIncomingServer.h',
+    'JaMsgFolder.h',
     'JaUrl.h',
 ]
 
 Library('JsAccount')
 FINAL_LIBRARY = 'mail'
--- a/mailnews/jsaccount/test/moz.build
+++ b/mailnews/jsaccount/test/moz.build
@@ -4,8 +4,12 @@
 # http://creativecommons.org/publicdomain/zero/1.0/
 
 TEST_DIRS += [
     'idl',
 ]
 
 XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
 
+TESTING_JS_MODULES.mailnews += [
+  'unit/resources/testJaBaseIncomingServer.jsm',
+  'unit/resources/testJaBaseMsgFolder.jsm',
+]
--- a/mailnews/jsaccount/test/unit/resources/testComponents.manifest
+++ b/mailnews/jsaccount/test/unit/resources/testComponents.manifest
@@ -1,3 +1,22 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+# Definitions of components used in testing of JsAccount
+
 interfaces testJsAccount.xpt
+
+# nsIMsgMailNewsUrl implementation of a demo base URL
 component {73F98539-A59F-4F6F-9A72-D83A08646C23} testJaFooUrlComponent.js
 contract @mozilla.org/jsaccount/testjafoourl;1 {73F98539-A59F-4F6F-9A72-D83A08646C23}
+
+# nsIMsgFolder implementation
+component {8508ddeb-3eab-4877-a420-297518f62371} testJaBaseMsgFolderComponent.js
+contract @mozilla.org/rdf/resource-factory;1?name=testja {8508ddeb-3eab-4877-a420-297518f62371}
+
+# nsIMsgIncomingServer implementation
+component {0eec03cd-da67-4949-ab2d-5fa4bdc68135} testJaBaseIncomingServerComponent.js
+contract @mozilla.org/messenger/server;1?type=testja {0eec03cd-da67-4949-ab2d-5fa4bdc68135}
+
+# nsIMsgProtocolInfo implementation
+component {74b9b9c3-9594-41c4-b9f0-326e5daac2e0} testJaMsgProtocolInfoComponent.js
+contract @mozilla.org/messenger/protocol/info;1?type=testja {74b9b9c3-9594-41c4-b9f0-326e5daac2e0}
new file mode 100644
--- /dev/null
+++ b/mailnews/jsaccount/test/unit/resources/testJaBaseIncomingServer.jsm
@@ -0,0 +1,73 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+  This file creates a JS-based override of the JaIncomingServer implementation. It
+  demos a minimal JS class, and is also used in testing the additional methods
+  added to JaIncomingServer.cpp that are not in nsMsgDBFolder.cpp
+ */
+
+const EXPORTED_SYMBOLS = ["JaBaseIncomingServerProperties", "JaBaseIncomingServer"];
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cr = Components.results;
+var Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/jsaccount/JSAccountUtils.jsm");
+
+// A partial JavaScript implementation of the base server methods.
+
+const JaBaseIncomingServerProperties = {
+  baseContractID:     "@mozilla.org/jacppincomingserverdelegator;1",
+  baseInterfaces:     [ Ci.nsISupports,
+                        Ci.nsIMsgIncomingServer,
+                        Ci.nsIInterfaceRequestor,
+                        Ci.msgIOverride,
+                        Ci.nsISupportsWeakReference,
+                      ],
+  delegateInterfaces: [ Ci.nsIMsgIncomingServer ],
+  contractID:         "@mozilla.org/messenger/server;1?type=testja",
+  classID:            Components.ID("{0eec03cd-da67-4949-ab2d-5fa4bdc68135}"),
+};
+
+function JaBaseIncomingServer(aDelegator, aBaseInterfaces) {
+  dump("JaBaseIncomingServer\n");
+  // Typical boilerplate to include in all implementations.
+
+  // Object delegating method calls to the appropriate XPCOM object.
+  // Weak because it owns us.
+  this.delegator = Cu.getWeakReference(aDelegator);
+
+  // Base implementation of methods with no overrides.
+  this.cppBase = aDelegator.cppBase;
+
+  // cppBase class sees all interfaces
+  aBaseInterfaces.forEach(iface => this.cppBase instanceof iface);
+}
+
+JaBaseIncomingServer.prototype = {
+  // Typical boilerplate to include in all implementations.
+
+  // Flag this item as CPP needs to delegate to JS.
+  _JsPrototypeToDelegate: true,
+
+  // QI to the (partially implemented only) interfaces.
+  QueryInterface: XPCOMUtils.generateQI(JaBaseIncomingServerProperties.delegateInterfaces),
+
+  // Used to access an instance as JS, bypassing XPCOM.
+  get wrappedJSObject() {
+    return this;
+  },
+
+  // Dynamically-generated list of delegate methods.
+  delegateList: null,
+
+  // nsIMsgIncomingServer overrides.
+  get localStoreType() { return "testja"},
+  get localDatabaseType() { return "mailbox"},
+
+};
new file mode 100644
--- /dev/null
+++ b/mailnews/jsaccount/test/unit/resources/testJaBaseIncomingServerComponent.js
@@ -0,0 +1,25 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// This file is the component definition for a demo base implementation of a
+// javascript IncomingServer.
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/jsaccount/JSAccountUtils.jsm");
+Components.utils.import("resource://testing-common/mailnews/testJaBaseIncomingServer.jsm");
+dump("\n\ntestJaBaseIncomingServerComponent.js\n\n");
+
+// Constructor
+function JaBaseIncomingServerConstructor() {
+  dump("JaBaseIncomingServerConstructor\n");
+}
+
+// Constructor prototype (not instance prototype).
+JaBaseIncomingServerConstructor.prototype = {
+  classID: JaBaseIncomingServerProperties.classID,
+  _xpcom_factory: JSAccountUtils.jaFactory(JaBaseIncomingServerProperties, JaBaseIncomingServer),
+}
+
+var NSGetFactory = XPCOMUtils.generateNSGetFactory([JaBaseIncomingServerConstructor]);
new file mode 100644
--- /dev/null
+++ b/mailnews/jsaccount/test/unit/resources/testJaBaseMsgFolder.jsm
@@ -0,0 +1,75 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+  This file creates a JS-based override of the JaMsgFolder implementation. It
+  demos a minimal JS class, and is also used in testing the additional methods
+  added to JaMsgFolder.cpp that are not in nsMsgDBFolder.cpp
+ */
+
+const EXPORTED_SYMBOLS = ["JaBaseMsgFolderProperties", "JaBaseMsgFolder"];
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cr = Components.results;
+var Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/jsaccount/JSAccountUtils.jsm");
+
+// A partial JavaScript implementation of the base server methods.
+
+const JaBaseMsgFolderProperties = {
+  baseContractID:     "@mozilla.org/jacppmsgfolderdelegator;1",
+  baseInterfaces:     [ Ci.nsISupports,
+                        Ci.nsIMsgFolder,
+                        Ci.nsIDBChangeListener,
+                        Ci.nsIUrlListener,
+                        Ci.nsIJunkMailClassificationListener,
+                        Ci.nsIMsgTraitClassificationListener,
+                        Ci.nsIRDFResource,
+                        Ci.nsIInterfaceRequestor,
+                        Ci.msgIOverride,
+                      ],
+  delegateInterfaces: [ Ci.nsIMsgFolder ],
+  contractID:         "@mozilla.org/rdf/resource-factory;1?name=testja",
+  classID:            Components.ID("{8508ddeb-3eab-4877-a420-297518f62371}"),
+};
+
+function JaBaseMsgFolder(aDelegator, aBaseInterfaces) {
+  // Typical boilerplate to include in all implementations.
+
+  // Object delegating method calls to the appropriate XPCOM object.
+  // Weak because it owns us.
+  this.delegator = Cu.getWeakReference(aDelegator);
+
+  // Base implementation of methods with no overrides.
+  this.cppBase = aDelegator.cppBase;
+
+  // cppBase class sees all interfaces
+  aBaseInterfaces.forEach(iface => this.cppBase instanceof iface);
+}
+
+JaBaseMsgFolder.prototype = {
+  // Typical boilerplate to include in all implementations.
+
+  // Flag this item as CPP needs to delegate to JS.
+  _JsPrototypeToDelegate: true,
+
+  // QI to the (partially implemented only) interfaces.
+  QueryInterface: XPCOMUtils.generateQI(JaBaseMsgFolderProperties.delegateInterfaces),
+
+  // Used to access an instance as JS, bypassing XPCOM.
+  get wrappedJSObject() {
+    return this;
+  },
+
+  // Dynamically-generated list of delegate methods.
+  delegateList: null,
+
+  // nsIMsgFolder overrides.
+  get incomingServerType() { return "testja";},
+
+};
new file mode 100644
--- /dev/null
+++ b/mailnews/jsaccount/test/unit/resources/testJaBaseMsgFolderComponent.js
@@ -0,0 +1,23 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// This file is the component definition for a demo base implementation of a
+// javascript msgFolder.
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/jsaccount/JSAccountUtils.jsm");
+Components.utils.import("resource://testing-common/mailnews/testJaBaseMsgFolder.jsm");
+
+// Constructor
+function JaBaseMsgFolderConstructor() {
+}
+
+// Constructor prototype (not instance prototype).
+JaBaseMsgFolderConstructor.prototype = {
+  classID: JaBaseMsgFolderProperties.classID,
+  _xpcom_factory: JSAccountUtils.jaFactory(JaBaseMsgFolderProperties, JaBaseMsgFolder),
+}
+
+var NSGetFactory = XPCOMUtils.generateNSGetFactory([JaBaseMsgFolderConstructor]);
new file mode 100644
--- /dev/null
+++ b/mailnews/jsaccount/test/unit/resources/testJaMsgProtocolInfoComponent.js
@@ -0,0 +1,59 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// This file is the component definition for a demo base implementation of a
+// javascript nsIMsgProtocolInfo implementation.
+
+var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+function testJaMsgProtocolInfo() {
+  dump("testJaMsgProtocolInfo");
+  // nsIFile object to be used for the default local path.
+  this._defaultLocalPath = null;
+}
+
+testJaMsgProtocolInfo.prototype = {
+  // Flag this item as CPP needs to delegate to JS.
+  _JsPrototypeToDelegate: true,
+
+  get defaultLocalPath() {
+    if (this._defaultLocalPath)
+      return this._defaultLocalPath;
+    // Setup a default location, "TestFoo" directory in profile.
+    const NS_APP_USER_PROFILE_50_DIR = "ProfD";
+    let typedir = Services.dirsvc.get(NS_APP_USER_PROFILE_50_DIR, Ci.nsIFile);
+    typedir.append("TestFoo");
+    if (!typedir.exists())
+      typedir.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0600", 8));
+    this._defaultLocalPath = typedir;
+    return typedir;
+  },
+  set defaultLocalPath(defaultLocalPath) {
+    this._defaultLocalPath = defaultLocalPath;
+  },
+  // serverIID is used in AccountWizard.js, if missing will just report an error.
+  get serverIID() { return null; },
+  get requiresUsername() { return false; },
+  get preflightPrettyNameWithEmailAddress() { return false; },
+  get canDelete() { return true; },
+  get canLoginAtStartUp() { return false; },
+  get canDuplicate() { return false; },
+  getDefaultServerPort: (isSecure) =>  0,
+  get canGetMessages() { return false; },
+  get canGetIncomingMessages() { return false; },
+  get defaultDoBiff() { return false; },
+  get showComposeMsgLink() { return false; },
+  get foldersCreatedAsync() { return false; },
+
+  classDescription: "testja Msg Protocol Info implementation",
+  classID: Components.ID("{74b9b9c3-9594-41c4-b9f0-326e5daac2e0}"),
+  contractID: "@mozilla.org/messenger/protocol/info;1?type=testja",
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIMsgProtocolInfo])
+};
+
+var NSGetFactory = XPCOMUtils.generateNSGetFactory([testJaMsgProtocolInfo]);
--- a/mailnews/jsaccount/test/unit/test_componentsExist.js
+++ b/mailnews/jsaccount/test/unit/test_componentsExist.js
@@ -10,37 +10,59 @@ let tests = [
   // JaUrl
               ["@mozilla.org/jacppurldelegator;1", "nsISupports"],
               ["@mozilla.org/jacppurldelegator;1", "nsIMsgMailNewsUrl"],
               ["@mozilla.org/jacppurldelegator;1", "nsIMsgMessageUrl"],
               ["@mozilla.org/jacppurldelegator;1", "nsIURL"],
               ["@mozilla.org/jacppurldelegator;1", "nsIURI"],
               ["@mozilla.org/jacppurldelegator;1", "msgIOverride"],
               ["@mozilla.org/jacppurldelegator;1", "nsIInterfaceRequestor"],
+              // (probably a url bug) ["@mozilla.org/jacppurldelegator;1", "nsISupportsWeakReference"],
 
   // FooJaUrl
               ["@mozilla.org/jsaccount/testjafoourl;1", "nsISupports"],
               ["@mozilla.org/jsaccount/testjafoourl;1", "nsIMsgMailNewsUrl"],
               ["@mozilla.org/jsaccount/testjafoourl;1", "nsIMsgMessageUrl"],
               ["@mozilla.org/jsaccount/testjafoourl;1", "nsIURL"],
               ["@mozilla.org/jsaccount/testjafoourl;1", "nsIURI"],
               ["@mozilla.org/jsaccount/testjafoourl;1", "msgIOverride"],
               ["@mozilla.org/jsaccount/testjafoourl;1", "nsIInterfaceRequestor"],
   // JaAbDirectory
               ["@mozilla.org/jacppabdirectorydelegator;1", "nsISupports"],
               ["@mozilla.org/jacppabdirectorydelegator;1", "nsIAbDirectory"],
               ["@mozilla.org/jacppabdirectorydelegator;1", "nsIAbCollection"],
               ["@mozilla.org/jacppabdirectorydelegator;1", "nsIAbItem"],
               ["@mozilla.org/jacppabdirectorydelegator;1", "msgIOverride"],
               ["@mozilla.org/jacppabdirectorydelegator;1", "nsIInterfaceRequestor"],
+              ["@mozilla.org/jacppabdirectorydelegator;1", "nsISupportsWeakReference"],
   // JaIncomingServer
               ["@mozilla.org/jacppincomingserverdelegator;1", "nsISupports"],
               ["@mozilla.org/jacppincomingserverdelegator;1", "nsIMsgIncomingServer"],
               ["@mozilla.org/jacppincomingserverdelegator;1", "msgIOverride"],
               ["@mozilla.org/jacppincomingserverdelegator;1", "nsIInterfaceRequestor"],
+              ["@mozilla.org/jacppincomingserverdelegator;1", "nsISupportsWeakReference"],
+  // JaMsgFolder
+              ["@mozilla.org/jacppmsgfolderdelegator;1", "nsISupports"],
+              ["@mozilla.org/jacppmsgfolderdelegator;1", "nsIMsgFolder"],
+              ["@mozilla.org/jacppmsgfolderdelegator;1", "nsIRDFResource"],
+              ["@mozilla.org/jacppmsgfolderdelegator;1", "nsIRDFNode"],
+              ["@mozilla.org/jacppmsgfolderdelegator;1", "nsIDBChangeListener"],
+              ["@mozilla.org/jacppmsgfolderdelegator;1", "nsIUrlListener"],
+              ["@mozilla.org/jacppmsgfolderdelegator;1", "nsIJunkMailClassificationListener"],
+              ["@mozilla.org/jacppmsgfolderdelegator;1", "nsIMsgTraitClassificationListener"],
+              ["@mozilla.org/jacppmsgfolderdelegator;1", "msgIOverride"],
+              ["@mozilla.org/jacppmsgfolderdelegator;1", "nsISupportsWeakReference"],
+  // TestJaIncomingServer
+              ["@mozilla.org/messenger/server;1?type=testja", "nsISupports"],
+              ["@mozilla.org/messenger/server;1?type=testja", "nsIMsgIncomingServer"],
+              ["@mozilla.org/messenger/server;1?type=testja", "msgIOverride"],
+              ["@mozilla.org/messenger/server;1?type=testja", "nsISupportsWeakReference"],
+  // TestJaMsgProtocolInfo
+              ["@mozilla.org/messenger/protocol/info;1?type=testja", "nsISupports"],
+              ["@mozilla.org/messenger/protocol/info;1?type=testja", "nsIMsgProtocolInfo"],
             ];
 
 function run_test()
 {
   for (let [contractID, iface] of tests) {
     dump('trying to create component ' + contractID +
          ' with interface ' + iface + '\n');
     try {
new file mode 100644
--- /dev/null
+++ b/mailnews/jsaccount/test/unit/test_jaMsgFolder.js
@@ -0,0 +1,49 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// This tests the additional methods added to JaMsgFolder.cpp that are not
+// in nsMsgDBFolder.cpp  Although this code have been done creating the
+// delegator class directly, instead we use a JS component as a demo of
+// JS override classes.
+
+Cu.import("resource://testing-common/mailnews/testJaBaseMsgFolder.jsm");
+Cu.import("resource:///modules/mailServices.js");
+
+var interfaces = JaBaseMsgFolderProperties.baseInterfaces;
+
+function run_test()
+{
+  let server = MailServices.accounts.createIncomingServer("foouser", "foohost", "testja");
+  Assert.ok(server instanceof Ci.msgIOverride);
+
+  // If you create a folder object directly, it will complain about not being registered.
+  // Use RDF instead.
+  let rdfService = Cc['@mozilla.org/rdf/rdf-service;1'].getService(Ci.nsIRDFService);
+  let testJaMsgFolder = rdfService.GetResource("testja://foouser@foohost/somefolder");
+  //let testJaMsgFolder = Cc[JaBaseMsgFolderProperties.contractID]
+  //                        .createInstance(Ci.msgIOverride);
+  Assert.ok(testJaMsgFolder instanceof Ci.nsIMsgFolder);
+
+  JaBaseMsgFolderProperties.baseInterfaces.forEach(iface => {
+    dump('testing interface ' + iface + '(' + Ci[iface] + ')\n');
+    testJaMsgFolder.QueryInterface(Ci[iface]);
+  });
+
+  let db = testJaMsgFolder.msgDatabase;
+  Assert.ok(db instanceof Ci.nsIMsgDatabase);
+
+  // Make sure the DB actually works.
+  let dbFolder = db.folder;
+  Assert.ok(dbFolder instanceof Ci.nsIMsgFolder);
+  Assert.equal(dbFolder.QueryInterface(Ci.nsIRDFResource).Value, "testja://foouser@foohost/somefolder");
+  let fi = db.dBFolderInfo;
+  Assert.ok(fi instanceof Ci.nsIDBFolderInfo);
+  fi.setCharProperty("testProperty", "foobar");
+  Assert.equal(fi.getCharProperty("testProperty"), "foobar");
+  db.ForceClosed();
+  db = null;
+
+  // Confirm that we can access XPCOM properties.
+}
--- a/mailnews/jsaccount/test/unit/xpcshell.ini
+++ b/mailnews/jsaccount/test/unit/xpcshell.ini
@@ -2,8 +2,9 @@
 # http://creativecommons.org/publicdomain/zero/1.0/
 
 [DEFAULT]
 head = head_jsaccount.js
 tail = tail_jsaccount.js
 support-files = resources/*
 [test_componentsExist.js]
 [test_fooUrl.js]
+[test_jaMsgFolder.js]
--- a/mailnews/local/src/nsMailboxServer.cpp
+++ b/mailnews/local/src/nsMailboxServer.cpp
@@ -8,16 +8,23 @@
 
 NS_IMETHODIMP
 nsMailboxServer::GetLocalStoreType(nsACString& type)
 {
   type.AssignLiteral("mailbox");
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsMailboxServer::GetLocalDatabaseType(nsACString& type)
+{
+  type.AssignLiteral("mailbox");
+  return NS_OK;
+}
+
 nsresult
 nsMailboxServer::CreateRootFolderFromUri(const nsCString &serverUri,
                                          nsIMsgFolder **rootFolder)
 {
   nsMsgLocalMailFolder *newRootFolder = new nsMsgLocalMailFolder;
   if (!newRootFolder)
     return NS_ERROR_OUT_OF_MEMORY;
   NS_ADDREF(*rootFolder = newRootFolder);
--- a/mailnews/local/src/nsMailboxServer.h
+++ b/mailnews/local/src/nsMailboxServer.h
@@ -8,14 +8,15 @@
 
 #include "mozilla/Attributes.h"
 #include "nsMsgIncomingServer.h"
 
 class nsMailboxServer : public nsMsgIncomingServer
 {
 public:
   NS_IMETHOD GetLocalStoreType(nsACString& type) override;
+  NS_IMETHOD GetLocalDatabaseType(nsACString& type) override;
 protected:
   virtual nsresult CreateRootFolderFromUri(const nsCString &serverUri,
                                            nsIMsgFolder **rootFolder) override;
 };
 
 #endif
--- a/mailnews/local/src/nsNoIncomingServer.cpp
+++ b/mailnews/local/src/nsNoIncomingServer.cpp
@@ -27,24 +27,31 @@ NS_IMPL_ISUPPORTS_INHERITED(nsNoIncoming
 nsNoIncomingServer::nsNoIncomingServer()
 {
 }
 
 nsNoIncomingServer::~nsNoIncomingServer()
 {
 }
 
-nsresult
+NS_IMETHODIMP
 nsNoIncomingServer::GetLocalStoreType(nsACString& type)
 {
   type.AssignLiteral("mailbox");
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsNoIncomingServer::GetLocalDatabaseType(nsACString& type)
+{
+  type.AssignLiteral("mailbox");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsNoIncomingServer::GetAccountManagerChrome(nsAString& aResult)
 {
   aResult.AssignLiteral("am-serverwithnoidentities.xul");
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNoIncomingServer::SetFlagsOnDefaultMailboxes()
--- a/mailnews/local/src/nsNoIncomingServer.h
+++ b/mailnews/local/src/nsNoIncomingServer.h
@@ -22,16 +22,17 @@ class nsNoIncomingServer : public nsMail
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSINOINCOMINGSERVER
   NS_DECL_NSILOCALMAILINCOMINGSERVER
 
   nsNoIncomingServer();
 
   NS_IMETHOD GetLocalStoreType(nsACString& type) override;
+  NS_IMETHOD GetLocalDatabaseType(nsACString& type) override;
   NS_IMETHOD GetCanSearchMessages(bool *canSearchMessages) override;
   NS_IMETHOD GetServerRequiresPasswordForBiff(bool *aServerRequiresPasswordForBiff) override;
   NS_IMETHOD GetAccountManagerChrome(nsAString& aResult) override;
   NS_IMETHOD GetSortOrder(int32_t* aSortOrder) override;
 
 private:
   virtual ~nsNoIncomingServer();
 };
--- a/mailnews/news/src/nsNntpIncomingServer.cpp
+++ b/mailnews/news/src/nsNntpIncomingServer.cpp
@@ -206,16 +206,23 @@ nsNntpIncomingServer::SetNewsrcFilePath(
 NS_IMETHODIMP
 nsNntpIncomingServer::GetLocalStoreType(nsACString& type)
 {
   type.AssignLiteral("news");
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsNntpIncomingServer::GetLocalDatabaseType(nsACString& type)
+{
+  type.AssignLiteral("news");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsNntpIncomingServer::SetNewsrcRootPath(nsIFile *aNewsrcRootPath)
 {
     NS_ENSURE_ARG(aNewsrcRootPath);
     return NS_SetPersistentFile(PREF_MAIL_NEWSRC_ROOT_REL, PREF_MAIL_NEWSRC_ROOT, aNewsrcRootPath);
 }
 
 NS_IMETHODIMP
 nsNntpIncomingServer::GetNewsrcRootPath(nsIFile **aNewsrcRootPath)
--- a/mailnews/news/src/nsNntpIncomingServer.h
+++ b/mailnews/news/src/nsNntpIncomingServer.h
@@ -43,17 +43,18 @@ public:
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSINNTPINCOMINGSERVER
     NS_DECL_NSIURLLISTENER
     NS_DECL_NSISUBSCRIBABLESERVER
     NS_DECL_NSITREEVIEW
 
     nsNntpIncomingServer();
 
-    NS_IMETHOD GetLocalStoreType(nsACString& type);
+    NS_IMETHOD GetLocalStoreType(nsACString& type) override;
+    NS_IMETHOD GetLocalDatabaseType(nsACString& type) override;
     NS_IMETHOD CloseCachedConnections();
     NS_IMETHOD PerformBiff(nsIMsgWindow *aMsgWindow);
     NS_IMETHOD PerformExpand(nsIMsgWindow *aMsgWindow);
     NS_IMETHOD OnUserOrHostNameChanged(const nsACString& oldName,
                                        const nsACString& newName,
                                        bool hostnameChanged);
 
     // for nsMsgLineBuffer