/** Object: DOMObjects * This class contains builders for all the DOM objects needed by TrophyIM */ DOMObjects = { /** Function: xmlParse * Cross-browser alternative to using innerHTML * Parses given string, returns valid DOM HTML object * * Parameters: * (String) xml - the xml string to parse */ xmlParse : function(xmlString) { var xmlObj = this.xmlRender(xmlString); if(xmlObj) { try { //Firefox, Gecko, etc if (this.processor == undefined) { this.processor = new XSLTProcessor(); this.processor.importStylesheet(this.xmlRender( '\ \ ')); } var htmlObj = this.processor.transformToDocument(xmlObj).documentElement; //Safari has a quirk where it wraps dom elements in if (htmlObj.tagName.toLowerCase() == 'html') { htmlObj = htmlObj.firstChild.firstChild; } return document.importNode(htmlObj, true); } catch(e) { try { //IE is so very very special var htmlObj = document.importNode(xmlObj.documentElement, true); if (htmlObj.tagName.toLowerCase() == "div") { var div_wrapper = document.createElement('div'); div_wrapper.appendChild(htmlObj); if(div_wrapper.innerHTML) { div_wrapper.innerHTML = div_wrapper.innerHTML; } htmlObj = div_wrapper.firstChild; } return htmlObj; } catch(e) { alert("TrophyIM Error: Cannot add html to page " + e.message); } } } }, /** Function: xmlRender * Uses browser-specific methods to turn given string into xml object * * Parameters: * (String) xml - the xml string to parse */ xmlRender : function(xmlString) { try {//IE var renderObj = new ActiveXObject("Microsoft.XMLDOM"); renderObj.async="false"; if(xmlString) { renderObj.loadXML(xmlString); } } catch (e) { try { //Firefox, Gecko, etc if (this.parser == undefined) { this.parser = new DOMParser(); } var renderObj = this.parser.parseFromString(xmlString, "application/xml"); } catch(e) { alert("TrophyIM Error: Cannot create new html for page"); } } return renderObj; }, /** Function: getHTML * Returns named HTML snippet as DOM object * * Parameters: * (String) name - name of HTML snippet to retrieve (see HTMLSnippets * object) */ getHTML : function(page) { return this.xmlParse(HTMLSnippets[page]); }, /** Function: getScript * Returns script object with src to given script * * Parameters: * (String) script - name of script to put in src attribute of script * element */ getScript : function(script) { var newscript = document.createElement('script'); newscript.setAttribute('src', script); newscript.setAttribute('type', 'text/javascript'); return newscript; } }; /** Object: TrophyIM * * This is the actual TrophyIM application. It searches for the * 'trophyimclient' element and inserts itself into that. */ TrophyIM = { controll : { notificationNewUsers : 0 }, /** AutoConnection * */ autoConnection : { connect : true }, /** Active Chat Room * */ activeChatRoom : { name : [] }, /** Object: chatHistory * * Stores chat history (last 10 message) and current presence of active * chat tabs. Indexed by jid. */ chatHistory : {}, /** Constants: * * (Boolean) stale_roster - roster is stale and needs to be rewritten. */ constants : { stale_roster: false }, /** PosWindow * */ posWindow : { left : 400, top : 100 }, /** StatusConnection * */ statusConn : { connected : false }, /** TimeOut Render Roster * * */ _timeOut : { renderRoster : null }, /** Remove Contact ( type = set ) * * */ removeResult : { idResult : [] }, /** Function: setCookie * * Sets cookie name/value pair. Date and path are auto-selected. * * Parameters: * (String) name - the name of the cookie variable * (String) value - the value of the cookie variable */ setCookie : function(name, value) { var expire = new Date(); expire.setDate(expire.getDate() + 365); document.cookie = name + "=" + value + "; expires=" + expire.toGMTString(); }, /** Function: delCookie * * Deletes cookie * * Parameters: * (String) name) - the name of the cookie to delete */ delCookie : function(name) { var expire = new Date(); expire.setDate(expire.getDate() - 365); document.cookie = name + "= ; expires=" + expire.toGMTString(); delete TrophyIM.cookies[name]; }, /** Function: getCookies * * Retrieves all trophyim cookies into an indexed object. Inteneded to be * called once, at which time the app refers to the returned object instead * of re-parsing the cookie string every time. * * Each cookie is also re-applied so as to refresh the expiry date. */ getCookies : function() { var cObj = {}; var cookies = document.cookie.split(';'); for(var i = 0 ; i < cookies.length; i++ ) { while ( cookies[i].charAt(0) == ' ') { cookies[i] = cookies[i].substring(1,cookies[i].length); } if (cookies[i].substr(0, 8) == "trophyim") { var nvpair = cookies[i].split("=", 2); cObj[nvpair[0]] = nvpair[1]; TrophyIM.setCookie(nvpair[0], nvpair[1]); } } return cObj; }, /** Function: load * * This function searches for the trophyimclient div and loads the client * into it. */ load : function() { if( loadscript.getUserCurrent() == null ) { loadscript.setUserCurrent(); } if ( !TrophyIM.statusConn.connected ) { TrophyIM.cookies = TrophyIM.getCookies(); //Wait a second to give scripts time to load setTimeout( "TrophyIM.showLogin()", 550 ); } else { loadscript.rosterDiv(); } }, /** Function: storeData * * Store all our data in the JSONStore, if it is active */ storeData : function() { if ( TrophyIM.connection && TrophyIM.connection.connected ) { TrophyIM.setCookie('trophyim_bosh_xid', TrophyIM.connection.jid + "|" + TrophyIM.connection.sid + "|" + TrophyIM.connection.rid); TrophyIM.rosterObj.save(); } }, /** Function: showlogin * * This function clears out the IM box and either redisplays the login * page, or re-attaches to Strophe, preserving the logging div if it * exists, or creating a new one of we are re-attaching. */ showLogin : function() { /** * * JSON is the last script to load, so we wait on it * Added Strophe check too because of bug where it's sometimes missing * */ if ( typeof(JSON) != undefined && typeof(Strophe) != undefined ) { TrophyIM.JSONStore = new TrophyIMJSONStore(); if ( TrophyIM.JSONStore.store_working && TrophyIM.cookies['trophyim_bosh_xid'] ) { var xids = TrophyIM.cookies['trophyim_bosh_xid'].split("|"); TrophyIM.delCookie('trophyim_bosh_xid'); TrophyIM.constants.stale_roster = true; TrophyIM.connection = new Strophe.Connection(TROPHYIM_BOSH_SERVICE); TrophyIM.connection.rawInput = TrophyIM.rawInput; TrophyIM.connection.rawOutput = TrophyIM.rawOutput; //Strophe.log = TrophyIM.log; Strophe.info('Attempting Strophe attach.'); TrophyIM.connection.attach(xids[0], xids[1], xids[2], TrophyIM.onConnect); TrophyIM.onConnect(Strophe.Status.CONNECTED); } else { // List Contact loadscript.rosterDiv(); // Get User Current; var _getUserCurrent = null; _getUserCurrent = loadscript.getUserCurrent(); if( _getUserCurrent == null ) { setTimeout( "TrophyIM.showLogin()", 500 ); } else { TrophyIM.login( Base64.decode( _getUserCurrent.jid ), Base64.decode( _getUserCurrent.password )); } } } else { setTimeout("TrophyIM.showLogin()", 500); } }, /** Function: log * * This function logs the given message in the trophyimlog div * * Parameter: (String) msg - the message to log */ log : function(level, msg) { if (TrophyIM.logging_div && level >= TROPHYIM_LOGLEVEL) { while(TrophyIM.logging_div.childNodes.length > TROPHYIM_LOG_LINES) { TrophyIM.logging_div.removeChild( TrophyIM.logging_div.firstChild ); } var msg_div = document.createElement('div'); msg_div.className = 'trophyimlogitem'; msg_div.appendChild(document.createTextNode(msg)); TrophyIM.logging_div.appendChild(msg_div); TrophyIM.logging_div.scrollTop = TrophyIM.logging_div.scrollHeight; } }, /** Function: rawInput * * This logs the packets actually recieved by strophe at the debug level */ rawInput : function (data) { Strophe.debug("RECV: " + data); }, /** Function: rawInput * * This logs the packets actually recieved by strophe at the debug level */ rawOutput : function (data) { Strophe.debug("SEND: " + data); }, /** Function: login * * This function logs into server using information given on login page. * Since the login page is where the logging checkbox is, it makes or * removes the logging div and cookie accordingly. * */ login : function() { if ( TrophyIM.JSONStore.store_working ) { //In case they never logged out TrophyIM.JSONStore.delData(['groups','roster', 'active_chat', 'chat_history']); } TrophyIM.connection = new Strophe.Connection(TROPHYIM_BOSH_SERVICE); TrophyIM.connection.rawInput = TrophyIM.rawInput; TrophyIM.connection.rawOutput = TrophyIM.rawOutput; //Strophe.log = TrophyIM.log; if ( arguments.length > 0 ) { var barejid = arguments[0]; var password = arguments[1]; TrophyIM.connection.connect( barejid + TROPHYIM_RESOURCE, password, TrophyIM.onConnect ); } else { var barejid = document.getElementById('trophyimjid').value var fulljid = barejid + TROPHYIM_RESOURCE; var password = document.getElementById('trophyimpass').value; var button = document.getElementById('trophyimconnect'); loadscript.setUserCurrent( barejid, password); if ( button.value == 'connect' ) { button.value = 'disconnect'; //TrophyIM.connection.connect( fulljid , password, TrophyIM.onConnect ); TrophyIM.login( barejid, password ); _winBuild('window_login_page', 'remove'); } } TrophyIM.setCookie('trophyimjid', barejid); }, /** Function: logout * * Logs into fresh session through Strophe, purging any old data. */ logout : function() { TrophyIM.autoConnection.connect = false; TrophyIM.delCookie('trophyim_bosh_xid'); delete TrophyIM['cookies']['trophyim_bosh_xid']; TrophyIM.connection.disconnect(); }, /** Function onConnect * * Callback given to Strophe upon connection to BOSH proxy. */ onConnect : function(status) { var loading_gif = document.getElementById("JabberIMRosterLoadingGif"); if( status == Strophe.Status.CONNECTING ) { loading_gif.style.display = "block"; Strophe.info('Strophe is connecting.'); } if( status == Strophe.Status.CONNFAIL ) { TrophyIM.delCookie('trophyim_bosh_xid'); TrophyIM.statusConn.connected = false; loading_gif.style.display = "block"; } if( status == Strophe.Status.DISCONNECTING ) { TrophyIM.statusConn.connected = false; } if( status == Strophe.Status.DISCONNECTED ) { if( TrophyIM.autoConnection.connect ) { loading_gif.style.display = "block"; TrophyIM.delCookie('trophyim_bosh_xid'); TrophyIM.statusConn.connected = false; setTimeout(function() { TrophyIM.showLogin(); },10000); loadscript.clrAllContacts(); loadscript.setStatusJabber(i18n.STATUS_ANAVAILABLE,"unavailable"); delete TrophyIM.rosterObj.roster; delete TrophyIM.rosterObj.groups; } } if( status == Strophe.Status.CONNECTED ) { loadscript.setStatusJabber(i18n.STATUS_AVAILABLE,'available'); TrophyIM.statusConn.connected = true; TrophyIM.showClient(); } }, /** Function: showClient * * This clears out the main div and puts in the main client. It also * registers all the handlers for Strophe to call in the client. */ showClient : function() { TrophyIM.setCookie('trophyim_bosh_xid', TrophyIM.connection.jid + "|" + TrophyIM.connection.sid + "|" + TrophyIM.connection.rid); TrophyIM.rosterObj = new TrophyIMRoster(); TrophyIM.connection.addHandler(TrophyIM.onVersion, Strophe.NS.VERSION, 'iq', null, null, null); TrophyIM.connection.addHandler(TrophyIM.onRoster, Strophe.NS.ROSTER, 'iq', null, null, null); TrophyIM.connection.addHandler(TrophyIM.onPresence, null, 'presence', null, null, null); TrophyIM.connection.addHandler(TrophyIM.onMessage, null, 'message', null, null, null); //Get roster then announce presence. TrophyIM.connection.send($iq({ type: 'get', xmlns: Strophe.NS.CLIENT }).c('query', { xmlns: Strophe.NS.ROSTER }).tree()); TrophyIM.connection.send($pres().tree()); setTimeout( TrophyIM.renderRoster, 1000); }, /** Function: clearClient * * Clears out client div, preserving and returning existing logging_div if * one exists */ clearClient : function() { if(TrophyIM.logging_div) { var logging_div = TrophyIM.client_div.removeChild(document.getElementById('trophyimlog')); } else { var logging_div = null; } while(TrophyIM.client_div.childNodes.length > 0) { TrophyIM.client_div.removeChild(TrophyIM.client_div.firstChild); } return logging_div; }, /** Function: onVersion * * jabber:iq:version query handler */ onVersion : function(msg) { Strophe.debug("Version handler"); if (msg.getAttribute('type') == 'get') { var from = msg.getAttribute('from'); var to = msg.getAttribute('to'); var id = msg.getAttribute('id'); var reply = $iq({ type: 'result', to: from, from: to, id: id }).c('query', { name: "TrophyIM", version: TROPHYIM_VERSION, os: "Javascript-capable browser" }); TrophyIM.connection.send(reply.tree()); } return true; }, /** Function: onRoster * * Roster iq handler */ onRoster : function(msg) { var roster_items = msg.firstChild.getElementsByTagName('item'); for (var i = 0; i < roster_items.length; i++) { with(roster_items[i]) { var groups = getElementsByTagName('group'); var group_array = []; for( var g = 0 ; g < groups.length; g++ ) { if( groups[g].hasChildNodes() ) group_array[group_array.length] = groups[g].firstChild.nodeValue; } if( getAttribute('ask') && getAttribute('ask').toString() === "subscribe" ) { if( getAttribute('subscription').toString() === "none" ) { TrophyIM.rosterObj.addContact( getAttribute('jid'), getAttribute('ask'), getAttribute('name'), group_array ); } if( getAttribute('subscription').toString() === "remove" ) { TrophyIM.rosterObj.removeContact( getAttribute('jid').toString() ); } } else { if( ( getAttribute('ask') == null && getAttribute('subscription').toString() === "remove" ) || getAttribute('subscription').toString() === "remove" ) { TrophyIM.rosterObj.removeContact( getAttribute('jid').toString() ); } else { TrophyIM.rosterObj.addContact( getAttribute('jid'), getAttribute('subscription'), getAttribute('name'), group_array ); } } } } if ( msg.getAttribute('type') == 'set' ) { var _iq = $iq({ type: 'reply', id: msg.getAttribute('id'), to: msg.getAttribute('from') }); TrophyIM.connection.send( _iq.tree()); } return true; }, /** Function: onPresence * * Presence Handler */ onPresence : function(msg) { // Get Presences ChatRoom TrophyIM.onPresenceChatRoom( msg ); var type = msg.getAttribute('type') ? msg.getAttribute('type') : 'available'; var show = msg.getElementsByTagName('show').length ? Strophe.getText(msg.getElementsByTagName('show')[0]) : type; var status = msg.getElementsByTagName('status').length ? Strophe.getText(msg.getElementsByTagName('status')[0]) : ''; var priority = msg.getElementsByTagName('priority').length ? parseInt(Strophe.getText(msg.getElementsByTagName('priority')[0])) : 0; if( msg.getAttribute('from').toString().indexOf( TROPHYIM_CHATROOM ) < 0 ) { var _from = Strophe.getBareJidFromJid( msg.getAttribute('from') ); var _flag = true; if( TrophyIM.removeResult.idResult.length > 0 ) { for( var i = 0 ; i < TrophyIM.removeResult.idResult.length; i++ ) { if( TrophyIM.removeResult.idResult[i] == _from ) { _flag = false; TrophyIM.removeResult.idResult.splice(i,1); i--; if( show.toLowerCase() === 'subscribe' ) _flag = true; } } } if( _flag ) TrophyIM.rosterObj.setPresence( msg.getAttribute('from'), priority, show, status ); } return true; }, /** Function : onPresenceChatRoom * * Presence ChatRoom Handler */ onPresenceChatRoom : function(msg) { var xquery = msg.getElementsByTagName("x"); var _error = msg.getElementsByTagName("error"); if( _error.length > 0 ) { /* Room creation is denied by service policy; * * * * Room creation is denied by service policy * */ for ( var i = 0; i < _error.length; i++ ) { if ( _error[i].getElementsByTagName("text") ) { var _errorMsg = Strophe.getText( _error[i].getElementsByTagName("text")[0] ); if( _errorMsg == "Room creation is denied by service policy" ) { alert( i18n.ROOM_CREATION_IS_DENIED_BY_SERVICE_POLICY ); } else { alert( " Informe ao seu Administrador ERRO : \n" + _errorMsg ); } } } } else { if ( xquery.length > 0 ) { for ( var i = 0; i < xquery.length; i++ ) { var xmlns = xquery[i].getAttribute("xmlns"); if( xmlns.indexOf("http://jabber.org/protocol/muc#user") == 0 ) { var _from = xquery[i].parentNode.getAttribute('from'); var _to = xquery[i].parentNode.getAttribute('to'); // Get NameChatRoom var nameChatRoom = Strophe.getBareJidFromJid( _from ); // Get nickName var nickName = Strophe.getResourceFromJid( _from ); // Get Type/Show var type = ( xquery[i].parentNode.getAttribute('type') != null ) ? xquery[i].parentNode.getAttribute('type') : 'available' ; var show = ( xquery[i].parentNode.firstChild.nodeName == "show" ) ? xquery[i].parentNode.firstChild.firstChild.nodeValue : type; var _idElement = nameChatRoom + "_UserChatRoom__" + nickName; var _UserChatRoom = document.createElement("div"); _UserChatRoom.id = _idElement; _UserChatRoom.style.paddingLeft = '18px'; _UserChatRoom.style.margin = '3px 0px 0px 2px'; _UserChatRoom.style.background = 'url("'+path_jabberit+'templates/default/images/' + show + '.gif") no-repeat center left'; _UserChatRoom.appendChild( document.createTextNode( nickName ) ); var nodeUser = document.getElementById( _idElement ); if( nodeUser == null ) { if( document.getElementById( nameChatRoom + '__roomChat__participants' ) != null ) { nameChatRoom = document.getElementById( nameChatRoom + '__roomChat__participants' ); nameChatRoom.appendChild( _UserChatRoom ); } else { if( type != 'unavailable' ) { TrophyIM.makeChatRoom( nameChatRoom, nameChatRoom.substring(0, nameChatRoom.indexOf('@'))); nameChatRoom = document.getElementById( nameChatRoom + '__roomChat__participants' ); nameChatRoom.appendChild( _UserChatRoom ); } } } else { if( type == 'unavailable' ) { nodeUser.parentNode.removeChild( nodeUser ); } else if( show ) { nodeUser.style.backgroundImage = 'url("'+path_jabberit+'templates/default/images/' + show + '.gif")'; } } } } } } }, /** Function: onMessage * * Message handler */ onMessage : function(msg) { var checkTime = function(i) { if ( i < 10 ) i= "0" + i; return i; }; var messageDate = function( _date ) { var _dt = _date.substr( 0, _date.indexOf( 'T' ) ).split( '-' ); var _hr = _date.substr( _date.indexOf( 'T' ) + 1, _date.length - _date.indexOf( 'T' ) - 2 ).split( ':' ); ( _date = new Date ).setTime( Date.UTC( _dt[0], _dt[1] - 1, _dt[2], _hr[0], _hr[1], _hr[2] ) ); return ( _date.toLocaleDateString( ).replace( /-/g, '/' ) + ' ' + _date.toLocaleTimeString( ) ); }; var data = new Date(); var dtNow = checkTime(data.getHours()) + ":" + checkTime(data.getMinutes()) + ":" + checkTime(data.getSeconds()); var from = msg.getAttribute('from'); var type = msg.getAttribute('type'); var elems = msg.getElementsByTagName('body'); var delay = ( msg.getElementsByTagName('delay') ) ? msg.getElementsByTagName('delay') : null; var stamp = ( delay[0] != null ) ? "" + messageDate(delay[0].getAttribute('stamp')) + "" : dtNow; var barejid = Strophe.getBareJidFromJid(from); var jidChatRoom = Strophe.getResourceFromJid(from); var jid_lower = barejid.toLowerCase(); var contact = ""; var state = ""; var chatBox = document.getElementById(jid_lower + "__chatState"); var chatStateOnOff = null; var active = msg.getElementsByTagName('active'); contact = barejid.toLowerCase(); contact = contact.substring(0, contact.indexOf('@')); if( TrophyIM.rosterObj.roster[barejid] ) { if( TrophyIM.rosterObj.roster[barejid.toLowerCase()]['contact']['name'] ) { contact = TrophyIM.rosterObj.roster[barejid.toLowerCase()]['contact']['name']; } } // Message with body are "content message", this means state active if ( elems.length > 0 ) { state = ""; // Set notify chat state capability on when sender notify it themself chatStateOnOff = document.getElementById(jid_lower + "__chatStateOnOff"); if (active.length > 0 & chatStateOnOff != null ) { chatStateOnOff.value = 'on'; } // Get Message var _message = document.createElement("div"); var _text = Strophe.getText( elems[0] ); // Events Javascript _text = _text.replace(/onblur/gi,"EVENT_DENY"); _text = _text.replace(/onchange/gi,"EVENT_DENY"); _text = _text.replace(/onclick/gi,"EVENT_DENY"); _text = _text.replace(/ondblclick/gi,"EVENT_DENY"); _text = _text.replace(/onerror/gi,"EVENT_DENY"); _text = _text.replace(/onfocus/gi,"EVENT_DENY"); _text = _text.replace(/onkeydown/gi,"EVENT_DENY"); _text = _text.replace(/onkeypress/gi,"EVENT_DENY"); _text = _text.replace(/onkeyup/gi,"EVENT_DENY"); _text = _text.replace(/onmousedown/gi,"EVENT_DENY"); _text = _text.replace(/onmousemove/gi,"EVENT_DENY"); _text = _text.replace(/onmouseout/gi,"EVENT_DENY"); _text = _text.replace(/onmouseover/gi,"EVENT_DENY"); _text = _text.replace(/onmouseup/gi,"EVENT_DENY"); _text = _text.replace(/onresize/gi,"EVENT_DENY"); _text = _text.replace(/onselect/gi,"EVENT_DENY"); _text = _text.replace(/onunload/gi,"EVENT_DENY"); // Events CSS _text = _text.replace(/style/gi,"EVENT_DENY"); // Tags HTML _text = _text.replace(/img /gi,"IMG_DENY "); _text = _text.replace(/script /gi,"SCRIPT_DENY "); _text = _text.replace(/div /gi,"DIV_DENY "); _text = _text.replace(/span /gi,"SPAN_DENY "); _text = _text.replace(/iframe /gi,"IFRAME_DENY "); _message.innerHTML = _text; ////////// BEGIN XSS ////////////////////////////////////////////////// // Delete Tags