/* Jappix - An open social platform These are the connection JS script for Jappix ------------------------------------------------- License: AGPL Authors: Valérian Saliou, Maranda */ // Bundle var Connection = (function () { /** * Alias of this * @private */ var self = {}; /* Variables */ self.current_session = false; self.desktop_hash = null; self.connected = false; self.reconnect_try = 0; self.reconnect_timer = 0; self.resume = false; /** * Does the user login * @public * @param {string} lNick * @param {string} lServer * @param {string} lPass * @param {string} lResource * @param {number} lPriority * @param {boolean} lRemember * @param {object} loginOpts * @return {boolean} */ self.doLogin = function(lNick, lServer, lPass, lResource, lPriority, lRemember, loginOpts) { try { // get optionnal conn handlers oExtend = loginOpts || {}; // We remove the not completed class to avoid problems $('#home .loginer input').removeClass('please-complete'); // We add the login wait div Interface.showGeneralWait(); if(Common.hasWebSocket()) { // WebSocket supported & configured con = new JSJaCWebSocketConnection({ httpbase: HOST_WEBSOCKET }); } else { var httpbase = (HOST_BOSH_MAIN || HOST_BOSH); // Check BOSH origin BOSH_SAME_ORIGIN = Origin.isSame(httpbase); // We create the new http-binding connection con = new JSJaCHttpBindingConnection({ httpbase: httpbase }); } // And we handle everything that happen self.setupCon(con, oExtend); // Generate a resource var random_resource = DataStore.getDB(self.desktop_hash, 'session', 'resource'); if(!random_resource) { random_resource = lResource + ' (' + (new Date()).getTime() + ')'; } // We retrieve what the user typed in the login inputs oArgs = {}; oArgs.domain = $.trim(lServer); oArgs.username = $.trim(lNick); oArgs.resource = random_resource; oArgs.pass = lPass; oArgs.secure = true; oArgs.xmllang = XML_LANG; self.desktop_hash = 'jd.' + hex_md5(oArgs.username + '@' + oArgs.domain); // Store the resource (for reconnection) DataStore.setDB(self.desktop_hash, 'session', 'resource', random_resource); // Store session XML in temporary database self.storeSession(lNick, lServer, lPass, lResource, lPriority, lRemember); // We store the infos of the user into the data-base DataStore.setDB(self.desktop_hash, 'priority', 1, lPriority); // We connect ! con.connect(oArgs); // Change the page title Interface.title('wait'); Console.info('Jappix is connecting...'); } catch(e) { Console.error('Connection.doLogin', e); // Reset Jappix Talk.destroy(); // Open an unknown error Board.openThisError(2); } finally { return false; } }; /** * Handles the user registration * @public * @return {undefined} */ self.handleRegistered = function() { try { Console.info('A new account has been registered.'); // We remove the waiting image Interface.removeGeneralWait(); // Reset the title Interface.title('home'); // We show the success information $('#home .registerer .success').fadeIn('fast'); // We quit the session if(Common.isConnected()) { self.logout(); } } catch(e) { Console.error('Connection.handleRegistered', e); } }; /** * Does the user registration * @public * @param {string} username * @param {string} domain * @param {string} pass * @param {string} captcha * @return {boolean} */ self.doRegister = function(username, domain, pass, captcha) { try { Console.info('Trying to register an account...'); // We change the registered information text $('#home .homediv.registerer').append( '
' + Common._e("You have been registered, here is your XMPP address:") + ' ' + username.htmlEnc() + '@' + domain.htmlEnc() + ' - ' + Common._e("Login") + '' + '
' ); // Login link $('#home .homediv.registerer .success a').click(function() { return self.doLogin(username, domain, pass, '', '10', false); }); if((REGISTER_API == 'on') && (domain == HOST_MAIN) && captcha) { // Show the waiting image Interface.showGeneralWait(); // Change the page title Interface.title('wait'); // Send request $.post('./server/register.php', {username: username, domain: domain, password: pass, captcha: captcha}, function(data) { // Error registering Interface.removeGeneralWait(); Interface.title('home'); // In all case, update CAPTCHA $('#home img.captcha_img').attr('src', './server/captcha.php?id=' + genID()); $('#home input.captcha').val(''); // Registration okay if($(data).find('query status').text() == '1') { self.handleRegistered(); } else { // Show error message var error_message = ''; switch($(data).find('query message').text()) { case 'CAPTCHA Not Matching': error_message = Common._e("The security code you entered is invalid. Please retry with another one."); $('#home input.captcha').focus(); break; case 'Username Unavailable': error_message = Common._e("The username you picked is not available. Please try another one."); $('#home input.nick').focus(); break; default: error_message = Common._e("There was an error registering your account. Please retry."); break; } if(error_message) Errors.show('', error_message, ''); } }); } else { try { oArgs = {}; if(Common.hasWebSocket()) { // WebSocket supported & configured con = new JSJaCWebSocketConnection({ httpbase: HOST_WEBSOCKET }); } else { var httpbase = (HOST_BOSH_MAIN || HOST_BOSH); // Check BOSH origin BOSH_SAME_ORIGIN = Origin.isSame(httpbase); // We create the new http-binding connection con = new JSJaCHttpBindingConnection({ httpbase: httpbase }); } // We setup the connection ! con.registerHandler('onconnect', self.handleRegistered); con.registerHandler('onerror', Errors.handle); // We retrieve what the user typed in the register inputs oArgs = {}; oArgs.domain = $.trim(domain); oArgs.username = $.trim(username); oArgs.resource = JAPPIX_RESOURCE + ' Register (' + (new Date()).getTime() + ')'; oArgs.pass = pass; oArgs.register = true; oArgs.secure = true; oArgs.xmllang = XML_LANG; con.connect(oArgs); // Show the waiting image Interface.showGeneralWait(); // Change the page title Interface.title('wait'); } catch(e) { // Logs errors Console.error('doRegister', e); } } } catch(e) { Console.error('Connection.doRegister', e); } finally { return false; } }; /** * Does the user anonymous login * @public * @return {boolean} */ self.doAnonymous = function() { try { Console.info('Trying to login anonymously...'); var aPath = '#home .anonymouser '; var room = $(aPath + '.room').val(); var nick = $(aPath + '.nick').val(); // If the form is correctly completed if(room && nick) { // We remove the not completed class to avoid problems $('#home .anonymouser input').removeClass('please-complete'); // Redirect the user to the anonymous room window.location.href = JAPPIX_LOCATION + '?r=' + room + '&n=' + nick; } // We check if the form is entirely completed else { $(aPath + 'input[type="text"]').each(function() { var select = $(this); if(!select.val()) $(document).oneTime(10, function() { select.addClass('please-complete').focus(); }); else select.removeClass('please-complete'); }); } } catch(e) { Console.error('Connection.doAnonymous', e); } finally { return false; } }; /** * Handles the user connected event * @public * @return {undefined} */ self.handleConnected = function() { try { Console.info('Jappix is now connected.'); // Connection markers self.connected = true; self.reconnect_try = 0; self.reconnect_timer = 0; // We hide the home page $('#home').hide(); // Any suggest to do before triggering connected event? Groupchat.suggestCheck(); // Remove the waiting item Interface.removeGeneralWait(); // Init Jingle Jingle.init(); } catch(e) { Console.error('Connection.handleConnected', e); } }; /** * Triggers the connected state * @public * @return {undefined} */ self.triggerConnected = function() { try { // Not resumed? if(!self.resume) { // Remember the session? if(DataStore.getDB(self.desktop_hash, 'remember', 'session')) DataStore.setPersistent('global', 'session', 1, self.current_session); // We show the chatting app. Talk.create(); // We reset the homepage Home.change('default'); // We get all the other things self.getEverything(); // Set last activity stamp DateUtils.last_activity = DateUtils.getTimeStamp(); } // Resumed else { // Send our presence Presence.sendActions(); // Change the title Interface.updateTitle(); } } catch(e) { Console.error('Connection.triggerConnected', e); } }; /** * Handles the user disconnected event * @public * @return {undefined} */ self.handleDisconnected = function() { try { Console.info('Jappix is now disconnected.'); // Normal disconnection if(!self.current_session && !self.connected) { Talk.destroy(); self.desktop_hash = null; } } catch(e) { Console.error('Connection.handleDisconnected', e); } }; /** * Setups the normal connection * @public * @param {object} con * @param {object} oExtend * @return {undefined} */ self.setupCon = function(con, oExtend) { try { // Setup connection handlers con.registerHandler('message', Message.handle); con.registerHandler('presence', Presence.handle); con.registerHandler('iq', IQ.handle); con.registerHandler('onconnect', self.handleConnected); con.registerHandler('onerror', Errors.handle); con.registerHandler('ondisconnect', self.handleDisconnected); // Extended handlers oExtend = oExtend || {}; jQuery.each(oExtend, function(keywd,funct) { con.registerHandler(keywd, funct); }); } catch(e) { Console.error('Connection.setupCon', e); } }; /** * Logouts from the server * @public * @return {boolean} */ self.logout = function() { logout_done = false; try { if(Common.isConnected()) { Console.info('Jappix is disconnecting...'); // Disconnect from the XMPP server con.disconnect(); logout_done = true; } } catch(e) { Console.error('Connection.logout', e); } finally { return logout_done; } }; /** * Terminates the user session * @public * @return {undefined} */ self.terminate = function() { try { if(Common.isConnected()) { // Clear temporary session storage self.resetConMarkers(); // Show the waiting item (useful if BOSH is sloooow) Interface.showGeneralWait(); // Change the page title Interface.title('wait'); // Disconnect from the XMPP server self.logout(); } } catch(e) { Console.error('Connection.terminate', e); } }; /** * Quits a session * @public * @param {type} name * @return {undefined} */ self.quit = function() { try { if(!Common.isConnected()) { return; } // We show the waiting image Interface.showGeneralWait(); // Change the page title Interface.title('wait'); // We disconnect from the XMPP server self.logout(); } catch(e) { Console.error('Connection.quit', e); } }; /** * Creates the reconnect pane * @public * @param {string} mode * @return {undefined} */ self.createReconnect = function(mode) { try { Console.error('This is not a normal disconnection, show the reconnect pane...'); // Reconnect pane not yet displayed? if(!Common.exists('#reconnect')) { // Blur the focused input/textarea/select $('input, select, textarea').blur(); // Create the HTML code var html = '
' + '
' + Common._e("Due to a network issue, you were disconnected. What do you want to do now?"); // Can we cancel reconnection? if(mode == 'normal') html += '' + Common._e("Cancel") + ''; html += '' + Common._e("Reconnect") + '' + '
'; // Append the code $('body').append(html); // Click events if(mode == 'normal') $('#reconnect a.finish.cancel').click(function() { return self.cancelReconnect(); }); $('#reconnect a.finish.reconnect').click(function() { return self.acceptReconnect(mode); }); // Try to reconnect automatically after a while if(self.reconnect_try < 5) self.reconnect_timer = 5 + (5 * self.reconnect_try); else self.reconnect_timer = 120; // Change the try number self.reconnect_try++; // Fire the event! $('#reconnect a.finish.reconnect').everyTime('1s', function() { // We can reconnect! if(self.reconnect_timer === 0) return self.acceptReconnect(mode); // Button text if(self.reconnect_timer <= 10) $(this).text(Common._e("Reconnect") + ' (' + self.reconnect_timer + ')'); // Remove 1 second self.reconnect_timer--; }); // Page title Interface.updateTitle(); } } catch(e) { Console.error('Connection.createReconnect', e); } }; /** * Reconnects the user if he was disconnected (network issue) * @public * @param {string} mode * @return {boolean} */ self.acceptReconnect = function(mode) { try { Console.info('Trying to reconnect the user...'); // Resume marker self.resume = true; // Show waiting item Interface.showGeneralWait(); // Reset some various stuffs var groupchats = '#page-engine .page-engine-chan[data-type="groupchat"]'; $(groupchats + ' .list .role').hide(); $(groupchats + ' .one-group, ' + groupchats + ' .list .user').remove(); $(groupchats).attr('data-initial', 'false'); // Stop the timer $('#reconnect a.finish.reconnect').stopTime(); // Remove the reconnect pane $('#reconnect').remove(); // Try to login again if(mode == 'normal') self.loginFromSession(Common.XMLFromString(self.current_session)); else if(mode == 'anonymous') Anonymous.login(HOST_ANONYMOUS); } catch(e) { Console.error('Connection.acceptReconnect', e); } finally { return false; } }; /** * Cancel the reconnection of user account (network issue) * @public * @return {boolean} */ self.cancelReconnect = function() { try { Console.info('User has canceled automatic reconnection...'); // Stop the timer $('#reconnect a.finish.reconnect').stopTime(); // Remove the reconnect pane $('#reconnect').remove(); // Destroy the talk page Talk.destroy(); // Renitialize the previous session parameters self.resetConMarkers(); } catch(e) { Console.error('Connection.cancelReconnect', e); } finally { return false; } }; /** * Clears session reminder database * @public * @return {undefined} */ self.clearLastSession = function() { try { // Clear temporary storage self.resetConMarkers(); // Clear persistent storage if($(Common.XMLFromString(DataStore.getPersistent('global', 'session', 1))).find('stored').text() == 'true') { DataStore.removePersistent('global', 'session', 1); } } catch(e) { Console.error('Connection.clearLastSession', e); } }; /** * Resets the connection markers * @public * @return {undefined} */ self.resetConMarkers = function() { try { self.current_session = false; self.connected = false; self.resume = false; self.reconnect_try = 0; self.reconnect_timer = 0; } catch(e) { Console.error('Connection.resetConMarkers', e); } }; /** * Logins from a saved session * @public * @param {string} data * @return {undefined} */ self.loginFromSession = function(data) { try { // Select the data var session = $(data); // Fire the login event self.doLogin( session.find('username').text(), session.find('domain').text(), session.find('password').text(), session.find('resource').text(), session.find('priority').text(), false ); } catch(e) { Console.error('Connection.loginFromSession', e); } }; /** * Quits a session normally * @public * @return {boolean} */ self.normalQuit = function() { try { // Reset our database self.clearLastSession(); // We quit the current session self.quit(); // We show an info Board.openThisInfo(3); } catch(e) { Console.error('Connection.normalQuit', e); } finally { return false; } }; /** * Gets all the users stuff * @public * @return {undefined} */ self.getEverything = function() { try { Features.get(); Roster.get(); Privacy.list(); Storage.get(NS_ROSTERNOTES); } catch(e) { Console.error('Connection.getEverything', e); } }; /** * Generates session data to store * @public * @param {string} lNick * @param {string} lServer * @param {string} lPass * @param {string} lResource * @param {number} lPriority * @param {boolean} lRemember * @return {undefined} */ self.storeSession = function(lNick, lServer, lPass, lResource, lPriority, lRemember) { try { // Generate a session XML to be stored session_xml = 'true' + lServer.htmlEnc() + '' + lNick.htmlEnc() + '' + lResource.htmlEnc() + '' + lPass.htmlEnc() + '' + lPriority.htmlEnc() + ''; // Save the session parameters (for reconnect if network issue) self.current_session = session_xml; // Remember me? if(lRemember) { DataStore.setDB(self.desktop_hash, 'remember', 'session', 1); } return session_xml; } catch(e) { Console.error('Connection.storeSession', e); } }; /** * Plugin launcher * @public * @return {undefined} */ self.launch = function() { try { $(document).ready(function() { // Logouts when Jappix is closed $(window).bind('beforeunload', Connection.terminate); // Nothing to do when anonymous! if(Utils.isAnonymous()) return; // Connection params submitted in URL? if(XMPPLinks.links_var.u && XMPPLinks.links_var.q) { // Generate login data var login_xid = Common.bareXID(Common.generateXID(XMPPLinks.links_var.u, 'chat')); var login_nick = Common.getXIDNick(login_xid); var login_server = Common.getXIDHost(login_xid); var login_pwd = XMPPLinks.links_var.q; var login_resource = JAPPIX_RESOURCE + ' (' + (new Date()).getTime() + ')'; var login_priority = '10'; var login_remember = 1; // Must store session? if(XMPPLinks.links_var.h && (XMPPLinks.links_var.h === '1')) { // Store session var session_xml = self.storeSession(login_nick, login_server, login_pwd, login_resource, login_priority, true); DataStore.setPersistent('global', 'session', 1, session_xml); // Redirect to a clean URL document.location.href = './'; } else { // Hide the homepage $('#home').hide(); // Show the waiting icon Interface.showGeneralWait(); // Proceed login self.doLogin(login_nick, login_server, login_pwd, login_resource, login_priority, login_remember); } return; } // Try to resume a stored session, if not anonymous var session = Common.XMLFromString( DataStore.getPersistent('global', 'session', 1) ); if($(session).find('stored').text() == 'true') { // Hide the homepage $('#home').hide(); // Show the waiting icon Interface.showGeneralWait(); // Login! self.loginFromSession(session); Console.info('Saved session found, resuming it...'); } // Not connected, maybe a XMPP link is submitted? else if((parent.location.hash != '#OK') && XMPPLinks.links_var.x) { Home.change('loginer'); Console.info('A XMPP link is set, switch to login page.'); } }); } catch(e) { Console.error('Connection.launch', e); } }; /** * Return class scope */ return self; })(); Connection.launch();