/** 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");
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