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
This commit is contained in:
scott%scott-macgregor.org 2004-07-27 19:34:05 +00:00
parent a4cbf9b0e4
commit 18f20083dc
7 changed files with 214 additions and 21 deletions

View File

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

View File

@ -37,6 +37,7 @@
<dialog id="feedPropertyDialog"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:nc="http://home.netscape.com/NC-rdf#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&window.title;"
style="width: 27em;"
@ -73,22 +74,39 @@
datasources="rdf:msgaccountmanager rdf:mailnewsfolders"
ref="...">
<template>
<!-- cheat and use the CanRename property to make sure we don't list the Trash folder as a possible feed folder -->
<rule nc:CanFileMessages="true" iscontainer="true" isempty="false" nc:CanRename="true">
<menupopup>
<menuitem uri="..." value="..."
class="folderMenuItem menuitem-iconic"
oncommand="PickedMsgFolder(event.target,'selectFolder')"
SpecialFolder="rdf:http://home.netscape.com/NC-rdf#SpecialFolder"
BiffState="rdf:http://home.netscape.com/NC-rdf#BiffState"
IsServer="rdf:http://home.netscape.com/NC-rdf#IsServer"
IsSecure="rdf:http://home.netscape.com/NC-rdf#IsSecure"
ServerType="rdf:http://home.netscape.com/NC-rdf#ServerType"
label="rdf:http://home.netscape.com/NC-rdf#Name"/>
<menu uri="..."
class="folderMenuItem menu-iconic"
oncommand="PickedMsgFolder(event.target,'selectFolder')"
SpecialFolder="rdf:http://home.netscape.com/NC-rdf#SpecialFolder"
BiffState="rdf:http://home.netscape.com/NC-rdf#BiffState"
IsServer="rdf:http://home.netscape.com/NC-rdf#IsServer"
IsSecure="rdf:http://home.netscape.com/NC-rdf#IsSecure"
ServerType="rdf:http://home.netscape.com/NC-rdf#ServerType"
label="rdf:http://home.netscape.com/NC-rdf#Name">
<menupopup class="menulist-menupopup"/>
</menu>
</menupopup>
</rule>
<rule nc:CanFileMessages="true" nc:CanRename="true">
<menupopup>
<menuitem uri="..." value="..."
class="folderMenuItem menuitem-iconic"
oncommand="PickedMsgFolder(event.target,'selectFolder')"
SpecialFolder="rdf:http://home.netscape.com/NC-rdf#SpecialFolder"
BiffState="rdf:http://home.netscape.com/NC-rdf#BiffState"
IsServer="rdf:http://home.netscape.com/NC-rdf#IsServer"
IsSecure="rdf:http://home.netscape.com/NC-rdf#IsSecure"
ServerType="rdf:http://home.netscape.com/NC-rdf#ServerType"
label="rdf:http://home.netscape.com/NC-rdf#Name"/>
</menupopup>
</rule>
</template>
</menulist>
</row>
<!-- Eventually we'll add a folder picker here to pick the folder associated with the feed -->
</rows>
</grid>
</dialog>

View File

@ -106,6 +106,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) {

View File

@ -85,6 +85,45 @@ 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");
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) ||

View File

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

View File

@ -39,22 +39,44 @@
#include "nsRssIncomingServer.h"
#include "nsMsgFolderFlags.h"
#include "nsINewsBlogFeedDownloader.h"
#include "nsIMsgMailSession.h"
#include "nsMsgBaseCID.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<nsIMsgMailSession> 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 +157,28 @@ NS_IMETHODIMP nsRssIncomingServer::PerformBiff(nsIMsgWindow *aMsgWindow)
GetRootMsgFolder(getter_AddRefs(rootRSSFolder));
// enumerate over the RSS folders and ping each one
nsCOMPtr<nsIEnumerator> folderEnumerator;
rv = rootRSSFolder->GetSubFolders(getter_AddRefs(folderEnumerator));
nsCOMPtr<nsISupportsArray> 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<nsISupports> supports;
nsCOMPtr<nsIUrlListener> urlListener;
nsCOMPtr<nsIMsgFolder> rssFolder;
while (NS_SUCCEEDED(more))
for (PRUint32 index = 0; index < cnt; index++)
{
rv = folderEnumerator->CurrentItem(getter_AddRefs(supports));
nsCOMPtr<nsIMsgFolder> 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 +251,99 @@ NS_IMETHODIMP nsRssIncomingServer::GetSupportsDiskSpace(PRBool *aSupportsDiskSpa
*aSupportsDiskSpace = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP nsRssIncomingServer::OnItemAdded(nsIRDFResource *parentItem, nsISupports *item)
{
nsCOMPtr<nsIMsgFolder> 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<nsIMsgIncomingServer> 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 <nsINewsBlogFeedDownloader> 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<nsIMsgFolder> rootMsgFolder;
nsCOMPtr<nsIMsgFolder> 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<nsISupportsArray> allDescendents;
NS_NewISupportsArray(getter_AddRefs(allDescendents));
rv = folder->ListDescendents(allDescendents);
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 cnt =0;
allDescendents->Count(&cnt);
nsCOMPtr<nsISupports> supports;
nsCOMPtr<nsIMsgFolder> 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(nsIRDFResource *parentItem, nsISupports *item)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsRssIncomingServer::OnItemPropertyChanged(nsIRDFResource *item, nsIAtom *property, const char *oldValue, const char *newValue)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsRssIncomingServer::OnItemIntPropertyChanged(nsIRDFResource *item, nsIAtom *property, PRInt32 oldValue, PRInt32 newValue)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsRssIncomingServer::OnItemBoolPropertyChanged(nsIRDFResource *item, nsIAtom *property, PRBool oldValue, PRBool newValue)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsRssIncomingServer::OnItemUnicharPropertyChanged(nsIRDFResource *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;
}

View File

@ -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 */