summaryrefslogtreecommitdiffstats
path: root/mailnews/base/util/folderUtils.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/base/util/folderUtils.jsm')
-rw-r--r--mailnews/base/util/folderUtils.jsm234
1 files changed, 234 insertions, 0 deletions
diff --git a/mailnews/base/util/folderUtils.jsm b/mailnews/base/util/folderUtils.jsm
new file mode 100644
index 000000000..62fb7700b
--- /dev/null
+++ b/mailnews/base/util/folderUtils.jsm
@@ -0,0 +1,234 @@
+/* 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 file contains helper methods for dealing with nsIMsgFolders.
+ */
+
+this.EXPORTED_SYMBOLS = ["getFolderProperties", "getSpecialFolderString",
+ "getFolderFromUri", "allAccountsSorted",
+ "getMostRecentFolders", "folderNameCompare"];
+
+Components.utils.import("resource:///modules/mailServices.js");
+Components.utils.import("resource:///modules/iteratorUtils.jsm");
+
+/**
+ * Returns a string representation of a folder's "special" type.
+ *
+ * @param aFolder the nsIMsgFolder whose special type should be returned
+ */
+function getSpecialFolderString(aFolder) {
+ const nsMsgFolderFlags = Components.interfaces.nsMsgFolderFlags;
+ let flags = aFolder.flags;
+ if (flags & nsMsgFolderFlags.Inbox)
+ return "Inbox";
+ if (flags & nsMsgFolderFlags.Trash)
+ return "Trash";
+ if (flags & nsMsgFolderFlags.Queue)
+ return "Outbox";
+ if (flags & nsMsgFolderFlags.SentMail)
+ return "Sent";
+ if (flags & nsMsgFolderFlags.Drafts)
+ return "Drafts";
+ if (flags & nsMsgFolderFlags.Templates)
+ return "Templates";
+ if (flags & nsMsgFolderFlags.Junk)
+ return "Junk";
+ if (flags & nsMsgFolderFlags.Archive)
+ return "Archive";
+ if (flags & nsMsgFolderFlags.Virtual)
+ return "Virtual";
+ return "none";
+}
+
+/**
+ * This function is meant to be used with trees. It returns the property list
+ * for all of the common properties that css styling is based off of.
+ *
+ * @param nsIMsgFolder aFolder the folder whose properties should be returned
+ * as a string
+ * @param bool aOpen true if the folder is open/expanded
+ *
+ * @return A string of the property names, delimited by space.
+ */
+function getFolderProperties(aFolder, aOpen) {
+ const nsIMsgFolder = Components.interfaces.nsIMsgFolder;
+ let properties = [];
+
+ properties.push("folderNameCol");
+
+ properties.push("serverType-" + aFolder.server.type);
+
+ // set the SpecialFolder attribute
+ properties.push("specialFolder-" + getSpecialFolderString(aFolder));
+
+ // Now set the biffState
+ switch (aFolder.biffState) {
+ case nsIMsgFolder.nsMsgBiffState_NewMail:
+ properties.push("biffState-NewMail");
+ break;
+ case nsIMsgFolder.nsMsgBiffState_NoMail:
+ properties.push("biffState-NoMail");
+ break;
+ default:
+ properties.push("biffState-UnknownMail");
+ }
+
+ properties.push("isSecure-" + aFolder.server.isSecure);
+
+ // A folder has new messages, or a closed folder or any subfolder has new messages.
+ if (aFolder.hasNewMessages ||
+ (!aOpen && aFolder.hasSubFolders && aFolder.hasFolderOrSubfolderNewMessages))
+ properties.push("newMessages-true");
+
+ if (aFolder.isServer) {
+ properties.push("isServer-true");
+ }
+ else
+ {
+ // We only set this if we're not a server
+ let shallowUnread = aFolder.getNumUnread(false);
+ if (shallowUnread > 0) {
+ properties.push("hasUnreadMessages-true");
+ }
+ else
+ {
+ // Make sure that shallowUnread isn't negative
+ shallowUnread = 0;
+ }
+ let deepUnread = aFolder.getNumUnread(true);
+ if (deepUnread - shallowUnread > 0)
+ properties.push("subfoldersHaveUnreadMessages-true");
+ }
+
+ properties.push("noSelect-" + aFolder.noSelect);
+ properties.push("imapShared-" + aFolder.imapShared);
+
+ return properties.join(" ");
+}
+
+/**
+ * Returns a folder for a particular uri
+ *
+ * @param aUri the rdf uri of the folder to return
+ */
+function getFolderFromUri(aUri) {
+ const Cc = Components.classes;
+ const Ci = Components.interfaces;
+ return Cc["@mozilla.org/mail/folder-lookup;1"].
+ getService(Ci.nsIFolderLookupService).getFolderById(aUri);
+}
+
+/**
+ * Returns the sort order value based on the server type to be used for sorting.
+ * The servers (accounts) go in the following order:
+ * (0) default account, (1) other mail accounts, (2) Local Folders,
+ * (3) IM accounts, (4) RSS, (5) News, (9) others (no server)
+ * This ordering is encoded in the .sortOrder property of each server type.
+ *
+ * @param aServer the server object to be tested
+ */
+function getServerSortOrder(aServer) {
+ // If there is no server sort this object to the end.
+ if (!aServer)
+ return 999999999;
+
+ // Otherwise get the server sort order from the Account manager.
+ return MailServices.accounts.getSortOrder(aServer);
+}
+
+/**
+ * Compares the passed in accounts according to their precedence.
+ */
+function compareAccounts(aAccount1, aAccount2) {
+ return getServerSortOrder(aAccount1.incomingServer)
+ - getServerSortOrder(aAccount2.incomingServer);
+}
+
+/**
+ * Returns a list of accounts sorted by server type.
+ *
+ * @param aExcludeIMAccounts Remove IM accounts from the list?
+ */
+function allAccountsSorted(aExcludeIMAccounts) {
+ // Get the account list, and add the proper items.
+ let accountList = toArray(fixIterator(MailServices.accounts.accounts,
+ Components.interfaces.nsIMsgAccount));
+
+ // This is a HACK to work around bug 41133. If we have one of the
+ // dummy "news" accounts there, that account won't have an
+ // incomingServer attached to it, and everything will blow up.
+ accountList = accountList.filter(function hasServer(a) {
+ return a.incomingServer;
+ });
+
+ // Remove IM servers.
+ if (aExcludeIMAccounts) {
+ accountList = accountList.filter(function(a) {
+ return a.incomingServer.type != "im";
+ });
+ }
+
+ return accountList.sort(compareAccounts);
+}
+
+/**
+ * Returns the most recently used/modified folders from the passed in list.
+ *
+ * @param aFolderList The array of nsIMsgFolders to search for recent folders.
+ * @param aMaxHits How many folders to return.
+ * @param aTimeProperty Which folder time property to use.
+ * Use "MRMTime" for most recently modified time.
+ * Use "MRUTime" for most recently used time.
+ */
+function getMostRecentFolders(aFolderList, aMaxHits, aTimeProperty) {
+ let recentFolders = [];
+
+ /**
+ * This sub-function will add a folder to the recentFolders array if it
+ * is among the aMaxHits most recent. If we exceed aMaxHits folders,
+ * it will pop the oldest folder, ensuring that we end up with the
+ * right number.
+ *
+ * @param aFolder The folder to check for recency.
+ */
+ let oldestTime = 0;
+ function addIfRecent(aFolder) {
+ let time = 0;
+ try {
+ time = Number(aFolder.getStringProperty(aTimeProperty)) || 0;
+ } catch(e) {}
+ if (time <= oldestTime)
+ return;
+
+ if (recentFolders.length == aMaxHits) {
+ recentFolders.sort(function sort_folders_by_time(a, b) {
+ return a.time < b.time; });
+ recentFolders.pop();
+ oldestTime = recentFolders[recentFolders.length - 1].time;
+ }
+ recentFolders.push({ folder: aFolder, time: time });
+ }
+
+ for (let folder of aFolderList) {
+ addIfRecent(folder);
+ }
+
+ return recentFolders.map(function (f) { return f.folder; });
+}
+
+/**
+ * A locale dependent comparison function to produce a case-insensitive sort order
+ * used to sort folder names.
+ * Returns positive number if aString1 > aString2, negative number if aString1 > aString2,
+ * otherwise 0.
+ *
+ * @param aString1 first string to compare
+ * @param aString2 second string to compare
+ */
+function folderNameCompare(aString1, aString2) {
+ // TODO: improve this as described in bug 992651.
+ return aString1.toLocaleLowerCase()
+ .localeCompare(aString2.toLocaleLowerCase());
+}