Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1

This commit is contained in:
Matt A. Tobin 2019-11-03 00:17:46 -04:00 • committed by Roy Tam
commit e400f4130a
1564 changed files with 510348 additions and 0 deletions

View file

@ -0,0 +1,9 @@
# vim: set filetype=python:
# 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/.
DIRS += [
'public',
'src',
]

View file

@ -0,0 +1,27 @@
# vim: set filetype=python:
# 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/.
XPIDL_SOURCES += [
'nsIDBChangeAnnouncer.idl',
'nsIDBChangeListener.idl',
'nsIDBFolderInfo.idl',
'nsIMsgDatabase.idl',
'nsIMsgOfflineImapOperation.idl',
'nsINewsDatabase.idl',
]
XPIDL_MODULE = 'msgdb'
EXPORTS += [
'nsDBFolderInfo.h',
'nsImapMailDatabase.h',
'nsMailDatabase.h',
'nsMsgDatabase.h',
'nsMsgDBCID.h',
'nsMsgHdr.h',
'nsMsgThread.h',
'nsNewsDatabase.h',
]

View file

@ -0,0 +1,135 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
/* This class encapsulates the global information about a folder stored in the
summary file.
*/
#ifndef _nsDBFolderInfo_H
#define _nsDBFolderInfo_H
#include "mozilla/MemoryReporting.h"
#include "nsStringGlue.h"
#include "MailNewsTypes.h"
#include "mdb.h"
#include "nsTArray.h"
#include "nsIDBFolderInfo.h"
#include <time.h>
class nsMsgDatabase;
// again, this could inherit from nsISupports, but I don't see the need as of yet.
// I'm not sure it needs to be ref-counted (but I think it does).
// I think these getters and setters really need to go through mdb and not rely on the object
// caching the values. If this somehow turns out to be prohibitively expensive, we can invent
// some sort of dirty mechanism, but I think it turns out that these values will be cached by
// the MSG_FolderInfo's anyway.
class nsDBFolderInfo : public nsIDBFolderInfo
{
public:
friend class nsMsgDatabase;
nsDBFolderInfo(nsMsgDatabase *mdb);
NS_DECL_ISUPPORTS
// interface methods.
NS_DECL_NSIDBFOLDERINFO
// create the appropriate table and row in a new db.
nsresult AddToNewMDB();
// accessor methods.
bool TestFlag(int32_t flags);
int16_t GetIMAPHierarchySeparator() ;
void SetIMAPHierarchySeparator(int16_t hierarchyDelimiter) ;
void ChangeImapTotalPendingMessages(int32_t delta);
void ChangeImapUnreadPendingMessages(int32_t delta) ;
nsresult InitFromExistingDB();
// get and set arbitrary property, aka row cell value.
nsresult SetPropertyWithToken(mdb_token aProperty, const nsAString &propertyStr);
nsresult SetUint32PropertyWithToken(mdb_token aProperty, uint32_t propertyValue);
nsresult SetInt64PropertyWithToken(mdb_token aProperty, int64_t propertyValue);
nsresult SetInt32PropertyWithToken(mdb_token aProperty, int32_t propertyValue);
nsresult GetPropertyWithToken(mdb_token aProperty, nsAString &propertyValue);
nsresult GetUint32PropertyWithToken(mdb_token aProperty, uint32_t &propertyValue, uint32_t defaultValue = 0);
nsresult GetInt32PropertyWithToken(mdb_token aProperty, int32_t &propertyValue, int32_t defaultValue = 0);
nsresult GetInt64PropertyWithToken(mdb_token aProperty,
int64_t &propertyValue, int64_t defaultValue = 0);
nsTArray<nsMsgKey> m_lateredKeys; // list of latered messages
virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
{
return m_lateredKeys.ShallowSizeOfExcludingThis(aMallocSizeOf);
}
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
{
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
protected:
virtual ~nsDBFolderInfo();
// initialize from appropriate table and row in existing db.
nsresult InitMDBInfo();
nsresult LoadMemberVariables();
nsresult AdjustHighWater(nsMsgKey highWater, bool force);
void ReleaseExternalReferences(); // let go of any references to other objects.
int64_t m_folderSize;
int64_t m_expungedBytes; // sum of size of deleted messages in folder
uint32_t m_folderDate;
nsMsgKey m_highWaterMessageKey; // largest news article number or imap uid whose header we've seen
// m_numUnreadMessages and m_numMessages can never be negative. 0 means 'no msgs'.
int32_t m_numUnreadMessages;
int32_t m_numMessages; // includes expunged and ignored messages
int32_t m_flags; // folder specific flags. This holds things like re-use thread pane,
// configured for off-line use, use default retrieval, purge article/header options
uint16_t m_version; // for upgrading...
int16_t m_IMAPHierarchySeparator; // imap path separator
// mail only (for now)
// IMAP only
int32_t m_ImapUidValidity;
int32_t m_totalPendingMessages;
int32_t m_unreadPendingMessages;
// news only (for now)
nsMsgKey m_expiredMark; // Highest invalid article number in group - for expiring
// the db folder info will have to know what db and row it belongs to, since it is really
// just a wrapper around the singleton folder info row in the mdb.
nsMsgDatabase *m_mdb;
nsIMdbTable *m_mdbTable; // singleton table in db
nsIMdbRow *m_mdbRow; // singleton row in table;
nsCString m_charSet;
bool m_charSetOverride;
bool m_mdbTokensInitialized;
mdb_token m_rowScopeToken;
mdb_token m_tableKindToken;
// tokens for the pre-set columns - we cache these for speed, which may be silly
mdb_token m_mailboxNameColumnToken;
mdb_token m_numMessagesColumnToken;
mdb_token m_numUnreadMessagesColumnToken;
mdb_token m_flagsColumnToken;
mdb_token m_folderSizeColumnToken;
mdb_token m_expungedBytesColumnToken;
mdb_token m_folderDateColumnToken;
mdb_token m_highWaterMessageKeyColumnToken;
mdb_token m_imapUidValidityColumnToken;
mdb_token m_totalPendingMessagesColumnToken;
mdb_token m_unreadPendingMessagesColumnToken;
mdb_token m_expiredMarkColumnToken;
mdb_token m_versionColumnToken;
};
#endif

View file

@ -0,0 +1,33 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 "nsISupports.idl"
#include "MailNewsTypes2.idl"
interface nsIDBChangeListener;
interface nsIMsgDBHdr;
[scriptable, uuid(22baf00b-939d-42c3-ac51-21d99dfa1f05)]
interface nsIDBChangeAnnouncer : nsISupports {
/* these 2 calls return NS_OK on success, NS_COMFALSE on failure */
void AddListener(in nsIDBChangeListener listener);
void RemoveListener(in nsIDBChangeListener listener);
void NotifyHdrChangeAll(in nsIMsgDBHdr aHdrChanged, in unsigned long aOldFlags, in unsigned long aNewFlags,
in nsIDBChangeListener instigator);
void NotifyHdrAddedAll(in nsIMsgDBHdr aHdrAdded, in nsMsgKey parentKey, in long flags,
in nsIDBChangeListener instigator);
void NotifyHdrDeletedAll(in nsIMsgDBHdr aHdrDeleted, in nsMsgKey parentKey, in long flags,
in nsIDBChangeListener instigator);
void NotifyParentChangedAll(in nsMsgKey keyReparented, in nsMsgKey oldParent, in nsMsgKey newParent, in nsIDBChangeListener instigator);
void NotifyReadChanged(in nsIDBChangeListener instigator);
void NotifyJunkScoreChanged(in nsIDBChangeListener aInstigator);
void NotifyAnnouncerGoingAway();
};

View file

@ -0,0 +1,115 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 "nsISupports.idl"
#include "MailNewsTypes2.idl"
interface nsIDBChangeAnnouncer;
interface nsIMsgDBHdr;
interface nsIMsgDatabase;
/**
* These callbacks are provided to allow listeners to the message database
* to update their status when changes occur.
*/
[scriptable, uuid(21c56d34-71b9-42bb-9606-331a6a5f8210)]
interface nsIDBChangeListener : nsISupports {
/**
* Callback when message flags are changed.
*
* @param aHdrChanged The changed header.
* @param aOldFlags Message flags prior to change.
* @param aNewFlags Message flags after change.
* @param aInstigator Object that initiated the change.
*/
void onHdrFlagsChanged(in nsIMsgDBHdr aHdrChanged, in unsigned long aOldFlags,
in unsigned long aNewFlags, in nsIDBChangeListener aInstigator);
/**
* Callback when message is marked as deleted.
*
* @param aHdrChanged The message header that is going to be deleted.
* @param aParentKey Key of parent.
* @param aFlags Flags that message has before delete.
* @param aInstigator Object that initiated the change. Can be null.
*/
void onHdrDeleted(in nsIMsgDBHdr aHdrChanged, in nsMsgKey aParentKey, in long aFlags,
in nsIDBChangeListener aInstigator);
/**
* Callback when message is added.
*
* @param aHdrChanged The message header that is added.
* @param aParentKey Parent key of message.
* @param aFlags Flags that new message will have.
* @param aInstigator Object that initiated the change. Can be null.
*/
void onHdrAdded(in nsIMsgDBHdr aHdrChanged, in nsMsgKey aParentKey, in long aFlags,
in nsIDBChangeListener aInstigator);
/**
* Callback when message parrent is changed. Parent is changed when message is deleted or moved.
*
* @param aKeyChanged The message key that parent key was changed.
* @param oldParent Old parent key.
* @param newParent New parent key.
* @param aInstigator Object that initiated the change. Can be null.
*/
void onParentChanged(in nsMsgKey aKeyChanged, in nsMsgKey oldParent, in nsMsgKey newParent,
in nsIDBChangeListener aInstigator);
/**
* Callback when announcer is going away. This is good place to release strong pointers to announcer.
*
* @param instigator Object that initiated the change. Can be null.
*/
void onAnnouncerGoingAway(in nsIDBChangeAnnouncer instigator);
/**
* Callback when read flag is changed.
*
* @param aInstigator Object that initiated the change. Can be null.
*/
void onReadChanged(in nsIDBChangeListener aInstigator);
/**
* Callback used in case when "junkscore" property is changed.
*
* @param aInstigator Object that initiated the change. Can be null.
*/
void onJunkScoreChanged(in nsIDBChangeListener aInstigator);
/**
* Callback used in the general case where any field may have changed.
* OnHdrPropertyChanged is called twice per change. On the first call, aPreChange
* is true, and aStatus is undefined. OnHdrPropertyChanged saves any required status in aStatus
* (such as a filter match). The calling function stores the value of aStatus, changes the
* header aHdrToChange, then calls OnHdrPropertyChanged again with aPreChange false. On this
* second call, the stored value of aStatus is provided, so that any changes may be noted.
*
* @param aHdrToChange the message header that is changing.
* @param aPreChange true on first call before change, false on second call after change
* @param aStatus storage location provided by calling routine for status
* @param aInstigator object that initiated the change
*/
void onHdrPropertyChanged(in nsIMsgDBHdr aHdrToChange, in boolean aPreChange, inout uint32_t aStatus,
in nsIDBChangeListener aInstigator);
/**
* Generic notification for extensibility. Common events should be documented
* here so we have a hope of keeping the documentation up to date.
* Current events are:
* "DBOpened" - When a pending listener becomes real. This can happen when
* the existing db is force closed and a new one opened. Only
* registered pending listeners are notified.
*
* @param aDB the db for this event.
* @param aEvent type of event.
*
*/
void onEvent(in nsIMsgDatabase aDB, in string aEvent);
};

View file

@ -0,0 +1,108 @@
/* -*- 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 "nsISupports.idl"
#include "MailNewsTypes2.idl"
[scriptable, uuid(a72dab4b-b3bd-471e-9a38-1b242b385459)]
interface nsIDBFolderInfo : nsISupports {
attribute long flags;
/**
* Or's aFlags into flags.
*
* @param - the flags(s) to set
*
* @return - the resulting flags.
*/
long orFlags(in long aFlags);
/**
* And's aFlags with flags, set flags to the result
*
* @param the flags(s) to AND
*
* @return the resulting flags.
*/
long andFlags(in long aFlags);
/**
* Allows us to keep track of the highwater mark
*
* @param aNewKey If larger than the current highwater
* mark, sets the highwater mark to aNewKey.
*/
void onKeyAdded(in nsMsgKey aNewKey);
attribute nsMsgKey highWater;
attribute nsMsgKey expiredMark;
attribute long long folderSize;
attribute unsigned long folderDate;
void changeNumUnreadMessages(in long aDelta);
void changeNumMessages(in long aDelta);
// numUnreadMessages and numMessages will never return negative numbers. 0 means 'no msgs'.
attribute long numUnreadMessages;
attribute long numMessages;
attribute long long expungedBytes;
attribute long imapUidValidity;
attribute unsigned long version;
attribute long imapTotalPendingMessages;
attribute long imapUnreadPendingMessages;
attribute nsMsgViewTypeValue viewType;
attribute nsMsgViewFlagsTypeValue viewFlags;
attribute nsMsgViewSortTypeValue sortType;
attribute nsMsgViewSortOrderValue sortOrder;
void changeExpungedBytes(in long aDelta);
/**
* Gets a string property from the folder.
*
* @param propertyName The name of the property for the value to retrieve.
*/
ACString getCharProperty(in string propertyName);
/**
* Sets a string property from the folder.
*
* @param propertyName The name of the property for which to set a value
* @param propertyValue The new value of the property.
*/
void setCharProperty(in string aPropertyName, in ACString aPropertyValue);
void setUint32Property(in string propertyName, in unsigned long propertyValue);
void setInt64Property(in string propertyName, in long long propertyValue);
unsigned long getUint32Property(in string propertyName, in unsigned long defaultValue);
long long getInt64Property(in string propertyName, in long long defaultValue);
boolean getBooleanProperty(in string propertyName, in boolean defaultValue);
void setBooleanProperty(in string propertyName, in boolean aPropertyValue);
nsIDBFolderInfo GetTransferInfo();
void initFromTransferInfo(in nsIDBFolderInfo transferInfo);
/**
* Gets/Sets the current character set for the folder. If there is no
* specific character set for the folder, it will return an empty string.
*/
attribute ACString characterSet;
/**
* Returns the effective character set on the folder. If there is no specific
* set defined for the folder, it will return the default character set.
*/
readonly attribute ACString effectiveCharacterSet;
attribute boolean characterSetOverride;
attribute AString locale;
attribute AString mailboxName;
AString getProperty(in string propertyName);
void setProperty(in string propertyName, in AString propertyStr);
attribute string knownArtsSet;
attribute ACString folderName;
};

