From 302bf1b523012e11b60425d6eee1221ebc2724eb Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Sun, 3 Nov 2019 00:17:46 -0400 Subject: Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1 --- mailnews/base/src/nsMsgFolderDataSource.cpp | 2475 +++++++++++++++++++++++++++ 1 file changed, 2475 insertions(+) create mode 100644 mailnews/base/src/nsMsgFolderDataSource.cpp (limited to 'mailnews/base/src/nsMsgFolderDataSource.cpp') diff --git a/mailnews/base/src/nsMsgFolderDataSource.cpp b/mailnews/base/src/nsMsgFolderDataSource.cpp new file mode 100644 index 000000000..391596ab4 --- /dev/null +++ b/mailnews/base/src/nsMsgFolderDataSource.cpp @@ -0,0 +1,2475 @@ +/* -*- 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" // precompiled header... +#include "prlog.h" +#include "prmem.h" +#include "nsMsgFolderDataSource.h" +#include "nsMsgFolderFlags.h" + +#include "nsMsgUtils.h" +#include "nsMsgRDFUtils.h" + +#include "rdf.h" +#include "nsIRDFService.h" +#include "nsRDFCID.h" +#include "nsIRDFNode.h" +#include "nsEnumeratorUtils.h" + +#include "nsStringGlue.h" +#include "nsCOMPtr.h" + +#include "nsIMsgMailSession.h" +#include "nsIMsgCopyService.h" +#include "nsMsgBaseCID.h" +#include "nsIInputStream.h" +#include "nsIMsgHdr.h" +#include "nsTraceRefcnt.h" +#include "nsIMsgFolder.h" // TO include biffState enum. Change to bool later... +#include "nsIMutableArray.h" +#include "nsIPop3IncomingServer.h" +#include "nsINntpIncomingServer.h" +#include "nsTextFormatter.h" +#include "nsIStringBundle.h" +#include "nsIPrompt.h" +#include "nsIMsgAccountManager.h" +#include "nsArrayEnumerator.h" +#include "nsArrayUtils.h" +#include "nsComponentManagerUtils.h" +#include "nsServiceManagerUtils.h" +#include "nsMemory.h" +#include "nsMsgUtils.h" +#include "mozilla/Services.h" + +#define MESSENGER_STRING_URL "chrome://messenger/locale/messenger.properties" + +nsIRDFResource* nsMsgFolderDataSource::kNC_Child = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_Folder= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_Name= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_Open = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_FolderTreeName= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_FolderTreeSimpleName= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_NameSort= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_FolderTreeNameSort= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_SpecialFolder= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_ServerType = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_IsDeferred = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_CanCreateFoldersOnServer = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_CanFileMessagesOnServer = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_IsServer = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_IsSecure = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_CanSubscribe = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_SupportsOffline = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_CanFileMessages = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_CanCreateSubfolders = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_CanRename = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_CanCompact = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_TotalMessages= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_TotalUnreadMessages= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_FolderSize = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_Charset = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_BiffState = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_HasUnreadMessages = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_NewMessages = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_SubfoldersHaveUnreadMessages = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_NoSelect = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_VirtualFolder = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_InVFEditSearchScope = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_ImapShared = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_Synchronize = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_SyncDisabled = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_CanSearchMessages = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_UnreadFolders = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_FavoriteFolders = nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_RecentFolders = nullptr; + +// commands +nsIRDFResource* nsMsgFolderDataSource::kNC_Delete= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_ReallyDelete= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_NewFolder= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_GetNewMessages= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_Copy= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_Move= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_CopyFolder= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_MoveFolder= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_MarkAllMessagesRead= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_Compact= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_CompactAll= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_Rename= nullptr; +nsIRDFResource* nsMsgFolderDataSource::kNC_EmptyTrash= nullptr; + +nsrefcnt nsMsgFolderDataSource::gFolderResourceRefCnt = 0; + +nsIAtom * nsMsgFolderDataSource::kBiffStateAtom = nullptr; +nsIAtom * nsMsgFolderDataSource::kSortOrderAtom = nullptr; +nsIAtom * nsMsgFolderDataSource::kNewMessagesAtom = nullptr; +nsIAtom * nsMsgFolderDataSource::kTotalMessagesAtom = nullptr; +nsIAtom * nsMsgFolderDataSource::kTotalUnreadMessagesAtom = nullptr; +nsIAtom * nsMsgFolderDataSource::kFolderSizeAtom = nullptr; +nsIAtom * nsMsgFolderDataSource::kNameAtom = nullptr; +nsIAtom * nsMsgFolderDataSource::kSynchronizeAtom = nullptr; +nsIAtom * nsMsgFolderDataSource::kOpenAtom = nullptr; +nsIAtom * nsMsgFolderDataSource::kIsDeferredAtom = nullptr; +nsIAtom * nsMsgFolderDataSource::kIsSecureAtom = nullptr; +nsIAtom * nsMsgFolderDataSource::kCanFileMessagesAtom = nullptr; +nsIAtom * nsMsgFolderDataSource::kInVFEditSearchScopeAtom = nullptr; + +static const uint32_t kDisplayBlankCount = 0xFFFFFFFE; +static const uint32_t kDisplayQuestionCount = 0xFFFFFFFF; +static const int64_t kDisplayBlankCount64 = -2; +static const int64_t kDisplayQuestionCount64 = -1; + +nsMsgFolderDataSource::nsMsgFolderDataSource() +{ + // one-time initialization here + nsIRDFService* rdf = getRDFService(); + + if (gFolderResourceRefCnt++ == 0) { + nsCOMPtr sMessengerStringBundle; + + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_CHILD), &kNC_Child); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_FOLDER), &kNC_Folder); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_NAME), &kNC_Name); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_OPEN), &kNC_Open); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_FOLDERTREENAME), &kNC_FolderTreeName); + rdf->GetResource(NS_LITERAL_CSTRING("mailnewsunreadfolders:/"), &kNC_UnreadFolders); + rdf->GetResource(NS_LITERAL_CSTRING("mailnewsfavefolders:/"), &kNC_FavoriteFolders); + rdf->GetResource(NS_LITERAL_CSTRING("mailnewsrecentfolders:/"), &kNC_RecentFolders); + + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_FOLDERTREESIMPLENAME), &kNC_FolderTreeSimpleName); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_NAME_SORT), &kNC_NameSort); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_FOLDERTREENAME_SORT), &kNC_FolderTreeNameSort); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_SPECIALFOLDER), &kNC_SpecialFolder); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_SERVERTYPE), &kNC_ServerType); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_ISDEFERRED),&kNC_IsDeferred); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_CANCREATEFOLDERSONSERVER), &kNC_CanCreateFoldersOnServer); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_CANFILEMESSAGESONSERVER), &kNC_CanFileMessagesOnServer); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_ISSERVER), &kNC_IsServer); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_ISSECURE), &kNC_IsSecure); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_CANSUBSCRIBE), &kNC_CanSubscribe); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_SUPPORTSOFFLINE), &kNC_SupportsOffline); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_CANFILEMESSAGES), &kNC_CanFileMessages); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_CANCREATESUBFOLDERS), &kNC_CanCreateSubfolders); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_CANRENAME), &kNC_CanRename); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_CANCOMPACT), &kNC_CanCompact); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_TOTALMESSAGES), &kNC_TotalMessages); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_TOTALUNREADMESSAGES), &kNC_TotalUnreadMessages); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_FOLDERSIZE), &kNC_FolderSize); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_CHARSET), &kNC_Charset); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_BIFFSTATE), &kNC_BiffState); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_HASUNREADMESSAGES), &kNC_HasUnreadMessages); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_NEWMESSAGES), &kNC_NewMessages); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_SUBFOLDERSHAVEUNREADMESSAGES), &kNC_SubfoldersHaveUnreadMessages); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_NOSELECT), &kNC_NoSelect); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_VIRTUALFOLDER), &kNC_VirtualFolder); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_INVFEDITSEARCHSCOPE), &kNC_InVFEditSearchScope); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_IMAPSHARED), &kNC_ImapShared); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_SYNCHRONIZE), &kNC_Synchronize); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_SYNCDISABLED), &kNC_SyncDisabled); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_CANSEARCHMESSAGES), &kNC_CanSearchMessages); + + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_DELETE), &kNC_Delete); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_REALLY_DELETE), &kNC_ReallyDelete); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_NEWFOLDER), &kNC_NewFolder); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_GETNEWMESSAGES), &kNC_GetNewMessages); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_COPY), &kNC_Copy); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_MOVE), &kNC_Move); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_COPYFOLDER), &kNC_CopyFolder); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_MOVEFOLDER), &kNC_MoveFolder); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_MARKALLMESSAGESREAD), + &kNC_MarkAllMessagesRead); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_COMPACT), &kNC_Compact); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_COMPACTALL), &kNC_CompactAll); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_RENAME), &kNC_Rename); + rdf->GetResource(NS_LITERAL_CSTRING(NC_RDF_EMPTYTRASH), &kNC_EmptyTrash); + + kTotalMessagesAtom = MsgNewAtom("TotalMessages").take(); + kTotalUnreadMessagesAtom = MsgNewAtom("TotalUnreadMessages").take(); + kFolderSizeAtom = MsgNewAtom("FolderSize").take(); + kBiffStateAtom = MsgNewAtom("BiffState").take(); + kSortOrderAtom = MsgNewAtom("SortOrder").take(); + kNewMessagesAtom = MsgNewAtom("NewMessages").take(); + kNameAtom = MsgNewAtom("Name").take(); + kSynchronizeAtom = MsgNewAtom("Synchronize").take(); + kOpenAtom = MsgNewAtom("open").take(); + kIsDeferredAtom = MsgNewAtom("isDeferred").take(); + kIsSecureAtom = MsgNewAtom("isSecure").take(); + kCanFileMessagesAtom = MsgNewAtom("canFileMessages").take(); + kInVFEditSearchScopeAtom = MsgNewAtom("inVFEditSearchScope").take(); + } + + CreateLiterals(rdf); + CreateArcsOutEnumerator(); +} + +nsMsgFolderDataSource::~nsMsgFolderDataSource (void) +{ + if (--gFolderResourceRefCnt == 0) + { + nsrefcnt refcnt; + NS_RELEASE2(kNC_Child, refcnt); + NS_RELEASE2(kNC_Folder, refcnt); + NS_RELEASE2(kNC_Name, refcnt); + NS_RELEASE2(kNC_Open, refcnt); + NS_RELEASE2(kNC_FolderTreeName, refcnt); + NS_RELEASE2(kNC_FolderTreeSimpleName, refcnt); + NS_RELEASE2(kNC_NameSort, refcnt); + NS_RELEASE2(kNC_FolderTreeNameSort, refcnt); + NS_RELEASE2(kNC_SpecialFolder, refcnt); + NS_RELEASE2(kNC_ServerType, refcnt); + NS_RELEASE2(kNC_IsDeferred, refcnt); + NS_RELEASE2(kNC_CanCreateFoldersOnServer, refcnt); + NS_RELEASE2(kNC_CanFileMessagesOnServer, refcnt); + NS_RELEASE2(kNC_IsServer, refcnt); + NS_RELEASE2(kNC_IsSecure, refcnt); + NS_RELEASE2(kNC_CanSubscribe, refcnt); + NS_RELEASE2(kNC_SupportsOffline, refcnt); + NS_RELEASE2(kNC_CanFileMessages, refcnt); + NS_RELEASE2(kNC_CanCreateSubfolders, refcnt); + NS_RELEASE2(kNC_CanRename, refcnt); + NS_RELEASE2(kNC_CanCompact, refcnt); + NS_RELEASE2(kNC_TotalMessages, refcnt); + NS_RELEASE2(kNC_TotalUnreadMessages, refcnt); + NS_RELEASE2(kNC_FolderSize, refcnt); + NS_RELEASE2(kNC_Charset, refcnt); + NS_RELEASE2(kNC_BiffState, refcnt); + NS_RELEASE2(kNC_HasUnreadMessages, refcnt); + NS_RELEASE2(kNC_NewMessages, refcnt); + NS_RELEASE2(kNC_SubfoldersHaveUnreadMessages, refcnt); + NS_RELEASE2(kNC_NoSelect, refcnt); + NS_RELEASE2(kNC_VirtualFolder, refcnt); + NS_RELEASE2(kNC_InVFEditSearchScope, refcnt); + NS_RELEASE2(kNC_ImapShared, refcnt); + NS_RELEASE2(kNC_Synchronize, refcnt); + NS_RELEASE2(kNC_SyncDisabled, refcnt); + NS_RELEASE2(kNC_CanSearchMessages, refcnt); + + NS_RELEASE2(kNC_Delete, refcnt); + NS_RELEASE2(kNC_ReallyDelete, refcnt); + NS_RELEASE2(kNC_NewFolder, refcnt); + NS_RELEASE2(kNC_GetNewMessages, refcnt); + NS_RELEASE2(kNC_Copy, refcnt); + NS_RELEASE2(kNC_Move, refcnt); + NS_RELEASE2(kNC_CopyFolder, refcnt); + NS_RELEASE2(kNC_MoveFolder, refcnt); + NS_RELEASE2(kNC_MarkAllMessagesRead, refcnt); + NS_RELEASE2(kNC_Compact, refcnt); + NS_RELEASE2(kNC_CompactAll, refcnt); + NS_RELEASE2(kNC_Rename, refcnt); + NS_RELEASE2(kNC_EmptyTrash, refcnt); + NS_RELEASE2(kNC_UnreadFolders, refcnt); + NS_RELEASE2(kNC_FavoriteFolders, refcnt); + NS_RELEASE2(kNC_RecentFolders, refcnt); + + NS_RELEASE(kTotalMessagesAtom); + NS_RELEASE(kTotalUnreadMessagesAtom); + NS_RELEASE(kFolderSizeAtom); + NS_RELEASE(kBiffStateAtom); + NS_RELEASE(kSortOrderAtom); + NS_RELEASE(kNewMessagesAtom); + NS_RELEASE(kNameAtom); + NS_RELEASE(kSynchronizeAtom); + NS_RELEASE(kOpenAtom); + NS_RELEASE(kIsDeferredAtom); + NS_RELEASE(kIsSecureAtom); + NS_RELEASE(kCanFileMessagesAtom); + NS_RELEASE(kInVFEditSearchScopeAtom); + } +} + +nsresult nsMsgFolderDataSource::CreateLiterals(nsIRDFService *rdf) +{ + createNode(u"true", + getter_AddRefs(kTrueLiteral), rdf); + createNode(u"false", + getter_AddRefs(kFalseLiteral), rdf); + + return NS_OK; +} + +nsresult nsMsgFolderDataSource::Init() +{ + nsresult rv; + + rv = nsMsgRDFDataSource::Init(); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr mailSession = + do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv); + + if(NS_SUCCEEDED(rv)) + mailSession->AddFolderListener(this, + nsIFolderListener::added | + nsIFolderListener::removed | + nsIFolderListener::intPropertyChanged | + nsIFolderListener::boolPropertyChanged | + nsIFolderListener::unicharPropertyChanged); + + return NS_OK; +} + +void nsMsgFolderDataSource::Cleanup() +{ + nsresult rv; + if (!m_shuttingDown) + { + nsCOMPtr mailSession = + do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv); + + if(NS_SUCCEEDED(rv)) + mailSession->RemoveFolderListener(this); + } + + nsMsgRDFDataSource::Cleanup(); +} + +nsresult nsMsgFolderDataSource::CreateArcsOutEnumerator() +{ + nsresult rv; + + rv = getFolderArcLabelsOut(kFolderArcsOutArray); + if(NS_FAILED(rv)) return rv; + + return rv; +} + +NS_IMPL_ADDREF_INHERITED(nsMsgFolderDataSource, nsMsgRDFDataSource) +NS_IMPL_RELEASE_INHERITED(nsMsgFolderDataSource, nsMsgRDFDataSource) + +NS_IMPL_QUERY_INTERFACE_INHERITED(nsMsgFolderDataSource, nsMsgRDFDataSource, nsIFolderListener) + + // nsIRDFDataSource methods +NS_IMETHODIMP nsMsgFolderDataSource::GetURI(char* *uri) +{ + if ((*uri = strdup("rdf:mailnewsfolders")) == nullptr) + return NS_ERROR_OUT_OF_MEMORY; + else + return NS_OK; +} + +NS_IMETHODIMP nsMsgFolderDataSource::GetSource(nsIRDFResource* property, + nsIRDFNode* target, + bool tv, + nsIRDFResource** source /* out */) +{ + NS_ASSERTION(false, "not implemented"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsMsgFolderDataSource::GetTarget(nsIRDFResource* source, + nsIRDFResource* property, + bool tv, + nsIRDFNode** target) +{ + nsresult rv = NS_RDF_NO_VALUE; + + // we only have positive assertions in the mail data source. + if (! tv) + return NS_RDF_NO_VALUE; + + nsCOMPtr folder(do_QueryInterface(source)); + if (folder) + rv = createFolderNode(folder, property, target); + else + return NS_RDF_NO_VALUE; + return rv; +} + + +NS_IMETHODIMP nsMsgFolderDataSource::GetSources(nsIRDFResource* property, + nsIRDFNode* target, + bool tv, + nsISimpleEnumerator** sources) +{ + return NS_RDF_NO_VALUE; +} + +NS_IMETHODIMP nsMsgFolderDataSource::GetTargets(nsIRDFResource* source, + nsIRDFResource* property, + bool tv, + nsISimpleEnumerator** targets) +{ + nsresult rv = NS_RDF_NO_VALUE; + if(!targets) + return NS_ERROR_NULL_POINTER; + + *targets = nullptr; + + nsCOMPtr folder(do_QueryInterface(source, &rv)); + if (NS_SUCCEEDED(rv)) + { + if (kNC_Child == property) + { + rv = folder->GetSubFolders(targets); + } + else if ((kNC_Name == property) || + (kNC_Open == property) || + (kNC_FolderTreeName == property) || + (kNC_FolderTreeSimpleName == property) || + (kNC_SpecialFolder == property) || + (kNC_IsServer == property) || + (kNC_IsSecure == property) || + (kNC_CanSubscribe == property) || + (kNC_SupportsOffline == property) || + (kNC_CanFileMessages == property) || + (kNC_CanCreateSubfolders == property) || + (kNC_CanRename == property) || + (kNC_CanCompact == property) || + (kNC_ServerType == property) || + (kNC_IsDeferred == property) || + (kNC_CanCreateFoldersOnServer == property) || + (kNC_CanFileMessagesOnServer == property) || + (kNC_NoSelect == property) || + (kNC_VirtualFolder == property) || + (kNC_InVFEditSearchScope == property) || + (kNC_ImapShared == property) || + (kNC_Synchronize == property) || + (kNC_SyncDisabled == property) || + (kNC_CanSearchMessages == property)) + { + return NS_NewSingletonEnumerator(targets, property); + } + } + if(!*targets) + { + //create empty cursor + rv = NS_NewEmptyEnumerator(targets); + } + + return rv; +} + +NS_IMETHODIMP nsMsgFolderDataSource::Assert(nsIRDFResource* source, + nsIRDFResource* property, + nsIRDFNode* target, + bool tv) +{ + nsresult rv; + nsCOMPtr folder(do_QueryInterface(source, &rv)); + //We don't handle tv = false at the moment. + if(NS_SUCCEEDED(rv) && tv) + return DoFolderAssert(folder, property, target); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP nsMsgFolderDataSource::Unassert(nsIRDFResource* source, + nsIRDFResource* property, + nsIRDFNode* target) +{ + nsresult rv; + nsCOMPtr folder(do_QueryInterface(source, &rv)); + NS_ENSURE_SUCCESS(rv,rv); + return DoFolderUnassert(folder, property, target); +} + + +NS_IMETHODIMP nsMsgFolderDataSource::HasAssertion(nsIRDFResource* source, + nsIRDFResource* property, + nsIRDFNode* target, + bool tv, + bool* hasAssertion) +{ + nsresult rv; + nsCOMPtr folder(do_QueryInterface(source, &rv)); + if(NS_SUCCEEDED(rv)) + return DoFolderHasAssertion(folder, property, target, tv, hasAssertion); + else + *hasAssertion = false; + return NS_OK; +} + + +NS_IMETHODIMP +nsMsgFolderDataSource::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result) +{ + nsresult rv; + nsCOMPtr folder(do_QueryInterface(aSource, &rv)); + if (NS_SUCCEEDED(rv)) + { + *result = (aArc == kNC_Name || + aArc == kNC_Open || + aArc == kNC_FolderTreeName || + aArc == kNC_FolderTreeSimpleName || + aArc == kNC_SpecialFolder || + aArc == kNC_ServerType || + aArc == kNC_IsDeferred || + aArc == kNC_CanCreateFoldersOnServer || + aArc == kNC_CanFileMessagesOnServer || + aArc == kNC_IsServer || + aArc == kNC_IsSecure || + aArc == kNC_CanSubscribe || + aArc == kNC_SupportsOffline || + aArc == kNC_CanFileMessages || + aArc == kNC_CanCreateSubfolders || + aArc == kNC_CanRename || + aArc == kNC_CanCompact || + aArc == kNC_TotalMessages || + aArc == kNC_TotalUnreadMessages || + aArc == kNC_FolderSize || + aArc == kNC_Charset || + aArc == kNC_BiffState || + aArc == kNC_Child || + aArc == kNC_NoSelect || + aArc == kNC_VirtualFolder || + aArc == kNC_InVFEditSearchScope || + aArc == kNC_ImapShared || + aArc == kNC_Synchronize || + aArc == kNC_SyncDisabled || + aArc == kNC_CanSearchMessages); + } + else + { + *result = false; + } + return NS_OK; +} + +NS_IMETHODIMP nsMsgFolderDataSource::ArcLabelsIn(nsIRDFNode* node, + nsISimpleEnumerator** labels) +{ + return nsMsgRDFDataSource::ArcLabelsIn(node, labels); +} + +NS_IMETHODIMP nsMsgFolderDataSource::ArcLabelsOut(nsIRDFResource* source, + nsISimpleEnumerator** labels) +{ + nsresult rv = NS_RDF_NO_VALUE; + + nsCOMPtr folder(do_QueryInterface(source, &rv)); + if (NS_SUCCEEDED(rv)) + { + rv = NS_NewArrayEnumerator(labels, kFolderArcsOutArray); + } + else + { + rv = NS_NewEmptyEnumerator(labels); + } + + return rv; +} + +nsresult +nsMsgFolderDataSource::getFolderArcLabelsOut(nsCOMArray &aArcs) +{ + aArcs.AppendObject(kNC_Name); + aArcs.AppendObject(kNC_Open); + aArcs.AppendObject(kNC_FolderTreeName); + aArcs.AppendObject(kNC_FolderTreeSimpleName); + aArcs.AppendObject(kNC_SpecialFolder); + aArcs.AppendObject(kNC_ServerType); + aArcs.AppendObject(kNC_IsDeferred); + aArcs.AppendObject(kNC_CanCreateFoldersOnServer); + aArcs.AppendObject(kNC_CanFileMessagesOnServer); + aArcs.AppendObject(kNC_IsServer); + aArcs.AppendObject(kNC_IsSecure); + aArcs.AppendObject(kNC_CanSubscribe); + aArcs.AppendObject(kNC_SupportsOffline); + aArcs.AppendObject(kNC_CanFileMessages); + aArcs.AppendObject(kNC_CanCreateSubfolders); + aArcs.AppendObject(kNC_CanRename); + aArcs.AppendObject(kNC_CanCompact); + aArcs.AppendObject(kNC_TotalMessages); + aArcs.AppendObject(kNC_TotalUnreadMessages); + aArcs.AppendObject(kNC_FolderSize); + aArcs.AppendObject(kNC_Charset); + aArcs.AppendObject(kNC_BiffState); + aArcs.AppendObject(kNC_Child); + aArcs.AppendObject(kNC_NoSelect); + aArcs.AppendObject(kNC_VirtualFolder); + aArcs.AppendObject(kNC_InVFEditSearchScope); + aArcs.AppendObject(kNC_ImapShared); + aArcs.AppendObject(kNC_Synchronize); + aArcs.AppendObject(kNC_SyncDisabled); + aArcs.AppendObject(kNC_CanSearchMessages); + + return NS_OK; +} + +NS_IMETHODIMP +nsMsgFolderDataSource::GetAllResources(nsISimpleEnumerator** aCursor) +{ + NS_NOTYETIMPLEMENTED("sorry!"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsMsgFolderDataSource::GetAllCmds(nsIRDFResource* source, + nsISimpleEnumerator/**/** commands) +{ + NS_NOTYETIMPLEMENTED("no one actually uses me"); + nsresult rv; + + nsCOMPtr folder(do_QueryInterface(source, &rv)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr cmds = + do_CreateInstance(NS_ARRAY_CONTRACTID); + NS_ENSURE_STATE(cmds); + + cmds->AppendElement(kNC_Delete, false); + cmds->AppendElement(kNC_ReallyDelete, false); + cmds->AppendElement(kNC_NewFolder, false); + cmds->AppendElement(kNC_GetNewMessages, false); + cmds->AppendElement(kNC_Copy, false); + cmds->AppendElement(kNC_Move, false); + cmds->AppendElement(kNC_CopyFolder, false); + cmds->AppendElement(kNC_MoveFolder, false); + cmds->AppendElement(kNC_MarkAllMessagesRead, false); + cmds->AppendElement(kNC_Compact, false); + cmds->AppendElement(kNC_CompactAll, false); + cmds->AppendElement(kNC_Rename, false); + cmds->AppendElement(kNC_EmptyTrash, false); + + return cmds->Enumerate(commands); +} + +NS_IMETHODIMP +nsMsgFolderDataSource::IsCommandEnabled(nsISupports/*nsISupportsArray*/* aSources, + nsIRDFResource* aCommand, + nsISupports/*nsISupportsArray*/* aArguments, + bool* aResult) +{ + nsresult rv; + nsCOMPtr folder; + + nsCOMPtr sources = do_QueryInterface(aSources); + NS_ENSURE_STATE(sources); + + uint32_t cnt; + rv = sources->Count(&cnt); + if (NS_FAILED(rv)) return rv; + for (uint32_t i = 0; i < cnt; i++) + { + folder = do_QueryElementAt(sources, i, &rv); + if (NS_SUCCEEDED(rv)) + { + // we don't care about the arguments -- folder commands are always enabled + if (!((aCommand == kNC_Delete) || + (aCommand == kNC_ReallyDelete) || + (aCommand == kNC_NewFolder) || + (aCommand == kNC_Copy) || + (aCommand == kNC_Move) || + (aCommand == kNC_CopyFolder) || + (aCommand == kNC_MoveFolder) || + (aCommand == kNC_GetNewMessages) || + (aCommand == kNC_MarkAllMessagesRead) || + (aCommand == kNC_Compact) || + (aCommand == kNC_CompactAll) || + (aCommand == kNC_Rename) || + (aCommand == kNC_EmptyTrash))) + { + *aResult = false; + return NS_OK; + } + } + } + *aResult = true; + return NS_OK; // succeeded for all sources +} + +NS_IMETHODIMP +nsMsgFolderDataSource::DoCommand(nsISupports/*nsISupportsArray*/* aSources, + nsIRDFResource* aCommand, + nsISupports/*nsISupportsArray*/* aArguments) +{ + nsresult rv = NS_OK; + nsCOMPtr supports; + nsCOMPtr window; + + nsCOMPtr sources = do_QueryInterface(aSources); + NS_ENSURE_STATE(sources); + nsCOMPtr arguments = do_QueryInterface(aArguments); + + // callers can pass in the msgWindow as the last element of the arguments + // array. If they do, we'll use that as the msg window for progress, etc. + if (arguments) + { + uint32_t numArgs; + arguments->Count(&numArgs); + if (numArgs > 1) + window = do_QueryElementAt(arguments, numArgs - 1); + } + if (!window) + window = mWindow; + + // XXX need to handle batching of command applied to all sources + + uint32_t cnt = 0; + uint32_t i = 0; + + rv = sources->Count(&cnt); + if (NS_FAILED(rv)) return rv; + + for ( ; i < cnt; i++) + { + nsCOMPtr folder = do_QueryElementAt(sources, i, &rv); + if (NS_SUCCEEDED(rv)) + { + if (aCommand == kNC_Delete) + { + rv = DoDeleteFromFolder(folder, arguments, window, false); + } + if (aCommand == kNC_ReallyDelete) + { + rv = DoDeleteFromFolder(folder, arguments, window, true); + } + else if (aCommand == kNC_NewFolder) + { + rv = DoNewFolder(folder, arguments, window); + } + else if (aCommand == kNC_GetNewMessages) + { + nsCOMPtr server = do_QueryElementAt(arguments, i, &rv); + NS_ENSURE_SUCCESS(rv, rv); + rv = server->GetNewMessages(folder, window, nullptr); + } + else if (aCommand == kNC_Copy) + { + rv = DoCopyToFolder(folder, arguments, window, false); + } + else if (aCommand == kNC_Move) + { + rv = DoCopyToFolder(folder, arguments, window, true); + } + else if (aCommand == kNC_CopyFolder) + { + rv = DoFolderCopyToFolder(folder, arguments, window, false); + } + else if (aCommand == kNC_MoveFolder) + { + rv = DoFolderCopyToFolder(folder, arguments, window, true); + } + else if (aCommand == kNC_MarkAllMessagesRead) + { + rv = folder->MarkAllMessagesRead(window); + } + else if (aCommand == kNC_Compact) + { + rv = folder->Compact(nullptr, window); + } + else if (aCommand == kNC_CompactAll) + { + // this will also compact offline stores for IMAP + rv = folder->CompactAll(nullptr, window, true); + } + else if (aCommand == kNC_EmptyTrash) + { + rv = folder->EmptyTrash(window, nullptr); + } + else if (aCommand == kNC_Rename) + { + nsCOMPtr literal = do_QueryElementAt(arguments, 0, &rv); + if(NS_SUCCEEDED(rv)) + { + nsString name; + literal->GetValue(getter_Copies(name)); + rv = folder->Rename(name, window); + } + } + } + else + { + rv = NS_ERROR_NOT_IMPLEMENTED; + } + } + //for the moment return NS_OK, because failure stops entire DoCommand process. + return rv; + //return NS_OK; +} + +NS_IMETHODIMP nsMsgFolderDataSource::OnItemAdded(nsIMsgFolder *parentItem, nsISupports *item) +{ + return OnItemAddedOrRemoved(parentItem, item, true); +} + +NS_IMETHODIMP nsMsgFolderDataSource::OnItemRemoved(nsIMsgFolder *parentItem, nsISupports *item) +{ + return OnItemAddedOrRemoved(parentItem, item, false); +} + +nsresult nsMsgFolderDataSource::OnItemAddedOrRemoved(nsIMsgFolder *parentItem, nsISupports *item, bool added) +{ + nsCOMPtr itemNode(do_QueryInterface(item)); + if (itemNode) + { + nsCOMPtr parentResource(do_QueryInterface(parentItem)); + if (parentResource) // RDF is not happy about a null parent resource. + NotifyObservers(parentResource, kNC_Child, itemNode, nullptr, added, false); + } + return NS_OK; +} + +NS_IMETHODIMP +nsMsgFolderDataSource::OnItemPropertyChanged(nsIMsgFolder *resource, + nsIAtom *property, + const char *oldValue, + const char *newValue) + +{ + return NS_OK; +} + +NS_IMETHODIMP +nsMsgFolderDataSource::OnItemIntPropertyChanged(nsIMsgFolder *folder, + nsIAtom *property, + int64_t oldValue, + int64_t newValue) +{ + nsCOMPtr resource(do_QueryInterface(folder)); + if (kTotalMessagesAtom == property) + OnTotalMessagePropertyChanged(resource, oldValue, newValue); + else if (kTotalUnreadMessagesAtom == property) + OnUnreadMessagePropertyChanged(resource, oldValue, newValue); + else if (kFolderSizeAtom == property) + OnFolderSizePropertyChanged(resource, oldValue, newValue); + else if (kSortOrderAtom == property) + OnFolderSortOrderPropertyChanged(resource, oldValue, newValue); + else if (kBiffStateAtom == property) { + // be careful about skipping if oldValue == newValue + // see the comment in nsMsgFolder::SetBiffState() about filters + + nsCOMPtr biffNode; + nsresult rv = createBiffStateNodeFromFlag(newValue, getter_AddRefs(biffNode)); + NS_ENSURE_SUCCESS(rv,rv); + + NotifyPropertyChanged(resource, kNC_BiffState, biffNode); + } + return NS_OK; +} + +NS_IMETHODIMP +nsMsgFolderDataSource::OnItemUnicharPropertyChanged(nsIMsgFolder *folder, + nsIAtom *property, + const char16_t *oldValue, + const char16_t *newValue) +{ + nsCOMPtr resource(do_QueryInterface(folder)); + if (kNameAtom == property) + { + int32_t numUnread; + folder->GetNumUnread(false, &numUnread); + NotifyFolderTreeNameChanged(folder, resource, numUnread); + NotifyFolderTreeSimpleNameChanged(folder, resource); + NotifyFolderNameChanged(folder, resource); + } + return NS_OK; +} + +NS_IMETHODIMP +nsMsgFolderDataSource::OnItemBoolPropertyChanged(nsIMsgFolder *folder, + nsIAtom *property, + bool oldValue, + bool newValue) +{ + nsCOMPtr resource(do_QueryInterface(folder)); + if (newValue != oldValue) { + nsIRDFNode* literalNode = newValue?kTrueLiteral:kFalseLiteral; + nsIRDFNode* oldLiteralNode = oldValue?kTrueLiteral:kFalseLiteral; + if (kNewMessagesAtom == property) + NotifyPropertyChanged(resource, kNC_NewMessages, literalNode); + else if (kSynchronizeAtom == property) + NotifyPropertyChanged(resource, kNC_Synchronize, literalNode); + else if (kOpenAtom == property) + NotifyPropertyChanged(resource, kNC_Open, literalNode); + else if (kIsDeferredAtom == property) + NotifyPropertyChanged(resource, kNC_IsDeferred, literalNode, oldLiteralNode); + else if (kIsSecureAtom == property) + NotifyPropertyChanged(resource, kNC_IsSecure, literalNode, oldLiteralNode); + else if (kCanFileMessagesAtom == property) + NotifyPropertyChanged(resource, kNC_CanFileMessages, literalNode, oldLiteralNode); + else if (kInVFEditSearchScopeAtom == property) + NotifyPropertyChanged(resource, kNC_InVFEditSearchScope, literalNode); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsMsgFolderDataSource::OnItemPropertyFlagChanged(nsIMsgDBHdr *item, + nsIAtom *property, + uint32_t oldFlag, + uint32_t newFlag) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsMsgFolderDataSource::OnItemEvent(nsIMsgFolder *aFolder, nsIAtom *aEvent) +{ + return NS_OK; +} + + +nsresult nsMsgFolderDataSource::createFolderNode(nsIMsgFolder* folder, + nsIRDFResource* property, + nsIRDFNode** target) +{ + nsresult rv = NS_RDF_NO_VALUE; + + if (kNC_NameSort == property) + rv = createFolderNameNode(folder, target, true); + else if(kNC_FolderTreeNameSort == property) + rv = createFolderNameNode(folder, target, true); + else if (kNC_Name == property) + rv = createFolderNameNode(folder, target, false); + else if(kNC_Open == property) + rv = createFolderOpenNode(folder, target); + else if (kNC_FolderTreeName == property) + rv = createFolderTreeNameNode(folder, target); + else if (kNC_FolderTreeSimpleName == property) + rv = createFolderTreeSimpleNameNode(folder, target); + else if (kNC_SpecialFolder == property) + rv = createFolderSpecialNode(folder,target); + else if (kNC_ServerType == property) + rv = createFolderServerTypeNode(folder, target); + else if (kNC_IsDeferred == property) + rv = createServerIsDeferredNode(folder, target); + else if (kNC_CanCreateFoldersOnServer == property) + rv = createFolderCanCreateFoldersOnServerNode(folder, target); + else if (kNC_CanFileMessagesOnServer == property) + rv = createFolderCanFileMessagesOnServerNode(folder, target); + else if (kNC_IsServer == property) + rv = createFolderIsServerNode(folder, target); + else if (kNC_IsSecure == property) + rv = createFolderIsSecureNode(folder, target); + else if (kNC_CanSubscribe == property) + rv = createFolderCanSubscribeNode(folder, target); + else if (kNC_SupportsOffline == property) + rv = createFolderSupportsOfflineNode(folder, target); + else if (kNC_CanFileMessages == property) + rv = createFolderCanFileMessagesNode(folder, target); + else if (kNC_CanCreateSubfolders == property) + rv = createFolderCanCreateSubfoldersNode(folder, target); + else if (kNC_CanRename == property) + rv = createFolderCanRenameNode(folder, target); + else if (kNC_CanCompact == property) + rv = createFolderCanCompactNode(folder, target); + else if (kNC_TotalMessages == property) + rv = createTotalMessagesNode(folder, target); + else if (kNC_TotalUnreadMessages == property) + rv = createUnreadMessagesNode(folder, target); + else if (kNC_FolderSize == property) + rv = createFolderSizeNode(folder, target); + else if (kNC_Charset == property) + rv = createCharsetNode(folder, target); + else if (kNC_BiffState == property) + rv = createBiffStateNodeFromFolder(folder, target); + else if (kNC_HasUnreadMessages == property) + rv = createHasUnreadMessagesNode(folder, false, target); + else if (kNC_NewMessages == property) + rv = createNewMessagesNode(folder, target); + else if (kNC_SubfoldersHaveUnreadMessages == property) + rv = createHasUnreadMessagesNode(folder, true, target); + else if (kNC_Child == property) + rv = createFolderChildNode(folder, target); + else if (kNC_NoSelect == property) + rv = createFolderNoSelectNode(folder, target); + else if (kNC_VirtualFolder == property) + rv = createFolderVirtualNode(folder, target); + else if (kNC_InVFEditSearchScope == property) + rv = createInVFEditSearchScopeNode(folder, target); + else if (kNC_ImapShared == property) + rv = createFolderImapSharedNode(folder, target); + else if (kNC_Synchronize == property) + rv = createFolderSynchronizeNode(folder, target); + else if (kNC_SyncDisabled == property) + rv = createFolderSyncDisabledNode(folder, target); + else if (kNC_CanSearchMessages == property) + rv = createCanSearchMessages(folder, target); + return NS_FAILED(rv) ? NS_RDF_NO_VALUE : rv; +} + +nsresult +nsMsgFolderDataSource::createFolderNameNode(nsIMsgFolder *folder, + nsIRDFNode **target, bool sort) +{ + nsresult rv; + if (sort) + { + uint8_t *sortKey=nullptr; + uint32_t sortKeyLength; + rv = folder->GetSortKey(&sortKeyLength, &sortKey); + NS_ENSURE_SUCCESS(rv, rv); + createBlobNode(sortKey, sortKeyLength, target, getRDFService()); + PR_Free(sortKey); + } + else + { + nsString name; + rv = folder->GetName(name); + if (NS_FAILED(rv)) + return rv; + createNode(name.get(), target, getRDFService()); + } + + return NS_OK; +} + +nsresult nsMsgFolderDataSource::GetFolderDisplayName(nsIMsgFolder *folder, nsString& folderName) +{ + return folder->GetAbbreviatedName(folderName); +} + +nsresult +nsMsgFolderDataSource::createFolderTreeNameNode(nsIMsgFolder *folder, + nsIRDFNode **target) +{ + nsString name; + nsresult rv = GetFolderDisplayName(folder, name); + if (NS_FAILED(rv)) return rv; + nsAutoString nameString(name); + int32_t unreadMessages; + + rv = folder->GetNumUnread(false, &unreadMessages); + if(NS_SUCCEEDED(rv)) + CreateUnreadMessagesNameString(unreadMessages, nameString); + + createNode(nameString.get(), target, getRDFService()); + return NS_OK; +} + +nsresult nsMsgFolderDataSource::createFolderTreeSimpleNameNode(nsIMsgFolder * folder, nsIRDFNode **target) +{ + nsString name; + nsresult rv = GetFolderDisplayName(folder, name); + if (NS_FAILED(rv)) return rv; + + createNode(name.get(), target, getRDFService()); + return NS_OK; +} + +nsresult nsMsgFolderDataSource::CreateUnreadMessagesNameString(int32_t unreadMessages, nsAutoString &nameString) +{ + //Only do this if unread messages are positive + if(unreadMessages > 0) + { + nameString.Append(NS_LITERAL_STRING(" (")); + nameString.AppendInt(unreadMessages); + nameString.Append(u')'); + } + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createFolderSpecialNode(nsIMsgFolder *folder, + nsIRDFNode **target) +{ + uint32_t flags; + nsresult rv = folder->GetFlags(&flags); + if(NS_FAILED(rv)) + return rv; + + nsAutoString specialFolderString; + if (flags & nsMsgFolderFlags::Inbox) + specialFolderString.AssignLiteral("Inbox"); + else if (flags & nsMsgFolderFlags::Trash) + specialFolderString.AssignLiteral("Trash"); + else if (flags & nsMsgFolderFlags::Queue) + specialFolderString.AssignLiteral("Outbox"); + else if (flags & nsMsgFolderFlags::SentMail) + specialFolderString.AssignLiteral("Sent"); + else if (flags & nsMsgFolderFlags::Drafts) + specialFolderString.AssignLiteral("Drafts"); + else if (flags & nsMsgFolderFlags::Templates) + specialFolderString.AssignLiteral("Templates"); + else if (flags & nsMsgFolderFlags::Junk) + specialFolderString.AssignLiteral("Junk"); + else if (flags & nsMsgFolderFlags::Virtual) + specialFolderString.AssignLiteral("Virtual"); + else if (flags & nsMsgFolderFlags::Archive) + specialFolderString.AssignLiteral("Archives"); + else { + // XXX why do this at all? or just "" + specialFolderString.AssignLiteral("none"); + } + + createNode(specialFolderString.get(), target, getRDFService()); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createFolderServerTypeNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + nsresult rv; + nsCOMPtr server; + rv = folder->GetServer(getter_AddRefs(server)); + if (NS_FAILED(rv) || !server) return NS_ERROR_FAILURE; + + nsCString serverType; + rv = server->GetType(serverType); + if (NS_FAILED(rv)) return rv; + + createNode(NS_ConvertASCIItoUTF16(serverType).get(), target, getRDFService()); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createServerIsDeferredNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + bool isDeferred = false; + nsCOMPtr incomingServer; + folder->GetServer(getter_AddRefs(incomingServer)); + if (incomingServer) + { + nsCOMPtr pop3Server = do_QueryInterface(incomingServer); + if (pop3Server) + { + nsCString deferredToServer; + pop3Server->GetDeferredToAccount(deferredToServer); + isDeferred = !deferredToServer.IsEmpty(); + } + } + *target = (isDeferred) ? kTrueLiteral : kFalseLiteral; + NS_IF_ADDREF(*target); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createFolderCanCreateFoldersOnServerNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + nsresult rv; + + nsCOMPtr server; + rv = folder->GetServer(getter_AddRefs(server)); + if (NS_FAILED(rv) || !server) return NS_ERROR_FAILURE; + + bool canCreateFoldersOnServer; + rv = server->GetCanCreateFoldersOnServer(&canCreateFoldersOnServer); + if (NS_FAILED(rv)) return rv; + + if (canCreateFoldersOnServer) + *target = kTrueLiteral; + else + *target = kFalseLiteral; + NS_IF_ADDREF(*target); + + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createFolderCanFileMessagesOnServerNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + nsresult rv; + + nsCOMPtr server; + rv = folder->GetServer(getter_AddRefs(server)); + if (NS_FAILED(rv) || !server) return NS_ERROR_FAILURE; + + bool canFileMessagesOnServer; + rv = server->GetCanFileMessagesOnServer(&canFileMessagesOnServer); + if (NS_FAILED(rv)) return rv; + + *target = (canFileMessagesOnServer) ? kTrueLiteral : kFalseLiteral; + NS_IF_ADDREF(*target); + + return NS_OK; +} + + +nsresult +nsMsgFolderDataSource::createFolderIsServerNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + nsresult rv; + bool isServer; + rv = folder->GetIsServer(&isServer); + if (NS_FAILED(rv)) return rv; + + *target = nullptr; + + if (isServer) + *target = kTrueLiteral; + else + *target = kFalseLiteral; + NS_IF_ADDREF(*target); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createFolderNoSelectNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + nsresult rv; + bool noSelect; + rv = folder->GetNoSelect(&noSelect); + if (NS_FAILED(rv)) return rv; + + *target = (noSelect) ? kTrueLiteral : kFalseLiteral; + NS_IF_ADDREF(*target); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createInVFEditSearchScopeNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + bool inVFEditSearchScope = false; + folder->GetInVFEditSearchScope(&inVFEditSearchScope); + + *target = inVFEditSearchScope ? kTrueLiteral : kFalseLiteral; + NS_IF_ADDREF(*target); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createFolderVirtualNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + uint32_t folderFlags; + folder->GetFlags(&folderFlags); + + *target = (folderFlags & nsMsgFolderFlags::Virtual) ? kTrueLiteral : kFalseLiteral; + NS_IF_ADDREF(*target); + return NS_OK; +} + + +nsresult +nsMsgFolderDataSource::createFolderImapSharedNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + nsresult rv; + bool imapShared; + rv = folder->GetImapShared(&imapShared); + if (NS_FAILED(rv)) return rv; + + *target = (imapShared) ? kTrueLiteral : kFalseLiteral; + NS_IF_ADDREF(*target); + return NS_OK; +} + + +nsresult +nsMsgFolderDataSource::createFolderSynchronizeNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + nsresult rv; + bool sync; + rv = folder->GetFlag(nsMsgFolderFlags::Offline, &sync); + if (NS_FAILED(rv)) return rv; + + *target = nullptr; + + *target = (sync) ? kTrueLiteral : kFalseLiteral; + NS_IF_ADDREF(*target); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createFolderSyncDisabledNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + + nsresult rv; + bool isServer; + nsCOMPtr server; + + rv = folder->GetIsServer(&isServer); + if (NS_FAILED(rv)) return rv; + + rv = folder->GetServer(getter_AddRefs(server)); + if (NS_FAILED(rv) || !server) return NS_ERROR_FAILURE; + + nsCString serverType; + rv = server->GetType(serverType); + if (NS_FAILED(rv)) return rv; + + *target = isServer || MsgLowerCaseEqualsLiteral(serverType, "none") || MsgLowerCaseEqualsLiteral(serverType, "pop3") ? + kTrueLiteral : kFalseLiteral; + NS_IF_ADDREF(*target); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createCanSearchMessages(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + nsresult rv; + + nsCOMPtr server; + rv = folder->GetServer(getter_AddRefs(server)); + if (NS_FAILED(rv) || !server) return NS_ERROR_FAILURE; + + bool canSearchMessages; + rv = server->GetCanSearchMessages(&canSearchMessages); + if (NS_FAILED(rv)) return rv; + + *target = (canSearchMessages) ? kTrueLiteral : kFalseLiteral; + NS_IF_ADDREF(*target); + + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createFolderOpenNode(nsIMsgFolder *folder, nsIRDFNode **target) +{ + NS_ENSURE_ARG_POINTER(target); + + // call GetSubFolders() to ensure mFlags is set correctly + // from the folder cache on startup + nsCOMPtr subFolders; + nsresult rv = folder->GetSubFolders(getter_AddRefs(subFolders)); + if (NS_FAILED(rv)) + return NS_RDF_NO_VALUE; + + bool closed; + rv = folder->GetFlag(nsMsgFolderFlags::Elided, &closed); + if (NS_FAILED(rv)) + return rv; + + *target = (closed) ? kFalseLiteral : kTrueLiteral; + + NS_IF_ADDREF(*target); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createFolderIsSecureNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + nsresult rv; + bool isSecure = false; + + nsCOMPtr server; + rv = folder->GetServer(getter_AddRefs(server)); + + if (NS_SUCCEEDED(rv) && server) { + rv = server->GetIsSecure(&isSecure); + NS_ENSURE_SUCCESS(rv, rv); + } + + *target = (isSecure) ? kTrueLiteral : kFalseLiteral; + NS_IF_ADDREF(*target); + return NS_OK; +} + + +nsresult +nsMsgFolderDataSource::createFolderCanSubscribeNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + nsresult rv; + bool canSubscribe; + rv = folder->GetCanSubscribe(&canSubscribe); + if (NS_FAILED(rv)) return rv; + + *target = (canSubscribe) ? kTrueLiteral : kFalseLiteral; + NS_IF_ADDREF(*target); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createFolderSupportsOfflineNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + nsresult rv; + bool supportsOffline; + rv = folder->GetSupportsOffline(&supportsOffline); + NS_ENSURE_SUCCESS(rv,rv); + + *target = (supportsOffline) ? kTrueLiteral : kFalseLiteral; + NS_IF_ADDREF(*target); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createFolderCanFileMessagesNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + nsresult rv; + bool canFileMessages; + rv = folder->GetCanFileMessages(&canFileMessages); + if (NS_FAILED(rv)) return rv; + + *target = (canFileMessages) ? kTrueLiteral : kFalseLiteral; + NS_IF_ADDREF(*target); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createFolderCanCreateSubfoldersNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + nsresult rv; + bool canCreateSubfolders; + rv = folder->GetCanCreateSubfolders(&canCreateSubfolders); + if (NS_FAILED(rv)) return rv; + + *target = (canCreateSubfolders) ? kTrueLiteral : kFalseLiteral; + NS_IF_ADDREF(*target); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createFolderCanRenameNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + bool canRename; + nsresult rv = folder->GetCanRename(&canRename); + if (NS_FAILED(rv)) return rv; + + *target = (canRename) ? kTrueLiteral : kFalseLiteral; + NS_IF_ADDREF(*target); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createFolderCanCompactNode(nsIMsgFolder* folder, + nsIRDFNode **target) +{ + bool canCompact; + nsresult rv = folder->GetCanCompact(&canCompact); + if (NS_FAILED(rv)) return rv; + + *target = (canCompact) ? kTrueLiteral : kFalseLiteral; + NS_IF_ADDREF(*target); + return NS_OK; +} + + +nsresult +nsMsgFolderDataSource::createTotalMessagesNode(nsIMsgFolder *folder, + nsIRDFNode **target) +{ + + bool isServer; + nsresult rv = folder->GetIsServer(&isServer); + if (NS_FAILED(rv)) return rv; + + int32_t totalMessages; + if(isServer) + totalMessages = kDisplayBlankCount; + else + { + rv = folder->GetTotalMessages(false, &totalMessages); + if(NS_FAILED(rv)) return rv; + } + GetNumMessagesNode(totalMessages, target); + + return rv; +} + +nsresult +nsMsgFolderDataSource::createFolderSizeNode(nsIMsgFolder *folder, nsIRDFNode **target) +{ + bool isServer; + nsresult rv = folder->GetIsServer(&isServer); + NS_ENSURE_SUCCESS(rv, rv); + + int64_t folderSize; + if (isServer) { + folderSize = kDisplayBlankCount64; + } + else + { + // XXX todo, we are asserting here for news + // for offline news, we'd know the size on disk, right? Yes, bug 851275. + rv = folder->GetSizeOnDisk(&folderSize); + NS_ENSURE_SUCCESS(rv, rv); + } + + return GetFolderSizeNode(folderSize, target); +} + +nsresult +nsMsgFolderDataSource::createCharsetNode(nsIMsgFolder *folder, nsIRDFNode **target) +{ + nsCString charset; + nsresult rv = folder->GetCharset(charset); + if (NS_SUCCEEDED(rv)) + createNode(NS_ConvertASCIItoUTF16(charset).get(), target, getRDFService()); + else + createNode(EmptyString().get(), target, getRDFService()); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createBiffStateNodeFromFolder(nsIMsgFolder *folder, nsIRDFNode **target) +{ + uint32_t biffState; + nsresult rv = folder->GetBiffState(&biffState); + if(NS_FAILED(rv)) return rv; + + rv = createBiffStateNodeFromFlag(biffState, target); + NS_ENSURE_SUCCESS(rv,rv); + + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createBiffStateNodeFromFlag(uint32_t flag, nsIRDFNode **target) +{ + const char16_t *biffStateStr; + + switch (flag) { + case nsIMsgFolder::nsMsgBiffState_NewMail: + biffStateStr = u"NewMail"; + break; + case nsIMsgFolder::nsMsgBiffState_NoMail: + biffStateStr = u"NoMail"; + break; + default: + biffStateStr = u"UnknownMail"; + break; + } + + createNode(biffStateStr, target, getRDFService()); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createUnreadMessagesNode(nsIMsgFolder *folder, + nsIRDFNode **target) +{ + bool isServer; + nsresult rv = folder->GetIsServer(&isServer); + if (NS_FAILED(rv)) return rv; + + int32_t totalUnreadMessages; + if(isServer) + totalUnreadMessages = kDisplayBlankCount; + else + { + rv = folder->GetNumUnread(false, &totalUnreadMessages); + if(NS_FAILED(rv)) return rv; + } + GetNumMessagesNode(totalUnreadMessages, target); + + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createHasUnreadMessagesNode(nsIMsgFolder *folder, bool aIncludeSubfolders, nsIRDFNode **target) +{ + bool isServer; + nsresult rv = folder->GetIsServer(&isServer); + if (NS_FAILED(rv)) return rv; + + *target = kFalseLiteral; + + int32_t totalUnreadMessages; + if(!isServer) + { + rv = folder->GetNumUnread(aIncludeSubfolders, &totalUnreadMessages); + if(NS_FAILED(rv)) return rv; + // if we're including sub-folders, we're trying to find out if child folders + // have unread. If so, we subtract the unread msgs in the current folder. + if (aIncludeSubfolders) + { + int32_t numUnreadInFolder; + rv = folder->GetNumUnread(false, &numUnreadInFolder); + NS_ENSURE_SUCCESS(rv, rv); + // don't subtract if numUnread is negative (which means we don't know the unread count) + if (numUnreadInFolder > 0) + totalUnreadMessages -= numUnreadInFolder; + } + *target = (totalUnreadMessages > 0) ? kTrueLiteral : kFalseLiteral; + } + + NS_IF_ADDREF(*target); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::OnUnreadMessagePropertyChanged(nsIRDFResource *folderResource, int32_t oldValue, int32_t newValue) +{ + nsCOMPtr folder = do_QueryInterface(folderResource); + if(folder) + { + //First send a regular unread message changed notification + nsCOMPtr newNode; + + GetNumMessagesNode(newValue, getter_AddRefs(newNode)); + NotifyPropertyChanged(folderResource, kNC_TotalUnreadMessages, newNode); + + //Now see if hasUnreadMessages has changed + if(oldValue <=0 && newValue >0) + { + NotifyPropertyChanged(folderResource, kNC_HasUnreadMessages, kTrueLiteral); + NotifyAncestors(folder, kNC_SubfoldersHaveUnreadMessages, kTrueLiteral); + } + else if(oldValue > 0 && newValue <= 0) + { + NotifyPropertyChanged(folderResource, kNC_HasUnreadMessages, kFalseLiteral); + // this isn't quite right - parents could still have other children with + // unread messages. NotifyAncestors will have to figure that out... + NotifyAncestors(folder, kNC_SubfoldersHaveUnreadMessages, kFalseLiteral); + } + + //We will have to change the folderTreeName if the unread column is hidden + NotifyFolderTreeNameChanged(folder, folderResource, newValue); + } + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::NotifyFolderNameChanged(nsIMsgFolder* aFolder, nsIRDFResource *folderResource) +{ + nsString name; + nsresult rv = aFolder->GetName(name); + + if (NS_SUCCEEDED(rv)) { + nsCOMPtr newNameNode; + createNode(name.get(), getter_AddRefs(newNameNode), getRDFService()); + NotifyPropertyChanged(folderResource, kNC_Name, newNameNode); + } + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::NotifyFolderTreeSimpleNameChanged(nsIMsgFolder* aFolder, nsIRDFResource *folderResource) +{ + nsString abbreviatedName; + nsresult rv = GetFolderDisplayName(aFolder, abbreviatedName); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr newNameNode; + createNode(abbreviatedName.get(), getter_AddRefs(newNameNode), getRDFService()); + NotifyPropertyChanged(folderResource, kNC_FolderTreeSimpleName, newNameNode); + } + + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::NotifyFolderTreeNameChanged(nsIMsgFolder* aFolder, + nsIRDFResource* aFolderResource, + int32_t aUnreadMessages) +{ + nsString name; + nsresult rv = GetFolderDisplayName(aFolder, name); + if (NS_SUCCEEDED(rv)) { + nsAutoString newNameString(name); + CreateUnreadMessagesNameString(aUnreadMessages, newNameString); + nsCOMPtr newNameNode; + createNode(newNameString.get(), getter_AddRefs(newNameNode), getRDFService()); + NotifyPropertyChanged(aFolderResource, kNC_FolderTreeName, newNameNode); + } + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::NotifyAncestors(nsIMsgFolder *aFolder, nsIRDFResource *aPropertyResource, nsIRDFNode *aNode) +{ + bool isServer = false; + nsresult rv = aFolder->GetIsServer(&isServer); + NS_ENSURE_SUCCESS(rv,rv); + + if (isServer) + // done, stop + return NS_OK; + + nsCOMPtr parentMsgFolder; + rv = aFolder->GetParent(getter_AddRefs(parentMsgFolder)); + NS_ENSURE_SUCCESS(rv,rv); + if (!parentMsgFolder) + return NS_OK; + + rv = parentMsgFolder->GetIsServer(&isServer); + NS_ENSURE_SUCCESS(rv,rv); + + // don't need to notify servers either. + if (isServer) + // done, stop + return NS_OK; + + nsCOMPtr parentFolderResource = do_QueryInterface(parentMsgFolder,&rv); + NS_ENSURE_SUCCESS(rv,rv); + + // if we're setting the subFoldersHaveUnreadMessages property to false, check + // if the folder really doesn't have subfolders with unread messages. + if (aPropertyResource == kNC_SubfoldersHaveUnreadMessages && aNode == kFalseLiteral) + { + nsCOMPtr unreadMsgsNode; + createHasUnreadMessagesNode(parentMsgFolder, true, getter_AddRefs(unreadMsgsNode)); + aNode = unreadMsgsNode; + } + NotifyPropertyChanged(parentFolderResource, aPropertyResource, aNode); + + return NotifyAncestors(parentMsgFolder, aPropertyResource, aNode); +} + +// New Messages + +nsresult +nsMsgFolderDataSource::createNewMessagesNode(nsIMsgFolder *folder, nsIRDFNode **target) +{ + + nsresult rv; + + bool isServer; + rv = folder->GetIsServer(&isServer); + if (NS_FAILED(rv)) return rv; + + *target = kFalseLiteral; + + //int32_t totalNewMessages; + bool isNewMessages; + if(!isServer) + { + rv = folder->GetHasNewMessages(&isNewMessages); + if(NS_FAILED(rv)) return rv; + *target = (isNewMessages) ? kTrueLiteral : kFalseLiteral; + } + NS_IF_ADDREF(*target); + return NS_OK; +} + +/** +nsresult +nsMsgFolderDataSource::OnUnreadMessagePropertyChanged(nsIMsgFolder *folder, int32_t oldValue, int32_t newValue) +{ + nsCOMPtr folderResource = do_QueryInterface(folder); + if(folderResource) + { + //First send a regular unread message changed notification + nsCOMPtr newNode; + + GetNumMessagesNode(newValue, getter_AddRefs(newNode)); + NotifyPropertyChanged(folderResource, kNC_TotalUnreadMessages, newNode); + + //Now see if hasUnreadMessages has changed + nsCOMPtr oldHasUnreadMessages; + nsCOMPtr newHasUnreadMessages; + if(oldValue <=0 && newValue >0) + { + oldHasUnreadMessages = kFalseLiteral; + newHasUnreadMessages = kTrueLiteral; + NotifyPropertyChanged(folderResource, kNC_HasUnreadMessages, newHasUnreadMessages); + } + else if(oldValue > 0 && newValue <= 0) + { + newHasUnreadMessages = kFalseLiteral; + NotifyPropertyChanged(folderResource, kNC_HasUnreadMessages, newHasUnreadMessages); + } + } + return NS_OK; +} + +**/ +nsresult +nsMsgFolderDataSource::OnFolderSortOrderPropertyChanged(nsIRDFResource *folderResource, int32_t oldValue, int32_t newValue) +{ + nsCOMPtr folder(do_QueryInterface(folderResource)); + if (folder) + { + nsCOMPtr newNode; + createFolderNameNode(folder, getter_AddRefs(newNode), true); + NotifyPropertyChanged(folderResource, kNC_FolderTreeNameSort, newNode); + } + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::OnFolderSizePropertyChanged(nsIRDFResource *folderResource, int64_t oldValue, int64_t newValue) +{ + nsCOMPtr newNode; + GetFolderSizeNode(newValue, getter_AddRefs(newNode)); + NotifyPropertyChanged(folderResource, kNC_FolderSize, newNode); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::OnTotalMessagePropertyChanged(nsIRDFResource *folderResource, int32_t oldValue, int32_t newValue) +{ + nsCOMPtr newNode; + GetNumMessagesNode(newValue, getter_AddRefs(newNode)); + NotifyPropertyChanged(folderResource, kNC_TotalMessages, newNode); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::GetNumMessagesNode(int32_t aNumMessages, nsIRDFNode **node) +{ + uint32_t numMessages = aNumMessages; + if(numMessages == kDisplayQuestionCount) + createNode(u"???", node, getRDFService()); + else if (numMessages == kDisplayBlankCount || numMessages == 0) + createNode(EmptyString().get(), node, getRDFService()); + else + createIntNode(numMessages, node, getRDFService()); + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::GetFolderSizeNode(int64_t aFolderSize, nsIRDFNode **aNode) +{ + nsresult rv; + if (aFolderSize == kDisplayBlankCount64 || aFolderSize == 0) + createNode(EmptyString().get(), aNode, getRDFService()); + else if (aFolderSize == kDisplayQuestionCount64) + createNode(u"???", aNode, getRDFService()); + else + { + nsAutoString sizeString; + rv = FormatFileSize(aFolderSize, true, sizeString); + NS_ENSURE_SUCCESS(rv, rv); + + createNode(sizeString.get(), aNode, getRDFService()); + } + return NS_OK; +} + +nsresult +nsMsgFolderDataSource::createFolderChildNode(nsIMsgFolder *folder, + nsIRDFNode **target) +{ + nsCOMPtr subFolders; + nsresult rv = folder->GetSubFolders(getter_AddRefs(subFolders)); + if (NS_FAILED(rv)) + return NS_RDF_NO_VALUE; + + bool hasMore; + rv = subFolders->HasMoreElements(&hasMore); + if (NS_FAILED(rv) || !hasMore) + return NS_RDF_NO_VALUE; + + nsCOMPtr firstFolder; + rv = subFolders->GetNext(getter_AddRefs(firstFolder)); + if (NS_FAILED(rv)) + return NS_RDF_NO_VALUE; + + return CallQueryInterface(firstFolder, target); +} + + +nsresult nsMsgFolderDataSource::DoCopyToFolder(nsIMsgFolder *dstFolder, nsISupportsArray *arguments, + nsIMsgWindow *msgWindow, bool isMove) +{ + nsresult rv; + uint32_t itemCount; + rv = arguments->Count(&itemCount); + NS_ENSURE_SUCCESS(rv, rv); + + //need source folder and at least one item to copy + if(itemCount < 2) + return NS_ERROR_FAILURE; + + nsCOMPtr srcFolder(do_QueryElementAt(arguments, 0)); + if(!srcFolder) + return NS_ERROR_FAILURE; + + nsCOMPtr messageArray(do_CreateInstance(NS_ARRAY_CONTRACTID)); + + // Remove first element + for(uint32_t i = 1; i < itemCount; i++) + { + nsCOMPtr message(do_QueryElementAt(arguments, i)); + if (message) + { + messageArray->AppendElement(message, false); + } + } + + //Call copyservice with dstFolder, srcFolder, messages, isMove, and txnManager + nsCOMPtr copyService = + do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv,rv); + + return copyService->CopyMessages(srcFolder, messageArray, dstFolder, isMove, + nullptr, msgWindow, true/* allowUndo */); +} + +nsresult nsMsgFolderDataSource::DoFolderCopyToFolder(nsIMsgFolder *dstFolder, nsISupportsArray *arguments, + nsIMsgWindow *msgWindow, bool isMoveFolder) +{ + nsresult rv; + uint32_t itemCount; + rv = arguments->Count(&itemCount); + NS_ENSURE_SUCCESS(rv, rv); + + //need at least one item to copy + if(itemCount < 1) + return NS_ERROR_FAILURE; + + if (!isMoveFolder) // copy folder not on the same server + { + // Create an nsIMutableArray from the nsISupportsArray + nsCOMPtr folderArray(do_CreateInstance(NS_ARRAY_CONTRACTID)); + for (uint32_t i = 0; i < itemCount; i++) + { + nsCOMPtr element(do_QueryElementAt(arguments, i, &rv)); + if (NS_SUCCEEDED(rv)) + folderArray->AppendElement(element, false); + } + + //Call copyservice with dstFolder, srcFolder, folders and isMoveFolder + nsCOMPtr copyService = do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &rv); + if(NS_SUCCEEDED(rv)) + { + rv = copyService->CopyFolders(folderArray, dstFolder, isMoveFolder, + nullptr, msgWindow); + + } + } + else //within the same server therefore no need for copy service + { + + nsCOMPtr msgFolder; + for (uint32_t i=0;i< itemCount; i++) + { + msgFolder = do_QueryElementAt(arguments, i, &rv); + if (NS_SUCCEEDED(rv)) + { + rv = dstFolder->CopyFolder(msgFolder, isMoveFolder , msgWindow, nullptr); + NS_ASSERTION((NS_SUCCEEDED(rv)),"Copy folder failed."); + } + } + } + + return rv; + //return NS_OK; +} + +nsresult nsMsgFolderDataSource::DoDeleteFromFolder(nsIMsgFolder *folder, nsISupportsArray *arguments, + nsIMsgWindow *msgWindow, bool reallyDelete) +{ + nsresult rv = NS_OK; + uint32_t itemCount; + rv = arguments->Count(&itemCount); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr messageArray(do_CreateInstance(NS_ARRAY_CONTRACTID)); + nsCOMPtr folderArray(do_CreateInstance(NS_ARRAY_CONTRACTID)); + + //Split up deleted items into different type arrays to be passed to the folder + //for deletion. + for(uint32_t item = 0; item < itemCount; item++) + { + nsCOMPtr supports(do_QueryElementAt(arguments, item)); + nsCOMPtr deletedMessage(do_QueryInterface(supports)); + nsCOMPtr deletedFolder(do_QueryInterface(supports)); + if (deletedMessage) + { + messageArray->AppendElement(supports, false); + } + else if(deletedFolder) + { + folderArray->AppendElement(supports, false); + } + } + uint32_t cnt; + rv = messageArray->GetLength(&cnt); + if (NS_FAILED(rv)) return rv; + if (cnt > 0) + rv = folder->DeleteMessages(messageArray, msgWindow, reallyDelete, false, nullptr, true /*allowUndo*/); + + rv = folderArray->GetLength(&cnt); + if (NS_FAILED(rv)) return rv; + if (cnt > 0) + { + nsCOMPtr folderToDelete = do_QueryElementAt(folderArray, 0); + uint32_t folderFlags = 0; + if (folderToDelete) + { + folderToDelete->GetFlags(&folderFlags); + if (folderFlags & nsMsgFolderFlags::Virtual) + { + NS_ENSURE_ARG_POINTER(msgWindow); + nsCOMPtr sBundleService = + mozilla::services::GetStringBundleService(); + NS_ENSURE_TRUE(sBundleService, NS_ERROR_UNEXPECTED); + nsCOMPtr sMessengerStringBundle; + nsString confirmMsg; + rv = sBundleService->CreateBundle(MESSENGER_STRING_URL, getter_AddRefs(sMessengerStringBundle)); + NS_ENSURE_SUCCESS(rv, rv); + sMessengerStringBundle->GetStringFromName(u"confirmSavedSearchDeleteMessage", getter_Copies(confirmMsg)); + + nsCOMPtr dialog; + rv = msgWindow->GetPromptDialog(getter_AddRefs(dialog)); + if (NS_SUCCEEDED(rv)) + { + bool dialogResult; + rv = dialog->Confirm(nullptr, confirmMsg.get(), &dialogResult); + if (!dialogResult) + return NS_OK; + } + } + } + rv = folder->DeleteSubFolders(folderArray, msgWindow); + } + return rv; +} + +nsresult nsMsgFolderDataSource::DoNewFolder(nsIMsgFolder *folder, nsISupportsArray *arguments, nsIMsgWindow *window) +{ + nsresult rv = NS_OK; + nsCOMPtr literal = do_QueryElementAt(arguments, 0, &rv); + if(NS_SUCCEEDED(rv)) + { + nsString name; + literal->GetValue(getter_Copies(name)); + rv = folder->CreateSubfolder(name, window); + } + return rv; +} + +nsresult nsMsgFolderDataSource::DoFolderAssert(nsIMsgFolder *folder, nsIRDFResource *property, nsIRDFNode *target) +{ + nsresult rv = NS_ERROR_FAILURE; + + if (kNC_Charset == property) + { + nsCOMPtr literal(do_QueryInterface(target)); + if(literal) + { + const char16_t* value; + rv = literal->GetValueConst(&value); + if(NS_SUCCEEDED(rv)) + rv = folder->SetCharset(NS_LossyConvertUTF16toASCII(value)); + } + else + rv = NS_ERROR_FAILURE; + } + else if (kNC_Open == property && target == kTrueLiteral) + rv = folder->ClearFlag(nsMsgFolderFlags::Elided); + + return rv; +} + +nsresult nsMsgFolderDataSource::DoFolderUnassert(nsIMsgFolder *folder, nsIRDFResource *property, nsIRDFNode *target) +{ + nsresult rv = NS_ERROR_FAILURE; + + if((kNC_Open == property) && target == kTrueLiteral) + rv = folder->SetFlag(nsMsgFolderFlags::Elided); + + return rv; +} + +nsresult nsMsgFolderDataSource::DoFolderHasAssertion(nsIMsgFolder *folder, + nsIRDFResource *property, + nsIRDFNode *target, + bool tv, + bool *hasAssertion) +{ + nsresult rv = NS_OK; + if(!hasAssertion) + return NS_ERROR_NULL_POINTER; + + //We're not keeping track of negative assertions on folders. + if(!tv) + { + *hasAssertion = false; + return NS_OK; + } + + if (kNC_Child == property) + { + nsCOMPtr childFolder(do_QueryInterface(target, &rv)); + if(NS_SUCCEEDED(rv)) + { + nsCOMPtr childsParent; + rv = childFolder->GetParent(getter_AddRefs(childsParent)); + *hasAssertion = (NS_SUCCEEDED(rv) && childsParent && folder + && (childsParent.get() == folder)); + } + } + else if ((kNC_Name == property) || + (kNC_Open == property) || + (kNC_FolderTreeName == property) || + (kNC_FolderTreeSimpleName == property) || + (kNC_SpecialFolder == property) || + (kNC_ServerType == property) || + (kNC_IsDeferred == property) || + (kNC_CanCreateFoldersOnServer == property) || + (kNC_CanFileMessagesOnServer == property) || + (kNC_IsServer == property) || + (kNC_IsSecure == property) || + (kNC_CanSubscribe == property) || + (kNC_SupportsOffline == property) || + (kNC_CanFileMessages == property) || + (kNC_CanCreateSubfolders == property) || + (kNC_CanRename == property) || + (kNC_CanCompact == property) || + (kNC_TotalMessages == property) || + (kNC_TotalUnreadMessages == property) || + (kNC_FolderSize == property) || + (kNC_Charset == property) || + (kNC_BiffState == property) || + (kNC_HasUnreadMessages == property) || + (kNC_NoSelect == property) || + (kNC_Synchronize == property) || + (kNC_SyncDisabled == property) || + (kNC_VirtualFolder == property) || + (kNC_CanSearchMessages == property)) + { + nsCOMPtr folderResource(do_QueryInterface(folder, &rv)); + + if(NS_FAILED(rv)) + return rv; + + rv = GetTargetHasAssertion(this, folderResource, property, tv, target, hasAssertion); + } + else + *hasAssertion = false; + return rv; +} + +nsMsgFlatFolderDataSource::nsMsgFlatFolderDataSource() +{ + m_builtFolders = false; +} + +nsMsgFlatFolderDataSource::~nsMsgFlatFolderDataSource() +{ +} + +nsresult nsMsgFlatFolderDataSource::Init() +{ + nsIRDFService* rdf = getRDFService(); + NS_ENSURE_TRUE(rdf, NS_ERROR_FAILURE); + nsCOMPtr source; + nsAutoCString dsUri(m_dsName); + dsUri.Append(":/"); + rdf->GetResource(dsUri, getter_AddRefs(m_rootResource)); + + return nsMsgFolderDataSource::Init(); +} + +void nsMsgFlatFolderDataSource::Cleanup() +{ + m_folders.Clear(); + m_builtFolders = false; + nsMsgFolderDataSource::Cleanup(); +} + +NS_IMETHODIMP nsMsgFlatFolderDataSource::GetTarget(nsIRDFResource* source, + nsIRDFResource* property, + bool tv, + nsIRDFNode** target) +{ + return (property == kNC_Child) + ? NS_RDF_NO_VALUE + : nsMsgFolderDataSource::GetTarget(source, property, tv, target); +} + + +NS_IMETHODIMP nsMsgFlatFolderDataSource::GetTargets(nsIRDFResource* source, + nsIRDFResource* property, + bool tv, + nsISimpleEnumerator** targets) +{ + if (kNC_Child != property) + return nsMsgFolderDataSource::GetTargets(source, property, tv, targets); + + if(!targets) + return NS_ERROR_NULL_POINTER; + + if (ResourceIsOurRoot(source)) + { + EnsureFolders(); + return NS_NewArrayEnumerator(targets, m_folders); + } + return NS_NewSingletonEnumerator(targets, property); +} + +void nsMsgFlatFolderDataSource::EnsureFolders() +{ + if (m_builtFolders) + return; + + m_builtFolders = true; // in case something goes wrong + + nsresult rv; + nsCOMPtr accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS_VOID(rv); + + nsCOMPtr allFolders; + rv = accountManager->GetAllFolders(getter_AddRefs(allFolders)); + if (NS_FAILED(rv) || !allFolders) + return; + + uint32_t count; + rv = allFolders->GetLength(&count); + NS_ENSURE_SUCCESS_VOID(rv); + + for (uint32_t i = 0; i < count; i++) + { + nsCOMPtr curFolder = do_QueryElementAt(allFolders, i); + if (WantsThisFolder(curFolder)) + m_folders.AppendObject(curFolder); + } +} + + +NS_IMETHODIMP nsMsgFlatFolderDataSource::GetURI(char* *aUri) +{ + nsAutoCString uri("rdf:"); + uri.Append(m_dsName); + return (*aUri = ToNewCString(uri)) + ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP nsMsgFlatFolderDataSource::HasAssertion(nsIRDFResource* source, + nsIRDFResource* property, + nsIRDFNode* target, + bool tv, + bool* hasAssertion) +{ + nsresult rv; + + nsCOMPtr folder(do_QueryInterface(source, &rv)); + // we need to check if the folder belongs in this datasource. + if (NS_SUCCEEDED(rv) && property != kNC_Open && property != kNC_Child) + { + if (WantsThisFolder(folder) && (kNC_Child != property)) + return DoFolderHasAssertion(folder, property, target, tv, hasAssertion); + } + else if (property == kNC_Child && ResourceIsOurRoot(source)) // check if source is us + { + folder = do_QueryInterface(target); + if (folder) + { + nsCOMPtr parentMsgFolder; + folder->GetParent(getter_AddRefs(parentMsgFolder)); + // a folder without a parent must be getting deleted as part of + // the rename operation and is thus a folder we are + // no longer interested in + if (parentMsgFolder && WantsThisFolder(folder)) + { + *hasAssertion = true; + return NS_OK; + } + } + } + *hasAssertion = false; + return NS_OK; +} + +nsresult nsMsgFlatFolderDataSource::OnItemAddedOrRemoved(nsIMsgFolder *parentItem, nsISupports *item, bool added) +{ + // When a folder is added or removed, parentItem is the parent folder and item is the folder being + // added or removed. In a flat data source, there is no arc in the graph between the parent folder + // and the folder being added or removed. Our flat data source root (i.e. mailnewsunreadfolders:/) has + // an arc with the child property to every folder in the data source. We must change parentItem + // to be our data source root before calling nsMsgFolderDataSource::OnItemAddedOrRemoved. This ensures + // that datasource listeners such as the template builder properly handle add and remove + // notifications on the flat datasource. + nsCOMPtr itemNode(do_QueryInterface(item)); + if (itemNode) + NotifyObservers(m_rootResource, kNC_Child, itemNode, nullptr, added, false); + return NS_OK; +} + +bool nsMsgFlatFolderDataSource::ResourceIsOurRoot(nsIRDFResource *resource) +{ + return m_rootResource.get() == resource; +} + +bool nsMsgFlatFolderDataSource::WantsThisFolder(nsIMsgFolder *folder) +{ + EnsureFolders(); + return m_folders.Contains(folder); +} + +nsresult nsMsgFlatFolderDataSource::GetFolderDisplayName(nsIMsgFolder *folder, nsString& folderName) +{ + folder->GetName(folderName); + uint32_t foldersCount = m_folders.Count(); + nsString otherFolderName; + for (uint32_t index = 0; index < foldersCount; index++) + { + if (folder == m_folders[index]) // ignore ourselves. + continue; + m_folders[index]->GetName(otherFolderName); + if (otherFolderName.Equals(folderName)) + { + nsCOMPtr server; + folder->GetServer(getter_AddRefs(server)); + if (server) + { + nsString serverName; + server->GetPrettyName(serverName); + folderName.AppendLiteral(" - "); + folderName.Append(serverName); + return NS_OK; + } + } + } + // check if folder name is unique - if not, append account name + return folder->GetAbbreviatedName(folderName); +} + + +bool nsMsgUnreadFoldersDataSource::WantsThisFolder(nsIMsgFolder *folder) +{ + int32_t numUnread; + folder->GetNumUnread(false, &numUnread); + return numUnread > 0; +} + +nsresult nsMsgUnreadFoldersDataSource::NotifyPropertyChanged(nsIRDFResource *resource, + nsIRDFResource *property, nsIRDFNode *newNode, + nsIRDFNode *oldNode) +{ + // check if it's the has unread property that's changed; if so, see if we need + // to add this folder to the view. + // Then, call base class. + if (kNC_HasUnreadMessages == property) + { + nsCOMPtr folder(do_QueryInterface(resource)); + if (folder) + { + int32_t numUnread; + folder->GetNumUnread(false, &numUnread); + if (numUnread > 0) + { + if (!m_folders.Contains(folder)) + m_folders.AppendObject(folder); + NotifyObservers(kNC_UnreadFolders, kNC_Child, resource, nullptr, true, false); + } + } + } + return nsMsgFolderDataSource::NotifyPropertyChanged(resource, property, + newNode, oldNode); +} + +bool nsMsgFavoriteFoldersDataSource::WantsThisFolder(nsIMsgFolder *folder) +{ + uint32_t folderFlags; + folder->GetFlags(&folderFlags); + return folderFlags & nsMsgFolderFlags::Favorite; +} + + +void nsMsgRecentFoldersDataSource::Cleanup() +{ + m_cutOffDate = 0; + nsMsgFlatFolderDataSource::Cleanup(); +} + + +void nsMsgRecentFoldersDataSource::EnsureFolders() +{ + if (m_builtFolders) + return; + + m_builtFolders = true; // in case something goes wrong + + nsresult rv; + nsCOMPtr accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS_VOID(rv); + + nsCOMPtr allFolders; + rv = accountManager->GetAllFolders(getter_AddRefs(allFolders)); + if (NS_FAILED(rv) || !allFolders) + return; + + uint32_t count; + rv = allFolders->GetLength(&count); + NS_ENSURE_SUCCESS_VOID(rv); + + for (uint32_t i = 0; i < count; i++) + { + nsCOMPtr curFolder = do_QueryElementAt(allFolders, i); + nsCString dateStr; + curFolder->GetStringProperty(MRU_TIME_PROPERTY, dateStr); + uint32_t curFolderDate = (uint32_t) dateStr.ToInteger(&rv); + if (NS_FAILED(rv)) + curFolderDate = 0; + + if (curFolderDate > m_cutOffDate) + { + // if m_folders is "full", replace oldest folder with this folder, + // and adjust m_cutOffDate so that it's the mrutime + // of the "new" oldest folder. + uint32_t curFaveFoldersCount = m_folders.Count(); + if (curFaveFoldersCount > m_maxNumFolders) + { + uint32_t indexOfOldestFolder = 0; + uint32_t oldestFaveDate = 0; + uint32_t newOldestFaveDate = 0; + for (uint32_t index = 0; index < curFaveFoldersCount; ) + { + nsCString curFaveFolderDateStr; + m_folders[index]->GetStringProperty(MRU_TIME_PROPERTY, curFaveFolderDateStr); + uint32_t curFaveFolderDate = (uint32_t) curFaveFolderDateStr.ToInteger(&rv); + if (!oldestFaveDate || curFaveFolderDate < oldestFaveDate) + { + indexOfOldestFolder = index; + newOldestFaveDate = oldestFaveDate; + oldestFaveDate = curFaveFolderDate; + } + if (!newOldestFaveDate || (index != indexOfOldestFolder + && curFaveFolderDate < newOldestFaveDate)) { + newOldestFaveDate = curFaveFolderDate; + } + index++; + } + if (curFolderDate > oldestFaveDate && !m_folders.Contains(curFolder)) + m_folders.ReplaceObjectAt(curFolder, indexOfOldestFolder); + + NS_ASSERTION(newOldestFaveDate >= m_cutOffDate, "cutoff date should be getting bigger"); + m_cutOffDate = newOldestFaveDate; + } + else if (!m_folders.Contains(curFolder)) + m_folders.AppendObject(curFolder); + } +#ifdef DEBUG_David_Bienvenu + else + { + for (uint32_t index = 0; index < m_folders.Count(); index++) + { + nsCString curFaveFolderDateStr; + m_folders[index]->GetStringProperty(MRU_TIME_PROPERTY, curFaveFolderDateStr); + uint32_t curFaveFolderDate = (uint32_t) curFaveFolderDateStr.ToInteger(&rv); + NS_ASSERTION(curFaveFolderDate > curFolderDate, "folder newer then faves but not added"); + } + } +#endif + } +} + +NS_IMETHODIMP nsMsgRecentFoldersDataSource::OnItemAdded(nsIMsgFolder *parentItem, nsISupports *item) +{ + // if we've already built the recent folder array, we should add this item to the array + // since just added items are by definition new. + // I think this means newly discovered imap folders (ones w/o msf files) will + // get added, but maybe that's OK. + if (m_builtFolders) + { + nsCOMPtr folder(do_QueryInterface(item)); + if (folder && !m_folders.Contains(folder)) + { + m_folders.AppendObject(folder); + nsCOMPtr resource = do_QueryInterface(item); + NotifyObservers(kNC_RecentFolders, kNC_Child, resource, nullptr, true, false); + } + } + return nsMsgFlatFolderDataSource::OnItemAdded(parentItem, item); +} + +nsresult nsMsgRecentFoldersDataSource::NotifyPropertyChanged(nsIRDFResource *resource, + nsIRDFResource *property, nsIRDFNode *newNode, + nsIRDFNode *oldNode) +{ + // check if it's the has new property that's changed; if so, see if we need + // to add this folder to the view. + // Then, call base class. + if (kNC_NewMessages == property) + { + nsCOMPtr folder(do_QueryInterface(resource)); + if (folder) + { + bool hasNewMessages; + folder->GetHasNewMessages(&hasNewMessages); + if (hasNewMessages) + { + if (!m_folders.Contains(folder)) + { + m_folders.AppendObject(folder); + NotifyObservers(kNC_RecentFolders, kNC_Child, resource, nullptr, true, false); + } + } + } + } + return nsMsgFolderDataSource::NotifyPropertyChanged(resource, property, + newNode, oldNode); +} -- cgit v1.2.3