summaryrefslogtreecommitdiffstats
path: root/mailnews/db/msgdb/src/nsDBFolderInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/db/msgdb/src/nsDBFolderInfo.cpp')
-rw-r--r--mailnews/db/msgdb/src/nsDBFolderInfo.cpp977
1 files changed, 977 insertions, 0 deletions
diff --git a/mailnews/db/msgdb/src/nsDBFolderInfo.cpp b/mailnews/db/msgdb/src/nsDBFolderInfo.cpp
new file mode 100644
index 000000000..0260738d0
--- /dev/null
+++ b/mailnews/db/msgdb/src/nsDBFolderInfo.cpp
@@ -0,0 +1,977 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "msgCore.h"
+#include "nsDBFolderInfo.h"
+#include "nsMsgDatabase.h"
+#include "nsMsgFolderFlags.h"
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
+#include "nsIPrefLocalizedString.h"
+#include "nsIObserver.h"
+#include "nsIObserverService.h"
+#include "nsIMsgDBView.h"
+#include "nsServiceManagerUtils.h"
+#include "nsImapCore.h"
+#include "mozilla/Services.h"
+
+static const char *kDBFolderInfoScope = "ns:msg:db:row:scope:dbfolderinfo:all";
+static const char *kDBFolderInfoTableKind = "ns:msg:db:table:kind:dbfolderinfo";
+
+struct mdbOid gDBFolderInfoOID;
+
+static const char * kNumMessagesColumnName ="numMsgs";
+// have to leave this as numNewMsgs even though it's numUnread Msgs
+static const char * kNumUnreadMessagesColumnName = "numNewMsgs";
+static const char * kFlagsColumnName = "flags";
+static const char * kFolderSizeColumnName = "folderSize";
+static const char * kExpungedBytesColumnName = "expungedBytes";
+static const char * kFolderDateColumnName = "folderDate";
+static const char * kHighWaterMessageKeyColumnName = "highWaterKey";
+
+static const char * kImapUidValidityColumnName = "UIDValidity";
+static const char * kTotalPendingMessagesColumnName = "totPendingMsgs";
+static const char * kUnreadPendingMessagesColumnName = "unreadPendingMsgs";
+static const char * kMailboxNameColumnName = "mailboxName";
+static const char * kKnownArtsSetColumnName = "knownArts";
+static const char * kExpiredMarkColumnName = "expiredMark";
+static const char * kVersionColumnName = "version";
+static const char * kCharacterSetColumnName = "charSet";
+static const char * kCharacterSetOverrideColumnName = "charSetOverride";
+static const char * kLocaleColumnName = "locale";
+
+
+#define kMAILNEWS_VIEW_DEFAULT_CHARSET "mailnews.view_default_charset"
+#define kMAILNEWS_DEFAULT_CHARSET_OVERRIDE "mailnews.force_charset_override"
+static nsCString* gDefaultCharacterSet = nullptr;
+static bool gDefaultCharacterOverride;
+static nsIObserver *gFolderCharsetObserver = nullptr;
+
+// observer for charset related preference notification
+class nsFolderCharsetObserver : public nsIObserver {
+
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+
+ nsFolderCharsetObserver() { }
+private:
+ virtual ~nsFolderCharsetObserver() {}
+};
+
+NS_IMPL_ISUPPORTS(nsFolderCharsetObserver, nsIObserver)
+
+NS_IMETHODIMP nsFolderCharsetObserver::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
+ if (NS_FAILED(rv)) return rv;
+
+ nsCOMPtr<nsIPrefBranch> prefBranch;
+ rv = prefs->GetBranch(nullptr, getter_AddRefs(prefBranch));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID))
+ {
+ nsDependentString prefName(someData);
+
+ if (prefName.EqualsLiteral(kMAILNEWS_VIEW_DEFAULT_CHARSET))
+ {
+ nsCOMPtr<nsIPrefLocalizedString> pls;
+ rv = prefBranch->GetComplexValue(kMAILNEWS_VIEW_DEFAULT_CHARSET,
+ NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(pls));
+ if (NS_SUCCEEDED(rv))
+ {
+ nsString ucsval;
+ pls->ToString(getter_Copies(ucsval));
+ if (!ucsval.IsEmpty())
+ {
+ if (gDefaultCharacterSet)
+ CopyUTF16toUTF8(ucsval, *gDefaultCharacterSet);
+ }
+ }
+ }
+ else if (prefName.EqualsLiteral(kMAILNEWS_DEFAULT_CHARSET_OVERRIDE))
+ {
+ rv = prefBranch->GetBoolPref(kMAILNEWS_DEFAULT_CHARSET_OVERRIDE, &gDefaultCharacterOverride);
+ }
+ }
+ else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID))
+ {
+ rv = prefBranch->RemoveObserver(kMAILNEWS_VIEW_DEFAULT_CHARSET, this);
+ rv = prefBranch->RemoveObserver(kMAILNEWS_DEFAULT_CHARSET_OVERRIDE, this);
+ NS_IF_RELEASE(gFolderCharsetObserver);
+ delete gDefaultCharacterSet;
+ gDefaultCharacterSet = nullptr;
+ }
+ return rv;
+}
+
+
+NS_IMPL_ADDREF(nsDBFolderInfo)
+NS_IMPL_RELEASE(nsDBFolderInfo)
+
+NS_IMETHODIMP
+nsDBFolderInfo::QueryInterface(REFNSIID iid, void** result)
+{
+ if (! result)
+ return NS_ERROR_NULL_POINTER;
+
+ *result = nullptr;
+ if(iid.Equals(NS_GET_IID(nsIDBFolderInfo)) ||
+ iid.Equals(NS_GET_IID(nsISupports)))
+ {
+ *result = static_cast<nsIDBFolderInfo*>(this);
+ AddRef();
+ return NS_OK;
+ }
+ return NS_NOINTERFACE;
+}
+
+
+nsDBFolderInfo::nsDBFolderInfo(nsMsgDatabase *mdb)
+ : m_flags(0),
+ m_expiredMark(0),
+ m_expiredMarkColumnToken(0)
+{
+ m_mdbTable = NULL;
+ m_mdbRow = NULL;
+ m_version = 1; // for upgrading...
+ m_IMAPHierarchySeparator = 0; // imap path separator
+ // mail only (for now)
+ m_folderSize = 0;
+ m_folderDate = 0;
+ m_expungedBytes = 0; // sum of size of deleted messages in folder
+ m_highWaterMessageKey = 0;
+
+ m_numUnreadMessages = 0;
+ m_numMessages = 0;
+ // IMAP only
+ m_ImapUidValidity = kUidUnknown;
+ m_totalPendingMessages =0;
+ m_unreadPendingMessages = 0;
+
+ m_mdbTokensInitialized = false;
+ m_charSetOverride = false;
+
+ if (!gFolderCharsetObserver)
+ {
+ nsresult rv;
+ nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
+ nsCOMPtr<nsIPrefBranch> prefBranch;
+ if (NS_SUCCEEDED(rv))
+ {
+ rv = prefs->GetBranch(nullptr, getter_AddRefs(prefBranch));
+ }
+ if (NS_SUCCEEDED(rv))
+ {
+ nsCOMPtr<nsIPrefLocalizedString> pls;
+ rv = prefBranch->GetComplexValue(kMAILNEWS_VIEW_DEFAULT_CHARSET,
+ NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(pls));
+ if (NS_SUCCEEDED(rv))
+ {
+ nsString ucsval;
+ pls->ToString(getter_Copies(ucsval));
+ if (!ucsval.IsEmpty())
+ {
+ if (!gDefaultCharacterSet)
+ gDefaultCharacterSet = new nsCString;
+
+ if (gDefaultCharacterSet)
+ CopyUTF16toUTF8(ucsval, *gDefaultCharacterSet);
+ }
+ }
+ rv = prefBranch->GetBoolPref(kMAILNEWS_DEFAULT_CHARSET_OVERRIDE, &gDefaultCharacterOverride);
+
+ gFolderCharsetObserver = new nsFolderCharsetObserver();
+ NS_ASSERTION(gFolderCharsetObserver, "failed to create observer");
+
+ // register prefs callbacks
+ if (gFolderCharsetObserver)
+ {
+ NS_ADDREF(gFolderCharsetObserver);
+ rv = prefBranch->AddObserver(kMAILNEWS_VIEW_DEFAULT_CHARSET, gFolderCharsetObserver, false);
+ rv = prefBranch->AddObserver(kMAILNEWS_DEFAULT_CHARSET_OVERRIDE, gFolderCharsetObserver, false);
+
+ // also register for shutdown
+ nsCOMPtr<nsIObserverService> observerService =
+ mozilla::services::GetObserverService();
+ if (observerService)
+ {
+ rv = observerService->AddObserver(gFolderCharsetObserver, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
+ }
+ }
+ }
+ }
+
+ m_mdb = mdb;
+ if (mdb)
+ {
+ nsresult err;
+
+ // mdb->AddRef();
+ err = m_mdb->GetStore()->StringToToken(mdb->GetEnv(), kDBFolderInfoScope, &m_rowScopeToken);
+ if (NS_SUCCEEDED(err))
+ {
+ err = m_mdb->GetStore()->StringToToken(mdb->GetEnv(), kDBFolderInfoTableKind, &m_tableKindToken);
+ if (NS_SUCCEEDED(err))
+ {
+ gDBFolderInfoOID.mOid_Scope = m_rowScopeToken;
+ gDBFolderInfoOID.mOid_Id = 1;
+ }
+ }
+ InitMDBInfo();
+ }
+}
+
+nsDBFolderInfo::~nsDBFolderInfo()
+{
+ // nsMsgDatabase strictly owns nsDBFolderInfo, so don't ref-count db.
+ ReleaseExternalReferences();
+}
+
+// Release any objects we're holding onto. This needs to be safe
+// to call multiple times.
+void nsDBFolderInfo::ReleaseExternalReferences()
+{
+ if (m_mdb)
+ {
+ if (m_mdbTable)
+ {
+ NS_RELEASE(m_mdbTable);
+ m_mdbTable = nullptr;
+ }
+ if (m_mdbRow)
+ {
+ NS_RELEASE(m_mdbRow);
+ m_mdbRow = nullptr;
+ }
+ m_mdb = nullptr;
+ }
+}
+
+// this routine sets up a new db to know about the dbFolderInfo stuff...
+nsresult nsDBFolderInfo::AddToNewMDB()
+{
+ nsresult ret = NS_OK;
+ if (m_mdb && m_mdb->GetStore())
+ {
+ nsIMdbStore *store = m_mdb->GetStore();
+ // create the unique table for the dbFolderInfo.
+ nsresult err = store->NewTable(m_mdb->GetEnv(), m_rowScopeToken,
+ m_tableKindToken, true, nullptr, &m_mdbTable);
+
+ // create the singleton row for the dbFolderInfo.
+ err = store->NewRowWithOid(m_mdb->GetEnv(),
+ &gDBFolderInfoOID, &m_mdbRow);
+
+ // add the row to the singleton table.
+ if (m_mdbRow && NS_SUCCEEDED(err))
+ err = m_mdbTable->AddRow(m_mdb->GetEnv(), m_mdbRow);
+
+ ret = err; // what are we going to do about nsresult's?
+ }
+ return ret;
+}
+
+nsresult nsDBFolderInfo::InitFromExistingDB()
+{
+ nsresult ret = NS_OK;
+ if (m_mdb && m_mdb->GetStore())
+ {
+ nsIMdbStore *store = m_mdb->GetStore();
+ if (store)
+ {
+ mdb_pos rowPos;
+ mdb_count outTableCount; // current number of such tables
+ mdb_bool mustBeUnique; // whether port can hold only one of these
+ mdb_bool hasOid;
+ ret = store->GetTableKind(m_mdb->GetEnv(), m_rowScopeToken, m_tableKindToken, &outTableCount,
+ &mustBeUnique, &m_mdbTable);
+ // NS_ASSERTION(mustBeUnique && outTableCount == 1, "only one global db info allowed");
+
+ if (m_mdbTable)
+ {
+ // find singleton row for global info.
+ ret = m_mdbTable->HasOid(m_mdb->GetEnv(), &gDBFolderInfoOID, &hasOid);
+ if (NS_SUCCEEDED(ret))
+ {
+ nsIMdbTableRowCursor *rowCursor;
+ rowPos = -1;
+ ret= m_mdbTable->GetTableRowCursor(m_mdb->GetEnv(), rowPos, &rowCursor);
+ if (NS_SUCCEEDED(ret))
+ {
+ ret = rowCursor->NextRow(m_mdb->GetEnv(), &m_mdbRow, &rowPos);
+ NS_RELEASE(rowCursor);
+ if (!m_mdbRow)
+ ret = NS_ERROR_FAILURE;
+ if (NS_SUCCEEDED(ret))
+ LoadMemberVariables();
+ }
+ }
+ }
+ else
+ ret = NS_ERROR_FAILURE;
+ }
+ }
+ return ret;
+}
+
+nsresult nsDBFolderInfo::InitMDBInfo()
+{
+ nsresult ret = NS_OK;
+ if (!m_mdbTokensInitialized && m_mdb && m_mdb->GetStore())
+ {
+ nsIMdbStore *store = m_mdb->GetStore();
+ nsIMdbEnv *env = m_mdb->GetEnv();
+
+ store->StringToToken(env, kNumMessagesColumnName, &m_numMessagesColumnToken);
+ store->StringToToken(env, kNumUnreadMessagesColumnName, &m_numUnreadMessagesColumnToken);
+ store->StringToToken(env, kFlagsColumnName, &m_flagsColumnToken);
+ store->StringToToken(env, kFolderSizeColumnName, &m_folderSizeColumnToken);
+ store->StringToToken(env, kExpungedBytesColumnName, &m_expungedBytesColumnToken);
+ store->StringToToken(env, kFolderDateColumnName, &m_folderDateColumnToken);
+
+ store->StringToToken(env, kHighWaterMessageKeyColumnName, &m_highWaterMessageKeyColumnToken);
+ store->StringToToken(env, kMailboxNameColumnName, &m_mailboxNameColumnToken);
+
+ store->StringToToken(env, kImapUidValidityColumnName, &m_imapUidValidityColumnToken);
+ store->StringToToken(env, kTotalPendingMessagesColumnName, &m_totalPendingMessagesColumnToken);
+ store->StringToToken(env, kUnreadPendingMessagesColumnName, &m_unreadPendingMessagesColumnToken);
+ store->StringToToken(env, kExpiredMarkColumnName, &m_expiredMarkColumnToken);
+ store->StringToToken(env, kVersionColumnName, &m_versionColumnToken);
+ m_mdbTokensInitialized = true;
+ }
+
+ return ret;
+}
+
+nsresult nsDBFolderInfo::LoadMemberVariables()
+{
+ // it's really not an error for these properties to not exist...
+ GetInt32PropertyWithToken(m_numMessagesColumnToken, m_numMessages);
+ GetInt32PropertyWithToken(m_numUnreadMessagesColumnToken, m_numUnreadMessages);
+ GetInt32PropertyWithToken(m_flagsColumnToken, m_flags);
+ GetInt64PropertyWithToken(m_folderSizeColumnToken, m_folderSize);
+ GetUint32PropertyWithToken(m_folderDateColumnToken, m_folderDate);
+ GetInt32PropertyWithToken(m_imapUidValidityColumnToken, m_ImapUidValidity, kUidUnknown);
+ GetUint32PropertyWithToken(m_expiredMarkColumnToken, m_expiredMark);
+ GetInt64PropertyWithToken(m_expungedBytesColumnToken, m_expungedBytes);
+ GetUint32PropertyWithToken(m_highWaterMessageKeyColumnToken, m_highWaterMessageKey);
+ int32_t version;
+
+ GetInt32PropertyWithToken(m_versionColumnToken, version);
+ m_version = (uint16_t) version;
+ m_charSetOverride = gDefaultCharacterOverride;
+ uint32_t propertyValue;
+ nsresult rv = GetUint32Property(kCharacterSetOverrideColumnName, gDefaultCharacterOverride, &propertyValue);
+ if (NS_SUCCEEDED(rv))
+ m_charSetOverride = propertyValue;
+
+ m_mdb->GetProperty(m_mdbRow, kCharacterSetColumnName, getter_Copies(m_charSet));
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetVersion(uint32_t version)
+{
+ m_version = version;
+ return SetUint32PropertyWithToken(m_versionColumnToken, (uint32_t) m_version);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::GetVersion(uint32_t *version)
+{
+ *version = m_version;
+ return NS_OK;
+}
+
+
+nsresult nsDBFolderInfo::AdjustHighWater(nsMsgKey highWater, bool force)
+{
+ if (force || m_highWaterMessageKey < highWater)
+ {
+ m_highWaterMessageKey = highWater;
+ SetUint32PropertyWithToken(m_highWaterMessageKeyColumnToken, highWater);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetHighWater(nsMsgKey highWater)
+{
+ return AdjustHighWater(highWater, true);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::OnKeyAdded(nsMsgKey aNewKey)
+{
+ return AdjustHighWater(aNewKey, false);
+}
+
+NS_IMETHODIMP
+nsDBFolderInfo::GetFolderSize(int64_t *size)
+{
+ NS_ENSURE_ARG_POINTER(size);
+ *size = m_folderSize;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetFolderSize(int64_t size)
+{
+ m_folderSize = size;
+ return SetInt64Property(kFolderSizeColumnName, m_folderSize);
+}
+
+NS_IMETHODIMP
+nsDBFolderInfo::GetFolderDate(uint32_t *folderDate)
+{
+ NS_ENSURE_ARG_POINTER(folderDate);
+ *folderDate = m_folderDate;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetFolderDate(uint32_t folderDate)
+{
+ m_folderDate = folderDate;
+ return SetUint32PropertyWithToken(m_folderDateColumnToken, folderDate);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::GetHighWater(nsMsgKey *result)
+{
+ // Sanity check highwater - if it gets too big, other code
+ // can fail. Look through last 100 messages to recalculate
+ // the highwater mark.
+ *result = m_highWaterMessageKey;
+ if (m_highWaterMessageKey > 0xFFFFFF00 && m_mdb)
+ {
+ nsCOMPtr <nsISimpleEnumerator> hdrs;
+ nsresult rv = m_mdb->ReverseEnumerateMessages(getter_AddRefs(hdrs));
+ if (NS_FAILED(rv))
+ return rv;
+ bool hasMore = false;
+ nsCOMPtr<nsIMsgDBHdr> pHeader;
+ nsMsgKey recalculatedHighWater = 1;
+ int32_t i = 0;
+ while(i++ < 100 && NS_SUCCEEDED(rv = hdrs->HasMoreElements(&hasMore))
+ && hasMore)
+ {
+ nsCOMPtr<nsISupports> supports;
+ (void) hdrs->GetNext(getter_AddRefs(supports));
+ pHeader = do_QueryInterface(supports);
+ if (pHeader)
+ {
+ nsMsgKey msgKey;
+ pHeader->GetMessageKey(&msgKey);
+ if (msgKey > recalculatedHighWater)
+ recalculatedHighWater = msgKey;
+ }
+ }
+ NS_ASSERTION(m_highWaterMessageKey >= recalculatedHighWater,
+ "highwater incorrect");
+ m_highWaterMessageKey = recalculatedHighWater;
+ }
+ *result = m_highWaterMessageKey;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetExpiredMark(nsMsgKey expiredKey)
+{
+ m_expiredMark = expiredKey;
+ return SetUint32PropertyWithToken(m_expiredMarkColumnToken, expiredKey);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::GetExpiredMark(nsMsgKey *result)
+{
+ *result = m_expiredMark;
+ return NS_OK;
+}
+
+// The size of the argument depends on the maximum size of a single message
+NS_IMETHODIMP nsDBFolderInfo::ChangeExpungedBytes(int32_t delta)
+{
+ return SetExpungedBytes(m_expungedBytes + delta);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetMailboxName(const nsAString &newBoxName)
+{
+ return SetPropertyWithToken(m_mailboxNameColumnToken, newBoxName);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::GetMailboxName(nsAString &boxName)
+{
+ return GetPropertyWithToken(m_mailboxNameColumnToken, boxName);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::ChangeNumUnreadMessages(int32_t delta)
+{
+ m_numUnreadMessages += delta;
+ // m_numUnreadMessages can never be set to negative.
+ if (m_numUnreadMessages < 0)
+ {
+#ifdef DEBUG_bienvenu1
+ NS_ASSERTION(false, "Hardcoded assertion");
+#endif
+ m_numUnreadMessages = 0;
+ }
+ return SetUint32PropertyWithToken(m_numUnreadMessagesColumnToken, m_numUnreadMessages);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::ChangeNumMessages(int32_t delta)
+{
+ m_numMessages += delta;
+ // m_numMessages can never be set to negative.
+ if (m_numMessages < 0)
+ {
+#ifdef DEBUG_bienvenu
+ NS_ASSERTION(false, "num messages can't be < 0");
+#endif
+ m_numMessages = 0;
+ }
+ return SetUint32PropertyWithToken(m_numMessagesColumnToken, m_numMessages);
+}
+
+
+NS_IMETHODIMP nsDBFolderInfo::GetNumUnreadMessages(int32_t *result)
+{
+ *result = m_numUnreadMessages;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetNumUnreadMessages(int32_t numUnreadMessages)
+{
+ m_numUnreadMessages = numUnreadMessages;
+ return SetUint32PropertyWithToken(m_numUnreadMessagesColumnToken, m_numUnreadMessages);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::GetNumMessages(int32_t *result)
+{
+ *result = m_numMessages;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetNumMessages(int32_t numMessages)
+{
+ m_numMessages = numMessages;
+ return SetUint32PropertyWithToken(m_numMessagesColumnToken, m_numMessages);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::GetExpungedBytes(int64_t *result)
+{
+ *result = m_expungedBytes;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetExpungedBytes(int64_t expungedBytes)
+{
+ m_expungedBytes = expungedBytes;
+ return SetInt64PropertyWithToken(m_expungedBytesColumnToken, m_expungedBytes);
+}
+
+
+NS_IMETHODIMP nsDBFolderInfo::GetFlags(int32_t *result)
+{
+ *result = m_flags;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetFlags(int32_t flags)
+{
+ nsresult ret = NS_OK;
+
+ if (m_flags != flags)
+ {
+ NS_ASSERTION((m_flags & nsMsgFolderFlags::Inbox) == 0 || (flags & nsMsgFolderFlags::Inbox) != 0, "lost inbox flag");
+ m_flags = flags;
+ ret = SetInt32PropertyWithToken(m_flagsColumnToken, m_flags);
+ }
+ return ret;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::OrFlags(int32_t flags, int32_t *result)
+{
+ m_flags |= flags;
+ *result = m_flags;
+ return SetInt32PropertyWithToken(m_flagsColumnToken, m_flags);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::AndFlags(int32_t flags, int32_t *result)
+{
+ m_flags &= flags;
+ *result = m_flags;
+ return SetInt32PropertyWithToken(m_flagsColumnToken, m_flags);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::GetImapUidValidity(int32_t *result)
+{
+ *result = m_ImapUidValidity;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetImapUidValidity(int32_t uidValidity)
+{
+ m_ImapUidValidity = uidValidity;
+ return SetUint32PropertyWithToken(m_imapUidValidityColumnToken, m_ImapUidValidity);
+}
+
+bool nsDBFolderInfo::TestFlag(int32_t flags)
+{
+ return (m_flags & flags) != 0;
+}
+
+NS_IMETHODIMP
+nsDBFolderInfo::GetCharacterSet(nsACString &result)
+{
+ if (!m_charSet.IsEmpty())
+ result.Assign(m_charSet);
+ else if (gDefaultCharacterSet)
+ result.Assign(*gDefaultCharacterSet);
+ else
+ result.Truncate();
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDBFolderInfo::GetEffectiveCharacterSet(nsACString &result)
+{
+ result.Truncate();
+ if (NS_FAILED(GetCharProperty(kCharacterSetColumnName, result)) ||
+ (result.IsEmpty() && gDefaultCharacterSet))
+ result = *gDefaultCharacterSet;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetCharacterSet(const nsACString &charSet)
+{
+ m_charSet.Assign(charSet);
+ return SetCharProperty(kCharacterSetColumnName, charSet);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::GetCharacterSetOverride(bool *characterSetOverride)
+{
+ NS_ENSURE_ARG_POINTER(characterSetOverride);
+ *characterSetOverride = m_charSetOverride;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetCharacterSetOverride(bool characterSetOverride)
+{
+ m_charSetOverride = characterSetOverride;
+ return SetUint32Property(kCharacterSetOverrideColumnName, characterSetOverride);
+}
+
+NS_IMETHODIMP
+nsDBFolderInfo::GetLocale(nsAString &result)
+{
+ GetProperty(kLocaleColumnName, result);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetLocale(const nsAString &locale)
+{
+ return SetProperty(kLocaleColumnName, locale);
+}
+
+NS_IMETHODIMP
+nsDBFolderInfo::GetImapTotalPendingMessages(int32_t *result)
+{
+ NS_ENSURE_ARG_POINTER(result);
+ *result = m_totalPendingMessages;
+ return NS_OK;
+}
+
+void nsDBFolderInfo::ChangeImapTotalPendingMessages(int32_t delta)
+{
+ m_totalPendingMessages+=delta;
+ SetInt32PropertyWithToken(m_totalPendingMessagesColumnToken, m_totalPendingMessages);
+}
+
+NS_IMETHODIMP
+nsDBFolderInfo::GetImapUnreadPendingMessages(int32_t *result)
+{
+ NS_ENSURE_ARG_POINTER(result);
+ *result = m_unreadPendingMessages;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetImapUnreadPendingMessages(int32_t numUnreadPendingMessages)
+{
+ m_unreadPendingMessages = numUnreadPendingMessages;
+ return SetUint32PropertyWithToken(m_unreadPendingMessagesColumnToken, m_unreadPendingMessages);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetImapTotalPendingMessages(int32_t numTotalPendingMessages)
+{
+ m_totalPendingMessages = numTotalPendingMessages;
+ return SetUint32PropertyWithToken(m_totalPendingMessagesColumnToken, m_totalPendingMessages);
+}
+
+void nsDBFolderInfo::ChangeImapUnreadPendingMessages(int32_t delta)
+{
+ m_unreadPendingMessages+=delta;
+ SetInt32PropertyWithToken(m_unreadPendingMessagesColumnToken, m_unreadPendingMessages);
+}
+
+/* attribute nsMsgViewTypeValue viewType; */
+NS_IMETHODIMP nsDBFolderInfo::GetViewType(nsMsgViewTypeValue *aViewType)
+{
+ uint32_t viewTypeValue;
+ nsresult rv = GetUint32Property("viewType", nsMsgViewType::eShowAllThreads, &viewTypeValue);
+ *aViewType = viewTypeValue;
+ return rv;
+}
+NS_IMETHODIMP nsDBFolderInfo::SetViewType(nsMsgViewTypeValue aViewType)
+{
+ return SetUint32Property("viewType", aViewType);
+}
+
+/* attribute nsMsgViewFlagsTypeValue viewFlags; */
+NS_IMETHODIMP nsDBFolderInfo::GetViewFlags(nsMsgViewFlagsTypeValue *aViewFlags)
+{
+ nsMsgViewFlagsTypeValue defaultViewFlags;
+ nsresult rv = m_mdb->GetDefaultViewFlags(&defaultViewFlags);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ uint32_t viewFlagsValue;
+ rv = GetUint32Property("viewFlags", defaultViewFlags, &viewFlagsValue);
+ *aViewFlags = viewFlagsValue;
+ return rv;
+}
+NS_IMETHODIMP nsDBFolderInfo::SetViewFlags(nsMsgViewFlagsTypeValue aViewFlags)
+{
+ return SetUint32Property("viewFlags", aViewFlags);
+}
+
+/* attribute nsMsgViewSortTypeValue sortType; */
+NS_IMETHODIMP nsDBFolderInfo::GetSortType(nsMsgViewSortTypeValue *aSortType)
+{
+ nsMsgViewSortTypeValue defaultSortType;
+ nsresult rv = m_mdb->GetDefaultSortType(&defaultSortType);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ uint32_t sortTypeValue;
+ rv = GetUint32Property("sortType", defaultSortType, &sortTypeValue);
+ *aSortType = sortTypeValue;
+ return rv;
+}
+NS_IMETHODIMP nsDBFolderInfo::SetSortType(nsMsgViewSortTypeValue aSortType)
+{
+ return SetUint32Property("sortType", aSortType);
+}
+
+/* attribute nsMsgViewSortOrderValue sortOrder; */
+NS_IMETHODIMP nsDBFolderInfo::GetSortOrder(nsMsgViewSortOrderValue *aSortOrder)
+{
+ nsMsgViewSortOrderValue defaultSortOrder;
+ nsresult rv = m_mdb->GetDefaultSortOrder(&defaultSortOrder);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ uint32_t sortOrderValue;
+ rv = GetUint32Property("sortOrder", defaultSortOrder, &sortOrderValue);
+ *aSortOrder = sortOrderValue;
+ return rv;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetSortOrder(nsMsgViewSortOrderValue aSortOrder)
+{
+ return SetUint32Property("sortOrder", aSortOrder);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetKnownArtsSet(const char *newsArtSet)
+{
+ return m_mdb->SetProperty(m_mdbRow, kKnownArtsSetColumnName, newsArtSet);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::GetKnownArtsSet(char **newsArtSet)
+{
+ return m_mdb->GetProperty(m_mdbRow, kKnownArtsSetColumnName, newsArtSet);
+}
+
+// get arbitrary property, aka row cell value.
+NS_IMETHODIMP nsDBFolderInfo::GetProperty(const char *propertyName, nsAString &resultProperty)
+{
+ return m_mdb->GetPropertyAsNSString(m_mdbRow, propertyName, resultProperty);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetCharProperty(const char *aPropertyName,
+ const nsACString &aPropertyValue)
+{
+ return m_mdb->SetProperty(m_mdbRow, aPropertyName,
+ nsCString(aPropertyValue).get());
+}
+
+NS_IMETHODIMP nsDBFolderInfo::GetCharProperty(const char *propertyName,
+ nsACString &resultProperty)
+{
+ nsCString result;
+ nsresult rv = m_mdb->GetProperty(m_mdbRow, propertyName, getter_Copies(result));
+ if (NS_SUCCEEDED(rv))
+ resultProperty.Assign(result);
+ return rv;
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetUint32Property(const char *propertyName, uint32_t propertyValue)
+{
+ return m_mdb->SetUint32Property(m_mdbRow, propertyName, propertyValue);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetInt64Property(const char *propertyName, int64_t propertyValue)
+{
+ return m_mdb->SetUint64Property(m_mdbRow, propertyName, (uint64_t) propertyValue);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetProperty(const char *propertyName, const nsAString &propertyStr)
+{
+ return m_mdb->SetPropertyFromNSString(m_mdbRow, propertyName, propertyStr);
+}
+
+nsresult nsDBFolderInfo::SetPropertyWithToken(mdb_token aProperty, const nsAString &propertyStr)
+{
+ return m_mdb->SetNSStringPropertyWithToken(m_mdbRow, aProperty, propertyStr);
+}
+
+nsresult nsDBFolderInfo::SetUint32PropertyWithToken(mdb_token aProperty, uint32_t propertyValue)
+{
+ return m_mdb->UInt32ToRowCellColumn(m_mdbRow, aProperty, propertyValue);
+}
+
+nsresult nsDBFolderInfo::SetInt64PropertyWithToken(mdb_token aProperty, int64_t propertyValue)
+{
+ return m_mdb->UInt64ToRowCellColumn(m_mdbRow, aProperty, (uint64_t) propertyValue);
+}
+
+nsresult nsDBFolderInfo::SetInt32PropertyWithToken(mdb_token aProperty, int32_t propertyValue)
+{
+ nsAutoString propertyStr;
+ propertyStr.AppendInt(propertyValue, 16);
+ return SetPropertyWithToken(aProperty, propertyStr);
+}
+
+nsresult nsDBFolderInfo::GetPropertyWithToken(mdb_token aProperty, nsAString &resultProperty)
+{
+ return m_mdb->RowCellColumnTonsString(m_mdbRow, aProperty, resultProperty);
+}
+
+nsresult nsDBFolderInfo::GetUint32PropertyWithToken(mdb_token aProperty, uint32_t &propertyValue, uint32_t defaultValue)
+{
+ return m_mdb->RowCellColumnToUInt32(m_mdbRow, aProperty, propertyValue, defaultValue);
+}
+
+nsresult nsDBFolderInfo::GetInt32PropertyWithToken(mdb_token aProperty, int32_t &propertyValue, int32_t defaultValue)
+{
+ return m_mdb->RowCellColumnToUInt32(m_mdbRow, aProperty, (uint32_t &) propertyValue, defaultValue);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::GetUint32Property(const char *propertyName, uint32_t defaultValue, uint32_t *propertyValue)
+{
+ return m_mdb->GetUint32Property(m_mdbRow, propertyName, propertyValue, defaultValue);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::GetInt64Property(const char *propertyName, int64_t defaultValue, int64_t *propertyValue)
+{
+ return m_mdb->GetUint64Property(m_mdbRow, propertyName, (uint64_t *) &propertyValue, defaultValue);
+}
+
+nsresult nsDBFolderInfo::GetInt64PropertyWithToken(mdb_token aProperty,
+ int64_t &propertyValue,
+ int64_t defaultValue)
+{
+ return m_mdb->RowCellColumnToUInt64(m_mdbRow, aProperty, (uint64_t *) &propertyValue, defaultValue);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::GetBooleanProperty(const char *propertyName, bool defaultValue, bool *propertyValue)
+{
+ uint32_t defaultUint32Value = (defaultValue) ? 1 : 0;
+ uint32_t returnValue;
+ nsresult rv = m_mdb->GetUint32Property(m_mdbRow, propertyName, &returnValue, defaultUint32Value);
+ *propertyValue = (returnValue != 0);
+ return rv;
+}
+NS_IMETHODIMP nsDBFolderInfo::SetBooleanProperty(const char *propertyName, bool propertyValue)
+{
+ return m_mdb->SetUint32Property(m_mdbRow, propertyName, propertyValue ? 1 : 0);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::GetFolderName(nsACString &folderName)
+{
+ return GetCharProperty("folderName", folderName);
+}
+
+NS_IMETHODIMP nsDBFolderInfo::SetFolderName(const nsACString &folderName)
+{
+ return SetCharProperty("folderName", folderName);
+}
+
+class nsTransferDBFolderInfo : public nsDBFolderInfo
+{
+public:
+ nsTransferDBFolderInfo();
+ virtual ~nsTransferDBFolderInfo();
+ // parallel arrays of properties and values
+ nsTArray<nsCString> m_properties;
+ nsTArray<nsCString> m_values;
+};
+
+nsTransferDBFolderInfo::nsTransferDBFolderInfo() : nsDBFolderInfo(nullptr)
+{
+}
+
+nsTransferDBFolderInfo::~nsTransferDBFolderInfo()
+{
+}
+
+/* void GetTransferInfo (out nsIDBFolderInfo transferInfo); */
+NS_IMETHODIMP nsDBFolderInfo::GetTransferInfo(nsIDBFolderInfo **transferInfo)
+{
+ NS_ENSURE_ARG_POINTER(transferInfo);
+
+ nsTransferDBFolderInfo *newInfo = new nsTransferDBFolderInfo;
+ *transferInfo = newInfo;
+ NS_ADDREF(newInfo);
+
+ mdb_count numCells;
+ mdbYarn cellYarn;
+ mdb_column cellColumn;
+ char columnName[100];
+ mdbYarn cellName = { columnName, 0, sizeof(columnName), 0, 0, nullptr };
+
+ NS_ASSERTION(m_mdbRow, "null row in getTransferInfo");
+ m_mdbRow->GetCount(m_mdb->GetEnv(), &numCells);
+ // iterate over the cells in the dbfolderinfo remembering attribute names and values.
+ for (mdb_count cellIndex = 0; cellIndex < numCells; cellIndex++)
+ {
+ nsresult err = m_mdbRow->SeekCellYarn(m_mdb->GetEnv(), cellIndex, &cellColumn, nullptr);
+ if (NS_SUCCEEDED(err))
+ {
+ err = m_mdbRow->AliasCellYarn(m_mdb->GetEnv(), cellColumn, &cellYarn);
+ if (NS_SUCCEEDED(err))
+ {
+ m_mdb->GetStore()->TokenToString(m_mdb->GetEnv(), cellColumn, &cellName);
+ newInfo->m_values.AppendElement(Substring((const char *)cellYarn.mYarn_Buf,
+ (const char *) cellYarn.mYarn_Buf + cellYarn.mYarn_Fill));
+ newInfo->m_properties.AppendElement(Substring((const char *) cellName.mYarn_Buf,
+ (const char *) cellName.mYarn_Buf + cellName.mYarn_Fill));
+ }
+ }
+ }
+
+ return NS_OK;
+}
+
+
+/* void InitFromTransferInfo (in nsIDBFolderInfo transferInfo); */
+NS_IMETHODIMP nsDBFolderInfo::InitFromTransferInfo(nsIDBFolderInfo *aTransferInfo)
+{
+ NS_ENSURE_ARG(aTransferInfo);
+
+ nsTransferDBFolderInfo *transferInfo = static_cast<nsTransferDBFolderInfo *>(aTransferInfo);
+
+ for (uint32_t i = 0; i < transferInfo->m_values.Length(); i++)
+ SetCharProperty(transferInfo->m_properties[i].get(), transferInfo->m_values[i]);
+
+ LoadMemberVariables();
+ return NS_OK;
+}
+