View file

@ -0,0 +1,570 @@
/* -*- 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/. */
/**
* @defgroup msgdb Mailnews message database
* This module is the access point to locally-stored databases.
*
* These databases are stored in .msf files. Each file contains useful cached
* information, like the message id or references, as well as the cc header or
* tag information. This cached information is encapsulated in nsIMsgDBHdr.
*
* Also included is threading information, mostly encapsulated in nsIMsgThread.
* The final component is the database folder info, which contains information
* on the view and basic information also stored in the folder cache such as the
* name or most recent update.
*
* What this module does not do is access individual messages. Access is
* strictly controlled by the nsIMsgFolder objects and their backends.
* @{
*/
#include "nsISupports.idl"
#include "nsIDBChangeAnnouncer.idl"
%{C++
#include "nsTArray.h"
%}
interface nsIMutableArray;
interface nsIMsgDatabase;
interface nsIMsgDBView;
interface nsIDBChangeListener;
interface nsIMsgDBHdr;
interface nsISimpleEnumerator;
interface nsIMsgThread;
interface nsIDBFolderInfo;
interface nsIMsgOfflineImapOperation;
interface nsIMsgFolder;
interface nsIMsgKeyArray;
interface nsIFile;
interface nsIArray;
typedef unsigned long nsMsgRetainByPreference;
[scriptable, uuid(fe8b7cec-eec8-4bcd-82ff-d8bb23cef3da)]
interface nsIMsgRetentionSettings : nsISupports
{
const unsigned long nsMsgRetainAll = 1;
const unsigned long nsMsgRetainByAge = 2;
const unsigned long nsMsgRetainByNumHeaders = 3;
attribute boolean useServerDefaults;
attribute nsMsgRetainByPreference retainByPreference;
attribute unsigned long daysToKeepHdrs;
attribute unsigned long numHeadersToKeep;
// this is for keeping offline bodies.
attribute boolean cleanupBodiesByDays;
attribute unsigned long daysToKeepBodies;
/**
* Should retention settings be applied to flagged/starred messages?
* If false, flagged messages are never automatically deleted.
*/
attribute boolean applyToFlaggedMessages;
};
[scriptable, uuid(86a9da90-14f1-11d5-a5c0-0060b0fc04b7)]
interface nsIMsgDownloadSettings : nsISupports
{
attribute boolean useServerDefaults;
attribute boolean downloadByDate;
attribute boolean downloadUnreadOnly;
attribute unsigned long ageLimitOfMsgsToDownload;
};
typedef long nsMsgDBCommit;
[scriptable, uuid(15431853-e448-45dc-8978-9958bf74d9b7)]
interface nsMsgDBCommitType
{
const long kLargeCommit = 1;
const long kSessionCommit = 2;
const long kCompressCommit = 3;
};
[ref] native nsMsgKeyArrayRef(nsTArray<nsMsgKey>);
[ptr] native nsMsgKeyArrayPtr(nsTArray<nsMsgKey>);
/**
* A service to open mail databases and manipulate listeners automatically.
*
* The contract ID for this component is
* <tt>\@mozilla.org/msgDatabase/msgDBService;1</tt>.
*/
[scriptable, uuid(4cbbf024-3760-402d-89f3-6ababafeb07d)]
interface nsIMsgDBService : nsISupports
{
/**
* Opens a database for a given folder.
*
* This method is preferred over nsIMsgDBService::openMailDBFromFile if the
* caller has an actual nsIMsgFolder around. If the database detects that it
* is unreadable or out of date (using nsIMsgDatabase::outOfDate) it will
* destroy itself and prepare to be rebuilt, unless aLeaveInvalidDB is true.
*
* If one gets a NS_MSG_ERROR_FOLDER_SUMMARY_MISSING message, then one
* should call nsIMsgDBService::createNewDB to create the new database.
*
* @param aFolder The folder whose database should be returned.
* @param aLeaveInvalidDB Whether or not the database should be deleted if it
* is invalid.
* @return A new nsIMsgDatabase object representing the folder
* database that was opened.
* @exception NS_ERROR_FILE_TARGET_DOES_NOT_EXIST
* 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, but the summary file is
* missing.
* @see nsIMsgDatabase::Open
* @see nsIMsgDBService::createNewDB
*/
nsIMsgDatabase openFolderDB(in nsIMsgFolder aFolder,
in boolean aLeaveInvalidDB);
/**
* This is the same as a synchronous open in terms of params and errors.
* But to finish opening the db, the caller must call
* nsIMsgDBService::OpenMore repeatedly until the open is finished.
* @see nsIMsgDBService::openFolderDB
* @see nsIMsgDBService::openMore
*/
nsIMsgDatabase asyncOpenFolderDB(in nsIMsgFolder aFolder,
in boolean aLeaveInvalidDB);
/**
* Continues the open process for a db opened with
* nsIMsgDBService::asyncOpenFolderDB. Returns true if the db is ready
* to use, false if openMore needs to be called again.
* This will throw the same kinds of exceptions as openFolderDB.
* @param aTimeHint approximate number of milliseconds to spend
* before returning. This is more of a floor than
a ceiling, since we can't guarantee that there
won't be one big chunk that we can't interrupt.
* @return true if db is ready to use, false if openMore needs to
* be called again.
* @see nsIMsgDBService::openFolderDB
*/
boolean openMore(in nsIMsgDatabase aDB, in unsigned long aTimeHint);
/**
* Creates a new database for the given folder.
*
* If the database already exists, it will return the database, emit a
* warning, but not fully initialize it. For this reason, it should only be
* used when it is known that the database does not exist, such as when
* nsIMsgDBService::openFolderDB throws an error.
*
* @see nsIMsgDBService::openFolderDB
*/
nsIMsgDatabase createNewDB(in nsIMsgFolder aFolder);
/**
* Opens or creates a database for a given file.
*
* This method should only be used if the caller does not have a folder
* instance, because the resulting db and message headers retrieved from the
* database would not know their owning folder, which limits their usefulness.
* For this reason, one should use nsIMsgDBService::openFolderDB instead
* except under special circumstances.
*
* Unlike nsIMsgDBService::openFolderDB, there is no corresponding method to
* create a new database if opening the database failed. However, this method
* will never throw NS_MSG_ERROR_FOLDER_SUMMARY_MISSING, so no corresponding
* method is needed.
*
* @param aFile The file for which the database should be returned.
* @param aFolder Folder the db corresponds to (may be null)
* @param aCreate Whether or not the file should be created.
* @param aLeaveInvalidDB Whether or not the database should be deleted if it
* is invalid.
* @return A new nsIMsgDatabase object encapsulating the file
* passed in.
* @exception NS_ERROR_FILE_TARGET_DOES_NOT_EXIST
* The file could not be created.
* @see nsIMsgDBService::openFolderDB
* @see nsIMsgDatabase::Open
*/
nsIMsgDatabase openMailDBFromFile(in nsIFile aFile,
in nsIMsgFolder aFolder,
in boolean aCreate,
in boolean aLeaveInvalidDB);
/**
* Adds the given listener to the listener set for the folder.
*
* Since the message database will likely be opened and closed many times, by
* registering using this method, one will be guaranteed to see all subsequent
* modifications. This will also add the listener to the database if it is
* already opened.
*
* @param aFolder The folder to add a listener to.
* @param aListener The listener to add the folder to.
*/
void registerPendingListener(in nsIMsgFolder aFolder,
in nsIDBChangeListener aListener);
/**
* Removes the listener from all folder listener sets.
*
* @param aListener The listener to remove.
* @exception NS_ERROR_FAILURE
* The listener is not registered.
*/
void unregisterPendingListener(in nsIDBChangeListener aListener);
/**
* Get the db for a folder, if already open.
*
* @param aFolder The folder to get the cached (open) db for.
*
* @returns null if the db isn't open, otherwise the db.
*/
nsIMsgDatabase cachedDBForFolder(in nsIMsgFolder aFolder);
/**
* Close the db for a folder, if already open.
*
* @param aFolder The folder to close the cached (open) db for.
*/
void forceFolderDBClosed(in nsIMsgFolder aFolder);
/// an enumerator to iterate over the open dbs.
readonly attribute nsIArray openDBs;
};
[scriptable, uuid(b64e66f8-4717-423a-be42-482658fb2199)]
interface nsIMsgDatabase : nsIDBChangeAnnouncer {
void Close(in boolean aForceCommit);
void Commit(in nsMsgDBCommit commitType);
// Force closed is evil, and we should see if we can do without it.
// In 4.x, it was mainly used to remove corrupted databases.
void ForceClosed();
void clearCachedHdrs();
void resetHdrCacheSize(in unsigned long size);
readonly attribute nsIDBFolderInfo dBFolderInfo;
/// Size of the database file in bytes.
readonly attribute long long databaseSize;
/// Folder this db was opened on.
readonly attribute nsIMsgFolder folder;
/**
* This is used when deciding which db's to close to free up memory
* and other resources in an LRU manner. It doesn't track every operation
* on every object from the db, but high level things like open, commit,
* and perhaps some of the list methods. Commit should be a proxy for all
* the mutation methods.
*
* I'm allowing clients to set the last use time as well, so that
* nsIMsgFolder.msgDatabase can set the last use time.
*/
attribute PRTime lastUseTime;
// get a message header for the given key. Caller must release()!
nsIMsgDBHdr GetMsgHdrForKey(in nsMsgKey key);
nsIMsgDBHdr getMsgHdrForMessageID(in string messageID);
/**
* get a message header for a Gmail message with the given X-GM-MSGID.
*/
nsIMsgDBHdr GetMsgHdrForGMMsgID(in string aGmailMessageID);
//Returns whether or not this database contains the given key
boolean ContainsKey(in nsMsgKey key);
/**
* Must call AddNewHdrToDB after creating. The idea is that you create
* a new header, fill in its properties, and then call AddNewHdrToDB.
* AddNewHdrToDB will send notifications to any listeners.
*
* @param aKey msgKey for the new header. If aKey is nsMsgKey_None,
* we will auto-assign a new key.
*/
nsIMsgDBHdr CreateNewHdr(in nsMsgKey aKey);
void AddNewHdrToDB(in nsIMsgDBHdr newHdr, in boolean notify);
nsIMsgDBHdr CopyHdrFromExistingHdr(in nsMsgKey key, in nsIMsgDBHdr existingHdr, in boolean addHdrToDB);
/**
* Returns all message keys stored in the database.
* Keys are returned in the order as stored in the database.
* The caller should sort them if it needs to.
*/
void ListAllKeys(in nsIMsgKeyArray array);
nsISimpleEnumerator EnumerateMessages();
nsISimpleEnumerator ReverseEnumerateMessages();
nsISimpleEnumerator EnumerateThreads();
/**
* Get an enumerator for use with nextMatchingHdrs. The enumerator
* will only return messages that match the passed-in search terms.
*
* @param searchTerms array of search terms to evaluate.
* @param reverse start at the end, defaults to false.
*
* @returns an enumerator for passing into nextMatchingHdrs
*/
nsISimpleEnumerator getFilterEnumerator(in nsIArray searchTerms,
[optional] in boolean reverse);
/**
* Get the next N matching headers using a filter enumerator
* obtained by calling getFilterEnumerator.
*
* @param enumerator - This *must* be a filter enumerator
* @param numHdrsToLookAt if non 0, the number of hdrs to advance the
* enumerator before returning.
* @param maxResults if non 0, the max results to return.
* @param matchingHdrs if non null, array of matching hdrs.
* @param numMatches if non null, the number of matching hdrs.
*
* @returns false, if done, true if more hdrs to look at.
*/
boolean nextMatchingHdrs(in nsISimpleEnumerator enumerator,
in long numHdrsToLookAt,
in long maxResults,
in nsIMutableArray matchingHdrs,
out long numMatches);
// count the total and unread msgs, and adjust global count if needed
void syncCounts();
nsIMsgThread GetThreadContainingMsgHdr(in nsIMsgDBHdr msgHdr) ;
// helpers for user command functions like delete, mark read, etc.
void MarkHdrRead(in nsIMsgDBHdr msgHdr, in boolean bRead,
in nsIDBChangeListener instigator);
void MarkHdrReplied(in nsIMsgDBHdr msgHdr, in boolean bReplied,
in nsIDBChangeListener instigator);
void MarkHdrMarked(in nsIMsgDBHdr msgHdr, in boolean mark,
in nsIDBChangeListener instigator);
/**
* Remove the new status from a message.
*
* @param aMsgHdr The database reference header for the message
* @param aInstigator Reference to original calling object
*/
void MarkHdrNotNew(in nsIMsgDBHdr aMsgHdr,
in nsIDBChangeListener aInstigator);
// MDN support
void MarkMDNNeeded(in nsMsgKey key, in boolean bNeeded,
in nsIDBChangeListener instigator);
// MarkMDNneeded only used when mail server is a POP3 server
// or when the IMAP server does not support user defined
// PERMANENTFLAGS
boolean IsMDNNeeded(in nsMsgKey key);
void MarkMDNSent(in nsMsgKey key, in boolean bNeeded,
in nsIDBChangeListener instigator);
boolean IsMDNSent(in nsMsgKey key);
// methods to get and set docsets for ids.
void MarkRead(in nsMsgKey key, in boolean bRead,
in nsIDBChangeListener instigator);
void MarkReplied(in nsMsgKey key, in boolean bReplied,
in nsIDBChangeListener instigator);
void MarkForwarded(in nsMsgKey key, in boolean bForwarded,
in nsIDBChangeListener instigator);
void MarkHasAttachments(in nsMsgKey key, in boolean bHasAttachments,
in nsIDBChangeListener instigator);
void MarkThreadRead(in nsIMsgThread thread, in nsIDBChangeListener instigator,
out unsigned long aCount,
[array, size_is(aCount)] out nsMsgKey aKeys);
/// Mark the specified thread ignored.
void MarkThreadIgnored(in nsIMsgThread thread, in nsMsgKey threadKey,
in boolean bIgnored,
in nsIDBChangeListener instigator);
/// Mark the specified thread watched.
void MarkThreadWatched(in nsIMsgThread thread, in nsMsgKey threadKey,
in boolean bWatched,
in nsIDBChangeListener instigator);
/// Mark the specified subthread ignored.
void MarkHeaderKilled(in nsIMsgDBHdr msg, in boolean bIgnored,
in nsIDBChangeListener instigator);
/// Is the message read.
boolean IsRead(in nsMsgKey key);
/// Is the message part of an ignored thread.
boolean IsIgnored(in nsMsgKey key);
/// Is the message part of a watched thread.
boolean IsWatched(in nsMsgKey key);
/// Is the message flagged/starred.
boolean IsMarked(in nsMsgKey key);
/// Does the message have attachments.
boolean HasAttachments(in nsMsgKey key);
void MarkAllRead(out unsigned long aCount,
[array, size_is(aCount)] out nsMsgKey aKeys);
void deleteMessages(in unsigned long aNumKeys,
[array, size_is(aNumKeys)] in nsMsgKey nsMsgKeys,
in nsIDBChangeListener instigator);
void DeleteMessage(in nsMsgKey key,
in nsIDBChangeListener instigator,
in boolean commit);
void DeleteHeader(in nsIMsgDBHdr msgHdr, in nsIDBChangeListener instigator,
in boolean commit, in boolean notify);
// lower level routine that doesn't remove hdr from thread or adjust counts
void RemoveHeaderMdbRow(in nsIMsgDBHdr msgHdr);
void UndoDelete(in nsIMsgDBHdr msgHdr);
void MarkMarked(in nsMsgKey key, in boolean mark,
in nsIDBChangeListener instigator);
void MarkOffline(in nsMsgKey key, in boolean offline,
in nsIDBChangeListener instigator);
void SetLabel(in nsMsgKey key, in nsMsgLabelValue label);
void setStringProperty(in nsMsgKey aKey, in string aProperty, in string aValue);
/**
* Set the value of a string property in a message header
*
* @param msgHdr Header of the message whose property will be changed
* @param aProperty the property to change
* @param aValue new value for the property
*/
void setStringPropertyByHdr(in nsIMsgDBHdr msgHdr, in string aProperty, in string aValue);
/**
* Set the value of a uint32 property in a message header.
*
* @param aMsgHdr header of the message whose property will be changed
* @param aProperty the property to change
* @param aValue new value for the property
*/
void setUint32PropertyByHdr(in nsIMsgDBHdr aMsgHdr,
in string aProperty, in unsigned long aValue);
void MarkImapDeleted(in nsMsgKey key, in boolean deleted,
in nsIDBChangeListener instigator);
readonly attribute nsMsgKey FirstNew;
attribute nsIMsgRetentionSettings msgRetentionSettings;
// purge unwanted message headers and/or bodies. If deleteViaFolder is
// true, we'll call nsIMsgFolder::DeleteMessages to delete the messages.
// Otherwise, we'll just delete them from the db.
void applyRetentionSettings(in nsIMsgRetentionSettings aMsgRetentionSettings,
in boolean aDeleteViaFolder);
attribute nsIMsgDownloadSettings msgDownloadSettings;
boolean HasNew();
void ClearNewList(in boolean notify);
void AddToNewList(in nsMsgKey key);
// used mainly to force the timestamp of a local mail folder db to
// match the time stamp of the corresponding berkeley mail folder,
// but also useful to tell the summary to mark itself invalid
// Also, if a local folder is being reparsed, summary will be invalid
// until the reparsing is done.
attribute boolean summaryValid;
// batching - can be used to cache file stream for local mail,
// and perhaps to use the mdb batching mechanism as well.
void StartBatch();
void EndBatch();
// offline operations - we could move these into an offline operation interface
// but it would have to be in nsMailDatabase, since local folders can be move destinations
nsIMsgOfflineImapOperation GetOfflineOpForKey(in nsMsgKey messageKey, in boolean create);
void RemoveOfflineOp(in nsIMsgOfflineImapOperation op);
nsISimpleEnumerator EnumerateOfflineOps();
[noscript] void ListAllOfflineOpIds(in nsMsgKeyArrayPtr offlineOpIds);
[noscript] void ListAllOfflineDeletes(in nsMsgKeyArrayPtr offlineDeletes);
void ListAllOfflineMsgs(in nsIMsgKeyArray aKeys);
void setAttributeOnPendingHdr(in nsIMsgDBHdr pendingHdr, in string property,
in string propertyVal);
void setUint32AttributeOnPendingHdr(in nsIMsgDBHdr pendingHdr, in string property,
in unsigned long propertyVal);
/**
* Sets a pending 64 bit attribute, which tells the DB that when a message
* which looks like the pendingHdr (e.g., same message-id) is added to the
* db, set the passed in property and value on the new header. This is
* usually because we've copied an imap message to a different folder, and
* want to carry forward attributes from the original message to the copy,
* but don't have the message hdr for the copy yet so we can't set
* attributes directly.
*
* @param aPendingHdr usually the source of the copy.
* @param aProperty name of property to set.
* @param aPropertyVal 64 bit value of property to set.
*/
void setUint64AttributeOnPendingHdr(in nsIMsgDBHdr aPendingHdr,
in string aProperty,
in unsigned long long aPropertyVal);
/**
* Given a message header with its message-id set, update any pending
* attributes on the header.
*
* @param aNewHdr a new header that may have pending attributes.
*/
void updatePendingAttributes(in nsIMsgDBHdr aNewHdr);
readonly attribute nsMsgKey lowWaterArticleNum;
readonly attribute nsMsgKey highWaterArticleNum;
attribute nsMsgKey nextPseudoMsgKey; //for undo-redo of move pop->imap
readonly attribute nsMsgKey nextFakeOfflineMsgKey; // for saving "fake" offline msg hdrs
// for sorting
void createCollationKey(in AString sourceString, out unsigned long aCount,
[array, size_is(aCount)] out octet aKey);
long compareCollationKeys(in unsigned long aLen1,
[array, size_is(aLen1)] in octet key1,
in unsigned long aLen2,
[array, size_is(aLen2)] in octet key2);
// when creating a view, the default sort order and view flags
// use these for the default. (this allows news to override, so that
// news can be threaded by default)
readonly attribute nsMsgViewFlagsTypeValue defaultViewFlags;
readonly attribute nsMsgViewSortTypeValue defaultSortType;
readonly attribute nsMsgViewSortOrderValue defaultSortOrder;
// for msg hdr hash table allocation. controllable by caller to improve folder loading preformance.
attribute unsigned long msgHdrCacheSize;
/**
* The list of messages currently in the NEW state.
*
* If there are no such messages, a null pointer may be returned.
* the caller should free when done using free.
*/
void getNewList(out unsigned long count, [array, size_is(count)] out nsMsgKey newKeys);
// These are used for caching search hits in a db, to speed up saved search folders.
nsISimpleEnumerator getCachedHits(in string aSearchFolderUri);
void refreshCache(in string aSearchFolderUri, in unsigned long aNumKeys, [array, size_is (aNumKeys)] in nsMsgKey aNewHits,
out unsigned long aNumBadHits, [array, size_is(aNumBadHits)] out nsMsgKey aStaleHits);
void updateHdrInCache(in string aSearchFolderUri, in nsIMsgDBHdr aHdr, in boolean aAdd);
boolean hdrIsInCache(in string aSearchFolderUri, in nsIMsgDBHdr aHdr);
};
/** @} */

