Bug 721517 - Convert mailnews/extensions/newsblog/content to Services.jsm and mailServices.js. Also fix global scope. r=dbienvenu, neil
This commit is contained in:
Родитель
a659d92c52
Коммит
502cebd462
|
@ -3249,16 +3249,14 @@ function FeedSetContentView(val)
|
|||
if (wintype == "mail:3pane") {
|
||||
// Get quickmode per feed pref from feeds.rdf
|
||||
var quickMode, targetRes;
|
||||
var scriptLoader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
|
||||
.getService(Components.interfaces.mozIJSSubScriptLoader);
|
||||
if (scriptLoader && typeof FZ_NS == 'undefined')
|
||||
scriptLoader.loadSubScript("chrome://messenger-newsblog/content/utils.js");
|
||||
if (!("FeedUtils" in window))
|
||||
Services.scriptloader.loadSubScript("chrome://messenger-newsblog/content/utils.js");
|
||||
try
|
||||
{
|
||||
var targetRes = getParentTargetForChildResource(
|
||||
gFolderDisplay.displayedFolder.URI,
|
||||
FZ_QUICKMODE,
|
||||
gFolderDisplay.displayedFolder.server);
|
||||
var targetRes = FeedUtils.getParentTargetForChildResource(
|
||||
gFolderDisplay.displayedFolder.URI,
|
||||
FeedUtils.FZ_QUICKMODE,
|
||||
gFolderDisplay.displayedFolder.server);
|
||||
}
|
||||
catch (ex) {};
|
||||
|
||||
|
|
|
@ -35,17 +35,10 @@
|
|||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
// 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.
|
||||
const kNewsBlogFeedIsBusy = 3;
|
||||
const kNewsBlogNoNewItems = 4; // there are no new articles for this feed
|
||||
|
||||
// Cache for all of the feeds currently being downloaded, indexed by URL, so the load event listener
|
||||
// can access the Feed objects after it finishes downloading the feed.
|
||||
var FeedCache =
|
||||
// Cache for all of the feeds currently being downloaded, indexed by URL,
|
||||
// so the load event listener can access the Feed objects after it finishes
|
||||
// downloading the feed.
|
||||
var FeedCache =
|
||||
{
|
||||
mFeeds: {},
|
||||
|
||||
|
@ -56,7 +49,7 @@ var FeedCache =
|
|||
|
||||
getFeed: function (aUrl)
|
||||
{
|
||||
var index = this.normalizeHost(aUrl);
|
||||
let index = this.normalizeHost(aUrl);
|
||||
if (index in this.mFeeds)
|
||||
return this.mFeeds[index];
|
||||
return null;
|
||||
|
@ -64,7 +57,7 @@ var FeedCache =
|
|||
|
||||
removeFeed: function (aUrl)
|
||||
{
|
||||
var index = this.normalizeHost(aUrl);
|
||||
let index = this.normalizeHost(aUrl);
|
||||
if (index in this.mFeeds)
|
||||
delete this.mFeeds[index];
|
||||
},
|
||||
|
@ -84,9 +77,9 @@ var FeedCache =
|
|||
}
|
||||
};
|
||||
|
||||
function Feed(aResource, aRSSServer)
|
||||
function Feed(aResource, aRSSServer)
|
||||
{
|
||||
this.resource = aResource.QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
this.resource = aResource.QueryInterface(Ci.nsIRDFResource);
|
||||
this.server = aRSSServer;
|
||||
}
|
||||
|
||||
|
@ -101,30 +94,33 @@ Feed.prototype =
|
|||
items: new Array(),
|
||||
mFolder: null,
|
||||
mInvalidFeed: false,
|
||||
mFeedType: null,
|
||||
|
||||
get folder()
|
||||
{
|
||||
if (!this.mFolder)
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
this.mFolder = this.server.rootMsgFolder.getChildNamed(this.name);
|
||||
} catch (ex) {}
|
||||
}
|
||||
catch (ex) {}
|
||||
}
|
||||
|
||||
return this.mFolder;
|
||||
},
|
||||
|
||||
set folder (aFolder)
|
||||
set folder (aFolder)
|
||||
{
|
||||
this.mFolder = aFolder;
|
||||
},
|
||||
|
||||
get name()
|
||||
{
|
||||
var name = this.title || this.description || this.url;
|
||||
let name = this.title || this.description || this.url;
|
||||
if (!name)
|
||||
throw("couldn't compute feed name, as feed has no title, description, or URL.");
|
||||
throw new Error("Feed.name: couldn't compute name, as feed has no title, " +
|
||||
"description, or URL.");
|
||||
|
||||
// Make sure the feed name doesn't have any line breaks, since we're going
|
||||
// to use it as the name of the folder in the filesystem. This may not
|
||||
|
@ -139,44 +135,52 @@ Feed.prototype =
|
|||
return name;
|
||||
},
|
||||
|
||||
download: function(aParseItems, aCallback)
|
||||
{
|
||||
this.downloadCallback = aCallback; // may be null
|
||||
download: function(aParseItems, aCallback)
|
||||
{
|
||||
// May be null.
|
||||
this.downloadCallback = aCallback;
|
||||
|
||||
// Whether or not to parse items when downloading and parsing the feed.
|
||||
// Defaults to true, but setting to false is useful for obtaining
|
||||
// just the title of the feed when the user subscribes to it.
|
||||
this.parseItems = aParseItems == null ? true : aParseItems ? 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);
|
||||
// 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.
|
||||
let uri = Cc["@mozilla.org/network/standard-url;1"].
|
||||
createInstance(Ci.nsIURI);
|
||||
uri.spec = this.url;
|
||||
if (!(uri.schemeIs("http") || uri.schemeIs("https")))
|
||||
if (!FeedUtils.isValidScheme(uri))
|
||||
{
|
||||
this.onParseError(this); // simulate an invalid feed error
|
||||
// Simulate an invalid feed error.
|
||||
FeedUtils.log.debug("Feed.download: invalid protocol for - " + uri.spec);
|
||||
this.onParseError(this);
|
||||
return;
|
||||
}
|
||||
|
||||
// Before we try to download the feed, make sure we aren't already processing the feed
|
||||
// by looking up the url in our feed cache
|
||||
// Before we try to download the feed, make sure we aren't already
|
||||
// processing the feed by looking up the url in our feed cache.
|
||||
if (FeedCache.getFeed(this.url))
|
||||
{
|
||||
if (this.downloadCallback)
|
||||
this.downloadCallback.downloaded(this, kNewsBlogFeedIsBusy);
|
||||
return ; // don't do anything, the feed is already in use
|
||||
this.downloadCallback.downloaded(this, FeedUtils.kNewsBlogFeedIsBusy);
|
||||
// Return, the feed is already in use.
|
||||
return;
|
||||
}
|
||||
|
||||
this.request = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Components.interfaces.nsIXMLHttpRequest);
|
||||
this.request.onprogress = this.onProgress; // must be set before calling .open
|
||||
this.request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
|
||||
createInstance(Ci.nsIXMLHttpRequest);
|
||||
// Must set onProgress before calling open.
|
||||
this.request.onprogress = this.onProgress;
|
||||
this.request.open("GET", this.url, true);
|
||||
|
||||
var lastModified = this.lastModified;
|
||||
if (lastModified)
|
||||
this.request.setRequestHeader("If-Modified-Since", lastModified);
|
||||
let lastModified = this.lastModified;
|
||||
// Some servers, if sent If-Modified-Since, will send 304 if subsequently
|
||||
// not sent If-Modified-Since, as in the case of an unsubscribe and new
|
||||
// subscribe. Send 0 to force a download.
|
||||
this.request.setRequestHeader("If-Modified-Since",
|
||||
lastModified ? lastModified : 0);
|
||||
|
||||
// Only order what you're going to eat...
|
||||
this.request.responseType = "document";
|
||||
|
@ -185,95 +189,103 @@ Feed.prototype =
|
|||
this.request.onerror = this.onDownloadError;
|
||||
FeedCache.putFeed(this);
|
||||
this.request.send(null);
|
||||
},
|
||||
},
|
||||
|
||||
onDownloaded: function(aEvent)
|
||||
onDownloaded: function(aEvent)
|
||||
{
|
||||
var request = aEvent.target;
|
||||
var url = request.channel.originalURI.spec;
|
||||
debug(url + " downloaded");
|
||||
if (request.status < 200 || request.status >= 300)
|
||||
let request = aEvent.target;
|
||||
let isHttp = /^http(s?)/.test(request.channel.originalURI.scheme);
|
||||
let url = request.channel.originalURI.spec;
|
||||
if (isHttp && (request.status < 200 || request.status >= 300))
|
||||
{
|
||||
Feed.prototype.onDownloadError(aEvent);
|
||||
return;
|
||||
}
|
||||
var feed = FeedCache.getFeed(url);
|
||||
|
||||
FeedUtils.log.debug("Feed.onDownloaded: got a download - " + url);
|
||||
let feed = FeedCache.getFeed(url);
|
||||
if (!feed)
|
||||
throw("error after downloading " + url + ": couldn't retrieve feed from request");
|
||||
throw new Error("Feed.onDownloaded: error - couldn't retrieve feed " +
|
||||
"from cache");
|
||||
|
||||
// If the server sends a Last-Modified header, store the property on the
|
||||
// feed so we can use it when making future requests, to avoid downloading
|
||||
// and parsing feeds that have not changed.
|
||||
var lastModifiedHeader = request.getResponseHeader('Last-Modified');
|
||||
let lastModifiedHeader = request.getResponseHeader("Last-Modified");
|
||||
if (lastModifiedHeader)
|
||||
feed.lastModified = lastModifiedHeader;
|
||||
|
||||
// The download callback is called asynchronously when parse() is done.
|
||||
feed.parse();
|
||||
},
|
||||
},
|
||||
|
||||
onProgress: function(aEvent)
|
||||
{
|
||||
var request = aEvent.target;
|
||||
var url = request.channel.originalURI.spec;
|
||||
var feed = FeedCache.getFeed(url);
|
||||
let request = aEvent.target;
|
||||
let url = request.channel.originalURI.spec;
|
||||
let feed = FeedCache.getFeed(url);
|
||||
|
||||
if (feed.downloadCallback)
|
||||
feed.downloadCallback.onProgress(feed, aEvent.position, aEvent.totalSize);
|
||||
feed.downloadCallback.onProgress(feed, aEvent.loaded, aEvent.total,
|
||||
aEvent.lengthComputable);
|
||||
},
|
||||
|
||||
onDownloadError: function(aEvent)
|
||||
onDownloadError: function(aEvent)
|
||||
{
|
||||
var request = aEvent.target;
|
||||
var url = request.channel.originalURI.spec;
|
||||
var feed = FeedCache.getFeed(url);
|
||||
let request = aEvent.target;
|
||||
let url = request.channel.originalURI.spec;
|
||||
let feed = FeedCache.getFeed(url);
|
||||
if (feed.downloadCallback)
|
||||
{
|
||||
var error = kNewsBlogRequestFailure;
|
||||
let error = FeedUtils.kNewsBlogRequestFailure;
|
||||
try
|
||||
{
|
||||
if (request.status == 304)
|
||||
// If the http status code is 304, the feed has not been modified
|
||||
// since we last downloaded it and does not need to be parsed.
|
||||
error = kNewsBlogNoNewItems;
|
||||
} catch (ex) {}
|
||||
error = FeedUtils.kNewsBlogNoNewItems;
|
||||
}
|
||||
catch (ex) {}
|
||||
|
||||
feed.downloadCallback.downloaded(feed, error);
|
||||
}
|
||||
|
||||
|
||||
FeedCache.removeFeed(url);
|
||||
},
|
||||
|
||||
onParseError: function(aFeed)
|
||||
onParseError: function(aFeed)
|
||||
{
|
||||
if (aFeed)
|
||||
{
|
||||
aFeed.mInvalidFeed = true;
|
||||
aFeed.lastModified = "";
|
||||
if (!aFeed)
|
||||
return;
|
||||
|
||||
if (aFeed.downloadCallback)
|
||||
aFeed.downloadCallback.downloaded(aFeed, kNewsBlogInvalidFeed);
|
||||
aFeed.mInvalidFeed = true;
|
||||
aFeed.lastModified = "";
|
||||
|
||||
FeedCache.removeFeed(aFeed.url);
|
||||
}
|
||||
if (aFeed.downloadCallback)
|
||||
aFeed.downloadCallback.downloaded(aFeed, FeedUtils.kNewsBlogInvalidFeed);
|
||||
|
||||
FeedCache.removeFeed(aFeed.url);
|
||||
},
|
||||
|
||||
get url()
|
||||
{
|
||||
var ds = getSubscriptionsDS(this.server);
|
||||
var url = ds.GetTarget(this.resource, DC_IDENTIFIER, true);
|
||||
let ds = FeedUtils.getSubscriptionsDS(this.server);
|
||||
let url = ds.GetTarget(this.resource, FeedUtils.DC_IDENTIFIER, true);
|
||||
if (url)
|
||||
url = url.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
|
||||
url = url.QueryInterface(Ci.nsIRDFLiteral).Value;
|
||||
else
|
||||
url = this.resource.Value;
|
||||
|
||||
return url;
|
||||
},
|
||||
|
||||
get title()
|
||||
{
|
||||
var ds = getSubscriptionsDS(this.server);
|
||||
var title = ds.GetTarget(this.resource, DC_TITLE, true);
|
||||
let ds = FeedUtils.getSubscriptionsDS(this.server);
|
||||
let title = ds.GetTarget(this.resource, FeedUtils.DC_TITLE, true);
|
||||
if (title)
|
||||
title = title.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
|
||||
title = title.QueryInterface(Ci.nsIRDFLiteral).Value;
|
||||
|
||||
return title;
|
||||
},
|
||||
|
||||
|
@ -282,69 +294,78 @@ Feed.prototype =
|
|||
if (!aNewTitle)
|
||||
return;
|
||||
|
||||
var ds = getSubscriptionsDS(this.server);
|
||||
aNewTitle = rdf.GetLiteral(aNewTitle);
|
||||
var old_title = ds.GetTarget(this.resource, DC_TITLE, true);
|
||||
let ds = FeedUtils.getSubscriptionsDS(this.server);
|
||||
aNewTitle = FeedUtils.rdf.GetLiteral(aNewTitle);
|
||||
let old_title = ds.GetTarget(this.resource, FeedUtils.DC_TITLE, true);
|
||||
if (old_title)
|
||||
ds.Change(this.resource, DC_TITLE, old_title, aNewTitle);
|
||||
ds.Change(this.resource, FeedUtils.DC_TITLE, old_title, aNewTitle);
|
||||
else
|
||||
ds.Assert(this.resource, DC_TITLE, aNewTitle, true);
|
||||
ds.Assert(this.resource, FeedUtils.DC_TITLE, aNewTitle, true);
|
||||
},
|
||||
|
||||
get lastModified()
|
||||
{
|
||||
var ds = getSubscriptionsDS(this.server);
|
||||
var lastModified = ds.GetTarget(this.resource, DC_LASTMODIFIED, true);
|
||||
let ds = FeedUtils.getSubscriptionsDS(this.server);
|
||||
let lastModified = ds.GetTarget(this.resource,
|
||||
FeedUtils.DC_LASTMODIFIED,
|
||||
true);
|
||||
if (lastModified)
|
||||
lastModified = lastModified.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
|
||||
lastModified = lastModified.QueryInterface(Ci.nsIRDFLiteral).Value;
|
||||
return lastModified;
|
||||
},
|
||||
|
||||
set lastModified(aLastModified)
|
||||
{
|
||||
var ds = getSubscriptionsDS(this.server);
|
||||
aLastModified = rdf.GetLiteral(aLastModified);
|
||||
var old_lastmodified = ds.GetTarget(this.resource, DC_LASTMODIFIED, true);
|
||||
let ds = FeedUtils.getSubscriptionsDS(this.server);
|
||||
aLastModified = FeedUtils.rdf.GetLiteral(aLastModified);
|
||||
let old_lastmodified = ds.GetTarget(this.resource,
|
||||
FeedUtils.DC_LASTMODIFIED,
|
||||
true);
|
||||
if (old_lastmodified)
|
||||
ds.Change(this.resource, DC_LASTMODIFIED, old_lastmodified, aLastModified);
|
||||
ds.Change(this.resource, FeedUtils.DC_LASTMODIFIED,
|
||||
old_lastmodified, aLastModified);
|
||||
else
|
||||
ds.Assert(this.resource, DC_LASTMODIFIED, aLastModified, true);
|
||||
ds.Assert(this.resource, FeedUtils.DC_LASTMODIFIED, aLastModified, true);
|
||||
|
||||
// do we need to flush every time this property changes?
|
||||
ds = ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
|
||||
ds.Flush();
|
||||
// Do we need to flush every time this property changes?
|
||||
ds.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush();
|
||||
},
|
||||
|
||||
get quickMode ()
|
||||
{
|
||||
var ds = getSubscriptionsDS(this.server);
|
||||
var quickMode = ds.GetTarget(this.resource, FZ_QUICKMODE, true);
|
||||
if (quickMode)
|
||||
let ds = FeedUtils.getSubscriptionsDS(this.server);
|
||||
let quickMode = ds.GetTarget(this.resource, FeedUtils.FZ_QUICKMODE, true);
|
||||
if (quickMode)
|
||||
{
|
||||
quickMode = quickMode.QueryInterface(Components.interfaces.nsIRDFLiteral);
|
||||
quickMode = quickMode.Value;
|
||||
quickMode = eval(quickMode);
|
||||
}
|
||||
quickMode = quickMode.QueryInterface(Ci.nsIRDFLiteral);
|
||||
quickMode = quickMode.Value == "true" ? true : false;
|
||||
}
|
||||
|
||||
return quickMode;
|
||||
},
|
||||
|
||||
set quickMode (aNewQuickMode)
|
||||
set quickMode (aNewQuickMode)
|
||||
{
|
||||
var ds = getSubscriptionsDS(this.server);
|
||||
aNewQuickMode = rdf.GetLiteral(aNewQuickMode);
|
||||
var old_quickMode = ds.GetTarget(this.resource, FZ_QUICKMODE, true);
|
||||
let ds = FeedUtils.getSubscriptionsDS(this.server);
|
||||
aNewQuickMode = FeedUtils.rdf.GetLiteral(aNewQuickMode);
|
||||
let old_quickMode = ds.GetTarget(this.resource,
|
||||
FeedUtils.FZ_QUICKMODE,
|
||||
true);
|
||||
if (old_quickMode)
|
||||
ds.Change(this.resource, FZ_QUICKMODE, old_quickMode, aNewQuickMode);
|
||||
ds.Change(this.resource, FeedUtils.FZ_QUICKMODE,
|
||||
old_quickMode, aNewQuickMode);
|
||||
else
|
||||
ds.Assert(this.resource, FZ_QUICKMODE, aNewQuickMode, true);
|
||||
ds.Assert(this.resource, FeedUtils.FZ_QUICKMODE,
|
||||
aNewQuickMode, true);
|
||||
},
|
||||
|
||||
get link ()
|
||||
{
|
||||
var ds = getSubscriptionsDS(this.server);
|
||||
var link = ds.GetTarget(this.resource, RSS_LINK, true);
|
||||
if(link)
|
||||
link = link.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
|
||||
let ds = FeedUtils.getSubscriptionsDS(this.server);
|
||||
let link = ds.GetTarget(this.resource, FeedUtils.RSS_LINK, true);
|
||||
if (link)
|
||||
link = link.QueryInterface(Ci.nsIRDFLiteral).Value;
|
||||
|
||||
return link;
|
||||
},
|
||||
|
||||
|
@ -353,19 +374,19 @@ Feed.prototype =
|
|||
if (!aNewLink)
|
||||
return;
|
||||
|
||||
var ds = getSubscriptionsDS(this.server);
|
||||
aNewLink = rdf.GetLiteral(aNewLink);
|
||||
var old_link = ds.GetTarget(this.resource, RSS_LINK, true);
|
||||
let ds = FeedUtils.getSubscriptionsDS(this.server);
|
||||
aNewLink = FeedUtils.rdf.GetLiteral(aNewLink);
|
||||
let old_link = ds.GetTarget(this.resource, FeedUtils.RSS_LINK, true);
|
||||
if (old_link)
|
||||
ds.Change(this.resource, RSS_LINK, old_link, aNewLink);
|
||||
ds.Change(this.resource, FeedUtils.RSS_LINK, old_link, aNewLink);
|
||||
else
|
||||
ds.Assert(this.resource, RSS_LINK, aNewLink, true);
|
||||
ds.Assert(this.resource, FeedUtils.RSS_LINK, aNewLink, true);
|
||||
},
|
||||
|
||||
parse: function()
|
||||
parse: function()
|
||||
{
|
||||
// Create a feed parser which will parse the feed.
|
||||
var parser = new FeedParser();
|
||||
let parser = new FeedParser();
|
||||
this.itemsToStore = parser.parseFeed(this,
|
||||
this.request.responseXML,
|
||||
this.request.channel.URI);
|
||||
|
@ -376,144 +397,148 @@ Feed.prototype =
|
|||
return;
|
||||
}
|
||||
|
||||
// storeNextItem will iterate through the parsed items, storing each one.
|
||||
// storeNextItem() will iterate through the parsed items, storing each one.
|
||||
this.itemsToStoreIndex = 0;
|
||||
this.storeNextItem();
|
||||
},
|
||||
|
||||
invalidateItems: function ()
|
||||
invalidateItems: function ()
|
||||
{
|
||||
var ds = getItemsDS(this.server);
|
||||
debug("invalidating items for " + this.url);
|
||||
var items = ds.GetSources(FZ_FEED, this.resource, true);
|
||||
var item;
|
||||
|
||||
while (items.hasMoreElements())
|
||||
let ds = FeedUtils.getItemsDS(this.server);
|
||||
FeedUtils.log.debug("Feed.invalidateItems: for url - " + this.url);
|
||||
let items = ds.GetSources(FeedUtils.FZ_FEED, this.resource, true);
|
||||
let item;
|
||||
|
||||
while (items.hasMoreElements())
|
||||
{
|
||||
item = items.getNext();
|
||||
item = item.QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
debug("invalidating " + item.Value);
|
||||
var valid = ds.GetTarget(item, FZ_VALID, true);
|
||||
item = item.QueryInterface(Ci.nsIRDFResource);
|
||||
FeedUtils.log.trace("Feed.invalidateItems: item - " + item.Value);
|
||||
let valid = ds.GetTarget(item, FeedUtils.FZ_VALID, true);
|
||||
if (valid)
|
||||
ds.Unassert(item, FZ_VALID, valid, true);
|
||||
ds.Unassert(item, FeedUtils.FZ_VALID, valid, true);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
removeInvalidItems: function(aDeleteFeed)
|
||||
removeInvalidItems: function(aDeleteFeed)
|
||||
{
|
||||
var ds = getItemsDS(this.server);
|
||||
debug("removing invalid items for " + this.url);
|
||||
var items = ds.GetSources(FZ_FEED, this.resource, true);
|
||||
var item;
|
||||
var currentTime = new Date().getTime();
|
||||
while (items.hasMoreElements())
|
||||
let ds = FeedUtils.getItemsDS(this.server);
|
||||
FeedUtils.log.debug("Feed.removeInvalidItems: for url - " + this.url);
|
||||
let items = ds.GetSources(FeedUtils.FZ_FEED, this.resource, true);
|
||||
let item;
|
||||
let currentTime = new Date().getTime();
|
||||
while (items.hasMoreElements())
|
||||
{
|
||||
item = items.getNext();
|
||||
item = item.QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
item = item.QueryInterface(Ci.nsIRDFResource);
|
||||
|
||||
if (ds.HasAssertion(item, FZ_VALID, RDF_LITERAL_TRUE, true))
|
||||
if (ds.HasAssertion(item, FeedUtils.FZ_VALID,
|
||||
FeedUtils.RDF_LITERAL_TRUE, true))
|
||||
continue;
|
||||
|
||||
var lastSeenTime = ds.GetTarget(item, FZ_LAST_SEEN_TIMESTAMP, true);
|
||||
lastSeenTime = lastSeenTime ?
|
||||
parseInt(lastSeenTime
|
||||
.QueryInterface(Components.interfaces.nsIRDFLiteral)
|
||||
.Value) : 0;
|
||||
if ((currentTime - lastSeenTime) < INVALID_ITEM_PURGE_DELAY && !aDeleteFeed)
|
||||
let lastSeenTime = ds.GetTarget(item, FeedUtils.FZ_LAST_SEEN_TIMESTAMP, true);
|
||||
if (lastSeenTime)
|
||||
lastSeenTime = parseInt(lastSeenTime.QueryInterface(Ci.nsIRDFLiteral).Value)
|
||||
else
|
||||
lastSeenTime = 0;
|
||||
|
||||
if ((currentTime - lastSeenTime) < FeedUtils.INVALID_ITEM_PURGE_DELAY &&
|
||||
!aDeleteFeed)
|
||||
// Don't immediately purge items in active feeds; do so for deleted feeds.
|
||||
continue;
|
||||
|
||||
debug("removing " + item.Value);
|
||||
ds.Unassert(item, FZ_FEED, this.resource, true);
|
||||
if (ds.hasArcOut(item, FZ_FEED))
|
||||
debug(item.Value + " is from more than one feed; only the reference to this feed removed");
|
||||
FeedUtils.log.trace("Feed.removeInvalidItems: item - " + item.Value);
|
||||
ds.Unassert(item, FeedUtils.FZ_FEED, this.resource, true);
|
||||
if (ds.hasArcOut(item, FeedUtils.FZ_FEED))
|
||||
FeedUtils.log.debug("Feed.removeInvalidItems: " + item.Value +
|
||||
" is from more than one feed; only the reference to" +
|
||||
" this feed removed");
|
||||
else
|
||||
removeAssertions(ds, item);
|
||||
FeedUtils.removeAssertions(ds, item);
|
||||
}
|
||||
},
|
||||
|
||||
createFolder: function()
|
||||
{
|
||||
if (!this.folder)
|
||||
this.server.rootMsgFolder.createSubfolder(this.name, null /* supposed to be a msg window */);
|
||||
{
|
||||
if (!this.folder)
|
||||
this.server.rootMsgFolder.createSubfolder(this.name, null);
|
||||
},
|
||||
|
||||
// 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.
|
||||
// otherwise it triggers a download done notification to the UI
|
||||
// Gets the next item from itemsToStore 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, otherwise triggers a download done notification to the UI.
|
||||
storeNextItem: function()
|
||||
{
|
||||
if (!this.itemsToStore || !this.itemsToStore.length)
|
||||
if (!this.itemsToStore || !this.itemsToStore.length)
|
||||
{
|
||||
this.createFolder();
|
||||
this.cleanupParsingState(this);
|
||||
return;
|
||||
}
|
||||
|
||||
var item = this.itemsToStore[this.itemsToStoreIndex];
|
||||
let item = this.itemsToStore[this.itemsToStoreIndex];
|
||||
|
||||
item.store();
|
||||
|
||||
this.itemsToStoreIndex++;
|
||||
|
||||
// if the listener is tracking progress for storing each item, report it here...
|
||||
// If the listener is tracking progress for each item, report it here.
|
||||
if (item.feed.downloadCallback && item.feed.downloadCallback.onFeedItemStored)
|
||||
item.feed.downloadCallback.onFeedItemStored(item.feed, this.itemsToStoreIndex, this.itemsToStore.length);
|
||||
|
||||
// eventually we'll report individual progress here....
|
||||
item.feed.downloadCallback.onFeedItemStored(item.feed,
|
||||
this.itemsToStoreIndex,
|
||||
this.itemsToStore.length);
|
||||
|
||||
// Eventually we'll report individual progress here.
|
||||
|
||||
if (this.itemsToStoreIndex < this.itemsToStore.length)
|
||||
{
|
||||
if (!this.storeItemsTimer)
|
||||
this.storeItemsTimer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
|
||||
this.storeItemsTimer.initWithCallback(this, 50, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
||||
this.storeItemsTimer = Cc["@mozilla.org/timer;1"].
|
||||
createInstance(Ci.nsITimer);
|
||||
this.storeItemsTimer.initWithCallback(this, 50, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have just finished downloading one or more feed items into the destination folder,
|
||||
// if the folder is still listed as having new messages in it, then we should set the biff state on the folder
|
||||
// so the right RDF UI changes happen in the folder pane to indicate new mail.
|
||||
|
||||
// We have just finished downloading one or more feed items into the
|
||||
// destination folder; if the folder is still listed as having new
|
||||
// messages in it, then we should set the biff state on the folder so the
|
||||
// right RDF UI changes happen in the folder pane to indicate new mail.
|
||||
if (item.feed.folder.hasNewMessages)
|
||||
{
|
||||
item.feed.folder.biffState = Components.interfaces.nsIMsgFolder.nsMsgBiffState_NewMail;
|
||||
// run the bayesian spam filter, if enabled
|
||||
item.feed.folder.biffState = Ci.nsIMsgFolder.nsMsgBiffState_NewMail;
|
||||
// Run the bayesian spam filter, if enabled.
|
||||
item.feed.folder.callFilterPlugins(null);
|
||||
}
|
||||
|
||||
this.cleanupParsingState(item.feed);
|
||||
}
|
||||
},
|
||||
|
||||
cleanupParsingState: function(aFeed)
|
||||
cleanupParsingState: function(aFeed)
|
||||
{
|
||||
// now that we are done parsing the feed, remove the feed from our feed cache
|
||||
// Now that we are done parsing the feed, remove the feed from the cache.
|
||||
FeedCache.removeFeed(aFeed.url);
|
||||
aFeed.removeInvalidItems(false);
|
||||
|
||||
// let's be sure to flush any feed item changes back to disk
|
||||
var ds = getItemsDS(aFeed.server);
|
||||
ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource).Flush(); // flush any changes
|
||||
// Flush any feed item changes to disk.
|
||||
let ds = FeedUtils.getItemsDS(aFeed.server);
|
||||
ds.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush();
|
||||
|
||||
if (aFeed.downloadCallback)
|
||||
aFeed.downloadCallback.downloaded(aFeed, kNewsBlogSuccess);
|
||||
aFeed.downloadCallback.downloaded(aFeed, FeedUtils.kNewsBlogSuccess);
|
||||
|
||||
this.request = null; // force the xml http request to go away. This helps reduce some nasty assertions on shut down.
|
||||
// Force the xml http request to go away. This helps reduce some nasty
|
||||
// assertions on shut down.
|
||||
this.request = null;
|
||||
this.itemsToStore = "";
|
||||
this.itemsToStoreIndex = 0;
|
||||
this.storeItemsTimer = null;
|
||||
},
|
||||
},
|
||||
|
||||
notify: function(aTimer)
|
||||
// nsITimerCallback
|
||||
notify: function(aTimer)
|
||||
{
|
||||
this.storeNextItem();
|
||||
},
|
||||
|
||||
QueryInterface: function(aIID)
|
||||
{
|
||||
if (aIID.equals(Components.interfaces.nsITimerCallback) || aIID.equals(Components.interfaces.nsISupports))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -35,52 +35,46 @@
|
|||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
// Handy conversion values.
|
||||
const HOURS_TO_MINUTES = 60;
|
||||
const MINUTES_TO_SECONDS = 60;
|
||||
const SECONDS_TO_MILLISECONDS = 1000;
|
||||
const MINUTES_TO_MILLISECONDS = MINUTES_TO_SECONDS * SECONDS_TO_MILLISECONDS;
|
||||
const HOURS_TO_MILLISECONDS = HOURS_TO_MINUTES * MINUTES_TO_MILLISECONDS;
|
||||
const ENCLOSURE_BOUNDARY_PREFIX = "--------------"; // 14 dashes
|
||||
const ENCLOSURE_HEADER_BOUNDARY_PREFIX = "------------"; // 12 dashes
|
||||
|
||||
const MESSAGE_TEMPLATE = "\n\
|
||||
<html>\n\
|
||||
<head>\n\
|
||||
<title>%TITLE%</title>\n\
|
||||
<base href=\"%BASE%\">\n\
|
||||
</head>\n\
|
||||
<body id=\"msgFeedSummaryBody\" selected=\"false\">\n\
|
||||
%CONTENT%\n\
|
||||
</body>\n\
|
||||
</html>\n\
|
||||
";
|
||||
|
||||
function FeedItem()
|
||||
{
|
||||
this.mDate = new Date().toString();
|
||||
this.mUnicodeConverter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
|
||||
this.mUnicodeConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
|
||||
createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
this.mUnescapeHTML = Cc["@mozilla.org/feed-unescapehtml;1"].
|
||||
getService(Ci.nsIScriptableUnescapeHTML);
|
||||
}
|
||||
|
||||
FeedItem.prototype =
|
||||
{
|
||||
// Currently only for IETF Atom. RSS2 with GUIDs should do this as too.
|
||||
// Currently only for IETF Atom. RSS2 with GUIDs should do this too.
|
||||
isStoredWithId: false,
|
||||
// Only for IETF Atom
|
||||
// Only for IETF Atom.
|
||||
xmlContentBase: null,
|
||||
id: null,
|
||||
feed: null,
|
||||
description: null,
|
||||
content: null,
|
||||
// Currently only support one enclosure per feed item...
|
||||
// Currently only support one enclosure per feed item.
|
||||
enclosure: null,
|
||||
// TO DO: this needs to be localized
|
||||
// TO DO: this needs to be localized.
|
||||
title: "(no subject)",
|
||||
author: "anonymous",
|
||||
mURL: null,
|
||||
characterSet: "",
|
||||
|
||||
ENCLOSURE_BOUNDARY_PREFIX: "--------------", // 14 dashes
|
||||
ENCLOSURE_HEADER_BOUNDARY_PREFIX: "------------", // 12 dashes
|
||||
MESSAGE_TEMPLATE: '\n' +
|
||||
'<html>\n' +
|
||||
' <head>\n' +
|
||||
' <title>%TITLE%</title>\n' +
|
||||
' <base href="%BASE%">\n' +
|
||||
' </head>\n' +
|
||||
' <body id="msgFeedSummaryBody" selected="false">\n' +
|
||||
' %CONTENT%\n' +
|
||||
' </body>\n' +
|
||||
'</html>\n',
|
||||
|
||||
get url()
|
||||
{
|
||||
return this.mURL;
|
||||
|
@ -90,9 +84,7 @@ FeedItem.prototype =
|
|||
{
|
||||
try
|
||||
{
|
||||
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
this.mURL = ioService.newURI(aVal, null, null).spec;
|
||||
this.mURL = Services.io.newURI(aVal, null, null).spec;
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
|
@ -120,25 +112,26 @@ FeedItem.prototype =
|
|||
|
||||
get messageID()
|
||||
{
|
||||
var messageID = this.id || this.mURL || this.title;
|
||||
let messageID = this.id || this.mURL || this.title;
|
||||
|
||||
debug('messageID - id = ' + this.id);
|
||||
debug('messageID - mURL = ' + this.mURL);
|
||||
debug('messageID - title = ' + this.title);
|
||||
debug('messageID - messageID = ' + messageID);
|
||||
FeedUtils.log.trace("FeedItem.messageID: id - " + this.id);
|
||||
FeedUtils.log.trace("FeedItem.messageID: mURL - " + this.mURL);
|
||||
FeedUtils.log.trace("FeedItem.messageID: title - " + this.title);
|
||||
|
||||
// Escape occurrences of message ID meta characters <, >, and @.
|
||||
messageID.replace(/</g, "%3C");
|
||||
messageID.replace(/>/g, "%3E");
|
||||
messageID.replace(/@/g, "%40");
|
||||
messageID = messageID + "@" + "localhost.localdomain";
|
||||
|
||||
FeedUtils.log.trace("FeedItem.messageID: messageID - " + messageID);
|
||||
return messageID;
|
||||
},
|
||||
|
||||
get itemUniqueURI()
|
||||
{
|
||||
return (this.isStoredWithId && this.id) ? createURN(this.id) :
|
||||
createURN(this.mURL || this.id);
|
||||
return this.isStoredWithId && this.id ? this.createURN(this.id) :
|
||||
this.createURN(this.mURL || this.id);
|
||||
},
|
||||
|
||||
get contentBase()
|
||||
|
@ -153,25 +146,27 @@ FeedItem.prototype =
|
|||
{
|
||||
this.mUnicodeConverter.charset = this.characterSet;
|
||||
|
||||
// this.title and this.content contain HTML
|
||||
// this.mUrl and this.contentBase contain plain text
|
||||
// this.title and this.content contain HTML.
|
||||
// this.mUrl and this.contentBase contain plain text.
|
||||
|
||||
let resource = this.findStoredResource();
|
||||
if (resource == null)
|
||||
{
|
||||
resource = rdf.GetResource(this.itemUniqueURI);
|
||||
resource = FeedUtils.rdf.GetResource(this.itemUniqueURI);
|
||||
if (!this.content)
|
||||
{
|
||||
debug(this.identity + " no content; storing");
|
||||
FeedUtils.log.trace("FeedItem.store: " + this.identity +
|
||||
" no content; storing");
|
||||
this.content = this.description || this.title;
|
||||
}
|
||||
|
||||
debug(this.identity + " store both remote/no content and content items");
|
||||
var content = MESSAGE_TEMPLATE;
|
||||
FeedUtils.log.trace("FeedItem.store: " + this.identity +
|
||||
" store both remote/no content and content items");
|
||||
let content = this.MESSAGE_TEMPLATE;
|
||||
content = content.replace(/%TITLE%/, this.title);
|
||||
content = content.replace(/%BASE%/, htmlEscape(this.contentBase));
|
||||
content = content.replace(/%BASE%/, this.htmlEscape(this.contentBase));
|
||||
content = content.replace(/%CONTENT%/, this.content);
|
||||
// XXX store it elsewhere, f.e. this.page
|
||||
// XXX store it elsewhere, f.e. this.page.
|
||||
this.content = content;
|
||||
this.writeToFolder();
|
||||
this.markStored(resource);
|
||||
|
@ -181,37 +176,39 @@ FeedItem.prototype =
|
|||
|
||||
findStoredResource: function()
|
||||
{
|
||||
// Checks to see if the item has already been stored in its feed's message folder.
|
||||
// Checks to see if the item has already been stored in its feed's
|
||||
// message folder.
|
||||
FeedUtils.log.trace("FeedItem.findStoredResource: " + this.identity +
|
||||
" checking to see if stored");
|
||||
|
||||
debug(this.identity + " checking to see if stored");
|
||||
|
||||
var server = this.feed.server;
|
||||
var folder = this.feed.folder;
|
||||
let server = this.feed.server;
|
||||
let folder = this.feed.folder;
|
||||
|
||||
if (!folder)
|
||||
{
|
||||
debug(this.feed.name + " folder doesn't exist; creating");
|
||||
debug("creating " + this.feed.name + "as child of " +
|
||||
server.rootMsgFolder + "\n");
|
||||
server.rootMsgFolder.createSubfolder(this.feed.name, null /* supposed to be a msg window */);
|
||||
FeedUtils.log.debug("FeedItem.findStoredResource: " + this.feed.name +
|
||||
" folder doesn't exist; creating as child of " +
|
||||
server.rootMsgFolder.prettyName + "\n");
|
||||
server.rootMsgFolder.createSubfolder(this.feed.name, null);
|
||||
folder = server.rootMsgFolder.findSubFolder(this.feed.name);
|
||||
debug(this.identity + " not stored (folder didn't exist)");
|
||||
FeedUtils.log.debug("FeedItem.findStoredResource: " + this.identity +
|
||||
" not stored (folder didn't exist)");
|
||||
return null;
|
||||
}
|
||||
|
||||
var ds = getItemsDS(server);
|
||||
var itemURI = this.itemUniqueURI;
|
||||
var itemResource = rdf.GetResource(itemURI);
|
||||
let ds = FeedUtils.getItemsDS(server);
|
||||
let itemURI = this.itemUniqueURI;
|
||||
let itemResource = FeedUtils.rdf.GetResource(itemURI);
|
||||
|
||||
var downloaded = ds.GetTarget(itemResource, FZ_STORED, true);
|
||||
let downloaded = ds.GetTarget(itemResource, FeedUtils.FZ_STORED, true);
|
||||
|
||||
// Backward compatibility: we might have stored this item before
|
||||
// isStoredWithId has been turned on for RSS 2.0 (bug 354345).
|
||||
// Check whether this item has been stored with its URL.
|
||||
if (!downloaded && this.mURL && itemURI != this.mURL)
|
||||
{
|
||||
itemResource = rdf.GetResource(this.mURL);
|
||||
downloaded = ds.GetTarget(itemResource, FZ_STORED, true);
|
||||
itemResource = FeedUtils.rdf.GetResource(this.mURL);
|
||||
downloaded = ds.GetTarget(itemResource, FeedUtils.FZ_STORED, true);
|
||||
}
|
||||
|
||||
// Backward compatibility: the item may have been stored
|
||||
|
@ -219,97 +216,108 @@ FeedItem.prototype =
|
|||
// (bug 410842 & bug 461109)
|
||||
if (!downloaded)
|
||||
{
|
||||
itemResource = rdf.GetResource((this.isStoredWithId && this.id) ?
|
||||
("urn:" + this.id) :
|
||||
(this.mURL || ("urn:" + this.id)));
|
||||
downloaded = ds.GetTarget(itemResource, FZ_STORED, true);
|
||||
itemResource = FeedUtils.rdf.GetResource((this.isStoredWithId && this.id) ?
|
||||
("urn:" + this.id) :
|
||||
(this.mURL || ("urn:" + this.id)));
|
||||
downloaded = ds.GetTarget(itemResource, FeedUtils.FZ_STORED, true);
|
||||
}
|
||||
|
||||
if (!downloaded ||
|
||||
downloaded.QueryInterface(Components.interfaces.nsIRDFLiteral)
|
||||
.Value == "false")
|
||||
downloaded.QueryInterface(Ci.nsIRDFLiteral).Value == "false")
|
||||
{
|
||||
// HACK ALERT: before we give up, try to work around an entity
|
||||
// escaping bug in RDF. See Bug #258465 for more details
|
||||
// escaping bug in RDF. See Bug #258465 for more details.
|
||||
itemURI = itemURI.replace(/</g, '<');
|
||||
itemURI = itemURI.replace(/>/g, '>');
|
||||
itemURI = itemURI.replace(/"/g, '"');
|
||||
itemURI = itemURI.replace(/&/g, '&');
|
||||
|
||||
debug('Failed to find item, trying entity replacement version: ' + itemURI);
|
||||
itemResource = rdf.GetResource(itemURI);
|
||||
downloaded = ds.GetTarget(itemResource, FZ_STORED, true);
|
||||
FeedUtils.log.trace("FeedItem.findStoredResource: failed to find item," +
|
||||
" trying entity replacement version - " + itemURI);
|
||||
itemResource = FeedUtils.rdf.GetResource(itemURI);
|
||||
downloaded = ds.GetTarget(itemResource, FeedUtils.FZ_STORED, true);
|
||||
|
||||
if (downloaded)
|
||||
{
|
||||
debug(this.identity + " stored");
|
||||
FeedUtils.log.trace("FeedItem.findStoredResource: " + this.identity +
|
||||
" stored");
|
||||
return itemResource;
|
||||
}
|
||||
|
||||
debug(this.identity + " not stored");
|
||||
FeedUtils.log.trace("FeedItem.findStoredResource: " + this.identity +
|
||||
" not stored");
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug(this.identity + " stored");
|
||||
FeedUtils.log.trace("FeedItem.findStoredResource: " + this.identity +
|
||||
" stored");
|
||||
return itemResource;
|
||||
}
|
||||
},
|
||||
|
||||
markValid: function(resource)
|
||||
{
|
||||
var ds = getItemsDS(this.feed.server);
|
||||
let ds = FeedUtils.getItemsDS(this.feed.server);
|
||||
|
||||
var newTimeStamp = rdf.GetLiteral(new Date().getTime());
|
||||
var currentTimeStamp = ds.GetTarget(resource, FZ_LAST_SEEN_TIMESTAMP, true);
|
||||
let newTimeStamp = FeedUtils.rdf.GetLiteral(new Date().getTime());
|
||||
let currentTimeStamp = ds.GetTarget(resource,
|
||||
FeedUtils.FZ_LAST_SEEN_TIMESTAMP,
|
||||
true);
|
||||
if (currentTimeStamp)
|
||||
ds.Change(resource, FZ_LAST_SEEN_TIMESTAMP, currentTimeStamp, newTimeStamp);
|
||||
ds.Change(resource, FeedUtils.FZ_LAST_SEEN_TIMESTAMP,
|
||||
currentTimeStamp, newTimeStamp);
|
||||
else
|
||||
ds.Assert(resource, FZ_LAST_SEEN_TIMESTAMP, newTimeStamp, true);
|
||||
ds.Assert(resource, FeedUtils.FZ_LAST_SEEN_TIMESTAMP,
|
||||
newTimeStamp, true);
|
||||
|
||||
if (!ds.HasAssertion(resource, FZ_FEED, rdf.GetResource(this.feed.url), true))
|
||||
ds.Assert(resource, FZ_FEED, rdf.GetResource(this.feed.url), true);
|
||||
if (!ds.HasAssertion(resource, FeedUtils.FZ_FEED,
|
||||
FeedUtils.rdf.GetResource(this.feed.url), true))
|
||||
ds.Assert(resource, FeedUtils.FZ_FEED,
|
||||
FeedUtils.rdf.GetResource(this.feed.url), true);
|
||||
|
||||
if (ds.hasArcOut(resource, FZ_VALID))
|
||||
if (ds.hasArcOut(resource, FeedUtils.FZ_VALID))
|
||||
{
|
||||
var currentValue = ds.GetTarget(resource, FZ_VALID, true);
|
||||
ds.Change(resource, FZ_VALID, currentValue, RDF_LITERAL_TRUE);
|
||||
let currentValue = ds.GetTarget(resource, FeedUtils.FZ_VALID, true);
|
||||
ds.Change(resource, FeedUtils.FZ_VALID,
|
||||
currentValue, FeedUtils.RDF_LITERAL_TRUE);
|
||||
}
|
||||
else
|
||||
ds.Assert(resource, FZ_VALID, RDF_LITERAL_TRUE, true);
|
||||
ds.Assert(resource, FeedUtils.FZ_VALID, FeedUtils.RDF_LITERAL_TRUE, true);
|
||||
},
|
||||
|
||||
markStored: function(resource)
|
||||
{
|
||||
var ds = getItemsDS(this.feed.server);
|
||||
let ds = FeedUtils.getItemsDS(this.feed.server);
|
||||
|
||||
if (!ds.HasAssertion(resource, FZ_FEED, rdf.GetResource(this.feed.url), true))
|
||||
ds.Assert(resource, FZ_FEED, rdf.GetResource(this.feed.url), true);
|
||||
if (!ds.HasAssertion(resource, FeedUtils.FZ_FEED,
|
||||
FeedUtils.rdf.GetResource(this.feed.url), true))
|
||||
ds.Assert(resource, FeedUtils.FZ_FEED,
|
||||
FeedUtils.rdf.GetResource(this.feed.url), true);
|
||||
|
||||
var currentValue;
|
||||
if (ds.hasArcOut(resource, FZ_STORED))
|
||||
let currentValue;
|
||||
if (ds.hasArcOut(resource, FeedUtils.FZ_STORED))
|
||||
{
|
||||
currentValue = ds.GetTarget(resource, FZ_STORED, true);
|
||||
ds.Change(resource, FZ_STORED, currentValue, RDF_LITERAL_TRUE);
|
||||
currentValue = ds.GetTarget(resource, FeedUtils.FZ_STORED, true);
|
||||
ds.Change(resource, FeedUtils.FZ_STORED,
|
||||
currentValue, FeedUtils.RDF_LITERAL_TRUE);
|
||||
}
|
||||
else
|
||||
ds.Assert(resource, FZ_STORED, RDF_LITERAL_TRUE, true);
|
||||
ds.Assert(resource, FeedUtils.FZ_STORED,
|
||||
FeedUtils.RDF_LITERAL_TRUE, true);
|
||||
},
|
||||
|
||||
mimeEncodeSubject: function(aSubject, aCharset)
|
||||
{
|
||||
// Get the mime header encoder service
|
||||
var mimeEncoder = Components.classes["@mozilla.org/messenger/mimeconverter;1"]
|
||||
.getService(Components.interfaces.nsIMimeConverter);
|
||||
|
||||
// This routine sometimes throws exceptions for mis-encoded data so
|
||||
// wrap it with a try catch for now..
|
||||
var newSubject;
|
||||
// wrap it with a try catch for now.
|
||||
let newSubject;
|
||||
try
|
||||
{
|
||||
newSubject = mimeEncoder.encodeMimePartIIStr(
|
||||
this.mUnicodeConverter.ConvertFromUnicode(aSubject),
|
||||
false, aCharset, 9, 72);
|
||||
newSubject = mailServices.mimeConverter.encodeMimePartIIStr(
|
||||
this.mUnicodeConverter.ConvertFromUnicode(aSubject),
|
||||
false,
|
||||
aCharset, 9, 72);
|
||||
}
|
||||
catch (ex)
|
||||
{
|
||||
|
@ -321,24 +329,21 @@ FeedItem.prototype =
|
|||
|
||||
writeToFolder: function()
|
||||
{
|
||||
debug(this.identity + " writing to message folder" + this.feed.name + "\n");
|
||||
|
||||
var server = this.feed.server;
|
||||
FeedUtils.log.trace("FeedItem.writeToFolder: " + this.identity +
|
||||
" writing to message folder " + this.feed.name);
|
||||
this.mUnicodeConverter.charset = this.characterSet;
|
||||
|
||||
// If the sender isn't a valid email address, quote it so it looks nicer.
|
||||
if (this.author && this.author.indexOf('@') == -1)
|
||||
this.author = '<' + this.author + '>';
|
||||
if (this.author && this.author.indexOf("@") == -1)
|
||||
this.author = "<" + this.author + ">";
|
||||
|
||||
// Convert the title to UTF-16 before performing our HTML entity
|
||||
// replacement reg expressions.
|
||||
var title = this.title;
|
||||
let title = this.title;
|
||||
|
||||
// the subject may contain HTML entities.
|
||||
// Convert these to their unencoded state. i.e. & becomes '&'
|
||||
title = Components.classes["@mozilla.org/feed-unescapehtml;1"]
|
||||
.getService(Components.interfaces.nsIScriptableUnescapeHTML)
|
||||
.unescape(title);
|
||||
// The subject may contain HTML entities. Convert these to their unencoded
|
||||
// state. i.e. & becomes '&'.
|
||||
title = this.mUnescapeHTML.unescape(title);
|
||||
|
||||
// Compress white space in the subject to make it look better. Trim
|
||||
// leading/trailing spaces to prevent mbox header folding issue at just
|
||||
|
@ -364,9 +369,9 @@ FeedItem.prototype =
|
|||
// use it to calculate the offset of the X-Mozilla-Status lines from
|
||||
// the front of the message for the statusOffset property of the
|
||||
// DB header object.
|
||||
var openingLine = 'From - ' + this.mDate + '\n';
|
||||
let openingLine = 'From - ' + this.mDate + '\n';
|
||||
|
||||
var source =
|
||||
let source =
|
||||
openingLine +
|
||||
'X-Mozilla-Status: 0000\n' +
|
||||
'X-Mozilla-Status2: 00000000\n' +
|
||||
|
@ -381,9 +386,11 @@ FeedItem.prototype =
|
|||
|
||||
if (this.enclosure && this.enclosure.mFileName)
|
||||
{
|
||||
var boundaryID = source.length + this.enclosure.mLength;
|
||||
source += 'Content-Type: multipart/mixed;\n boundary="' + ENCLOSURE_HEADER_BOUNDARY_PREFIX + boundaryID + '"' + '\n\n' +
|
||||
'This is a multi-part message in MIME format.\n' + ENCLOSURE_BOUNDARY_PREFIX + boundaryID + '\n' +
|
||||
let boundaryID = source.length + this.enclosure.mLength;
|
||||
source += 'Content-Type: multipart/mixed;\n boundary="' +
|
||||
this.ENCLOSURE_HEADER_BOUNDARY_PREFIX + boundaryID + '"' + '\n\n' +
|
||||
'This is a multi-part message in MIME format.\n' +
|
||||
this.ENCLOSURE_BOUNDARY_PREFIX + boundaryID + '\n' +
|
||||
'Content-Type: text/html; charset=' + this.characterSet + '\n' +
|
||||
'Content-Transfer-Encoding: 8bit\n' +
|
||||
this.content;
|
||||
|
@ -396,47 +403,72 @@ FeedItem.prototype =
|
|||
|
||||
}
|
||||
|
||||
debug(this.identity + " is " + source.length + " characters long");
|
||||
FeedUtils.log.trace("FeedItem.writeToFolder: " + this.identity +
|
||||
" is " + source.length + " characters long");
|
||||
|
||||
// Get the folder and database storing the feed's messages and headers.
|
||||
var folder = this.feed.folder.QueryInterface(Components.interfaces.nsIMsgLocalMailFolder);
|
||||
var msgFolder = folder.QueryInterface(Components.interfaces.nsIMsgFolder);
|
||||
let folder = this.feed.folder.QueryInterface(Ci.nsIMsgLocalMailFolder);
|
||||
let msgFolder = folder.QueryInterface(Ci.nsIMsgFolder);
|
||||
msgFolder.gettingNewMessages = true;
|
||||
// Source is a unicode string, we want to save a char * string in
|
||||
// the original charset. So convert back
|
||||
// the original charset. So convert back.
|
||||
folder.addMessage(this.mUnicodeConverter.ConvertFromUnicode(source));
|
||||
msgFolder.gettingNewMessages = false;
|
||||
},
|
||||
|
||||
htmlEscape: function(s)
|
||||
{
|
||||
s = s.replace(/&/g, "&");
|
||||
s = s.replace(/>/g, ">");
|
||||
s = s.replace(/</g, "<");
|
||||
s = s.replace(/'/g, "'");
|
||||
s = s.replace(/"/g, """);
|
||||
return s;
|
||||
},
|
||||
|
||||
createURN: function(aName)
|
||||
{
|
||||
// Returns name as a URN in the 'feeditem' namespace. The returned URN is
|
||||
// (or is intended to be) RFC2141 compliant.
|
||||
// The builtin encodeURI provides nearly the exact encoding functionality
|
||||
// required by the RFC. The exceptions are that NULL characters should not
|
||||
// appear, and that #, /, ?, &, and ~ should be escaped.
|
||||
// NULL characters are removed before encoding.
|
||||
|
||||
let name = aName.replace(/\0/g, "");
|
||||
let encoded = encodeURI(name);
|
||||
encoded = encoded.replace(/\#/g, "%23");
|
||||
encoded = encoded.replace(/\//g, "%2f");
|
||||
encoded = encoded.replace(/\?/g, "%3f");
|
||||
encoded = encoded.replace(/\&/g, "%26");
|
||||
encoded = encoded.replace(/\~/g, "%7e");
|
||||
|
||||
return FeedUtils.FZ_ITEM_NS + encoded;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// A feed enclosure is to RSS what an attachment is for e-mail. We make enclosures look
|
||||
// like attachments in the UI.
|
||||
|
||||
// A feed enclosure is to RSS what an attachment is for e-mail. We make
|
||||
// enclosures look like attachments in the UI.
|
||||
function FeedEnclosure(aURL, aContentType, aLength)
|
||||
{
|
||||
this.mURL = aURL;
|
||||
this.mContentType = aContentType;
|
||||
this.mLength = aLength;
|
||||
|
||||
// generate a fileName from the URL
|
||||
// Generate a fileName from the URL.
|
||||
if (this.mURL)
|
||||
{
|
||||
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
var enclosureURL, fileName;
|
||||
try
|
||||
{
|
||||
enclosureURL = ioService.newURI(this.mURL, null, null)
|
||||
.QueryInterface(Components.interfaces.nsIURL);
|
||||
fileName = enclosureURL.fileName;
|
||||
this.mFileName = Services.io.newURI(this.mURL, null, null).
|
||||
QueryInterface(Ci.nsIURL).
|
||||
fileName;
|
||||
}
|
||||
catch(ex)
|
||||
{
|
||||
fileName = this.mURL;
|
||||
this.mFileName = this.mURL;
|
||||
}
|
||||
if (fileName)
|
||||
this.mFileName = fileName;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -446,20 +478,20 @@ FeedEnclosure.prototype =
|
|||
mContentType: "",
|
||||
mLength: 0,
|
||||
mFileName: "",
|
||||
ENCLOSURE_BOUNDARY_PREFIX: "--------------", // 14 dashes
|
||||
|
||||
// Returns a string that looks like an e-mail attachment which
|
||||
// represents the enclosure.
|
||||
// Returns a string that looks like an e-mail attachment which represents
|
||||
// the enclosure.
|
||||
convertToAttachment: function(aBoundaryID)
|
||||
{
|
||||
return '\n' +
|
||||
ENCLOSURE_BOUNDARY_PREFIX + aBoundaryID + '\n' +
|
||||
'Content-Type: ' + this.mContentType +
|
||||
'; name="' + this.mFileName +
|
||||
(this.mLength ? '"; size=' + this.mLength : '"') + '\n' +
|
||||
'X-Mozilla-External-Attachment-URL: ' + this.mURL + '\n' +
|
||||
'Content-Disposition: attachment; filename="' + this.mFileName + '"\n\n' +
|
||||
'This MIME attachment is stored separately from the message.\n' +
|
||||
ENCLOSURE_BOUNDARY_PREFIX + aBoundaryID + '--' + '\n';
|
||||
|
||||
this.ENCLOSURE_BOUNDARY_PREFIX + aBoundaryID + '\n' +
|
||||
'Content-Type: ' + this.mContentType +
|
||||
'; name="' + this.mFileName +
|
||||
(this.mLength ? '"; size=' + this.mLength : '"') + '\n' +
|
||||
'X-Mozilla-External-Attachment-URL: ' + this.mURL + '\n' +
|
||||
'Content-Disposition: attachment; filename="' + this.mFileName + '"\n\n' +
|
||||
'This MIME attachment is stored separately from the message.\n' +
|
||||
this.ENCLOSURE_BOUNDARY_PREFIX + aBoundaryID + '--' + '\n';
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
function enumerateInterfaces(obj)
|
||||
{
|
||||
var interfaces = new Array();
|
||||
for (i in Components.interfaces)
|
||||
{
|
||||
try
|
||||
{
|
||||
obj.QueryInterface(Components.interfaces[i]);
|
||||
interfaces.push(i);
|
||||
}
|
||||
catch(e) {}
|
||||
}
|
||||
return interfaces;
|
||||
}
|
||||
|
||||
function enumerateProperties(obj, excludeComplexTypes)
|
||||
{
|
||||
var properties = "";
|
||||
for (p in obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (excludeComplexTypes
|
||||
&& (typeof obj[p] == 'object' || typeof obj[p] == 'function')) next;
|
||||
properties += p + " = " + obj[p] + "\n";
|
||||
}
|
||||
catch(e) {
|
||||
properties += p + " = " + e + "\n";
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
// minimal implementation of nsIOutputStream for use by dumpRDF, adapted from
|
||||
// http://groups.google.com/search?as_umsgid=20011203111618.C1302%40erde.jan.netgaroo.de
|
||||
var DumpOutputStream = {
|
||||
write: function(buf, count) { dump(buf); return count; }
|
||||
};
|
||||
|
||||
function dumpRDF( aDS ) {
|
||||
var serializer = Components.classes["@mozilla.org/rdf/xml-serializer;1"]
|
||||
.createInstance( Components.interfaces.nsIRDFXMLSerializer );
|
||||
|
||||
serializer.init( aDS );
|
||||
|
||||
serializer.QueryInterface( Components.interfaces.nsIRDFXMLSource )
|
||||
.Serialize( DumpOutputStream );
|
||||
}
|
|
@ -34,122 +34,138 @@
|
|||
* the terms of any one of the MPL, the GPL or the
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
// The feed parser depends on FeedItems.js, Feed.js.
|
||||
// The feed parser depends on FeedItem.js, Feed.js.
|
||||
function FeedParser() {
|
||||
this.mSerializer = Cc["@mozilla.org/xmlextras/xmlserializer;1"].
|
||||
createInstance(Ci.nsIDOMSerializer);
|
||||
}
|
||||
|
||||
var rdfcontainer = Components.classes["@mozilla.org/rdf/container-utils;1"].getService(Components.interfaces.nsIRDFContainerUtils);
|
||||
var rdfparser = Components.classes["@mozilla.org/rdf/xml-parser;1"].createInstance(Components.interfaces.nsIRDFXMLParser);
|
||||
var serializer = Components.classes["@mozilla.org/xmlextras/xmlserializer;1"].createInstance(Components.interfaces.nsIDOMSerializer);
|
||||
var gIOService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
|
||||
|
||||
function FeedParser()
|
||||
{}
|
||||
|
||||
FeedParser.prototype =
|
||||
FeedParser.prototype =
|
||||
{
|
||||
// parseFeed returns an array of parsed items ready for processing
|
||||
// it is currently a synchronous operation. If there was an error parsing the feed,
|
||||
// parseFeed returns an empty feed in addition to calling aFeed.onParseError
|
||||
// parseFeed() returns an array of parsed items ready for processing. It is
|
||||
// currently a synchronous operation. If there is an error parsing the feed,
|
||||
// parseFeed returns an empty feed in addition to calling aFeed.onParseError.
|
||||
parseFeed: function (aFeed, aDOM, aBaseURI)
|
||||
{
|
||||
if (!(aDOM instanceof Components.interfaces.nsIDOMXMLDocument) ||
|
||||
aDOM.documentElement.getElementsByTagNameNS("http://www.mozilla.org/newlayout/xml/parsererror.xml", "parsererror")[0])
|
||||
let doc = aDOM.documentElement;
|
||||
if (!(aDOM instanceof Ci.nsIDOMXMLDocument) ||
|
||||
doc.getElementsByTagNameNS(FeedUtils.MOZ_PARSERERROR_NS, "parsererror")[0])
|
||||
{
|
||||
// No xml doc or gecko caught a basic parsing error.
|
||||
aFeed.onParseError(aFeed);
|
||||
return new Array();
|
||||
}
|
||||
else if((aDOM.documentElement.namespaceURI == "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
|
||||
&& (aDOM.documentElement.getElementsByTagNameNS("http://purl.org/rss/1.0/", "channel")[0]))
|
||||
else if(doc.namespaceURI == FeedUtils.RDF_SYNTAX_NS &&
|
||||
doc.getElementsByTagNameNS(FeedUtils.RSS_NS, "channel")[0])
|
||||
{
|
||||
debug(aFeed.url + " is an RSS 1.x (RDF-based) feed");
|
||||
// aSource can be misencoded (XMLHttpRequest converts to UTF-8 by default),
|
||||
// but the DOM is almost always right because it uses the hints in the XML file.
|
||||
// This is slower, but not noticably so. Mozilla doesn't have the
|
||||
// XMLHttpRequest.responseBody property that IE has, which provides access
|
||||
// to the unencoded response.
|
||||
var xmlString=serializer.serializeToString(aDOM.documentElement);
|
||||
aFeed.mFeedType = "RSS_1.xRDF"
|
||||
FeedUtils.log.debug("FeedParser.parseFeed: type:url - " +
|
||||
aFeed.mFeedType +" : " +aFeed.url);
|
||||
// aSource can be misencoded (XMLHttpRequest converts to UTF-8 by default),
|
||||
// but the DOM is almost always right because it uses the hints in the
|
||||
// XML file. This is slower, but not noticably so. Mozilla doesn't have
|
||||
// the XMLHttpRequest.responseBody property that IE has, which provides
|
||||
// access to the unencoded response.
|
||||
let xmlString = this.mSerializer.serializeToString(doc);
|
||||
return this.parseAsRSS1(aFeed, xmlString, aBaseURI);
|
||||
}
|
||||
else if (aDOM.documentElement.namespaceURI == ATOM_03_NS)
|
||||
else if (doc.namespaceURI == FeedUtils.ATOM_03_NS)
|
||||
{
|
||||
debug(aFeed.url + " is an Atom 0.3 feed");
|
||||
aFeed.mFeedType = "ATOM_0.3"
|
||||
FeedUtils.log.debug("FeedParser.parseFeed: type:url - " +
|
||||
aFeed.mFeedType +" : " +aFeed.url);
|
||||
return this.parseAsAtom(aFeed, aDOM);
|
||||
}
|
||||
else if (aDOM.documentElement.namespaceURI == ATOM_IETF_NS)
|
||||
else if (doc.namespaceURI == FeedUtils.ATOM_IETF_NS)
|
||||
{
|
||||
debug(aFeed.url + " is an IETF Atom feed");
|
||||
aFeed.mFeedType = "ATOM_IETF"
|
||||
FeedUtils.log.debug("FeedParser.parseFeed: type:url - " +
|
||||
aFeed.mFeedType +" : " +aFeed.url);
|
||||
return this.parseAsAtomIETF(aFeed, aDOM);
|
||||
}
|
||||
else if (aDOM.documentElement.getElementsByTagNameNS("http://my.netscape.com/rdf/simple/0.9/", "channel")[0])
|
||||
else if (doc.getElementsByTagNameNS(FeedUtils.RSS_090_NS, "channel")[0])
|
||||
{
|
||||
debug(aFeed.url + " is an 0.90 feed");
|
||||
aFeed.mFeedType = "RSS_0.90"
|
||||
FeedUtils.log.debug("FeedParser.parseFeed: type:url - " +
|
||||
aFeed.mFeedType +" : " +aFeed.url);
|
||||
return this.parseAsRSS2(aFeed, aDOM);
|
||||
}
|
||||
// XXX Explicitly check for RSS 2.0 instead of letting it be handled by the
|
||||
// default behavior (who knows, we may change the default at some point).
|
||||
else
|
||||
else
|
||||
{
|
||||
// We don't know what kind of feed this is; let's pretend it's RSS 0.9x
|
||||
// and hope things work out for the best. In theory even RSS 1.0 feeds
|
||||
// could be parsed by the 0.9x parser if the RSS namespace was the default.
|
||||
debug(aFeed.url + " is of unknown format; assuming an RSS 0.9x feed");
|
||||
// Parse as RSS 0.9x. In theory even RSS 1.0 feeds could be parsed by
|
||||
// the 0.9x parser if the RSS namespace were the default.
|
||||
let rssVer = doc.localName == "rss" ? doc.getAttribute("version") : null;
|
||||
if (rssVer)
|
||||
aFeed.mFeedType = "RSS_" + rssVer;
|
||||
else
|
||||
aFeed.mFeedType = "RSS_0.9x?";
|
||||
FeedUtils.log.debug("FeedParser.parseFeed: type:url - " +
|
||||
aFeed.mFeedType +" : " +aFeed.url);
|
||||
return this.parseAsRSS2(aFeed, aDOM);
|
||||
}
|
||||
},
|
||||
|
||||
parseAsRSS2: function (aFeed, aDOM)
|
||||
parseAsRSS2: function (aFeed, aDOM)
|
||||
{
|
||||
// Get the first channel (assuming there is only one per RSS File).
|
||||
var parsedItems = new Array();
|
||||
let parsedItems = new Array();
|
||||
|
||||
var channel = aDOM.getElementsByTagName("channel")[0];
|
||||
let channel = aDOM.getElementsByTagName("channel")[0];
|
||||
if (!channel)
|
||||
return aFeed.onParseError(aFeed);
|
||||
|
||||
//usually the empty string, unless this is RSS .90
|
||||
var nsURI = channel.namespaceURI || "";
|
||||
debug("channel NS: '" + nsURI +"'");
|
||||
// Usually the empty string, unless this is RSS .90.
|
||||
let nsURI = channel.namespaceURI || "";
|
||||
FeedUtils.log.debug("FeedParser.parseAsRSS2: channel nsURI - " + nsURI);
|
||||
|
||||
aFeed.title = aFeed.title || getNodeValue(this.childrenByTagNameNS(channel, nsURI, "title")[0]);
|
||||
aFeed.description = getNodeValue(this.childrenByTagNameNS(channel, nsURI, "description")[0]);
|
||||
aFeed.link = getNodeValue(this.childrenByTagNameNS(channel, nsURI, "link")[0]);
|
||||
let tags = this.childrenByTagNameNS(channel, nsURI, "title");
|
||||
aFeed.title = aFeed.title || this.getNodeValue(tags ? tags[0] : null);
|
||||
tags = this.childrenByTagNameNS(channel, nsURI, "description");
|
||||
aFeed.description = this.getNodeValue(tags ? tags[0] : null);
|
||||
tags = this.childrenByTagNameNS(channel, nsURI, "link");
|
||||
aFeed.link = this.getNodeValue(tags ? tags[0] : null);
|
||||
|
||||
if (!aFeed.parseItems)
|
||||
return parsedItems;
|
||||
|
||||
aFeed.invalidateItems();
|
||||
// XXX use getElementsByTagNameNS for now
|
||||
// childrenByTagNameNS would be better, but RSS .90 is still with us
|
||||
var itemNodes = aDOM.getElementsByTagNameNS(nsURI,"item");
|
||||
// XXX use getElementsByTagNameNS for now; childrenByTagNameNS would be
|
||||
// better, but RSS .90 is still with us.
|
||||
let itemNodes = aDOM.getElementsByTagNameNS(nsURI, "item");
|
||||
FeedUtils.log.debug("FeedParser.parseAsRSS2: items to parse - " +
|
||||
itemNodes.length);
|
||||
|
||||
for (var i=0; i < itemNodes.length; i++)
|
||||
for (let i = 0; i < itemNodes.length; i++)
|
||||
{
|
||||
var itemNode = itemNodes[i];
|
||||
var item = new FeedItem();
|
||||
let itemNode = itemNodes[i];
|
||||
let item = new FeedItem();
|
||||
item.feed = aFeed;
|
||||
item.characterSet = "UTF-8";
|
||||
|
||||
var link = getNodeValue(this.childrenByTagNameNS(itemNode, nsURI, "link")[0]);
|
||||
var guidNode = this.childrenByTagNameNS(itemNode, nsURI, "guid")[0];
|
||||
var guid;
|
||||
var isPermaLink = false;
|
||||
if (guidNode)
|
||||
tags = this.childrenByTagNameNS(itemNode, nsURI, "link");
|
||||
let link = this.getNodeValue(tags ? tags[0] : null);
|
||||
tags = this.childrenByTagNameNS(itemNode, nsURI, "guid");
|
||||
let guidNode = tags ? tags[0] : null;
|
||||
|
||||
let guid;
|
||||
let isPermaLink = false;
|
||||
if (guidNode)
|
||||
{
|
||||
guid = getNodeValue(guidNode);
|
||||
guid = this.getNodeValue(guidNode);
|
||||
// isPermaLink is true if the value is "true" or if the attribute is
|
||||
// not present; all other values, including "false" and "False" and
|
||||
// for that matter "TRuE" and "meatcake" are false.
|
||||
if (!guidNode.hasAttribute("isPermaLink") ||
|
||||
guidNode.getAttribute("isPermaLink") == "true")
|
||||
isPermaLink = true;
|
||||
// if attribute isPermaLink is missing, it is good to check the validity
|
||||
// of <guid> value as an URL to avoid linking to non-URL strings
|
||||
// If attribute isPermaLink is missing, it is good to check the validity
|
||||
// of <guid> value as an URL to avoid linking to non-URL strings.
|
||||
if (!guidNode.hasAttribute("isPermaLink"))
|
||||
{
|
||||
try
|
||||
{
|
||||
gIOService.newURI(guid, null, null);
|
||||
if (gIOService.extractScheme(guid) == "tag")
|
||||
Services.io.newURI(guid, null, null);
|
||||
if (Services.io.extractScheme(guid) == "tag")
|
||||
isPermaLink = false;
|
||||
}
|
||||
catch (ex)
|
||||
|
@ -163,182 +179,215 @@ FeedParser.prototype =
|
|||
}
|
||||
|
||||
item.url = (guid && isPermaLink) ? guid : link ? link : null;
|
||||
item.description = getNodeValue(this.childrenByTagNameNS(itemNode, nsURI, "description")[0]);
|
||||
item.title = getNodeValue(this.childrenByTagNameNS(itemNode, nsURI, "title")[0])
|
||||
|| (item.description ? (this.stripTags(item.description).substr(0, 150)) : null)
|
||||
|| item.title;
|
||||
tags = this.childrenByTagNameNS(itemNode, nsURI, "description");
|
||||
item.description = this.getNodeValue(tags ? tags[0] : null);
|
||||
tags = this.childrenByTagNameNS(itemNode, nsURI, "title");
|
||||
item.title = this.getNodeValue(tags ? tags[0] : null) ||
|
||||
(item.description ?
|
||||
this.stripTags(item.description).substr(0, 150) : null) ||
|
||||
item.title;
|
||||
|
||||
item.author = getNodeValue(this.childrenByTagNameNS(itemNode, nsURI, "author")[0]
|
||||
|| this.childrenByTagNameNS(itemNode, DC_NS, "creator")[0])
|
||||
|| aFeed.title
|
||||
|| item.author;
|
||||
item.date = getNodeValue(this.childrenByTagNameNS(itemNode, nsURI, "pubDate")[0]
|
||||
|| this.childrenByTagNameNS(itemNode, DC_NS, "date")[0])
|
||||
|| item.date;
|
||||
tags = this.childrenByTagNameNS(itemNode, nsURI, "author");
|
||||
if (!tags)
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.DC_NS, "creator");
|
||||
item.author = this.getNodeValue(tags ? tags[0] : null) ||
|
||||
aFeed.title ||
|
||||
item.author;
|
||||
|
||||
tags = this.childrenByTagNameNS(itemNode, nsURI, "pubDate");
|
||||
if (!tags)
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.DC_NS, "date");
|
||||
item.date = this.getNodeValue(tags ? tags[0] : null) || item.date;
|
||||
|
||||
if (!item.id)
|
||||
item.id = item.feed.url + '#' + (item.date || item.title);
|
||||
item.id = item.feed.url + "#" + (item.date || item.title);
|
||||
|
||||
// If the date is invalid, users will see the beginning of the epoch
|
||||
// unless we reset it here, so they'll see the current time instead.
|
||||
// This is typical aggregator behavior.
|
||||
if(item.date)
|
||||
if (item.date)
|
||||
{
|
||||
item.date = item.date.trim();
|
||||
if(!isValidRFC822Date(item.date))
|
||||
if (!this.isValidRFC822Date(item.date))
|
||||
{
|
||||
// XXX Use this on the other formats as well
|
||||
item.date = dateRescue(item.date);
|
||||
// XXX Use this on the other formats as well.
|
||||
item.date = this.dateRescue(item.date);
|
||||
}
|
||||
}
|
||||
|
||||
var content = getNodeValue(this.childrenByTagNameNS(itemNode, RSS_CONTENT_NS, "encoded")[0]);
|
||||
if(content)
|
||||
item.content = content;
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.RSS_CONTENT_NS, "encoded");
|
||||
item.content = this.getNodeValue(tags ? tags[0] : null);
|
||||
|
||||
// Handle an enclosure (if present)
|
||||
var enclosureNode = this.childrenByTagNameNS(itemNode, nsURI, "enclosure")[0];
|
||||
// Handle an enclosure (if present).
|
||||
tags = this.childrenByTagNameNS(itemNode, nsURI, "enclosure");
|
||||
let enclosureNode = tags ? tags[0] : null;
|
||||
if (enclosureNode)
|
||||
item.enclosure = new FeedEnclosure(enclosureNode.getAttribute("url"),
|
||||
enclosureNode.getAttribute("type"),
|
||||
enclosureNode.getAttribute("length"));
|
||||
item.enclosure = new FeedEnclosure(enclosureNode.getAttribute("url"),
|
||||
enclosureNode.getAttribute("type"),
|
||||
enclosureNode.getAttribute("length"));
|
||||
parsedItems[i] = item;
|
||||
}
|
||||
|
||||
return parsedItems;
|
||||
},
|
||||
|
||||
parseAsRSS1 : function(aFeed, aSource, aBaseURI)
|
||||
parseAsRSS1 : function(aFeed, aSource, aBaseURI)
|
||||
{
|
||||
var parsedItems = new Array();
|
||||
let parsedItems = new Array();
|
||||
|
||||
// RSS 1.0 is valid RDF, so use the RDF parser/service to extract data.
|
||||
// Create a new RDF data source and parse the feed into it.
|
||||
var ds = Components.classes["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"]
|
||||
.createInstance(Components.interfaces.nsIRDFDataSource);
|
||||
let ds = Cc["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"].
|
||||
createInstance(Ci.nsIRDFDataSource);
|
||||
|
||||
let rdfparser = Cc["@mozilla.org/rdf/xml-parser;1"].
|
||||
createInstance(Ci.nsIRDFXMLParser);
|
||||
rdfparser.parseString(ds, aBaseURI, aSource);
|
||||
|
||||
|
||||
// Get information about the feed as a whole.
|
||||
var channel = ds.GetSource(RDF_TYPE, RSS_CHANNEL, true);
|
||||
|
||||
aFeed.title = aFeed.title || getRDFTargetValue(ds, channel, RSS_TITLE) || aFeed.url;
|
||||
aFeed.description = getRDFTargetValue(ds, channel, RSS_DESCRIPTION) || "";
|
||||
aFeed.link = getRDFTargetValue(ds, channel, RSS_LINK) || aFeed.url;
|
||||
let channel = ds.GetSource(FeedUtils.RDF_TYPE, FeedUtils.RSS_CHANNEL, true);
|
||||
|
||||
aFeed.title = aFeed.title ||
|
||||
this.getRDFTargetValue(ds, channel, FeedUtils.RSS_TITLE) ||
|
||||
aFeed.url;
|
||||
aFeed.description = this.getRDFTargetValue(ds, channel, FeedUtils.RSS_DESCRIPTION) ||
|
||||
"";
|
||||
aFeed.link = this.getRDFTargetValue(ds, channel, FeedUtils.RSS_LINK) ||
|
||||
aFeed.url;
|
||||
|
||||
if (!aFeed.parseItems)
|
||||
return parsedItems;
|
||||
|
||||
aFeed.invalidateItems();
|
||||
|
||||
var items = ds.GetTarget(channel, RSS_ITEMS, true);
|
||||
let items = ds.GetTarget(channel, FeedUtils.RSS_ITEMS, true);
|
||||
if (items)
|
||||
items = rdfcontainer.MakeSeq(ds, items).GetElements();
|
||||
|
||||
items = FeedUtils.rdfContainerUtils.MakeSeq(ds, items).GetElements();
|
||||
|
||||
// If the channel doesn't list any items, look for resources of type "item"
|
||||
// (a hacky workaround for some buggy feeds).
|
||||
if (!items || !items.hasMoreElements())
|
||||
items = ds.GetSources(RDF_TYPE, RSS_ITEM, true);
|
||||
items = ds.GetSources(FeedUtils.RDF_TYPE, FeedUtils.RSS_ITEM, true);
|
||||
|
||||
var index = 0;
|
||||
while (items.hasMoreElements())
|
||||
let index = 0;
|
||||
while (items.hasMoreElements())
|
||||
{
|
||||
var itemResource = items.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
var item = new FeedItem();
|
||||
let itemResource = items.getNext().QueryInterface(Ci.nsIRDFResource);
|
||||
let item = new FeedItem();
|
||||
item.feed = aFeed;
|
||||
item.characterSet = "UTF-8";
|
||||
|
||||
// Prefer the value of the link tag to the item URI since the URI could be
|
||||
// a relative URN.
|
||||
var uri = itemResource.Value;
|
||||
var link = getRDFTargetValue(ds, itemResource, RSS_LINK);
|
||||
let uri = itemResource.Value;
|
||||
let link = this.getRDFTargetValue(ds, itemResource, FeedUtils.RSS_LINK);
|
||||
|
||||
// XXX
|
||||
// check for bug258465 -- entities appear escaped
|
||||
// in the value returned by getRDFTargetValue when they shouldn't
|
||||
// XXX Check for bug258465 - entities appear escaped in the value
|
||||
// returned by getRDFTargetValue when they shouldn't.
|
||||
//debug("link comparison\n" + " uri: " + uri + "\nlink: " + link);
|
||||
|
||||
item.url = link || uri;
|
||||
item.id = item.url;
|
||||
item.description = getRDFTargetValue(ds, itemResource, RSS_DESCRIPTION);
|
||||
item.title = getRDFTargetValue(ds, itemResource, RSS_TITLE)
|
||||
|| getRDFTargetValue(ds, itemResource, DC_SUBJECT)
|
||||
|| (item.description ? (this.stripTags(item.description).substr(0, 150)) : null)
|
||||
|| item.title;
|
||||
item.author = getRDFTargetValue(ds, itemResource, DC_CREATOR)
|
||||
|| getRDFTargetValue(ds, channel, DC_CREATOR)
|
||||
|| aFeed.title
|
||||
|| item.author;
|
||||
|
||||
item.date = getRDFTargetValue(ds, itemResource, DC_DATE) || item.date;
|
||||
item.content = getRDFTargetValue(ds, itemResource, RSS_CONTENT_ENCODED);
|
||||
item.description = this.getRDFTargetValue(ds, itemResource,
|
||||
FeedUtils.RSS_DESCRIPTION);
|
||||
item.title = this.getRDFTargetValue(ds, itemResource, FeedUtils.RSS_TITLE) ||
|
||||
this.getRDFTargetValue(ds, itemResource, FeedUtils.DC_SUBJECT) ||
|
||||
(item.description ?
|
||||
(this.stripTags(item.description).substr(0, 150)) : null) ||
|
||||
item.title;
|
||||
item.author = this.getRDFTargetValue(ds, itemResource, FeedUtils.DC_CREATOR) ||
|
||||
this.getRDFTargetValue(ds, channel, FeedUtils.DC_CREATOR) ||
|
||||
aFeed.title ||
|
||||
item.author;
|
||||
item.date = this.getRDFTargetValue(ds, itemResource, FeedUtils.DC_DATE) ||
|
||||
item.date;
|
||||
item.content = this.getRDFTargetValue(ds, itemResource,
|
||||
FeedUtils.RSS_CONTENT_ENCODED);
|
||||
|
||||
parsedItems[index++] = item;
|
||||
}
|
||||
|
||||
FeedUtils.log.debug("FeedParser.parseAsRSS1: items parsed - " + index);
|
||||
|
||||
return parsedItems;
|
||||
},
|
||||
|
||||
parseAsAtom: function(aFeed, aDOM)
|
||||
parseAsAtom: function(aFeed, aDOM)
|
||||
{
|
||||
var parsedItems = new Array();
|
||||
let parsedItems = new Array();
|
||||
|
||||
// Get the first channel (assuming there is only one per Atom File).
|
||||
var channel = aDOM.getElementsByTagName("feed")[0];
|
||||
let channel = aDOM.getElementsByTagName("feed")[0];
|
||||
if (!channel)
|
||||
{
|
||||
aFeed.onParseError(aFeed);
|
||||
return parsedItems;
|
||||
}
|
||||
|
||||
aFeed.title = aFeed.title || this.stripTags(getNodeValue(this.childrenByTagNameNS(channel, ATOM_03_NS, "title")[0]));
|
||||
aFeed.description = getNodeValue(this.childrenByTagNameNS(channel, ATOM_03_NS, "tagline")[0]);
|
||||
aFeed.link = this.findAtomLink("alternate",this.childrenByTagNameNS(channel, ATOM_03_NS, "link"));
|
||||
let tags = this.childrenByTagNameNS(channel, FeedUtils.ATOM_03_NS, "title");
|
||||
aFeed.title = aFeed.title ||
|
||||
this.stripTags(this.getNodeValue(tags ? tags[0] : null));
|
||||
tags = this.childrenByTagNameNS(channel, FeedUtils.ATOM_03_NS, "tagline");
|
||||
aFeed.description = this.getNodeValue(tags ? tags[0] : null);
|
||||
tags = this.childrenByTagNameNS(channel, FeedUtils.ATOM_03_NS, "link");
|
||||
aFeed.link = this.findAtomLink("alternate", tags);
|
||||
|
||||
if (!aFeed.parseItems)
|
||||
return parsedItems;
|
||||
|
||||
aFeed.invalidateItems();
|
||||
var items = this.childrenByTagNameNS(channel, ATOM_03_NS, "entry");
|
||||
debug("Items to parse: " + items.length);
|
||||
|
||||
for (var i=0; i < items.length; i++)
|
||||
let items = this.childrenByTagNameNS(channel, FeedUtils.ATOM_03_NS, "entry");
|
||||
FeedUtils.log.debug("FeedParser.parseAsAtom: items to parse - " +
|
||||
items.length);
|
||||
|
||||
for (let i = 0; i < items.length; i++)
|
||||
{
|
||||
var itemNode = items[i];
|
||||
var item = new FeedItem();
|
||||
let itemNode = items[i];
|
||||
let item = new FeedItem();
|
||||
item.feed = aFeed;
|
||||
item.characterSet = "UTF-8";
|
||||
|
||||
var url;
|
||||
url = this.findAtomLink("alternate",this.childrenByTagNameNS(itemNode, ATOM_03_NS, "link"));
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_03_NS, "link");
|
||||
item.url = this.findAtomLink("alternate", tags);
|
||||
|
||||
item.url = url;
|
||||
item.id = getNodeValue(this.childrenByTagNameNS(itemNode, ATOM_03_NS, "id")[0]);
|
||||
item.description = getNodeValue(this.childrenByTagNameNS(itemNode, ATOM_03_NS, "summary")[0]);
|
||||
item.title = getNodeValue(this.childrenByTagNameNS(itemNode, ATOM_03_NS, "title")[0])
|
||||
|| (item.description ? item.description.substr(0, 150) : null)
|
||||
|| item.title;
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_03_NS, "id");
|
||||
item.id = this.getNodeValue(tags ? tags[0] : null);
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_03_NS, "summary");
|
||||
item.description = this.getNodeValue(tags ? tags[0] : null);
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_03_NS, "title");
|
||||
item.title = this.getNodeValue(tags ? tags[0] : null) ||
|
||||
(item.description ? item.description.substr(0, 150) : null) ||
|
||||
item.title;
|
||||
|
||||
var authorEl = this.childrenByTagNameNS(itemNode, ATOM_03_NS, "author")[0]
|
||||
|| this.childrenByTagNameNS(itemNode, ATOM_03_NS, "contributor")[0]
|
||||
|| this.childrenByTagNameNS(channel, ATOM_03_NS, "author")[0];
|
||||
var author = "";
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_03_NS, "author");
|
||||
if (!tags)
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_03_NS, "contributor");
|
||||
if (!tags)
|
||||
tags = this.childrenByTagNameNS(channel, FeedUtils.ATOM_03_NS, "author");
|
||||
|
||||
if (authorEl)
|
||||
let authorEl = tags ? tags[0] : null;
|
||||
|
||||
let author = "";
|
||||
if (authorEl)
|
||||
{
|
||||
var name = getNodeValue(this.childrenByTagNameNS(authorEl, ATOM_03_NS, "name")[0]);
|
||||
var email = getNodeValue(this.childrenByTagNameNS(authorEl, ATOM_03_NS, "email")[0]);
|
||||
tags = this.childrenByTagNameNS(authorEl, FeedUtils.ATOM_03_NS, "name");
|
||||
let name = this.getNodeValue(tags ? tags[0] : null);
|
||||
tags = this.childrenByTagNameNS(authorEl, FeedUtils.ATOM_03_NS, "email");
|
||||
let email = this.getNodeValue(tags ? tags[0] : null);
|
||||
if (name)
|
||||
author = name + (email ? " <" + email + ">" : "");
|
||||
else if (email)
|
||||
author = email;
|
||||
}
|
||||
|
||||
|
||||
item.author = author || item.author || aFeed.title;
|
||||
|
||||
item.date = getNodeValue(this.childrenByTagNameNS(itemNode, ATOM_03_NS, "modified")[0]
|
||||
|| this.childrenByTagNameNS(itemNode, ATOM_03_NS, "issued")[0]
|
||||
|| this.childrenByTagNameNS(itemNode, ATOM_03_NS, "created")[0])
|
||||
|| item.date;
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_03_NS, "modified");
|
||||
if (!tags)
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_03_NS, "issued");
|
||||
if (!tags)
|
||||
tags = this.childrenByTagNameNS(channel, FeedUtils.ATOM_03_NS, "created");
|
||||
|
||||
item.date = this.getNodeValue(tags ? tags[0] : null) || item.date;
|
||||
|
||||
// XXX We should get the xml:base attribute from the content tag as well
|
||||
// and use it as the base HREF of the message.
|
||||
|
@ -348,104 +397,132 @@ FeedParser.prototype =
|
|||
// a namespace to identify the tags as HTML; and a few are buggy and put
|
||||
// HTML tags in without declaring their namespace so they look like Atom.
|
||||
// We deal with the first two but not the third.
|
||||
|
||||
var content;
|
||||
var contentNode = this.childrenByTagNameNS(itemNode, ATOM_03_NS, "content")[0];
|
||||
if (contentNode)
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_03_NS, "content");
|
||||
let contentNode = tags ? tags[0] : null;
|
||||
|
||||
let content;
|
||||
if (contentNode)
|
||||
{
|
||||
content = "";
|
||||
for (var j=0; j < contentNode.childNodes.length; j++)
|
||||
for (let j = 0; j < contentNode.childNodes.length; j++)
|
||||
{
|
||||
var node = contentNode.childNodes.item(j);
|
||||
let node = contentNode.childNodes.item(j);
|
||||
if (node.nodeType == node.CDATA_SECTION_NODE)
|
||||
content += node.data;
|
||||
else
|
||||
content += serializer.serializeToString(node);
|
||||
content += this.mSerializer.serializeToString(node);
|
||||
}
|
||||
|
||||
if (contentNode.getAttribute('mode') == "escaped")
|
||||
if (contentNode.getAttribute("mode") == "escaped")
|
||||
{
|
||||
content = content.replace(/</g, "<");
|
||||
content = content.replace(/>/g, ">");
|
||||
content = content.replace(/&/g, "&");
|
||||
}
|
||||
|
||||
|
||||
if (content == "")
|
||||
content = null;
|
||||
}
|
||||
|
||||
|
||||
item.content = content;
|
||||
parsedItems[i] = item;
|
||||
}
|
||||
|
||||
return parsedItems;
|
||||
},
|
||||
|
||||
parseAsAtomIETF: function(aFeed, aDOM)
|
||||
{
|
||||
|
||||
var parsedItems = new Array();
|
||||
let parsedItems = new Array();
|
||||
|
||||
// Get the first channel (assuming there is only one per Atom File).
|
||||
var channel = this.childrenByTagNameNS(aDOM,ATOM_IETF_NS,"feed")[0];
|
||||
let channel = this.childrenByTagNameNS(aDOM, FeedUtils.ATOM_IETF_NS, "feed")[0];
|
||||
if (!channel)
|
||||
{
|
||||
aFeed.onParseError(aFeed);
|
||||
return parsedItems;
|
||||
}
|
||||
|
||||
aFeed.title = aFeed.title || this.stripTags(this.serializeTextConstruct(this.childrenByTagNameNS(channel,ATOM_IETF_NS,"title")[0]));
|
||||
aFeed.description = this.serializeTextConstruct(this.childrenByTagNameNS(channel,ATOM_IETF_NS,"subtitle")[0]);
|
||||
aFeed.link = this.findAtomLink("alternate", this.childrenByTagNameNS(channel,ATOM_IETF_NS,"link"));
|
||||
|
||||
let tags = this.childrenByTagNameNS(channel, FeedUtils.ATOM_IETF_NS, "title");
|
||||
aFeed.title = aFeed.title ||
|
||||
this.stripTags(this.serializeTextConstruct(tags ? tags[0] : null));
|
||||
|
||||
tags = this.childrenByTagNameNS(channel, FeedUtils.ATOM_IETF_NS, "subtitle");
|
||||
aFeed.description = this.serializeTextConstruct(tags ? tags[0] : null);
|
||||
|
||||
tags = this.childrenByTagNameNS(channel, FeedUtils.ATOM_IETF_NS, "link");
|
||||
aFeed.link = this.findAtomLink("alternate", tags);
|
||||
|
||||
if (!aFeed.parseItems)
|
||||
return parsedItems;
|
||||
|
||||
aFeed.invalidateItems();
|
||||
var items = this.childrenByTagNameNS(channel,ATOM_IETF_NS,"entry");
|
||||
debug("Items to parse: " + items.length);
|
||||
let items = this.childrenByTagNameNS(channel, FeedUtils.ATOM_IETF_NS, "entry");
|
||||
FeedUtils.log.debug("FeedParser.parseAsAtomIETF: items to parse - " +
|
||||
items.length);
|
||||
|
||||
for (var i=0; i < items.length; i++)
|
||||
for (let i = 0; i < items.length; i++)
|
||||
{
|
||||
var itemNode = items[i];
|
||||
var item = new FeedItem();
|
||||
let itemNode = items[i];
|
||||
let item = new FeedItem();
|
||||
item.feed = aFeed;
|
||||
item.characterSet = "UTF-8";
|
||||
item.isStoredWithId = true;
|
||||
item.url = this.findAtomLink("alternate", this.childrenByTagNameNS(itemNode, ATOM_IETF_NS, "link")) || aFeed.link;
|
||||
item.id = getNodeValue(this.childrenByTagNameNS(itemNode, ATOM_IETF_NS, "id")[0]);
|
||||
item.description = this.serializeTextConstruct(this.childrenByTagNameNS(itemNode, ATOM_IETF_NS, "summary")[0]);
|
||||
item.title = this.stripTags(this.serializeTextConstruct(this.childrenByTagNameNS(itemNode, ATOM_IETF_NS, "title")[0])
|
||||
|| (item.description ? item.description.substr(0, 150) : null)
|
||||
|| item.title);
|
||||
|
||||
// XXX Support multiple authors
|
||||
var source = this.childrenByTagNameNS(itemNode, ATOM_IETF_NS, "source")[0];
|
||||
var authorEl = this.childrenByTagNameNS(itemNode, ATOM_IETF_NS, "author")[0]
|
||||
|| (source ? this.childrenByTagNameNS(source, ATOM_IETF_NS, "author")[0] : null)
|
||||
|| this.childrenByTagNameNS(channel, ATOM_IETF_NS, "author")[0];
|
||||
var author = "";
|
||||
|
||||
if (authorEl)
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_IETF_NS, "link");
|
||||
item.url = this.findAtomLink("alternate", tags) || aFeed.link;
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_IETF_NS, "id");
|
||||
item.id = this.getNodeValue(tags ? tags[0] : null);
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_IETF_NS, "summary");
|
||||
item.description = this.serializeTextConstruct(tags ? tags[0] : null);
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_IETF_NS, "title");
|
||||
item.title = this.stripTags(this.serializeTextConstruct(tags ? tags[0] : null) ||
|
||||
(item.description ?
|
||||
item.description.substr(0, 150) : null) ||
|
||||
item.title);
|
||||
|
||||
// XXX Support multiple authors.
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_IETF_NS, "source");
|
||||
let source = tags ? tags[0] : null;
|
||||
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_IETF_NS, "author");
|
||||
if (!tags && source)
|
||||
tags = this.childrenByTagNameNS(source, FeedUtils.ATOM_IETF_NS, "author");
|
||||
if (!tags)
|
||||
tags = this.childrenByTagNameNS(channel, FeedUtils.ATOM_IETF_NS, "author");
|
||||
|
||||
let authorEl = tags ? tags[0] : null;
|
||||
|
||||
let author = "";
|
||||
if (authorEl)
|
||||
{
|
||||
var name = getNodeValue(this.childrenByTagNameNS(authorEl, ATOM_IETF_NS, "name")[0]);
|
||||
var email = getNodeValue(this.childrenByTagNameNS(authorEl, ATOM_IETF_NS, "email")[0]);
|
||||
tags = this.childrenByTagNameNS(authorEl, FeedUtils.ATOM_IETF_NS, "name");
|
||||
let name = this.getNodeValue(tags ? tags[0] : null);
|
||||
tags = this.childrenByTagNameNS(authorEl, FeedUtils.ATOM_IETF_NS, "email");
|
||||
let email = this.getNodeValue(tags ? tags[0] : null);
|
||||
if (name)
|
||||
author = name + (email ? " <" + email + ">" : "");
|
||||
else if (email)
|
||||
author = email;
|
||||
}
|
||||
|
||||
|
||||
item.author = author || item.author || aFeed.title;
|
||||
item.date = getNodeValue(this.childrenByTagNameNS(itemNode, ATOM_IETF_NS, "updated")[0]
|
||||
|| this.childrenByTagNameNS(itemNode, ATOM_IETF_NS, "published")[0])
|
||||
|| item.date;
|
||||
|
||||
item.content = this.serializeTextConstruct(this.childrenByTagNameNS(itemNode, ATOM_IETF_NS, "content")[0]);
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_IETF_NS, "updated");
|
||||
if (!tags)
|
||||
tags = this.childrenByTagNameNS(source, FeedUtils.ATOM_IETF_NS, "published");
|
||||
item.date = this.getNodeValue(tags ? tags[0] : null) || item.date;
|
||||
|
||||
if(item.content)
|
||||
item.xmlContentBase = this.childrenByTagNameNS(itemNode, ATOM_IETF_NS, "content")[0].baseURI;
|
||||
else if(item.description)
|
||||
item.xmlContentBase = this.childrenByTagNameNS(itemNode, ATOM_IETF_NS, "summary")[0].baseURI;
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_IETF_NS, "content");
|
||||
item.content = this.serializeTextConstruct(tags ? tags[0] : null);
|
||||
|
||||
if (item.content)
|
||||
item.xmlContentBase = tags ? tags[0].baseURI : null;
|
||||
else if (item.description)
|
||||
{
|
||||
tags = this.childrenByTagNameNS(itemNode, FeedUtils.ATOM_IETF_NS, "summary");
|
||||
item.xmlContentBase = tags ? tags[0].baseURI : null;
|
||||
}
|
||||
else
|
||||
item.xmlContentBase = itemNode.baseURI;
|
||||
|
||||
|
@ -453,79 +530,125 @@ FeedParser.prototype =
|
|||
}
|
||||
|
||||
return parsedItems;
|
||||
|
||||
},
|
||||
|
||||
serializeTextConstruct: function(textElement)
|
||||
{
|
||||
var content = "";
|
||||
|
||||
if (textElement)
|
||||
let content = "";
|
||||
if (textElement)
|
||||
{
|
||||
var textType = textElement.getAttribute('type');
|
||||
let textType = textElement.getAttribute("type");
|
||||
|
||||
// Atom spec says consider it "text" if not present
|
||||
if(!textType)
|
||||
// Atom spec says consider it "text" if not present.
|
||||
if (!textType)
|
||||
textType = "text";
|
||||
|
||||
// There could be some strange content type we don't handle
|
||||
if((textType != "text") && (textType != "html") && (textType != "xhtml"))
|
||||
// There could be some strange content type we don't handle.
|
||||
if (textType != "text" && textType != "html" && textType != "xhtml")
|
||||
return null;
|
||||
|
||||
for (var j=0; j < textElement.childNodes.length; j++)
|
||||
for (let j = 0; j < textElement.childNodes.length; j++)
|
||||
{
|
||||
var node = textElement.childNodes.item(j);
|
||||
let node = textElement.childNodes.item(j);
|
||||
if (node.nodeType == node.CDATA_SECTION_NODE)
|
||||
content += this.xmlEscape(node.data);
|
||||
else
|
||||
content += serializer.serializeToString(node);
|
||||
content += this.mSerializer.serializeToString(node);
|
||||
}
|
||||
if (textType == "html")
|
||||
|
||||
if (textType == "html")
|
||||
content = this.xmlUnescape(content);
|
||||
}
|
||||
|
||||
// other parts of the code depend on this being null
|
||||
// if there's no content
|
||||
// Other parts of the code depend on this being null if there's no content.
|
||||
return content ? content : null;
|
||||
},
|
||||
|
||||
// finds elements that are direct children of the first arg
|
||||
getRDFTargetValue: function(ds, source, property)
|
||||
{
|
||||
let node = ds.GetTarget(source, property, true);
|
||||
if (node)
|
||||
{
|
||||
try
|
||||
{
|
||||
node = node.QueryInterface(Ci.nsIRDFLiteral);
|
||||
if (node)
|
||||
return node.Value;
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
// If the RDF was bogus, do nothing. Rethrow if it's some other problem.
|
||||
if (!((e instanceof Ci.nsIXPCException) &&
|
||||
e.result == Cr.NS_ERROR_NO_INTERFACE))
|
||||
throw new Error("FeedParser.getRDFTargetValue: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
getNodeValue: function(node)
|
||||
{
|
||||
if (node && node.textContent)
|
||||
return node.textContent.trim();
|
||||
else if (node && node.firstChild)
|
||||
{
|
||||
let ret = "";
|
||||
for (let child = node.firstChild; child; child = child.nextSibling)
|
||||
{
|
||||
let value = this.getNodeValue(child);
|
||||
if (value)
|
||||
ret += value;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
// Finds elements that are direct children of the first arg.
|
||||
childrenByTagNameNS: function(aElement, aNamespace, aTagName)
|
||||
{
|
||||
var matches = aElement.getElementsByTagNameNS(aNamespace, aTagName);
|
||||
var matchingChildren = new Array();
|
||||
for (var i = 0; i < matches.length; i++)
|
||||
let matches = aElement.getElementsByTagNameNS(aNamespace, aTagName);
|
||||
let matchingChildren = new Array();
|
||||
for (let i = 0; i < matches.length; i++)
|
||||
{
|
||||
if(matches[i].parentNode == aElement)
|
||||
if (matches[i].parentNode == aElement)
|
||||
matchingChildren.push(matches[i])
|
||||
}
|
||||
return matchingChildren;
|
||||
|
||||
return matchingChildren.length ? matchingChildren : null;
|
||||
},
|
||||
|
||||
findAtomLink: function(linkRel, linkElements)
|
||||
{
|
||||
// XXX Need to check for MIME type and hreflang
|
||||
for ( var j=0 ; j<linkElements.length ; j++ ) {
|
||||
var alink = linkElements[j];
|
||||
if (alink &&
|
||||
//if there's a link rel
|
||||
((alink.getAttribute('rel') && alink.getAttribute('rel') == linkRel) ||
|
||||
//if there isn't, assume 'alternate'
|
||||
(!alink.getAttribute('rel') && (linkRel=="alternate")))
|
||||
&& alink.getAttribute('href'))
|
||||
// XXX Need to check for MIME type and hreflang.
|
||||
for (let j = 0; j < linkElements.length; j++) {
|
||||
let alink = linkElements[j];
|
||||
if (alink &&
|
||||
// If there's a link rel.
|
||||
((alink.getAttribute("rel") && alink.getAttribute("rel") == linkRel) ||
|
||||
// If there isn't, assume 'alternate'.
|
||||
(!alink.getAttribute("rel") && (linkRel == "alternate"))) &&
|
||||
alink.getAttribute("href"))
|
||||
{
|
||||
// Atom links are interpreted relative to xml:base
|
||||
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
return ioService.newURI(alink.baseURI, null, null).resolve(alink.getAttribute('href'));
|
||||
// Atom links are interpreted relative to xml:base.
|
||||
try {
|
||||
return Services.io.newURI(alink.baseURI, null, null).
|
||||
resolve(alink.getAttribute("href"));
|
||||
}
|
||||
catch (ex) {}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
|
||||
stripTags: function(someHTML)
|
||||
{
|
||||
return someHTML ? someHTML.replace(/<[^>]+>/g,"") : someHTML;
|
||||
return someHTML ? someHTML.replace(/<[^>]+>/g, "") : someHTML;
|
||||
},
|
||||
|
||||
xmlUnescape: function(s)
|
||||
|
@ -542,5 +665,41 @@ FeedParser.prototype =
|
|||
s = s.replace(/>/g, ">");
|
||||
s = s.replace(/</g, "<");
|
||||
return s;
|
||||
}
|
||||
},
|
||||
|
||||
// Date validator for RSS feeds
|
||||
FZ_RFC822_RE: "^(((Mon)|(Tue)|(Wed)|(Thu)|(Fri)|(Sat)|(Sun)), *)?\\d\\d?" +
|
||||
" +((Jan)|(Feb)|(Mar)|(Apr)|(May)|(Jun)|(Jul)|(Aug)|(Sep)|(Oct)|(Nov)|(Dec))" +
|
||||
" +\\d\\d(\\d\\d)? +\\d\\d:\\d\\d(:\\d\\d)? +(([+-]?\\d\\d\\d\\d)|(UT)|(GMT)" +
|
||||
"|(EST)|(EDT)|(CST)|(CDT)|(MST)|(MDT)|(PST)|(PDT)|\\w)$",
|
||||
|
||||
isValidRFC822Date: function(pubDate)
|
||||
{
|
||||
let regex = new RegExp(this.FZ_RFC822_RE);
|
||||
return regex.test(pubDate);
|
||||
},
|
||||
|
||||
dateRescue: function(dateString)
|
||||
{
|
||||
// Deal with various kinds of invalid dates.
|
||||
if (!isNaN(parseInt(dateString)))
|
||||
{
|
||||
// It's an integer, so maybe it's a timestamp.
|
||||
let d = new Date(parseInt(dateString) * 1000);
|
||||
let now = new Date();
|
||||
let yeardiff = now.getFullYear() - d.getFullYear();
|
||||
FeedUtils.log.trace("FeedParser.dateRescue: Rescue Timestamp date - " +
|
||||
d.toString() + " ,year diff - " + yeardiff);
|
||||
if (yeardiff >= 0 && yeardiff < 3)
|
||||
// It's quite likely the correct date.
|
||||
return d.toString();
|
||||
}
|
||||
|
||||
if (dateString.search(/^\d\d\d\d/) != -1)
|
||||
//Could be an ISO8601/W3C date.
|
||||
return new Date(dateString).toUTCString();
|
||||
|
||||
// Can't help. Set to current time.
|
||||
return (new Date()).toString();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -137,9 +137,9 @@ var gFeedSubscriptionsWindow = {
|
|||
{
|
||||
// If selecting a prior selected feed, get its folder from the db
|
||||
// in case an ancestor folder was renamed/moved.
|
||||
let itemResource = rdf.GetResource(item.url);
|
||||
let ds = getSubscriptionsDS(item.parentFolder.server);
|
||||
let itemFolder = ds.GetTarget(itemResource, FZ_DESTFOLDER, true);
|
||||
let itemResource = FeedUtils.rdf.GetResource(item.url);
|
||||
let ds = FeedUtils.getSubscriptionsDS(item.parentFolder.server);
|
||||
let itemFolder = ds.GetTarget(itemResource, FeedUtils.FZ_DESTFOLDER, true);
|
||||
if (itemFolder)
|
||||
{
|
||||
itemFolder = itemFolder.QueryInterface(Ci.nsIMsgFolder);
|
||||
|
@ -582,7 +582,7 @@ var gFeedSubscriptionsWindow = {
|
|||
// Finally, set the folder's quickMode based on the its first feed's
|
||||
// quickMode, since that is how the view determines summary mode, and now
|
||||
// quickMode is updated to be the same for all feeds in a folder.
|
||||
if (feeds)
|
||||
if (feeds && feeds[0])
|
||||
folderObject.quickMode = feeds[0].quickMode;
|
||||
|
||||
return folderObject;
|
||||
|
@ -591,16 +591,16 @@ var gFeedSubscriptionsWindow = {
|
|||
getFeedsInFolder: function (aFolder)
|
||||
{
|
||||
let feeds = new Array();
|
||||
let feedUrlArray = getFeedUrlsInFolder(aFolder);
|
||||
let feedUrlArray = FeedUtils.getFeedUrlsInFolder(aFolder);
|
||||
if (!feedUrlArray)
|
||||
// No feedUrls in this folder.
|
||||
return;
|
||||
return feeds;
|
||||
|
||||
for (let url in feedUrlArray)
|
||||
{
|
||||
if (!feedUrlArray[url])
|
||||
continue;
|
||||
let feedResource = rdf.GetResource(feedUrlArray[url]);
|
||||
let feedResource = FeedUtils.rdf.GetResource(feedUrlArray[url]);
|
||||
let feed = new Feed(feedResource, aFolder.server);
|
||||
feeds.push(feed);
|
||||
}
|
||||
|
@ -887,7 +887,7 @@ var gFeedSubscriptionsWindow = {
|
|||
item.folder.server.setBoolValue("quickMode", aChecked);
|
||||
this.refreshSubscriptionView();
|
||||
}
|
||||
else if (!getFeedUrlsInFolder(item.folder))
|
||||
else if (!FeedUtils.getFeedUrlsInFolder(item.folder))
|
||||
// Not a folder with feeds.
|
||||
return;
|
||||
else
|
||||
|
@ -945,7 +945,7 @@ var gFeedSubscriptionsWindow = {
|
|||
|
||||
if (item && item.folder &&
|
||||
(locationValue.hasAttribute("focused") || locationValue.value ||
|
||||
item.folder.isServer || getFeedUrlsInFolder(item.folder)))
|
||||
item.folder.isServer || FeedUtils.getFeedUrlsInFolder(item.folder)))
|
||||
{
|
||||
// Enable summary for account folder or folder with feeds or focus/value
|
||||
// in the feed url field of empty folders prior to add.
|
||||
|
@ -981,9 +981,9 @@ var gFeedSubscriptionsWindow = {
|
|||
return;
|
||||
}
|
||||
|
||||
deleteFeed(rdf.GetResource(itemToRemove.url),
|
||||
itemToRemove.parentFolder.server,
|
||||
itemToRemove.parentFolder);
|
||||
FeedUtils.deleteFeed(FeedUtils.rdf.GetResource(itemToRemove.url),
|
||||
itemToRemove.parentFolder.server,
|
||||
itemToRemove.parentFolder);
|
||||
|
||||
// Now that we have removed the feed from the datasource, it is time to
|
||||
// update our view layer. Update parent folder's quickMode if necessary
|
||||
|
@ -1061,7 +1061,7 @@ var gFeedSubscriptionsWindow = {
|
|||
|
||||
// Before we go any further, make sure the user is not already subscribed
|
||||
// to this feed.
|
||||
if (feedAlreadyExists(feedLocation, addFolder.server))
|
||||
if (FeedUtils.feedAlreadyExists(feedLocation, addFolder.server))
|
||||
{
|
||||
message = FeedUtils.strings.GetStringFromName(
|
||||
"subscribe-feedAlreadySubscribed");
|
||||
|
@ -1094,13 +1094,13 @@ var gFeedSubscriptionsWindow = {
|
|||
// Helper routine used by addFeed and importOPMLFile.
|
||||
storeFeed: function(feedProperties)
|
||||
{
|
||||
let itemResource = rdf.GetResource(feedProperties.feedLocation);
|
||||
let itemResource = FeedUtils.rdf.GetResource(feedProperties.feedLocation);
|
||||
let feed = new Feed(itemResource, feedProperties.server);
|
||||
|
||||
// If the user specified a folder to add the feed to, then set it here.
|
||||
if (feedProperties.folderURI)
|
||||
{
|
||||
let folderResource = rdf.GetResource(feedProperties.folderURI);
|
||||
let folderResource = FeedUtils.rdf.GetResource(feedProperties.folderURI);
|
||||
if (folderResource)
|
||||
{
|
||||
let folder = folderResource.QueryInterface(Ci.nsIMsgFolder);
|
||||
|
@ -1124,10 +1124,10 @@ var gFeedSubscriptionsWindow = {
|
|||
if (!itemToEdit || itemToEdit.container || !itemToEdit.parentFolder)
|
||||
return;
|
||||
|
||||
let resource = rdf.GetResource(itemToEdit.url);
|
||||
let resource = FeedUtils.rdf.GetResource(itemToEdit.url);
|
||||
let currentFolderServer = itemToEdit.parentFolder.server;
|
||||
let ds = getSubscriptionsDS(currentFolderServer);
|
||||
let currentFolder = ds.GetTarget(resource, FZ_DESTFOLDER, true);
|
||||
let ds = FeedUtils.getSubscriptionsDS(currentFolderServer);
|
||||
let currentFolder = ds.GetTarget(resource, FeedUtils.FZ_DESTFOLDER, true);
|
||||
let currentFolderURI = currentFolder.QueryInterface(Ci.nsIRDFResource).Value;
|
||||
let feed = new Feed(resource, currentFolderServer);
|
||||
feed.folder = itemToEdit.parentFolder;
|
||||
|
@ -1213,15 +1213,15 @@ var gFeedSubscriptionsWindow = {
|
|||
|
||||
let currentParentIndex = this.mView.getParentIndex(aOldFeedIndex);
|
||||
let currentParentItem = this.mView.getItemAtIndex(currentParentIndex);
|
||||
let currentParentResource = rdf.GetResource(currentParentItem.url);
|
||||
let currentParentResource = FeedUtils.rdf.GetResource(currentParentItem.url);
|
||||
let currentFolder = currentParentResource.QueryInterface(Ci.nsIMsgFolder);
|
||||
|
||||
let newParentItem = this.mView.getItemAtIndex(aNewParentIndex);
|
||||
let newParentResource = rdf.GetResource(newParentItem.url);
|
||||
let newParentResource = FeedUtils.rdf.GetResource(newParentItem.url);
|
||||
let newFolder = newParentResource.QueryInterface(Ci.nsIMsgFolder);
|
||||
|
||||
let ds = getSubscriptionsDS(currentItem.parentFolder.server);
|
||||
let resource = rdf.GetResource(currentItem.url);
|
||||
let ds = FeedUtils.getSubscriptionsDS(currentItem.parentFolder.server);
|
||||
let resource = FeedUtils.rdf.GetResource(currentItem.url);
|
||||
|
||||
let accountMoveCopy = false;
|
||||
if (currentFolder.rootFolder.URI == newFolder.rootFolder.URI)
|
||||
|
@ -1233,14 +1233,14 @@ var gFeedSubscriptionsWindow = {
|
|||
return;
|
||||
|
||||
// Unassert the older URI, add an assertion for the new parent URI.
|
||||
ds.Change(resource, FZ_DESTFOLDER,
|
||||
ds.Change(resource, FeedUtils.FZ_DESTFOLDER,
|
||||
currentParentResource, newParentResource);
|
||||
ds.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush();
|
||||
// Update the feed url attributes on the databases for each folder:
|
||||
// Remove our feed url property from the current folder.
|
||||
updateFolderFeedUrl(currentFolder, currentItem.url, true);
|
||||
FeedUtils.updateFolderFeedUrl(currentFolder, currentItem.url, true);
|
||||
// Add our feed url property to the new folder.
|
||||
updateFolderFeedUrl(newFolder, currentItem.url, false);
|
||||
FeedUtils.updateFolderFeedUrl(newFolder, currentItem.url, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1256,9 +1256,9 @@ var gFeedSubscriptionsWindow = {
|
|||
// Unsubscribe the feed from the old folder, if add to the new folder
|
||||
// is successfull, and doing a move.
|
||||
if (moveFeed)
|
||||
deleteFeed(rdf.GetResource(currentItem.url),
|
||||
currentItem.parentFolder.server,
|
||||
currentItem.parentFolder);
|
||||
FeedUtils.deleteFeed(FeedUtils.rdf.GetResource(currentItem.url),
|
||||
currentItem.parentFolder.server,
|
||||
currentItem.parentFolder);
|
||||
}
|
||||
|
||||
// Finally, update our view layer. Update old parent folder's quickMode
|
||||
|
@ -1300,7 +1300,7 @@ var gFeedSubscriptionsWindow = {
|
|||
{
|
||||
let feedItem = aFeedItem;
|
||||
let parentItem = aParentItem;
|
||||
let feedUrlArray = getFeedUrlsInFolder(feedItem.parentFolder);
|
||||
let feedUrlArray = FeedUtils.getFeedUrlsInFolder(feedItem.parentFolder);
|
||||
let feedsInFolder = feedUrlArray ? feedUrlArray.length : 0;
|
||||
|
||||
if (aRemove && feedsInFolder < 1)
|
||||
|
@ -1314,7 +1314,7 @@ var gFeedSubscriptionsWindow = {
|
|||
// only feed, update the parent folder to the feed's quickMode.
|
||||
if (feedsInFolder > 1)
|
||||
{
|
||||
let feedResource = rdf.GetResource(feedItem.url);
|
||||
let feedResource = FeedUtils.rdf.GetResource(feedItem.url);
|
||||
let feed = new Feed(feedResource, feedItem.parentFolder.server);
|
||||
feed.quickMode = parentItem.quickMode;
|
||||
feedItem.quickMode = parentItem.quickMode;
|
||||
|
@ -1358,11 +1358,11 @@ var gFeedSubscriptionsWindow = {
|
|||
|
||||
// If we get here we should always have a folder by now, either in
|
||||
// feed.folder or FeedItems created the folder for us.
|
||||
updateFolderFeedUrl(feed.folder, feed.url, false);
|
||||
FeedUtils.updateFolderFeedUrl(feed.folder, feed.url, false);
|
||||
|
||||
// Add feed adds the feed to the subscriptions db and flushes the
|
||||
// datasource.
|
||||
addFeed(feed.url, feed.name, feed.folder);
|
||||
FeedUtils.addFeed(feed.url, feed.name, feed.folder);
|
||||
|
||||
// Now add the feed to our view. If adding, the current selection will
|
||||
// be a folder; if updating it will be a feed. No need to rebuild the
|
||||
|
@ -1432,9 +1432,9 @@ var gFeedSubscriptionsWindow = {
|
|||
{
|
||||
// Non success. Remove intermediate traces from the feeds database.
|
||||
if (feed && feed.url && feed.server)
|
||||
deleteFeed(rdf.GetResource(feed.url),
|
||||
feed.server,
|
||||
feed.server.rootFolder);
|
||||
FeedUtils.deleteFeed(FeedUtils.rdf.GetResource(feed.url),
|
||||
feed.server,
|
||||
feed.server.rootFolder);
|
||||
|
||||
if (aErrorCode == FeedUtils.kNewsBlogInvalidFeed)
|
||||
message = FeedUtils.strings.GetStringFromName(
|
||||
|
@ -1466,7 +1466,7 @@ var gFeedSubscriptionsWindow = {
|
|||
this.onProgress(feed, aCurrentFeedItems, aMaxFeedItems);
|
||||
},
|
||||
|
||||
onProgress: function(feed, aProgress, aProgressMax)
|
||||
onProgress: function(feed, aProgress, aProgressMax, aLengthComputable)
|
||||
{
|
||||
gFeedSubscriptionsWindow.updateStatusItem("progressMeter",
|
||||
(aProgress * 100) / aProgressMax);
|
||||
|
@ -1588,7 +1588,10 @@ var gFeedSubscriptionsWindow = {
|
|||
let curSelItem = this.currentSelectedItem;
|
||||
let feedWindow = this.feedWindow;
|
||||
if (aMove && aDestFolder.getFlag(Ci.nsMsgFolderFlags.Trash))
|
||||
return this.folderDeleted(aSrcFolder);
|
||||
{
|
||||
this.folderDeleted(aSrcFolder);
|
||||
return
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
feedWindow.refreshSubscriptionView();
|
||||
|
@ -1819,7 +1822,7 @@ var gFeedSubscriptionsWindow = {
|
|||
return -1;
|
||||
|
||||
// Silently skip feeds that are already subscribed.
|
||||
if (feedAlreadyExists(newFeedUrl, this.mRSSServer))
|
||||
if (FeedUtils.feedAlreadyExists(newFeedUrl, this.mRSSServer))
|
||||
{
|
||||
FeedUtils.log.debug("importOutline: already subscribed in account "+
|
||||
this.mRSSServer.prettyName+", url - "+ newFeedUrl);
|
||||
|
@ -1846,11 +1849,11 @@ var gFeedSubscriptionsWindow = {
|
|||
feed.link = aOutline.getAttribute("htmlUrl");
|
||||
|
||||
feed.createFolder();
|
||||
updateFolderFeedUrl(feed.folder, feed.url, false);
|
||||
FeedUtils.updateFolderFeedUrl(feed.folder, feed.url, false);
|
||||
|
||||
// addFeed adds the feed we have validated and downloaded to
|
||||
// our datasource, it also flushes the subscription datasource.
|
||||
addFeed(feed.url, feed.name, feed.folder);
|
||||
FeedUtils.addFeed(feed.url, feed.name, feed.folder);
|
||||
// Feed correctly added.
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -62,8 +62,6 @@
|
|||
src="chrome://messenger-newsblog/content/utils.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://messenger-newsblog/content/file-utils.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://messenger-newsblog/content/debug-utils.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://messenger-newsblog/content/feed-subscriptions.js"/>
|
||||
<script type="application/javascript"
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,7 +1,6 @@
|
|||
newsblog.jar:
|
||||
% content messenger-newsblog %content/messenger-newsblog/
|
||||
* content/messenger-newsblog/newsblogOverlay.js (content/newsblogOverlay.js)
|
||||
* content/messenger-newsblog/debug-utils.js (content/debug-utils.js)
|
||||
* content/messenger-newsblog/Feed.js (content/Feed.js)
|
||||
* content/messenger-newsblog/FeedItem.js (content/FeedItem.js)
|
||||
* content/messenger-newsblog/feed-parser.js (content/feed-parser.js)
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
* Myk Melez <myk@mozilla.org) (Original Author)
|
||||
* David Bienvenu <bienvenu@nventure.com>
|
||||
* Ian Neal <iann_bugzilla@blueyonder.co.uk>
|
||||
* alta88 <alta88@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -59,14 +60,6 @@ var nsNewsBlogFeedDownloader =
|
|||
return;
|
||||
}
|
||||
|
||||
let feedUrlArray = getFeedUrlsInFolder(aFolder);
|
||||
|
||||
// Return if there are no feedUrls for the base folder in the feeds
|
||||
// database, the base folder has no subfolders, or the folder is in Trash.
|
||||
if ((!feedUrlArray && !aFolder.hasSubFolders) ||
|
||||
aFolder.isSpecialFolder(Ci.nsMsgFolderFlags.Trash, true))
|
||||
return;
|
||||
|
||||
let allFolders = Cc["@mozilla.org/supports-array;1"].
|
||||
createInstance(Ci.nsISupportsArray);
|
||||
// Add the base folder; it does not get added by ListDescendents.
|
||||
|
@ -107,7 +100,7 @@ var nsNewsBlogFeedDownloader =
|
|||
continue;
|
||||
}
|
||||
|
||||
let feedUrlArray = getFeedUrlsInFolder(folder);
|
||||
let feedUrlArray = FeedUtils.getFeedUrlsInFolder(folder);
|
||||
// Continue if there are no feedUrls for the folder in the feeds
|
||||
// database. All folders in Trash are now unsubscribed, so perhaps
|
||||
// we may not want to check that here each biff each folder.
|
||||
|
@ -126,7 +119,7 @@ var nsNewsBlogFeedDownloader =
|
|||
{
|
||||
if (feedUrlArray[url])
|
||||
{
|
||||
id = rdf.GetResource(feedUrlArray[url]);
|
||||
id = FeedUtils.rdf.GetResource(feedUrlArray[url]);
|
||||
feed = new Feed(id, folder.server);
|
||||
feed.folder = folder;
|
||||
// Bump our pending feed download count.
|
||||
|
@ -197,7 +190,7 @@ var nsNewsBlogFeedDownloader =
|
|||
for (let i = 0; i < allServers.Count() && !aFolder; i++)
|
||||
{
|
||||
let currentServer = allServers.QueryElementAt(i, Ci.nsIMsgIncomingServer);
|
||||
if (currentServer && currentServer.type == 'rss')
|
||||
if (currentServer && currentServer.type == "rss")
|
||||
aFolder = currentServer.rootFolder;
|
||||
}
|
||||
}
|
||||
|
@ -265,16 +258,16 @@ var nsNewsBlogFeedDownloader =
|
|||
|
||||
// Make sure we aren't already subscribed to this feed before we attempt
|
||||
// to subscribe to it.
|
||||
if (feedAlreadyExists(aUrl, aFolder.server))
|
||||
if (FeedUtils.feedAlreadyExists(aUrl, aFolder.server))
|
||||
{
|
||||
aMsgWindow.statusFeedback.showStatusString(
|
||||
FeedUtils.strings.GetStringFromName('subscribe-feedAlreadySubscribed'));
|
||||
FeedUtils.strings.GetStringFromName("subscribe-feedAlreadySubscribed"));
|
||||
return;
|
||||
}
|
||||
|
||||
let itemResource = rdf.GetResource(aUrl);
|
||||
let itemResource = FeedUtils.rdf.GetResource(aUrl);
|
||||
let feed = new Feed(itemResource, aFolder.server);
|
||||
feed.quickMode = feed.server.getBoolValue('quickMode');
|
||||
feed.quickMode = feed.server.getBoolValue("quickMode");
|
||||
|
||||
// If the root server, create a new folder for the feed. The user must
|
||||
// want us to add this subscription url to an existing RSS folder.
|
||||
|
@ -293,13 +286,13 @@ var nsNewsBlogFeedDownloader =
|
|||
|
||||
// An rss folder was just changed, get the folder's feedUrls and update
|
||||
// our feed data source.
|
||||
let feedUrlArray = getFeedUrlsInFolder(aFolder);
|
||||
let feedUrlArray = FeedUtils.getFeedUrlsInFolder(aFolder);
|
||||
if (!feedUrlArray)
|
||||
// No feedUrls in this folder.
|
||||
return;
|
||||
|
||||
let newFeedUrl, id, resource, node;
|
||||
let ds = getSubscriptionsDS(aFolder.server);
|
||||
let ds = FeedUtils.getSubscriptionsDS(aFolder.server);
|
||||
let trashFolder =
|
||||
aFolder.rootFolder.getFolderWithFlags(Ci.nsMsgFolderFlags.Trash);
|
||||
for (let url in feedUrlArray)
|
||||
|
@ -307,22 +300,22 @@ var nsNewsBlogFeedDownloader =
|
|||
newFeedUrl = feedUrlArray[url];
|
||||
if (newFeedUrl)
|
||||
{
|
||||
id = rdf.GetResource(newFeedUrl);
|
||||
id = FeedUtils.rdf.GetResource(newFeedUrl);
|
||||
// If explicit delete or move to trash, unsubscribe.
|
||||
if (aUnsubscribe ||
|
||||
(trashFolder && trashFolder.isAncestorOf(aFolder)))
|
||||
{
|
||||
deleteFeed(id, aFolder.server, aFolder);
|
||||
FeedUtils.deleteFeed(id, aFolder.server, aFolder);
|
||||
}
|
||||
else
|
||||
{
|
||||
resource = rdf.GetResource(aFolder.URI);
|
||||
resource = FeedUtils.rdf.GetResource(aFolder.URI);
|
||||
// Get the node for the current folder URI.
|
||||
node = ds.GetTarget(id, FZ_DESTFOLDER, true);
|
||||
node = ds.GetTarget(id, FeedUtils.FZ_DESTFOLDER, true);
|
||||
if (node)
|
||||
ds.Change(id, FZ_DESTFOLDER, node, resource);
|
||||
ds.Change(id, FeedUtils.FZ_DESTFOLDER, node, resource);
|
||||
else
|
||||
addFeed(newFeedUrl, resource.name, resource);
|
||||
FeedUtils.addFeed(newFeedUrl, resource.name, resource);
|
||||
}
|
||||
}
|
||||
} // for each feed url in the folder property
|
||||
|
|
|
@ -3102,14 +3102,14 @@ function FeedSetContentView(val)
|
|||
if (wintype == "mail:3pane") {
|
||||
// Get quickmode per feed pref from feeds.rdf
|
||||
var quickMode, targetRes;
|
||||
if (typeof FZ_NS == 'undefined')
|
||||
if (!("FeedUtils" in window))
|
||||
Services.scriptloader.loadSubScript("chrome://messenger-newsblog/content/utils.js");
|
||||
try
|
||||
{
|
||||
var targetRes = getParentTargetForChildResource(
|
||||
gMsgFolderSelected.URI,
|
||||
FZ_QUICKMODE,
|
||||
gMsgFolderSelected.server);
|
||||
var targetRes = FeedUtils.getParentTargetForChildResource(
|
||||
gFolderDisplay.displayedFolder.URI,
|
||||
FeedUtils.FZ_QUICKMODE,
|
||||
gFolderDisplay.displayedFolder.server);
|
||||
}
|
||||
catch (ex) {};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче