3 Jappix - An open social platform
4 These are the presence JS scripts for Jappix
6 -------------------------------------------------
10 Last revision: 23/09/11
14 // Sends the user first presence
15 var FIRST_PRESENCE_SENT = false;
17 function firstPresence(checksum) {
18 logThis('First presence sent.', 3);
20 // Jappix is now ready: change the title
24 var is_anonymous = isAnonymous();
27 FIRST_PRESENCE_SENT = true;
29 // Try to use the last status message
30 var status = getDB('options', 'presence-status');
35 // We tell the world that we are online
37 sendPresence('', '', '', status, checksum);
39 // Any status to apply?
41 $('#presence-status').val(status);
43 // Enable the presence picker
44 $('#presence-status').removeAttr('disabled');
45 $('#my-infos .f-presence a.picker').removeClass('disabled');
47 // We set the last activity stamp
48 PRESENCE_LAST_ACTIVITY = getTimeStamp();
50 // We store our presence
51 setDB('presence-show', 1, 'available');
55 // We get the stored bookmarks (because of the photo hash and some other stuffs, we must get it later)
56 getStorage(NS_BOOKMARKS);
58 // We open a new chat if a XMPP link was submitted
59 if((parent.location.hash != '#OK') && LINK_VARS['x']) {
60 // A link is submitted in the URL
61 xmppLink(LINK_VARS['x']);
64 parent.location.hash = 'OK';
69 // Handles incoming presence packets
70 function handlePresence(presence) {
71 // We define everything needed here
72 var from = fullXID(getStanzaFrom(presence));
73 var hash = hex_md5(from);
74 var node = presence.getNode();
75 var xid = bareXID(from);
76 var xidHash = hex_md5(xid);
78 // We get the type content
79 var type = presence.getType();
83 // We get the priority content
84 var priority = presence.getPriority() + '';
85 if(!priority || (type == 'error'))
88 // We get the show content
89 var show = presence.getShow();
90 if(!show || (type == 'error'))
93 // We get the status content
94 var status = presence.getStatus();
95 if(!status || (type == 'error'))
98 // We get the photo content
99 var photo = $(node).find('x[xmlns=' + NS_VCARD_P + ']:first photo');
100 var checksum = photo.text();
101 var hasPhoto = photo.size();
103 if(hasPhoto && (type != 'error'))
108 // We get the CAPS content
109 var caps = $(node).find('c[xmlns=' + NS_CAPS + ']:first').attr('ver');
110 if(!caps || (type == 'error'))
113 // This presence comes from another resource of my account with a difference avatar checksum
114 if((xid == getXID()) && (hasPhoto == 'true') && (checksum != getDB('checksum', 1)))
115 getAvatar(getXID(), 'force', 'true', 'forget');
117 // This presence comes from a groupchat
119 var x_muc = $(node).find('x[xmlns=' + NS_MUC_USER + ']:first');
120 var item = x_muc.find('item');
121 var affiliation = item.attr('affiliation');
122 var role = item.attr('role');
123 var reason = item.find('reason').text();
124 var iXID = item.attr('jid');
125 var iNick = item.attr('nick');
126 var nick = thisResource(from);
127 var messageTime = getCompleteTime();
128 var notInitial = true;
130 // Read the status code
131 var status_code = new Array();
133 x_muc.find('status').each(function() {
134 status_code.push(parseInt($(this).attr('code')));
137 // If this is an initial presence (when user join the room)
138 if(exists('#' + xidHash + '[data-initial=true]'))
141 // If one user is quitting
142 if(type && (type == 'unavailable')) {
143 displayMucPresence(from, xidHash, hash, type, show, status, affiliation, role, reason, status_code, iXID, iNick, messageTime, nick, notInitial);
145 removeDB('presence', from);
148 // If one user is joining
150 // Fixes M-Link first presence bug (missing ID!)
151 if((nick == getMUCNick(xidHash)) && (presence.getID() == null) && !exists('#page-engine #' + xidHash + ' .list .' + hash)) {
154 logThis('Passed M-Link MUC first presence handling.', 2);
158 displayMucPresence(from, xidHash, hash, type, show, status, affiliation, role, reason, status_code, iXID, iNick, messageTime, nick, notInitial);
160 var xml = '<presence from="' + encodeQuotes(from) + '"><priority>' + priority.htmlEnc() + '</priority><show>' + show.htmlEnc() + '</show><type>' + type.htmlEnc() + '</type><status>' + status.htmlEnc() + '</status><avatar>' + hasPhoto.htmlEnc() + '</avatar><checksum>' + checksum.htmlEnc() + '</checksum><caps>' + caps.htmlEnc() + '</caps></presence>';
162 setDB('presence', from, xml);
166 // Manage the presence
167 presenceFunnel(from, hash);
170 // This presence comes from an user or a gateway
172 // Subscribed & unsubscribed stanzas
173 if((type == 'subscribed') || (type == 'unsubscribed'))
177 else if(type == 'subscribe') {
178 // This is a buddy we can safely authorize, because we added him to our roster
179 if(exists('#buddy-list .buddy[data-xid=' + escape(xid) + ']'))
180 acceptSubscribe(xid);
182 // We do not know this entity, we'd be better ask the user
185 var nickname = $(node).find('nick[xmlns=' + NS_NICK + ']:first').text();
188 newNotification('subscribe', xid, [xid, nickname], status);
192 // Unsubscribe stanza
193 else if(type == 'unsubscribe')
194 sendRoster(xid, 'remove');
198 // Unavailable/error presence
199 if(type == 'unavailable')
200 removeDB('presence', from);
202 // Other presence (available, subscribe...)
204 var xml = '<presence from="' + encodeQuotes(from) + '"><priority>' + priority.htmlEnc() + '</priority><show>' + show.htmlEnc() + '</show><type>' + type.htmlEnc() + '</type><status>' + status.htmlEnc() + '</status><avatar>' + hasPhoto.htmlEnc() + '</avatar><checksum>' + checksum.htmlEnc() + '</checksum><caps>' + caps.htmlEnc() + '</caps></presence>';
206 setDB('presence', from, xml);
209 // We manage the presence
210 presenceFunnel(xid, xidHash);
212 // We display the presence in the current chat
213 if(exists('#' + xidHash)) {
214 var dStatus = filterStatus(xid, status, false);
217 dStatus = ' (' + dStatus + ')';
219 // Generate the presence-in-chat code
220 var dName = getBuddyName(from).htmlEnc();
221 var dBody = dName + ' (' + from + ') ' + _e("is now") + ' ' + humanShow(show, type) + dStatus;
223 // Check whether it has been previously displayed
224 var can_display = true;
226 if($('#' + xidHash + ' .one-line.system-message:last').html() == dBody)
230 displayMessage('chat', xid, xidHash, dName, dBody, getCompleteTime(), getTimeStamp(), 'system-message', false);
240 show = 'unavailable';
243 logThis('Presence received: ' + show + ', from ' + from);
246 // Displays a MUC presence
247 function displayMucPresence(from, roomHash, hash, type, show, status, affiliation, role, reason, status_code, iXID, iNick, messageTime, nick, initial) {
248 // Generate the values
249 var thisUser = '#page-engine #' + roomHash + ' .list .' + hash;
250 var thisPrivate = $('#' + hash + ' .message-area');
251 var nick_html = nick.htmlEnc();
253 var write = nick_html + ' ';
258 role = 'participant';
260 affiliation = 'none';
262 // Must update the role?
263 if(exists(thisUser) && (($(thisUser).attr('data-role') != role) || ($(thisUser).attr('data-affiliation') != affiliation)))
264 $(thisUser).remove();
266 // Any XID submitted?
268 real_xid = ' data-realxid="' + iXID + '"';
269 iXID = bareXID(iXID);
270 write += ' (<a onclick="return checkChatCreate(\'' + encodeOnclick(iXID) + '\', \'chat\');" href="xmpp:' + encodeOnclick(iXID) + '">' + iXID + '</a>) ';
273 // User does not exists yet
274 if(!exists(thisUser) && (!type || (type == 'available'))) {
278 if(nick == getMUCNick(roomHash)) {
280 $('#' + roomHash + ' .message-area').removeAttr('disabled');
286 // Set the user in the MUC list
287 $('#' + roomHash + ' .list .' + role + ' .title').after(
288 '<div class="user ' + hash + myself + '" data-xid="' + encodeQuotes(from) + '" data-nick="' + escape(nick) + '"' + real_xid + ' data-role="' + encodeQuotes(role) + '" data-affiliation="' + encodeQuotes(affiliation) + '">' +
289 '<div class="name talk-images available">' + nick_html + '</div>' +
291 '<div class="avatar-container">' +
292 '<img class="avatar" src="' + './img/others/default-avatar.png' + '" alt="" />' +
298 if(nick != getMUCNick(roomHash))
299 $(thisUser).live('click', function() {
300 checkChatCreate(from, 'private');
303 // We tell the user that someone entered the room
306 write += _e("joined the chat room");
310 write += ' (' + filterThisMessage(status, nick_html, true) + ')';
312 write += ' (' + _e("no status") + ')';
315 // Enable the private chat input
316 thisPrivate.removeAttr('disabled');
319 else if((type == 'unavailable') || (type == 'error')) {
321 if(nick == getMUCNick(roomHash)) {
322 $(thisUser).remove();
324 // Disable the groupchat input
325 $('#' + roomHash + ' .message-area').attr('disabled', true);
327 // Remove all the groupchat users
328 $('#' + roomHash + ' .list .user').remove();
331 // Someone has been kicked or banned?
332 if(existArrayValue(status_code, 301) || existArrayValue(status_code, 307)) {
333 $(thisUser).remove();
337 if(existArrayValue(status_code, 307))
338 write += _e("has been kicked");
341 if(existArrayValue(status_code, 301))
342 write += _e("has been banned");
346 write += ' (' + filterThisMessage(reason, nick_html, true) + ')';
348 write += ' (' + _e("no reason") + ')';
352 else if(existArrayValue(status_code, 303) && iNick) {
354 write += printf(_e("changed his/her nickname to %s"), iNick.htmlEnc());
357 var new_xid = cutResource(from) + '/' + iNick;
358 var new_hash = hex_md5(new_xid);
359 var new_class = 'user ' + new_hash;
361 if($(thisUser).hasClass('myself'))
362 new_class += ' myself';
364 // Die the click event
365 $(thisUser).die('click');
367 // Change to the new nickname
368 $(thisUser).attr('data-nick', iNick)
369 .attr('data-xid', new_xid)
370 .find('.name').text(iNick);
372 // Change the user class
373 $(thisUser).attr('class', new_class);
376 $('#page-engine #' + roomHash + ' .list .' + new_hash).live('click', function() {
377 checkChatCreate(new_xid, 'private');
381 // We tell the user that someone left the room
383 $(thisUser).remove();
385 write += _e("left the chat room");
389 write += ' (' + filterThisMessage(status, nick_html, true) + ')';
391 write += ' (' + _e("no status") + ')';
394 // Disable the private chat input
395 thisPrivate.attr('disabled', true);
398 // Must notify something
400 displayMessage('groupchat', from, roomHash, nick_html, write, messageTime, getTimeStamp(), 'system-message', false);
402 // Set the good status show icon
415 $(thisUser + ' .name').attr('class', 'name talk-images ' + show);
417 // Set the good status text
422 uTitle += ' (' + iXID + ')';
424 // Any status to add?
426 uTitle += ' - ' + status;
428 $(thisUser).attr('title', uTitle);
430 // Show or hide the role category, depending of its content
431 $('#' + roomHash + ' .list .role').each(function() {
432 if($(this).find('.user').size())
439 // Filters a given status
440 function filterStatus(xid, status, cut) {
448 dStatus = truncate(status, 50);
452 dStatus = filterThisMessage(dStatus, getBuddyName(xid).htmlEnc(), true);
458 // Displays a user's presence
459 function displayPresence(value, type, show, status, hash, xid, avatar, checksum, caps) {
460 // Display the presence in the roster
461 var path = '#buddy-list .' + hash;
462 var buddy = $('#buddy-list .content .' + hash);
463 var dStatus = filterStatus(xid, status, false);
464 var tStatus = encodeQuotes(status);
467 // The buddy presence behind his name
468 $(path + ' .name .buddy-presence').replaceWith('<p class="buddy-presence talk-images ' + type + '">' + value + '</p>');
470 // The buddy presence in the buddy infos
476 $(path + ' .bi-status').replaceWith('<p class="bi-status talk-images ' + type + '" title="' + tStatus + '">' + biStatus + '</p>');
478 // When the buddy disconnect himself, we hide him
479 if((type == 'unavailable') || (type == 'error')) {
480 // Set a special class to the buddy
481 buddy.addClass('hidden-buddy');
483 // No filtering is launched?
487 // All the buddies are shown?
492 if(exists('#' + hash)) {
493 // Remove the chatstate stuffs
494 resetChatState(hash);
495 $('#' + hash + ' .chatstate').remove();
496 $('#' + hash + ' .message-area').removeAttr('data-chatstates');
498 // Get the buddy avatar (only if a chat is opened)
499 getAvatar(xid, 'cache', 'true', 'forget');
503 // If the buddy is online
505 // When the buddy is online, we show it
506 buddy.removeClass('hidden-buddy');
508 // No filtering is launched?
512 // Get the online buddy avatar if not a gateway
513 getAvatar(xid, 'cache', avatar, checksum);
516 // Display the presence in the chat
517 if(exists('#' + hash)) {
518 // We generate a well formed status message
520 // No need to write the same status two times
524 dStatus = ' (' + dStatus + ')';
527 // We show the presence value
528 $('#' + hash + ' .bc-infos').replaceWith('<p class="bc-infos" title="' + tStatus + '"><span class="' + type + ' show talk-images">' + value + '</span>' + dStatus + '</p>');
530 // Process the new status position
531 adaptChatPresence(hash);
533 // Get the disco#infos for this user
534 var highest = getHighestResource(xid);
537 getDiscoInfos(highest, caps);
539 displayDiscoInfos(xid, '');
542 // Display the presence in the switcher
543 if(exists('#page-switch .' + hash))
544 $('#page-switch .' + hash + ' .icon').removeClass('available unavailable error away busy').addClass(type);
546 // Update roster groups
550 funnelFilterBuddySearch();
553 // Process the chat presence position
554 function adaptChatPresence(hash) {
556 var pep_numb = $('#' + hash + ' .bc-pep').find('a').size();
558 // Process the right position
559 var presence_right = 12;
562 presence_right = (pep_numb * 20) + 18;
564 // Apply the right position
565 $('#' + hash + ' p.bc-infos').css('right', presence_right);
568 // Convert the presence "show" element into a human-readable output
569 function humanShow(show, type) {
570 if(type == 'unavailable')
571 show = _e("Unavailable");
573 else if(type == 'error')
579 show = _e("Talkative");
587 show = _e("Not available");
595 show = _e("Available");
603 // Makes the presence data go in the right way
604 function presenceIA(type, show, status, hash, xid, avatar, checksum, caps) {
605 // Is there a status defined?
607 status = humanShow(show, type);
609 // Then we can handle the events
611 displayPresence(_e("Error"), 'error', show, status, hash, xid, avatar, checksum, caps);
613 else if(type == 'unavailable')
614 displayPresence(_e("Unavailable"), 'unavailable', show, status, hash, xid, avatar, checksum, caps);
619 displayPresence(_e("Talkative"), 'available', show, status, hash, xid, avatar, checksum, caps);
623 displayPresence(_e("Away"), 'away', show, status, hash, xid, avatar, checksum, caps);
627 displayPresence(_e("Not available"), 'busy', show, status, hash, xid, avatar, checksum, caps);
631 displayPresence(_e("Busy"), 'busy', show, status, hash, xid, avatar, checksum, caps);
635 displayPresence(_e("Available"), 'available', show, status, hash, xid, avatar, checksum, caps);
641 // Gets the highest resource priority for an user
642 function highestPriority(xid) {
644 var selector, priority, type, highest;
646 // This is a groupchat presence
647 if(xid.indexOf('/') != -1)
648 highest = XMLFromString(getDB('presence', xid));
650 // This is a "normal" presence: get the highest priority resource
652 for(var i = 0; i < sessionStorage.length; i++) {
653 // Get the pointer values
654 var current = sessionStorage.key(i);
656 // If the pointer is on a stored presence
657 if(explodeThis('_', current, 0) == 'presence') {
658 // Get the current XID
659 var now = bareXID(explodeThis('_', current, 1));
661 // If the current XID equals the asked XID
663 var xml = XMLFromString(sessionStorage.getItem(current));
664 var priority = parseInt($(xml).find('priority').text());
667 if((priority >= maximum) || (maximum == null)) {
676 // The user might be offline if no highest
678 highest = XMLFromString('<presence><type>unavailable</type></presence>');
683 // Gets the resource from a XID which has the highest priority
684 function getHighestResource(xid) {
685 var xml = $(highestPriority(xid));
686 var highest = xml.find('presence').attr('from');
687 var type = xml.find('type').text();
689 // If the use is online, we can return its highest resource
690 if(!type || (type == 'available') || (type == 'null'))
696 // Makes something easy to process for the presence IA
697 function presenceFunnel(xid, hash) {
698 // Get the highest priority presence value
699 var xml = $(highestPriority(xid));
700 var type = xml.find('type').text();
701 var show = xml.find('show').text();
702 var status = xml.find('status').text();
703 var avatar = xml.find('avatar').text();
704 var checksum = xml.find('checksum').text();
705 var caps = xml.find('caps').text();
707 // Display the presence with that stored value
709 presenceIA('', 'available', status, hash, xid, avatar, checksum, caps);
711 presenceIA(type, show, status, hash, xid, avatar, checksum, caps);
714 // Sends a defined presence packet
715 function sendPresence(to, type, show, status, checksum, limit_history, password, handle) {
717 var priority = getDB('priority', 1);
722 checksum = getDB('checksum', 1);
723 if(show == 'available')
725 if(type == 'available')
729 var presence = new JSJaCPresence();
731 // Avoid "null" or "none" if nothing stored
732 if(!checksum || (checksum == 'none'))
739 presence.setType(type);
741 presence.setShow(show);
743 presence.setStatus(status);
745 presence.setPriority(priority);
747 // CAPS (entity capabilities)
748 presence.appendNode('c', {'xmlns': NS_CAPS, 'hash': 'sha-1', 'node': 'https://www.jappix.com/', 'ver': myCaps()});
751 var nickname = getName();
754 presence.appendNode('nick', {'xmlns': NS_NICK}, nickname);
756 // vcard-temp:x:update node
757 var x = presence.appendNode('x', {'xmlns': NS_VCARD_P});
758 x.appendChild(presence.buildNode('photo', {'xmlns': NS_VCARD_P}, checksum));
761 if(limit_history || password) {
762 var xMUC = presence.appendNode('x', {'xmlns': NS_MUC});
764 // Max messages age (for MUC)
766 xMUC.appendChild(presence.buildNode('history', {'maxstanzas': 20, 'seconds': 86400, 'xmlns': NS_MUC}));
770 xMUC.appendChild(presence.buildNode('password', {'xmlns': NS_MUC}, password));
773 // If away, send a last activity time
774 if((show == 'away') || (show == 'xa')) {
775 /* REF: http://xmpp.org/extensions/xep-0256.html */
777 presence.appendNode(presence.buildNode('query', {
779 'seconds': getPresenceLast()
783 // Else, set a new last activity stamp
785 PRESENCE_LAST_ACTIVITY = getTimeStamp();
787 // Send the presence packet
789 con.send(presence, handle);
796 logThis('Presence sent: ' + type, 3);
799 // Performs all the actions to get the presence data
800 function presenceSend(checksum, autoidle) {
801 // We get the values of the inputs
802 var show = getUserShow();
803 var status = getUserStatus();
807 sendPresence('', '', show, status, checksum);
809 // We set the good icon
812 // We store our presence
814 setDB('presence-show', 1, show);
816 // We send the presence to our active MUC
817 $('.page-engine-chan[data-type=groupchat]').each(function() {
818 var tmp_nick = $(this).attr('data-nick');
823 var room = unescape($(this).attr('data-xid'));
824 var nick = unescape(tmp_nick);
826 // Must re-initialize?
831 else if(!$(this).find('.message-area').attr('disabled'))
832 sendPresence(room + '/' + nick, '', show, status, '', true);
836 // Changes the presence icon
837 function presenceIcon(value) {
838 $('#my-infos .f-presence a.picker').attr('data-value', value);
841 // Sends a subscribe stanza
842 function sendSubscribe(to, type) {
845 // Subscribe request?
846 if(type == 'subscribe')
847 status = printf(_e("Hi, I am %s, I would like to add you as my friend."), getName());
849 sendPresence(to, type, '', status);
852 // Accepts the subscription from another entity
853 function acceptSubscribe(xid, name) {
854 // We update our chat
855 $('#' + hex_md5(xid) + ' .tools-add').hide();
857 // We send a subsribed presence (to confirm)
858 sendSubscribe(xid, 'subscribed');
860 // We send a subscription request (subscribe both sides)
861 sendSubscribe(xid, 'subscribe');
863 // Specify the buddy name (if any)
865 sendRoster(xid, '', name)
868 // Sends automatic away presence
869 var AUTO_IDLE = false;
871 function autoIdle() {
876 // Stop if an xa presence was set manually
877 var last_presence = getUserShow();
879 if(!AUTO_IDLE && ((last_presence == 'away') || (last_presence == 'xa')))
885 // Can we extend to auto extended away mode (20 minutes)?
886 if(AUTO_IDLE && (last_presence == 'away')) {
887 idle_presence = 'xa';
888 activity_limit = 1200;
891 // We must set the user to auto-away (10 minutes)
893 idle_presence = 'away';
894 activity_limit = 600;
897 // The user is really inactive and has set another presence than extended away
898 if(((!AUTO_IDLE && (last_presence != 'away')) || (AUTO_IDLE && (last_presence == 'away'))) && (getLastActivity() >= activity_limit)) {
899 // Then tell we use an auto presence
902 // Get the old status message
903 var status = getDB('options', 'presence-status');
908 // Change the presence input
909 $('#my-infos .f-presence a.picker').attr('data-value', idle_presence);
910 $('#presence-status').val(status);
912 // Then send the xa presence
913 presenceSend('', true);
915 logThis('Auto-idle presence sent: ' + idle_presence, 3);
919 // Restores the old presence on a document bind
920 function eventIdle() {
921 // If we were idle, restore our old presence
924 var show = getDB('presence-show', 1);
925 var status = getDB('options', 'presence-status');
927 // Change the presence input
928 $('#my-infos .f-presence a.picker').attr('data-value', show);
929 $('#presence-status').val(status);
930 $('#presence-status').placeholder();
932 // Then restore the old presence
933 presenceSend('', true);
938 logThis('Presence restored: ' + show, 3);
943 LAST_ACTIVITY = getTimeStamp();
946 // Lives the auto idle functions
947 function liveIdle() {
948 // Apply the autoIdle function every minute
950 $('#my-infos .f-presence').everyTime('30s', autoIdle);
952 // On body bind (click & key event)
953 $('body').live('mousedown', eventIdle)
954 .live('mousemove', eventIdle)
955 .live('keydown', eventIdle);
958 // Kills the auto idle functions
960 // Remove the event detector
961 $('body').die('mousedown', eventIdle)
962 .die('mousemove', eventIdle)
963 .die('keydown', eventIdle);
966 // Gets the user presence show
967 function getUserShow() {
968 return $('#my-infos .f-presence a.picker').attr('data-value');
971 // Gets the user presence status
972 function getUserStatus() {
973 return $('#presence-status').val();
977 function launchPresence() {
978 // Click event for user presence show
979 $('#my-infos .f-presence a.picker').click(function() {
981 if($(this).hasClass('disabled'))
984 // Initialize some vars
985 var path = '#my-infos .f-presence div.bubble';
986 var show_id = ['xa', 'away', 'available'];
987 var show_lang = [_e("Not available"), _e("Away"), _e("Available")];
988 var show_val = getUserShow();
991 var can_append = true;
1002 // Generate the HTML code
1003 var html = '<div class="bubble removable">';
1006 // Yet in use: no need to display it!
1007 if(show_id[i] == show_val)
1010 html += '<a href="#" class="talk-images" data-value="' + show_id[i] + '" title="' + show_lang[i] + '"></a>';
1015 // Append the HTML code
1016 $('#my-infos .f-presence').append(html);
1019 $(path + ' a').click(function() {
1020 // Update the presence show marker
1021 $('#my-infos .f-presence a.picker').attr('data-value', $(this).attr('data-value'));
1026 // Focus on the status input
1027 $(document).oneTime(10, function() {
1028 $('#presence-status').focus();
1037 // Submit events for user presence status
1038 $('#presence-status').placeholder()
1040 .keyup(function(e) {
1041 if(e.keyCode == 13) {
1049 // Read the parameters
1050 var show = getUserShow();
1051 var status = getUserStatus();
1053 // Read the old parameters
1054 var old_show = getDB('presence-show', 1);
1055 var old_status = getDB('options', 'presence-status');
1057 // Must send the presence?
1058 if((show != old_show) || (status != old_status)) {
1059 // Update the local stored status
1060 setDB('options', 'presence-status', status);
1062 // Update the server stored status
1063 if(status != old_status)
1066 // Send the presence
1071 // Input focus handler