# HG changeset patch # User Sonny Piers # Date 1327721670 -3600 # Node ID 1e6d2ca2daae5eb718c8f18cd201330f7b7c157d # Parent 630b9579fe4a722cc251b334052d172003b6d18b Adds a Lightstring.Stanza object and use it. diff --git a/lightstring.js b/lightstring.js --- a/lightstring.js +++ b/lightstring.js @@ -58,16 +58,34 @@ var Lightstring = { * @param {String} aString XML string. * @return {Object} Domified XML. */ - xml2dom: function(aString) { - return this.parser.parseFromString(aString, 'text/xml').documentElement; + XML2DOM: function(aString) { + var DOM = null; + try { + DOM = this.parser.parseFromString(aString, 'text/xml').documentElement; + } + catch (e) { + alert(e); + } + finally { + return DOM; + }; }, /** * @function Transforms a DOM object to a XML string. * @param {Object} aString DOM object. * @return {String} Stringified DOM. */ - dom2xml: function(aElement) { - return this.serializer.serializeToString(aElement); + DOM2XML: function(aElement) { + var XML = null; + try { + XML = this.serializer.serializeToString(aElement); + } + catch (e) { + alert(e); + } + finally { + return XML; + }; } }; @@ -86,7 +104,7 @@ Lightstring.Connection = function(aServi return 'sendiq:' + this.iqid; }; this.on('stream:features', function(stanza, that) { - var nodes = stanza.querySelectorAll('mechanism'); + var nodes = stanza.DOM.querySelectorAll('mechanism'); //SASL/Auth features if (nodes.length > 0) { that.emit('mechanisms', stanza); @@ -125,11 +143,12 @@ Lightstring.Connection = function(aServi (that.jid.resource? "" + that.jid.resource + "": "") + "" + ""; + that.send( bind, function(stanza) { //Session http://xmpp.org/rfcs/rfc3921.html#session - that.jid = new Lightstring.JID(stanza.textContent); + that.jid = new Lightstring.JID(stanza.DOM.textContent); that.send( "" + "" + @@ -151,7 +170,7 @@ Lightstring.Connection = function(aServi ); }); this.on('failure', function(stanza, that) { - that.emit('conn-error', stanza.firstChild.tagName); + that.emit('conn-error', stanza.DOM.firstChild.tagName); }); this.on('challenge', function(stanza, that) { //FIXME this is mostly Strophe code @@ -160,7 +179,7 @@ Lightstring.Connection = function(aServi return '"' + str.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"'; }; - var challenge = atob(stanza.textContent); + var challenge = atob(stanza.DOM.textContent); var attribMatch = /([a-z]+)=("[^"]+"|[^,"]+)(?:,|$)/; @@ -248,13 +267,15 @@ Lightstring.Connection.prototype = { var that = this; this.socket.addEventListener('open', function() { - if (this.protocol !== 'xmpp') - console.error('Lightstring: The server located at '+ that.service + ' doesn\'t seems to be XMPP aware.'); + //TODO: if (this.protocol !== 'xmpp') var stream = Lightstring.stanza.stream.open(that.jid.domain); - + //TODO: Use Lightstring.Connection.send (problem with parsing steam); that.socket.send(stream); - that.emit('XMLOutput', stream); + var stanza = { + XML: stream + }; + that.emit('output', stanza); }); this.socket.addEventListener('error', function(e) { that.emit('error', e.data); @@ -264,16 +285,21 @@ Lightstring.Connection.prototype = { that.emit('disconnected', e.data); }); this.socket.addEventListener('message', function(e) { - that.emit('XMLInput', e.data); - var elm = Lightstring.xml2dom(e.data); - that.emit('DOMInput', elm); - that.emit(elm.tagName, elm); + var stanza = new Lightstring.Stanza(e.data); - if (elm.tagName === 'iq') { - var payload = elm.firstChild; + //TODO node-xmpp-bosh sends a self-closing stream:stream tag; it is wrong! + that.emit('input', stanza); + + if(!stanza.DOM) + return; + + that.emit(stanza.DOM.tagName, stanza); + + if (stanza.DOM.tagName === 'iq') { + var payload = stanza.DOM.firstChild; if (payload) - that.emit('iq/' + payload.namespaceURI + ':' + payload.localName, elm); - that.emit(elm.getAttribute('id'), elm); //FIXME: possible attack vector. + that.emit('iq/' + payload.namespaceURI + ':' + payload.localName, stanza); + that.emit(stanza.DOM.getAttribute('id'), stanza); //FIXME: possible attack vector. } }); }, @@ -283,36 +309,32 @@ Lightstring.Connection.prototype = { * @param {Function} [aCallback] Executed on answer. (stanza must be iq) */ send: function(aStanza, aCallback) { - if (typeof aStanza === 'string') { - var str = aStanza; - var elm = Lightstring.xml2dom(str); + if (!(aStanza instanceof Lightstring.Stanza)) + var stanza = new Lightstring.Stanza(aStanza); + else + var stanza = aStanza; + + if(!stanza) + return; + + if (stanza.DOM.tagName === 'iq') { + var id = stanza.DOM.getAttribute('id'); + //TODO: This should be done by a plugin + if (!id) { + alert(Lightstring.DOM2XML(stanza.DOM)); + stanza.DOM.setAttribute('id', this.getNewId()); + } + if (aCallback) + this.on(stanza.DOM.getAttribute('id'), aCallback); } - else if (aStanza instanceof Element) { - var elm = aStanza; - var str = this.dom2xml(elm); - } - else { - this.emit('error', 'Unsupported data type.'); - return; + else if (aCallback) { + this.emit('warning', 'Callback can\'t be called with non-iq stanza.'); } - if (elm.tagName === 'iq') { - var id = elm.getAttribute('id'); - if (!id) { - elm.setAttribute('id', this.getNewId()); - str = Lightstring.dom2xml(elm); - } - if (aCallback) - this.on(elm.getAttribute('id'), aCallback); - } - else if (aCallback) - this.emit('warning', 'Callback can\'t be called with non-iq stanza.'); - - - this.socket.send(str); - this.emit('XMLOutput', str); - this.emit('DOMOutput', elm); + //TODO this.socket.send(stanza.XML); (need some work on Lightstring.Stanza) + this.socket.send(Lightstring.DOM2XML(stanza.DOM)); + this.emit('output', stanza); }, /** * @function Closes the XMPP stream and the socket. diff --git a/stanza.js b/stanza.js new file mode 100644 --- /dev/null +++ b/stanza.js @@ -0,0 +1,38 @@ +'use strict'; + +/** + Copyright (c) 2011, Sonny Piers + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + + +/** + * @constructor Creates a new Stanza object. + * @param {String|Object} [aStanza] The XML or DOM content of the stanza + * @memberOf Lightstring + */ +Lightstring.Stanza = function(aStanza) { + if (typeof aStanza === 'string') { + this.XML = aStanza; + this.DOM = Lightstring.XML2DOM(this.XML); + } + else if (aStanza instanceof Element) { + this.DOM = aStanza; + this.XML = Lightstring.DOM2XML(this.DOM); + } + //ToDo error ? + else { + return null; + } +};