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
Родитель 79b7376653
Коммит 779ba78259
7 изменённых файлов: 214 добавлений и 21 удалений

Просмотреть файл

@ -481,6 +481,10 @@ function storeNextItem()
{ {
item.feed.removeInvalidItems(); 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) if (item.feed.downloadCallback)
item.feed.downloadCallback.downloaded(item.feed, kNewsBlogSuccess); item.feed.downloadCallback.downloaded(item.feed, kNewsBlogSuccess);

Просмотреть файл

@ -37,6 +37,7 @@
<dialog id="feedPropertyDialog" <dialog id="feedPropertyDialog"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 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" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&window.title;" title="&window.title;"
style="width: 27em;" style="width: 27em;"
@ -73,6 +74,24 @@
datasources="rdf:msgaccountmanager rdf:mailnewsfolders" datasources="rdf:msgaccountmanager rdf:mailnewsfolders"
ref="..."> ref="...">
<template> <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>
<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> <menupopup>
<menuitem uri="..." value="..." <menuitem uri="..." value="..."
class="folderMenuItem menuitem-iconic" class="folderMenuItem menuitem-iconic"
@ -84,11 +103,10 @@
ServerType="rdf:http://home.netscape.com/NC-rdf#ServerType" ServerType="rdf:http://home.netscape.com/NC-rdf#ServerType"
label="rdf:http://home.netscape.com/NC-rdf#Name"/> label="rdf:http://home.netscape.com/NC-rdf#Name"/>
</menupopup> </menupopup>
</rule>
</template> </template>
</menulist> </menulist>
</row> </row>
<!-- Eventually we'll add a folder picker here to pick the folder associated with the feed -->
</rows> </rows>
</grid> </grid>
</dialog> </dialog>

Просмотреть файл

@ -106,6 +106,9 @@ function updateFolderFeedUrl(aFolder, aFeedUrl, aRemoveUrl)
} }
else else
folderInfo.setCharPtrProperty("feedUrl", oldFeedUrl + kFeedUrlDelimiter + aFeedUrl); folderInfo.setCharPtrProperty("feedUrl", oldFeedUrl + kFeedUrlDelimiter + aFeedUrl);
// commit the db to preserve our changes
msgdb.Close(true);
} }
function getNodeValue(node) { function getNodeValue(node) {

Просмотреть файл

@ -85,6 +85,45 @@ var nsNewsBlogFeedDownloader =
feed.download(true, progressNotifier); 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) QueryInterface: function(aIID)
{ {
if (aIID.equals(Components.interfaces.nsINewsBlogFeedDownloader) || if (aIID.equals(Components.interfaces.nsINewsBlogFeedDownloader) ||

Просмотреть файл

@ -50,5 +50,10 @@ interface nsINewsBlogFeedDownloader : nsISupports
/* A convient method to subscribe to feeds without going through the subscribe UI /* A convient method to subscribe to feeds without going through the subscribe UI
used by drag and drop */ used by drag and drop */
void subscribeToFeed(in string aUrl, in nsIMsgFolder aFolder, in nsIMsgWindow aMsgWindow); 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);
}; };

Просмотреть файл

@ -39,22 +39,44 @@
#include "nsRssIncomingServer.h" #include "nsRssIncomingServer.h"
#include "nsMsgFolderFlags.h" #include "nsMsgFolderFlags.h"
#include "nsINewsBlogFeedDownloader.h" #include "nsINewsBlogFeedDownloader.h"
#include "nsIMsgMailSession.h"
#include "nsMsgBaseCID.h"
#include "nsIMsgLocalMailFolder.h" #include "nsIMsgLocalMailFolder.h"
#include "nsIDBFolderInfo.h" #include "nsIDBFolderInfo.h"
NS_IMPL_ISUPPORTS_INHERITED2(nsRssIncomingServer, nsrefcnt nsRssIncomingServer::gInstanceCount = 0;
NS_IMPL_ISUPPORTS_INHERITED3(nsRssIncomingServer,
nsMsgIncomingServer, nsMsgIncomingServer,
nsIRssIncomingServer, nsIRssIncomingServer,
nsIFolderListener,
nsILocalMailIncomingServer) nsILocalMailIncomingServer)
nsRssIncomingServer::nsRssIncomingServer() nsRssIncomingServer::nsRssIncomingServer()
{ {
m_canHaveFilters = PR_TRUE; 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() 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) nsresult nsRssIncomingServer::FillInDataSourcePath(const nsAString& aDataSourceName, nsILocalFile ** aLocation)
@ -135,25 +157,28 @@ NS_IMETHODIMP nsRssIncomingServer::PerformBiff(nsIMsgWindow *aMsgWindow)
GetRootMsgFolder(getter_AddRefs(rootRSSFolder)); GetRootMsgFolder(getter_AddRefs(rootRSSFolder));
// enumerate over the RSS folders and ping each one // enumerate over the RSS folders and ping each one
nsCOMPtr<nsIEnumerator> folderEnumerator; nsCOMPtr<nsISupportsArray> allDescendents;
rv = rootRSSFolder->GetSubFolders(getter_AddRefs(folderEnumerator)); NS_NewISupportsArray(getter_AddRefs(allDescendents));
rv = rootRSSFolder->ListDescendents(allDescendents);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
nsresult more = folderEnumerator->First(); PRUint32 cnt =0;
allDescendents->Count(&cnt);
nsCOMPtr<nsISupports> supports; nsCOMPtr<nsISupports> supports;
nsCOMPtr<nsIUrlListener> urlListener; nsCOMPtr<nsIUrlListener> urlListener;
nsCOMPtr<nsIMsgFolder> rssFolder;
while (NS_SUCCEEDED(more)) for (PRUint32 index = 0; index < cnt; index++)
{ {
rv = folderEnumerator->CurrentItem(getter_AddRefs(supports)); supports = getter_AddRefs(allDescendents->ElementAt(index));
nsCOMPtr<nsIMsgFolder> rssFolder = do_QueryInterface(supports); rssFolder = do_QueryInterface(supports, &rv);
if (rssFolder) if (rssFolder)
{ {
urlListener = do_QueryInterface(rssFolder); urlListener = do_QueryInterface(rssFolder);
// WARNING: Never call GetNewMail with the root folder or you will trigger an infinite loop... // WARNING: Never call GetNewMail with the root folder or you will trigger an infinite loop...
GetNewMail(aMsgWindow, urlListener, rssFolder, nsnull); GetNewMail(aMsgWindow, urlListener, rssFolder, nsnull);
} }
more = folderEnumerator->Next();
} }
return NS_OK; return NS_OK;
@ -226,3 +251,99 @@ NS_IMETHODIMP nsRssIncomingServer::GetSupportsDiskSpace(PRBool *aSupportsDiskSpa
*aSupportsDiskSpace = PR_FALSE; *aSupportsDiskSpace = PR_FALSE;
return NS_OK; 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;
}

Просмотреть файл

@ -40,17 +40,19 @@
#include "nsIRssIncomingServer.h" #include "nsIRssIncomingServer.h"
#include "nsILocalMailIncomingServer.h" #include "nsILocalMailIncomingServer.h"
#include "nsMsgIncomingServer.h" #include "nsMsgIncomingServer.h"
#include "nsIFolderListener.h"
class nsRssIncomingServer : public nsMsgIncomingServer, class nsRssIncomingServer : public nsMsgIncomingServer,
public nsIRssIncomingServer, public nsIRssIncomingServer,
public nsILocalMailIncomingServer public nsILocalMailIncomingServer,
public nsIFolderListener
{ {
public: public:
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIRSSINCOMINGSERVER NS_DECL_NSIRSSINCOMINGSERVER
NS_DECL_NSILOCALMAILINCOMINGSERVER NS_DECL_NSILOCALMAILINCOMINGSERVER
NS_DECL_NSIFOLDERLISTENER
NS_IMETHOD GetLocalStoreType(char **); NS_IMETHOD GetLocalStoreType(char **);
NS_IMETHOD GetOfflineSupportLevel(PRInt32 *aSupportLevel); NS_IMETHOD GetOfflineSupportLevel(PRInt32 *aSupportLevel);
@ -62,6 +64,7 @@ public:
virtual ~nsRssIncomingServer(); virtual ~nsRssIncomingServer();
protected: protected:
nsresult FillInDataSourcePath(const nsAString& aDataSourceName, nsILocalFile ** aLocation); nsresult FillInDataSourcePath(const nsAString& aDataSourceName, nsILocalFile ** aLocation);
static nsrefcnt gInstanceCount;
}; };
#endif /* __nsRssIncomingServer_h */ #endif /* __nsRssIncomingServer_h */