зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
79b7376653
Коммит
779ba78259
|
@ -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);
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) ||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
Загрузка…
Ссылка в новой задаче