Bug #252859 --> Add support for dropping RSS urls onto RSS servers and folders to automatically subscribe to the feed.

Bug #252860 --> Add error reporting to alert the user when the feed url could not be downloaded or if the feed url wasn't an rss type we could understand.

sr=bienvenu
This commit is contained in:
scott%scott-macgregor.org 2004-07-24 19:58:43 +00:00
parent 8ad0b5d01a
commit 0f6bca050a
7 changed files with 190 additions and 92 deletions

View File

@ -14,6 +14,12 @@ var serializer =
.classes["@mozilla.org/xmlextras/xmlserializer;1"] .classes["@mozilla.org/xmlextras/xmlserializer;1"]
.createInstance(Components.interfaces.nsIDOMSerializer); .createInstance(Components.interfaces.nsIDOMSerializer);
// error codes used to inform the consumer about attempts to download a feed
const kNewsBlogSuccess = 0;
const kNewsBlogInvalidFeed = 1; // usually means there was an error trying to parse the feed...
const kNewsBlogRequestFailure = 2; // generic networking failure when trying to download the feed.
// Hash of feeds being downloaded, indexed by URL, so the load event listener // Hash of feeds being downloaded, indexed by URL, so the load event listener
// can access the Feed objects after it finishes downloading the feed files. // can access the Feed objects after it finishes downloading the feed files.
var gFzFeedCache = new Object(); var gFzFeedCache = new Object();
@ -57,19 +63,27 @@ Feed.prototype.name getter = function() {
} }
Feed.prototype.download = function(parseItems, aCallback) { Feed.prototype.download = function(parseItems, aCallback) {
this.downloadCallback = aCallback; // may be null
// Whether or not to parse items when downloading and parsing the feed. // Whether or not to parse items when downloading and parsing the feed.
// Defaults to true, but setting to false is useful for obtaining // Defaults to true, but setting to false is useful for obtaining
// just the title of the feed when the user subscribes to it. // just the title of the feed when the user subscribes to it.
this.parseItems = parseItems == null ? true : parseItems ? true : false; this.parseItems = parseItems == null ? true : parseItems ? true : false;
// Before we do anything...make sure the url is an http url. This is just a sanity check
// so we don't try opening mailto urls, imap urls, etc. that the user may have tried to subscribe to
// as an rss feed..
var uri = Components.classes["@mozilla.org/network/standard-url;1"].
createInstance(Components.interfaces.nsIURI);
uri.spec = this.url;
if (!uri.schemeIs("http"))
return this.onParseError(this); // simulate an invalid feed error
this.request = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"] this.request = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Components.interfaces.nsIXMLHttpRequest); .createInstance(Components.interfaces.nsIXMLHttpRequest);
this.request.onprogress = Feed.onProgress; // must be set before calling .open this.request.onprogress = Feed.onProgress; // must be set before calling .open
this.request.open("GET", this.url, true); this.request.open("GET", this.url, true);
this.downloadCallback = aCallback; // may be null
this.request.overrideMimeType("text/xml"); this.request.overrideMimeType("text/xml");
this.request.onload = Feed.onDownloaded; this.request.onload = Feed.onDownloaded;
this.request.onerror = Feed.onDownloadError; this.request.onerror = Feed.onDownloadError;
@ -100,17 +114,13 @@ Feed.onProgress = function(event) {
} }
Feed.onDownloadError = function(event) { Feed.onDownloadError = function(event) {
// XXX add error message if available and notify the user? if (feed.downloadCallback)
var request = event.target; feed.downloadCallback.downloaded(feed, kNewsBlogRequestFailure);
var url = request.channel.originalURI.spec; }
var feed = gFzFeedCache[url];
if (feed) Feed.prototype.onParseError = function(feed) {
{ if (feed && feed.downloadCallback)
debug(feed.title + " download failed"); feed.downloadCallback.downloaded(feed, kNewsBlogInvalidFeed);
if (feed.downloadCallback)
feed.downloaded(feed, false);
}
throw("error downloading feed " + url);
} }
Feed.prototype.url getter = function() { Feed.prototype.url getter = function() {
@ -159,8 +169,7 @@ Feed.prototype.parse = function() {
debug("parsing feed " + this.url); debug("parsing feed " + this.url);
if (!this.request.responseText) { if (!this.request.responseText) {
throw("error parsing feed " + this.url + ": no data"); return this.onParseError(this);
return;
} }
else if (this.request.responseText.search(/="http:\/\/purl\.org\/rss\/1\.0\/"/) != -1) { else if (this.request.responseText.search(/="http:\/\/purl\.org\/rss\/1\.0\/"/) != -1) {
debug(this.url + " is an RSS 1.x (RDF-based) feed"); debug(this.url + " is an RSS 1.x (RDF-based) feed");
@ -192,12 +201,12 @@ Feed.prototype.parse = function() {
Feed.prototype.parseAsRSS2 = function() { Feed.prototype.parseAsRSS2 = function() {
if (!this.request.responseXML || !(this.request.responseXML instanceof Components.interfaces.nsIDOMXMLDocument)) if (!this.request.responseXML || !(this.request.responseXML instanceof Components.interfaces.nsIDOMXMLDocument))
throw("error parsing RSS 2.0 feed " + this.url + ": data not parsed into XMLDocument object"); return this.onParseError(this);
// Get the first channel (assuming there is only one per RSS File). // Get the first channel (assuming there is only one per RSS File).
var channel = this.request.responseXML.getElementsByTagName("channel")[0]; var channel = this.request.responseXML.getElementsByTagName("channel")[0];
if (!channel) if (!channel)
throw("error parsing RSS 2.0 feed " + this.url + ": channel element missing"); return this.onParseError(this);
this.title = this.title || getNodeValue(channel.getElementsByTagName("title")[0]); this.title = this.title || getNodeValue(channel.getElementsByTagName("title")[0]);
this.description = getNodeValue(channel.getElementsByTagName("description")[0]); this.description = getNodeValue(channel.getElementsByTagName("description")[0]);
@ -311,12 +320,12 @@ Feed.prototype.parseAsRSS1 = function() {
Feed.prototype.parseAsAtom = function() { Feed.prototype.parseAsAtom = function() {
if (!this.request.responseXML || !(this.request.responseXML instanceof Components.interfaces.nsIDOMXMLDocument)) if (!this.request.responseXML || !(this.request.responseXML instanceof Components.interfaces.nsIDOMXMLDocument))
throw("error parsing Atom feed " + this.url + ": data not parsed into XMLDocument object"); return this.onParseError(this);
// Get the first channel (assuming there is only one per Atom File). // Get the first channel (assuming there is only one per Atom File).
var channel = this.request.responseXML.getElementsByTagName("feed")[0]; var channel = this.request.responseXML.getElementsByTagName("feed")[0];
if (!channel) if (!channel)
throw("channel missing from Atom feed " + request.channel.name); return this.onParseError(this);
this.title = this.title || getNodeValue(channel.getElementsByTagName("title")[0]); this.title = this.title || getNodeValue(channel.getElementsByTagName("title")[0]);
this.description = getNodeValue(channel.getElementsByTagName("tagline")[0]); this.description = getNodeValue(channel.getElementsByTagName("tagline")[0]);
@ -443,6 +452,7 @@ Feed.prototype.removeInvalidItems = function() {
var gItemsToStore; var gItemsToStore;
var gItemsToStoreIndex = 0; var gItemsToStoreIndex = 0;
var gStoreItemsTimer;
// gets the next item from gItemsToStore and forces that item to be stored // gets the next item from gItemsToStore and forces that item to be stored
// to the folder. If more items are left to be stored, fires a timer for the next one. // to the folder. If more items are left to be stored, fires a timer for the next one.
@ -463,20 +473,16 @@ function storeNextItem()
if (gItemsToStoreIndex < gItemsToStore.length) if (gItemsToStoreIndex < gItemsToStore.length)
{ {
if ('setTimeout' in this) if (!gStoreItemsTimer)
setTimeout(storeNextItem, 50); // fire off a timer for the next item to store gStoreItemsTimer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
else gStoreItemsTimer.initWithCallback(storeNextItemTimerCallback, 50, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
{
debug('set timeout is not defined if this call originated from newsblog.js\n');
storeNextItem();
}
} }
else else
{ {
item.feed.removeInvalidItems(); item.feed.removeInvalidItems();
if (item.feed.downloadCallback) if (item.feed.downloadCallback)
item.feed.downloadCallback.downloaded(item.feed, true); item.feed.downloadCallback.downloaded(item.feed, kNewsBlogSuccess);
item.feed.request = null; // force the xml http request to go away. This helps reduce some item.feed.request = null; // force the xml http request to go away. This helps reduce some
// nasty assertions on shut down of all things. // nasty assertions on shut down of all things.
@ -485,3 +491,17 @@ function storeNextItem()
gItemsToStoreIndex = 0; gItemsToStoreIndex = 0;
} }
} }
var storeNextItemTimerCallback = {
notify: function(aTimer) {
storeNextItem();
},
QueryInterface: function(aIID) {
if (aIID.equals(Components.interfaces.nsITimerCallback) || aIID.equals(Components.interfaces.nsISupports))
return this;
Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE;
return null;
}
}

View File

@ -34,7 +34,6 @@
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
var kFeedUrlDelimiter = '|'; // the delimiter used to delimit feed urls in the msg folder database "feedUrl" property
var gRSSServer = null; var gRSSServer = null;
function doLoad() { function doLoad() {
@ -74,10 +73,10 @@ function clearStatusInfo()
} }
var feedDownloadCallback = { var feedDownloadCallback = {
downloaded: function(feed, aSuccess) downloaded: function(feed, aErrorCode)
{ {
// feed is null if our attempt to parse the feed failed // feed is null if our attempt to parse the feed failed
if (aSuccess) if (aErrorCode == kNewsBlogSuccess)
{ {
updateStatusItem('progressMeter', 100); updateStatusItem('progressMeter', 100);
@ -91,10 +90,10 @@ var feedDownloadCallback = {
// it also flushes the subscription datasource // it also flushes the subscription datasource
addFeed(feed.url, feed.name, null, folder); addFeed(feed.url, feed.name, null, folder);
} }
else else if (aErrorCode == kNewsBlogInvalidFeed) // the feed was bad...
{ window.alert(document.getElementById('bundle_newsblog').getFormattedString('newsblog-invalidFeed', [feed.url]));
// Add some code to alert the user that the feed was not something we could understand... else // we never even downloaded the feed...(kNewsBlogRequestFailure)
} window.alert(document.getElementById('bundle_newsblog').getFormattedString('newsblog-networkError', [feed.url]));
// our operation is done...clear out the status text and progressmeter // our operation is done...clear out the status text and progressmeter
setTimeout(clearStatusInfo, 1000); setTimeout(clearStatusInfo, 1000);
@ -116,23 +115,6 @@ var feedDownloadCallback = {
}, },
} }
// updates the "feedUrl" property in the message database for the folder in question.
function updateFolderFeedUrl(aFolder, aFeedUrl, aRemoveUrl)
{
var msgdb = aFolder.QueryInterface(Components.interfaces.nsIMsgFolder).getMsgDatabase(null);
var folderInfo = msgdb.dBFolderInfo;
var oldFeedUrl = folderInfo.getCharPtrProperty("feedUrl");
if (aRemoveUrl)
{
// remove our feed url string from the list of feed urls
var newFeedUrl = oldFeedUrl.replace(kFeedUrlDelimiter + aFeedUrl, "");
folderInfo.setCharPtrProperty("feedUrl", newFeedUrl);
}
else
folderInfo.setCharPtrProperty("feedUrl", oldFeedUrl + kFeedUrlDelimiter + aFeedUrl);
}
function doAdd() { function doAdd() {
var userAddedFeed = false; var userAddedFeed = false;
var feedProperties = { feedName: "", feedLocation: "", serverURI: gRSSServer.serverURI, folderURI: "", result: userAddedFeed}; var feedProperties = { feedName: "", feedLocation: "", serverURI: gRSSServer.serverURI, folderURI: "", result: userAddedFeed};

View File

@ -88,6 +88,25 @@ function addFeed(url, title, quickMode, destFolder) {
ds.Flush(); ds.Flush();
} }
// updates the "feedUrl" property in the message database for the folder in question.
var kFeedUrlDelimiter = '|'; // the delimiter used to delimit feed urls in the msg folder database "feedUrl" property
function updateFolderFeedUrl(aFolder, aFeedUrl, aRemoveUrl)
{
var msgdb = aFolder.QueryInterface(Components.interfaces.nsIMsgFolder).getMsgDatabase(null);
var folderInfo = msgdb.dBFolderInfo;
var oldFeedUrl = folderInfo.getCharPtrProperty("feedUrl");
if (aRemoveUrl)
{
// remove our feed url string from the list of feed urls
var newFeedUrl = oldFeedUrl.replace(kFeedUrlDelimiter + aFeedUrl, "");
folderInfo.setCharPtrProperty("feedUrl", newFeedUrl);
}
else
folderInfo.setCharPtrProperty("feedUrl", oldFeedUrl + kFeedUrlDelimiter + aFeedUrl);
}
function getNodeValue(node) { function getNodeValue(node) {
if (node && node.textContent) if (node && node.textContent)

View File

@ -51,7 +51,7 @@ var nsNewsBlogFeedDownloader =
var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"] var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"]
.getService(Components.interfaces.nsIRDFService); .getService(Components.interfaces.nsIRDFService);
progressNotifier.init(aMsgWindow.statusFeedback); progressNotifier.init(aMsgWindow.statusFeedback, false);
var index = 0; var index = 0;
for (url in feedUrlArray) for (url in feedUrlArray)
@ -68,6 +68,23 @@ var nsNewsBlogFeedDownloader =
} }
}, },
subscribeToFeed: function(aUrl, aFolder, aMsgWindow)
{
if (!gExternalScriptsLoaded)
loadScripts();
var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"]
.getService(Components.interfaces.nsIRDFService);
var itemResource = rdf.GetResource(aUrl);
var feed = new Feed(itemResource);
feed.server = aFolder.server;
if (!aFolder.server.isServer) // if the root server, create a new folder for the feed
feed.folder = aFolder; // user must want us to add this subscription url to an existing RSS folder.
progressNotifier.init(aMsgWindow.statusFeedback, true);
feed.download(true, progressNotifier);
},
QueryInterface: function(aIID) QueryInterface: function(aIID)
{ {
if (aIID.equals(Components.interfaces.nsINewsBlogFeedDownloader) || if (aIID.equals(Components.interfaces.nsINewsBlogFeedDownloader) ||
@ -222,33 +239,52 @@ function loadScripts()
var gNumPendingFeedDownloads = 0; var gNumPendingFeedDownloads = 0;
var progressNotifier = { var progressNotifier = {
mSubscribeMode: false,
mStatusFeedback: null, mStatusFeedback: null,
mFeeds: new Array, mFeeds: new Array,
init: function(aStatusFeedback) init: function(aStatusFeedback, aSubscribeMode)
{ {
if (!gNumPendingFeedDownloads) // if we aren't already in the middle of downloading feed items... if (!gNumPendingFeedDownloads) // if we aren't already in the middle of downloading feed items...
{ {
this.mStatusFeedback = aStatusFeedback; this.mStatusFeedback = aStatusFeedback;
this.mSubscribeMode = aSubscribeMode;
this.mStatusFeedback.startMeteors(); this.mStatusFeedback.startMeteors();
this.mStatusFeedback.showStatusString(GetString('newsblog-getNewMailCheck'));
this.mStatusFeedback.showStatusString(aSubscribeMode ? GetNewsBlogStringBundle().GetStringFromName('subscribe-validating')
: GetNewsBlogStringBundle().GetStringFromName('newsblog-getNewMailCheck'));
} }
}, },
downloaded: function(feed) downloaded: function(feed, aErrorCode)
{ {
if (this.mSubscribeMode && aErrorCode == kNewsBlogSuccess)
{
// if we get here...we should always have a folder by now...either
// in feed.folder or FeedItems created the folder for us....
var folder = feed.folder ? feed.folder : feed.server.rootMsgFolder.getChildNamed(feed.name);
updateFolderFeedUrl(folder, feed.url, false);
addFeed(feed.url, feed.name, null, folder); // add feed just adds the feed to the subscription UI and flushes the datasource
}
else if (aErrorCode == kNewsBlogInvalidFeed)
this.mStatusFeedback.showStatusString(GetNewsBlogStringBundle().formatStringFromName("newsblog-invalidFeed",
[feed.url], 1));
else if (aErrorCode == kNewsBlogRequestFailure)
this.mStatusFeedback.showStatusString(GetNewsBlogStringBundle().formatStringFromName("newsblog-networkError",
[feed.url], 1));
this.mStatusFeedback.stopMeteors(); this.mStatusFeedback.stopMeteors();
gNumPendingFeedDownloads--; gNumPendingFeedDownloads--;
if (!gNumPendingFeedDownloads) if (!gNumPendingFeedDownloads)
{ {
this.mFeeds = new Array; this.mFeeds = new Array;
// no more pending actions...clear the status bar text...should we do this on a timer this.mSubscribeMode = false;
// so the text sticks around for a little while? It doesnt look like we do it on a timer for
// newsgroups so we'll follow that model.
this.mStatusFeedback.showStatusString(""); // should we do this on a timer so the text sticks around for a little while?
// It doesnt look like we do it on a timer for newsgroups so we'll follow that model.
if (aErrorCode == kNewsBlogSuccess) // don't clear the status text if we just dumped an error to the status bar!
this.mStatusFeedback.showStatusString("");
} }
}, },
@ -259,6 +295,12 @@ var progressNotifier = {
{ {
// we currently don't do anything here. Eventually we may add // we currently don't do anything here. Eventually we may add
// status text about the number of new feed articles received. // status text about the number of new feed articles received.
if (this.mSubscribeMode) // if we are subscribing to a feed, show feed download progress
{
this.mStatusFeedback.showStatusString(GetNewsBlogStringBundle().formatStringFromName("subscribe-fetchingFeedItems", [aCurrentFeedItems, aMaxFeedItems], 2));
this.onProgress(feed, aCurrentFeedItems, aMaxFeedItems);
}
}, },
onProgress: function(feed, aProgress, aProgressMax) onProgress: function(feed, aProgress, aProgressMax)
@ -292,10 +334,10 @@ var progressNotifier = {
} }
} }
function GetString(name) function GetNewsBlogStringBundle(name)
{ {
var strBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(); var strBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"].getService();
strBundleService = strBundleService.QueryInterface(Components.interfaces.nsIStringBundleService); strBundleService = strBundleService.QueryInterface(Components.interfaces.nsIStringBundleService);
var strBundle = strBundleService.createBundle("chrome://messenger-newsblog/locale/newsblog.properties"); var strBundle = strBundleService.createBundle("chrome://messenger-newsblog/locale/newsblog.properties");
return strBundle.GetStringFromName(name); return strBundle;
} }

View File

@ -1,6 +1,6 @@
# Status strings used in the subscribe dialog # Status strings used in the subscribe dialog
subscribe-validating=Verifying the feed... subscribe-validating=Verifying the RSS feed...
# when downloading new feed items from the subscribe dialog. # when downloading new feed items from the subscribe dialog.
# LOCALIZATION NOTE: Do not translate %d in the following line. # LOCALIZATION NOTE: Do not translate %d in the following line.
@ -8,4 +8,6 @@ subscribe-validating=Verifying the feed...
# the second %S will receive the total number of messages # the second %S will receive the total number of messages
subscribe-fetchingFeedItems=Downloading feed articles (%S of %S) subscribe-fetchingFeedItems=Downloading feed articles (%S of %S)
newsblog-invalidFeed=%S is not a valid RSS feed.
newsblog-networkError=%S could not be found. Please check the name and try again.
newsblog-getNewMailCheck=Checking RSS feeds for new items newsblog-getNewMailCheck=Checking RSS feeds for new items

View File

@ -69,6 +69,7 @@ function CanDropOnFolderTree(index, orientation)
trans.addDataFlavor("text/x-moz-message"); trans.addDataFlavor("text/x-moz-message");
trans.addDataFlavor("text/x-moz-folder"); trans.addDataFlavor("text/x-moz-folder");
trans.addDataFlavor("text/x-moz-url");
var folderTree = GetFolderTree(); var folderTree = GetFolderTree();
var targetResource = GetFolderResource(folderTree, index); var targetResource = GetFolderResource(folderTree, index);
@ -121,33 +122,43 @@ function CanDropOnFolderTree(index, orientation)
if (hdr.folder == targetFolder) if (hdr.folder == targetFolder)
return false; return false;
break; break;
} else if (dataFlavor.value == "text/x-moz-folder") {
// we should only get here if we are dragging and dropping folders
dragFolder = true;
sourceResource = RDF.GetResource(sourceUri);
var sourceFolder = sourceResource.QueryInterface(Components.interfaces.nsIMsgFolder);
sourceServer = sourceFolder.server;
if (targetUri == sourceUri)
return false;
//don't allow drop on different imap servers.
if (sourceServer != targetServer && targetServer.type == "imap")
return false;
//don't allow immediate child to be dropped to it's parent
if (targetFolder.URI == sourceFolder.parent.URI)
{
debugDump(targetFolder.URI + "\n");
debugDump(sourceFolder.parent.URI + "\n");
return false;
}
var isAncestor = sourceFolder.isAncestorOf(targetFolder);
// don't allow parent to be dropped on its ancestors
if (isAncestor)
return false;
} else if (dataFlavor.value == "text/x-moz-url") {
// eventually check to make sure this is an http url before doing anything else...
var uri = Components.classes["@mozilla.org/network/standard-url;1"].
createInstance(Components.interfaces.nsIURI);
var url = sourceUri.split("\n")[0];
uri.spec = url;
if (uri.schemeIs("http") && targetServer && targetServer.type == 'rss')
return true;
} }
// we should only get here if we are dragging and dropping folders
dragFolder = true;
sourceResource = RDF.GetResource(sourceUri);
var sourceFolder = sourceResource.QueryInterface(Components.interfaces.nsIMsgFolder);
sourceServer = sourceFolder.server;
if (targetUri == sourceUri)
return false;
//don't allow drop on different imap servers.
if (sourceServer != targetServer && targetServer.type == "imap")
return false;
//don't allow immediate child to be dropped to it's parent
if (targetFolder.URI == sourceFolder.parent.URI)
{
debugDump(targetFolder.URI + "\n");
debugDump(sourceFolder.parent.URI + "\n");
return false;
}
var isAncestor = sourceFolder.isAncestorOf(targetFolder);
// don't allow parent to be dropped on its ancestors
if (isAncestor)
return false;
} }
if (dragFolder) if (dragFolder)
@ -198,6 +209,8 @@ function DropOnFolderTree(row, orientation)
var folderTree = GetFolderTree(); var folderTree = GetFolderTree();
var targetResource = GetFolderResource(folderTree, row); var targetResource = GetFolderResource(folderTree, row);
var targetFolder = targetResource.QueryInterface(Components.interfaces.nsIMsgFolder);
var targetServer = targetFolder.server;
var targetUri = targetResource.Value; var targetUri = targetResource.Value;
debugDump("***targetUri = " + targetUri + "\n"); debugDump("***targetUri = " + targetUri + "\n");
@ -209,6 +222,7 @@ function DropOnFolderTree(row, orientation)
var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable); var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
trans.addDataFlavor("text/x-moz-message"); trans.addDataFlavor("text/x-moz-message");
trans.addDataFlavor("text/x-moz-folder"); trans.addDataFlavor("text/x-moz-folder");
trans.addDataFlavor("text/x-moz-url");
var list = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray); var list = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray);
@ -248,6 +262,24 @@ function DropOnFolderTree(row, orientation)
} }
else if (flavor.value == "text/x-moz-message") else if (flavor.value == "text/x-moz-message")
dropMessage = true; dropMessage = true;
else if (flavor.value == "text/x-moz-url")
{
var uri = Components.classes["@mozilla.org/network/standard-url;1"].
createInstance(Components.interfaces.nsIURI);
var url = sourceUri.split("\n")[0];
uri.spec = url;
if (uri.schemeIs("http") && targetServer && targetServer.type == 'rss')
{
var rssService = Components.classes["@mozilla.org/newsblog-feed-downloader;1"].getService().
QueryInterface(Components.interfaces.nsINewsBlogFeedDownloader);
if (rssService)
rssService.subscribeToFeed(url, targetFolder, msgWindow);
return true;
}
else
return false;
}
} }
else { else {
if (!dropMessage) if (!dropMessage)
@ -273,9 +305,6 @@ function DropOnFolderTree(row, orientation)
var isSourceNews = false; var isSourceNews = false;
isSourceNews = isNewsURI(sourceUri); isSourceNews = isNewsURI(sourceUri);
var targetFolder = targetResource.QueryInterface(Components.interfaces.nsIMsgFolder);
var targetServer = targetFolder.server;
if (dropMessage) { if (dropMessage) {
var sourceMsgHdr = list.GetElementAt(0).QueryInterface(Components.interfaces.nsIMsgDBHdr); var sourceMsgHdr = list.GetElementAt(0).QueryInterface(Components.interfaces.nsIMsgDBHdr);

View File

@ -46,5 +46,9 @@ interface nsINewsBlogFeedDownloader : nsISupports
void downloadFeed(in string aUrl, in nsIMsgFolder aFolder, void downloadFeed(in string aUrl, in nsIMsgFolder aFolder,
in boolean aQuickMode, in wstring aTitle, in boolean aQuickMode, in wstring aTitle,
in nsIUrlListener aUrlListener, in nsIMsgWindow aMsgWindow); in nsIUrlListener aUrlListener, in nsIMsgWindow aMsgWindow);
/* 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);
}; };