comparison lightstring.js @ 29:1e6d2ca2daae

Adds a Lightstring.Stanza object and use it.
author Sonny Piers <sonny.piers@gmail.com>
date Sat, 28 Jan 2012 04:34:30 +0100
parents 630b9579fe4a
children 6ce66fba0242
comparison
equal deleted inserted replaced
28:630b9579fe4a 29:1e6d2ca2daae
56 /** 56 /**
57 * @function Transforms a XML string to a DOM object. 57 * @function Transforms a XML string to a DOM object.
58 * @param {String} aString XML string. 58 * @param {String} aString XML string.
59 * @return {Object} Domified XML. 59 * @return {Object} Domified XML.
60 */ 60 */
61 xml2dom: function(aString) { 61 XML2DOM: function(aString) {
62 return this.parser.parseFromString(aString, 'text/xml').documentElement; 62 var DOM = null;
63 try {
64 DOM = this.parser.parseFromString(aString, 'text/xml').documentElement;
65 }
66 catch (e) {
67 alert(e);
68 }
69 finally {
70 return DOM;
71 };
63 }, 72 },
64 /** 73 /**
65 * @function Transforms a DOM object to a XML string. 74 * @function Transforms a DOM object to a XML string.
66 * @param {Object} aString DOM object. 75 * @param {Object} aString DOM object.
67 * @return {String} Stringified DOM. 76 * @return {String} Stringified DOM.
68 */ 77 */
69 dom2xml: function(aElement) { 78 DOM2XML: function(aElement) {
70 return this.serializer.serializeToString(aElement); 79 var XML = null;
80 try {
81 XML = this.serializer.serializeToString(aElement);
82 }
83 catch (e) {
84 alert(e);
85 }
86 finally {
87 return XML;
88 };
71 } 89 }
72 }; 90 };
73 91
74 /** 92 /**
75 * @constructor Creates a new Lightstring connection 93 * @constructor Creates a new Lightstring connection
84 this.getNewId = function() { 102 this.getNewId = function() {
85 this.iqid++; 103 this.iqid++;
86 return 'sendiq:' + this.iqid; 104 return 'sendiq:' + this.iqid;
87 }; 105 };
88 this.on('stream:features', function(stanza, that) { 106 this.on('stream:features', function(stanza, that) {
89 var nodes = stanza.querySelectorAll('mechanism'); 107 var nodes = stanza.DOM.querySelectorAll('mechanism');
90 //SASL/Auth features 108 //SASL/Auth features
91 if (nodes.length > 0) { 109 if (nodes.length > 0) {
92 that.emit('mechanisms', stanza); 110 that.emit('mechanisms', stanza);
93 var mechanisms = {}; 111 var mechanisms = {};
94 for (var i = 0; i < nodes.length; i++) 112 for (var i = 0; i < nodes.length; i++)
123 "<iq type='set' xmlns='jabber:client'>" + 141 "<iq type='set' xmlns='jabber:client'>" +
124 "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>" + 142 "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>" +
125 (that.jid.resource? "<resource>" + that.jid.resource + "</resource>": "") + 143 (that.jid.resource? "<resource>" + that.jid.resource + "</resource>": "") +
126 "</bind>" + 144 "</bind>" +
127 "</iq>"; 145 "</iq>";
146
128 that.send( 147 that.send(
129 bind, 148 bind,
130 function(stanza) { 149 function(stanza) {
131 //Session http://xmpp.org/rfcs/rfc3921.html#session 150 //Session http://xmpp.org/rfcs/rfc3921.html#session
132 that.jid = new Lightstring.JID(stanza.textContent); 151 that.jid = new Lightstring.JID(stanza.DOM.textContent);
133 that.send( 152 that.send(
134 "<iq type='set' xmlns='jabber:client'>" + 153 "<iq type='set' xmlns='jabber:client'>" +
135 "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>" + 154 "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>" +
136 "</iq>", 155 "</iq>",
137 function() { 156 function() {
149 " xmlns:stream='http://etherx.jabber.org/streams'" + 168 " xmlns:stream='http://etherx.jabber.org/streams'" +
150 " version='1.0'/>" 169 " version='1.0'/>"
151 ); 170 );
152 }); 171 });
153 this.on('failure', function(stanza, that) { 172 this.on('failure', function(stanza, that) {
154 that.emit('conn-error', stanza.firstChild.tagName); 173 that.emit('conn-error', stanza.DOM.firstChild.tagName);
155 }); 174 });
156 this.on('challenge', function(stanza, that) { 175 this.on('challenge', function(stanza, that) {
157 //FIXME this is mostly Strophe code 176 //FIXME this is mostly Strophe code
158 177
159 function _quote(str) { 178 function _quote(str) {
160 return '"' + str.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"'; 179 return '"' + str.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
161 }; 180 };
162 181
163 var challenge = atob(stanza.textContent); 182 var challenge = atob(stanza.DOM.textContent);
164 183
165 var attribMatch = /([a-z]+)=("[^"]+"|[^,"]+)(?:,|$)/; 184 var attribMatch = /([a-z]+)=("[^"]+"|[^,"]+)(?:,|$)/;
166 185
167 var cnonce = MD5.hexdigest(Math.random() * 1234567890); 186 var cnonce = MD5.hexdigest(Math.random() * 1234567890);
168 var realm = ''; 187 var realm = '';
246 this.socket = new MozWebSocket(this.service, 'xmpp'); 265 this.socket = new MozWebSocket(this.service, 'xmpp');
247 } 266 }
248 267
249 var that = this; 268 var that = this;
250 this.socket.addEventListener('open', function() { 269 this.socket.addEventListener('open', function() {
251 if (this.protocol !== 'xmpp') 270 //TODO: if (this.protocol !== 'xmpp')
252 console.error('Lightstring: The server located at '+ that.service + ' doesn\'t seems to be XMPP aware.');
253 271
254 var stream = Lightstring.stanza.stream.open(that.jid.domain); 272 var stream = Lightstring.stanza.stream.open(that.jid.domain);
255 273 //TODO: Use Lightstring.Connection.send (problem with parsing steam);
256 that.socket.send(stream); 274 that.socket.send(stream);
257 that.emit('XMLOutput', stream); 275 var stanza = {
276 XML: stream
277 };
278 that.emit('output', stanza);
258 }); 279 });
259 this.socket.addEventListener('error', function(e) { 280 this.socket.addEventListener('error', function(e) {
260 that.emit('error', e.data); 281 that.emit('error', e.data);
261 console.log(e.data); 282 console.log(e.data);
262 }); 283 });
263 this.socket.addEventListener('close', function(e) { 284 this.socket.addEventListener('close', function(e) {
264 that.emit('disconnected', e.data); 285 that.emit('disconnected', e.data);
265 }); 286 });
266 this.socket.addEventListener('message', function(e) { 287 this.socket.addEventListener('message', function(e) {
267 that.emit('XMLInput', e.data); 288 var stanza = new Lightstring.Stanza(e.data);
268 var elm = Lightstring.xml2dom(e.data); 289
269 that.emit('DOMInput', elm); 290 //TODO node-xmpp-bosh sends a self-closing stream:stream tag; it is wrong!
270 that.emit(elm.tagName, elm); 291 that.emit('input', stanza);
271 292
272 if (elm.tagName === 'iq') { 293 if(!stanza.DOM)
273 var payload = elm.firstChild; 294 return;
295
296 that.emit(stanza.DOM.tagName, stanza);
297
298 if (stanza.DOM.tagName === 'iq') {
299 var payload = stanza.DOM.firstChild;
274 if (payload) 300 if (payload)
275 that.emit('iq/' + payload.namespaceURI + ':' + payload.localName, elm); 301 that.emit('iq/' + payload.namespaceURI + ':' + payload.localName, stanza);
276 that.emit(elm.getAttribute('id'), elm); //FIXME: possible attack vector. 302 that.emit(stanza.DOM.getAttribute('id'), stanza); //FIXME: possible attack vector.
277 } 303 }
278 }); 304 });
279 }, 305 },
280 /** 306 /**
281 * @function Send a message. 307 * @function Send a message.
282 * @param {String|Object} aStanza The message to send. 308 * @param {String|Object} aStanza The message to send.
283 * @param {Function} [aCallback] Executed on answer. (stanza must be iq) 309 * @param {Function} [aCallback] Executed on answer. (stanza must be iq)
284 */ 310 */
285 send: function(aStanza, aCallback) { 311 send: function(aStanza, aCallback) {
286 if (typeof aStanza === 'string') { 312 if (!(aStanza instanceof Lightstring.Stanza))
287 var str = aStanza; 313 var stanza = new Lightstring.Stanza(aStanza);
288 var elm = Lightstring.xml2dom(str); 314 else
289 } 315 var stanza = aStanza;
290 else if (aStanza instanceof Element) { 316
291 var elm = aStanza; 317 if(!stanza)
292 var str = this.dom2xml(elm);
293 }
294 else {
295 this.emit('error', 'Unsupported data type.');
296 return; 318 return;
297 } 319
298 320 if (stanza.DOM.tagName === 'iq') {
299 321 var id = stanza.DOM.getAttribute('id');
300 if (elm.tagName === 'iq') { 322 //TODO: This should be done by a plugin
301 var id = elm.getAttribute('id');
302 if (!id) { 323 if (!id) {
303 elm.setAttribute('id', this.getNewId()); 324 alert(Lightstring.DOM2XML(stanza.DOM));
304 str = Lightstring.dom2xml(elm); 325 stanza.DOM.setAttribute('id', this.getNewId());
305 } 326 }
306 if (aCallback) 327 if (aCallback)
307 this.on(elm.getAttribute('id'), aCallback); 328 this.on(stanza.DOM.getAttribute('id'), aCallback);
308 } 329 }
309 else if (aCallback) 330 else if (aCallback) {
310 this.emit('warning', 'Callback can\'t be called with non-iq stanza.'); 331 this.emit('warning', 'Callback can\'t be called with non-iq stanza.');
311 332 }
312 333
313 this.socket.send(str); 334
314 this.emit('XMLOutput', str); 335 //TODO this.socket.send(stanza.XML); (need some work on Lightstring.Stanza)
315 this.emit('DOMOutput', elm); 336 this.socket.send(Lightstring.DOM2XML(stanza.DOM));
337 this.emit('output', stanza);
316 }, 338 },
317 /** 339 /**
318 * @function Closes the XMPP stream and the socket. 340 * @function Closes the XMPP stream and the socket.
319 */ 341 */
320 disconnect: function() { 342 disconnect: function() {