/* Jappix - An open social platform These are the messages JS scripts for Jappix ------------------------------------------------- License: AGPL Authors: Valérian Saliou, Maranda */ // Bundle var Message = (function () { /** * Alias of this * @private */ var self = {}; /** * Handles MAM forwared messages * @private * @param {object} c_mam * @return {boolean} */ self._handleMAM = function(c_mam) { try { var c_mam_sel = $(c_mam); var c_mam_delay = c_mam_sel.find('delay[xmlns="' + NS_URN_DELAY + '"]'); var c_mam_forward = c_mam_sel.find('forwarded[xmlns="' + NS_URN_FORWARD + '"]'); if(c_mam_forward.size()) { MAM.handleMessage(c_mam_forward, c_mam_delay); } } catch(e) { Console.error('Message._handleMAM', e); } finally { return false; } }; /** * Handles chatstate messages * @private * @param {string} from * @param {string} hash * @param {string} type * @param {object} node * @return {undefined} */ self._handleChatstate = function(from, hash, type, node) { try { /* REF: http://xmpp.org/extensions/xep-0085.html */ var node_sel = $(node); // Re-process the hash? var chatstate_hash = (type == 'groupchat') ? hex_md5(from) : hash; // Do something depending of the received state if(node_sel.find('active').size()) { ChatState.display('active', chatstate_hash, type); // Tell Jappix the entity supports chatstates $('#' + chatstate_hash + ' .message-area').attr('data-chatstates', 'true'); Console.log('Active chatstate received from: ' + from); } else if(node_sel.find('composing').size()) { ChatState.display('composing', chatstate_hash, type); Console.log('Composing chatstate received from: ' + from); } else if(node_sel.find('paused').size()) { ChatState.display('paused', chatstate_hash, type); Console.log('Paused chatstate received from: ' + from); } else if(node_sel.find('inactive').size()){ ChatState.display('inactive', chatstate_hash, type); Console.log('Inactive chatstate received from: ' + from); } else if(node_sel.find('gone').size()){ ChatState.display('gone', chatstate_hash, type); Console.log('Gone chatstate received from: ' + from); } } catch(e) { Console.error('Message._doThat', e); } }; /** * Handles Jappix App messages * @private * @param {string} xid * @param {string} body * @param {object} node * @return {boolean} */ self._handleJappixApp = function(xid, body, node) { var is_exit = false; try { var node_sel = $(node); // Get notification data var jappix_app_node = node_sel.find('app[xmlns="jappix:app"]'); var jappix_app_name = jappix_app_node.find('name'); var jappix_app_name_id = jappix_app_name.attr('id'); var jappix_app_name_value = jappix_app_name.text(); // Jappix Me notification? if(jappix_app_name_id == 'me') { // Get more notification data var jappix_app_data = jappix_app_node.find('data[xmlns="jappix:app:me"]'); var jappix_app_data_action = jappix_app_data.find('action'); var jappix_app_data_url = jappix_app_data.find('url'); var jappix_app_data_action_type = jappix_app_data_action.attr('type'); var jappix_app_data_action_success = jappix_app_data_action.attr('success'); var jappix_app_data_action_job = jappix_app_data_action.attr('job'); var jappix_app_data_url_value = jappix_app_data_url.text(); // Validate data if(jappix_app_data_action_type && jappix_app_data_action_success && jappix_app_data_action_job) { // Filter success jappix_app_data_action_success = parseInt(jappix_app_data_action_success) == 1 ? 'success' : 'error'; // Generate notification namespace var jappix_me_notification_ns = jappix_app_name_id + '_' + jappix_app_data_action_type + '_' + jappix_app_data_action_job + '_' + jappix_app_data_action_success; // Open a new notification Notification.create(jappix_me_notification_ns, xid, [jappix_app_name_value, jappix_app_data_url_value], body); Console.log('Jappix Me notification from: ' + xid + ' with namespace: ' + jappix_me_notification_ns); is_exit = true; } } } catch(e) { Console.error('Message._handleJappixApp', e); } finally { return is_exit; } }; /** * Handles invite messages * @private * @param {string} body * @param {object} node * @return {boolean} */ self._handleInvite = function(body, node) { try { var node_sel = $(node); // We get the needed values var iFrom = node_sel.find('x[xmlns="' + NS_MUC_USER + '"] invite').attr('from'); var iRoom = node_sel.find('x[xmlns="' + NS_XCONFERENCE + '"]').attr('jid') || from; // We display the notification Notification.create('invite_room', iFrom, [iRoom], body); Console.log('Invite Request from: ' + iFrom + ' to join: ' + iRoom); } catch(e) { Console.error('Message._handleInvite', e); } finally { return false; } }; /** * Handles request messages * @private * @param {string} xid * @param {object} message * @param {string} body * @return {boolean} */ self._handleRequest = function(xid, message, body) { try { // Open a new notification Notification.create('request', xid, [message], body); Console.log('HTTP Request from: ' + xid); } catch(e) { Console.error('Message._handleRequest', e); } finally { return false; } }; /** * Handles OOB messages * @private * @param {string} from * @param {string} xid * @param {string} id * @param {object} node * @return {boolean} */ self._handleOOB = function(from, xid, id, node) { try { OOB.handle(from, id, 'x', node); Console.log('Message OOB request from: ' + xid); } catch(e) { Console.error('Message._handleOOB', e); } finally { return false; } }; /** * Handles Roster Item Exchange messages * @private * @param {string} xid * @param {object} message * @param {string} body * @return {boolean} */ self._handleRosterItemExchange = function(xid, message, body) { try { // Open a new notification Notification.create('rosterx', xid, [message], body); Console.log('Roster Item Exchange from: ' + xid); } catch(e) { Console.error('Message._handleRosterItemExchange', e); } finally { return false; } }; /** * Handles attention messages * @private * @param {string} xid * @param {string} body * @return {boolean} */ self._handleAttention = function(xid, body) { try { Attention.receive(xid, body); } catch(e) { Console.error('Message._handleAttention', e); } finally { return false; } }; /** * Handles normal messages * @private * @param {string} xid * @param {string} subject * @param {string} body * @param {string} delay * @return {boolean} */ self._handleNormal = function(xid, subject, body, delay) { try { var message_date = delay || DateUtils.getXMPPTime('utc'); var message_id = hex_md5(xid + subject + message_date); // Store the received message Inbox.storeMessage(xid, subject, body, 'unread', message_id, message_date); // Display the inbox message if(Common.exists('#inbox')) { Inbox.displayMessage(xid, subject, body, 'unread', message_id, message_date); } // Check we have new messages (play a sound if any unread messages) if(Inbox.checkMessages()) { Audio.play('notification'); } // Send it to the server Inbox.store(); } catch(e) { Console.error('Message._handleNormal', e); } finally { return false; } }; /** * Handles Pubsub event messages * @private * @param {string} xid * @param {string} hash * @param {object} message * @param {object} node * @return {boolean} */ self._handlePubsub = function(xid, hash, message, node) { try { // We get the needed values var items_sel = $(node).find('event items'); var node_attr = items_sel.attr('node'); var text; // Turn around the different result cases if(node_attr) { switch(node_attr) { // Mood case NS_MOOD: // Retrieve the values var mood = items_sel.find('mood'); var value = ''; text = ''; // There's something if(mood.children().size()) { value = node.getElementsByTagName('mood').item(0).childNodes.item(0).nodeName || ''; text = mood.find('text').text(); } // Store the PEP event (and display it) PEP.store(xid, 'mood', value, text); break; // Activity case NS_ACTIVITY: // Retrieve the values var activity_sel = items_sel.find('activity'); text = ''; // There's something if(activity_sel.children().size()) { value = node.getElementsByTagName('activity').item(0).childNodes.item(0).nodeName || ''; text = activity_sel.find('text').text(); } // Store the PEP event (and display it) PEP.store(xid, 'activity', value, text); break; // Tune case NS_TUNE: // Retrieve the values var tune_sel = items_sel.find('tune'); var artist = tune_sel.find('artist').text(); var source = tune_sel.find('source').text(); var title = tune_sel.find('title').text(); var uri = tune_sel.find('uri').text(); // Store the PEP event (and display it) PEP.store(xid, 'tune', artist, title, source, uri); break; // Geolocation case NS_GEOLOC: // Retrieve the values var geoloc_sel = items_sel.find('geoloc'); var lat = geoloc_sel.find('lat').text(); var lon = geoloc_sel.find('lon').text(); // Any extra-values? var locality = geoloc_sel.find('locality').text(); var region = geoloc_sel.find('region').text(); var country = geoloc_sel.find('country').text(); var human = PEP.humanPosition(locality, region, country); // Store the PEP event (and display it) PEP.store(xid, 'geoloc', lat, lon, human); break; // Microblog case NS_URN_MBLOG: Microblog.display(message, xid, hash, 'mixed', 'push'); break; // Inbox case NS_URN_INBOX: // Do not handle friend's notifications if(xid == Common.getXID()) { Notification.handle(message); } break; } } } catch(e) { Console.error('Message._handlePubsub', e); } finally { return false; } }; /** * Handles room topic messages * @private * @param {string} type * @param {string} from * @param {string} hash * @param {string} subject * @param {string} resource * @param {string} time * @param {string} stamp * @return {undefined} */ self._handleRoomTopic = function(type, from, hash, subject, resource, time, stamp) { try { // Filter the vars var filter_subject = subject.replace(/\n+/g, ' '); var filteredSubject = Filter.message(filter_subject, resource, true); var filteredName = resource.htmlEnc(); // Display the new subject at the top $('#' + hash + ' .top .name .bc-infos .muc-topic').replaceWith( '' + filteredSubject + '' ); // Display the new subject as a system message if(resource) { var topic_body = filteredName + ' ' + Common._e("changed the subject to:") + ' ' + Filter.message(subject, resource, true); self.display(type, from, hash, filteredName, topic_body, time, stamp, 'system-message', false); } } catch(e) { Console.error('Message._handleRoomTopic', e); } }; /** * Handles groupchat messages * @private * @param {string} from * @param {string} hash * @param {string} type * @param {string} resource * @param {string} id * @param {string} body * @param {string} raw_body * @param {string} time * @param {number} stamp * @param {boolean} html_escape * @param {string} delay * @param {object} message_edit * @param {boolean} is_storable * @return {undefined} */ self._handleGroupchat = function(from, hash, type, resource, id, body, raw_body, time, stamp, html_escape, delay, message_edit, is_storable) { try { /* REF: http://xmpp.org/extensions/xep-0045.html */ // Message type var message_type = 'user-message'; if(delay && resource) { // Old message message_type = 'old-message'; } else if(!resource) { // System message message_type = 'system-message'; } var nickQuote = ''; // If this is not an old message if(message_type == 'user-message') { var myNick = Name.getMUCNick(hash); // If an user quoted our nick (with some checks) var regex = new RegExp('((^)|( )|(@))' + Common.escapeRegex(myNick) + '(($)|(:)|(,)|( ))', 'gi'); if(body.match(regex) && (myNick != resource) && (message_type == 'user-message')) { nickQuote = ' my-nick'; } // We notify the user if there's a new personal message if(nickQuote) { Interface.messageNotify(hash, 'personal'); Board.quick(from, 'groupchat', raw_body, resource); Audio.play('receive-message'); } // We notify the user there's a new unread MUC message else { Interface.messageNotify(hash, 'unread'); // Play sound to all users in the MUC, except user who sent the message. if(myNick != resource) { Audio.play('receive-message'); } } } // Display the received message self.display( type, from, hash, resource.htmlEnc(), body, time, stamp, message_type, html_escape, nickQuote, undefined, id, undefined, undefined, message_edit.is_edited, message_edit.next_count, is_storable ); } catch(e) { Console.error('Message._handleGroupchat', e); } }; /** * Handles chat messages * @private * @param {string} from * @param {string} xid * @param {string} hash * @param {string} type * @param {string} resource * @param {string} id * @param {string} body * @param {string} raw_body * @param {string} time * @param {number} stamp * @param {boolean} html_escape * @param {object} message_edit * @param {boolean} is_storable * @param {boolean} is_markable * @param {boolean} is_groupchat_user * @param {object} message * @return {undefined} */ self._handleChat = function(from, xid, hash, type, resource, id, body, raw_body, time, stamp, html_escape, message_edit, is_storable, is_markable, is_groupchat_user, message) { try { // Gets the nickname of the user var fromName = resource; var chatType = 'chat'; // Must send a receipt notification? if(Receipts.has(message) && (id !== null)) { Receipts.sendReceived(type, from, id); } // It does not come from a groupchat user, get the full name if(!is_groupchat_user) { fromName = Name.getBuddy(xid); } else { chatType = 'private'; } // If the chat isn't yet opened, open it ! if(!Common.exists('#' + hash)) { // We create a new chat Chat.create(hash, xid, fromName, chatType); // We tell the user that a new chat has started Audio.play('new-chat'); } else { Audio.play('receive-message'); } // Display the received message var message_sel = self.display( type, xid, hash, fromName.htmlEnc(), body, time, stamp, 'user-message', html_escape, '', 'him', id, undefined, undefined, message_edit.is_edited, message_edit.next_count, is_storable, is_markable ); // We notify the user Interface.messageNotify(hash, 'personal'); Board.quick(xid, 'chat', raw_body, fromName); // Mark the message if(is_markable === true && Markers.hasSupport(xid)) { var mark_type = Markers.MARK_TYPE_RECEIVED; if(Interface.hasChanFocus(hash) === true) { mark_type = Markers.MARK_TYPE_DISPLAYED; } Markers.change(from, mark_type, id, message_sel); } } catch(e) { Console.error('Message._handleChat', e); } }; /** * Sends an help message * @private * @param {string} type * @param {string} xid * @param {string} hash * @return {undefined} */ self._sendHelp = function(type, xid, hash) { try { // Help text var help_text = '

