From ade62cad45058cb3ef91f573a672bef58fe28658 Mon Sep 17 00:00:00 2001 From: "scott%scott-macgregor.org" Date: Tue, 27 Jul 2004 20:43:01 +0000 Subject: [PATCH] Bug #253055 --> Use a folder listener to track folder name changes and folder deletions of RSS folders so we can keep our subscription data source up to date. Part of the Thunderbird RSS work. sr=bienvenu git-svn-id: svn://10.0.0.236/branches/AVIARY_1_0_20040515_BRANCH@159929 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/mail/extensions/Makefile.in | 2 +- .../mail/extensions/newsblog/content/Feed.js | 4 + .../newsblog/content/feed-properties.xul | 22 ++- .../mail/extensions/newsblog/content/utils.js | 3 + .../mail/extensions/newsblog/js/newsblog.js | 42 ++++++ .../public/nsINewsBlogFeedDownloader.idl | 5 + .../local/src/nsRssIncomingServer.cpp | 138 +++++++++++++++++- .../mailnews/local/src/nsRssIncomingServer.h | 7 +- 8 files changed, 210 insertions(+), 13 deletions(-) diff --git a/mozilla/mail/extensions/Makefile.in b/mozilla/mail/extensions/Makefile.in index 570ed01ea84..404155d0931 100644 --- a/mozilla/mail/extensions/Makefile.in +++ b/mozilla/mail/extensions/Makefile.in @@ -26,7 +26,7 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -DIRS = offline +DIRS = offline newsblog ifdef MOZ_PSM BUILD_SMIME=1 diff --git a/mozilla/mail/extensions/newsblog/content/Feed.js b/mozilla/mail/extensions/newsblog/content/Feed.js index 89ff844be50..7c2ddebef9d 100755 --- a/mozilla/mail/extensions/newsblog/content/Feed.js +++ b/mozilla/mail/extensions/newsblog/content/Feed.js @@ -481,6 +481,10 @@ function storeNextItem() { item.feed.removeInvalidItems(); + // let's be sure to flush any feed item changes back to disk + var ds = getItemsDS(item.feed.server); + ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource).Flush(); // flush any changes + if (item.feed.downloadCallback) item.feed.downloadCallback.downloaded(item.feed, kNewsBlogSuccess); diff --git a/mozilla/mail/extensions/newsblog/content/feed-properties.xul b/mozilla/mail/extensions/newsblog/content/feed-properties.xul index 197248f9b9b..8645c692bd7 100644 --- a/mozilla/mail/extensions/newsblog/content/feed-properties.xul +++ b/mozilla/mail/extensions/newsblog/content/feed-properties.xul @@ -37,6 +37,7 @@ - - diff --git a/mozilla/mail/extensions/newsblog/content/utils.js b/mozilla/mail/extensions/newsblog/content/utils.js index 39a6617601e..f3ba1ef576a 100755 --- a/mozilla/mail/extensions/newsblog/content/utils.js +++ b/mozilla/mail/extensions/newsblog/content/utils.js @@ -109,6 +109,9 @@ function updateFolderFeedUrl(aFolder, aFeedUrl, aRemoveUrl) } else folderInfo.SetCharPtrProperty("feedUrl", oldFeedUrl + kFeedUrlDelimiter + aFeedUrl); + + // commit the db to preserve our changes + msgdb.Close(true); } function getNodeValue(node) { diff --git a/mozilla/mail/extensions/newsblog/js/newsblog.js b/mozilla/mail/extensions/newsblog/js/newsblog.js index cf69b9497ce..51d3a97f5ec 100755 --- a/mozilla/mail/extensions/newsblog/js/newsblog.js +++ b/mozilla/mail/extensions/newsblog/js/newsblog.js @@ -85,6 +85,48 @@ var nsNewsBlogFeedDownloader = feed.download(true, progressNotifier); }, + updateSubscriptionsDS: function(aFolder, aUnsubscribe) + { + if (!gExternalScriptsLoaded) + loadScripts(); + + // an rss folder was just renamed...we need to update our feed data source + var msgdb = aFolder.QueryInterface(Components.interfaces.nsIMsgFolder).getMsgDatabase(null); + var folderInfo = msgdb.dBFolderInfo; + var feedurls = {}; + folderInfo.GetCharPtrProperty("feedUrl", feedurls); + feedurls = feedurls.value; + + var feedUrlArray = feedurls.split("|"); + + var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService); + var ds = getSubscriptionsDS(aFolder.server); + + for (url in feedUrlArray) + { + if (feedUrlArray[url]) + { + id = rdf.GetResource(feedUrlArray[url]); + // get the node for the current folder URI + var node = ds.GetTarget(id, FZ_DESTFOLDER, true); + + // we need to check and see if the folder is a child of the trash...if it is, then we can + // treat this as an unsubscribe action + if (aUnsubscribe) + { + var feeds = getSubscriptionsList(aFolder.server); + var index = feeds.IndexOf(id); + if (index != -1) + feeds.RemoveElementAt(index, false); + removeAssertions(ds, id); + } + ds.Change(id, FZ_DESTFOLDER, node, rdf.GetResource(aFolder.URI)); + } + } // for each feed url in the folder property + + ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource).Flush(); // flush any changes + }, + QueryInterface: function(aIID) { if (aIID.equals(Components.interfaces.nsINewsBlogFeedDownloader) || diff --git a/mozilla/mailnews/local/public/nsINewsBlogFeedDownloader.idl b/mozilla/mailnews/local/public/nsINewsBlogFeedDownloader.idl index a12241fc52b..ec530988a8d 100755 --- a/mozilla/mailnews/local/public/nsINewsBlogFeedDownloader.idl +++ b/mozilla/mailnews/local/public/nsINewsBlogFeedDownloader.idl @@ -50,5 +50,10 @@ interface nsINewsBlogFeedDownloader : nsISupports /* A convient method to subscribe to feeds without going through the subscribe UI used by drag and drop */ void subscribeToFeed(in string aUrl, in nsIMsgFolder aFolder, in nsIMsgWindow aMsgWindow); + + /* called when the RSS Incoming Server detects a change to an RSS folder. For instance, the user just + deleted an RSS folder and we need to update the subscriptions data source. Or the user renamed an RSS folder... + */ + void updateSubscriptionsDS(in nsIMsgFolder aFolder, in boolean aUnsubscribe); }; diff --git a/mozilla/mailnews/local/src/nsRssIncomingServer.cpp b/mozilla/mailnews/local/src/nsRssIncomingServer.cpp index 602074ae8c7..11dd84668cf 100755 --- a/mozilla/mailnews/local/src/nsRssIncomingServer.cpp +++ b/mozilla/mailnews/local/src/nsRssIncomingServer.cpp @@ -39,22 +39,45 @@ #include "nsRssIncomingServer.h" #include "nsMsgFolderFlags.h" #include "nsINewsBlogFeedDownloader.h" +#include "nsIMsgMailSession.h" +#include "nsMsgBaseCID.h" +#include "nsIRDFResource.h" #include "nsIMsgLocalMailFolder.h" #include "nsIDBFolderInfo.h" -NS_IMPL_ISUPPORTS_INHERITED2(nsRssIncomingServer, +nsrefcnt nsRssIncomingServer::gInstanceCount = 0; + +NS_IMPL_ISUPPORTS_INHERITED3(nsRssIncomingServer, nsMsgIncomingServer, nsIRssIncomingServer, + nsIFolderListener, nsILocalMailIncomingServer) nsRssIncomingServer::nsRssIncomingServer() { m_canHaveFilters = PR_TRUE; + + if (gInstanceCount == 0) + { + nsresult rv; + nsCOMPtr mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv); + + if (NS_SUCCEEDED(rv)) + mailSession->AddFolderListener(this, nsIFolderListener::added); + } + + gInstanceCount++; } nsRssIncomingServer::~nsRssIncomingServer() { + gInstanceCount--; + + // I used to have code here which unregistered the global rss folder listener with the + // mail session. But the rss incoming server is held until shutdown when we shut down the + // account datasource. And at shutdown the mail session explicitly releases all of its folder listeners + // anyway so this was effectively a no-op... } nsresult nsRssIncomingServer::FillInDataSourcePath(const nsAString& aDataSourceName, nsILocalFile ** aLocation) @@ -135,25 +158,28 @@ NS_IMETHODIMP nsRssIncomingServer::PerformBiff(nsIMsgWindow *aMsgWindow) GetRootMsgFolder(getter_AddRefs(rootRSSFolder)); // enumerate over the RSS folders and ping each one - nsCOMPtr folderEnumerator; - rv = rootRSSFolder->GetSubFolders(getter_AddRefs(folderEnumerator)); + nsCOMPtr allDescendents; + NS_NewISupportsArray(getter_AddRefs(allDescendents)); + rv = rootRSSFolder->ListDescendents(allDescendents); NS_ENSURE_SUCCESS(rv, rv); - nsresult more = folderEnumerator->First(); + PRUint32 cnt =0; + allDescendents->Count(&cnt); + nsCOMPtr supports; nsCOMPtr urlListener; + nsCOMPtr rssFolder; - while (NS_SUCCEEDED(more)) + for (PRUint32 index = 0; index < cnt; index++) { - rv = folderEnumerator->CurrentItem(getter_AddRefs(supports)); - nsCOMPtr rssFolder = do_QueryInterface(supports); + supports = getter_AddRefs(allDescendents->ElementAt(index)); + rssFolder = do_QueryInterface(supports, &rv); if (rssFolder) { urlListener = do_QueryInterface(rssFolder); // WARNING: Never call GetNewMail with the root folder or you will trigger an infinite loop... GetNewMail(aMsgWindow, urlListener, rssFolder, nsnull); } - more = folderEnumerator->Next(); } return NS_OK; @@ -226,3 +252,99 @@ NS_IMETHODIMP nsRssIncomingServer::GetSupportsDiskSpace(PRBool *aSupportsDiskSpa *aSupportsDiskSpace = PR_FALSE; return NS_OK; } + +NS_IMETHODIMP nsRssIncomingServer::OnItemAdded(nsISupports *parentItem, nsISupports *item, const char *viewString) +{ + nsCOMPtr folder = do_QueryInterface(item); + NS_ENSURE_TRUE(folder, NS_OK); // just kick out with a success code if the item in question is not a folder + + nsCOMPtr server; + nsresult rv = folder->GetServer(getter_AddRefs(server)); + NS_ENSURE_SUCCESS(rv, rv); + + nsXPIDLCString type; + rv = server->GetType(getter_Copies(type)); + NS_ENSURE_SUCCESS(rv, rv); + + if (type.Equals("rss")) + { + nsCOMPtr rssDownloader = do_GetService("@mozilla.org/newsblog-feed-downloader;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // did the user just delete this folder (adding it to trash?) + nsCOMPtr rootMsgFolder; + nsCOMPtr trashFolder; + rv = GetRootFolder(getter_AddRefs(rootMsgFolder)); + NS_ENSURE_SUCCESS(rv, rv); + + PRUint32 numFolders; + rv = rootMsgFolder->GetFoldersWithFlag(MSG_FOLDER_FLAG_TRASH, 1, &numFolders, getter_AddRefs(trashFolder)); + + PRBool unsubscribe = PR_FALSE; + if (trashFolder) + trashFolder->IsAncestorOf(folder, &unsubscribe); + + rssDownloader->UpdateSubscriptionsDS(folder, unsubscribe); + + // if the user was moving or deleting a set of nested folders, we only seem to get a single OnItemAdded + // notification. So we need to iterate over all of the descedent folders of the folder whose location has + // changed. + + nsCOMPtr allDescendents; + NS_NewISupportsArray(getter_AddRefs(allDescendents)); + rv = folder->ListDescendents(allDescendents); + NS_ENSURE_SUCCESS(rv, rv); + + PRUint32 cnt =0; + allDescendents->Count(&cnt); + + nsCOMPtr supports; + nsCOMPtr rssFolder; + + for (PRUint32 index = 0; index < cnt; index++) + { + supports = getter_AddRefs(allDescendents->ElementAt(index)); + rssFolder = do_QueryInterface(supports, &rv); + if (rssFolder) + rssDownloader->UpdateSubscriptionsDS(rssFolder, unsubscribe); + } + } + + return rv; +} + +NS_IMETHODIMP nsRssIncomingServer::OnItemRemoved(nsISupports *parentItem, nsISupports *item, const char *viewString) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsRssIncomingServer::OnItemPropertyChanged(nsISupports *item, nsIAtom *property, const char *oldValue, const char *newValue) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsRssIncomingServer::OnItemIntPropertyChanged(nsISupports *item, nsIAtom *property, PRInt32 oldValue, PRInt32 newValue) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsRssIncomingServer::OnItemBoolPropertyChanged(nsISupports *item, nsIAtom *property, PRBool oldValue, PRBool newValue) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsRssIncomingServer::OnItemUnicharPropertyChanged(nsISupports *item, nsIAtom *property, const PRUnichar *oldValue, const PRUnichar *newValue) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + +NS_IMETHODIMP nsRssIncomingServer::OnItemPropertyFlagChanged(nsISupports *item, nsIAtom *property, PRUint32 oldFlag, PRUint32 newFlag) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsRssIncomingServer::OnItemEvent(nsIMsgFolder *aFolder, nsIAtom *aEvent) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} diff --git a/mozilla/mailnews/local/src/nsRssIncomingServer.h b/mozilla/mailnews/local/src/nsRssIncomingServer.h index 1f1381c5d77..bd07bdc80e9 100755 --- a/mozilla/mailnews/local/src/nsRssIncomingServer.h +++ b/mozilla/mailnews/local/src/nsRssIncomingServer.h @@ -40,17 +40,19 @@ #include "nsIRssIncomingServer.h" #include "nsILocalMailIncomingServer.h" #include "nsMsgIncomingServer.h" - +#include "nsIFolderListener.h" class nsRssIncomingServer : public nsMsgIncomingServer, public nsIRssIncomingServer, - public nsILocalMailIncomingServer + public nsILocalMailIncomingServer, + public nsIFolderListener { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIRSSINCOMINGSERVER NS_DECL_NSILOCALMAILINCOMINGSERVER + NS_DECL_NSIFOLDERLISTENER NS_IMETHOD GetLocalStoreType(char **); NS_IMETHOD GetOfflineSupportLevel(PRInt32 *aSupportLevel); @@ -62,6 +64,7 @@ public: virtual ~nsRssIncomingServer(); protected: nsresult FillInDataSourcePath(const nsAString& aDataSourceName, nsILocalFile ** aLocation); + static nsrefcnt gInstanceCount; }; #endif /* __nsRssIncomingServer_h */