fix for 250633, sr=mscott don't redownload rss messages we've already downloaded
This commit is contained in:
Родитель
352b310090
Коммит
973fab624e
|
@ -15,17 +15,17 @@ var serializer = new XMLSerializer;
|
|||
// can access the Feed objects after it finishes downloading the feed files.
|
||||
var gFzFeedCache = new Object();
|
||||
|
||||
function Feed(url, quickMode, title) {
|
||||
this.url = url;
|
||||
this.quickMode = quickMode || false;
|
||||
this.title = title || null;
|
||||
function Feed(resource) {
|
||||
this.resource = resource.QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
|
||||
this.description = null;
|
||||
this.author = null;
|
||||
this.description = null;
|
||||
this.author = null;
|
||||
|
||||
this.request = null;
|
||||
|
||||
this.request = null;
|
||||
|
||||
return this;
|
||||
this.items = new Array();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// The name of the message folder corresponding to the feed.
|
||||
|
@ -92,6 +92,45 @@ Feed.onDownloadError = function(event) {
|
|||
throw("error downloading feed " + url);
|
||||
}
|
||||
|
||||
Feed.prototype.url getter = function() {
|
||||
var ds = getSubscriptionsDS();
|
||||
var url = ds.GetTarget(this.resource, DC_IDENTIFIER, true);
|
||||
if (url)
|
||||
url = url.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
|
||||
else
|
||||
url = this.resource.Value;
|
||||
return url;
|
||||
}
|
||||
|
||||
Feed.prototype.title getter = function() {
|
||||
var ds = getSubscriptionsDS();
|
||||
var title = ds.GetTarget(this.resource, DC_TITLE, true);
|
||||
if (title)
|
||||
title = title.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
|
||||
return title;
|
||||
}
|
||||
|
||||
Feed.prototype.title setter = function(new_title) {
|
||||
var ds = getSubscriptionsDS();
|
||||
new_title = rdf.GetLiteral(new_title || "");
|
||||
var old_title = ds.GetTarget(this.resource, DC_TITLE, true);
|
||||
if (old_title)
|
||||
ds.Change(this.resource, DC_TITLE, old_title, new_title);
|
||||
else
|
||||
ds.Assert(this.resource, DC_TITLE, new_title, true);
|
||||
}
|
||||
|
||||
Feed.prototype.quickMode getter = function() {
|
||||
var ds = getSubscriptionsDS();
|
||||
var quickMode = ds.GetTarget(this.resource, FZ_QUICKMODE, true);
|
||||
if (quickMode) {
|
||||
quickMode = quickMode.QueryInterface(Components.interfaces.nsIRDFLiteral);
|
||||
quickMode = quickMode.Value;
|
||||
quickMode = eval(quickMode);
|
||||
}
|
||||
return quickMode;
|
||||
}
|
||||
|
||||
Feed.prototype.parse = function() {
|
||||
// Figures out what description language (RSS, Atom) and version this feed
|
||||
// is using and calls a language/version-specific feed parser.
|
||||
|
@ -125,6 +164,9 @@ Feed.prototype.parse = function() {
|
|||
debug(this.url + " is of unknown format; assuming an RSS 0.9x feed");
|
||||
this.parseAsRSS2();
|
||||
}
|
||||
var ds = getItemsDS();
|
||||
ds = ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
|
||||
ds.Flush();
|
||||
}
|
||||
|
||||
Feed.prototype.parseAsRSS2 = function() {
|
||||
|
@ -142,6 +184,8 @@ Feed.prototype.parseAsRSS2 = function() {
|
|||
if (!this.parseItems)
|
||||
return;
|
||||
|
||||
this.invalidateItems();
|
||||
|
||||
var itemNodes = this.request.responseXML.getElementsByTagName("item");
|
||||
for ( var i=0 ; i<itemNodes.length ; i++ ) {
|
||||
var itemNode = itemNodes[i];
|
||||
|
@ -173,7 +217,10 @@ Feed.prototype.parseAsRSS2 = function() {
|
|||
|| item.date;
|
||||
|
||||
item.store();
|
||||
item.markValid();
|
||||
|
||||
}
|
||||
this.removeInvalidItems();
|
||||
}
|
||||
|
||||
Feed.prototype.parseAsRSS1 = function() {
|
||||
|
@ -193,6 +240,8 @@ Feed.prototype.parseAsRSS1 = function() {
|
|||
if (!this.parseItems)
|
||||
return;
|
||||
|
||||
this.invalidateItems();
|
||||
|
||||
var items = ds.GetTarget(channel, RSS_ITEMS, true);
|
||||
//items = items.QueryInterface(Components.interfaces.nsIRDFContainer);
|
||||
items = rdfcontainer.MakeSeq(ds, items);
|
||||
|
@ -227,7 +276,9 @@ Feed.prototype.parseAsRSS1 = function() {
|
|||
item.content = getRDFTargetValue(ds, itemResource, RSS_CONTENT_ENCODED);
|
||||
|
||||
item.store();
|
||||
item.markValid();
|
||||
}
|
||||
this.removeInvalidItems();
|
||||
}
|
||||
|
||||
Feed.prototype.parseAsAtom = function() {
|
||||
|
@ -245,6 +296,8 @@ Feed.prototype.parseAsAtom = function() {
|
|||
if (!this.parseItems)
|
||||
return;
|
||||
|
||||
this.invalidateItems();
|
||||
|
||||
var items = this.request.responseXML.getElementsByTagName("entry");
|
||||
for ( var i=0 ; i<items.length ; i++ ) {
|
||||
var itemNode = items[i];
|
||||
|
@ -317,5 +370,42 @@ Feed.prototype.parseAsAtom = function() {
|
|||
item.content = content;
|
||||
|
||||
item.store();
|
||||
item.markValid();
|
||||
}
|
||||
this.removeInvalidItems();
|
||||
}
|
||||
|
||||
Feed.prototype.invalidateItems = function invalidateItems() {
|
||||
var ds = getItemsDS();
|
||||
debug("invalidating items for " + this.url);
|
||||
var items = ds.GetSources(FZ_FEED, this.resource, true);
|
||||
var 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);
|
||||
if (valid)
|
||||
ds.Unassert(item, FZ_VALID, valid, true);
|
||||
}
|
||||
}
|
||||
|
||||
Feed.prototype.removeInvalidItems = function() {
|
||||
var ds = getItemsDS();
|
||||
debug("removing invalid items for " + this.url);
|
||||
var items = ds.GetSources(FZ_FEED, this.resource, true);
|
||||
var item;
|
||||
while (items.hasMoreElements()) {
|
||||
item = items.getNext();
|
||||
item = item.QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
if (ds.HasAssertion(item, FZ_VALID, RDF_LITERAL_TRUE, true))
|
||||
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");
|
||||
else
|
||||
removeAssertions(ds, item);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -186,7 +186,8 @@ FeedItem.prototype.isStored = function() {
|
|||
} catch(e) {
|
||||
folder = null;
|
||||
}
|
||||
if (!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, getMessageWindow());
|
||||
|
@ -198,22 +199,56 @@ FeedItem.prototype.isStored = function() {
|
|||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
folder = folder.QueryInterface(Components.interfaces.nsIMsgFolder);
|
||||
var db = folder.getMsgDatabase(getMessageWindow());
|
||||
var hdr = db.getMsgHdrForMessageID(this.messageID);
|
||||
if (hdr) {
|
||||
debug(this.identity + " stored");
|
||||
return true;
|
||||
var ds = getItemsDS();
|
||||
var itemResource = rdf.GetResource(this.url || ("urn:" + this.id));
|
||||
var downloaded = ds.GetTarget(itemResource, FZ_STORED, true);
|
||||
if (!downloaded || downloaded.QueryInterface(Components.interfaces.nsIRDFLiteral).Value == "false")
|
||||
{
|
||||
debug(this.identity + " not stored");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug(this.identity + " stored");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// XXX This should happen in the constructor automatically.
|
||||
FeedItem.prototype.markValid = function() {
|
||||
debug("validating " + this.url);
|
||||
|
||||
var ds = getItemsDS();
|
||||
var resource = rdf.GetResource(this.url || ("urn:" + this.id));
|
||||
|
||||
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.hasArcOut(resource, FZ_VALID)) {
|
||||
var currentValue = ds.GetTarget(resource, FZ_VALID, true);
|
||||
ds.Change(resource, FZ_VALID, currentValue, RDF_LITERAL_TRUE);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
ds.Assert(resource, FZ_VALID, RDF_LITERAL_TRUE, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FeedItem.prototype.markStored = function() {
|
||||
var ds = getItemsDS();
|
||||
var resource = rdf.GetResource(this.url || ("urn:" + this.id));
|
||||
|
||||
if (!ds.HasAssertion(resource, FZ_FEED, rdf.GetResource(this.feed.url), true))
|
||||
ds.Assert(resource, FZ_FEED, rdf.GetResource(this.feed.url), true);
|
||||
|
||||
var currentValue;
|
||||
if (ds.hasArcOut(resource, FZ_STORED)) {
|
||||
currentValue = ds.GetTarget(resource, FZ_STORED, true);
|
||||
ds.Change(resource, FZ_STORED, currentValue, RDF_LITERAL_TRUE);
|
||||
}
|
||||
else {
|
||||
ds.Assert(resource, FZ_STORED, RDF_LITERAL_TRUE, true);
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
debug(this.identity + " error checking if stored: " + e);
|
||||
throw(e);
|
||||
}
|
||||
}
|
||||
|
||||
FeedItem.prototype.download = function() {
|
||||
|
@ -319,6 +354,7 @@ FeedItem.prototype.writeToFolder = function() {
|
|||
var folder = server.rootMsgFolder.getChildNamed(this.feed.name);
|
||||
folder = folder.QueryInterface(Components.interfaces.nsIMsgLocalMailFolder);
|
||||
folder.addMessage(source);
|
||||
this.markStored();
|
||||
}
|
||||
|
||||
function W3CToIETFDate(dateString) {
|
||||
|
|
|
@ -34,6 +34,7 @@ var gFzStartupTime = new Date();
|
|||
|
||||
// Load and cache the subscriptions data source so it's available when we need it.
|
||||
getSubscriptionsDS();
|
||||
getItemsDS();
|
||||
|
||||
function onLoad() {
|
||||
// XXX Code to make the News & Blogs toolbar button show up automatically.
|
||||
|
@ -47,6 +48,19 @@ function onLoad() {
|
|||
// currentset += ",button-newsandblogs";
|
||||
//toolbar.setAttribute('currentset', currentset);
|
||||
|
||||
// Make sure the subscriptions and items data source is loaded, since we'll
|
||||
// need them for everything we do.
|
||||
var itemsDS =
|
||||
getItemsDS()
|
||||
.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
|
||||
if (!itemsDS.loaded) {
|
||||
if (new Date() - gFzStartupTime < 30 * 1000) {
|
||||
window.setTimeout(onLoad, 1000);
|
||||
return;
|
||||
}
|
||||
else
|
||||
throw("couldn't load the items datasource within thirty seconds");
|
||||
}
|
||||
// Make sure the subscriptions data source is loaded, since we'll need it
|
||||
// for everything we do. If it's not loaded, recheck it every second until
|
||||
// it's been ten seconds since we started up, then give up.
|
||||
|
@ -78,35 +92,18 @@ function onLoad() {
|
|||
window.setTimeout(onLoad, gFzStartupDelay * 1000);
|
||||
|
||||
function downloadFeeds() {
|
||||
// Reload subscriptions every 30 minutes (XXX make this configurable via a pref).
|
||||
window.setTimeout(downloadFeeds, 30 * 60 * 1000);
|
||||
|
||||
var ds = getSubscriptionsDS();
|
||||
var feeds = getSubscriptionsList().GetElements();
|
||||
|
||||
var feed;
|
||||
while(feeds.hasMoreElements())
|
||||
downloadFeed(feeds.getNext());
|
||||
}
|
||||
|
||||
function downloadFeed(feed) {
|
||||
var ds = getSubscriptionsDS();
|
||||
var feeds = getSubscriptionsList().GetElements();
|
||||
|
||||
var feed, url, quickMode, title;
|
||||
while(feeds.hasMoreElements()) {
|
||||
feed = feeds.getNext();
|
||||
feed = feed.QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
|
||||
url = ds.GetTarget(feed, DC_IDENTIFIER, true);
|
||||
if (url)
|
||||
url = url.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
|
||||
|
||||
quickMode = ds.GetTarget(feed, FZ_QUICKMODE, true);
|
||||
if (quickMode) {
|
||||
quickMode = quickMode.QueryInterface(Components.interfaces.nsIRDFLiteral);
|
||||
quickMode = quickMode.Value;
|
||||
quickMode = eval(quickMode);
|
||||
}
|
||||
|
||||
title = ds.GetTarget(feed, DC_TITLE, true);
|
||||
if (title)
|
||||
title = title.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
|
||||
|
||||
feed = new Feed(url, quickMode, title);
|
||||
feed.download();
|
||||
}
|
||||
new Feed(feed).download();
|
||||
}
|
||||
|
||||
function migrateSubscriptions(oldFile) {
|
||||
|
|
|
@ -39,41 +39,47 @@ function doAdd() {
|
|||
|
||||
// if the user hit cancel, exit without doing anything
|
||||
if (!feedProperties.result)
|
||||
{
|
||||
debug("feedProperties.result empty\n");
|
||||
return;
|
||||
|
||||
}
|
||||
if (!feedProperties.feedLocation)
|
||||
{
|
||||
debug("feedProperties.feedLocation empty\n");
|
||||
return;
|
||||
|
||||
}
|
||||
const DEFAULT_FEED_TITLE = "feed title";
|
||||
const DEFAULT_FEED_URL = "feed location";
|
||||
|
||||
feed = new Feed(feedProperties.feedLocation || DEFAULT_FEED_URL);
|
||||
feed.download(false, false);
|
||||
if (!feedProperties.feedName)
|
||||
feedProperties.feedName = DEFAULT_FEED_TITLE;
|
||||
|
||||
var itemResource = rdf.GetResource(feedProperties.feedLocation);
|
||||
feed = new Feed(itemResource);
|
||||
feed.download(false, false);
|
||||
debug("after download, feed name = " + feed.name + "\n");
|
||||
|
||||
var server = getIncomingServer();
|
||||
var folder;
|
||||
try {
|
||||
//var folder = server.rootMsgFolder.FindSubFolder(feed.name);
|
||||
folder = server.rootMsgFolder.getChildNamed(feedProperties.feedName);
|
||||
var folder = server.rootMsgFolder.getChildNamed(feed.name);
|
||||
}
|
||||
catch(e) {
|
||||
// If we're here, it's probably because the folder doesn't exist yet,
|
||||
// so create it.
|
||||
debug("folder for new feed " + feedProperties.feedName + " doesn't exist; creating");
|
||||
debug("creating " + feedProperties.feedName + "as child of " + server.rootMsgFolder + "\n");
|
||||
server.rootMsgFolder.createSubfolder(feedProperties.feedName, getMessageWindow());
|
||||
folder = server.rootMsgFolder.FindSubFolder(feedProperties.feedName);
|
||||
debug("folder for new feed " + feed.name + " doesn't exist; creating");
|
||||
debug("creating " + feed.name + "as child of " + server.rootMsgFolder + "\n");
|
||||
server.rootMsgFolder.createSubfolder(feed.name, getMessageWindow());
|
||||
folder = server.rootMsgFolder.FindSubFolder(feed.name);
|
||||
var msgdb = folder.getMsgDatabase(null);
|
||||
var folderInfo = msgdb.dBFolderInfo;
|
||||
folderInfo.setCharPtrProperty("feedUrl", feedProperties.feedLocation);
|
||||
}
|
||||
|
||||
// XXX This should be something like "subscribe to feed".
|
||||
dump ("feed name = " + feedProperties.feedName + "\n");
|
||||
addFeed(feedProperties.feedLocation, feedProperties.feedName, null, folder);
|
||||
// XXX Maybe we can combine this with the earlier download?
|
||||
dump ("feed name = " + feed.name + "\n");
|
||||
addFeed(feedProperties.feedLocation, feed.name, null, folder);
|
||||
// now download it for real, now that we have a folder.
|
||||
feed.download();
|
||||
}
|
||||
|
||||
|
@ -174,7 +180,7 @@ function doEdit() {
|
|||
// the title, so despite the cancellation we should still redownload
|
||||
// the feed if the title has changed.
|
||||
if (new_title != old_title) {
|
||||
feed = new Feed(old_url, null, feedProperties.feedName);
|
||||
feed = new Feed(item.id);
|
||||
feed.download();
|
||||
}
|
||||
return;
|
||||
|
@ -182,7 +188,7 @@ function doEdit() {
|
|||
else if (feedProperties.feedLocation != old_url)
|
||||
updateURL(item.id, feedProperties.feedLocation);
|
||||
|
||||
feed = new Feed(feedProperties.feedLocation, null, feedProperties.feedName);
|
||||
feed = new Feed(item.id);
|
||||
feed.download();
|
||||
}
|
||||
|
||||
|
@ -204,8 +210,7 @@ function doRemove() {
|
|||
var server = getIncomingServer();
|
||||
var openerResource = server.rootMsgFolder.QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
var titleValue = title ? title.QueryInterface(Components.interfaces.nsIRDFLiteral).Value : "";
|
||||
var url = ds.GetTarget(resource, DC_IDENTIFIER, true);
|
||||
var feed = new Feed(url, null, titleValue);
|
||||
var feed = new Feed(resource);
|
||||
try {
|
||||
var folderResource = server.rootMsgFolder.getChildNamed(feed.name).QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
var foo = window.opener.messenger.DeleteFolders(window.opener.GetFolderDatasource(), openerResource, folderResource);
|
||||
|
@ -218,7 +223,7 @@ function doRemove() {
|
|||
// so don't remove it.
|
||||
folder = server.rootMsgFolder.getChildNamed(feed.name);
|
||||
if (folder)
|
||||
return;
|
||||
return;
|
||||
}
|
||||
catch (e) {}
|
||||
ds.Unassert(resource, DC_TITLE, title, true);
|
||||
|
@ -232,6 +237,23 @@ function doRemove() {
|
|||
|
||||
feeds.RemoveElementAt(index, true);
|
||||
}
|
||||
// Remove all assertions about the feed from the subscriptions database.
|
||||
var ds = getSubscriptionsDS();
|
||||
removeAssertions(ds, feed);
|
||||
|
||||
// Remove all assertions about items in the feed from the items database.
|
||||
ds = getItemsDS();
|
||||
var items = ds.GetSources(FZ_FEED, feed, true);
|
||||
while (items.hasMoreElements()) {
|
||||
var item = items.getNext();
|
||||
item = item.QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
ds.Unassert(item, FZ_FEED, feed, true);
|
||||
if (ds.hasArcOut(item, FZ_FEED))
|
||||
debug(item.Value + " is from more than one feed; only the reference to this feed removed");
|
||||
else
|
||||
removeAssertions(ds, item);
|
||||
}
|
||||
|
||||
//tree.builder.rebuild();
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,11 @@ const FZ_FEEDS = rdf.GetResource(FZ_NS + "feeds");
|
|||
const FZ_FEED = rdf.GetResource(FZ_NS + "feed");
|
||||
const FZ_QUICKMODE = rdf.GetResource(FZ_NS + "quickMode");
|
||||
const FZ_DESTFOLDER = rdf.GetResource(FZ_NS + "destFolder");
|
||||
const FZ_STORED = rdf.GetResource(FZ_NS + "stored");
|
||||
const FZ_VALID = rdf.GetResource(FZ_NS + "valid");
|
||||
|
||||
const RDF_LITERAL_TRUE = rdf.GetLiteral("true");
|
||||
const RDF_LITERAL_FALSE = rdf.GetLiteral("false");
|
||||
|
||||
// XXX There's a containerutils in forumzilla.js that this should be merged with.
|
||||
var containerUtils =
|
||||
|
@ -81,6 +86,11 @@ function addFeed(url, title, quickMode, destFolder) {
|
|||
ds.Assert(id, FZ_DESTFOLDER, destFolder, true);
|
||||
ds = ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
|
||||
ds.Flush();
|
||||
// Create a new feed object for the feed.
|
||||
feed = new Feed(id);
|
||||
|
||||
// Downloading the feed synchronously will pick up the title.
|
||||
feed.download(false, false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -184,3 +194,71 @@ function createSubscriptionsFile(file) {
|
|||
');
|
||||
file.close();
|
||||
}
|
||||
|
||||
var gFzItemsDS; // cache
|
||||
function getItemsDS() {
|
||||
if (gFzItemsDS)
|
||||
return gFzItemsDS;
|
||||
|
||||
var file = getItemsFile();
|
||||
var url = fileHandler.getURLSpecFromFile(file);
|
||||
|
||||
gFzItemsDS = rdf.GetDataSource(url);
|
||||
if (!gFzItemsDS)
|
||||
throw("can't get subscriptions data source");
|
||||
|
||||
// Note that it this point the datasource may not be loaded yet.
|
||||
// You have to QueryInterface it to nsIRDFRemoteDataSource and check
|
||||
// its "loaded" property to be sure. You can also attach an observer
|
||||
// which will get notified when the load is complete.
|
||||
|
||||
return gFzItemsDS;
|
||||
}
|
||||
|
||||
function getItemsFile() {
|
||||
// Get the app directory service so we can look up the user's profile dir.
|
||||
var appDirectoryService =
|
||||
Components
|
||||
.classes["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Components.interfaces.nsIProperties);
|
||||
if ( !appDirectoryService )
|
||||
throw("couldn't get the directory service");
|
||||
|
||||
// Get the user's profile directory.
|
||||
var profileDir =
|
||||
appDirectoryService.get("ProfD", Components.interfaces.nsIFile);
|
||||
if ( !profileDir )
|
||||
throw ("couldn't get the user's profile directory");
|
||||
|
||||
// Get the user's subscriptions file.
|
||||
var file = profileDir.clone();
|
||||
file.append("feeditems.rdf");
|
||||
|
||||
// If the file doesn't exist, create it.
|
||||
if (!file.exists()) {
|
||||
var newfile = new LocalFile(file, MODE_WRONLY | MODE_CREATE);
|
||||
newfile.write('\
|
||||
<?xml version="1.0"?>\n\
|
||||
<RDF:RDF xmlns:dc="http://purl.org/dc/elements/1.1/"\n\
|
||||
xmlns:fz="' + FZ_NS + '"\n\
|
||||
xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n\
|
||||
</RDF:RDF>\n\
|
||||
');
|
||||
newfile.close();
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
function removeAssertions(ds, resource) {
|
||||
var properties = ds.ArcLabelsOut(resource);
|
||||
var property;
|
||||
while (properties.hasMoreElements()) {
|
||||
property = properties.getNext();
|
||||
var values = ds.GetTargets(resource, property, true);
|
||||
var value;
|
||||
while (values.hasMoreElements()) {
|
||||
value = values.getNext();
|
||||
ds.Unassert(resource, property, value, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,10 +41,13 @@ var nsNewsBlogFeedDownloader =
|
|||
downloadFeed: function(aUrl, aFolder, aQuickMode, aTitle, aUrlListener, aMsgWindow)
|
||||
{
|
||||
// we might just pull all these args out of the aFolder DB, instead of passing them in...
|
||||
feed = new Feed(aUrl, aQuickMode, aTitle);
|
||||
var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"]
|
||||
.getService(Components.interfaces.nsIRDFService);
|
||||
id = rdf.GetResource(aUrl);
|
||||
feed = new Feed(id);
|
||||
feed.urlListener = aUrlListener;
|
||||
feed.folder = aFolder;
|
||||
feed.msgWindow = aMsgWindow;
|
||||
feed.folder = aFolder;
|
||||
feed.msgWindow = aMsgWindow;
|
||||
feed.download();
|
||||
},
|
||||
|
||||
|
@ -166,17 +169,17 @@ var serializer = Components
|
|||
// can access the Feed objects after it finishes downloading the feed files.
|
||||
var gFzFeedCache = new Object();
|
||||
|
||||
function Feed(url, quickMode, title) {
|
||||
this.url = url;
|
||||
this.quickMode = quickMode || false;
|
||||
this.title = title || null;
|
||||
function Feed(resource) {
|
||||
this.resource = resource.QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
|
||||
this.description = null;
|
||||
this.author = null;
|
||||
this.description = null;
|
||||
this.author = null;
|
||||
|
||||
this.request = null;
|
||||
|
||||
this.request = null;
|
||||
|
||||
return this;
|
||||
this.items = new Array();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// The name of the message folder corresponding to the feed.
|
||||
|
@ -245,6 +248,47 @@ Feed.onDownloadError = function(event) {
|
|||
throw("error downloading feed " + url);
|
||||
}
|
||||
|
||||
Feed.prototype.url getter = function() {
|
||||
var ds = getSubscriptionsDS();
|
||||
var url = ds.GetTarget(this.resource, DC_IDENTIFIER, true);
|
||||
if (url)
|
||||
url = url.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
|
||||
else
|
||||
url = this.resource.Value;
|
||||
return url;
|
||||
}
|
||||
|
||||
Feed.prototype.title getter = function() {
|
||||
var ds = getSubscriptionsDS();
|
||||
var title = ds.GetTarget(this.resource, DC_TITLE, true);
|
||||
if (title)
|
||||
title = title.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
|
||||
return title;
|
||||
}
|
||||
|
||||
Feed.prototype.title setter = function(new_title) {
|
||||
var ds = getSubscriptionsDS();
|
||||
new_title = rdf.GetLiteral(new_title || "");
|
||||
var old_title = ds.GetTarget(this.resource, DC_TITLE, true);
|
||||
if (old_title)
|
||||
ds.Change(this.resource, DC_TITLE, old_title, new_title);
|
||||
else
|
||||
ds.Assert(this.resource, DC_TITLE, new_title, true);
|
||||
}
|
||||
|
||||
Feed.prototype.quickMode getter = function() {
|
||||
var ds = getSubscriptionsDS();
|
||||
var quickMode = ds.GetTarget(this.resource, FZ_QUICKMODE, true);
|
||||
if (quickMode) {
|
||||
quickMode = quickMode.QueryInterface(Components.interfaces.nsIRDFLiteral);
|
||||
quickMode = quickMode.Value;
|
||||
quickMode = eval(quickMode);
|
||||
}
|
||||
return quickMode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Feed.prototype.parse = function() {
|
||||
// Figures out what description language (RSS, Atom) and version this feed
|
||||
// is using and calls a language/version-specific feed parser.
|
||||
|
@ -295,6 +339,8 @@ Feed.prototype.parseAsRSS2 = function() {
|
|||
if (!this.parseItems)
|
||||
return;
|
||||
|
||||
this.invalidateItems();
|
||||
|
||||
var itemNodes = this.request.responseXML.getElementsByTagName("item");
|
||||
for ( var i=0 ; i<itemNodes.length ; i++ ) {
|
||||
var itemNode = itemNodes[i];
|
||||
|
@ -326,7 +372,9 @@ Feed.prototype.parseAsRSS2 = function() {
|
|||
|| item.date;
|
||||
|
||||
item.store();
|
||||
item.markValid();
|
||||
}
|
||||
this.removeInvalidItems();
|
||||
}
|
||||
|
||||
Feed.prototype.parseAsRSS1 = function() {
|
||||
|
@ -346,6 +394,8 @@ Feed.prototype.parseAsRSS1 = function() {
|
|||
if (!this.parseItems)
|
||||
return;
|
||||
|
||||
this.invalidateItems();
|
||||
|
||||
var items = ds.GetTarget(channel, RSS_ITEMS, true);
|
||||
//items = items.QueryInterface(Components.interfaces.nsIRDFContainer);
|
||||
items = rdfcontainer.MakeSeq(ds, items);
|
||||
|
@ -380,7 +430,9 @@ Feed.prototype.parseAsRSS1 = function() {
|
|||
item.content = getRDFTargetValue(ds, itemResource, RSS_CONTENT_ENCODED);
|
||||
|
||||
item.store();
|
||||
item.markValid();
|
||||
}
|
||||
this.removeInvalidItems();
|
||||
}
|
||||
|
||||
Feed.prototype.parseAsAtom = function() {
|
||||
|
@ -398,6 +450,8 @@ Feed.prototype.parseAsAtom = function() {
|
|||
if (!this.parseItems)
|
||||
return;
|
||||
|
||||
this.invalidateItems();
|
||||
|
||||
var items = this.request.responseXML.getElementsByTagName("entry");
|
||||
for ( var i=0 ; i<items.length ; i++ ) {
|
||||
var itemNode = items[i];
|
||||
|
@ -470,9 +524,46 @@ Feed.prototype.parseAsAtom = function() {
|
|||
item.content = content;
|
||||
|
||||
item.store();
|
||||
item.markValid();
|
||||
}
|
||||
this.removeInvalidItems();
|
||||
}
|
||||
|
||||
Feed.prototype.invalidateItems = function invalidateItems() {
|
||||
var ds = getItemsDS();
|
||||
debug("invalidating items for " + this.url);
|
||||
var items = ds.GetSources(FZ_FEED, this.resource, true);
|
||||
var 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);
|
||||
if (valid)
|
||||
ds.Unassert(item, FZ_VALID, valid, true);
|
||||
}
|
||||
}
|
||||
|
||||
Feed.prototype.removeInvalidItems = function() {
|
||||
var ds = getItemsDS();
|
||||
debug("removing invalid items for " + this.url);
|
||||
var items = ds.GetSources(FZ_FEED, this.resource, true);
|
||||
var item;
|
||||
while (items.hasMoreElements()) {
|
||||
item = items.getNext();
|
||||
item = item.QueryInterface(Components.interfaces.nsIRDFResource);
|
||||
if (ds.HasAssertion(item, FZ_VALID, RDF_LITERAL_TRUE, true))
|
||||
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");
|
||||
else
|
||||
removeAssertions(ds, item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------
|
||||
// From FeedItem.js
|
||||
|
@ -646,7 +737,6 @@ FeedItem.prototype.store = function() {
|
|||
content = content.replace(/%DESCRIPTION%/, this.description || this.title);
|
||||
this.content = content; // XXX store it elsewhere, f.e. this.page
|
||||
this.writeToFolder();
|
||||
//this.download();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -674,22 +764,56 @@ FeedItem.prototype.isStored = function() {
|
|||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
folder = folder.QueryInterface(Components.interfaces.nsIMsgFolder);
|
||||
var db = folder.getMsgDatabase(this.feed.msgWindow);
|
||||
var hdr = db.getMsgHdrForMessageID(this.messageID);
|
||||
if (hdr) {
|
||||
debug(this.identity + " stored");
|
||||
return true;
|
||||
var ds = getItemsDS();
|
||||
var itemResource = rdf.GetResource(this.url || ("urn:" + this.id));
|
||||
var downloaded = ds.GetTarget(itemResource, FZ_STORED, true);
|
||||
if (!downloaded || downloaded.QueryInterface(Components.interfaces.nsIRDFLiteral).Value == "false")
|
||||
{
|
||||
debug(this.identity + " not stored");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug(this.identity + " stored");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// XXX This should happen in the constructor automatically.
|
||||
FeedItem.prototype.markValid = function() {
|
||||
debug("validating " + this.url);
|
||||
|
||||
var ds = getItemsDS();
|
||||
var resource = rdf.GetResource(this.url || ("urn:" + this.id));
|
||||
|
||||
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.hasArcOut(resource, FZ_VALID)) {
|
||||
var currentValue = ds.GetTarget(resource, FZ_VALID, true);
|
||||
ds.Change(resource, FZ_VALID, currentValue, RDF_LITERAL_TRUE);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
ds.Assert(resource, FZ_VALID, RDF_LITERAL_TRUE, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FeedItem.prototype.markStored = function() {
|
||||
var ds = getItemsDS();
|
||||
var resource = rdf.GetResource(this.url || ("urn:" + this.id));
|
||||
|
||||
if (!ds.HasAssertion(resource, FZ_FEED, rdf.GetResource(this.feed.url), true))
|
||||
ds.Assert(resource, FZ_FEED, rdf.GetResource(this.feed.url), true);
|
||||
|
||||
var currentValue;
|
||||
if (ds.hasArcOut(resource, FZ_STORED)) {
|
||||
currentValue = ds.GetTarget(resource, FZ_STORED, true);
|
||||
ds.Change(resource, FZ_STORED, currentValue, RDF_LITERAL_TRUE);
|
||||
}
|
||||
else {
|
||||
ds.Assert(resource, FZ_STORED, RDF_LITERAL_TRUE, true);
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
debug(this.identity + " error checking if stored: " + e);
|
||||
throw(e);
|
||||
}
|
||||
}
|
||||
|
||||
FeedItem.prototype.download = function() {
|
||||
|
@ -797,6 +921,7 @@ FeedItem.prototype.writeToFolder = function() {
|
|||
var folder = server.rootMsgFolder.getChildNamed(this.feed.name);
|
||||
folder = folder.QueryInterface(Components.interfaces.nsIMsgLocalMailFolder);
|
||||
folder.addMessage(source);
|
||||
this.markStored();
|
||||
}
|
||||
|
||||
function W3CToIETFDate(dateString) {
|
||||
|
@ -1233,6 +1358,11 @@ const FZ_FEEDS = rdf.GetResource(FZ_NS + "feeds");
|
|||
const FZ_FEED = rdf.GetResource(FZ_NS + "feed");
|
||||
const FZ_QUICKMODE = rdf.GetResource(FZ_NS + "quickMode");
|
||||
const FZ_DESTFOLDER = rdf.GetResource(FZ_NS + "destFolder");
|
||||
const FZ_STORED = rdf.GetResource(FZ_NS + "stored");
|
||||
const FZ_VALID = rdf.GetResource(FZ_NS + "valid");
|
||||
|
||||
const RDF_LITERAL_TRUE = rdf.GetLiteral("true");
|
||||
const RDF_LITERAL_FALSE = rdf.GetLiteral("false");
|
||||
|
||||
// XXX There's a containerutils in forumzilla.js that this should be merged with.
|
||||
var containerUtils =
|
||||
|
@ -1347,3 +1477,71 @@ function createSubscriptionsFile(file) {
|
|||
');
|
||||
file.close();
|
||||
}
|
||||
|
||||
var gFzItemsDS; // cache
|
||||
function getItemsDS() {
|
||||
if (gFzItemsDS)
|
||||
return gFzItemsDS;
|
||||
|
||||
var file = getItemsFile();
|
||||
var url = fileHandler.getURLSpecFromFile(file);
|
||||
|
||||
gFzItemsDS = rdf.GetDataSource(url);
|
||||
if (!gFzItemsDS)
|
||||
throw("can't get subscriptions data source");
|
||||
|
||||
// Note that it this point the datasource may not be loaded yet.
|
||||
// You have to QueryInterface it to nsIRDFRemoteDataSource and check
|
||||
// its "loaded" property to be sure. You can also attach an observer
|
||||
// which will get notified when the load is complete.
|
||||
|
||||
return gFzItemsDS;
|
||||
}
|
||||
|
||||
function getItemsFile() {
|
||||
// Get the app directory service so we can look up the user's profile dir.
|
||||
var appDirectoryService =
|
||||
Components
|
||||
.classes["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Components.interfaces.nsIProperties);
|
||||
if ( !appDirectoryService )
|
||||
throw("couldn't get the directory service");
|
||||
|
||||
// Get the user's profile directory.
|
||||
var profileDir =
|
||||
appDirectoryService.get("ProfD", Components.interfaces.nsIFile);
|
||||
if ( !profileDir )
|
||||
throw ("couldn't get the user's profile directory");
|
||||
|
||||
// Get the user's subscriptions file.
|
||||
var file = profileDir.clone();
|
||||
file.append("feeditems.rdf");
|
||||
|
||||
// If the file doesn't exist, create it.
|
||||
if (!file.exists()) {
|
||||
var newfile = new LocalFile(file, MODE_WRONLY | MODE_CREATE);
|
||||
newfile.write('\
|
||||
<?xml version="1.0"?>\n\
|
||||
<RDF:RDF xmlns:dc="http://purl.org/dc/elements/1.1/"\n\
|
||||
xmlns:fz="' + FZ_NS + '"\n\
|
||||
xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n\
|
||||
</RDF:RDF>\n\
|
||||
');
|
||||
newfile.close();
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
function removeAssertions(ds, resource) {
|
||||
var properties = ds.ArcLabelsOut(resource);
|
||||
var property;
|
||||
while (properties.hasMoreElements()) {
|
||||
property = properties.getNext();
|
||||
var values = ds.GetTargets(resource, property, true);
|
||||
var value;
|
||||
while (values.hasMoreElements()) {
|
||||
value = values.getNext();
|
||||
ds.Unassert(resource, property, value, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче