summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/db/msgdb/public/nsMsgDatabase.h
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/db/msgdb/public/nsMsgDatabase.h')
-rw-r--r--comm/mailnews/db/msgdb/public/nsMsgDatabase.h447
1 files changed, 447 insertions, 0 deletions
diff --git a/comm/mailnews/db/msgdb/public/nsMsgDatabase.h b/comm/mailnews/db/msgdb/public/nsMsgDatabase.h
new file mode 100644
index 0000000000..f61b9a7b25
--- /dev/null
+++ b/comm/mailnews/db/msgdb/public/nsMsgDatabase.h
@@ -0,0 +1,447 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _nsMsgDatabase_H_
+#define _nsMsgDatabase_H_
+
+#include "mozilla/Attributes.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/Path.h"
+#include "nsIFile.h"
+#include "nsIMsgDatabase.h"
+#include "nsMsgHdr.h"
+#include "nsString.h"
+#include "nsIDBChangeAnnouncer.h"
+#include "nsMsgMessageFlags.h"
+#include "nsIMsgFolder.h"
+#include "nsDBFolderInfo.h"
+#include "mozilla/intl/Collator.h"
+#include "nsIMimeConverter.h"
+#include "nsCOMPtr.h"
+#include "nsCOMArray.h"
+#include "PLDHashTable.h"
+#include "nsTArray.h"
+#include "nsTObserverArray.h"
+
+using mozilla::intl::Collator;
+
+class nsMsgThread;
+class nsMsgDatabase;
+class nsIMsgOfflineOpsDatabase;
+class nsIMsgThread;
+class nsMsgDBEnumerator;
+class nsMsgDBThreadEnumerator;
+
+const int32_t kMsgDBVersion = 1;
+
+// Hopefully we're not opening up lots of databases at the same time, however
+// this will give us a buffer before we need to start reallocating the cache
+// array.
+const uint32_t kInitialMsgDBCacheSize = 20;
+
+class nsMsgDBService final : public nsIMsgDBService {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIMSGDBSERVICE
+
+ nsMsgDBService();
+
+ void AddToCache(nsMsgDatabase* pMessageDB);
+ void DumpCache();
+ void EnsureCached(nsMsgDatabase* pMessageDB) {
+ if (!m_dbCache.Contains(pMessageDB)) m_dbCache.AppendElement(pMessageDB);
+ }
+ void RemoveFromCache(nsMsgDatabase* pMessageDB) {
+ m_dbCache.RemoveElement(pMessageDB);
+ }
+
+ protected:
+ ~nsMsgDBService();
+ void HookupPendingListeners(nsIMsgDatabase* db, nsIMsgFolder* folder);
+ void FinishDBOpen(nsIMsgFolder* aFolder, nsMsgDatabase* aMsgDB);
+ nsMsgDatabase* FindInCache(nsIFile* dbName);
+
+ nsCOMArray<nsIMsgFolder> m_foldersPendingListeners;
+ nsCOMArray<nsIDBChangeListener> m_pendingListeners;
+ AutoTArray<nsMsgDatabase*, kInitialMsgDBCacheSize> m_dbCache;
+};
+
+namespace mozilla {
+namespace mailnews {
+class MsgDBReporter;
+}
+} // namespace mozilla
+
+class nsMsgDatabase : public nsIMsgOfflineOpsDatabase {
+ public:
+ friend class nsMsgDBService;
+ friend class nsMsgPropertyEnumerator; // accesses m_mdbEnv and m_mdbStore
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIDBCHANGEANNOUNCER
+ NS_DECL_NSIMSGDATABASE
+ NS_DECL_NSIMSGOFFLINEOPSDATABASE
+
+ /**
+ * 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.
+ * @exception NS_ERROR_FILE_NOT_FOUND
+ * The file could not be created.
+ * @exception NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE
+ * The database is present (and was opened), but the
+ * summary file is out of date.
+ * @exception NS_MSG_ERROR_FOLDER_SUMMARY_MISSING
+ * The database is present (and was opened), but the
+ * summary file is missing.
+ */
+ virtual nsresult Open(nsMsgDBService* aDBService, nsIFile* aFolderName,
+ bool aCreate, bool aLeaveInvalidDB);
+ virtual nsresult IsHeaderRead(nsIMsgDBHdr* hdr, bool* pRead);
+ virtual nsresult MarkHdrReadInDB(nsIMsgDBHdr* msgHdr, bool bRead,
+ nsIDBChangeListener* instigator);
+ nsresult OpenInternal(nsMsgDBService* aDBService, nsIFile* aFolderName,
+ bool aCreate, bool aLeaveInvalidDB, bool sync);
+ nsresult CheckForErrors(nsresult err, bool sync, nsMsgDBService* aDBService,
+ nsIFile* summaryFile);
+ virtual nsresult OpenMDB(nsIFile* dbfile, bool create, bool sync);
+ virtual nsresult CloseMDB(bool commit);
+ virtual nsresult CreateMsgHdr(nsIMdbRow* hdrRow, nsMsgKey key,
+ nsIMsgDBHdr** result);
+ virtual nsresult GetThreadForMsgKey(nsMsgKey msgKey, nsIMsgThread** result);
+ virtual nsresult EnumerateMessagesWithFlag(nsIMsgEnumerator** result,
+ uint32_t* pFlag);
+ nsresult GetSearchResultsTable(const nsACString& searchFolderUri,
+ bool createIfMissing, nsIMdbTable** table);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // nsMsgDatabase methods:
+ nsMsgDatabase();
+
+ nsresult GetMDBFactory(nsIMdbFactory** aMdbFactory);
+ nsIMdbEnv* GetEnv() { return m_mdbEnv; }
+ nsIMdbStore* GetStore() { return m_mdbStore; }
+ virtual uint32_t GetCurVersion();
+ nsresult GetCollationKeyGenerator();
+ nsIMimeConverter* GetMimeConverter();
+
+ nsresult GetTableCreateIfMissing(const char* scope, const char* kind,
+ nsIMdbTable** table, mdb_token& scopeToken,
+ mdb_token& kindToken);
+
+ // helper function to fill in nsStrings from hdr row cell contents.
+ nsresult RowCellColumnTonsString(nsIMdbRow* row, mdb_token columnToken,
+ nsAString& resultStr);
+ nsresult RowCellColumnToUInt32(nsIMdbRow* row, mdb_token columnToken,
+ uint32_t* uint32Result,
+ uint32_t defaultValue = 0);
+ nsresult RowCellColumnToUInt32(nsIMdbRow* row, mdb_token columnToken,
+ uint32_t& uint32Result,
+ uint32_t defaultValue = 0);
+ nsresult RowCellColumnToUInt64(nsIMdbRow* row, mdb_token columnToken,
+ uint64_t* uint64Result,
+ uint64_t defaultValue = 0);
+ nsresult RowCellColumnToMime2DecodedString(nsIMdbRow* row,
+ mdb_token columnToken,
+ nsAString& resultStr);
+ nsresult RowCellColumnToCollationKey(nsIMdbRow* row, mdb_token columnToken,
+ nsTArray<uint8_t>& result);
+ nsresult RowCellColumnToConstCharPtr(nsIMdbRow* row, mdb_token columnToken,
+ const char** ptr);
+ nsresult RowCellColumnToAddressCollationKey(nsIMdbRow* row,
+ mdb_token colToken,
+ nsTArray<uint8_t>& result);
+
+ nsresult GetEffectiveCharset(nsIMdbRow* row, nsACString& resultCharset);
+
+ // these methods take the property name as a string, not a token.
+ // they should be used when the properties aren't accessed a lot
+ nsresult GetProperty(nsIMdbRow* row, const char* propertyName, char** result);
+ nsresult SetProperty(nsIMdbRow* row, const char* propertyName,
+ const char* propertyVal);
+ nsresult GetPropertyAsNSString(nsIMdbRow* row, const char* propertyName,
+ nsAString& result);
+ nsresult SetPropertyFromNSString(nsIMdbRow* row, const char* propertyName,
+ const nsAString& propertyVal);
+ nsresult GetUint32Property(nsIMdbRow* row, const char* propertyName,
+ uint32_t* result, uint32_t defaultValue = 0);
+ nsresult GetUint64Property(nsIMdbRow* row, const char* propertyName,
+ uint64_t* result, uint64_t defaultValue = 0);
+ nsresult SetUint32Property(nsIMdbRow* row, const char* propertyName,
+ uint32_t propertyVal);
+ nsresult SetUint64Property(nsIMdbRow* row, const char* propertyName,
+ uint64_t propertyVal);
+ nsresult GetBooleanProperty(nsIMdbRow* row, const char* propertyName,
+ bool* result, bool defaultValue = false);
+ nsresult SetBooleanProperty(nsIMdbRow* row, const char* propertyName,
+ bool propertyVal);
+ // helper function for once we have the token.
+ nsresult SetNSStringPropertyWithToken(nsIMdbRow* row, mdb_token aProperty,
+ const nsAString& propertyStr);
+
+ // helper functions to put values in cells for the passed-in row
+ nsresult UInt32ToRowCellColumn(nsIMdbRow* row, mdb_token columnToken,
+ uint32_t value);
+ nsresult CharPtrToRowCellColumn(nsIMdbRow* row, mdb_token columnToken,
+ const char* charPtr);
+ nsresult RowCellColumnToCharPtr(nsIMdbRow* row, mdb_token columnToken,
+ char** result);
+ nsresult UInt64ToRowCellColumn(nsIMdbRow* row, mdb_token columnToken,
+ uint64_t value);
+
+ // helper functions to copy an nsString to a yarn, int32 to yarn, and vice
+ // versa.
+ static struct mdbYarn* nsStringToYarn(struct mdbYarn* yarn,
+ const nsAString& str);
+ static struct mdbYarn* UInt32ToYarn(struct mdbYarn* yarn, uint32_t i);
+ static struct mdbYarn* UInt64ToYarn(struct mdbYarn* yarn, uint64_t i);
+ static void YarnTonsString(struct mdbYarn* yarn, nsAString& str);
+ static void YarnTonsCString(struct mdbYarn* yarn, nsACString& str);
+ static void YarnToUInt32(struct mdbYarn* yarn, uint32_t* i);
+ static void YarnToUInt64(struct mdbYarn* yarn, uint64_t* i);
+
+#ifdef DEBUG
+ virtual nsresult DumpContents();
+#endif
+
+ friend class nsMsgHdr; // use this to get access to cached tokens for hdr
+ // fields
+ friend class nsMsgThread; // use this to get access to cached tokens for hdr
+ // fields
+
+ friend class nsMsgDBEnumerator;
+ friend class nsMsgDBThreadEnumerator;
+
+ protected:
+ virtual ~nsMsgDatabase();
+
+ // prefs stuff - in future, we might want to cache the prefs interface
+ nsresult GetBoolPref(const char* prefName, bool* result);
+ nsresult GetIntPref(const char* prefName, int32_t* result);
+ virtual void GetGlobalPrefs();
+ // retrieval methods
+ nsIMsgThread* GetThreadForReference(nsCString& msgID, nsIMsgDBHdr** pMsgHdr);
+ nsIMsgThread* GetThreadForSubject(nsCString& subject);
+ nsIMsgThread* GetThreadForMessageId(nsCString& msgId);
+ nsIMsgThread* GetThreadForThreadId(nsMsgKey threadId);
+ nsMsgHdr* GetMsgHdrForReference(nsCString& reference);
+ nsIMsgDBHdr* GetMsgHdrForSubject(nsCString& subject);
+ // threading interfaces
+ virtual nsresult CreateNewThread(nsMsgKey key, const char* subject,
+ nsMsgThread** newThread);
+ virtual bool ThreadBySubjectWithoutRe();
+ virtual bool UseStrictThreading();
+ virtual bool UseCorrectThreading();
+ virtual nsresult ThreadNewHdr(nsMsgHdr* hdr, bool& newThread);
+ virtual nsresult AddNewThread(nsMsgHdr* msgHdr);
+ virtual nsresult AddToThread(nsMsgHdr* newHdr, nsIMsgThread* thread,
+ nsIMsgDBHdr* pMsgHdr, bool threadInThread);
+
+ static PRTime gLastUseTime; // global last use time
+ PRTime m_lastUseTime; // last use time for this db
+ // inline to make instrumentation as cheap as possible
+ inline void RememberLastUseTime() { gLastUseTime = m_lastUseTime = PR_Now(); }
+
+ bool MatchDbName(nsIFile* dbName); // returns TRUE if they match
+
+ // Flag handling routines
+ virtual nsresult SetKeyFlag(nsMsgKey key, bool set, nsMsgMessageFlagType flag,
+ nsIDBChangeListener* instigator = nullptr);
+ virtual nsresult SetMsgHdrFlag(nsIMsgDBHdr* msgHdr, bool set,
+ nsMsgMessageFlagType flag,
+ nsIDBChangeListener* instigator);
+
+ virtual bool SetHdrFlag(nsIMsgDBHdr*, bool bSet, nsMsgMessageFlagType flag);
+ virtual bool SetHdrReadFlag(nsIMsgDBHdr*, bool pRead);
+ virtual uint32_t GetStatusFlags(nsIMsgDBHdr* msgHdr,
+ nsMsgMessageFlagType origFlags);
+ // helper function which doesn't involve thread object
+
+ virtual nsresult RemoveHeaderFromDB(nsMsgHdr* msgHdr);
+ virtual nsresult RemoveHeaderFromThread(nsMsgHdr* msgHdr);
+ virtual nsresult AdjustExpungedBytesOnDelete(nsIMsgDBHdr* msgHdr);
+
+ mozilla::UniquePtr<mozilla::intl::Collator> m_collationKeyGenerator = nullptr;
+ nsCOMPtr<nsIMimeConverter> m_mimeConverter;
+ nsCOMPtr<nsIMsgRetentionSettings> m_retentionSettings;
+ nsCOMPtr<nsIMsgDownloadSettings> m_downloadSettings;
+
+ nsresult FindMessagesOlderThan(uint32_t daysToKeepHdrs,
+ bool applyToFlaggedMessages,
+ nsTArray<RefPtr<nsIMsgDBHdr>>& hdrsToDelete);
+ nsresult FindExcessMessages(uint32_t numHeadersToKeep,
+ bool applyToFlaggedMessages,
+ nsTArray<RefPtr<nsIMsgDBHdr>>& hdrsToDelete);
+
+ // mdb bookkeeping stuff
+ virtual nsresult InitExistingDB();
+ virtual nsresult InitNewDB();
+ virtual nsresult InitMDBInfo();
+
+ nsCOMPtr<nsIMsgFolder> m_folder;
+ RefPtr<nsDBFolderInfo> m_dbFolderInfo;
+ nsMsgKey m_nextPseudoMsgKey;
+ nsIMdbEnv* m_mdbEnv; // to be used in all the db calls.
+ nsIMdbStore* m_mdbStore;
+ nsIMdbTable* m_mdbAllMsgHeadersTable;
+ nsIMdbTable* m_mdbAllThreadsTable;
+
+ // Used for asynchronous db opens. If non-null, we're still opening
+ // the underlying mork database. If null, the db has been completely opened.
+ nsCOMPtr<nsIMdbThumb> m_thumb;
+ // used to remember the args to Open for async open.
+ bool m_create;
+ bool m_leaveInvalidDB;
+
+ nsCOMPtr<nsIFile> m_dbFile;
+ nsTArray<nsMsgKey> m_newSet; // new messages since last open.
+ bool m_mdbTokensInitialized;
+ nsTObserverArray<nsCOMPtr<nsIDBChangeListener>> m_ChangeListeners;
+ mdb_token m_hdrRowScopeToken;
+ mdb_token m_threadRowScopeToken;
+ mdb_token m_hdrTableKindToken;
+ mdb_token m_threadTableKindToken;
+ mdb_token m_allThreadsTableKindToken;
+ mdb_token m_subjectColumnToken;
+ mdb_token m_senderColumnToken;
+ mdb_token m_messageIdColumnToken;
+ mdb_token m_referencesColumnToken;
+ mdb_token m_recipientsColumnToken;
+ mdb_token m_dateColumnToken;
+ mdb_token m_messageSizeColumnToken;
+ mdb_token m_flagsColumnToken;
+ mdb_token m_priorityColumnToken;
+ mdb_token m_labelColumnToken;
+ mdb_token m_numLinesColumnToken;
+ mdb_token m_ccListColumnToken;
+ mdb_token m_bccListColumnToken;
+ mdb_token m_threadFlagsColumnToken;
+ mdb_token m_threadIdColumnToken;
+ mdb_token m_threadChildrenColumnToken;
+ mdb_token m_threadUnreadChildrenColumnToken;
+ mdb_token m_messageThreadIdColumnToken;
+ mdb_token m_threadSubjectColumnToken;
+ mdb_token m_messageCharSetColumnToken;
+ mdb_token m_threadParentColumnToken;
+ mdb_token m_threadRootKeyColumnToken;
+ mdb_token m_threadNewestMsgDateColumnToken;
+ mdb_token m_offlineMsgOffsetColumnToken;
+ mdb_token m_offlineMessageSizeColumnToken;
+
+ // header caching stuff - MRU headers, keeps them around in memory
+ nsresult AddHdrToCache(nsIMsgDBHdr* hdr, nsMsgKey key);
+ nsresult ClearHdrCache(bool reInit);
+ nsresult RemoveHdrFromCache(nsIMsgDBHdr* hdr, nsMsgKey key);
+ // all headers currently instantiated, doesn't hold refs
+ // these get added when msg hdrs get constructed, and removed when they get
+ // destroyed.
+ nsresult GetHdrFromUseCache(nsMsgKey key, nsIMsgDBHdr** result);
+ nsresult AddHdrToUseCache(nsIMsgDBHdr* hdr, nsMsgKey key);
+ nsresult ClearUseHdrCache();
+ nsresult RemoveHdrFromUseCache(nsIMsgDBHdr* hdr, nsMsgKey key);
+
+ // not-reference holding array of threads we've handed out.
+ // If a db goes away, it will clean up the outstanding threads.
+ // We use an nsTArray because we don't expect to ever have very many
+ // of these, rarely more than 5.
+ nsTArray<nsMsgThread*> m_threads;
+ // Clear outstanding thread objects
+ void ClearThreads();
+ nsMsgThread* FindExistingThread(nsMsgKey threadId);
+
+ mdb_pos FindInsertIndexInSortedTable(nsIMdbTable* table, mdb_id idToInsert);
+
+ void ClearCachedObjects(bool dbGoingAway);
+ void InvalidateEnumerators();
+ // all instantiated headers, but doesn't hold refs.
+ PLDHashTable* m_headersInUse;
+ static PLDHashNumber HashKey(const void* aKey);
+ static bool MatchEntry(const PLDHashEntryHdr* aEntry, const void* aKey);
+ static void MoveEntry(PLDHashTable* aTable, const PLDHashEntryHdr* aFrom,
+ PLDHashEntryHdr* aTo);
+ static void ClearEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry);
+ static PLDHashTableOps gMsgDBHashTableOps;
+ struct MsgHdrHashElement : public PLDHashEntryHdr {
+ nsMsgKey mKey;
+ nsIMsgDBHdr* mHdr;
+ };
+ PLDHashTable* m_cachedHeaders;
+ bool m_bCacheHeaders;
+ nsMsgKey m_cachedThreadId;
+ nsCOMPtr<nsIMsgThread> m_cachedThread;
+ nsCOMPtr<nsIMdbFactory> mMdbFactory;
+
+ // Message reference hash table
+ static PLDHashTableOps gRefHashTableOps;
+ struct RefHashElement : public PLDHashEntryHdr {
+ const char* mRef; // Hash entry key, must come first
+ nsMsgKey mThreadId;
+ uint32_t mCount;
+ };
+ PLDHashTable* m_msgReferences;
+ nsresult GetRefFromHash(nsCString& reference, nsMsgKey* threadId);
+ nsresult AddRefToHash(nsCString& reference, nsMsgKey threadId);
+ nsresult AddMsgRefsToHash(nsIMsgDBHdr* msgHdr);
+ nsresult RemoveRefFromHash(nsCString& reference);
+ nsresult RemoveMsgRefsFromHash(nsIMsgDBHdr* msgHdr);
+ nsresult InitRefHash();
+
+ // The enumerators add themselves to these lists.
+ // If a db goes away - via destruction or ForceClosed() - it needs to
+ // invalidate any outstanding enumerators.
+ nsTArray<nsMsgDBEnumerator*> m_msgEnumerators;
+ nsTArray<nsMsgDBThreadEnumerator*> m_threadEnumerators;
+
+ // Memory reporter details
+ public:
+ static size_t HeaderHashSizeOf(PLDHashEntryHdr* hdr,
+ mozilla::MallocSizeOf aMallocSizeOf,
+ void* arg);
+ virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+ virtual size_t SizeOfIncludingThis(
+ mozilla::MallocSizeOf aMallocSizeOf) const {
+ return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
+ }
+
+ private:
+ uint32_t m_cacheSize;
+ RefPtr<mozilla::mailnews::MsgDBReporter> mMemReporter;
+};
+
+class nsMsgRetentionSettings : public nsIMsgRetentionSettings {
+ public:
+ nsMsgRetentionSettings();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIMSGRETENTIONSETTINGS
+ protected:
+ virtual ~nsMsgRetentionSettings();
+ nsMsgRetainByPreference m_retainByPreference;
+ uint32_t m_daysToKeepHdrs;
+ uint32_t m_numHeadersToKeep;
+ bool m_useServerDefaults;
+ bool m_cleanupBodiesByDays;
+ uint32_t m_daysToKeepBodies;
+ bool m_applyToFlaggedMessages;
+};
+
+class nsMsgDownloadSettings : public nsIMsgDownloadSettings {
+ public:
+ nsMsgDownloadSettings();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIMSGDOWNLOADSETTINGS
+ protected:
+ virtual ~nsMsgDownloadSettings();
+ bool m_useServerDefaults;
+ bool m_downloadUnreadOnly;
+ bool m_downloadByDate;
+ int32_t m_ageLimitOfMsgsToDownload;
+};
+
+#endif