View file

@ -0,0 +1,53 @@
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 "nsISupports.idl"
#include "MailNewsTypes2.idl"
// #include "nsIImapUrl.idl" // for imapMessageFlagsType
typedef unsigned short imapMessageFlagsType;
typedef long nsOfflineImapOperationType;
[scriptable, uuid(b5229a55-22bb-444b-be92-13d719353828)]
interface nsIMsgOfflineImapOperation : nsISupports
{
// type of stored imap operations
const long kFlagsChanged = 0x1;
const long kMsgMoved = 0x2;
const long kMsgCopy = 0x4;
const long kMoveResult = 0x8;
const long kAppendDraft = 0x10;
const long kAddedHeader = 0x20;
const long kDeletedMsg = 0x40;
const long kMsgMarkedDeleted = 0x80;
const long kAppendTemplate = 0x100;
const long kDeleteAllMsgs = 0x200;
const long kAddKeywords = 0x400;
const long kRemoveKeywords = 0x800;
attribute nsOfflineImapOperationType operation;
void clearOperation(in nsOfflineImapOperationType operation);
attribute nsMsgKey messageKey;
// for move/copy operations, the msg key of the source msg.
attribute nsMsgKey srcMessageKey;
attribute imapMessageFlagsType flagOperation;
attribute imapMessageFlagsType newFlags; // for kFlagsChanged
attribute string destinationFolderURI; // for move or copy
attribute string sourceFolderURI;
void addKeywordToAdd(in string aKeyword);
void addKeywordToRemove(in string aKeyword);
readonly attribute string keywordsToAdd;
readonly attribute string keywordsToRemove;
readonly attribute long numberOfCopies;
void addMessageCopyOperation(in string destinationBox);
string getCopyDestination(in long copyIndex);
attribute unsigned long msgSize;
attribute boolean playingBack;
};

View file

@ -0,0 +1,18 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 "nsISupports.idl"
%{C++
#include "nsMsgKeySet.h"
%}
[ptr] native nsMsgKeySetPtr(nsMsgKeySet);
[scriptable, uuid(f700208a-1dd1-11b2-b947-e4e1e4fdf278)]
interface nsINewsDatabase : nsISupports {
[noscript] attribute nsMsgKeySetPtr readSet;
};

View file

@ -0,0 +1,52 @@
/* -*- 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 _nsImapMailDatabase_H_
#define _nsImapMailDatabase_H_
#include "mozilla/Attributes.h"
#include "nsMailDatabase.h"
class nsImapMailDatabase : public nsMailDatabase
{
public:
// OK, it's dumb that this should require a fileSpec, since there is no file
// for the folder. This is mainly because we're deriving from nsMailDatabase;
// Perhaps we shouldn't...
nsImapMailDatabase();
virtual ~nsImapMailDatabase();
NS_IMETHOD StartBatch() override;
NS_IMETHOD EndBatch() override;
NS_IMETHOD GetSummaryValid(bool *aResult) override;
NS_IMETHOD SetSummaryValid(bool valid = true) override;
virtual nsresult AdjustExpungedBytesOnDelete(nsIMsgDBHdr *msgHdr) override;
NS_IMETHOD ForceClosed() override;
NS_IMETHOD AddNewHdrToDB(nsIMsgDBHdr *newHdr, bool notify) override;
NS_IMETHOD SetAttributeOnPendingHdr(nsIMsgDBHdr *pendingHdr, const char *property,
const char *propertyVal) override;
NS_IMETHOD SetUint32AttributeOnPendingHdr(nsIMsgDBHdr *pendingHdr, const char *property,
uint32_t propertyVal) override;
NS_IMETHOD SetUint64AttributeOnPendingHdr(nsIMsgDBHdr *aPendingHdr,
const char *aProperty,
uint64_t aPropertyVal) override;
NS_IMETHOD DeleteMessages(uint32_t aNumKeys, nsMsgKey* nsMsgKeys,
nsIDBChangeListener *instigator) override;
NS_IMETHOD UpdatePendingAttributes(nsIMsgDBHdr* aNewHdr) override;
protected:
// IMAP does not set local file flags, override does nothing
virtual void UpdateFolderFlag(nsIMsgDBHdr *msgHdr, bool bSet,
nsMsgMessageFlagType flag, nsIOutputStream **ppFileStream);
nsresult GetRowForPendingHdr(nsIMsgDBHdr *pendingHdr, nsIMdbRow **row);
nsresult GetAllPendingHdrsTable();
mdb_token m_pendingHdrsRowScopeToken;
mdb_token m_pendingHdrsTableKindToken;
nsCOMPtr<nsIMdbTable> m_mdbAllPendingHdrsTable;
};
#endif

View file

@ -0,0 +1,67 @@
/* -*- 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 _nsMailDatabase_H_
#define _nsMailDatabase_H_
#include "mozilla/Attributes.h"
#include "nsMsgDatabase.h"
#include "nsMsgMessageFlags.h"
#include "nsIFile.h"
#include "nsTArray.h"
// This is the subclass of nsMsgDatabase that handles local mail messages.
class nsIOFileStream;
class nsIFile;
class nsOfflineImapOperation;
class nsMailDatabase : public nsMsgDatabase
{
public:
nsMailDatabase();
virtual ~nsMailDatabase();
NS_IMETHOD ForceClosed() override;
NS_IMETHOD DeleteMessages(uint32_t aNumKeys, nsMsgKey* nsMsgKeys,
nsIDBChangeListener *instigator) override;
NS_IMETHOD StartBatch() override;
NS_IMETHOD EndBatch() override;
nsresult Open(nsMsgDBService* aDBService, nsIFile *aSummaryFile, bool create, bool upgrading) override;
virtual nsMailDatabase *GetMailDB() {return this;}
virtual uint32_t GetCurVersion() override {return kMsgDBVersion;}
NS_IMETHOD GetOfflineOpForKey(nsMsgKey opKey, bool create,
nsIMsgOfflineImapOperation **op) override;
NS_IMETHOD RemoveOfflineOp(nsIMsgOfflineImapOperation *op) override;
NS_IMETHOD SetSummaryValid(bool valid) override;
NS_IMETHOD GetSummaryValid(bool *valid) override;
NS_IMETHOD EnumerateOfflineOps(nsISimpleEnumerator **enumerator) override;
NS_IMETHOD ListAllOfflineOpIds(nsTArray<nsMsgKey> *offlineOpIds) override;
NS_IMETHOD ListAllOfflineDeletes(nsTArray<nsMsgKey> *offlineDeletes) override;
friend class nsMsgOfflineOpEnumerator;
protected:
nsresult GetAllOfflineOpsTable(); // get this on demand
// get the time and date of the mailbox file
void GetMailboxModProperties(int64_t *aSize, uint32_t *aDate);
nsCOMPtr <nsIMdbTable> m_mdbAllOfflineOpsTable;
mdb_token m_offlineOpsRowScopeToken;
mdb_token m_offlineOpsTableKindToken;
virtual void SetReparse(bool reparse);
protected:
bool m_reparse;
};
#endif

View file

@ -0,0 +1,63 @@
/* -*- 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/. */
#ifndef nsMsgDBCID_h__
#define nsMsgDBCID_h__
#include "nsISupports.h"
#include "nsIFactory.h"
#include "nsIComponentManager.h"
// 03223c50-1e88-45e8-ba1a-7ce792dc3fc3
#define NS_MSGDB_SERVICE_CID \
{ 0x03223c50, 0x1e88, 0x45e8, \
{ 0xba, 0x1a, 0x7c, 0xe7, 0x92, 0xdc, 0x3f, 0xc3 } }
#define NS_MSGDB_SERVICE_CONTRACTID \
"@mozilla.org/msgDatabase/msgDBService;1"
#define NS_MSGDB_CONTRACTID \
"@mozilla.org/nsMsgDatabase/msgDB-"
#define NS_MAILBOXDB_CONTRACTID \
NS_MSGDB_CONTRACTID"mailbox"
// a86c86ae-e97f-11d2-a506-0060b0fc04b7
#define NS_MAILDB_CID \
{ 0xa86c86ae, 0xe97f, 0x11d2, \
{ 0xa5, 0x06, 0x00, 0x60, 0xb0, 0xfc, 0x04, 0xb7 } }
#define NS_NEWSDB_CONTRACTID \
NS_MSGDB_CONTRACTID"news"
// 36414aa0-e980-11d2-a506-0060b0fc04b7
#define NS_NEWSDB_CID \
{ 0x36414aa0, 0xe980, 0x11d2, \
{ 0xa5, 0x06, 0x00, 0x60, 0xb0, 0xfc, 0x04, 0xb7 } }
#define NS_IMAPDB_CONTRACTID \
NS_MSGDB_CONTRACTID"imap"
// 9e4b07ee-e980-11d2-a506-0060b0fc04b7
#define NS_IMAPDB_CID \
{ 0x9e4b07ee, 0xe980, 0x11d2, \
{ 0xa5, 0x06, 0x00, 0x60, 0xb0, 0xfc, 0x04, 0xb7 } }
#define NS_MSG_RETENTIONSETTINGS_CID \
{ 0x1bd976d6, 0xdf44, 0x11d4, \
{0xa5, 0xb6, 0x00, 0x60, 0xb0, 0xfc, 0x04, 0xb7} }
#define NS_MSG_RETENTIONSETTINGS_CONTRACTID \
"@mozilla.org/msgDatabase/retentionSettings;1"
// 4e3dae5a-157a-11d5-a5c0-0060b0fc04b7
#define NS_MSG_DOWNLOADSETTINGS_CID \
{ 0x4e3dae5a, 0x157a, 0x11d5, \
{0xa5, 0xc0, 0x00, 0x60, 0xb0, 0xfc, 0x04, 0xb7} }
#define NS_MSG_DOWNLOADSETTINGS_CONTRACTID \
"@mozilla.org/msgDatabase/downloadSettings;1"
#endif

