summaryrefslogtreecommitdiffabout
authorMichael Krelin <hacker@klever.net>2008-03-01 16:14:55 (UTC)
committer Michael Krelin <hacker@klever.net>2008-03-01 16:14:55 (UTC)
commitfe00dd0be8fd88dc8179eed7a38663f07c1288a7 (patch) (unidiff)
tree7c16d78aef4f216192b197a37420ec9c0a77d2c4
parentd85adfb349b3c7a988bec21fcbad86f5f98c70de (diff)
downloadfoxri-fe00dd0be8fd88dc8179eed7a38663f07c1288a7.zip
foxri-fe00dd0be8fd88dc8179eed7a38663f07c1288a7.tar.gz
foxri-fe00dd0be8fd88dc8179eed7a38663f07c1288a7.tar.bz2
added more OpenID service types and handling of append='qxri' attribute
* added OpenID 1.1 and 2.0 service types to SERVICE_CLASSES * append qxri to URI in presence of append='qxri' attribute (append='authority' is yet to be handled) * added more OpenID service type URIs to friendlyServiceName() Signed-off-by: Michael Krelin <hacker@klever.net>
Diffstat (more/less context) (show whitespace changes)
-rwxr-xr-xsrc/components/xriProtocolHandler.js28
1 files changed, 22 insertions, 6 deletions
diff --git a/src/components/xriProtocolHandler.js b/src/components/xriProtocolHandler.js
index 1105874..3d27784 100755
--- a/src/components/xriProtocolHandler.js
+++ b/src/components/xriProtocolHandler.js
@@ -4,96 +4,99 @@
4 4
5// The interface we implement - nsIProtocolHandler 5// The interface we implement - nsIProtocolHandler
6const nsIProtocolHandler = Components.interfaces.nsIProtocolHandler; 6const nsIProtocolHandler = Components.interfaces.nsIProtocolHandler;
7 7
8// Interfaces that we require 8// Interfaces that we require
9 const nsISupports = Components.interfaces.nsISupports; 9 const nsISupports = Components.interfaces.nsISupports;
10 const nsIIOService = Components.interfaces.nsIIOService; 10 const nsIIOService = Components.interfaces.nsIIOService;
11 const nsIURI = Components.interfaces.nsIURI; 11 const nsIURI = Components.interfaces.nsIURI;
12 const nsIURL = Components.interfaces.nsIURL; 12 const nsIURL = Components.interfaces.nsIURL;
13 const nsIRequest = Components.interfaces.nsIRequest; 13 const nsIRequest = Components.interfaces.nsIRequest;
14const nsIRequestObserver = Components.interfaces.nsIRequestObserver; 14const nsIRequestObserver = Components.interfaces.nsIRequestObserver;
15 const nsIChannel = Components.interfaces.nsIChannel; 15 const nsIChannel = Components.interfaces.nsIChannel;
16 const nsIHttpChannel = Components.interfaces.nsIHttpChannel; 16 const nsIHttpChannel = Components.interfaces.nsIHttpChannel;
17 const nsIStreamListener = Components.interfaces.nsIStreamListener; 17 const nsIStreamListener = Components.interfaces.nsIStreamListener;
18 18
19 19
20// UUID uniquely identifying our component 20// UUID uniquely identifying our component
21// You can get from: http://kruithof.xs4all.nl/uuid/uuidgen here 21// You can get from: http://kruithof.xs4all.nl/uuid/uuidgen here
22const CLASS_ID = Components.ID("{ea00b610-215a-11db-a98b-0800200c9a66}"); 22const CLASS_ID = Components.ID("{ea00b610-215a-11db-a98b-0800200c9a66}");
23 23
24// textual unique identifier 24// textual unique identifier
25const CONTRACT_ID = "@mozilla.org/network/protocol;1?name=xri"; 25const CONTRACT_ID = "@mozilla.org/network/protocol;1?name=xri";
26 26
27// Components that we require 27// Components that we require
28const CID_URI = "@mozilla.org/network/simple-uri;1"; 28const CID_URI = "@mozilla.org/network/simple-uri;1";
29const kIOSERVICE_CID_STR = "{9ac9e770-18bc-11d3-9337-00104ba0fd40}"; 29const kIOSERVICE_CID_STR = "{9ac9e770-18bc-11d3-9337-00104ba0fd40}";
30const CID_URL = "@mozilla.org/network/standard-url;1"; 30const CID_URL = "@mozilla.org/network/standard-url;1";
31 31
32// description 32// description
33const CLASS_NAME = "XRI Protocol Handler"; 33const CLASS_NAME = "XRI Protocol Handler";
34 34
35const PROXY_URI = "http://xri.net/"; 35const PROXY_URI = "http://xri.net/";
36 36
37const XP_ANY_TYPE = 0; 37const XP_ANY_TYPE = 0;
38const XP_NUMBER_TYPE = 1; 38const XP_NUMBER_TYPE = 1;
39const XP_STRING_TYPE = 2; 39const XP_STRING_TYPE = 2;
40const XP_BOOLEAN_TYPE = 3; 40const XP_BOOLEAN_TYPE = 3;
41const XP_UNORDERED_NODE_ITERATOR_TYPE = 4; 41const XP_UNORDERED_NODE_ITERATOR_TYPE = 4;
42const XP_ORDERED_NODE_ITERATOR_TYPE = 5; 42const XP_ORDERED_NODE_ITERATOR_TYPE = 5;
43const XP_UNORDERED_NODE_SNAPSHOT_TYPE = 6; 43const XP_UNORDERED_NODE_SNAPSHOT_TYPE = 6;
44const XP_ORDERED_NODE_SNAPSHOT_TYPE = 7; 44const XP_ORDERED_NODE_SNAPSHOT_TYPE = 7;
45const XP_ANY_UNORDERED_NODE_TYPE = 8; 45const XP_ANY_UNORDERED_NODE_TYPE = 8;
46const XP_FIRST_ORDERED_NODE_TYPE = 9; 46const XP_FIRST_ORDERED_NODE_TYPE = 9;
47 47
48 48
49var SERVICE_CLASSES = { 49var SERVICE_CLASSES = {
50 'xri://+i-service*(+contact)*($v*1.0)': 'i-contact', 50 'xri://+i-service*(+contact)*($v*1.0)': 'i-contact',
51 'http://openid.net/signon/1.0': 'openid', 51 'http://openid.net/signon/1.0': 'openid',
52 'http://openid.net/signon/1.1': 'openid',
53 'http://specs.openid.net/auth/2.0/signon': 'openid',
54 'http://specs.openid.net/auth/2.0/server': 'openid',
52 'xri://$res*auth*($v*2.0)': 'res-auth', 55 'xri://$res*auth*($v*2.0)': 'res-auth',
53 'xri://+i-service*(+authn)*(+saml)*($v*1.0)': 'authn-saml', 56 'xri://+i-service*(+authn)*(+saml)*($v*1.0)': 'authn-saml',
54 'xri://+i-service*(+metadata)*(+saml)*($v*1.0)' : 'metadata-saml', 57 'xri://+i-service*(+metadata)*(+saml)*($v*1.0)' : 'metadata-saml',
55 'xri://+i-service*(+forwarding)*($v*1.0)': 'i-forwarding' 58 'xri://+i-service*(+forwarding)*($v*1.0)': 'i-forwarding'
56}; 59};
57 60
58 61
59const HTML_HEAD = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\ 62const HTML_HEAD = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\
60 <html xmlns=\"http://www.w3.org/1999/xhtml\">\n\ 63 <html xmlns=\"http://www.w3.org/1999/xhtml\">\n\
61 <head>\n\ 64 <head>\n\
62 <title>FoXRI Explorer - #QXRI#</title>\n\ 65 <title>FoXRI Explorer - #QXRI#</title>\n\
63 <link href=\"chrome://foxri/content/foxri_explorer.css\" rel=\"stylesheet\" type=\"text/css\" />\n\ 66 <link href=\"chrome://foxri/content/foxri_explorer.css\" rel=\"stylesheet\" type=\"text/css\" />\n\
64 <body>\n\ 67 <body>\n\
65 <h1>FoXRI Explorer</h1>\n\ 68 <h1>FoXRI Explorer</h1>\n\
66 <div id=\"explorer_body\">\n"; 69 <div id=\"explorer_body\">\n";
67 70
68const HTML_FOOT = "</div>\n\ 71const HTML_FOOT = "</div>\n\
69 </body>\n\ 72 </body>\n\
70 </html>"; 73 </html>";
71 74
72 75
73 76
74/// Generic object method wrapper 77/// Generic object method wrapper
75function methodWrapper(obj, method) 78function methodWrapper(obj, method)
76{ 79{
77 return ( 80 return (
78 function() { 81 function() {
79 /* pass it this inner closure's arguments */ 82 /* pass it this inner closure's arguments */
80 obj[method](arguments); 83 obj[method](arguments);
81 } 84 }
82 ); 85 );
83} 86}
84 87
85 88
86 89
87/// XRDS utility functions 90/// XRDS utility functions
88 91
89 92
90var nsResolver = { 93var nsResolver = {
91 lookupNamespaceURI: function(prefix) 94 lookupNamespaceURI: function(prefix)
92 { 95 {
93 if (prefix == "xrds") 96 if (prefix == "xrds")
94 return "xri://$xrds"; 97 return "xri://$xrds";
95 else if (prefix == "xrd") 98 else if (prefix == "xrd")
96 return "xri://$xrd*($v*2.0)"; 99 return "xri://$xrd*($v*2.0)";
97 return ""; 100 return "";
98 } 101 }
99}; 102};
@@ -192,145 +195,153 @@ function renderService(srv, doc, qxri)
192 var res = runExpr(doc, srv, "xrd:Type/text()"); 195 var res = runExpr(doc, srv, "xrd:Type/text()");
193 var t; 196 var t;
194 while (t = res.iterateNext()) { 197 while (t = res.iterateNext()) {
195 if (t.nodeValue) { 198 if (t.nodeValue) {
196 if (!knownServiceType && isKnownServiceType(t.nodeValue)) { 199 if (!knownServiceType && isKnownServiceType(t.nodeValue)) {
197 knownServiceType = t.nodeValue; 200 knownServiceType = t.nodeValue;
198 } 201 }
199 202
200 serviceType = t.nodeValue; 203 serviceType = t.nodeValue;
201 html_types += "<strong>Type:</strong> " + t.nodeValue + "<br/>"; 204 html_types += "<strong>Type:</strong> " + t.nodeValue + "<br/>";
202 } 205 }
203 } 206 }
204 207
205 // get the paths 208 // get the paths
206 res = runExpr(doc, srv, "xrd:Path/text()"); 209 res = runExpr(doc, srv, "xrd:Path/text()");
207 var p; 210 var p;
208 var qxri_prefix = qxri; 211 var qxri_prefix = qxri;
209 if (qxri_prefix.charAt(qxri_prefix.length - 1) != '/') { 212 if (qxri_prefix.charAt(qxri_prefix.length - 1) != '/') {
210 qxri_prefix += '/'; 213 qxri_prefix += '/';
211 } 214 }
212 215
213 while (p = res.iterateNext()) { 216 while (p = res.iterateNext()) {
214 if (p.nodeValue) { 217 if (p.nodeValue) {
215 html_paths += "<strong>Path:</strong> " + p.nodeValue 218 html_paths += "<strong>Path:</strong> " + p.nodeValue
216 + " [ <tt><a href=\"" + qxri_prefix + p.nodeValue + "\">" 219 + " [ <tt><a href=\"" + qxri_prefix + p.nodeValue + "\">"
217 + qxri_prefix + p.nodeValue + "</a></tt> ]" 220 + qxri_prefix + p.nodeValue + "</a></tt> ]"
218 + "<br/>\n"; 221 + "<br/>\n";
219 } 222 }
220 } 223 }
221 224
222 225
223 // get the mediatypes 226 // get the mediatypes
224 mediaTypes = new Array(); 227 mediaTypes = new Array();
225 res = runExpr(doc, srv, "xrd:MediaType/text()"); 228 res = runExpr(doc, srv, "xrd:MediaType/text()");
226 var m; 229 var m;
227 while (m = res.iterateNext()) { 230 while (m = res.iterateNext()) {
228 if (!knownServiceType) { 231 if (!knownServiceType) {
229 var srvType = guessServiceTypeByMime(m.nodeValue); 232 var srvType = guessServiceTypeByMime(m.nodeValue);
230 knownServiceType = srvType? srvType : null; 233 knownServiceType = srvType? srvType : null;
231 } 234 }
232 235
233 mediaTypes.push(m.nodeValue); 236 mediaTypes.push(m.nodeValue);
234 if (m.nodeValue) { 237 if (m.nodeValue) {
235 html_mediatypes += "<strong>Media Type:</strong> " + m.nodeValue + "<br/>"; 238 html_mediatypes += "<strong>Media Type:</strong> " + m.nodeValue + "<br/>";
236 } 239 }
237 } 240 }
238 241
239 242
240 res = runExpr(doc, srv, "xrd:URI/text()"); 243 res = runExpr(doc, srv, "xrd:URI");
241 var u; 244 var uu;
242 while (u = res.iterateNext()) { 245 while (uu = res.iterateNext()) {
243 if (!u.nodeValue) 246 var u = uu.firstChild;
247 if (!(u.nodeValue && u.nodeType==3))
244 continue; 248 continue;
245 249
246 var srvType = guessServiceTypeByURI(u.nodeValue); 250 var srvType = guessServiceTypeByURI(u.nodeValue);
247 if (!knownServiceType) { 251 if (!knownServiceType) {
248 knownServiceType = srvType; 252 knownServiceType = srvType;
249 } 253 }
250 254
251 html_uris += "<div class=\"" + getServiceClass(srvType) + "\">"; 255 html_uris += "<div class=\"" + getServiceClass(srvType) + "\">";
252 256
253 var linkContent = u.nodeValue; 257 var linkContent = u.nodeValue;
254 var uriParts = u.nodeValue.match('^(.*):(.*)$'); 258 var uriParts = u.nodeValue.match('^(.*):(.*)$');
255 if (!uriParts) 259 if (!uriParts)
256 continue; 260 continue;
257 261
258 if (uriParts[1] == 'data') { 262 if (uriParts[1] == 'data') {
259 uriParts = uriParts[2].match('^(.*/.*),(.*)'); 263 uriParts = uriParts[2].match('^(.*/.*),(.*)');
260 if (uriParts && uriParts[1].match('^image/', 'i')) { 264 if (uriParts && uriParts[1].match('^image/', 'i')) {
261 linkContent = "<img src=\"" + u.nodeValue + "\"/>"; 265 linkContent = "<img src=\"" + u.nodeValue + "\"/>";
262 } 266 }
263 else if (uriParts) { 267 else if (uriParts) {
264 linkContent = uriParts[1] + " data"; 268 linkContent = uriParts[1] + " data";
265 } 269 }
266 } 270 }
267 else if (uriParts[1] == 'skype') { 271 else if (uriParts[1] == 'skype') {
268 uriParts = uriParts[2].match('^(.*)\\?(.*)'); 272 uriParts = uriParts[2].match('^(.*)\\?(.*)');
269 if (uriParts) { 273 if (uriParts) {
270 if (uriParts[2] == "call") { 274 if (uriParts[2] == "call") {
271 linkContent = "<img src=\"chrome://foxri/content/skype_call_large.png\" alt=\"Call " + uriParts[1] + "\"/>"; 275 linkContent = "<img src=\"chrome://foxri/content/skype_call_large.png\" alt=\"Call " + uriParts[1] + "\"/>";
272 } 276 }
273 else if (uriParts[2] == "chat") { 277 else if (uriParts[2] == "chat") {
274 linkContent = "<img src=\"chrome://foxri/content/skype_chat_large.png\" alt=\"Chat with " + uriParts[1] + "\"/>"; 278 linkContent = "<img src=\"chrome://foxri/content/skype_chat_large.png\" alt=\"Chat with " + uriParts[1] + "\"/>";
275 } 279 }
276 else if (uriParts[2] == "add") { 280 else if (uriParts[2] == "add") {
277 linkContent = "<img src=\"chrome://foxri/content/skype_add_large.png\" alt=\"Add " + uriParts[1] + " to Skype\"/>"; 281 linkContent = "<img src=\"chrome://foxri/content/skype_add_large.png\" alt=\"Add " + uriParts[1] + " to Skype\"/>";
278 } 282 }
279 } 283 }
280 } 284 }
281 else if (uriParts[1] == 'aim') { 285 else if (uriParts[1] == 'aim') {
282 uriParts = uriParts[2].match('^(.*)\\?.*screenname=([^&]*)', 'i'); 286 uriParts = uriParts[2].match('^(.*)\\?.*screenname=([^&]*)', 'i');
283 if (uriParts) { 287 if (uriParts) {
284 linkContent = "<img src=\"chrome://foxri/content/aim_logo.gif\" alt=\"Chat with " + uriParts[2] + "\"/> Chat with " + uriParts[2]; 288 linkContent = "<img src=\"chrome://foxri/content/aim_logo.gif\" alt=\"Chat with " + uriParts[2] + "\"/> Chat with " + uriParts[2];
285 } 289 }
286 } 290 }
287 291
288 html_uris += "<a href=\""+u.nodeValue+"\">" 292 var linkhref = u.nodeValue;
293 var xrap = uu.getAttribute('append');
294 if(xrap=='qxri') {
295 linkhref += qxri.replace(/^xri:\/\//,'');
296 }else if(xrap!=null){
297 dump("Unhandled @append: "+xrap+"\n");
298 }
299 html_uris += "<a href=\""+linkhref+"\">"
289 + linkContent + "</a>"; 300 + linkContent + "</a>";
290 html_uris += "</div>"; 301 html_uris += "</div>";
291 } 302 }
292 303
293 var html = "<div class=\"service srv_" + getServiceClass(knownServiceType) + "\">\n"; 304 var html = "<div class=\"service srv_" + getServiceClass(knownServiceType) + "\">\n";
294 html += html_types; 305 html += html_types;
295 html += html_paths; 306 html += html_paths;
296 html += html_mediatypes; 307 html += html_mediatypes;
297 if (html_uris) { 308 if (html_uris) {
298 html += "<strong>URI(s):</strong><br/>\n"; 309 html += "<strong>URI(s):</strong><br/>\n";
299 html += html_uris; 310 html += html_uris;
300 } 311 }
301 html += "</div>"; 312 html += "</div>";
302 313
303 return html; 314 return html;
304} 315}
305 316
306 317
307 318
308function isKnownServiceType(type) 319function isKnownServiceType(type)
309{ 320{
310 if (type.toLowerCase() in SERVICE_CLASSES) { 321 if (type.toLowerCase() in SERVICE_CLASSES) {
311 return true; 322 return true;
312 } 323 }
313 return false; 324 return false;
314} 325}
315 326
316function getServiceClass(type) 327function getServiceClass(type)
317{ 328{
318 if (type && isKnownServiceType(type)) { 329 if (type && isKnownServiceType(type)) {
319 return SERVICE_CLASSES[type.toLowerCase()]; 330 return SERVICE_CLASSES[type.toLowerCase()];
320 } 331 }
321 return type; 332 return type;
322} 333}
323 334
324 335
325function guessServiceTypeByURI(uri) 336function guessServiceTypeByURI(uri)
326{ 337{
327 if (uri == null || uri == "") { 338 if (uri == null || uri == "") {
328 return "unknown"; 339 return "unknown";
329 } 340 }
330 if (uri.match(/^https?:/i)) { 341 if (uri.match(/^https?:/i)) {
331 return "www"; 342 return "www";
332 } 343 }
333 else if (uri.match(/^skype:/i)) { 344 else if (uri.match(/^skype:/i)) {
334 return "skype"; 345 return "skype";
335 } 346 }
336 else if (uri.match(/^aim:/i)) { 347 else if (uri.match(/^aim:/i)) {
@@ -347,97 +358,102 @@ function guessServiceTypeByURI(uri)
347 } 358 }
348 else if (uri.match(/^telnet:/i)) { 359 else if (uri.match(/^telnet:/i)) {
349 return "telnet"; 360 return "telnet";
350 } 361 }
351 else if (uri.match(/^news:/i)) { 362 else if (uri.match(/^news:/i)) {
352 return "news"; 363 return "news";
353 } 364 }
354 else if (uri.match(/^nntp:/i)) { 365 else if (uri.match(/^nntp:/i)) {
355 return "nntp"; 366 return "nntp";
356 } 367 }
357 else if (uri.match(/^ftp:/i)) { 368 else if (uri.match(/^ftp:/i)) {
358 return "ftp"; 369 return "ftp";
359 } 370 }
360 else if (uri.match(/^mailto:/i)) { 371 else if (uri.match(/^mailto:/i)) {
361 return "email"; 372 return "email";
362 } 373 }
363 else if (uri.match(/^urn:/i)) { 374 else if (uri.match(/^urn:/i)) {
364 return "urn"; 375 return "urn";
365 } 376 }
366 else if (uri.match(/^data:/i)) { 377 else if (uri.match(/^data:/i)) {
367 return "data"; 378 return "data";
368 } 379 }
369 else if (uri.match(/^feed:/i)) { 380 else if (uri.match(/^feed:/i)) {
370 return "feed"; 381 return "feed";
371 } 382 }
372 return "unknown"; 383 return "unknown";
373} 384}
374 385
375 386
376function guessServiceTypeByMime(mimeType) 387function guessServiceTypeByMime(mimeType)
377{ 388{
378 if (mimeType.match(/^application\/(rss|atom)\+xml/i)) { 389 if (mimeType.match(/^application\/(rss|atom)\+xml/i)) {
379 dump("feed detected!\n"); 390 dump("feed detected!\n");
380 return "feed"; 391 return "feed";
381 } 392 }
382 else if (mimeType.match(/^image\//i)) { 393 else if (mimeType.match(/^image\//i)) {
383 return "image"; 394 return "image";
384 } 395 }
385 return null; 396 return null;
386} 397}
387 398
388 399
389 400
390function friendlyServiceName(srvType, uri) 401function friendlyServiceName(srvType, uri)
391{ 402{
392 if (srvType && srvType == "xri://+i-service*(+contact)*($v*1.0)") { 403 if (srvType && srvType == "xri://+i-service*(+contact)*($v*1.0)") {
393 return "Contact Service"; 404 return "Contact Service";
394 } 405 }
395 else if (srvType && srvType == "http://openid.net/signon/1.0") { 406 else if (srvType && (
407 srvType == "http://openid.net/signon/1.0"
408 || srvType == "http://openid.net/signon/1.1"
409 || srvType == "http://specs.openid.net/auth/2.0/signon"
410 || srcType == "http://specs.openid.net/auth/2.0/server"
411 ) ) {
396 return "OpenID Authentication Service"; 412 return "OpenID Authentication Service";
397 } 413 }
398 else if (srvType && srvType == "xri://$res*auth*($v*2.0)") { 414 else if (srvType && srvType == "xri://$res*auth*($v*2.0)") {
399 return "Authority Resolution Service"; 415 return "Authority Resolution Service";
400 } 416 }
401 else { 417 else {
402 if (uri == null) { 418 if (uri == null) {
403 return "Generic Service"; 419 return "Generic Service";
404 } 420 }
405 if (uri.match(/^https?:/i)) { 421 if (uri.match(/^https?:/i)) {
406 return "Web Link"; 422 return "Web Link";
407 } 423 }
408 else if (uri.match(/^skype:/i)) { 424 else if (uri.match(/^skype:/i)) {
409 var user = uri.substring("skype:".length, uri.indexOf('?')); 425 var user = uri.substring("skype:".length, uri.indexOf('?'));
410 return "Skype <a href=\"" + uri + "\"><img src=\"chrome://foxri/content/skype_call.png\"></a>"; 426 return "Skype <a href=\"" + uri + "\"><img src=\"chrome://foxri/content/skype_call.png\"></a>";
411 } 427 }
412 else if (uri.match(/^mailto:/i)) { 428 else if (uri.match(/^mailto:/i)) {
413 var qmark = uri.indexOf('?'); 429 var qmark = uri.indexOf('?');
414 var email = (qmark == -1)? 430 var email = (qmark == -1)?
415 uri.substr("mailto:".length) : 431 uri.substr("mailto:".length) :
416 uri.substring("mailto:".length, qmark); 432 uri.substring("mailto:".length, qmark);
417 return "Email (address: " + email + ")"; 433 return "Email (address: " + email + ")";
418 } 434 }
419 else if (srvType != null) { 435 else if (srvType != null) {
420 return srvType; // return verbatim 436 return srvType; // return verbatim
421 } 437 }
422 return "Generic Service"; 438 return "Generic Service";
423 } 439 }
424} 440}
425 441
426 442
427 443
428 444
429function subHTML(template, vars) 445function subHTML(template, vars)
430{ 446{
431 for (key in vars) { 447 for (key in vars) {
432 template = template.replace(key, vars[key], 'g'); 448 template = template.replace(key, vars[key], 'g');
433 } 449 }
434 return template; 450 return template;
435} 451}
436 452
437 453
438/// Given the completed XMLHttpRequest object, renders the XRDS 454/// Given the completed XMLHttpRequest object, renders the XRDS
439function renderXRDS(xmlDoc) 455function renderXRDS(xmlDoc)
440{ 456{
441 var x = xmlDoc; 457 var x = xmlDoc;
442 var qxri = getString(x, x, "/xrds:XRDS/@ref"); 458 var qxri = getString(x, x, "/xrds:XRDS/@ref");
443 459