'; help_text += '' + Common._e("Available shortcuts:") + ''; // Shortcuts array var shortcuts = []; // Common shortcuts shortcuts.push(Common.printf(Common._e("%s removes the chat logs"), '/clear')); shortcuts.push(Common.printf(Common._e("%s joins a groupchat"), '/join jid')); shortcuts.push(Common.printf(Common._e("%s closes the chat"), '/part')); shortcuts.push(Common.printf(Common._e("%s shows the user profile"), '/whois jid')); // Groupchat shortcuts if(type == 'groupchat') { shortcuts.push(Common.printf(Common._e("%s sends a message to the room"), '/say message')); shortcuts.push(Common.printf(Common._e("%s changes your nickname"), '/nick nickname')); shortcuts.push(Common.printf(Common._e("%s sends a message to someone in the room"), '/msg nickname message')); shortcuts.push(Common.printf(Common._e("%s changes the room topic"), '/topic subject')); shortcuts.push(Common.printf(Common._e("%s kicks a user of the room"), '/kick [reason:] nickname')); shortcuts.push(Common.printf(Common._e("%s bans a user of the room"), '/ban [reason:] nickname')); shortcuts.push(Common.printf(Common._e("%s invites someone to join the room"), '/invite jid message')); } // Generate the code from the array shortcuts = shortcuts.sort(); for(var s in shortcuts) { help_text += shortcuts[s] + '
'; } help_text += '

