summaryrefslogtreecommitdiffabout
path: root/src
Unidiff
Diffstat (limited to 'src') (more/less context) (show whitespace changes)
-rwxr-xr-xsrc/components/xriProtocolHandler.js2
1 files changed, 2 insertions, 0 deletions
diff --git a/src/components/xriProtocolHandler.js b/src/components/xriProtocolHandler.js
index 3d27784..2e09f64 100755
--- a/src/components/xriProtocolHandler.js
+++ b/src/components/xriProtocolHandler.js
@@ -1,679 +1,681 @@
1/*********************************************************** 1/***********************************************************
2 constants 2 constants
3 ***********************************************************/ 3 ***********************************************************/
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', 52 'http://openid.net/signon/1.1': 'openid',
53 'http://specs.openid.net/auth/2.0/signon': 'openid', 53 'http://specs.openid.net/auth/2.0/signon': 'openid',
54 'http://specs.openid.net/auth/2.0/server': 'openid', 54 'http://specs.openid.net/auth/2.0/server': 'openid',
55 'xri://$res*auth*($v*2.0)': 'res-auth', 55 'xri://$res*auth*($v*2.0)': 'res-auth',
56 'xri://+i-service*(+authn)*(+saml)*($v*1.0)': 'authn-saml', 56 'xri://+i-service*(+authn)*(+saml)*($v*1.0)': 'authn-saml',
57 'xri://+i-service*(+metadata)*(+saml)*($v*1.0)' : 'metadata-saml', 57 'xri://+i-service*(+metadata)*(+saml)*($v*1.0)' : 'metadata-saml',
58 'xri://+i-service*(+forwarding)*($v*1.0)': 'i-forwarding' 58 'xri://+i-service*(+forwarding)*($v*1.0)': 'i-forwarding'
59}; 59};
60 60
61 61
62const 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\
63 <html xmlns=\"http://www.w3.org/1999/xhtml\">\n\ 63 <html xmlns=\"http://www.w3.org/1999/xhtml\">\n\
64 <head>\n\ 64 <head>\n\
65 <title>FoXRI Explorer - #QXRI#</title>\n\ 65 <title>FoXRI Explorer - #QXRI#</title>\n\
66 <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\
67 <body>\n\ 67 <body>\n\
68 <h1>FoXRI Explorer</h1>\n\ 68 <h1>FoXRI Explorer</h1>\n\
69 <div id=\"explorer_body\">\n"; 69 <div id=\"explorer_body\">\n";
70 70
71const HTML_FOOT = "</div>\n\ 71const HTML_FOOT = "</div>\n\
72 </body>\n\ 72 </body>\n\
73 </html>"; 73 </html>";
74 74
75 75
76 76
77/// Generic object method wrapper 77/// Generic object method wrapper
78function methodWrapper(obj, method) 78function methodWrapper(obj, method)
79{ 79{
80 return ( 80 return (
81 function() { 81 function() {
82 /* pass it this inner closure's arguments */ 82 /* pass it this inner closure's arguments */
83 obj[method](arguments); 83 obj[method](arguments);
84 } 84 }
85 ); 85 );
86} 86}
87 87
88 88
89 89
90/// XRDS utility functions 90/// XRDS utility functions
91 91
92 92
93var nsResolver = { 93var nsResolver = {
94 lookupNamespaceURI: function(prefix) 94 lookupNamespaceURI: function(prefix)
95 { 95 {
96 if (prefix == "xrds") 96 if (prefix == "xrds")
97 return "xri://$xrds"; 97 return "xri://$xrds";
98 else if (prefix == "xrd") 98 else if (prefix == "xrd")
99 return "xri://$xrd*($v*2.0)"; 99 return "xri://$xrd*($v*2.0)";
100 return ""; 100 return "";
101 } 101 }
102}; 102};
103 103
104 104
105 105
106function runExpr(doc, context, expr, returnType) 106function runExpr(doc, context, expr, returnType)
107{ 107{
108 if (!returnType) 108 if (!returnType)
109 returnType = XP_ANY_TYPE; 109 returnType = XP_ANY_TYPE;
110 var res = doc.evaluate(expr, context, nsResolver, returnType, null); 110 var res = doc.evaluate(expr, context, nsResolver, returnType, null);
111 return res; 111 return res;
112} 112}
113 113
114 114
115function getNumeric(doc, context, expr) 115function getNumeric(doc, context, expr)
116{ 116{
117 var res = runExpr(doc, context, expr, XP_NUMBER_TYPE); 117 var res = runExpr(doc, context, expr, XP_NUMBER_TYPE);
118 if (res) 118 if (res)
119 return res.numberValue; 119 return res.numberValue;
120 return null; 120 return null;
121} 121}
122 122
123 123
124function getString(doc, context, expr) 124function getString(doc, context, expr)
125{ 125{
126 // var res = runExpr(doc, context, expr, XPathResult.STRING_TYPE); 126 // var res = runExpr(doc, context, expr, XPathResult.STRING_TYPE);
127 var res = runExpr(doc, context, expr, XP_STRING_TYPE); 127 var res = runExpr(doc, context, expr, XP_STRING_TYPE);
128 if (res) 128 if (res)
129 return res.stringValue; 129 return res.stringValue;
130 return null; 130 return null;
131} 131}
132 132
133function getNode(doc, context, expr) 133function getNode(doc, context, expr)
134{ 134{
135 var res = runExpr(doc, context, expr, XP_FIRST_ORDERED_NODE_TYPE); 135 var res = runExpr(doc, context, expr, XP_FIRST_ORDERED_NODE_TYPE);
136 if (res) 136 if (res)
137 return res.singleNodeValue; 137 return res.singleNodeValue;
138 return null; 138 return null;
139} 139}
140 140
141 141
142function getFinalXRD(doc) 142function getFinalXRD(doc)
143{ 143{
144 var lastNode = doc.firstChild; 144 var lastNode = doc.firstChild;
145 while (true) { 145 while (true) {
146 var node = getNode(doc, lastNode, "xrds:XRDS[position()=last()]"); 146 var node = getNode(doc, lastNode, "xrds:XRDS[position()=last()]");
147 if (!node) 147 if (!node)
148 break; 148 break;
149 lastNode = node; 149 lastNode = node;
150 } 150 }
151 151
152 return getNode(doc, lastNode, "xrd:XRD[position()=last()]"); 152 return getNode(doc, lastNode, "xrd:XRD[position()=last()]");
153} 153}
154 154
155 155
156function isIName(xri) 156function isIName(xri)
157{ 157{
158 if (xri.match('^xri://.!', 'i')) { 158 if (xri.match('^xri://.!', 'i')) {
159 return false; 159 return false;
160 } 160 }
161 if (xri.match('^.!', 'i')) { 161 if (xri.match('^.!', 'i')) {
162 return false; 162 return false;
163 } 163 }
164 return true; 164 return true;
165} 165}
166 166
167 167
168function arraySearch(a, re) 168function arraySearch(a, re)
169{ 169{
170 var returnArr = new Array(); 170 var returnArr = new Array();
171 var i; 171 var i;
172 for (i = 0; i < a.length; i++) { 172 for (i = 0; i < a.length; i++) {
173 if (a[i].match(re)) { 173 if (a[i].match(re)) {
174 returnArr.push(a[i]); 174 returnArr.push(a[i]);
175 } 175 }
176 } 176 }
177 177
178 return returnArr; 178 return returnArr;
179} 179}
180 180
181 181
182function renderService(srv, doc, qxri) 182function renderService(srv, doc, qxri)
183{ 183{
184 var html_types = ''; 184 var html_types = '';
185 var html_paths = ''; 185 var html_paths = '';
186 var html_mediatypes = ''; 186 var html_mediatypes = '';
187 var html_uris = ''; 187 var html_uris = '';
188 var html_actions = ''; 188 var html_actions = '';
189 189
190 var serviceName = friendlyServiceName(null); 190 var serviceName = friendlyServiceName(null);
191 var serviceType; // the last non-null Type 191 var serviceType; // the last non-null Type
192 var knownServiceType; // first recognized service type 192 var knownServiceType; // first recognized service type
193 193
194 // get the types 194 // get the types
195 var res = runExpr(doc, srv, "xrd:Type/text()"); 195 var res = runExpr(doc, srv, "xrd:Type/text()");
196 var t; 196 var t;
197 while (t = res.iterateNext()) { 197 while (t = res.iterateNext()) {
198 if (t.nodeValue) { 198 if (t.nodeValue) {
199 if (!knownServiceType && isKnownServiceType(t.nodeValue)) { 199 if (!knownServiceType && isKnownServiceType(t.nodeValue)) {
200 knownServiceType = t.nodeValue; 200 knownServiceType = t.nodeValue;
201 } 201 }
202 202
203 serviceType = t.nodeValue; 203 serviceType = t.nodeValue;
204 html_types += "<strong>Type:</strong> " + t.nodeValue + "<br/>"; 204 html_types += "<strong>Type:</strong> " + t.nodeValue + "<br/>";
205 } 205 }
206 } 206 }
207 207
208 // get the paths 208 // get the paths
209 res = runExpr(doc, srv, "xrd:Path/text()"); 209 res = runExpr(doc, srv, "xrd:Path/text()");
210 var p; 210 var p;
211 var qxri_prefix = qxri; 211 var qxri_prefix = qxri;
212 if (qxri_prefix.charAt(qxri_prefix.length - 1) != '/') { 212 if (qxri_prefix.charAt(qxri_prefix.length - 1) != '/') {
213 qxri_prefix += '/'; 213 qxri_prefix += '/';
214 } 214 }
215 215
216 while (p = res.iterateNext()) { 216 while (p = res.iterateNext()) {
217 if (p.nodeValue) { 217 if (p.nodeValue) {
218 html_paths += "<strong>Path:</strong> " + p.nodeValue 218 html_paths += "<strong>Path:</strong> " + p.nodeValue
219 + " [ <tt><a href=\"" + qxri_prefix + p.nodeValue + "\">" 219 + " [ <tt><a href=\"" + qxri_prefix + p.nodeValue + "\">"
220 + qxri_prefix + p.nodeValue + "</a></tt> ]" 220 + qxri_prefix + p.nodeValue + "</a></tt> ]"
221 + "<br/>\n"; 221 + "<br/>\n";
222 } 222 }
223 } 223 }
224 224
225 225
226 // get the mediatypes 226 // get the mediatypes
227 mediaTypes = new Array(); 227 mediaTypes = new Array();
228 res = runExpr(doc, srv, "xrd:MediaType/text()"); 228 res = runExpr(doc, srv, "xrd:MediaType/text()");
229 var m; 229 var m;
230 while (m = res.iterateNext()) { 230 while (m = res.iterateNext()) {
231 if (!knownServiceType) { 231 if (!knownServiceType) {
232 var srvType = guessServiceTypeByMime(m.nodeValue); 232 var srvType = guessServiceTypeByMime(m.nodeValue);
233 knownServiceType = srvType? srvType : null; 233 knownServiceType = srvType? srvType : null;
234 } 234 }
235 235
236 mediaTypes.push(m.nodeValue); 236 mediaTypes.push(m.nodeValue);
237 if (m.nodeValue) { 237 if (m.nodeValue) {
238 html_mediatypes += "<strong>Media Type:</strong> " + m.nodeValue + "<br/>"; 238 html_mediatypes += "<strong>Media Type:</strong> " + m.nodeValue + "<br/>";
239 } 239 }
240 } 240 }
241 241
242 242
243 res = runExpr(doc, srv, "xrd:URI"); 243 res = runExpr(doc, srv, "xrd:URI");
244 var uu; 244 var uu;
245 while (uu = res.iterateNext()) { 245 while (uu = res.iterateNext()) {
246 var u = uu.firstChild; 246 var u = uu.firstChild;
247 if (!(u.nodeValue && u.nodeType==3)) 247 if (!(u.nodeValue && u.nodeType==3))
248 continue; 248 continue;
249 249
250 var srvType = guessServiceTypeByURI(u.nodeValue); 250 var srvType = guessServiceTypeByURI(u.nodeValue);
251 if (!knownServiceType) { 251 if (!knownServiceType) {
252 knownServiceType = srvType; 252 knownServiceType = srvType;
253 } 253 }
254 254
255 html_uris += "<div class=\"" + getServiceClass(srvType) + "\">"; 255 html_uris += "<div class=\"" + getServiceClass(srvType) + "\">";
256 256
257 var linkContent = u.nodeValue; 257 var linkContent = u.nodeValue;
258 var uriParts = u.nodeValue.match('^(.*):(.*)$'); 258 var uriParts = u.nodeValue.match('^(.*):(.*)$');
259 if (!uriParts) 259 if (!uriParts)
260 continue; 260 continue;
261 261
262 if (uriParts[1] == 'data') { 262 if (uriParts[1] == 'data') {
263 uriParts = uriParts[2].match('^(.*/.*),(.*)'); 263 uriParts = uriParts[2].match('^(.*/.*),(.*)');
264 if (uriParts && uriParts[1].match('^image/', 'i')) { 264 if (uriParts && uriParts[1].match('^image/', 'i')) {
265 linkContent = "<img src=\"" + u.nodeValue + "\"/>"; 265 linkContent = "<img src=\"" + u.nodeValue + "\"/>";
266 } 266 }
267 else if (uriParts) { 267 else if (uriParts) {
268 linkContent = uriParts[1] + " data"; 268 linkContent = uriParts[1] + " data";
269 } 269 }
270 } 270 }
271 else if (uriParts[1] == 'skype') { 271 else if (uriParts[1] == 'skype') {
272 uriParts = uriParts[2].match('^(.*)\\?(.*)'); 272 uriParts = uriParts[2].match('^(.*)\\?(.*)');
273 if (uriParts) { 273 if (uriParts) {
274 if (uriParts[2] == "call") { 274 if (uriParts[2] == "call") {
275 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] + "\"/>";
276 } 276 }
277 else if (uriParts[2] == "chat") { 277 else if (uriParts[2] == "chat") {
278 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] + "\"/>";
279 } 279 }
280 else if (uriParts[2] == "add") { 280 else if (uriParts[2] == "add") {
281 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\"/>";
282 } 282 }
283 } 283 }
284 } 284 }
285 else if (uriParts[1] == 'aim') { 285 else if (uriParts[1] == 'aim') {
286 uriParts = uriParts[2].match('^(.*)\\?.*screenname=([^&]*)', 'i'); 286 uriParts = uriParts[2].match('^(.*)\\?.*screenname=([^&]*)', 'i');
287 if (uriParts) { 287 if (uriParts) {
288 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];
289 } 289 }
290 } 290 }
291 291
292 var linkhref = u.nodeValue; 292 var linkhref = u.nodeValue;
293 var xrap = uu.getAttribute('append'); 293 var xrap = uu.getAttribute('append');
294 if(xrap=='qxri') { 294 if(xrap=='qxri') {
295 linkhref += qxri.replace(/^xri:\/\//,''); 295 linkhref += qxri.replace(/^xri:\/\//,'');
296 }else if(xrap=='authority') {
297 linkhref += qxri.replace(/^xri:\/\//,'').replace(/\//.*,'');
296 }else if(xrap!=null){ 298 }else if(xrap!=null){
297 dump("Unhandled @append: "+xrap+"\n"); 299 dump("Unhandled @append: "+xrap+"\n");
298 } 300 }
299 html_uris += "<a href=\""+linkhref+"\">" 301 html_uris += "<a href=\""+linkhref+"\">"
300 + linkContent + "</a>"; 302 + linkContent + "</a>";
301 html_uris += "</div>"; 303 html_uris += "</div>";
302 } 304 }
303 305
304 var html = "<div class=\"service srv_" + getServiceClass(knownServiceType) + "\">\n"; 306 var html = "<div class=\"service srv_" + getServiceClass(knownServiceType) + "\">\n";
305 html += html_types; 307 html += html_types;
306 html += html_paths; 308 html += html_paths;
307 html += html_mediatypes; 309 html += html_mediatypes;
308 if (html_uris) { 310 if (html_uris) {
309 html += "<strong>URI(s):</strong><br/>\n"; 311 html += "<strong>URI(s):</strong><br/>\n";
310 html += html_uris; 312 html += html_uris;
311 } 313 }
312 html += "</div>"; 314 html += "</div>";
313 315
314 return html; 316 return html;
315} 317}
316 318
317 319
318 320
319function isKnownServiceType(type) 321function isKnownServiceType(type)
320{ 322{
321 if (type.toLowerCase() in SERVICE_CLASSES) { 323 if (type.toLowerCase() in SERVICE_CLASSES) {
322 return true; 324 return true;
323 } 325 }
324 return false; 326 return false;
325} 327}
326 328
327function getServiceClass(type) 329function getServiceClass(type)
328{ 330{
329 if (type && isKnownServiceType(type)) { 331 if (type && isKnownServiceType(type)) {
330 return SERVICE_CLASSES[type.toLowerCase()]; 332 return SERVICE_CLASSES[type.toLowerCase()];
331 } 333 }
332 return type; 334 return type;
333} 335}
334 336
335 337
336function guessServiceTypeByURI(uri) 338function guessServiceTypeByURI(uri)
337{ 339{
338 if (uri == null || uri == "") { 340 if (uri == null || uri == "") {
339 return "unknown"; 341 return "unknown";
340 } 342 }
341 if (uri.match(/^https?:/i)) { 343 if (uri.match(/^https?:/i)) {
342 return "www"; 344 return "www";
343 } 345 }
344 else if (uri.match(/^skype:/i)) { 346 else if (uri.match(/^skype:/i)) {
345 return "skype"; 347 return "skype";
346 } 348 }
347 else if (uri.match(/^aim:/i)) { 349 else if (uri.match(/^aim:/i)) {
348 return "aim"; 350 return "aim";
349 } 351 }
350 else if (uri.match(/^xmpp:/i)) { 352 else if (uri.match(/^xmpp:/i)) {
351 return "jabber"; 353 return "jabber";
352 } 354 }
353 else if (uri.match(/^tel:/i)) { 355 else if (uri.match(/^tel:/i)) {
354 return "tel"; 356 return "tel";
355 } 357 }
356 else if (uri.match(/^callto:/i)) { 358 else if (uri.match(/^callto:/i)) {
357 return "callto"; 359 return "callto";
358 } 360 }
359 else if (uri.match(/^telnet:/i)) { 361 else if (uri.match(/^telnet:/i)) {
360 return "telnet"; 362 return "telnet";
361 } 363 }
362 else if (uri.match(/^news:/i)) { 364 else if (uri.match(/^news:/i)) {
363 return "news"; 365 return "news";
364 } 366 }
365 else if (uri.match(/^nntp:/i)) { 367 else if (uri.match(/^nntp:/i)) {
366 return "nntp"; 368 return "nntp";
367 } 369 }
368 else if (uri.match(/^ftp:/i)) { 370 else if (uri.match(/^ftp:/i)) {
369 return "ftp"; 371 return "ftp";
370 } 372 }
371 else if (uri.match(/^mailto:/i)) { 373 else if (uri.match(/^mailto:/i)) {
372 return "email"; 374 return "email";
373 } 375 }
374 else if (uri.match(/^urn:/i)) { 376 else if (uri.match(/^urn:/i)) {
375 return "urn"; 377 return "urn";
376 } 378 }
377 else if (uri.match(/^data:/i)) { 379 else if (uri.match(/^data:/i)) {
378 return "data"; 380 return "data";
379 } 381 }
380 else if (uri.match(/^feed:/i)) { 382 else if (uri.match(/^feed:/i)) {
381 return "feed"; 383 return "feed";
382 } 384 }
383 return "unknown"; 385 return "unknown";
384} 386}
385 387
386 388
387function guessServiceTypeByMime(mimeType) 389function guessServiceTypeByMime(mimeType)
388{ 390{
389 if (mimeType.match(/^application\/(rss|atom)\+xml/i)) { 391 if (mimeType.match(/^application\/(rss|atom)\+xml/i)) {
390 dump("feed detected!\n"); 392 dump("feed detected!\n");
391 return "feed"; 393 return "feed";
392 } 394 }
393 else if (mimeType.match(/^image\//i)) { 395 else if (mimeType.match(/^image\//i)) {
394 return "image"; 396 return "image";
395 } 397 }
396 return null; 398 return null;
397} 399}
398 400
399 401
400 402
401function friendlyServiceName(srvType, uri) 403function friendlyServiceName(srvType, uri)
402{ 404{
403 if (srvType && srvType == "xri://+i-service*(+contact)*($v*1.0)") { 405 if (srvType && srvType == "xri://+i-service*(+contact)*($v*1.0)") {
404 return "Contact Service"; 406 return "Contact Service";
405 } 407 }
406 else if (srvType && ( 408 else if (srvType && (
407 srvType == "http://openid.net/signon/1.0" 409 srvType == "http://openid.net/signon/1.0"
408 || srvType == "http://openid.net/signon/1.1" 410 || srvType == "http://openid.net/signon/1.1"
409 || srvType == "http://specs.openid.net/auth/2.0/signon" 411 || srvType == "http://specs.openid.net/auth/2.0/signon"
410 || srcType == "http://specs.openid.net/auth/2.0/server" 412 || srcType == "http://specs.openid.net/auth/2.0/server"
411 ) ) { 413 ) ) {
412 return "OpenID Authentication Service"; 414 return "OpenID Authentication Service";
413 } 415 }
414 else if (srvType && srvType == "xri://$res*auth*($v*2.0)") { 416 else if (srvType && srvType == "xri://$res*auth*($v*2.0)") {
415 return "Authority Resolution Service"; 417 return "Authority Resolution Service";
416 } 418 }
417 else { 419 else {
418 if (uri == null) { 420 if (uri == null) {
419 return "Generic Service"; 421 return "Generic Service";
420 } 422 }
421 if (uri.match(/^https?:/i)) { 423 if (uri.match(/^https?:/i)) {
422 return "Web Link"; 424 return "Web Link";
423 } 425 }
424 else if (uri.match(/^skype:/i)) { 426 else if (uri.match(/^skype:/i)) {
425 var user = uri.substring("skype:".length, uri.indexOf('?')); 427 var user = uri.substring("skype:".length, uri.indexOf('?'));
426 return "Skype <a href=\"" + uri + "\"><img src=\"chrome://foxri/content/skype_call.png\"></a>"; 428 return "Skype <a href=\"" + uri + "\"><img src=\"chrome://foxri/content/skype_call.png\"></a>";
427 } 429 }
428 else if (uri.match(/^mailto:/i)) { 430 else if (uri.match(/^mailto:/i)) {
429 var qmark = uri.indexOf('?'); 431 var qmark = uri.indexOf('?');
430 var email = (qmark == -1)? 432 var email = (qmark == -1)?
431 uri.substr("mailto:".length) : 433 uri.substr("mailto:".length) :
432 uri.substring("mailto:".length, qmark); 434 uri.substring("mailto:".length, qmark);
433 return "Email (address: " + email + ")"; 435 return "Email (address: " + email + ")";
434 } 436 }
435 else if (srvType != null) { 437 else if (srvType != null) {
436 return srvType; // return verbatim 438 return srvType; // return verbatim
437 } 439 }
438 return "Generic Service"; 440 return "Generic Service";
439 } 441 }
440} 442}
441 443
442 444
443 445
444 446
445function subHTML(template, vars) 447function subHTML(template, vars)
446{ 448{
447 for (key in vars) { 449 for (key in vars) {
448 template = template.replace(key, vars[key], 'g'); 450 template = template.replace(key, vars[key], 'g');
449 } 451 }
450 return template; 452 return template;
451} 453}
452 454
453 455
454/// Given the completed XMLHttpRequest object, renders the XRDS 456/// Given the completed XMLHttpRequest object, renders the XRDS
455function renderXRDS(xmlDoc) 457function renderXRDS(xmlDoc)
456{ 458{
457 var x = xmlDoc; 459 var x = xmlDoc;
458 var qxri = getString(x, x, "/xrds:XRDS/@ref"); 460 var qxri = getString(x, x, "/xrds:XRDS/@ref");
459 461
460 var html = subHTML(HTML_HEAD, { '#QXRI#': qxri }); 462 var html = subHTML(HTML_HEAD, { '#QXRI#': qxri });
461 463
462 // TODO: render parents as well 464 // TODO: render parents as well
463 465
464 var lastNode = getFinalXRD(x); 466 var lastNode = getFinalXRD(x);
465 if (lastNode) { 467 if (lastNode) {
466 var stat = getString(x, lastNode, "xrd:Status/@code"); 468 var stat = getString(x, lastNode, "xrd:Status/@code");
467 if (stat == "100") { 469 if (stat == "100") {
468 html += "<h3>Exploring <strong>" + qxri + "</strong></h3>"; 470 html += "<h3>Exploring <strong>" + qxri + "</strong></h3>";
469 } 471 }
470 else { 472 else {
471 var msg = getString(x, lastNode, "xrd:Status/text()"); 473 var msg = getString(x, lastNode, "xrd:Status/text()");
472 html += "<h3 class=\"error\"><strong>" + qxri + "</strong> failed to resolve (reason: " + stat + " - " + msg + ")</h3>"; 474 html += "<h3 class=\"error\"><strong>" + qxri + "</strong> failed to resolve (reason: " + stat + " - " + msg + ")</h3>";
473 } 475 }
474 476
475 html += "<br/>"; 477 html += "<br/>";
476 478
477 var services = runExpr(x, lastNode, "xrd:Service"); 479 var services = runExpr(x, lastNode, "xrd:Service");
478 var s; 480 var s;
479 var count = getNumeric(x, lastNode, "count(xrd:Service)"); 481 var count = getNumeric(x, lastNode, "count(xrd:Service)");
480 if (count > 0) { 482 if (count > 0) {
481 while (s = services.iterateNext()) { 483 while (s = services.iterateNext()) {
482 count++; 484 count++;
483 html += renderService(s, x, qxri); 485 html += renderService(s, x, qxri);
484 } 486 }
485 } 487 }
486 else if (stat == '222') { 488 else if (stat == '222') {
487 var xriType = isIName(qxri)? 'I-name' : 'I-number'; 489 var xriType = isIName(qxri)? 'I-name' : 'I-number';
488 html += "<p class='error'>" + xriType + " does not exist.</p>\n"; 490 html += "<p class='error'>" + xriType + " does not exist.</p>\n";
489 } 491 }
490 else { 492 else {
491 html += "<p>No service has been configured for this XRI</p>"; 493 html += "<p>No service has been configured for this XRI</p>";
492 } 494 }
493 495
494 } 496 }
495 497
496 html += "</html>"; 498 html += "</html>";
497 499
498 return html; 500 return html;
499} 501}
500 502
501 503
502 504
503 505
504 506
505 507
506/*********************************************************** 508/***********************************************************
507 XriServiceExplorer class definition 509 XriServiceExplorer class definition
508 ***********************************************************/ 510 ***********************************************************/
509 511
510 512
511function XRIChannel(uri) { 513function XRIChannel(uri) {
512 this.URI = uri; 514 this.URI = uri;
513 var r = uri.spec.indexOf('#'); 515 var r = uri.spec.indexOf('#');
514 if (r >= 0) { 516 if (r >= 0) {
515 this.qxri = uri.spec.substring(0, r); 517 this.qxri = uri.spec.substring(0, r);
516 this.fragment = uri.spec.substring(r); 518 this.fragment = uri.spec.substring(r);
517 } 519 }
518 else { 520 else {
519 this.qxri = uri.spec; 521 this.qxri = uri.spec;
520 } 522 }
521}; 523};
522 524
523 525
524XRIChannel.prototype = { 526XRIChannel.prototype = {
525 527
526 fragment: null, 528 fragment: null,
527 529
528/* private fields used internally */ 530/* private fields used internally */
529 qxri: null, 531 qxri: null,
530 532
531 xmlRequest: null, 533 xmlRequest: null,
532 534
533 renderedHTML: null, 535 renderedHTML: null,
534 536
535 scriptableInStream: null, 537 scriptableInStream: null,
536 538
537 buf: null, 539 buf: null,
538 540
539 mChannel: null, 541 mChannel: null,
540 542
541 543
542 copyFields: function(request) 544 copyFields: function(request)
543 { 545 {
544 dump("copyFields(loadFlags=" + request.loadFlags + ")\n"); 546 dump("copyFields(loadFlags=" + request.loadFlags + ")\n");
545 dump("loadGroup = " + request.loadGroup + "\n"); 547 dump("loadGroup = " + request.loadGroup + "\n");
546 dump("notificationCallbacks = " + request.notificationCallbacks + "\n"); 548 dump("notificationCallbacks = " + request.notificationCallbacks + "\n");
547 549
548 // copy request fields 550 // copy request fields
549 this.loadFlags = request.loadFlags; 551 this.loadFlags = request.loadFlags;
550 this.loadGroup = request.loadGroup; 552 this.loadGroup = request.loadGroup;
551 this.name = request.name; 553 this.name = request.name;
552 this.status = request.status; 554 this.status = request.status;
553 555
554 var channel = request.QueryInterface(nsIChannel); 556 var channel = request.QueryInterface(nsIChannel);
555 if (channel) { 557 if (channel) {
556 this.contentCharset = channel.contentCharset; 558 this.contentCharset = channel.contentCharset;
557 this.contentLength = channel.contentLength; 559 this.contentLength = channel.contentLength;
558 this.contentType = channel.contentType; // XXX 560 this.contentType = channel.contentType; // XXX
559 this.contentType = "text/html"; 561 this.contentType = "text/html";
560 this.notificationCallbacks = channel.notificationCallbacks; 562 this.notificationCallbacks = channel.notificationCallbacks;
561 this.originalURI = this.originalURI; 563 this.originalURI = this.originalURI;
562 this.URI = this.URI; 564 this.URI = this.URI;
563 this.owner = channel.owner; 565 this.owner = channel.owner;
564 this.securityInfo = channel.securityInfo; 566 this.securityInfo = channel.securityInfo;
565 567
566 channel = channel.QueryInterface(nsIHttpChannel); 568 channel = channel.QueryInterface(nsIHttpChannel);
567 if (channel) { 569 if (channel) {
568 this.allowPipelining = channel.allowPipelining; 570 this.allowPipelining = channel.allowPipelining;
569 this.redirectionLimit = channel.redirectionLimit; 571 this.redirectionLimit = channel.redirectionLimit;
570 this.referrer = channel.referrer; 572 this.referrer = channel.referrer;
571 this.requestMethod = channel.requestMethod; 573 this.requestMethod = channel.requestMethod;
572 this.requestSucceeded = channel.requestSucceeded; 574 this.requestSucceeded = channel.requestSucceeded;
573 this.responseStatus = channel.responseStatus; 575 this.responseStatus = channel.responseStatus;
574 this.responseStatusText = channel.responseStatusText; 576 this.responseStatusText = channel.responseStatusText;
575 } 577 }
576 } 578 }
577 579
578 }, 580 },
579 581
580 /* nsIStreamListener */ 582 /* nsIStreamListener */
581 asyncOpenListener: null, 583 asyncOpenListener: null,
582 584
583 /* nsISupports (but we really don't care) */ 585 /* nsISupports (but we really don't care) */
584 asyncOpenContext: null, 586 asyncOpenContext: null,
585 587
586 588
587 /* has the XML finished loading? */ 589 /* has the XML finished loading? */
588 loadDone: false, 590 loadDone: false,
589 591
590 592
591 593
592/* public fields (nsIStreamListener implementation) */ 594/* public fields (nsIStreamListener implementation) */
593 onDataAvailable : function(request, ctx, inputStream, offset, count) 595 onDataAvailable : function(request, ctx, inputStream, offset, count)
594 { 596 {
595 dump("\nonDataAvailable, offset=" + offset + ", count=" + count + "\n"); 597 dump("\nonDataAvailable, offset=" + offset + ", count=" + count + "\n");
596 598
597 // XXX 599 // XXX
598/* 600/*
599 this.copyFields(request); 601 this.copyFields(request);
600 this.asyncOpenListener.onDataAvailable(this, this.asyncOpenContext, inputStream, offset, count); 602 this.asyncOpenListener.onDataAvailable(this, this.asyncOpenContext, inputStream, offset, count);
601 return; 603 return;
602*/ 604*/
603 605
604 606
605 if (offset == 0) { 607 if (offset == 0) {
606 this.scriptableInStream.init(inputStream); 608 this.scriptableInStream.init(inputStream);
607 } 609 }
608 610
609 this.buf += this.scriptableInStream.read(count); 611 this.buf += this.scriptableInStream.read(count);
610 612
611 if (!request.isPending()) { 613 if (!request.isPending()) {
612 dump("request finished, buf = " + this.buf + "\n"); 614 dump("request finished, buf = " + this.buf + "\n");
613 615
614 this.scriptableInStream = null; 616 this.scriptableInStream = null;
615 } 617 }
616 else { 618 else {
617 dump("request pending...\n"); 619 dump("request pending...\n");
618 dump("buf so far = " + this.buf + "\n"); 620 dump("buf so far = " + this.buf + "\n");
619 } 621 }
620 }, 622 },
621 623
622 624
623/* public fields (nsIRequestObserver implementation) */ 625/* public fields (nsIRequestObserver implementation) */
624 onStartRequest : function(request, ctx) 626 onStartRequest : function(request, ctx)
625 { 627 {
626 dump("\nonStartRequest called\n"); 628 dump("\nonStartRequest called\n");
627 // XXX 629 // XXX
628 630
629 this.copyFields(request); 631 this.copyFields(request);
630 this.asyncOpenListener.onStartRequest(this, this.asyncOpenContext); 632 this.asyncOpenListener.onStartRequest(this, this.asyncOpenContext);
631 }, 633 },
632 634
633 635
634 onStopRequest : function(request, ctx, status) 636 onStopRequest : function(request, ctx, status)
635 { 637 {
636 dump("\nonStopRequest called - status " + status + "\n"); 638 dump("\nonStopRequest called - status " + status + "\n");
637 639
638 // XXX 640 // XXX
639/* 641/*
640 this.asyncOpenListener.onStopRequest(this, this.asyncOpenContext, status); 642 this.asyncOpenListener.onStopRequest(this, this.asyncOpenContext, status);
641 return; 643 return;
642*/ 644*/
643 645
644 this.copyFields(request); 646 this.copyFields(request);
645 this.loadDone = true; 647 this.loadDone = true;
646 648
647 if (status == 0) { 649 if (status == 0) {
648 650
649 var domParser = Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser); 651 var domParser = Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser);
650 var xmlDoc = domParser.parseFromString(this.buf, "text/xml"); 652 var xmlDoc = domParser.parseFromString(this.buf, "text/xml");
651 653
652 // make fake inputstream 654 // make fake inputstream
653 var renderedHTML = renderXRDS(xmlDoc); 655 var renderedHTML = renderXRDS(xmlDoc);
654 656
655 this.contentCharset = "UTF-8"; 657 this.contentCharset = "UTF-8";
656 this.contentLength = renderedHTML.length; 658 this.contentLength = renderedHTML.length;
657 this.contentType = "text/html"; 659 this.contentType = "text/html";
658 660
659 dump("rendered HTML = \n" + renderedHTML + "\n"); 661 dump("rendered HTML = \n" + renderedHTML + "\n");
660 662
661 dump("\nCalling asyncOpenListener.onStartRequest\n\n"); 663 dump("\nCalling asyncOpenListener.onStartRequest\n\n");
662 664
663 665
664 var strIStream = Components.classes["@mozilla.org/io/string-input-stream;1"].createInstance(Components.interfaces.nsIStringInputStream); 666 var strIStream = Components.classes["@mozilla.org/io/string-input-stream;1"].createInstance(Components.interfaces.nsIStringInputStream);
665 if (strIStream) { 667 if (strIStream) {
666 strIStream.setData(renderedHTML, renderedHTML.length); 668 strIStream.setData(renderedHTML, renderedHTML.length);
667/* 669/*
668 strIStream.setData(this.buf, this.buf.length); 670 strIStream.setData(this.buf, this.buf.length);
669*/ 671*/
670 dump("\nleftovers in string-input-stream = " + strIStream.available() + "\n"); 672 dump("\nleftovers in string-input-stream = " + strIStream.available() + "\n");
671 dump("\nCalling asyncOpenListener.onDataAvailable\n\n"); 673 dump("\nCalling asyncOpenListener.onDataAvailable\n\n");
672 this.asyncOpenListener.onDataAvailable(this, this.asyncOpenContext, strIStream, 0, renderedHTML.length); 674 this.asyncOpenListener.onDataAvailable(this, this.asyncOpenContext, strIStream, 0, renderedHTML.length);
673/* 675/*
674 this.asyncOpenListener.onDataAvailable(this, this.asyncOpenContext, strIStream, 0, this.buf.length); 676 this.asyncOpenListener.onDataAvailable(this, this.asyncOpenContext, strIStream, 0, this.buf.length);
675*/ 677*/
676 678
677 dump("\nleftovers in string-input-stream = " + strIStream.available() + "\n"); 679 dump("\nleftovers in string-input-stream = " + strIStream.available() + "\n");
678 } 680 }
679 } 681 }