!import
1 //@line 39 "/home/visbrero/mnt/roisin/rev_control/hg/mozilla/mail/extensions/newsblog/content/utils.js"
2
3 // Whether or not to dump debugging messages to the console.
4 const DEBUG = false;
5 var debug;
6 if (DEBUG)
anon:7:10
7 debug = function(msg) { dump(' -- FZ -- : ' + msg + '\n'); }
8 else
anon:9:10
9 debug = function() {}
10
11 Components.utils.import("resource://gre/modules/ISO8601DateUtils.jsm");
12 var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
13
14 const RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
15 const RDF_TYPE = rdf.GetResource(RDF_NS + "type");
16
17 const RSS_NS = "http://purl.org/rss/1.0/";
18 const RSS_CHANNEL = rdf.GetResource(RSS_NS + "channel");
19 const RSS_TITLE = rdf.GetResource(RSS_NS + "title");
20 const RSS_DESCRIPTION = rdf.GetResource(RSS_NS + "description");
21 const RSS_ITEMS = rdf.GetResource(RSS_NS + "items");
22 const RSS_ITEM = rdf.GetResource(RSS_NS + "item");
23 const RSS_LINK = rdf.GetResource(RSS_NS + "link");
24
25 const RSS_CONTENT_NS = "http://purl.org/rss/1.0/modules/content/";
26 const RSS_CONTENT_ENCODED = rdf.GetResource(RSS_CONTENT_NS + "encoded");
27
28 const DC_NS = "http://purl.org/dc/elements/1.1/";
29 const DC_CREATOR = rdf.GetResource(DC_NS + "creator");
30 const DC_SUBJECT = rdf.GetResource(DC_NS + "subject");
31 const DC_DATE = rdf.GetResource(DC_NS + "date");
32 const DC_TITLE = rdf.GetResource(DC_NS + "title");
33 const DC_LASTMODIFIED = rdf.GetResource(DC_NS + "lastModified");
34 const DC_IDENTIFIER = rdf.GetResource(DC_NS + "identifier");
35
36 const FZ_NS = "urn:forumzilla:";
37 const FZ_ROOT = rdf.GetResource(FZ_NS + "root");
38 const FZ_FEEDS = rdf.GetResource(FZ_NS + "feeds");
39 const FZ_FEED = rdf.GetResource(FZ_NS + "feed");
40 const FZ_QUICKMODE = rdf.GetResource(FZ_NS + "quickMode");
41 const FZ_DESTFOLDER = rdf.GetResource(FZ_NS + "destFolder");
42 const FZ_STORED = rdf.GetResource(FZ_NS + "stored");
43 const FZ_VALID = rdf.GetResource(FZ_NS + "valid");
44
45 const RDF_LITERAL_TRUE = rdf.GetLiteral("true");
46 const RDF_LITERAL_FALSE = rdf.GetLiteral("false");
47
48 // Atom constants
49 const ATOM_03_NS = "http://purl.org/atom/ns#";
50 const ATOM_IETF_NS = "http://www.w3.org/2005/Atom";
51
52 // XXX There's a containerutils in forumzilla.js that this should be merged with.
53 var containerUtils = Components.classes["@mozilla.org/rdf/container-utils;1"]
54 .getService(Components.interfaces.nsIRDFContainerUtils);
55
56 var fileHandler = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService)
57 .getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
58
59 // helper routine that checks our subscriptions list array and returns true if the url
60 // is already in our list. This is used to prevent the user from subscribing to the same
61 // feed multiple times for the same server...
feedAlreadyExists
62 function feedAlreadyExists(aUrl, aServer)
63 {
64 var feeds = getSubscriptionsList(aServer);
65 return feeds.IndexOf(rdf.GetResource(aUrl)) != -1;
66 }
67
addFeed
68 function addFeed(url, title, destFolder)
69 {
70 var ds = getSubscriptionsDS(destFolder.server);
71 var feeds = getSubscriptionsList(destFolder.server);
72
73 // Generate a unique ID for the feed.
74 var id = url;
75 var i = 1;
76 while (feeds.IndexOf(rdf.GetResource(id)) != -1 && ++i < 1000)
77 id = url + i;
78 if (id == 1000)
79 throw("couldn't generate a unique ID for feed " + url);
80
81 // Add the feed to the list.
82 id = rdf.GetResource(id);
83 feeds.AppendElement(id);
84 ds.Assert(id, RDF_TYPE, FZ_FEED, true);
85 ds.Assert(id, DC_IDENTIFIER, rdf.GetLiteral(url), true);
86 if (title)
87 ds.Assert(id, DC_TITLE, rdf.GetLiteral(title), true);
88 ds.Assert(id, FZ_DESTFOLDER, destFolder, true);
89 ds = ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
90 ds.Flush();
91 }
92
93 // updates the "feedUrl" property in the message database for the folder in question.
94
95 var kFeedUrlDelimiter = '|'; // the delimiter used to delimit feed urls in the msg folder database "feedUrl" property
96
updateFolderFeedUrl
97 function updateFolderFeedUrl(aFolder, aFeedUrl, aRemoveUrl)
98 {
99 var msgdb = aFolder.QueryInterface(Components.interfaces.nsIMsgFolder).getMsgDatabase(null);
100 var folderInfo = msgdb.dBFolderInfo;
101 var oldFeedUrl = folderInfo.getCharProperty("feedUrl");
102
103 if (aRemoveUrl)
104 {
105 // remove our feed url string from the list of feed urls
106 var newFeedUrl = oldFeedUrl.replace(kFeedUrlDelimiter + aFeedUrl, "");
107 folderInfo.setCharProperty("feedUrl", newFeedUrl);
108 }
109 else
110 folderInfo.setCharProperty("feedUrl", oldFeedUrl + kFeedUrlDelimiter + aFeedUrl);
111
112 // commit the db to preserve our changes
113 msgdb.Close(true);
114 }
115
getNodeValue
116 function getNodeValue(node)
117 {
118 if (node && node.textContent)
119 return node.textContent;
120 else if (node && node.firstChild)
121 {
122 var ret = "";
123 for (var child = node.firstChild; child; child = child.nextSibling)
124 {
125 var value = getNodeValue(child);
126 if (value)
127 ret += value;
128 }
129
130 if (ret)
131 return ret;
132 }
133
134 return null;
135 }
136
getRDFTargetValue
137 function getRDFTargetValue(ds, source, property)
138 {
139 var node = ds.GetTarget(source, property, true);
140 if (node)
141 {
142 try{
143 node = node.QueryInterface(Components.interfaces.nsIRDFLiteral);
144 if (node)
145 return node.Value;
146 }catch(e){
147 // if the RDF was bogus, do nothing. rethrow if it's some other problem
148 if(!((e instanceof Components.interfaces.nsIXPCException)
149 && (e.result==Components.results.NS_ERROR_NO_INTERFACE)))
150 throw e;
151 }
152
153 }
154 return null;
155 }
156
getSubscriptionsDS
157 function getSubscriptionsDS(server)
158 {
159 var file = getSubscriptionsFile(server);
160 var url = fileHandler.getURLSpecFromFile(file);
161
162 // GetDataSourceBlocking has a cache, so it's cheap to do this again
163 // once we've already done it once.
164 var ds = rdf.GetDataSourceBlocking(url);
165
166 if (!ds)
167 throw("can't get subscriptions data source");
168
169 return ds;
170 }
171
getSubscriptionsList
172 function getSubscriptionsList(server)
173 {
174 var ds = getSubscriptionsDS(server);
175 var list = ds.GetTarget(FZ_ROOT, FZ_FEEDS, true);
176 //list = feeds.QueryInterface(Components.interfaces.nsIRDFContainer);
177 list = list.QueryInterface(Components.interfaces.nsIRDFResource);
178 list = containerUtils.MakeSeq(ds, list);
179 return list;
180 }
181
getSubscriptionsFile
182 function getSubscriptionsFile(server)
183 {
184 server.QueryInterface(Components.interfaces.nsIRssIncomingServer);
185 var file = server.subscriptionsDataSourcePath;
186
187 // If the file doesn't exist, create it.
188 if (!file.exists())
189 createSubscriptionsFile(file);
190
191 return file;
192 }
193
createSubscriptionsFile
194 function createSubscriptionsFile(file)
195 {
196 file = new LocalFile(file, MODE_WRONLY | MODE_CREATE);
197 file.write('\
198 <?xml version="1.0"?>\n\
199 <RDF:RDF xmlns:dc="http://purl.org/dc/elements/1.1/"\n\
200 xmlns:fz="' + FZ_NS + '"\n\
201 xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n\
202 <RDF:Description about="' + FZ_ROOT.Value + '">\n\
203 <fz:feeds>\n\
204 <RDF:Seq>\n\
205 </RDF:Seq>\n\
206 </fz:feeds>\n\
207 </RDF:Description>\n\
208 </RDF:RDF>\n\
209 ');
210 file.close();
211 }
212
getItemsDS
213 function getItemsDS(server)
214 {
215 var file = getItemsFile(server);
216 var url = fileHandler.getURLSpecFromFile(file);
217
218 // GetDataSourceBlocking has a cache, so it's cheap to do this again
219 // once we've already done it once.
220 var ds = rdf.GetDataSourceBlocking(url);
221 if (!ds)
222 throw("can't get subscriptions data source");
223
224 // Note that it this point the datasource may not be loaded yet.
225 // You have to QueryInterface it to nsIRDFRemoteDataSource and check
226 // its "loaded" property to be sure. You can also attach an observer
227 // which will get notified when the load is complete.
228 return ds;
229 }
230
getItemsFile
231 function getItemsFile(server)
232 {
233 server.QueryInterface(Components.interfaces.nsIRssIncomingServer);
234 var file = server.feedItemsDataSourcePath;
235
236 // If the file doesn't exist, create it.
237 if (!file.exists())
238 {
239 var newfile = new LocalFile(file, MODE_WRONLY | MODE_CREATE);
240 newfile.write('\
241 <?xml version="1.0"?>\n\
242 <RDF:RDF xmlns:dc="http://purl.org/dc/elements/1.1/"\n\
243 xmlns:fz="' + FZ_NS + '"\n\
244 xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n\
245 </RDF:RDF>\n\
246 ');
247 newfile.close();
248 }
249 return file;
250 }
251
removeAssertions
252 function removeAssertions(ds, resource)
253 {
254 var properties = ds.ArcLabelsOut(resource);
255 var property;
256 while (properties.hasMoreElements())
257 {
258 property = properties.getNext();
259 var values = ds.GetTargets(resource, property, true);
260 var value;
261 while (values.hasMoreElements())
262 {
263 value = values.getNext();
264 ds.Unassert(resource, property, value, true);
265 }
266 }
267 }
268
269 // Date validator for RSS feeds
270 const FZ_RFC822_RE = "^(((Mon)|(Tue)|(Wed)|(Thu)|(Fri)|(Sat)|(Sun)), *)?\\d\\d?"
271 + " +((Jan)|(Feb)|(Mar)|(Apr)|(May)|(Jun)|(Jul)|(Aug)|(Sep)|(Oct)|(Nov)|(Dec))"
272 + " +\\d\\d(\\d\\d)? +\\d\\d:\\d\\d(:\\d\\d)? +(([+-]?\\d\\d\\d\\d)|(UT)|(GMT)"
273 + "|(EST)|(EDT)|(CST)|(CDT)|(MST)|(MDT)|(PST)|(PDT)|\\w)$";
274
isValidRFC822Date
275 function isValidRFC822Date(pubDate)
276 {
277 var regex = new RegExp(FZ_RFC822_RE);
278 return regex.test(pubDate);
279 }
280
dateRescue
281 function dateRescue(dateString)
282 {
283 // Deal with various kinds of invalid dates
284 if(!isNaN(parseInt(dateString)))
285 { // It's an integer, so maybe it's a timestamp
286 var d = new Date(parseInt(dateString)*1000);
287 var now = new Date();
288 var yeardiff = now.getFullYear()-d.getFullYear();
289 debug("Rescue Timestamp date: " + d.toString() + "\nYear diff:" + yeardiff + "\n");
290 if((yeardiff >= 0) && (yeardiff<3))
291 {
292 // it's quite likely the correct date
293 return d.toString();
294 }
295 }
296 if(dateString.search(/^\d\d\d\d/) != -1) //Could be a ISO8601/W3C date
297 return W3CToIETFDate(dateString);
298
299 // Can't help. Set to current time.
300 return (new Date()).toString();
301 }
302
303 // Could be a prototype on String, but I don't know the policy on that
trimString
304 function trimString(s)
305 {
306 return(s.replace(/^\s+/,'').replace(/\s+$/,''));
307 }
308
W3CToIETFDate
309 function W3CToIETFDate(dateString) {
310 var date = ISO8601DateUtils.parse(dateString);
311 return date.toUTCString();
312 }