1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef _nsMsgDatabase_H_ 7 #define _nsMsgDatabase_H_ 8 9 #include "mozilla/Attributes.h" 10 #include "mozilla/MemoryReporting.h" 11 #include "mozilla/Path.h" 12 #include "nsIFile.h" 13 #include "nsIMsgDatabase.h" 14 #include "nsMsgHdr.h" 15 #include "nsString.h" 16 #include "nsIDBChangeAnnouncer.h" 17 #include "nsMsgMessageFlags.h" 18 #include "nsIMsgFolder.h" 19 #include "nsDBFolderInfo.h" 20 #include "nsICollation.h" 21 #include "nsIMimeConverter.h" 22 #include "nsCOMPtr.h" 23 #include "nsCOMArray.h" 24 #include "PLDHashTable.h" 25 #include "nsTArray.h" 26 #include "nsTObserverArray.h" 27 28 class nsMsgThread; 29 class nsMsgDatabase; 30 class nsIMsgThread; 31 class nsMsgDBEnumerator; 32 class nsMsgDBThreadEnumerator; 33 34 const int32_t kMsgDBVersion = 1; 35 36 // Hopefully we're not opening up lots of databases at the same time, however 37 // this will give us a buffer before we need to start reallocating the cache 38 // array. 39 const uint32_t kInitialMsgDBCacheSize = 20; 40 41 class nsMsgDBService final : public nsIMsgDBService { 42 public: 43 NS_DECL_ISUPPORTS 44 NS_DECL_NSIMSGDBSERVICE 45 46 nsMsgDBService(); 47 48 void AddToCache(nsMsgDatabase* pMessageDB); 49 void DumpCache(); EnsureCached(nsMsgDatabase * pMessageDB)50 void EnsureCached(nsMsgDatabase* pMessageDB) { 51 if (!m_dbCache.Contains(pMessageDB)) m_dbCache.AppendElement(pMessageDB); 52 } RemoveFromCache(nsMsgDatabase * pMessageDB)53 void RemoveFromCache(nsMsgDatabase* pMessageDB) { 54 m_dbCache.RemoveElement(pMessageDB); 55 } 56 57 protected: 58 ~nsMsgDBService(); 59 void HookupPendingListeners(nsIMsgDatabase* db, nsIMsgFolder* folder); 60 void FinishDBOpen(nsIMsgFolder* aFolder, nsMsgDatabase* aMsgDB); 61 nsMsgDatabase* FindInCache(nsIFile* dbName); 62 63 nsCOMArray<nsIMsgFolder> m_foldersPendingListeners; 64 nsCOMArray<nsIDBChangeListener> m_pendingListeners; 65 AutoTArray<nsMsgDatabase*, kInitialMsgDBCacheSize> m_dbCache; 66 }; 67 68 namespace mozilla { 69 namespace mailnews { 70 class MsgDBReporter; 71 } 72 } // namespace mozilla 73 74 class nsMsgDatabase : public nsIMsgDatabase { 75 public: 76 friend class nsMsgDBService; 77 friend class nsMsgPropertyEnumerator; // accesses m_mdbEnv and m_mdbStore 78 79 NS_DECL_ISUPPORTS 80 NS_DECL_NSIDBCHANGEANNOUNCER 81 NS_DECL_NSIMSGDATABASE 82 83 /** 84 * Opens a database folder. 85 * 86 * @param aFolderName The name of the folder to create. 87 * @param aCreate Whether or not the file should be created. 88 * @param aLeaveInvalidDB Set to true if you do not want the database to be 89 * deleted if it is invalid. 90 * @exception NS_ERROR_FILE_TARGET_DOES_NOT_EXIST 91 * The file could not be created. 92 * @exception NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE 93 * The database is present (and was opened), but the 94 * summary file is out of date. 95 * @exception NS_MSG_ERROR_FOLDER_SUMMARY_MISSING 96 * The database is present (and was opened), but the 97 * summary file is missing. 98 */ 99 virtual nsresult Open(nsMsgDBService* aDBService, nsIFile* aFolderName, 100 bool aCreate, bool aLeaveInvalidDB); 101 virtual nsresult IsHeaderRead(nsIMsgDBHdr* hdr, bool* pRead); 102 virtual nsresult MarkHdrReadInDB(nsIMsgDBHdr* msgHdr, bool bRead, 103 nsIDBChangeListener* instigator); 104 nsresult OpenInternal(nsMsgDBService* aDBService, nsIFile* aFolderName, 105 bool aCreate, bool aLeaveInvalidDB, bool sync); 106 nsresult CheckForErrors(nsresult err, bool sync, nsMsgDBService* aDBService, 107 nsIFile* summaryFile); 108 virtual nsresult OpenMDB(nsIFile* dbfile, bool create, bool sync); 109 virtual nsresult CloseMDB(bool commit); 110 virtual nsresult CreateMsgHdr(nsIMdbRow* hdrRow, nsMsgKey key, 111 nsIMsgDBHdr** result); 112 virtual nsresult GetThreadForMsgKey(nsMsgKey msgKey, nsIMsgThread** result); 113 virtual nsresult EnumerateMessagesWithFlag(nsIMsgEnumerator** result, 114 uint32_t* pFlag); 115 nsresult GetSearchResultsTable(const nsACString& searchFolderUri, 116 bool createIfMissing, nsIMdbTable** table); 117 118 ////////////////////////////////////////////////////////////////////////////// 119 // nsMsgDatabase methods: 120 nsMsgDatabase(); 121 122 nsresult GetMDBFactory(nsIMdbFactory** aMdbFactory); GetEnv()123 nsIMdbEnv* GetEnv() { return m_mdbEnv; } GetStore()124 nsIMdbStore* GetStore() { return m_mdbStore; } 125 virtual uint32_t GetCurVersion(); 126 nsresult GetCollationKeyGenerator(); 127 nsIMimeConverter* GetMimeConverter(); 128 129 nsresult GetTableCreateIfMissing(const char* scope, const char* kind, 130 nsIMdbTable** table, mdb_token& scopeToken, 131 mdb_token& kindToken); 132 133 // helper function to fill in nsStrings from hdr row cell contents. 134 nsresult RowCellColumnTonsString(nsIMdbRow* row, mdb_token columnToken, 135 nsAString& resultStr); 136 nsresult RowCellColumnToUInt32(nsIMdbRow* row, mdb_token columnToken, 137 uint32_t* uint32Result, 138 uint32_t defaultValue = 0); 139 nsresult RowCellColumnToUInt32(nsIMdbRow* row, mdb_token columnToken, 140 uint32_t& uint32Result, 141 uint32_t defaultValue = 0); 142 nsresult RowCellColumnToUInt64(nsIMdbRow* row, mdb_token columnToken, 143 uint64_t* uint64Result, 144 uint64_t defaultValue = 0); 145 nsresult RowCellColumnToMime2DecodedString(nsIMdbRow* row, 146 mdb_token columnToken, 147 nsAString& resultStr); 148 nsresult RowCellColumnToCollationKey(nsIMdbRow* row, mdb_token columnToken, 149 nsTArray<uint8_t>& result); 150 nsresult RowCellColumnToConstCharPtr(nsIMdbRow* row, mdb_token columnToken, 151 const char** ptr); 152 nsresult RowCellColumnToAddressCollationKey(nsIMdbRow* row, 153 mdb_token colToken, 154 nsTArray<uint8_t>& result); 155 156 nsresult GetEffectiveCharset(nsIMdbRow* row, nsACString& resultCharset); 157 158 // these methods take the property name as a string, not a token. 159 // they should be used when the properties aren't accessed a lot 160 nsresult GetProperty(nsIMdbRow* row, const char* propertyName, char** result); 161 nsresult SetProperty(nsIMdbRow* row, const char* propertyName, 162 const char* propertyVal); 163 nsresult GetPropertyAsNSString(nsIMdbRow* row, const char* propertyName, 164 nsAString& result); 165 nsresult SetPropertyFromNSString(nsIMdbRow* row, const char* propertyName, 166 const nsAString& propertyVal); 167 nsresult GetUint32Property(nsIMdbRow* row, const char* propertyName, 168 uint32_t* result, uint32_t defaultValue = 0); 169 nsresult GetUint64Property(nsIMdbRow* row, const char* propertyName, 170 uint64_t* result, uint64_t defaultValue = 0); 171 nsresult SetUint32Property(nsIMdbRow* row, const char* propertyName, 172 uint32_t propertyVal); 173 nsresult SetUint64Property(nsIMdbRow* row, const char* propertyName, 174 uint64_t propertyVal); 175 nsresult GetBooleanProperty(nsIMdbRow* row, const char* propertyName, 176 bool* result, bool defaultValue = false); 177 nsresult SetBooleanProperty(nsIMdbRow* row, const char* propertyName, 178 bool propertyVal); 179 // helper function for once we have the token. 180 nsresult SetNSStringPropertyWithToken(nsIMdbRow* row, mdb_token aProperty, 181 const nsAString& propertyStr); 182 183 // helper functions to put values in cells for the passed-in row 184 nsresult UInt32ToRowCellColumn(nsIMdbRow* row, mdb_token columnToken, 185 uint32_t value); 186 nsresult CharPtrToRowCellColumn(nsIMdbRow* row, mdb_token columnToken, 187 const char* charPtr); 188 nsresult RowCellColumnToCharPtr(nsIMdbRow* row, mdb_token columnToken, 189 char** result); 190 nsresult UInt64ToRowCellColumn(nsIMdbRow* row, mdb_token columnToken, 191 uint64_t value); 192 193 // helper functions to copy an nsString to a yarn, int32 to yarn, and vice 194 // versa. 195 static struct mdbYarn* nsStringToYarn(struct mdbYarn* yarn, 196 const nsAString& str); 197 static struct mdbYarn* UInt32ToYarn(struct mdbYarn* yarn, uint32_t i); 198 static struct mdbYarn* UInt64ToYarn(struct mdbYarn* yarn, uint64_t i); 199 static void YarnTonsString(struct mdbYarn* yarn, nsAString& str); 200 static void YarnTonsCString(struct mdbYarn* yarn, nsACString& str); 201 static void YarnToUInt32(struct mdbYarn* yarn, uint32_t* i); 202 static void YarnToUInt64(struct mdbYarn* yarn, uint64_t* i); 203 204 #ifdef DEBUG 205 virtual nsresult DumpContents(); 206 #endif 207 208 friend class nsMsgHdr; // use this to get access to cached tokens for hdr 209 // fields 210 friend class nsMsgThread; // use this to get access to cached tokens for hdr 211 // fields 212 213 friend class nsMsgDBEnumerator; 214 friend class nsMsgDBThreadEnumerator; 215 216 protected: 217 virtual ~nsMsgDatabase(); 218 219 // prefs stuff - in future, we might want to cache the prefs interface 220 nsresult GetBoolPref(const char* prefName, bool* result); 221 nsresult GetIntPref(const char* prefName, int32_t* result); 222 virtual void GetGlobalPrefs(); 223 // retrieval methods 224 nsIMsgThread* GetThreadForReference(nsCString& msgID, nsIMsgDBHdr** pMsgHdr); 225 nsIMsgThread* GetThreadForSubject(nsCString& subject); 226 nsIMsgThread* GetThreadForMessageId(nsCString& msgId); 227 nsIMsgThread* GetThreadForThreadId(nsMsgKey threadId); 228 nsMsgHdr* GetMsgHdrForReference(nsCString& reference); 229 nsIMsgDBHdr* GetMsgHdrForSubject(nsCString& subject); 230 // threading interfaces 231 virtual nsresult CreateNewThread(nsMsgKey key, const char* subject, 232 nsMsgThread** newThread); 233 virtual bool ThreadBySubjectWithoutRe(); 234 virtual bool UseStrictThreading(); 235 virtual bool UseCorrectThreading(); 236 virtual nsresult ThreadNewHdr(nsMsgHdr* hdr, bool& newThread); 237 virtual nsresult AddNewThread(nsMsgHdr* msgHdr); 238 virtual nsresult AddToThread(nsMsgHdr* newHdr, nsIMsgThread* thread, 239 nsIMsgDBHdr* pMsgHdr, bool threadInThread); 240 241 static PRTime gLastUseTime; // global last use time 242 PRTime m_lastUseTime; // last use time for this db 243 // inline to make instrumentation as cheap as possible RememberLastUseTime()244 inline void RememberLastUseTime() { gLastUseTime = m_lastUseTime = PR_Now(); } 245 246 bool MatchDbName(nsIFile* dbName); // returns TRUE if they match 247 248 // Flag handling routines 249 virtual nsresult SetKeyFlag(nsMsgKey key, bool set, nsMsgMessageFlagType flag, 250 nsIDBChangeListener* instigator = nullptr); 251 virtual nsresult SetMsgHdrFlag(nsIMsgDBHdr* msgHdr, bool set, 252 nsMsgMessageFlagType flag, 253 nsIDBChangeListener* instigator); 254 255 virtual bool SetHdrFlag(nsIMsgDBHdr*, bool bSet, nsMsgMessageFlagType flag); 256 virtual bool SetHdrReadFlag(nsIMsgDBHdr*, bool pRead); 257 virtual uint32_t GetStatusFlags(nsIMsgDBHdr* msgHdr, 258 nsMsgMessageFlagType origFlags); 259 // helper function which doesn't involve thread object 260 261 virtual nsresult RemoveHeaderFromDB(nsMsgHdr* msgHdr); 262 virtual nsresult RemoveHeaderFromThread(nsMsgHdr* msgHdr); 263 virtual nsresult AdjustExpungedBytesOnDelete(nsIMsgDBHdr* msgHdr); 264 265 nsCOMPtr<nsICollation> m_collationKeyGenerator; 266 nsCOMPtr<nsIMimeConverter> m_mimeConverter; 267 nsCOMPtr<nsIMsgRetentionSettings> m_retentionSettings; 268 nsCOMPtr<nsIMsgDownloadSettings> m_downloadSettings; 269 270 nsresult FindMessagesOlderThan(uint32_t daysToKeepHdrs, 271 bool applyToFlaggedMessages, 272 nsTArray<RefPtr<nsIMsgDBHdr>>& hdrsToDelete); 273 nsresult FindExcessMessages(uint32_t numHeadersToKeep, 274 bool applyToFlaggedMessages, 275 nsTArray<RefPtr<nsIMsgDBHdr>>& hdrsToDelete); 276 277 // mdb bookkeeping stuff 278 virtual nsresult InitExistingDB(); 279 virtual nsresult InitNewDB(); 280 virtual nsresult InitMDBInfo(); 281 282 nsCOMPtr<nsIMsgFolder> m_folder; 283 RefPtr<nsDBFolderInfo> m_dbFolderInfo; 284 nsMsgKey m_nextPseudoMsgKey; 285 nsIMdbEnv* m_mdbEnv; // to be used in all the db calls. 286 nsIMdbStore* m_mdbStore; 287 nsIMdbTable* m_mdbAllMsgHeadersTable; 288 nsIMdbTable* m_mdbAllThreadsTable; 289 290 // Used for asynchronous db opens. If non-null, we're still opening 291 // the underlying mork database. If null, the db has been completely opened. 292 nsCOMPtr<nsIMdbThumb> m_thumb; 293 // used to remember the args to Open for async open. 294 bool m_create; 295 bool m_leaveInvalidDB; 296 297 nsCOMPtr<nsIFile> m_dbFile; 298 nsTArray<nsMsgKey> m_newSet; // new messages since last open. 299 bool m_mdbTokensInitialized; 300 nsTObserverArray<nsCOMPtr<nsIDBChangeListener>> m_ChangeListeners; 301 mdb_token m_hdrRowScopeToken; 302 mdb_token m_threadRowScopeToken; 303 mdb_token m_hdrTableKindToken; 304 mdb_token m_threadTableKindToken; 305 mdb_token m_allThreadsTableKindToken; 306 mdb_token m_subjectColumnToken; 307 mdb_token m_senderColumnToken; 308 mdb_token m_messageIdColumnToken; 309 mdb_token m_referencesColumnToken; 310 mdb_token m_recipientsColumnToken; 311 mdb_token m_dateColumnToken; 312 mdb_token m_messageSizeColumnToken; 313 mdb_token m_flagsColumnToken; 314 mdb_token m_priorityColumnToken; 315 mdb_token m_labelColumnToken; 316 mdb_token m_statusOffsetColumnToken; 317 mdb_token m_numLinesColumnToken; 318 mdb_token m_ccListColumnToken; 319 mdb_token m_bccListColumnToken; 320 mdb_token m_threadFlagsColumnToken; 321 mdb_token m_threadIdColumnToken; 322 mdb_token m_threadChildrenColumnToken; 323 mdb_token m_threadUnreadChildrenColumnToken; 324 mdb_token m_messageThreadIdColumnToken; 325 mdb_token m_threadSubjectColumnToken; 326 mdb_token m_messageCharSetColumnToken; 327 mdb_token m_threadParentColumnToken; 328 mdb_token m_threadRootKeyColumnToken; 329 mdb_token m_threadNewestMsgDateColumnToken; 330 mdb_token m_offlineMsgOffsetColumnToken; 331 mdb_token m_offlineMessageSizeColumnToken; 332 333 // header caching stuff - MRU headers, keeps them around in memory 334 nsresult AddHdrToCache(nsIMsgDBHdr* hdr, nsMsgKey key); 335 nsresult ClearHdrCache(bool reInit); 336 nsresult RemoveHdrFromCache(nsIMsgDBHdr* hdr, nsMsgKey key); 337 // all headers currently instantiated, doesn't hold refs 338 // these get added when msg hdrs get constructed, and removed when they get 339 // destroyed. 340 nsresult GetHdrFromUseCache(nsMsgKey key, nsIMsgDBHdr** result); 341 nsresult AddHdrToUseCache(nsIMsgDBHdr* hdr, nsMsgKey key); 342 nsresult ClearUseHdrCache(); 343 nsresult RemoveHdrFromUseCache(nsIMsgDBHdr* hdr, nsMsgKey key); 344 345 // not-reference holding array of threads we've handed out. 346 // If a db goes away, it will clean up the outstanding threads. 347 // We use an nsTArray because we don't expect to ever have very many 348 // of these, rarely more than 5. 349 nsTArray<nsMsgThread*> m_threads; 350 // Clear outstanding thread objects 351 void ClearThreads(); 352 nsMsgThread* FindExistingThread(nsMsgKey threadId); 353 354 mdb_pos FindInsertIndexInSortedTable(nsIMdbTable* table, mdb_id idToInsert); 355 356 void ClearCachedObjects(bool dbGoingAway); 357 void InvalidateEnumerators(); 358 // all instantiated headers, but doesn't hold refs. 359 PLDHashTable* m_headersInUse; 360 static PLDHashNumber HashKey(const void* aKey); 361 static bool MatchEntry(const PLDHashEntryHdr* aEntry, const void* aKey); 362 static void MoveEntry(PLDHashTable* aTable, const PLDHashEntryHdr* aFrom, 363 PLDHashEntryHdr* aTo); 364 static void ClearEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry); 365 static PLDHashTableOps gMsgDBHashTableOps; 366 struct MsgHdrHashElement : public PLDHashEntryHdr { 367 nsMsgKey mKey; 368 nsIMsgDBHdr* mHdr; 369 }; 370 PLDHashTable* m_cachedHeaders; 371 bool m_bCacheHeaders; 372 nsMsgKey m_cachedThreadId; 373 nsCOMPtr<nsIMsgThread> m_cachedThread; 374 nsCOMPtr<nsIMdbFactory> mMdbFactory; 375 376 // Message reference hash table 377 static PLDHashTableOps gRefHashTableOps; 378 struct RefHashElement : public PLDHashEntryHdr { 379 const char* mRef; // Hash entry key, must come first 380 nsMsgKey mThreadId; 381 uint32_t mCount; 382 }; 383 PLDHashTable* m_msgReferences; 384 nsresult GetRefFromHash(nsCString& reference, nsMsgKey* threadId); 385 nsresult AddRefToHash(nsCString& reference, nsMsgKey threadId); 386 nsresult AddMsgRefsToHash(nsIMsgDBHdr* msgHdr); 387 nsresult RemoveRefFromHash(nsCString& reference); 388 nsresult RemoveMsgRefsFromHash(nsIMsgDBHdr* msgHdr); 389 nsresult InitRefHash(); 390 391 // The enumerators add themselves to these lists. 392 // If a db goes away - via destruction or ForceClosed() - it needs to 393 // invalidate any outstanding enumerators. 394 nsTArray<nsMsgDBEnumerator*> m_msgEnumerators; 395 nsTArray<nsMsgDBThreadEnumerator*> m_threadEnumerators; 396 397 // Memory reporter details 398 public: 399 static size_t HeaderHashSizeOf(PLDHashEntryHdr* hdr, 400 mozilla::MallocSizeOf aMallocSizeOf, 401 void* arg); 402 virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)403 virtual size_t SizeOfIncludingThis( 404 mozilla::MallocSizeOf aMallocSizeOf) const { 405 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 406 } 407 408 private: 409 uint32_t m_cacheSize; 410 RefPtr<mozilla::mailnews::MsgDBReporter> mMemReporter; 411 }; 412 413 class nsMsgRetentionSettings : public nsIMsgRetentionSettings { 414 public: 415 nsMsgRetentionSettings(); 416 417 NS_DECL_ISUPPORTS 418 NS_DECL_NSIMSGRETENTIONSETTINGS 419 protected: 420 virtual ~nsMsgRetentionSettings(); 421 nsMsgRetainByPreference m_retainByPreference; 422 uint32_t m_daysToKeepHdrs; 423 uint32_t m_numHeadersToKeep; 424 bool m_useServerDefaults; 425 bool m_cleanupBodiesByDays; 426 uint32_t m_daysToKeepBodies; 427 bool m_applyToFlaggedMessages; 428 }; 429 430 class nsMsgDownloadSettings : public nsIMsgDownloadSettings { 431 public: 432 nsMsgDownloadSettings(); 433 434 NS_DECL_ISUPPORTS 435 NS_DECL_NSIMSGDOWNLOADSETTINGS 436 protected: 437 virtual ~nsMsgDownloadSettings(); 438 bool m_useServerDefaults; 439 bool m_downloadUnreadOnly; 440 bool m_downloadByDate; 441 int32_t m_ageLimitOfMsgsToDownload; 442 }; 443 444 #endif 445