View file

@ -0,0 +1,462 @@
/* -*- 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 "nsIMsgDatabase.h"
#include "nsMsgHdr.h"
#include "nsStringGlue.h"
#include "nsAutoPtr.h"
#include "nsIDBChangeListener.h"
#include "nsIDBChangeAnnouncer.h"
#include "nsMsgMessageFlags.h"
#include "nsIMsgFolder.h"
#include "nsIMutableArray.h"
#include "nsDBFolderInfo.h"
#include "nsICollation.h"
#include "nsIMsgSearchSession.h"
#include "nsIMimeConverter.h"
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#include "PLDHashTable.h"
#include "nsTArray.h"
#include "nsTObserverArray.h"
class ListContext;
class nsMsgKeySet;
class nsMsgThread;
class nsMsgDatabase;
class nsIMsgThread;
class nsIDBFolderInfo;
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;
};
class nsMsgDBEnumerator : public nsISimpleEnumerator {
public:
NS_DECL_ISUPPORTS
// nsISimpleEnumerator methods:
NS_DECL_NSISIMPLEENUMERATOR
// nsMsgDBEnumerator methods:
typedef nsresult (*nsMsgDBEnumeratorFilter)(nsIMsgDBHdr* hdr, void* closure);
nsMsgDBEnumerator(nsMsgDatabase* db, nsIMdbTable *table,
nsMsgDBEnumeratorFilter filter, void* closure,
bool iterateForwards = true);
void Clear();
nsresult GetRowCursor();
virtual nsresult PrefetchNext();
RefPtr<nsMsgDatabase> mDB;
nsCOMPtr<nsIMdbTableRowCursor> mRowCursor;
mdb_pos mRowPos;
nsCOMPtr<nsIMsgDBHdr> mResultHdr;
bool mDone;
bool mNextPrefetched;
bool mIterateForwards;
nsMsgDBEnumeratorFilter mFilter;
nsCOMPtr <nsIMdbTable> mTable;
void* mClosure;
// This is used when the caller wants to limit how many headers the
// enumerator looks at in any given time slice.
mdb_pos mStopPos;
protected:
virtual ~nsMsgDBEnumerator();
};
class nsMsgFilteredDBEnumerator : public nsMsgDBEnumerator
{
public:
nsMsgFilteredDBEnumerator(nsMsgDatabase* db, nsIMdbTable *table,
bool reverse, nsIArray *searchTerms);
virtual ~nsMsgFilteredDBEnumerator();
nsresult InitSearchSession(nsIArray *searchTerms, nsIMsgFolder *folder);
protected:
virtual nsresult PrefetchNext() override;
nsCOMPtr <nsIMsgSearchSession> m_searchSession;
};
namespace mozilla {
namespace mailnews {
class MsgDBReporter;
}
}
class nsMsgDatabase : public nsIMsgDatabase
{
public:
friend class nsMsgDBService;
friend class nsMsgPropertyEnumerator; // accesses m_mdbEnv and m_mdbStore
NS_DECL_ISUPPORTS
NS_DECL_NSIDBCHANGEANNOUNCER
NS_DECL_NSIMSGDATABASE
/**
* 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_TARGET_DOES_NOT_EXIST
* 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(const char *dbName, 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(nsISimpleEnumerator* *result, uint32_t *pFlag);
nsresult GetSearchResultsTable(const char *searchFolderUri, bool createIfMissing, nsIMdbTable **table);
// this might just be for debugging - we'll see.
nsresult ListAllThreads(nsTArray<nsMsgKey> *threadIds);
//////////////////////////////////////////////////////////////////////////////
// nsMsgDatabase methods:
nsMsgDatabase();
void 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, uint8_t **result, uint32_t *len);
nsresult RowCellColumnToConstCharPtr(nsIMdbRow *row, mdb_token columnToken, const char **ptr);
nsresult RowCellColumnToAddressCollationKey(nsIMdbRow *row, mdb_token colToken, uint8_t **result, uint32_t *len);
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();
nsresult DumpThread(nsMsgKey threadId);
nsresult DumpMsgChildren(nsIMsgDBHdr *msgHdr);
#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, uint32_t flag,
nsIDBChangeListener *instigator = NULL);
virtual nsresult SetMsgHdrFlag(nsIMsgDBHdr *msgHdr, bool set, uint32_t flag,
nsIDBChangeListener *instigator);
virtual bool SetHdrFlag(nsIMsgDBHdr *, bool bSet, nsMsgMessageFlagType flag);
virtual bool SetHdrReadFlag(nsIMsgDBHdr *, bool pRead);
virtual uint32_t GetStatusFlags(nsIMsgDBHdr *msgHdr, uint32_t origFlags);
// helper function which doesn't involve thread object
virtual nsresult RemoveHeaderFromDB(nsMsgHdr *msgHdr);
virtual nsresult RemoveHeaderFromThread(nsMsgHdr *msgHdr);
virtual nsresult AdjustExpungedBytesOnDelete(nsIMsgDBHdr *msgHdr);
nsCOMPtr <nsICollation> m_collationKeyGenerator;
nsCOMPtr <nsIMimeConverter> m_mimeConverter;
nsCOMPtr <nsIMsgRetentionSettings> m_retentionSettings;
nsCOMPtr <nsIMsgDownloadSettings> m_downloadSettings;
nsresult PurgeMessagesOlderThan(uint32_t daysToKeepHdrs,
bool applyToFlaggedMessages,
nsIMutableArray *hdrsToDelete);
nsresult PurgeExcessMessages(uint32_t numHeadersToKeep,
bool applyToFlaggedMessages,
nsIMutableArray *hdrsToDelete);
// mdb bookkeeping stuff
virtual nsresult InitExistingDB();
virtual nsresult InitNewDB();
virtual nsresult InitMDBInfo();
nsCOMPtr <nsIMsgFolder> m_folder;
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;
nsCString m_dbName;
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_statusOffsetColumnToken;
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 ClearEnumerators();
// 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();
// not-reference holding array of enumerators we've handed out.
// If a db goes away, it will clean up the outstanding enumerators.
nsTArray<nsMsgDBEnumerator *> m_enumerators;
// 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

View file

@ -0,0 +1,86 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 _nsMsgHdr_H
#define _nsMsgHdr_H
#include "mozilla/MemoryReporting.h"
#include "nsIMsgHdr.h"
#include "nsStringGlue.h"
#include "MailNewsTypes.h"
#include "mdb.h"
#include "nsTArray.h"
class nsMsgDatabase;
class nsCString;
class nsIMsgThread;
class nsMsgHdr : public nsIMsgDBHdr {
public:
NS_DECL_NSIMSGDBHDR
friend class nsMsgDatabase;
friend class nsMsgPropertyEnumerator; // accesses m_mdb
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// nsMsgHdr methods:
nsMsgHdr(nsMsgDatabase *db, nsIMdbRow *dbRow);
virtual nsresult GetRawFlags(uint32_t *result);
void Init();
virtual nsresult InitCachedValues();
virtual nsresult InitFlags();
void ClearCachedValues() {m_initedValues = 0;}
NS_DECL_ISUPPORTS
nsIMdbRow *GetMDBRow() {return m_mdbRow;}
bool IsParentOf(nsIMsgDBHdr *possibleChild);
bool IsAncestorOf(nsIMsgDBHdr *possibleChild);
bool IsAncestorKilled(uint32_t ancestorsToCheck);
void ReparentInThread(nsIMsgThread *thread);
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOfFun) const
{
return m_references.ShallowSizeOfExcludingThis(aMallocSizeOfFun);
}
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOfFun) const
{
return aMallocSizeOfFun(this) + SizeOfExcludingThis(aMallocSizeOfFun);
}
protected:
virtual ~nsMsgHdr();
nsresult SetStringColumn(const char *str, mdb_token token);
nsresult SetUInt32Column(uint32_t value, mdb_token token);
nsresult GetUInt32Column(mdb_token token, uint32_t *pvalue, uint32_t defaultValue = 0);
nsresult SetUInt64Column(uint64_t value, mdb_token token);
nsresult GetUInt64Column(mdb_token token, uint64_t *pvalue, uint64_t defaultValue = 0);
// reference and threading stuff.
nsresult ParseReferences(const char *references);
const char* GetNextReference(const char *startNextRef, nsCString &reference,
bool acceptNonDelimitedReferences);
nsMsgKey m_threadId;
nsMsgKey m_messageKey; //news: article number, mail mbox offset, imap uid...
nsMsgKey m_threadParent; // message this is a reply to, in thread.
PRTime m_date;
uint32_t m_messageSize; // lines for news articles, bytes for mail messages
uint32_t m_statusOffset; // offset in a local mail message of the mozilla status hdr
uint32_t m_flags;
// avoid parsing references every time we want one
nsTArray<nsCString> m_references;
nsMsgPriorityValue m_priority;
// nsMsgHdrs will have to know what db and row they belong to, since they are really
// just a wrapper around the msg row in the mdb. This could cause problems,
// though I hope not.
nsMsgDatabase *m_mdb;
nsIMdbRow *m_mdbRow;
uint32_t m_initedValues;
};
#endif

View file

@ -0,0 +1,63 @@
/* -*- 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/. */
#ifndef _nsMsgThread_H
#define _nsMsgThread_H
#include "nsAutoPtr.h"
#include "nsIMsgThread.h"
#include "nsStringGlue.h"
#include "MailNewsTypes.h"
#include "mdb.h"
class nsIMdbTable;
class nsIMsgDBHdr;
class nsMsgDatabase;
class nsMsgThread : public nsIMsgThread {
public:
nsMsgThread();
nsMsgThread(nsMsgDatabase *db, nsIMdbTable *table);
friend class nsMsgThreadEnumerator;
friend class nsMsgDatabase;
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGTHREAD
RefPtr<nsMsgDatabase> m_mdbDB;
protected:
virtual ~nsMsgThread();
void Init();
void Clear();
virtual nsresult InitCachedValues();
nsresult ChangeChildCount(int32_t delta);
nsresult ChangeUnreadChildCount(int32_t delta);
nsresult RemoveChild(nsMsgKey msgKey);
nsresult SetThreadRootKey(nsMsgKey threadRootKey);
nsresult GetChildHdrForKey(nsMsgKey desiredKey,
nsIMsgDBHdr **result, int32_t *resultIndex);
nsresult RerootThread(nsIMsgDBHdr *newParentOfOldRoot, nsIMsgDBHdr *oldRoot, nsIDBChangeAnnouncer *announcer);
nsresult ReparentChildrenOf(nsMsgKey oldParent, nsMsgKey newParent, nsIDBChangeAnnouncer *announcer);
nsresult ReparentNonReferenceChildrenOf(nsIMsgDBHdr *topLevelHdr, nsMsgKey newParentKey,
nsIDBChangeAnnouncer *announcer);
nsresult ReparentMsgsWithInvalidParent(uint32_t numChildren, nsMsgKey threadParentKey);
nsMsgKey m_threadKey;
uint32_t m_numChildren;
uint32_t m_numUnreadChildren;
uint32_t m_flags;
nsCOMPtr<nsIMdbTable> m_mdbTable;
nsCOMPtr<nsIMdbRow> m_metaRow;
bool m_cachedValuesInitialized;
nsMsgKey m_threadRootKey;
uint32_t m_newestMsgDate;
};
#endif

View file