'; // Display the message self.display(type, xid, hash, 'help', help_text, DateUtils.getCompleteTime(), DateUtils.getTimeStamp(), 'system-message', false); // Reset chatstate ChatState.send('active', xid, hash); } catch(e) { Console.error('Message._sendHelp', e); } }; /** * Sends a clear message * @private * @param {string} xid * @param {string} hash * @return {undefined} */ self._sendClear = function(xid, hash) { try { Chat.clean(hex_md5(xid)); // Reset chatstate ChatState.send('active', xid, hash); } catch(e) { Console.error('Message._sendClear', e); } }; /** * Sends a join message * @private * @param {string} xid * @param {string} hash * @param {string} e_1 * @param {string} e_2 * @return {undefined} */ self._sendJoin = function(xid, hash, e_1, e_2) { try { // Join var room_gen = Common.generateXID(e_1, 'groupchat'); var pass = e_2; Chat.checkCreate(room_gen, 'groupchat'); // Reset chatstate ChatState.send('active', xid, hash); } catch(e) { Console.error('Message._sendJoin', e); } }; /** * Sends a part message * @private * @param {string} xid * @param {string} type * @return {undefined} */ self._sendPart = function(xid, type) { try { Interface.quitThisChat(xid, hex_md5(xid), type); } catch(e) { Console.error('Message._sendPart', e); } }; /** * Sends a WHOIS message * @private * @param {string} type * @param {string} xid * @param {string} hash * @param {string} e_3 * @return {undefined} */ self._sendWHOIS = function(type, xid, hash, e_3) { try { var whois_xid = RegExp.$3; // Groupchat WHOIS if(type == 'groupchat') { nXID = Utils.getMUCUserXID(xid, whois_xid); if(!nXID) { Board.openThisInfo(6); } else { UserInfos.open(nXID); } } // Chat or private WHOIS else { if(!whois_xid) { UserInfos.open(xid); } else { UserInfos.open(whois_xid); } } // Reset chatstate ChatState.send('active', xid, hash); } catch(e) { Console.error('Message._sendWHOIS', e); } }; /** * Sends an attention message * @private * @param {string} xid * @param {string} e_2 * @return {undefined} */ self._sendAttention = function(xid, e_2) { try { Attention.send( xid, $.trim(e_2) ); } catch(e) { Console.error('Message._sendAttention', e); } }; /** * Sends a chat message * @private * @param {string} xid * @param {string} hash * @param {string} id * @param {string} body * @param {object} message_packet * @return {undefined} */ self._sendChat = function(xid, hash, id, body, message_packet) { try { message_packet.setType('chat'); // Generates the correct message depending of the choosen style var genMsg = self.generate(message_packet, body, hash); var html_escape = (genMsg !== 'XHTML'); // Receipt request var receipt_request = Receipts.request(hash); if(receipt_request) { message_packet.appendNode('request', { 'xmlns': NS_URN_RECEIPTS }); } // Chatstate message_packet.appendNode('active', { 'xmlns': NS_CHATSTATES }); // Markable message? var has_markers = Markers.hasSupport(xid); if(has_markers === true) { Markers.mark(message_packet); } // Send it! con.send(message_packet, Errors.handleReply); // Filter the xHTML message (for us!) if(!html_escape) { body = Filter.xhtml(message_packet.getNode()); } // Finally we display the message we just sent var my_xid = Common.getXID(); var message_sel = self.display( 'chat', my_xid, hash, Name.getBuddy(my_xid).htmlEnc(), body, DateUtils.getCompleteTime(), DateUtils.getTimeStamp(), 'user-message', html_escape, '', 'me', id ); if(has_markers === true) { message_sel.addClass('is-sending'); message_sel.find('.message-marker').text( Common._e("Sending...") ).show(); } // Receipt timer if(receipt_request) { Receipts.checkReceived(hash, id); } } catch(e) { Console.error('Message._sendChat', e); } }; /** * Sends a groupchat say message * @private * @param {string} hash * @param {string} body * @param {object} message_packet * @return {undefined} */ self._sendGroupchatSat = function(hash, body, message_packet) { try { body = body.replace(/^\/say (.+)/, '$1'); message_packet.setType('groupchat'); self.generate(message_packet, body, hash); con.send(message_packet, Errors.handleReply); } catch(e) { Console.error('Message._sendGroupchatSat', e); } }; /** * Sends a groupchat nick message * @private * @param {string} xid * @param {string} hash * @param {string} nick * @param {string} body * @return {undefined} */ self._sendGroupchatNick = function(xid, hash, e_1, body) { try { var nick = $.trim(e_1); // Does not exist yet? if(nick && !Utils.getMUCUserXID(xid, nick)) { // Send a new presence Presence.send( (xid + '/' + nick), '', Presence.getUserShow(), Presence.getUserStatus(), '', false, false, Errors.handleReply ); // Change the stored nickname $('#' + hex_md5(xid)).attr('data-nick', escape(nick)); // Reset chatstate ChatState.send('active', xid, hash); } } catch(e) { Console.error('Message._sendGroupchatNick', e); } }; /** * Sends a groupchat msg message * @private * @param {string} xid * @param {string} hash * @param {string} e_1 * @param {string} e_2 * @param {object} message_packet * @return {undefined} */ self._sendGroupchatMsg = function(xid, hash, e_1, e_2, message_packet) { try { var msg_nick = e_1; var msg_body = e_2; var nick_xid = Utils.getMUCUserXID(xid, msg_nick); // We check if the user exists if(!nick_xid) { Board.openThisInfo(6); } else if(msg_body) { message_packet.setType('chat'); message_packet.setTo(nick_xid); self.generate(message_packet, msg_body, hash); con.send(message_packet, Errors.handleReply); } } catch(e) { Console.error('Message._sendGroupchatMsg', e); } }; /** * Sends a groupchat XXX message * @private * @param {string} xid * @param {string} hash * @param {string} body * @param {object} message_packet * @return {undefined} */ self._sendGroupchatTopic = function(xid, hash, body, message_packet) { try { var topic = body.replace(/^\/topic (.+)/, '$1'); message_packet.setType('groupchat'); message_packet.setSubject(topic); con.send(message_packet, Errors.handleMessage); // Reset chatstate ChatState.send('active', xid, hash); } catch(e) { Console.error('Message._sendGroupchatTopic', e); } }; /** * Sends a groupchat XXX message * @private * @param {string} xid * @param {string} hash * @param {string} body * @param {string} e_1 * @param {string} e_2 * @return {undefined} */ self._sendGroupchatBan = function(xid, hash, body, e_1, e_2) { try { var ban_nick = $.trim(e_1); var ban_reason = ''; // We check if the user exists, if not it may be because a reason is given // we do not check it at first because the nickname could contain ':' var ban_xid = Utils.getMUCUserRealXID(xid, ban_nick); if(!ban_xid && (body.match(/^\/ban ([^:]+)[:]*(.*)/))) { ban_reason = $.trim(e_1); ban_nick = $.trim(e_2); if(ban_nick.length === 0) { ban_nick = ban_reason; ban_reason = ''; } ban_xid = Utils.getMUCUserXID(xid, ban_nick); } Groupchat.banUser(xid, ban_xid, ban_reason); // Reset chatstate ChatState.send('active', xid, hash); } catch(e) { Console.error('Message._sendGroupchatBan', e); } }; /** * Sends a groupchat XXX message * @private * @param {string} xid * @param {string} hash * @param {string} body * @param {string} e_1 * @param {string} e_2 * @return {undefined} */ self._sendGroupchatKick = function(xid, hash, body, e_1, e_2) { try { var kick_nick = $.trim(e_1); var kick_reason = ''; // We check if the user exists, if not it may be because a reason is given // we do not check it at first because the nickname could contain ':' var kick_xid = Utils.getMUCUserRealXID(xid, kick_nick); if(!kick_xid && (body.match(/^\/kick ([^:]+)[:]*(.*)/))) { kick_reason = $.trim(e_1); kick_nick = $.trim(e_2); if(kick_nick.length === 0) { kick_nick = kick_reason; kick_reason = ''; } kick_xid = Utils.getMUCUserXID(xid, kick_nick); } Groupchat.kickUser(xid, kick_xid, kick_nick, kick_reason); // Reset chatstate ChatState.send('active', xid, hash); } catch(e) { Console.error('Message._sendGroupchatKick', e); } }; /** * Sends a groupchat XXX message * @private * @param {string} xid * @param {string} hash * @param {string} e_1 * @param {string} e_2 * @param {object} message_packet * @return {undefined} */ self._sendGroupchatInvite = function(xid, hash, e_1, e_2, message_packet) { try { var i_xid = e_1; var invite_reason = e_2; var x = message_packet.appendNode('x', { 'xmlns': NS_MUC_USER }); var node = x.appendChild(message_packet.buildNode('invite', { 'to': i_xid, 'xmlns': NS_MUC_USER })); if(invite_reason) { node.appendChild(message_packet.buildNode('reason', { 'xmlns': NS_MUC_USER }, invite_reason)); } con.send(message_packet, Errors.handleReply); // Reset chatstate ChatState.send('active', xid, hash); } catch(e) { Console.error('Message._sendGroupchatInvite', e); } }; /** * Sends a groupchat XXX message * @private * @param {string} xid * @param {string} hash * @param {string} type * @param {string} body * @param {object} message_packet * @return {undefined} */ self._sendGroupchatMessage = function(xid, hash, type, body, message_packet) { try { message_packet.setType('groupchat'); // Chatstate message_packet.appendNode('active', { 'xmlns': NS_CHATSTATES }); self.generate(message_packet, body, hash); con.send(message_packet, Errors.handleMessage); Console.info('Message sent to: ' + xid + ' / ' + type); } catch(e) { Console.error('Message._sendGroupchatMessage', e); } }; /** * Sends a groupchat message * @private * @param {string} xid * @param {string} hash * @param {string} type * @param {string} body * @param {object} message_packet * @return {undefined} */ self._sendGroupchat = function(xid, hash, type, body, message_packet) { try { // /say shortcut if(body.match(/^\/say (.+)/)) { self._sendGroupchatSat( hash, body, message_packet ); } // /nick shortcut else if(body.match(/^\/nick (.+)/)) { self._sendGroupchatNick( xid, hash, RegExp.$1, body ); } // /msg shortcut else if(body.match(/^\/msg (\S+)\s+(.+)/)) { self._sendGroupchatMsg( xid, hash, RegExp.$1, RegExp.$2, message_packet ); } // /topic shortcut else if(body.match(/^\/topic (.+)/)) { self._sendGroupchatTopic( xid, hash, body, message_packet ); } // /ban shortcut else if(body.match(/^\/ban (.*)/)) { self._sendGroupchatBan( xid, hash, body, RegExp.$1, RegExp.$2 ); } // /kick shortcut else if(body.match(/^\/kick (.*)/)) { self._sendGroupchatKick( xid, hash, body, RegExp.$1, RegExp.$2 ); } // /invite shortcut else if(body.match(/^\/invite (\S+)\s*(.*)/)) { self._sendGroupchatInvite( xid, hash, RegExp.$1, RegExp.$2, message_packet ); } // No shortcut, this is a message else { self._sendGroupchatMessage( xid, hash, type, body, message_packet ); } } catch(e) { Console.error('Message._sendGroupchat', e); } }; /** * Handles the incoming message packets * @public * @param {object} message * @return {boolean} */ self.handle = function(message) { try { // Error packet? Stop! if(Errors.handleReply(message)) { return; } // Carbon-forwarded message? if(message.getChild('sent', NS_URN_CARBONS)) { Carbons.handleSent(message); return; } if(message.getChild('received', NS_URN_CARBONS)) { Carbons.handleReceived(message); return; } // MAM-forwarded message? var c_mam = message.getChild('result', NS_URN_MAM); if(c_mam) { return self._handleMAM(c_mam); } // We get the message items var from = Common.fullXID(Common.getStanzaFrom(message)); var id = message.getID(); var type = message.getType(); var body = $.trim(message.getBody()); var node = message.getNode(); var subject = $.trim(message.getSubject()); // Keep raw message body var raw_body = body; // We generate some values var xid = Common.bareXID(from); var resource = Common.thisResource(from); var hash = hex_md5(xid); var xHTML = $(node).find('html body').size(); var is_groupchat_user = false; // This message comes from a Muji room (ignore) if(Muji.is_room(xid)) { return false; } // This message comes from a groupchat user if(Utils.isPrivate(xid) && ((type == 'chat') || !type) && resource) { is_groupchat_user = true; xid = from; hash = hex_md5(xid); } // Get message date var time, stamp; var delay = DateUtils.readMessageDelay(node); // Any delay? if(delay) { time = DateUtils.relative(delay); stamp = DateUtils.extractStamp(Date.jab2date(delay)); } else { time = DateUtils.getCompleteTime(); stamp = DateUtils.extractStamp(new Date()); } // Received message if(Receipts.hasReceived(message)) { return Receipts.messageReceived(hash, id); } // Chatstate message if(node && !delay && ((((type == 'chat') || !type) && !Common.exists('#page-switch .' + hash + ' .unavailable')) || (type == 'groupchat'))) { self._handleChatstate(from, hash, type, node); } // Jappix App message if(message.getChild('app', 'jappix:app')) { if(self._handleJappixApp(xid, body, node) === true) { return false; } } // Invite message if($(node).find('x[xmlns="' + NS_MUC_USER + '"] invite').size()) { return self._handleInvite(body, node); } // Request message if(message.getChild('confirm', NS_HTTP_AUTH)) { return self._handleRequest(xid, message, body); } // OOB message if(message.getChild('x', NS_XOOB)) { return self._handleOOB(from, xid, id, node); } // Roster Item Exchange message if(message.getChild('x', NS_ROSTERX)) { return self._handleRosterItemExchange(xid, message, body); } // Attention message if(message.getChild('attention', NS_URN_ATTENTION)) { return self._handleAttention(xid, body); } // Normal message if((type == 'normal') && body) { return self._handleNormal(xid, subject, body, delay); } // PubSub event if($(node).find('event').attr('xmlns') == NS_PUBSUB_EVENT) { return self._handlePubsub(xid, hash, message, node); } // If this is a room topic message if(subject && (type == 'groupchat')) { self._handleRoomTopic(type, from, hash, subject, resource, time, stamp); } // If the message has a content if(xHTML || body) { var filteredMessage; var html_escape = true; // IE bug fix if((BrowserDetect.browser == 'Explorer') && (BrowserDetect.version < 9)) { xHTML = 0; } // If this is a xHTML message if(xHTML) { html_escape = false; // Filter the xHTML message body = Filter.xhtml(node); } // Catch message edit (XEP-0308) var message_edit = Correction.catch(message, hash, type); // Storable message? var is_storable = message.getChild('no-permanent-storage', NS_URN_HINTS) ? false : true; // Groupchat message if(type == 'groupchat') { self._handleGroupchat( from, hash, type, resource, id, body, raw_body, time, stamp, html_escape, delay, message_edit, is_storable ); } else { // Markable message? var is_markable = Markers.hasRequestMarker(node); self._handleChat( from, xid, hash, type, resource, id, body, raw_body, time, stamp, html_escape, message_edit, is_storable, is_markable, is_groupchat_user, message ); } } // Message marker? if(Markers.hasResponseMarker(node)) { return Markers.handle(from, node); } return false; } catch(e) { Console.error('Message.handle', e); } }; /** * Sends a given message * @public * @param {string} hash * @param {string} type * @return {boolean} */ self.send = function(hash, type) { try { // Get the values var message_area = $('#' + hash + ' .message-area'); var body = $.trim(message_area.val()); var xid = unescape(message_area.attr('data-to')); var nXID; // If the user didn't entered any message, stop if(!body || !xid) { return false; } // We send the message through the XMPP network var message_packet = new JSJaCMessage(); message_packet.setTo(xid); // Set an ID var id = genID(); message_packet.setID(id); // /help shortcut if(body.match(/^\/help\s*(.*)/)) { self._sendHelp(type, xid, hash); } // /clear shortcut else if(body.match(/^\/clear/)) { self._sendClear(xid, hash); } // /join shortcut else if(body.match(/^\/join (\S+)\s*(.*)/)) { self._sendJoin(xid, hash, RegExp.$1, RegExp.$2); } // /part shortcut else if(body.match(/^\/part\s*(.*)/) && (!Utils.isAnonymous() || (Utils.isAnonymous() && (xid != Common.generateXID(ANONYMOUS_ROOM, 'groupchat'))))) { self._sendPart(xid, type); } // /whois shortcut else if(body.match(/^\/whois(( (\S+))|($))/)) { self._sendWHOIS(type, xid, hash, RegExp.$3); } // /attention shortcut else if(body.match(/^\/attention( (.*))?/) && type == 'chat') { self._sendAttention(xid, RegExp.$2); } // Chat message type else if(type == 'chat') { self._sendChat( xid, hash, id, body, message_packet ); } // Groupchat message type else if(type == 'groupchat') { self._sendGroupchat( xid, hash, type, body, message_packet ); } // We reset the message input $('#' + hash + ' .message-area').val(''); } catch(e) { Console.error('Message.send', e); } finally { return false; } }; /** * Generates the correct message area style * @public * @param {string} hash * @return {string} */ self.generateStyle = function() { try { // Initialize the vars var styles = '#' + hash + ' div.bubble-style'; var font = styles + ' a.font-current'; var fontsize = styles + ' a.fontsize-current'; var checkbox = styles + ' input[type="checkbox"]'; var color = '#' + hash + ' .message-area[data-color]'; var style = ''; // Get the font value $(font).filter('[data-font]').each(function() { style += 'font-family: ' + $(this).attr('data-font') + ';'; }); // Get the font value $(fontsize).filter('[data-value]').each(function() { style += 'font-size: ' + $(this).attr('data-value') + 'px;'; }); // Loop the input values $(checkbox).filter(':checked').each(function() { // If there is a previous element if(style) { style += ' '; } // Get the current style switch($(this).attr('class')) { case 'bold': style += 'font-weight: bold;'; break; case 'italic': style += 'font-style: italic;'; break; case 'underline': style += 'text-decoration: underline;'; break; } }); // Get the color value $(color).each(function() { style += 'color: #' + $(this).attr('data-color'); }); return style; } catch(e) { Console.error('Message.generateStyle', e); } }; /** * Read messages from local archive * @public * @param {string} hash * @return {string} */ self.readLocalArchive = function(hash) { try { return DataStore.getPersistent(Common.getXID(), 'history', hash); } catch(e) { Console.error('Message.readLocalArchive', e); } }; /** * Stores message in local archive * @public * @param {string} hash * @param {string} store_html * @return {undefined} */ self.storeLocalArchive = function(hash, store_html) { try { if(DataStore.getDB(Connection.desktop_hash, 'options', 'localarchives') != '0') { DataStore.setPersistent(Common.getXID(), 'history', hash, store_html); } } catch(e) { Console.error('Message.storeLocalArchive', e); } }; /** * Removes messages from local archive * @public * @param {string} hash * @return {undefined} */ self.removeLocalArchive = function(hash) { try { DataStore.removePersistent(Common.getXID(), 'history', hash); } catch(e) { Console.error('Message.removeLocalArchive', e); } }; /** * Flushes local messages archive * @public * @return {undefined} */ self.flushLocalArchive = function() { try { var flush_count = 0; var db_regex = new RegExp(('^' + Common.getXID() + '_') + ('history_')); for(var i = 0; i < JappixDataStore.storagePersistent.length; i++) { var db_current = JappixDataStore.storagePersistent.key(i); if(db_regex.exec(db_current)) { JappixDataStore.storagePersistent.removeItem(db_current); flush_count++; } } Console.info('Flushed ' + flush_count + ' archives in total.'); } catch(e) { Console.error('Message.flushLocalArchive', e); } }; /** * Generates the correct message code * @public * @param {object} message_packet * @param {string} body * @param {string} hash * @return {string} */ self.generate = function(message_packet, body, hash) { try { // Create the classical body message_packet.setBody(body); // Get the style var style = $('#' + hash + ' .message-area').attr('style'); // A message style is choosen if(style) { // Explode the message body new lines (to create one

