Mercurial > eldonilo > lightstring
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() { |