@ -0,0 +1,57 @@
/* -*- 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 _nsNewsDatabase_H_
#define _nsNewsDatabase_H_
#include "mozilla/Attributes.h"
#include "nsMsgDatabase.h"
#include "nsINewsDatabase.h"
#include "nsTArray.h"
class nsIDBChangeListener;
class MSG_RetrieveArtInfo;
class MSG_PurgeInfo;
// news group database
class nsNewsDatabase : public nsMsgDatabase , public nsINewsDatabase
{
public:
nsNewsDatabase();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSINEWSDATABASE
NS_IMETHOD Close(bool forceCommit) override;
NS_IMETHOD ForceClosed() override;
NS_IMETHOD Commit(nsMsgDBCommit commitType) override;
virtual uint32_t GetCurVersion() override;
// methods to get and set docsets for ids.
NS_IMETHOD IsRead(nsMsgKey key, bool *pRead) override;
virtual nsresult IsHeaderRead(nsIMsgDBHdr *msgHdr, bool *pRead) override;
NS_IMETHOD GetHighWaterArticleNum(nsMsgKey *key) override;
NS_IMETHOD GetLowWaterArticleNum(nsMsgKey *key) override;
NS_IMETHOD MarkAllRead(uint32_t *aNumMarked, nsMsgKey **thoseMarked) override;
virtual nsresult ExpireUpTo(nsMsgKey expireKey);
virtual nsresult ExpireRange(nsMsgKey startRange, nsMsgKey endRange);
virtual bool SetHdrReadFlag(nsIMsgDBHdr *msgHdr, bool bRead) override;
virtual nsresult AdjustExpungedBytesOnDelete(nsIMsgDBHdr *msgHdr) override;
nsresult SyncWithReadSet();
NS_IMETHOD GetDefaultViewFlags(nsMsgViewFlagsTypeValue *aDefaultViewFlags) override;
NS_IMETHOD GetDefaultSortType(nsMsgViewSortTypeValue *aDefaultSortType) override;
NS_IMETHOD GetDefaultSortOrder(nsMsgViewSortOrderValue *aDefaultSortOrder) override;
protected:
virtual ~nsNewsDatabase();
// this is owned by the nsNewsFolder, which lives longer than the db.
nsMsgKeySet *m_readSet;
};
#endif

View file

@ -0,0 +1,18 @@
# vim: set filetype=python:
# 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 += [
'nsDBFolderInfo.cpp',
'nsImapMailDatabase.cpp',
'nsMailDatabase.cpp',
'nsMsgDatabase.cpp',
'nsMsgHdr.cpp',
'nsMsgOfflineImapOperation.cpp',
'nsMsgThread.cpp',
'nsNewsDatabase.cpp',
]
FINAL_LIBRARY = 'mail'

View file

@ -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;
}

View file

@ -0,0 +1,249 @@
/* -*- 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/. */
#include <sys/stat.h>
#include "msgCore.h"
#include "nsImapMailDatabase.h"
#include "nsDBFolderInfo.h"
const char *kPendingHdrsScope = "ns:msg:db:row:scope:pending:all"; // scope for all offine ops table
const char *kPendingHdrsTableKind = "ns:msg:db:table:kind:pending";
struct mdbOid gAllPendingHdrsTableOID;
nsImapMailDatabase::nsImapMailDatabase()
{
m_mdbAllPendingHdrsTable = nullptr;
}
nsImapMailDatabase::~nsImapMailDatabase()
{
}
NS_IMETHODIMP nsImapMailDatabase::GetSummaryValid(bool *aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
if (m_dbFolderInfo)
{
uint32_t version;
m_dbFolderInfo->GetVersion(&version);
*aResult = (GetCurVersion() == version);
}
else
*aResult = false;
return NS_OK;
}
NS_IMETHODIMP nsImapMailDatabase::SetSummaryValid(bool valid)
{
if (m_dbFolderInfo)
{
m_dbFolderInfo->SetVersion(valid ? GetCurVersion() : 0);
Commit(nsMsgDBCommitType::kLargeCommit);
}
return NS_OK;
}
// IMAP does not set local file flags, override does nothing
void nsImapMailDatabase::UpdateFolderFlag(nsIMsgDBHdr * /* msgHdr */, bool /* bSet */,
nsMsgMessageFlagType /* flag */, nsIOutputStream ** /* ppFileStream */)
{
}
// We override this to avoid our parent class (nsMailDatabase)'s
// grabbing of the folder semaphore, and bailing on failure.
NS_IMETHODIMP nsImapMailDatabase::DeleteMessages(uint32_t aNumKeys, nsMsgKey* nsMsgKeys, nsIDBChangeListener *instigator)
{
return nsMsgDatabase::DeleteMessages(aNumKeys, nsMsgKeys, instigator);
}
// override so nsMailDatabase methods that deal with m_folderStream are *not* called
NS_IMETHODIMP nsImapMailDatabase::StartBatch()
{
return NS_OK;
}
NS_IMETHODIMP nsImapMailDatabase::EndBatch()
{
return NS_OK;
}
nsresult nsImapMailDatabase::AdjustExpungedBytesOnDelete(nsIMsgDBHdr *msgHdr)
{
uint32_t msgFlags;
msgHdr->GetFlags(&msgFlags);
if (msgFlags & nsMsgMessageFlags::Offline && m_dbFolderInfo)
{
uint32_t size = 0;
(void)msgHdr->GetOfflineMessageSize(&size);
return m_dbFolderInfo->ChangeExpungedBytes (size);
}
return NS_OK;
}
NS_IMETHODIMP nsImapMailDatabase::ForceClosed()
{
m_mdbAllPendingHdrsTable = nullptr;
return nsMailDatabase::ForceClosed();
}
nsresult nsImapMailDatabase::GetAllPendingHdrsTable()
{
nsresult rv = NS_OK;
if (!m_mdbAllPendingHdrsTable)
rv = GetTableCreateIfMissing(kPendingHdrsScope, kPendingHdrsTableKind, getter_AddRefs(m_mdbAllPendingHdrsTable),
m_pendingHdrsRowScopeToken, m_pendingHdrsTableKindToken) ;
return rv;
}
NS_IMETHODIMP nsImapMailDatabase::AddNewHdrToDB(nsIMsgDBHdr *newHdr, bool notify)
{
nsresult rv = nsMsgDatabase::AddNewHdrToDB(newHdr, notify);
if (NS_SUCCEEDED(rv))
rv = UpdatePendingAttributes(newHdr);
return rv;
}
NS_IMETHODIMP nsImapMailDatabase::UpdatePendingAttributes(nsIMsgDBHdr* aNewHdr)
{
nsresult rv = GetAllPendingHdrsTable();
NS_ENSURE_SUCCESS(rv, rv);
mdb_count numPendingHdrs = 0;
m_mdbAllPendingHdrsTable->GetCount(GetEnv(), &numPendingHdrs);
if (numPendingHdrs > 0)
{
mdbYarn messageIdYarn;
nsCOMPtr <nsIMdbRow> pendingRow;
mdbOid outRowId;
nsCString messageId;
aNewHdr->GetMessageId(getter_Copies(messageId));
messageIdYarn.mYarn_Buf = (void*)messageId.get();
messageIdYarn.mYarn_Fill = messageId.Length();
messageIdYarn.mYarn_Form = 0;
messageIdYarn.mYarn_Size = messageIdYarn.mYarn_Fill;
m_mdbStore->FindRow(GetEnv(), m_pendingHdrsRowScopeToken,
m_messageIdColumnToken, &messageIdYarn, &outRowId, getter_AddRefs(pendingRow));
if (pendingRow)
{
mdb_count numCells;
mdbYarn cellYarn;
mdb_column cellColumn;
uint32_t existingFlags;
pendingRow->GetCount(GetEnv(), &numCells);
aNewHdr->GetFlags(&existingFlags);
// iterate over the cells in the pending hdr setting properties on the aNewHdr.
// we skip cell 0, which is the messageId;
nsMsgHdr* msgHdr = static_cast<nsMsgHdr*>(aNewHdr); // closed system, cast ok
nsIMdbRow *row = msgHdr->GetMDBRow();
for (mdb_count cellIndex = 1; cellIndex < numCells; cellIndex++)
{
nsresult err = pendingRow->SeekCellYarn(GetEnv(), cellIndex, &cellColumn, nullptr);
if (NS_SUCCEEDED(err))
{
err = pendingRow->AliasCellYarn(GetEnv(), cellColumn, &cellYarn);
if (NS_SUCCEEDED(err))
{
if (row)
row->AddColumn(GetEnv(), cellColumn, &cellYarn);
}
}
}
// We might have changed some cached values, so force a refresh.
msgHdr->ClearCachedValues();
uint32_t resultFlags;
msgHdr->OrFlags(existingFlags, &resultFlags);
m_mdbAllPendingHdrsTable->CutRow(GetEnv(), pendingRow);
pendingRow->CutAllColumns(GetEnv());
}
}
return rv;
}
nsresult nsImapMailDatabase::GetRowForPendingHdr(nsIMsgDBHdr *pendingHdr,
nsIMdbRow **row)
{
nsresult rv = GetAllPendingHdrsTable();
NS_ENSURE_SUCCESS(rv, rv);
mdbYarn messageIdYarn;
nsCOMPtr<nsIMdbRow> pendingRow;
mdbOid outRowId;
nsCString messageId;
pendingHdr->GetMessageId(getter_Copies(messageId));
messageIdYarn.mYarn_Buf = (void*)messageId.get();
messageIdYarn.mYarn_Fill = messageId.Length();
messageIdYarn.mYarn_Form = 0;
messageIdYarn.mYarn_Size = messageIdYarn.mYarn_Fill;
rv = m_mdbStore->FindRow(GetEnv(), m_pendingHdrsRowScopeToken,
m_messageIdColumnToken, &messageIdYarn, &outRowId, getter_AddRefs(pendingRow));
if (!pendingRow)
rv = m_mdbStore->NewRow(GetEnv(), m_pendingHdrsRowScopeToken, getter_AddRefs(pendingRow));
NS_ENSURE_SUCCESS(rv, rv);
if (pendingRow)
{
// now we need to add cells to the row to remember the messageid, property and property value, and flags.
// Then, when hdrs are added to the db, we'll check if they have a matching message-id, and if so,
// set the property and flags
// XXX we already fetched messageId from the pending hdr, could it have changed by the time we get here?
nsCString messageId;
pendingHdr->GetMessageId(getter_Copies(messageId));
// we're just going to ignore messages without a message-id. They should be rare. If SPAM messages often
// didn't have message-id's, they'd be filtered on the server, most likely, and spammers would then
// start putting in message-id's.
if (!messageId.IsEmpty())
{
extern const char *kMessageIdColumnName;
m_mdbAllPendingHdrsTable->AddRow(GetEnv(), pendingRow);
// make sure this is the first cell so that when we ignore the first
// cell in nsImapMailDatabase::AddNewHdrToDB, we're ignoring the right one
(void) SetProperty(pendingRow, kMessageIdColumnName, messageId.get());
pendingRow.forget(row);
}
else
return NS_ERROR_FAILURE;
}
return rv;
}
NS_IMETHODIMP nsImapMailDatabase::SetAttributeOnPendingHdr(nsIMsgDBHdr *pendingHdr, const char *property,
const char *propertyVal)
{
NS_ENSURE_ARG_POINTER(pendingHdr);
nsCOMPtr<nsIMdbRow> pendingRow;
nsresult rv = GetRowForPendingHdr(pendingHdr, getter_AddRefs(pendingRow));
NS_ENSURE_SUCCESS(rv, rv);
return SetProperty(pendingRow, property, propertyVal);
}
NS_IMETHODIMP
nsImapMailDatabase::SetUint32AttributeOnPendingHdr(nsIMsgDBHdr *pendingHdr,
const char *property,
uint32_t propertyVal)
{
NS_ENSURE_ARG_POINTER(pendingHdr);
nsCOMPtr<nsIMdbRow> pendingRow;
nsresult rv = GetRowForPendingHdr(pendingHdr, getter_AddRefs(pendingRow));
NS_ENSURE_SUCCESS(rv, rv);
return SetUint32Property(pendingRow, property, propertyVal);
}
NS_IMETHODIMP
nsImapMailDatabase::SetUint64AttributeOnPendingHdr(nsIMsgDBHdr *aPendingHdr,
const char *aProperty,
uint64_t aPropertyVal)
{
NS_ENSURE_ARG_POINTER(aPendingHdr);
nsCOMPtr<nsIMdbRow> pendingRow;
nsresult rv = GetRowForPendingHdr(aPendingHdr, getter_AddRefs(pendingRow));
NS_ENSURE_SUCCESS(rv, rv);
return SetUint64Property(pendingRow, aProperty, aPropertyVal);
}

View file