element by line) var new_lines = new Array(body); if(body.match(/\n/)) { new_lines = body.split('\n'); } // Create the XML elements var html_node = message_packet.appendNode('html', { 'xmlns': NS_XHTML_IM }); var body_node = html_node.appendChild(message_packet.buildNode('body', { 'xmlns': NS_XHTML })); // Use the exploded body array to create one element per entry for(var i in new_lines) { // Current line var cLine = new_lines[i]; // Blank line, we put a
if(cLine.match(/(^)(\s+)($)/) || !cLine) { body_node.appendChild(message_packet.buildNode('br', {'xmlns': NS_XHTML})); } // Line with content, we put a

else { // HTML encode the line cLine = cLine.htmlEnc(); // Filter the links cLine = Links.apply(cLine, 'xhtml-im', style); // Append the filtered line $(body_node).append($('

' + cLine + '

')); } } return 'XHTML'; } return 'PLAIN'; } catch(e) { Console.error('Message.generate', e); } }; /** * Displays a given message in a chat tab * @public * @param {string} type * @param {string} xid * @param {string} hash * @param {string} name * @param {string} body * @param {string} time * @param {string} stamp * @param {string} message_type * @param {boolean} html_escape * @param {string} nick_quote * @param {string} mode * @param {string} id * @param {object} c_target_sel * @param {boolean} no_scroll * @param {boolean} is_edited * @param {number} edit_count * @param {boolean} is_storable * @param {boolean} is_markable * @return {object} */ self.display = function(type, xid, hash, name, body, time, stamp, message_type, html_escape, nick_quote, mode, id, c_target_sel, no_scroll, is_edited, edit_count, is_storable, is_markable) { var message_sel = null; try { // Target if(typeof c_target_sel === 'undefined') { c_target_sel = $('#' + hash + ' .content'); } // Auto-calculate mode for groupchat? if(type == 'groupchat' && !mode) { var own_groupchat_nickname = $('#' + hash).attr('data-nick') || ''; own_groupchat_nickname = unescape(own_groupchat_nickname); if(name == own_groupchat_nickname) { mode = 'me'; } else { mode = 'him'; } } // Generate some stuffs var has_avatar = false; var xid_hash = ''; if(!nick_quote) { nick_quote = ''; } if(message_type != 'system-message') { has_avatar = true; xid_hash = hex_md5(xid); } // Can scroll? var cont_scroll = document.getElementById('chat-content-' + hash); var can_scroll = false; if((!cont_scroll.scrollTop || ((cont_scroll.clientHeight + cont_scroll.scrollTop) == cont_scroll.scrollHeight)) && no_scroll !== true) { can_scroll = true; } // Any ID? var data_id = ''; if(id) { data_id = ' data-id="' + id + '"'; } // Edited state? var data_edited = ''; var data_edit_count = ''; if(is_edited === true) { data_edited = ' data-edited="true"'; data_edit_count = ' data-edit-count="' + (edit_count || 0) + '"'; } // Markable state? var data_markable = (is_markable === true) ? ' data-markable="true"' : ''; // Filter the message var filteredMessage = Filter.message(body, name, html_escape); // Display the received message in the room var message_code = '
'; // Name color attribute if(type == 'groupchat') { attribute = ' style="color: ' + Common.generateColor(name) + ';" class="name'; } else { attribute = ' class="name'; if(mode) { attribute += ' ' + mode; } } // Close the class attribute if(message_type == 'system-message') { attribute += ' hidden"'; } else { attribute += '"'; } // Filter the previous displayed message var last = c_target_sel.find('.one-group:not(.from-history):last'); var last_name = last.find('b.name').attr('data-xid'); var last_type = last.attr('data-type'); var last_stamp = parseInt(last.attr('data-stamp')); var grouped = false; // We can group it with another previous message if((last_name == xid) && (message_type == last_type) && ((stamp - last_stamp) <= 1800)) { grouped = true; } // Is it a /me command? if(body.match(/(^|>)(\/me )([^<]+)/)) { filteredMessage = '' + filteredMessage + ''; } message_code += filteredMessage + '
'; // Message correction containers if(message_type == 'user-message') { // Message edit properties message_code += '' + Common._e("Edit") + ''; if(is_edited === true) { var edit_text = Common._e("Edited"); if(edit_count > 1) { edit_text = Common._e(Common.printf("Edited (%s)", edit_count)); } message_code += '' + edit_text + ''; } } // Message marker container if(type == 'chat') { message_code += ''; } message_code += '
'; // Must group it? if(!grouped) { // Generate message headers var message_head = ''; // Any avatar to add? if(has_avatar) { message_head += '
'; } // Add the date & the name message_head += '' + time + '' + name + ''; // Generate message code message_code = '
' + message_head + message_code + '
'; } // Write the code in the DOM if(grouped) { c_target_sel.find('.one-group:last').append(message_code); } else { c_target_sel.append(message_code); } message_sel = c_target_sel.find('.one-line:last'); // Store the last MAM.REQ_MAX message groups if(!Features.enabledMAM() && (type == 'chat') && (message_type == 'user-message')) { // Filter the DOM var dom_filter = $('#' + hash + ' .content').clone().contents(); var default_avatar = ('./images/others/default-avatar.png').replace(/&/g, '&'); // Fixes #252 $(dom_filter).find('.system-message').parent().remove(); $(dom_filter).find('.avatar-container img.avatar').attr('src', default_avatar); $(dom_filter).find('.one-line').parent().slice(0, $(dom_filter).find('.one-line').parent().size() - MAM.REQ_MAX).remove(); var store_html = $(dom_filter).parent().html(); // Store the data if(store_html && is_storable !== false) { self.storeLocalArchive(hash, store_html); } if(is_storable === false) { Console.info('Message.display', 'Won\'t store message since it\'s labeled as not storable (' + xid + ')'); } } // Must get the avatar? if(has_avatar && xid && !grouped) { Avatar.get(xid, 'cache', 'true', 'forget'); } // Scroll to this message if(can_scroll) { Interface.autoScroll(hash); } // Add click events var xid_to = $('#' + hash).attr('data-xid'); if(xid_to) { xid_to = unescape(xid_to); $('#' + hash + ' .content .one-line:last .correction-edit').click(function() { Correction.enter(xid_to); return false; }); } } catch(e) { Console.error('Message.display', e); } finally { return message_sel; } }; /** * Return class scope */ return self; })();