summaryrefslogtreecommitdiffabout
path: root/src
Unidiff
Diffstat (limited to 'src') (more/less context) (ignore 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,1074 +1,1076 @@
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 }
680 else { 682 else {
681 dump("\nStatus = " + status + "\n"); 683 dump("\nStatus = " + status + "\n");
682 dump("Calling asyncOpenListener.onStartRequest\n\n"); 684 dump("Calling asyncOpenListener.onStartRequest\n\n");
683 this.asyncOpenListener.onStartRequest(this, this.asyncOpenContext); 685 this.asyncOpenListener.onStartRequest(this, this.asyncOpenContext);
684 } 686 }
685 687
686 dump("stopping request for underlying asyncOpenListener\n"); 688 dump("stopping request for underlying asyncOpenListener\n");
687 689
688 this.asyncOpenListener.onStopRequest(this, this.asyncOpenContext, status); 690 this.asyncOpenListener.onStopRequest(this, this.asyncOpenContext, status);
689 691
690 // copied from nsIWyciwygChannel 692 // copied from nsIWyciwygChannel
691 this.asyncOpenListener = null; 693 this.asyncOpenListener = null;
692 this.asyncOpenContext = null; 694 this.asyncOpenContext = null;
693 695
694/* 696/*
695 if (this.loadGroup) { 697 if (this.loadGroup) {
696 this.loadGroup.removeRequest(request, null, status); 698 this.loadGroup.removeRequest(request, null, status);
697 } 699 }
698*/ 700*/
699 701
700 this.notificationCallbacks = null; 702 this.notificationCallbacks = null;
701 this.mChannel = null; 703 this.mChannel = null;
702 704
703 dump("stopped request\n"); 705 dump("stopped request\n");
704 }, 706 },
705 707
706 708
707/* public fields (nsIInputStream implementation) */ 709/* public fields (nsIInputStream implementation) */
708 available: function() 710 available: function()
709 { 711 {
710 dump("nsIInputStream::available called\n"); 712 dump("nsIInputStream::available called\n");
711 return renderedHTML.length; 713 return renderedHTML.length;
712 }, 714 },
713 715
714 close: function() 716 close: function()
715 { 717 {
716 dump("nsIInputStream::close called\n"); 718 dump("nsIInputStream::close called\n");
717 }, 719 },
718 720
719 isNonBlocking: function() { 721 isNonBlocking: function() {
720 dump("nsIInputStream::isNonBlocking called\n"); 722 dump("nsIInputStream::isNonBlocking called\n");
721 return true; 723 return true;
722 }, 724 },
723 725
724 read: function() { dump("nsIInputStream::read() called!!!\n"); }, 726 read: function() { dump("nsIInputStream::read() called!!!\n"); },
725 727
726 728
727 729
728 730
729 731
730/* public fields (nsIRequest implmentation) */ 732/* public fields (nsIRequest implmentation) */
731 733
732 loadFlags: 0, 734 loadFlags: 0,
733 735
734 loadGroup: null, 736 loadGroup: null,
735 737
736 name: "xri://request", 738 name: "xri://request",
737 739
738 status: 0, 740 status: 0,
739 741
740 cancel: function(status) { dump("\ncancel called...\n"); }, 742 cancel: function(status) { dump("\ncancel called...\n"); },
741 743
742 isPending: function() { 744 isPending: function() {
743 dump("isPending called\n\n"); 745 dump("isPending called\n\n");
744 return !this.loadDone; 746 return !this.loadDone;
745 }, 747 },
746 748
747 resume: function() { dump("resume called\n"); }, 749 resume: function() { dump("resume called\n"); },
748 750
749 suspend: function() { dump("suspend called\n"); }, 751 suspend: function() { dump("suspend called\n"); },
750 752
751 753
752 754
753/* public fields (nsIChannel implmentation) */ 755/* public fields (nsIChannel implmentation) */
754 756
755 contentCharset: null, 757 contentCharset: null,
756 758
757 contentLength: -1, 759 contentLength: -1,
758 760
759 contentType: null, 761 contentType: null,
760 762
761 notificationCallbacks: null, 763 notificationCallbacks: null,
762 764
763 originalURI: null, 765 originalURI: null,
764 766
765 owner: null, 767 owner: null,
766 768
767 securityInfo: null, 769 securityInfo: null,
768 770
769 URI: null, 771 URI: null,
770 772
771 open: function() 773 open: function()
772 { 774 {
773 dump("open not supporteD!!!!!!\n"); 775 dump("open not supporteD!!!!!!\n");
774 }, 776 },
775 777
776 asyncOpen: function(listener, context) 778 asyncOpen: function(listener, context)
777 { 779 {
778 dump("asyncOpen called!!!!!!\n"); 780 dump("asyncOpen called!!!!!!\n");
779 this.asyncOpenListener = listener; 781 this.asyncOpenListener = listener;
780 this.asyncOpenContext = context; 782 this.asyncOpenContext = context;
781 783
782 var hxri = PROXY_URI + this.qxri 784 var hxri = PROXY_URI + this.qxri
783 + "?_xrd_r=application/xrds%2Bxml;sep=false"; 785 + "?_xrd_r=application/xrds%2Bxml;sep=false";
784 var ioService = Components.classesByID[kIOSERVICE_CID_STR].getService(); 786 var ioService = Components.classesByID[kIOSERVICE_CID_STR].getService();
785 ioService = ioService.QueryInterface(nsIIOService); 787 ioService = ioService.QueryInterface(nsIIOService);
786 var channel = ioService.newChannel(hxri, null, null); 788 var channel = ioService.newChannel(hxri, null, null);
787 789
788 if (this.scriptableInStream) { 790 if (this.scriptableInStream) {
789 dump("Hey! You can't possibly be reusing this handler?!\n"); 791 dump("Hey! You can't possibly be reusing this handler?!\n");
790 return; 792 return;
791 } 793 }
792 794
793 dump("making scriptableInStream\n"); 795 dump("making scriptableInStream\n");
794 this.scriptableInStream = Components.classes["@mozilla.org/scriptableinputstream;1"] 796 this.scriptableInStream = Components.classes["@mozilla.org/scriptableinputstream;1"]
795 .createInstance(Components.interfaces.nsIScriptableInputStream); 797 .createInstance(Components.interfaces.nsIScriptableInputStream);
796 798
797 this.buf = ''; 799 this.buf = '';
798 800
799 dump("notificationCallbacks = " + this.notificationCallbacks + "\n"); 801 dump("notificationCallbacks = " + this.notificationCallbacks + "\n");
800 dump("loadFlags = " + this.loadFlags + "\n"); 802 dump("loadFlags = " + this.loadFlags + "\n");
801 dump("loadGroup = " + this.loadGroup + "\n"); 803 dump("loadGroup = " + this.loadGroup + "\n");
802 dump("owner = " + this.owner + "\n"); 804 dump("owner = " + this.owner + "\n");
803 dump("securityInfo = " + this.securityInfo + "\n"); 805 dump("securityInfo = " + this.securityInfo + "\n");
804 806
805 // these nsIRequest attributes must be copied to the stub 807 // these nsIRequest attributes must be copied to the stub
806 // channel that we created 808 // channel that we created
807 channel.notificationCallbacks = this.notificationCallbacks; 809 channel.notificationCallbacks = this.notificationCallbacks;
808 channel.loadGroup = this.loadGroup; 810 channel.loadGroup = this.loadGroup;
809 channel.loadFlags = this.loadFlags; 811 channel.loadFlags = this.loadFlags;
810 812
811 this.mChannel = channel; 813 this.mChannel = channel;
812 channel.asyncOpen(this, null); 814 channel.asyncOpen(this, null);
813 }, 815 },
814 816
815 817
816/* public fields (nsIChannel implementation) */ 818/* public fields (nsIChannel implementation) */
817 allowPipelining: false, 819 allowPipelining: false,
818 redirectionLimit: 5, 820 redirectionLimit: 5,
819 referrer: "", 821 referrer: "",
820 requestMethod: "GET", 822 requestMethod: "GET",
821 requestSucceeded: true, 823 requestSucceeded: true,
822 responseStatus: 200, 824 responseStatus: 200,
823 responseStatusText: "OK", 825 responseStatusText: "OK",
824 getRequestHeader: function(header) { 826 getRequestHeader: function(header) {
825 dump("getRequestHeader(" + header + ")\n"); 827 dump("getRequestHeader(" + header + ")\n");
826 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel); 828 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
827 829
828 try { 830 try {
829 var val = httpChannel.getRequestHeader(header); 831 var val = httpChannel.getRequestHeader(header);
830 dump("getRequestHeader(" + header + ") = " + val + "\n"); 832 dump("getRequestHeader(" + header + ") = " + val + "\n");
831 return val; 833 return val;
832 } 834 }
833 catch (e) { 835 catch (e) {
834 dump("getRequestHeader - got exception: " + e + "\n"); 836 dump("getRequestHeader - got exception: " + e + "\n");
835 throw e; 837 throw e;
836 } 838 }
837 }, 839 },
838 getResponseHeader: function(header) { 840 getResponseHeader: function(header) {
839 dump("getResponseHeader(" + header + ")\n"); 841 dump("getResponseHeader(" + header + ")\n");
840 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel); 842 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
841 843
842 try { 844 try {
843 var val = httpChannel.getResponseHeader(header); 845 var val = httpChannel.getResponseHeader(header);
844 dump("getResponseHeader(" + header + ") = " + val + "\n"); 846 dump("getResponseHeader(" + header + ") = " + val + "\n");
845 return val; 847 return val;
846 } 848 }
847 catch (e) { 849 catch (e) {
848 dump("getResponseHeader - got exception: " + e + "\n"); 850 dump("getResponseHeader - got exception: " + e + "\n");
849 throw e; 851 throw e;
850 } 852 }
851 return null; 853 return null;
852 }, 854 },
853 isNoCacheResponse: function() { 855 isNoCacheResponse: function() {
854 dump("isNoCacheResponse()\n"); 856 dump("isNoCacheResponse()\n");
855 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel); 857 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
856 return httpChannel.isNoCacheResponse(); 858 return httpChannel.isNoCacheResponse();
857 }, 859 },
858 isNoStoreResponse: function() { 860 isNoStoreResponse: function() {
859 dump("isNoStoreResponse()\n"); 861 dump("isNoStoreResponse()\n");
860 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel); 862 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
861 return httpChannel.isNoStoreResponse(); 863 return httpChannel.isNoStoreResponse();
862 return true; 864 return true;
863 }, 865 },
864 setRequestHeader: function(header, value, merge) { 866 setRequestHeader: function(header, value, merge) {
865 dump("setRequestHeader(" + header + ", " + value + ")\n"); 867 dump("setRequestHeader(" + header + ", " + value + ")\n");
866 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel); 868 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
867 return httpChannel.setRequestHeader(header, value, merge); 869 return httpChannel.setRequestHeader(header, value, merge);
868 }, 870 },
869 setResponseHeader: function(header, value, merge) { 871 setResponseHeader: function(header, value, merge) {
870 dump("setResponseHeader(" + header + ", " + value + ")\n"); 872 dump("setResponseHeader(" + header + ", " + value + ")\n");
871 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel); 873 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
872 return httpChannel.setResponseHeader(header, value, merge); 874 return httpChannel.setResponseHeader(header, value, merge);
873 }, 875 },
874 visitRequestHeaders: function(visitor) { 876 visitRequestHeaders: function(visitor) {
875 dump("visitRequestHeaders()\n"); 877 dump("visitRequestHeaders()\n");
876 }, 878 },
877 visitResponseHeaders: function(visitor) { 879 visitResponseHeaders: function(visitor) {
878 dump("visitResponseHeaders()\n"); 880 dump("visitResponseHeaders()\n");
879 }, 881 },
880 882
881 QueryInterface: function(iid) 883 QueryInterface: function(iid)
882 { 884 {
883 dump("QI.. \n"); 885 dump("QI.. \n");
884 if (iid.equals(nsIChannel)) 886 if (iid.equals(nsIChannel))
885 dump("QI(nsIChannel)\n"); 887 dump("QI(nsIChannel)\n");
886 else if (iid.equals(nsIHttpChannel)) 888 else if (iid.equals(nsIHttpChannel))
887 dump("QI(nsIHttpChannel)\n"); 889 dump("QI(nsIHttpChannel)\n");
888 else if (iid.equals(Components.interfaces.nsIUploadChannel)) 890 else if (iid.equals(Components.interfaces.nsIUploadChannel))
889 dump("QI(nsIUploadChannel) - not supported\n"); 891 dump("QI(nsIUploadChannel) - not supported\n");
890 else if (iid.equals(Components.interfaces.nsICachingChannel)) 892 else if (iid.equals(Components.interfaces.nsICachingChannel))
891 dump("QI(nsICachingChannel) - not supported\n"); 893 dump("QI(nsICachingChannel) - not supported\n");
892 else if (iid.equals(Components.interfaces.nsIClassInfo)) 894 else if (iid.equals(Components.interfaces.nsIClassInfo))
893 dump("QI(nsIClassInfo) - not supported\n"); 895 dump("QI(nsIClassInfo) - not supported\n");
894 else if (iid.equals(Components.interfaces.nsISecurityCheckedComponent)) 896 else if (iid.equals(Components.interfaces.nsISecurityCheckedComponent))
895 dump("QI(nsISecurityCheckedComponent) - not supported\n"); 897 dump("QI(nsISecurityCheckedComponent) - not supported\n");
896 else if (iid.equals(Components.interfaces.nsIWyciwygChannel)) 898 else if (iid.equals(Components.interfaces.nsIWyciwygChannel))
897 dump("QI(nsIWyciwygChannel) - not supported\n"); 899 dump("QI(nsIWyciwygChannel) - not supported\n");
898 else if (iid.equals(Components.interfaces.nsIMultiPartChannel)) 900 else if (iid.equals(Components.interfaces.nsIMultiPartChannel))
899 dump("QI(nsIMultiPartChannel) - not supported\n"); 901 dump("QI(nsIMultiPartChannel) - not supported\n");
900 else if (iid.equals(Components.interfaces.nsIHttpChannelInternal)) 902 else if (iid.equals(Components.interfaces.nsIHttpChannelInternal))
901 dump("QI(nsIHttpChannelInternal) - not supported\n"); 903 dump("QI(nsIHttpChannelInternal) - not supported\n");
902 else if (iid.equals(Components.interfaces.nsIWritablePropertyBag2)) 904 else if (iid.equals(Components.interfaces.nsIWritablePropertyBag2))
903 dump("QI(nsIWritablePropertyBag2) - not supported\n"); 905 dump("QI(nsIWritablePropertyBag2) - not supported\n");
904 else if (iid.equals(nsIRequest)) 906 else if (iid.equals(nsIRequest))
905 dump("QI(nsIRequest)\n"); 907 dump("QI(nsIRequest)\n");
906 else if (iid.equals(nsIRequestObserver)) 908 else if (iid.equals(nsIRequestObserver))
907 dump("QI(nsIRequestObserver)\n"); 909 dump("QI(nsIRequestObserver)\n");
908 else if (iid.equals(nsISupports)) 910 else if (iid.equals(nsISupports))
909 dump("QI(nsISupports)\n"); 911 dump("QI(nsISupports)\n");
910 else if (iid.equals(nsIStreamListener)) 912 else if (iid.equals(nsIStreamListener))
911 dump("QI(nsIStreamListener)\n"); 913 dump("QI(nsIStreamListener)\n");
912 else 914 else
913 dump("unknown " + iid + "\n"); 915 dump("unknown " + iid + "\n");
914 916
915 if (iid.equals(nsISupports) || 917 if (iid.equals(nsISupports) ||
916 iid.equals(nsIRequest) || 918 iid.equals(nsIRequest) ||
917 iid.equals(nsIRequestObserver) || 919 iid.equals(nsIRequestObserver) ||
918 iid.equals(nsIChannel) || 920 iid.equals(nsIChannel) ||
919 iid.equals(nsIHttpChannel) || 921 iid.equals(nsIHttpChannel) ||
920 iid.equals(nsIStreamListener) 922 iid.equals(nsIStreamListener)
921 ) { 923 ) {
922 return this; 924 return this;
923 } 925 }
924 926
925 throw Components.results.NS_ERROR_NO_INTERFACE; 927 throw Components.results.NS_ERROR_NO_INTERFACE;
926 } 928 }
927}; 929};
928 930
929 931
930 932
931/*********************************************************** 933/***********************************************************
932 XriProtocolHandler class definition 934 XriProtocolHandler class definition
933 ***********************************************************/ 935 ***********************************************************/
934 936
935//class constructor 937//class constructor
936function XriProtocolHandler() { 938function XriProtocolHandler() {
937}; 939};
938 940
939// class definition 941// class definition
940XriProtocolHandler.prototype = { 942XriProtocolHandler.prototype = {
941 defaultPort: 80, // HTTP 943 defaultPort: 80, // HTTP
942 944
943 protocolFlags : nsIProtocolHandler.ALLOWS_PROXY | nsIProtocolHandler.ALLOWS_PROXY_HTTP, 945 protocolFlags : nsIProtocolHandler.ALLOWS_PROXY | nsIProtocolHandler.ALLOWS_PROXY_HTTP,
944 946
945 scheme: "xri", 947 scheme: "xri",
946 948
947 allowPort: function() { 949 allowPort: function() {
948 return false; // only called for blacklisted ports, should respect 950 return false; // only called for blacklisted ports, should respect
949 }, 951 },
950 952
951 _newHttpChannel: function(aURI) 953 _newHttpChannel: function(aURI)
952 { 954 {
953 var HXRI = PROXY_URI + aURI.spec; 955 var HXRI = PROXY_URI + aURI.spec;
954 var ioService = Components.classesByID[kIOSERVICE_CID_STR].getService(); 956 var ioService = Components.classesByID[kIOSERVICE_CID_STR].getService();
955 ioService = ioService.QueryInterface(nsIIOService); 957 ioService = ioService.QueryInterface(nsIIOService);
956 var channel = ioService.newChannel(HXRI, null, null); 958 var channel = ioService.newChannel(HXRI, null, null);
957 return channel; 959 return channel;
958 }, 960 },
959 961
960 newChannel: function(aURI) 962 newChannel: function(aURI)
961 { 963 {
962 // leave alone if path is not empty or just a single slash or query exists 964 // leave alone if path is not empty or just a single slash or query exists
963 965
964 dump("path='" + aURI.path + "'\n"); 966 dump("path='" + aURI.path + "'\n");
965 dump("query='" + aURI.query + "'\n"); 967 dump("query='" + aURI.query + "'\n");
966 dump("spec='" + aURI.spec + "'\n"); 968 dump("spec='" + aURI.spec + "'\n");
967 969
968 var slashPos = aURI.spec.indexOf('/', 'xri://'.length); 970 var slashPos = aURI.spec.indexOf('/', 'xri://'.length);
969 var qmarkPos = aURI.spec.indexOf('?'); 971 var qmarkPos = aURI.spec.indexOf('?');
970 dump("slashPos='" + slashPos + "'\n"); 972 dump("slashPos='" + slashPos + "'\n");
971 dump("qmarkPos='" + qmarkPos + "'\n"); 973 dump("qmarkPos='" + qmarkPos + "'\n");
972 if ((slashPos > 0 && slashPos < aURI.spec.length - 1) || qmarkPos > -1) { 974 if ((slashPos > 0 && slashPos < aURI.spec.length - 1) || qmarkPos > -1) {
973 return this._newHttpChannel(aURI); 975 return this._newHttpChannel(aURI);
974 } 976 }
975 977
976 var explorer = new XRIChannel(aURI); 978 var explorer = new XRIChannel(aURI);
977 return explorer; 979 return explorer;
978 }, 980 },
979 981
980 982
981 newURI: function(spec, originCharset, baseURI) 983 newURI: function(spec, originCharset, baseURI)
982 { 984 {
983 var newSpec = spec; 985 var newSpec = spec;
984 if (baseURI != null) { 986 if (baseURI != null) {
985 // standard-url (nsIURL) does not work with @-GCS 987 // standard-url (nsIURL) does not work with @-GCS
986 var baseURL = Components.classes[CID_URL].createInstance(nsIURL); 988 var baseURL = Components.classes[CID_URL].createInstance(nsIURL);
987 baseURL.spec = baseURI.spec; 989 baseURL.spec = baseURI.spec;
988 newSpec = baseURL.resolve(spec); 990 newSpec = baseURL.resolve(spec);
989 } 991 }
990 992
991 var uri = Components.classes[CID_URI].createInstance(nsIURI); 993 var uri = Components.classes[CID_URI].createInstance(nsIURI);
992 uri.spec = newSpec; 994 uri.spec = newSpec;
993 return uri; 995 return uri;
994 }, 996 },
995 997
996 QueryInterface: function(aIID) 998 QueryInterface: function(aIID)
997 { 999 {
998 if (!aIID.equals(nsIProtocolHandler) && 1000 if (!aIID.equals(nsIProtocolHandler) &&
999 !aIID.equals(nsISupports)) 1001 !aIID.equals(nsISupports))
1000 throw Components.results.NS_ERROR_NO_INTERFACE; 1002 throw Components.results.NS_ERROR_NO_INTERFACE;
1001 return this; 1003 return this;
1002 } 1004 }
1003}; 1005};
1004 1006
1005 1007
1006/*********************************************************** 1008/***********************************************************
1007 class factory 1009 class factory
1008 1010
1009 This object is a member of the global-scope Components.classes. 1011 This object is a member of the global-scope Components.classes.
1010 It is keyed off of the contract ID. Eg: 1012 It is keyed off of the contract ID. Eg:
1011 1013
1012 myXriProtocolHandler = Components.classes["@dietrich.ganx4.com/helloworld;1"]. 1014 myXriProtocolHandler = Components.classes["@dietrich.ganx4.com/helloworld;1"].
1013 createInstance(Components.interfaces.nsIXriProtocolHandler); 1015 createInstance(Components.interfaces.nsIXriProtocolHandler);
1014 1016
1015 ***********************************************************/ 1017 ***********************************************************/
1016var XriProtocolHandlerFactory = { 1018var XriProtocolHandlerFactory = {
1017 createInstance: function (aOuter, aIID) 1019 createInstance: function (aOuter, aIID)
1018 { 1020 {
1019 if (aOuter != null) 1021 if (aOuter != null)
1020 throw Components.results.NS_ERROR_NO_AGGREGATION; 1022 throw Components.results.NS_ERROR_NO_AGGREGATION;
1021 return (new XriProtocolHandler()).QueryInterface(aIID); 1023 return (new XriProtocolHandler()).QueryInterface(aIID);
1022 } 1024 }
1023}; 1025};
1024 1026
1025 1027
1026/*********************************************************** 1028/***********************************************************
1027 module definition (xpcom registration) 1029 module definition (xpcom registration)
1028 ***********************************************************/ 1030 ***********************************************************/
1029var XriProtocolHandlerModule = { 1031var XriProtocolHandlerModule = {
1030 1032
1031 _firstTime: true, 1033 _firstTime: true,
1032 1034
1033 registerSelf: function(aCompMgr, aFileSpec, aLocation, aType) 1035 registerSelf: function(aCompMgr, aFileSpec, aLocation, aType)
1034 { 1036 {
1035 if (this._firstTime) { 1037 if (this._firstTime) {
1036 this._firstTime = false; 1038 this._firstTime = false;
1037 throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN; 1039 throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
1038 } 1040 }
1039 aCompMgr = aCompMgr. 1041 aCompMgr = aCompMgr.
1040 QueryInterface(Components.interfaces.nsIComponentRegistrar); 1042 QueryInterface(Components.interfaces.nsIComponentRegistrar);
1041 aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME, 1043 aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME,
1042 CONTRACT_ID, aFileSpec, aLocation, aType); 1044 CONTRACT_ID, aFileSpec, aLocation, aType);
1043 }, 1045 },
1044 1046
1045 unregisterSelf: function(aCompMgr, aLocation, aType) 1047 unregisterSelf: function(aCompMgr, aLocation, aType)
1046 { 1048 {
1047 aCompMgr = aCompMgr. 1049 aCompMgr = aCompMgr.
1048 QueryInterface(Components.interfaces.nsIComponentRegistrar); 1050 QueryInterface(Components.interfaces.nsIComponentRegistrar);
1049 aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation); 1051 aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation);
1050 }, 1052 },
1051 1053
1052 getClassObject: function(aCompMgr, aCID, aIID) 1054 getClassObject: function(aCompMgr, aCID, aIID)
1053 { 1055 {
1054 if (!aIID.equals(Components.interfaces.nsIFactory)) 1056 if (!aIID.equals(Components.interfaces.nsIFactory))
1055 throw Components.results.NS_ERROR_NOT_IMPLEMENTED; 1057 throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
1056 1058
1057 if (aCID.equals(CLASS_ID)) 1059 if (aCID.equals(CLASS_ID))
1058 return XriProtocolHandlerFactory; 1060 return XriProtocolHandlerFactory;
1059 1061
1060 throw Components.results.NS_ERROR_NO_INTERFACE; 1062 throw Components.results.NS_ERROR_NO_INTERFACE;
1061 }, 1063 },
1062 1064
1063 canUnload: function(aCompMgr) { return true; } 1065 canUnload: function(aCompMgr) { return true; }
1064}; 1066};
1065 1067
1066 1068
1067/*********************************************************** 1069/***********************************************************
1068 module initialization 1070 module initialization
1069 1071
1070 When the application registers the component, this function 1072 When the application registers the component, this function
1071 is called. 1073 is called.
1072 ***********************************************************/ 1074 ***********************************************************/
1073function NSGetModule(aCompMgr, aFileSpec) { return XriProtocolHandlerModule; } 1075function NSGetModule(aCompMgr, aFileSpec) { return XriProtocolHandlerModule; }
1074 1076