@ -0,0 +1,444 @@
/* -*- 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 "nsMailDatabase.h"
#include "nsDBFolderInfo.h"
#include "nsMsgLocalFolderHdrs.h"
#include "nsNetUtil.h"
#include "nsISeekableStream.h"
#include "nsMsgOfflineImapOperation.h"
#include "nsMsgFolderFlags.h"
#include "mozilla/Logging.h"
#include "prprf.h"
#include "nsMsgUtils.h"
#include "nsIMsgPluggableStore.h"
extern PRLogModuleInfo *IMAPOffline;
using namespace mozilla;
// scope for all offine ops table
const char *kOfflineOpsScope = "ns:msg:db:row:scope:ops:all";
const char *kOfflineOpsTableKind = "ns:msg:db:table:kind:ops";
struct mdbOid gAllOfflineOpsTableOID;
nsMailDatabase::nsMailDatabase() : m_reparse(false)
{
m_mdbAllOfflineOpsTable = nullptr;
m_offlineOpsRowScopeToken = 0;
m_offlineOpsTableKindToken = 0;
}
nsMailDatabase::~nsMailDatabase()
{
}
// caller passes in upgrading==true if they want back a db even if the db is out of date.
// If so, they'll extract out the interesting info from the db, close it, delete it, and
// then try to open the db again, prior to reparsing.
nsresult nsMailDatabase::Open(nsMsgDBService* aDBService, nsIFile *aSummaryFile,
bool aCreate, bool aUpgrading)
{
#ifdef DEBUG
nsString leafName;
aSummaryFile->GetLeafName(leafName);
if (!StringEndsWith(leafName, NS_LITERAL_STRING(".msf"),
nsCaseInsensitiveStringComparator()))
NS_ERROR("non summary file passed into open\n");
#endif
return nsMsgDatabase::Open(aDBService, aSummaryFile, aCreate, aUpgrading);
}
NS_IMETHODIMP nsMailDatabase::ForceClosed()
{
m_mdbAllOfflineOpsTable = nullptr;
return nsMsgDatabase::ForceClosed();
}
// get this on demand so that only db's that have offline ops will
// create the table.
nsresult nsMailDatabase::GetAllOfflineOpsTable()
{
nsresult rv = NS_OK;
if (!m_mdbAllOfflineOpsTable)
rv = GetTableCreateIfMissing(kOfflineOpsScope, kOfflineOpsTableKind, getter_AddRefs(m_mdbAllOfflineOpsTable),
m_offlineOpsRowScopeToken, m_offlineOpsTableKindToken) ;
return rv;
}
NS_IMETHODIMP nsMailDatabase::StartBatch()
{
return NS_OK;
}
NS_IMETHODIMP nsMailDatabase::EndBatch()
{
SetSummaryValid(true);
return NS_OK;
}
NS_IMETHODIMP nsMailDatabase::DeleteMessages(uint32_t aNumKeys, nsMsgKey* nsMsgKeys, nsIDBChangeListener *instigator)
{
nsresult rv;
if (m_folder)
{
bool isLocked;
m_folder->GetLocked(&isLocked);
if (isLocked)
{
NS_ASSERTION(false, "Some other operation is in progress");
return NS_MSG_FOLDER_BUSY;
}
}
rv = nsMsgDatabase::DeleteMessages(aNumKeys, nsMsgKeys, instigator);
SetSummaryValid(true);
return rv;
}
NS_IMETHODIMP nsMailDatabase::GetSummaryValid(bool *aResult)
{
uint32_t version;
m_dbFolderInfo->GetVersion(&version);
if (GetCurVersion() != version)
{
*aResult = false;
return NS_OK;
}
nsCOMPtr<nsIMsgPluggableStore> msgStore;
if (!m_folder) {
// If the folder is not set, we just return without checking the validity
// of the summary file. For now, this is an expected condition when the
// message database is being opened from a URL in
// nsMailboxUrl::GetMsgHdrForKey() which calls
// nsMsgDBService::OpenMailDBFromFile() without a folder.
// Returning an error here would lead to the deletion of the MSF in the
// caller nsMsgDatabase::CheckForErrors().
*aResult = true;
return NS_OK;
}
nsresult rv = m_folder->GetMsgStore(getter_AddRefs(msgStore));
NS_ENSURE_SUCCESS(rv, rv);
return msgStore->IsSummaryFileValid(m_folder, this, aResult);
}
NS_IMETHODIMP nsMailDatabase::SetSummaryValid(bool aValid)
{
nsMsgDatabase::SetSummaryValid(aValid);
if (!m_folder)
return NS_ERROR_NULL_POINTER;
// If this is a virtual folder, there is no storage.
bool flag;
m_folder->GetFlag(nsMsgFolderFlags::Virtual, &flag);
if (flag)
return NS_OK;
nsCOMPtr<nsIMsgPluggableStore> msgStore;
nsresult rv = m_folder->GetMsgStore(getter_AddRefs(msgStore));
NS_ENSURE_SUCCESS(rv, rv);
return msgStore->SetSummaryFileValid(m_folder, this, aValid);
}
NS_IMETHODIMP nsMailDatabase::RemoveOfflineOp(nsIMsgOfflineImapOperation *op)
{
nsresult rv = GetAllOfflineOpsTable();
NS_ENSURE_SUCCESS(rv, rv);
if (!op || !m_mdbAllOfflineOpsTable)
return NS_ERROR_NULL_POINTER;
nsMsgOfflineImapOperation* offlineOp = static_cast<nsMsgOfflineImapOperation*>(op); // closed system, so this is ok
nsIMdbRow* row = offlineOp->GetMDBRow();
rv = m_mdbAllOfflineOpsTable->CutRow(GetEnv(), row);
row->CutAllColumns(GetEnv());
return rv;
}
NS_IMETHODIMP nsMailDatabase::GetOfflineOpForKey(nsMsgKey msgKey, bool create, nsIMsgOfflineImapOperation **offlineOp)
{
mdb_bool hasOid;
mdbOid rowObjectId;
nsresult err;
if (!IMAPOffline)
IMAPOffline = PR_NewLogModule("IMAPOFFLINE");
nsresult rv = GetAllOfflineOpsTable();
NS_ENSURE_SUCCESS(rv, rv);
if (!offlineOp || !m_mdbAllOfflineOpsTable)
return NS_ERROR_NULL_POINTER;
*offlineOp = NULL;
rowObjectId.mOid_Id = msgKey;
rowObjectId.mOid_Scope = m_offlineOpsRowScopeToken;
err = m_mdbAllOfflineOpsTable->HasOid(GetEnv(), &rowObjectId, &hasOid);
if (NS_SUCCEEDED(err) && m_mdbStore && (hasOid || create))
{
nsCOMPtr <nsIMdbRow> offlineOpRow;
err = m_mdbStore->GetRow(GetEnv(), &rowObjectId, getter_AddRefs(offlineOpRow));
if (create)
{
if (!offlineOpRow)
{
err = m_mdbStore->NewRowWithOid(GetEnv(), &rowObjectId, getter_AddRefs(offlineOpRow));
NS_ENSURE_SUCCESS(err, err);
}
if (offlineOpRow && !hasOid)
m_mdbAllOfflineOpsTable->AddRow(GetEnv(), offlineOpRow);
}
if (NS_SUCCEEDED(err) && offlineOpRow)
{
*offlineOp = new nsMsgOfflineImapOperation(this, offlineOpRow);
if (*offlineOp)
(*offlineOp)->SetMessageKey(msgKey);
NS_IF_ADDREF(*offlineOp);
}
if (!hasOid && m_dbFolderInfo)
{
// set initial value for flags so we don't lose them.
nsCOMPtr <nsIMsgDBHdr> msgHdr;
GetMsgHdrForKey(msgKey, getter_AddRefs(msgHdr));
if (msgHdr)
{
uint32_t flags;
msgHdr->GetFlags(&flags);
(*offlineOp)->SetNewFlags(flags);
}
int32_t newFlags;
m_dbFolderInfo->OrFlags(nsMsgFolderFlags::OfflineEvents, &newFlags);
}
}
return err;
}
NS_IMETHODIMP nsMailDatabase::EnumerateOfflineOps(nsISimpleEnumerator **enumerator)
{
NS_ASSERTION(false, "not impl yet");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsMailDatabase::ListAllOfflineOpIds(nsTArray<nsMsgKey> *offlineOpIds)
{
NS_ENSURE_ARG(offlineOpIds);
nsresult rv = GetAllOfflineOpsTable();
NS_ENSURE_SUCCESS(rv, rv);
nsIMdbTableRowCursor *rowCursor;
if (!IMAPOffline)
IMAPOffline = PR_NewLogModule("IMAPOFFLINE");
if (m_mdbAllOfflineOpsTable)
{
nsresult err = m_mdbAllOfflineOpsTable->GetTableRowCursor(GetEnv(), -1, &rowCursor);
while (NS_SUCCEEDED(err) && rowCursor)
{
mdbOid outOid;
mdb_pos outPos;
err = rowCursor->NextRowOid(GetEnv(), &outOid, &outPos);
// is this right? Mork is returning a 0 id, but that should valid.
if (outPos < 0 || outOid.mOid_Id == (mdb_id) -1)
break;
if (NS_SUCCEEDED(err))
{
offlineOpIds->AppendElement(outOid.mOid_Id);
if (MOZ_LOG_TEST(IMAPOffline, LogLevel::Info))
{
nsCOMPtr <nsIMsgOfflineImapOperation> offlineOp;
GetOfflineOpForKey(outOid.mOid_Id, false, getter_AddRefs(offlineOp));
if (offlineOp)
{
nsMsgOfflineImapOperation *logOp = static_cast<nsMsgOfflineImapOperation *>(static_cast<nsIMsgOfflineImapOperation *>(offlineOp.get()));
if (logOp)
logOp->Log(IMAPOffline);
}
}
}
}
// TODO: would it cause a problem to replace this with "rv = err;" ?
rv = (NS_SUCCEEDED(err)) ? NS_OK : NS_ERROR_FAILURE;
rowCursor->Release();
}
offlineOpIds->Sort();
return rv;
}
NS_IMETHODIMP nsMailDatabase::ListAllOfflineDeletes(nsTArray<nsMsgKey> *offlineDeletes)
{
NS_ENSURE_ARG_POINTER(offlineDeletes);
nsresult rv = GetAllOfflineOpsTable();
NS_ENSURE_SUCCESS(rv, rv);
nsIMdbTableRowCursor *rowCursor;
if (m_mdbAllOfflineOpsTable)
{
nsresult err = m_mdbAllOfflineOpsTable->GetTableRowCursor(GetEnv(), -1, &rowCursor);
while (NS_SUCCEEDED(err) && rowCursor)
{
mdbOid outOid;
mdb_pos outPos;
nsIMdbRow* offlineOpRow;
err = rowCursor->NextRow(GetEnv(), &offlineOpRow, &outPos);
// is this right? Mork is returning a 0 id, but that should valid.
if (outPos < 0 || offlineOpRow == nullptr)
break;
if (NS_SUCCEEDED(err))
{
offlineOpRow->GetOid(GetEnv(), &outOid);
nsIMsgOfflineImapOperation *offlineOp = new nsMsgOfflineImapOperation(this, offlineOpRow);
if (offlineOp)
{
NS_ADDREF(offlineOp);
imapMessageFlagsType newFlags;
nsOfflineImapOperationType opType;
offlineOp->GetOperation(&opType);
offlineOp->GetNewFlags(&newFlags);
if (opType & nsIMsgOfflineImapOperation::kMsgMoved ||
((opType & nsIMsgOfflineImapOperation::kFlagsChanged)
&& (newFlags & nsIMsgOfflineImapOperation::kMsgMarkedDeleted)))
offlineDeletes->AppendElement(outOid.mOid_Id);
NS_RELEASE(offlineOp);
}
offlineOpRow->Release();
}
}
// TODO: would it cause a problem to replace this with "rv = err;" ?
rv = (NS_SUCCEEDED(err)) ? NS_OK : NS_ERROR_FAILURE;
rowCursor->Release();
}
return rv;
}
// This is used to remember that the db is out of sync with the mail folder
// and needs to be regenerated.
void nsMailDatabase::SetReparse(bool reparse)
{
m_reparse = reparse;
}
class nsMsgOfflineOpEnumerator : public nsISimpleEnumerator {
public:
NS_DECL_ISUPPORTS
// nsISimpleEnumerator methods:
NS_DECL_NSISIMPLEENUMERATOR
nsMsgOfflineOpEnumerator(nsMailDatabase* db);
protected:
virtual ~nsMsgOfflineOpEnumerator();
nsresult GetRowCursor();
nsresult PrefetchNext();
nsMailDatabase* mDB;
nsIMdbTableRowCursor* mRowCursor;
nsCOMPtr <nsIMsgOfflineImapOperation> mResultOp;
bool mDone;
bool mNextPrefetched;
};
nsMsgOfflineOpEnumerator::nsMsgOfflineOpEnumerator(nsMailDatabase* db)
: mDB(db), mRowCursor(nullptr), mDone(false)
{
NS_ADDREF(mDB);
mNextPrefetched = false;
}
nsMsgOfflineOpEnumerator::~nsMsgOfflineOpEnumerator()
{
NS_IF_RELEASE(mRowCursor);
NS_RELEASE(mDB);
}
NS_IMPL_ISUPPORTS(nsMsgOfflineOpEnumerator, nsISimpleEnumerator)
nsresult nsMsgOfflineOpEnumerator::GetRowCursor()
{
nsresult rv = NS_OK;
mDone = false;
if (!mDB || !mDB->m_mdbAllOfflineOpsTable)
return NS_ERROR_NULL_POINTER;
rv = mDB->m_mdbAllOfflineOpsTable->GetTableRowCursor(mDB->GetEnv(), -1, &mRowCursor);
return rv;
}
NS_IMETHODIMP nsMsgOfflineOpEnumerator::GetNext(nsISupports **aItem)
{
NS_ENSURE_ARG_POINTER(aItem);
nsresult rv = NS_OK;
if (!mNextPrefetched)
rv = PrefetchNext();
if (NS_SUCCEEDED(rv))
{
if (mResultOp)
{
*aItem = mResultOp;
NS_ADDREF(*aItem);
mNextPrefetched = false;
}
}
return rv;
}
nsresult nsMsgOfflineOpEnumerator::PrefetchNext()
{
nsresult rv = NS_OK;
nsIMdbRow* offlineOpRow;
mdb_pos rowPos;
if (!mRowCursor)
{
rv = GetRowCursor();
if (NS_FAILED(rv))
return rv;
}
rv = mRowCursor->NextRow(mDB->GetEnv(), &offlineOpRow, &rowPos);
if (!offlineOpRow)
{
mDone = true;
return NS_ERROR_FAILURE;
}
if (NS_FAILED(rv))
{
mDone = true;
return rv;
}
nsIMsgOfflineImapOperation *op = new nsMsgOfflineImapOperation(mDB, offlineOpRow);
mResultOp = op;
if (!op)
return NS_ERROR_OUT_OF_MEMORY;
if (mResultOp)
{
mNextPrefetched = true;
return NS_OK;
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMsgOfflineOpEnumerator::HasMoreElements(bool *aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
if (!mNextPrefetched)
PrefetchNext();
*aResult = !mDone;
return NS_OK;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,378 @@
/* -*- 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 "nsMsgOfflineImapOperation.h"
#include "nsMsgUtils.h"
#include "mozilla/Logging.h"
using namespace mozilla;
PRLogModuleInfo *IMAPOffline;
/* Implementation file */
NS_IMPL_ISUPPORTS(nsMsgOfflineImapOperation, nsIMsgOfflineImapOperation)
// property names for offine imap operation fields.
#define PROP_OPERATION "op"
#define PROP_OPERATION_FLAGS "opFlags"
#define PROP_NEW_FLAGS "newFlags"
#define PROP_MESSAGE_KEY "msgKey"
#define PROP_SRC_MESSAGE_KEY "srcMsgKey"
#define PROP_SRC_FOLDER_URI "srcFolderURI"
#define PROP_MOVE_DEST_FOLDER_URI "moveDest"
#define PROP_NUM_COPY_DESTS "numCopyDests"
#define PROP_COPY_DESTS "copyDests" // how to delimit these? Or should we do the "dest1","dest2" etc trick? But then we'd need to shuffle
// them around since we delete off the front first.
#define PROP_KEYWORD_ADD "addedKeywords"
#define PROP_KEYWORD_REMOVE "removedKeywords"
#define PROP_MSG_SIZE "msgSize"
#define PROP_PLAYINGBACK "inPlayback"
nsMsgOfflineImapOperation::nsMsgOfflineImapOperation(nsMsgDatabase *db, nsIMdbRow *row)
{
NS_ASSERTION(db, "can't have null db");
NS_ASSERTION(row, "can't have null row");
m_operation = 0;
m_operationFlags = 0;
m_messageKey = nsMsgKey_None;
m_sourceMessageKey = nsMsgKey_None;
m_mdb = db;
NS_ADDREF(m_mdb);
m_mdbRow = row;
m_newFlags = 0;
m_mdb->GetUint32Property(m_mdbRow, PROP_OPERATION, (uint32_t *) &m_operation, 0);
m_mdb->GetUint32Property(m_mdbRow, PROP_MESSAGE_KEY, &m_messageKey, 0);
m_mdb->GetUint32Property(m_mdbRow, PROP_OPERATION_FLAGS, &m_operationFlags, 0);
m_mdb->GetUint32Property(m_mdbRow, PROP_NEW_FLAGS, (uint32_t *) &m_newFlags, 0);
}
nsMsgOfflineImapOperation::~nsMsgOfflineImapOperation()
{
// clear the row first, in case we're holding the last reference
// to the db.
m_mdbRow = nullptr;
NS_IF_RELEASE(m_mdb);
}
/* attribute nsOfflineImapOperationType operation; */
NS_IMETHODIMP nsMsgOfflineImapOperation::GetOperation(nsOfflineImapOperationType *aOperation)
{
NS_ENSURE_ARG(aOperation);
*aOperation = m_operation;
return NS_OK;
}
NS_IMETHODIMP nsMsgOfflineImapOperation::SetOperation(nsOfflineImapOperationType aOperation)
{
if (MOZ_LOG_TEST(IMAPOffline, LogLevel::Info))
MOZ_LOG(IMAPOffline, LogLevel::Info, ("msg id %x setOperation was %x add %x", m_messageKey, m_operation, aOperation));
m_operation |= aOperation;
return m_mdb->SetUint32Property(m_mdbRow, PROP_OPERATION, m_operation);
}
/* void clearOperation (in nsOfflineImapOperationType operation); */
NS_IMETHODIMP nsMsgOfflineImapOperation::ClearOperation(nsOfflineImapOperationType aOperation)
{
if (MOZ_LOG_TEST(IMAPOffline, LogLevel::Info))
MOZ_LOG(IMAPOffline, LogLevel::Info, ("msg id %x clearOperation was %x clear %x", m_messageKey, m_operation, aOperation));
m_operation &= ~aOperation;
switch (aOperation)
{
case kMsgMoved:
case kAppendTemplate:
case kAppendDraft:
m_moveDestination.Truncate();
break;
case kMsgCopy:
m_copyDestinations.RemoveElementAt(0);
break;
}
return m_mdb->SetUint32Property(m_mdbRow, PROP_OPERATION, m_operation);
}
/* attribute nsMsgKey messageKey; */
NS_IMETHODIMP nsMsgOfflineImapOperation::GetMessageKey(nsMsgKey *aMessageKey)
{
NS_ENSURE_ARG(aMessageKey);
*aMessageKey = m_messageKey;
return NS_OK;
}
NS_IMETHODIMP nsMsgOfflineImapOperation::SetMessageKey(nsMsgKey aMessageKey)
{
m_messageKey = aMessageKey;
return m_mdb->SetUint32Property(m_mdbRow, PROP_MESSAGE_KEY, m_messageKey);
}
/* attribute nsMsgKey srcMessageKey; */
NS_IMETHODIMP nsMsgOfflineImapOperation::GetSrcMessageKey(nsMsgKey *aMessageKey)
{
NS_ENSURE_ARG(aMessageKey);
return m_mdb->GetUint32Property(m_mdbRow, PROP_SRC_MESSAGE_KEY, aMessageKey, nsMsgKey_None);
}
NS_IMETHODIMP nsMsgOfflineImapOperation::SetSrcMessageKey(nsMsgKey aMessageKey)
{
m_messageKey = aMessageKey;
return m_mdb->SetUint32Property(m_mdbRow, PROP_SRC_MESSAGE_KEY, m_messageKey);
}
/* attribute imapMessageFlagsType flagOperation; */
NS_IMETHODIMP nsMsgOfflineImapOperation::GetFlagOperation(imapMessageFlagsType *aFlagOperation)
{
NS_ENSURE_ARG(aFlagOperation);
*aFlagOperation = m_operationFlags;
return NS_OK;
}
NS_IMETHODIMP nsMsgOfflineImapOperation::SetFlagOperation(imapMessageFlagsType aFlagOperation)
{
if (MOZ_LOG_TEST(IMAPOffline, LogLevel::Info))
MOZ_LOG(IMAPOffline, LogLevel::Info, ("msg id %x setFlagOperation was %x add %x", m_messageKey, m_operationFlags, aFlagOperation));
SetOperation(kFlagsChanged);
nsresult rv = SetNewFlags(aFlagOperation);
NS_ENSURE_SUCCESS(rv, rv);
m_operationFlags |= aFlagOperation;
return m_mdb->SetUint32Property(m_mdbRow, PROP_OPERATION_FLAGS, m_operationFlags);
}
/* attribute imapMessageFlagsType flagOperation; */
NS_IMETHODIMP nsMsgOfflineImapOperation::GetNewFlags(imapMessageFlagsType *aNewFlags)
{
NS_ENSURE_ARG(aNewFlags);
uint32_t flags;
nsresult rv = m_mdb->GetUint32Property(m_mdbRow, PROP_NEW_FLAGS, &flags, 0);
*aNewFlags = m_newFlags = (imapMessageFlagsType) flags;
return rv;
}
NS_IMETHODIMP nsMsgOfflineImapOperation::SetNewFlags(imapMessageFlagsType aNewFlags)
{
if (MOZ_LOG_TEST(IMAPOffline, LogLevel::Info) && m_newFlags != aNewFlags)
MOZ_LOG(IMAPOffline, LogLevel::Info, ("msg id %x SetNewFlags was %x to %x", m_messageKey, m_newFlags, aNewFlags));
m_newFlags = aNewFlags;
return m_mdb->SetUint32Property(m_mdbRow, PROP_NEW_FLAGS, m_newFlags);
}
/* attribute string destinationFolderURI; */
NS_IMETHODIMP nsMsgOfflineImapOperation::GetDestinationFolderURI(char * *aDestinationFolderURI)
{
NS_ENSURE_ARG(aDestinationFolderURI);
(void) m_mdb->GetProperty(m_mdbRow, PROP_MOVE_DEST_FOLDER_URI, getter_Copies(m_moveDestination));
*aDestinationFolderURI = ToNewCString(m_moveDestination);
return (*aDestinationFolderURI) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP nsMsgOfflineImapOperation::SetDestinationFolderURI(const char * aDestinationFolderURI)
{
if (MOZ_LOG_TEST(IMAPOffline, LogLevel::Info))
MOZ_LOG(IMAPOffline, LogLevel::Info, ("msg id %x SetDestinationFolderURI to %s", m_messageKey, aDestinationFolderURI));
m_moveDestination = aDestinationFolderURI ? aDestinationFolderURI : 0;
return m_mdb->SetProperty(m_mdbRow, PROP_MOVE_DEST_FOLDER_URI, aDestinationFolderURI);
}
/* attribute string sourceFolderURI; */
NS_IMETHODIMP nsMsgOfflineImapOperation::GetSourceFolderURI(char * *aSourceFolderURI)
{
NS_ENSURE_ARG(aSourceFolderURI);
nsresult rv = m_mdb->GetProperty(m_mdbRow, PROP_SRC_FOLDER_URI, getter_Copies(m_sourceFolder));
*aSourceFolderURI = ToNewCString(m_sourceFolder);
return rv;
}
NS_IMETHODIMP nsMsgOfflineImapOperation::SetSourceFolderURI(const char * aSourceFolderURI)
{
m_sourceFolder = aSourceFolderURI ? aSourceFolderURI : 0;
SetOperation(kMoveResult);
return m_mdb->SetProperty(m_mdbRow, PROP_SRC_FOLDER_URI, aSourceFolderURI);
}
/* attribute string keyword; */
NS_IMETHODIMP nsMsgOfflineImapOperation::GetKeywordsToAdd(char * *aKeywords)
{
NS_ENSURE_ARG(aKeywords);
nsresult rv = m_mdb->GetProperty(m_mdbRow, PROP_KEYWORD_ADD, getter_Copies(m_keywordsToAdd));
*aKeywords = ToNewCString(m_keywordsToAdd);
return rv;
}
NS_IMETHODIMP nsMsgOfflineImapOperation::AddKeywordToAdd(const char * aKeyword)
{
SetOperation(kAddKeywords);
return AddKeyword(aKeyword, m_keywordsToAdd, PROP_KEYWORD_ADD, m_keywordsToRemove, PROP_KEYWORD_REMOVE);
}
NS_IMETHODIMP nsMsgOfflineImapOperation::GetKeywordsToRemove(char * *aKeywords)
{
NS_ENSURE_ARG(aKeywords);
nsresult rv = m_mdb->GetProperty(m_mdbRow, PROP_KEYWORD_REMOVE, getter_Copies(m_keywordsToRemove));
*aKeywords = ToNewCString(m_keywordsToRemove);
return rv;
}
nsresult nsMsgOfflineImapOperation::AddKeyword(const char *aKeyword, nsCString &addList, const char *addProp,
nsCString &removeList, const char *removeProp)
{
int32_t startOffset, keywordLength;
if (!MsgFindKeyword(nsDependentCString(aKeyword), addList, &startOffset, &keywordLength))
{
if (!addList.IsEmpty())
addList.Append(' ');
addList.Append(aKeyword);
}
// if the keyword we're removing was in the list of keywords to add,
// cut it from that list.
if (MsgFindKeyword(nsDependentCString(aKeyword), removeList, &startOffset, &keywordLength))
{
removeList.Cut(startOffset, keywordLength);
m_mdb->SetProperty(m_mdbRow, removeProp, removeList.get());
}
return m_mdb->SetProperty(m_mdbRow, addProp, addList.get());
}
NS_IMETHODIMP nsMsgOfflineImapOperation::AddKeywordToRemove(const char * aKeyword)
{
SetOperation(kRemoveKeywords);
return AddKeyword(aKeyword, m_keywordsToRemove, PROP_KEYWORD_REMOVE, m_keywordsToAdd, PROP_KEYWORD_ADD);
}
NS_IMETHODIMP nsMsgOfflineImapOperation::AddMessageCopyOperation(const char *destinationBox)
{
SetOperation(kMsgCopy);
nsAutoCString newDest(destinationBox);
nsresult rv = GetCopiesFromDB();
NS_ENSURE_SUCCESS(rv, rv);
m_copyDestinations.AppendElement(newDest);
return SetCopiesToDB();
}
// we write out the folders as one string, separated by 0x1.
#define FOLDER_SEP_CHAR '\001'
nsresult nsMsgOfflineImapOperation::GetCopiesFromDB()
{
nsCString copyDests;
m_copyDestinations.Clear();
nsresult rv = m_mdb->GetProperty(m_mdbRow, PROP_COPY_DESTS, getter_Copies(copyDests));
// use 0x1 as the delimiter between folder names since it's not a legal character
if (NS_SUCCEEDED(rv) && !copyDests.IsEmpty())
{
int32_t curCopyDestStart = 0;
int32_t nextCopyDestPos = 0;
while (nextCopyDestPos != -1)
{
nsCString curDest;
nextCopyDestPos = copyDests.FindChar(FOLDER_SEP_CHAR, curCopyDestStart);
if (nextCopyDestPos > 0)
curDest = Substring(copyDests, curCopyDestStart, nextCopyDestPos - curCopyDestStart);
else
curDest = Substring(copyDests, curCopyDestStart, copyDests.Length() - curCopyDestStart);
curCopyDestStart = nextCopyDestPos + 1;
m_copyDestinations.AppendElement(curDest);
}
}
return rv;
}
nsresult nsMsgOfflineImapOperation::SetCopiesToDB()
{
nsAutoCString copyDests;
// use 0x1 as the delimiter between folders
for (uint32_t i = 0; i < m_copyDestinations.Length(); i++)
{
if (i > 0)
copyDests.Append(FOLDER_SEP_CHAR);
copyDests.Append(m_copyDestinations.ElementAt(i));
}
return m_mdb->SetProperty(m_mdbRow, PROP_COPY_DESTS, copyDests.get());
}
/* attribute long numberOfCopies; */
NS_IMETHODIMP nsMsgOfflineImapOperation::GetNumberOfCopies(int32_t *aNumberOfCopies)
{
NS_ENSURE_ARG(aNumberOfCopies);
nsresult rv = GetCopiesFromDB();
NS_ENSURE_SUCCESS(rv, rv);
*aNumberOfCopies = m_copyDestinations.Length();
return NS_OK;
}
/* string getCopyDestination (in long copyIndex); */
NS_IMETHODIMP nsMsgOfflineImapOperation::GetCopyDestination(int32_t copyIndex, char **retval)
{
NS_ENSURE_ARG(retval);
nsresult rv = GetCopiesFromDB();
NS_ENSURE_SUCCESS(rv, rv);
if (copyIndex >= (int32_t)m_copyDestinations.Length())
return NS_ERROR_ILLEGAL_VALUE;
*retval = ToNewCString(m_copyDestinations.ElementAt(copyIndex));
return (*retval) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
/* attribute unsigned log msgSize; */
NS_IMETHODIMP nsMsgOfflineImapOperation::GetMsgSize(uint32_t *aMsgSize)
{
NS_ENSURE_ARG(aMsgSize);
return m_mdb->GetUint32Property(m_mdbRow, PROP_MSG_SIZE, aMsgSize, 0);
}
NS_IMETHODIMP nsMsgOfflineImapOperation::SetMsgSize(uint32_t aMsgSize)
{
return m_mdb->SetUint32Property(m_mdbRow, PROP_MSG_SIZE, aMsgSize);
}
NS_IMETHODIMP nsMsgOfflineImapOperation::SetPlayingBack(bool aPlayingBack)
{
return m_mdb->SetBooleanProperty(m_mdbRow, PROP_PLAYINGBACK, aPlayingBack);
}
NS_IMETHODIMP nsMsgOfflineImapOperation::GetPlayingBack(bool *aPlayingBack)
{
NS_ENSURE_ARG(aPlayingBack);
return m_mdb->GetBooleanProperty(m_mdbRow, PROP_PLAYINGBACK, aPlayingBack);
}
void nsMsgOfflineImapOperation::Log(PRLogModuleInfo *logFile)
{
if (!IMAPOffline)
IMAPOffline = PR_NewLogModule("IMAPOFFLINE");
if (!MOZ_LOG_TEST(IMAPOffline, LogLevel::Info))
return;
// const long kMoveResult = 0x8;
// const long kAppendDraft = 0x10;
// const long kAddedHeader = 0x20;
// const long kDeletedMsg = 0x40;
// const long kMsgMarkedDeleted = 0x80;
// const long kAppendTemplate = 0x100;
// const long kDeleteAllMsgs = 0x200;
if (m_operation & nsIMsgOfflineImapOperation::kFlagsChanged)
MOZ_LOG(IMAPOffline, LogLevel::Info, ("msg id %x changeFlag:%x", m_messageKey, m_newFlags));
if (m_operation & nsIMsgOfflineImapOperation::kMsgMoved)
{
nsCString moveDestFolder;
GetDestinationFolderURI(getter_Copies(moveDestFolder));
MOZ_LOG(IMAPOffline, LogLevel::Info, ("msg id %x moveTo:%s", m_messageKey, moveDestFolder.get()));
}
if (m_operation & nsIMsgOfflineImapOperation::kMsgCopy)
{
nsCString copyDests;
m_mdb->GetProperty(m_mdbRow, PROP_COPY_DESTS, getter_Copies(copyDests));
MOZ_LOG(IMAPOffline, LogLevel::Info, ("msg id %x moveTo:%s", m_messageKey, copyDests.get()));
}
if (m_operation & nsIMsgOfflineImapOperation::kAppendDraft)
MOZ_LOG(IMAPOffline, LogLevel::Info, ("msg id %x append draft", m_messageKey));
if (m_operation & nsIMsgOfflineImapOperation::kAddKeywords)
MOZ_LOG(IMAPOffline, LogLevel::Info, ("msg id %x add keyword:%s", m_messageKey, m_keywordsToAdd.get()));
if (m_operation & nsIMsgOfflineImapOperation::kRemoveKeywords)
MOZ_LOG(IMAPOffline, LogLevel::Info, ("msg id %x remove keyword:%s", m_messageKey, m_keywordsToRemove.get()));
}

View file

@ -0,0 +1,55 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 _nsMsgOfflineImapOperation_H_
#include "nsIMsgOfflineImapOperation.h"
#include "mdb.h"
#include "nsMsgDatabase.h"
#include "prlog.h"
class nsMsgOfflineImapOperation : public nsIMsgOfflineImapOperation
{
public:
/** Instance Methods **/
nsMsgOfflineImapOperation(nsMsgDatabase *db, nsIMdbRow *row);
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGOFFLINEIMAPOPERATION
nsIMdbRow *GetMDBRow() {return m_mdbRow;}
nsresult GetCopiesFromDB();
nsresult SetCopiesToDB();
void Log(PRLogModuleInfo *logFile);
protected:
virtual ~nsMsgOfflineImapOperation();
nsresult AddKeyword(const char *aKeyword, nsCString &addList, const char *addProp,
nsCString &removeList, const char *removeProp);
nsOfflineImapOperationType m_operation;
nsMsgKey m_messageKey;
nsMsgKey m_sourceMessageKey;
uint32_t m_operationFlags; // what to do on sync
imapMessageFlagsType m_newFlags; // used for kFlagsChanged
// these are URI's, and are escaped. Thus, we can use a delimter like ' '
// because the real spaces should be escaped.
nsCString m_sourceFolder;
nsCString m_moveDestination;
nsTArray<nsCString> m_copyDestinations;
nsCString m_keywordsToAdd;
nsCString m_keywordsToRemove;
// nsMsgOfflineImapOperation will have to know what db and row they belong to, since they are really
// just a wrapper around the offline operation row in the mdb.
// though I hope not.
nsMsgDatabase *m_mdb;
nsCOMPtr <nsIMdbRow> m_mdbRow;
};
#endif /* _nsMsgOfflineImapOperation_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,360 @@
/* -*- 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/. */
#include "msgCore.h"
#include "nsIMsgDBView.h"
#include "nsIMsgThread.h"
#include "nsNewsDatabase.h"
#include "nsMsgKeySet.h"
#include "nsCOMPtr.h"
#include "prlog.h"
#if defined(DEBUG_sspitzer_) || defined(DEBUG_seth_)
#define DEBUG_NEWS_DATABASE 1
#endif
nsNewsDatabase::nsNewsDatabase()
{
m_readSet = nullptr;
}
nsNewsDatabase::~nsNewsDatabase()
{
}
NS_IMPL_ADDREF_INHERITED(nsNewsDatabase, nsMsgDatabase)
NS_IMPL_RELEASE_INHERITED(nsNewsDatabase, nsMsgDatabase)
NS_IMETHODIMP nsNewsDatabase::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if (!aInstancePtr) return NS_ERROR_NULL_POINTER;
*aInstancePtr = nullptr;
if (aIID.Equals(NS_GET_IID(nsINewsDatabase)))
{
*aInstancePtr = static_cast<nsINewsDatabase *>(this);
}
if(*aInstancePtr)
{
AddRef();
return NS_OK;
}
return nsMsgDatabase::QueryInterface(aIID, aInstancePtr);
}
nsresult nsNewsDatabase::Close(bool forceCommit)
{
return nsMsgDatabase::Close(forceCommit);
}
nsresult nsNewsDatabase::ForceClosed()
{
return nsMsgDatabase::ForceClosed();
}
nsresult nsNewsDatabase::Commit(nsMsgDBCommit commitType)
{
if (m_dbFolderInfo && m_readSet)
{
// let's write out our idea of the read set so we can compare it with that of
// the .rc file next time we start up.
nsCString readSet;
m_readSet->Output(getter_Copies(readSet));
m_dbFolderInfo->SetCharProperty("readSet", readSet);
}
return nsMsgDatabase::Commit(commitType);
}
uint32_t nsNewsDatabase::GetCurVersion()
{
return kMsgDBVersion;
}
NS_IMETHODIMP nsNewsDatabase::IsRead(nsMsgKey key, bool *pRead)
{
NS_ASSERTION(pRead, "null out param in IsRead");
if (!pRead) return NS_ERROR_NULL_POINTER;
if (!m_readSet) return NS_ERROR_FAILURE;
*pRead = m_readSet->IsMember(key);
return NS_OK;
}
nsresult nsNewsDatabase::IsHeaderRead(nsIMsgDBHdr *msgHdr, bool *pRead)
{
nsresult rv;
nsMsgKey messageKey;
if (!msgHdr || !pRead) return NS_ERROR_NULL_POINTER;
rv = msgHdr->GetMessageKey(&messageKey);
if (NS_FAILED(rv)) return rv;
rv = IsRead(messageKey,pRead);
return rv;
}
// return highest article number we've seen.
NS_IMETHODIMP nsNewsDatabase::GetHighWaterArticleNum(nsMsgKey *key)
{
NS_ASSERTION(m_dbFolderInfo, "null db folder info");
if (!m_dbFolderInfo)
return NS_ERROR_FAILURE;
return m_dbFolderInfo->GetHighWater(key);
}
// return the key of the first article number we know about.
// Since the iterator iterates in id order, we can just grab the
// messagekey of the first header it returns.
// ### dmb
// This will not deal with the situation where we get holes in
// the headers we know about. Need to figure out how and when
// to solve that. This could happen if a transfer is interrupted.
// Do we need to keep track of known arts permanently?
NS_IMETHODIMP nsNewsDatabase::GetLowWaterArticleNum(nsMsgKey *key)
{
nsresult rv;
nsMsgHdr *pHeader;
nsCOMPtr<nsISimpleEnumerator> hdrs;
rv = EnumerateMessages(getter_AddRefs(hdrs));
if (NS_FAILED(rv))
return rv;
rv = hdrs->GetNext((nsISupports**)&pHeader);
NS_ASSERTION(NS_SUCCEEDED(rv), "nsMsgDBEnumerator broken");
if (NS_FAILED(rv))
return rv;
return pHeader->GetMessageKey(key);
}
nsresult nsNewsDatabase::ExpireUpTo(nsMsgKey expireKey)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult nsNewsDatabase::ExpireRange(nsMsgKey startRange, nsMsgKey endRange)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsNewsDatabase::GetReadSet(nsMsgKeySet **pSet)
{
if (!pSet) return NS_ERROR_NULL_POINTER;
*pSet = m_readSet;
return NS_OK;
}
NS_IMETHODIMP nsNewsDatabase::SetReadSet(nsMsgKeySet *pSet)
{
m_readSet = pSet;
if (m_readSet)
{
// compare this read set with the one in the db folder info.
// If not equivalent, sync with this one.
nsCString dbReadSet;
if (m_dbFolderInfo)
m_dbFolderInfo->GetCharProperty("readSet", dbReadSet);
nsCString newsrcReadSet;
m_readSet->Output(getter_Copies(newsrcReadSet));
if (!dbReadSet.Equals(newsrcReadSet))
SyncWithReadSet();
}
return NS_OK;
}
bool nsNewsDatabase::SetHdrReadFlag(nsIMsgDBHdr *msgHdr, bool bRead)
{
nsresult rv;
bool isRead;
rv = IsHeaderRead(msgHdr, &isRead);
if (isRead == bRead)
{
// give the base class a chance to update m_flags.
nsMsgDatabase::SetHdrReadFlag(msgHdr, bRead);
return false;
}
else {
nsMsgKey messageKey;
// give the base class a chance to update m_flags.
nsMsgDatabase::SetHdrReadFlag(msgHdr, bRead);
rv = msgHdr->GetMessageKey(&messageKey);
if (NS_FAILED(rv)) return false;
NS_ASSERTION(m_readSet, "m_readSet is null");
if (!m_readSet) return false;
if (!bRead) {
#ifdef DEBUG_NEWS_DATABASE
printf("remove %d from the set\n",messageKey);
#endif
m_readSet->Remove(messageKey);
rv = NotifyReadChanged(nullptr);
if (NS_FAILED(rv)) return false;
}
else {
#ifdef DEBUG_NEWS_DATABASE
printf("add %d to the set\n",messageKey);
#endif
if (m_readSet->Add(messageKey) < 0) return false;
rv = NotifyReadChanged(nullptr);
if (NS_FAILED(rv)) return false;
}
}
return true;
}
NS_IMETHODIMP nsNewsDatabase::MarkAllRead(uint32_t *aNumMarked,
nsMsgKey **aThoseMarked)
{
nsMsgKey lowWater = nsMsgKey_None, highWater;
nsCString knownArts;
if (m_dbFolderInfo)
{
m_dbFolderInfo->GetKnownArtsSet(getter_Copies(knownArts));
nsMsgKeySet *knownKeys = nsMsgKeySet::Create(knownArts.get());
if (knownKeys)
lowWater = knownKeys->GetFirstMember();
delete knownKeys;
}
if (lowWater == nsMsgKey_None)
GetLowWaterArticleNum(&lowWater);
GetHighWaterArticleNum(&highWater);
if (lowWater > 2)
m_readSet->AddRange(1, lowWater - 1);
nsresult err = nsMsgDatabase::MarkAllRead(aNumMarked, aThoseMarked);
if (NS_SUCCEEDED(err) && 1 <= highWater)
m_readSet->AddRange(1, highWater); // mark everything read in newsrc.
return err;
}
nsresult nsNewsDatabase::SyncWithReadSet()
{
// The code below attempts to update the underlying nsMsgDatabase's idea
// of read/unread flags to match the read set in the .newsrc file. It should
// only be called when they don't match, e.g., we crashed after committing the
// db but before writing out the .newsrc
nsCOMPtr <nsISimpleEnumerator> hdrs;
nsresult rv = EnumerateMessages(getter_AddRefs(hdrs));
NS_ENSURE_SUCCESS(rv, rv);
bool hasMore = false, readInNewsrc, isReadInDB, changed = false;
int32_t numMessages = 0, numUnreadMessages = 0;
nsMsgKey messageKey;
nsCOMPtr <nsIMsgThread> threadHdr;
// Scan all messages in DB
while (NS_SUCCEEDED(rv = hdrs->HasMoreElements(&hasMore)) && hasMore)
{
nsCOMPtr<nsISupports> supports;
rv = hdrs->GetNext(getter_AddRefs(supports));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr <nsIMsgDBHdr> header = do_QueryInterface(supports, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = nsMsgDatabase::IsHeaderRead(header, &isReadInDB);
NS_ENSURE_SUCCESS(rv, rv);
header->GetMessageKey(&messageKey);
IsRead(messageKey,&readInNewsrc);
numMessages++;
if (!readInNewsrc)
numUnreadMessages++;
// If DB and readSet disagree on Read/Unread, fix DB
if (readInNewsrc!=isReadInDB)
{
MarkHdrRead(header, readInNewsrc, nullptr);
changed = true;
}
}
// Update FolderInfo Counters
int32_t oldMessages, oldUnreadMessages;
rv = m_dbFolderInfo->GetNumMessages(&oldMessages);
if (NS_SUCCEEDED(rv) && oldMessages!=numMessages)
{
changed = true;
m_dbFolderInfo->ChangeNumMessages(numMessages-oldMessages);
}
rv = m_dbFolderInfo->GetNumUnreadMessages(&oldUnreadMessages);
if (NS_SUCCEEDED(rv) && oldUnreadMessages!=numUnreadMessages)
{
changed = true;
m_dbFolderInfo->ChangeNumUnreadMessages(numUnreadMessages-oldUnreadMessages);
}
if (changed)
Commit(nsMsgDBCommitType::kLargeCommit);
return rv;
}
nsresult nsNewsDatabase::AdjustExpungedBytesOnDelete(nsIMsgDBHdr *msgHdr)
{
uint32_t msgFlags;
msgHdr->GetFlags(&msgFlags);
if (msgFlags & nsMsgMessageFlags::Offline && m_dbFolderInfo)
{
uint32_t size = 0;
(void)msgHdr->GetOfflineMessageSize(&size);
return m_dbFolderInfo->ChangeExpungedBytes (size);
}
return NS_OK;
}
NS_IMETHODIMP
nsNewsDatabase::GetDefaultViewFlags(nsMsgViewFlagsTypeValue *aDefaultViewFlags)
{
NS_ENSURE_ARG_POINTER(aDefaultViewFlags);
GetIntPref("mailnews.default_news_view_flags", aDefaultViewFlags);
if (*aDefaultViewFlags < nsMsgViewFlagsType::kNone ||
*aDefaultViewFlags > (nsMsgViewFlagsType::kThreadedDisplay |
nsMsgViewFlagsType::kShowIgnored |
nsMsgViewFlagsType::kUnreadOnly |
nsMsgViewFlagsType::kExpandAll |
nsMsgViewFlagsType::kGroupBySort))
*aDefaultViewFlags = nsMsgViewFlagsType::kThreadedDisplay;
return NS_OK;
}
NS_IMETHODIMP
nsNewsDatabase::GetDefaultSortType(nsMsgViewSortTypeValue *aDefaultSortType)
{
NS_ENSURE_ARG_POINTER(aDefaultSortType);
GetIntPref("mailnews.default_news_sort_type", aDefaultSortType);
if (*aDefaultSortType < nsMsgViewSortType::byDate ||
*aDefaultSortType > nsMsgViewSortType::byAccount)
*aDefaultSortType = nsMsgViewSortType::byThread;
return NS_OK;
}
NS_IMETHODIMP
nsNewsDatabase::GetDefaultSortOrder(nsMsgViewSortOrderValue *aDefaultSortOrder)
{
NS_ENSURE_ARG_POINTER(aDefaultSortOrder);
GetIntPref("mailnews.default_news_sort_order", aDefaultSortOrder);
if (*aDefaultSortOrder != nsMsgViewSortOrder::descending)
*aDefaultSortOrder = nsMsgViewSortOrder::ascending;
return NS_OK;
}