]> git.mxchange.org Git - friendica-addons.git/blob - jappixmini/jappix/js/message.js
Merge branch '3.6-rc'
[friendica-addons.git] / jappixmini / jappix / js / message.js
1 /*
2
3 Jappix - An open social platform
4 These are the messages JS scripts for Jappix
5
6 -------------------------------------------------
7
8 License: AGPL
9 Authors: Vanaryon, Maranda
10 Last revision: 01/09/11
11
12 */
13
14 // Handles the incoming message packets
15 function handleMessage(message) {
16         // Error packet? Stop!
17         if(handleErrorReply(message))
18                 return;
19         
20         // We get the message items
21         var from = fullXID(getStanzaFrom(message));
22         var id = message.getID();
23         var type = message.getType();
24         var body = trim(message.getBody());
25         var node = message.getNode();
26         var subject = trim(message.getSubject());
27         
28         // We generate some values
29         var xid = bareXID(from);
30         var resource = thisResource(from);
31         var hash = hex_md5(xid);
32         var xHTML = $(node).find('html body').size();
33         var GCUser = false;
34         
35         // This message comes from a groupchat user
36         if(isPrivate(xid) && ((type == 'chat') || !type) && resource) {
37                 GCUser = true;
38                 xid = from;
39                 hash = hex_md5(xid);
40         }
41         
42         // Get message date
43         var time, stamp, d_stamp;
44         
45         // Read the delay
46         var delay = readMessageDelay(node);
47         
48         // Any delay?
49         if(delay) {
50                 time = relativeDate(delay);
51                 d_stamp = Date.jab2date(delay);
52         }
53         
54         // No delay: get actual time
55         else {
56                 time = getCompleteTime();
57                 d_stamp = new Date();
58         }
59         
60         // Get the date stamp
61         stamp = extractStamp(d_stamp);
62         
63         // Received message
64         if(hasReceived(message))
65                 return messageReceived(hash, id);
66         
67         // Chatstate message
68         if(node && !delay && ((((type == 'chat') || !type) && !exists('#page-switch .' + hash + ' .unavailable')) || (type == 'groupchat'))) {
69                 /* REF: http://xmpp.org/extensions/xep-0085.html */
70                 
71                 // Re-process the hash
72                 var chatstate_hash = hash;
73                 
74                 if(type == 'groupchat')
75                         chatstate_hash = hex_md5(from);
76                 
77                 // Do something depending of the received state
78                 if($(node).find('active').size()) {
79                         displayChatState('active', chatstate_hash, type);
80                         
81                         // Tell Jappix the entity supports chatstates
82                         $('#' + chatstate_hash + ' .message-area').attr('data-chatstates', 'true');
83                         
84                         logThis('Active chatstate received from: ' + from);
85                 }
86                 
87                 else if($(node).find('composing').size())
88                         displayChatState('composing', chatstate_hash, type);
89                 
90                 else if($(node).find('paused').size())
91                         displayChatState('paused', chatstate_hash, type);
92                 
93                 else if($(node).find('inactive').size())
94                         displayChatState('inactive', chatstate_hash, type);
95                 
96                 else if($(node).find('gone').size())
97                         displayChatState('gone', chatstate_hash, type);
98         }
99         
100         // Invite message
101         if($(node).find('x[xmlns=' + NS_MUC_USER + '] invite').size()) {
102                 // We get the needed values
103                 var iFrom = $(node).find('x[xmlns=' + NS_MUC_USER + '] invite').attr('from');
104                 var iRoom = $(node).find('x[xmlns=' + NS_XCONFERENCE + ']').attr('jid');
105                 
106                 // Old invite method?
107                 if(!iRoom)
108                         iRoom = from;
109                 
110                 // We display the notification
111                 newNotification('invite_room', iFrom, [iRoom], body);
112                 
113                 logThis('Invite Request from: ' + iFrom + ' to join: ' + iRoom);
114                 
115                 return false;
116         }
117         
118         // Request message
119         if(message.getChild('confirm', NS_HTTP_AUTH)) {
120                 // Open a new notification
121                 newNotification('request', xid, [message], body);
122                 
123                 logThis('HTTP Request from: ' + xid);
124                 
125                 return false;
126         }
127         
128         // OOB message
129         if(message.getChild('x', NS_XOOB)) {
130                 handleOOB(from, id, 'x', node);
131                 
132                 logThis('Message OOB request from: ' + xid);
133                 
134                 return false;
135         }
136         
137         // Roster Item Exchange message
138         if(message.getChild('x', NS_ROSTERX)) {
139                 // Open a new notification
140                 newNotification('rosterx', xid, [message], body);
141                 
142                 logThis('Roster Item Exchange from: ' + xid);
143                 
144                 return false;
145         }
146         
147         // Normal message
148         if((type == 'normal') && body) {
149                 // Message date
150                 var messageDate = delay;
151                 
152                 // No message date?
153                 if(!messageDate)
154                         messageDate = getXMPPTime('utc');
155                 
156                 // Message ID
157                 var messageID = hex_md5(xid + subject + messageDate);
158                 
159                 // We store the received message
160                 storeInboxMessage(xid, subject, body, 'unread', messageID, messageDate);
161                 
162                 // Display the inbox message
163                 if(exists('#inbox'))
164                         displayInboxMessage(xid, subject, body, 'unread', messageID, messageDate);
165                 
166                 // Check we have new messages (play a sound if any unread messages)
167                 if(checkInboxMessages())
168                         soundPlay(2);
169                 
170                 // Send it to the server
171                 storeInbox();
172                 
173                 return false;
174         }
175         
176         // PubSub event
177         if($(node).find('event').attr('xmlns') == NS_PUBSUB_EVENT) {
178                 // We get the needed values
179                 var iParse = $(node).find('event items');
180                 var iNode = iParse.attr('node');
181                 
182                 // Turn around the different result cases
183                 if(iNode) {
184                         switch(iNode) {
185                                 // Mood
186                                 case NS_MOOD:
187                                         // Retrieve the values
188                                         var iMood = iParse.find('mood');
189                                         var fValue = '';
190                                         var tText = '';
191                                         
192                                         // There's something
193                                         if(iMood.children().size()) {
194                                                 // Read the value
195                                                 fValue = node.getElementsByTagName('mood').item(0).childNodes.item(0).nodeName;
196                                                 
197                                                 // Read the text
198                                                 tText = iMood.find('text').text();
199                                                 
200                                                 // Avoid errors
201                                                 if(!fValue)
202                                                         fValue = '';
203                                         }
204                                         
205                                         // Store the PEP event (and display it)
206                                         storePEP(xid, 'mood', fValue, tText);
207                                         
208                                         break;
209                                 
210                                 // Activity
211                                 case NS_ACTIVITY:
212                                         // Retrieve the values
213                                         var iActivity = iParse.find('activity');
214                                         var sValue = '';
215                                         var tText = '';
216                                         
217                                         // There's something
218                                         if(iActivity.children().size()) {
219                                                 // Read the value
220                                                 fValue = node.getElementsByTagName('activity').item(0).childNodes.item(0).nodeName;
221                                                 
222                                                 // Read the text
223                                                 tText = iActivity.find('text').text();
224                                                 
225                                                 // Avoid errors
226                                                 if(!fValue)
227                                                         fValue = '';
228                                         }
229                                         
230                                         // Store the PEP event (and display it)
231                                         storePEP(xid, 'activity', fValue, tText);
232                                         
233                                         break;
234                                 
235                                 // Tune
236                                 case NS_TUNE:
237                                         // Retrieve the values
238                                         var iTune = iParse.find('tune');
239                                         var tArtist = iTune.find('artist').text();
240                                         var tSource = iTune.find('source').text();
241                                         var tTitle = iTune.find('title').text();
242                                         var tURI = iTune.find('uri').text();
243                                         
244                                         // Store the PEP event (and display it)
245                                         storePEP(xid, 'tune', tArtist, tTitle, tSource, tURI);
246                                         
247                                         break;
248                                 
249                                 // Geolocation
250                                 case NS_GEOLOC:
251                                         // Retrieve the values
252                                         var iGeoloc = iParse.find('geoloc');
253                                         var tLat = iGeoloc.find('lat').text();
254                                         var tLon = iGeoloc.find('lon').text();
255                                         
256                                         // Any extra-values?
257                                         var tLocality = iGeoloc.find('locality').text();
258                                         var tRegion = iGeoloc.find('region').text();
259                                         var tCountry = iGeoloc.find('country').text();
260                                         var tHuman = humanPosition(tLocality, tRegion, tCountry);
261                                         
262                                         // Store the PEP event (and display it)
263                                         storePEP(xid, 'geoloc', tLat, tLon, tHuman);
264                                         
265                                         break;
266                                 
267                                 // Microblog
268                                 case NS_URN_MBLOG:
269                                         displayMicroblog(message, xid, hash, 'mixed', 'push');
270                                         
271                                         break;
272                                 
273                                 // Inbox
274                                 case NS_URN_INBOX:
275                                         // Do not handle friend's notifications
276                                         if(xid == getXID())
277                                                 handleNotifications(message);
278                                         
279                                         break;
280                         }
281                 }
282                 
283                 return false;
284         }
285         
286         // If this is a room topic message
287         if(subject && (type == 'groupchat')) {
288                 // Filter the vars
289                 var filter_subject = subject.replace(/\n+/g, ' ');
290                 var filteredSubject = filterThisMessage(filter_subject, resource, true);
291                 var filteredName = resource.htmlEnc();
292                 
293                 // Display the new subject at the top
294                 $('#' + hash + ' .top .name .bc-infos .muc-topic').replaceWith('<span class="muc-topic" title="' + filter_subject + '">' + filteredSubject + '</span>');
295                 
296                 // Display the new subject as a system message
297                 if(resource) {
298                         var topic_body = filteredName + ' ' + _e("changed the subject to:") + ' ' + filterThisMessage(subject, resource, true);
299                         displayMessage(type, from, hash, filteredName, topic_body, time, stamp, 'system-message', false);
300                 }
301         }
302         
303         // If the message has a content
304         if(xHTML || body) {
305                 var filteredMessage;
306                 var notXHTML = true;
307                 
308                 // IE bug fix
309                 if((BrowserDetect.browser == 'Explorer') && (BrowserDetect.version < 9))
310                         xHTML = 0;
311                 
312                 //If this is a xHTML message
313                 if(xHTML) {
314                         notXHTML = false;
315                         
316                         // Filter the xHTML message
317                         body = filterThisXHTML(node);
318                 }
319                 
320                 // Groupchat message
321                 if(type == 'groupchat') {
322                         /* REF: http://xmpp.org/extensions/xep-0045.html */
323                         
324                         // We generate the message type and time
325                         var message_type = 'user-message';
326                         
327                         // This is an old message
328                         if(delay && resource)
329                                 message_type = 'old-message';
330                         
331                         // This is a system message
332                         else if(!resource)
333                                 message_type = 'system-message';
334                         
335                         var nickQuote = '';
336                         
337                         // If this is not an old message
338                         if(message_type == 'user-message') {
339                                 var myNick = getMUCNick(hash);
340                                 
341                                 // If an user quoted our nick (with some checks)
342                                 var regex = new RegExp('((^)|( )|(@))' + escapeRegex(myNick) + '(($)|(:)|(,)|( ))', 'gi');
343                                 
344                                 if(body.match(regex) && (myNick != resource) && (message_type == 'user-message'))
345                                         nickQuote = ' my-nick';
346                                 
347                                 // We notify the user if there's a new personnal message
348                                 if(nickQuote) {
349                                         messageNotify(hash, 'personnal');
350                                         soundPlay(1);
351                                 }
352                                 
353                                 // We notify the user there's a new unread muc message
354                                 else
355                                         messageNotify(hash, 'unread');
356                         }
357                         
358                         // Display the received message
359                         displayMessage(type, from, hash, resource.htmlEnc(), body, time, stamp, message_type, notXHTML, nickQuote);
360                 }
361                 
362                 // Chat message
363                 else if((type == 'chat') || !type) {
364                         // Gets the nickname of the user
365                         var fromName = resource;
366                         var chatType = 'chat';
367                         
368                         // Must send a receipt notification?
369                         if(hasReceipt(message) && (id != null))
370                                 sendReceived(type, from, id);
371                         
372                         // It does not come from a groupchat user, get the full name
373                         if(!GCUser)
374                                 fromName = getBuddyName(xid);
375                         else
376                                 chatType = 'private';
377                         
378                         // If the chat isn't yet opened, open it !
379                         if(!exists('#' + hash)) {
380                                 // We create a new chat
381                                 chatCreate(hash, xid, fromName, chatType);
382                                 
383                                 // We tell the user that a new chat has started
384                                 soundPlay(0);
385                         }
386                         
387                         else
388                                 soundPlay(1);
389                         
390                         // Display the received message
391                         displayMessage(type, xid, hash, fromName.htmlEnc(), body, time, stamp, 'user-message', notXHTML, '', 'him');
392                         
393                         // We notify the user
394                         messageNotify(hash, 'personnal');
395                 }
396                 
397                 return false;
398         }
399         
400         return false;
401 }
402
403 // Sends a given message
404 function sendMessage(hash, type) {
405         // Get the values
406         var message_area = $('#' + hash + ' .message-area');
407         var body = trim(message_area.val());
408         var xid = unescape(message_area.attr('data-to'));
409         
410         // If the user didn't entered any message, stop
411         if(!body || !xid)
412                 return false;
413         
414         try {
415                 // We send the message through the XMPP network
416                 var aMsg = new JSJaCMessage();
417                 aMsg.setTo(xid);
418                 
419                 // Set an ID
420                 var id = genID();
421                 aMsg.setID(id);
422                 
423                 // /help shortcut
424                 if(body.match(/^\/help\s*(.*)/)) {
425                         // Help text
426                         var help_text = '<p class="help" xmlns="http://www.w3.org/1999/xhtml">';
427                         help_text += '<b>' + _e("Available shortcuts:") + '</b>';
428                         
429                         // Shortcuts array
430                         var shortcuts = [];
431                         
432                         // Common shortcuts
433                         shortcuts.push(printf(_e("%s removes the chat logs"), '<em>/clear</em>'));
434                         shortcuts.push(printf(_e("%s joins a groupchat"), '<em>/join jid</em>'));
435                         shortcuts.push(printf(_e("%s closes the chat"), '<em>/part</em>'));
436                         shortcuts.push(printf(_e("%s shows the user profile"), '<em>/whois jid</em>'));
437                         
438                         // Groupchat shortcuts
439                         if(type == 'groupchat') {
440                                 shortcuts.push(printf(_e("%s sends a message to the room"), '<em>/say message</em>'));
441                                 shortcuts.push(printf(_e("%s changes your nickname"), '<em>/nick nickname</em>'));
442                                 shortcuts.push(printf(_e("%s sends a message to someone in the room"), '<em>/msg nickname message</em>'));
443                                 shortcuts.push(printf(_e("%s changes the room topic"), '<em>/topic subject</em>'));
444                                 shortcuts.push(printf(_e("%s kicks an user of the room"), '<em>/kick nickname reason</em>'));
445                                 shortcuts.push(printf(_e("%s bans an user of the room"), '<em>/ban nickname reason</em>'));
446                                 shortcuts.push(printf(_e("%s invites someone to join the room"), '<em>/invite jid message</em>'));
447                         }
448                         
449                         // Generate the code from the array
450                         shortcuts = shortcuts.sort();
451                         
452                         for(s in shortcuts)
453                                 help_text += shortcuts[s] + '<br />';
454                         
455                         help_text += '</p>';
456                         
457                         // Display the message
458                         displayMessage(type, xid, hash, 'help', help_text, getCompleteTime(), getTimeStamp(), 'system-message', false);
459                         
460                         // Reset chatstate
461                         chatStateSend('active', xid, hash);
462                 }
463                 
464                 // /clear shortcut
465                 else if(body.match(/^\/clear/)) {
466                         cleanChat(hex_md5(xid));
467                         
468                         // Reset chatstate
469                         chatStateSend('active', xid, hash);
470                 }
471                 
472                 // /join shortcut
473                 else if(body.match(/^\/join (\S+)\s*(.*)/)) {
474                         // Join
475                         var room = generateXID(RegExp.$1, 'groupchat');
476                         var pass = RegExp.$2;
477                         
478                         checkChatCreate(room, 'groupchat');
479                         
480                         // Reset chatstate
481                         chatStateSend('active', xid, hash);
482                 }
483                 
484                 // /part shortcut
485                 else if(body.match(/^\/part\s*(.*)/) && (!isAnonymous() || (isAnonymous() && (xid != generateXID(ANONYMOUS_ROOM, 'groupchat')))))
486                         quitThisChat(xid, hex_md5(xid), type);
487                 
488                 // /whois shortcut
489                 else if(body.match(/^\/whois(( (\S+))|($))/)) {
490                         var whois_xid = RegExp.$3;
491                         
492                         // Groupchat WHOIS
493                         if(type == 'groupchat') {
494                                 var nXID = getMUCUserXID(xid, whois_xid);
495                                 
496                                 if(!nXID)
497                                         openThisInfo(6);
498                                 else
499                                         openUserInfos(nXID);
500                         }
501                         
502                         // Chat or private WHOIS
503                         else {
504                                 if(!whois_xid)
505                                         openUserInfos(xid);
506                                 else
507                                         openUserInfos(whois_xid);
508                         }
509                         
510                         // Reset chatstate
511                         chatStateSend('active', xid, hash);
512                 }
513                 
514                 // Chat message type
515                 else if(type == 'chat') {
516                         aMsg.setType('chat');
517                         
518                         // Generates the correct message depending of the choosen style
519                         var notXHTML = true;
520                         var genMsg = generateMessage(aMsg, body, hash);
521                         
522                         if(genMsg == 'XHTML')
523                                 notXHTML = false;
524                         
525                         // Receipt request
526                         var receipt_request = receiptRequest(hash);
527                         
528                         if(receipt_request)
529                                 aMsg.appendNode('request', {'xmlns': NS_URN_RECEIPTS});
530                         
531                         // Chatstate
532                         aMsg.appendNode('active', {'xmlns': NS_CHATSTATES});
533                         
534                         // Send it!
535                         con.send(aMsg, handleErrorReply);
536                         
537                         // Filter the xHTML message (for us!)
538                         if(!notXHTML)
539                                 body = filterThisXHTML(aMsg.getNode());
540                         
541                         // Finally we display the message we just sent
542                         var my_xid = getXID();
543                         
544                         displayMessage('chat', my_xid, hash, getBuddyName(my_xid).htmlEnc(), body, getCompleteTime(), getTimeStamp(), 'user-message', notXHTML, '', 'me', id);
545                         
546                         // Receipt timer
547                         if(receipt_request)
548                                 checkReceived(hash, id);
549                 }
550                 
551                 // Groupchat message type
552                 else if(type == 'groupchat') {
553                         // /say shortcut
554                         if(body.match(/^\/say (.+)/)) {
555                                 body = body.replace(/^\/say (.+)/, '$1');
556                                 
557                                 aMsg.setType('groupchat');
558                                 generateMessage(aMsg, body, hash);
559                                 
560                                 con.send(aMsg, handleErrorReply);
561                         }
562                         
563                         // /nick shortcut
564                         else if(body.match(/^\/nick (.+)/)) {
565                                 var nick = body.replace(/^\/nick (.+)/, '$1');
566                                 
567                                 // Does not exist yet?
568                                 if(!getMUCUserXID(xid, nick)) {
569                                         // Send a new presence
570                                         sendPresence(xid + '/' + nick, '', getUserShow(), getUserStatus(), '', false, false, handleErrorReply);
571                                         
572                                         // Change the stored nickname
573                                         $('#' + hex_md5(xid)).attr('data-nick', escape(nick));
574                                         
575                                         // Reset chatstate
576                                         chatStateSend('active', xid, hash);
577                                 }
578                         }
579                         
580                         // /msg shortcut
581                         else if(body.match(/^\/msg (\S+)\s+(.+)/)) {
582                                 var nick = RegExp.$1;
583                                 var body = RegExp.$2;
584                                 var nXID = getMUCUserXID(xid, nick);
585                                 
586                                 // We check if the user exists
587                                 if(!nXID)
588                                         openThisInfo(6);
589                                 
590                                 // If the private message is not empty
591                                 else if(body) {
592                                         aMsg.setType('chat');
593                                         aMsg.setTo(nXID);
594                                         generateMessage(aMsg, body, hash);
595                                         
596                                         con.send(aMsg, handleErrorReply);
597                                 }
598                         }
599                         
600                         // /topic shortcut
601                         else if(body.match(/^\/topic (.+)/)) {
602                                 var topic = body.replace(/^\/topic (.+)/, '$1');
603                                 
604                                 aMsg.setType('groupchat');
605                                 aMsg.setSubject(topic);
606                                 
607                                 con.send(aMsg, handleMessageError);
608                                 
609                                 // Reset chatstate
610                                 chatStateSend('active', xid, hash);
611                         }
612                         
613                         // /ban shortcut
614                         else if(body.match(/^\/ban (\S+)\s*(.*)/)) {
615                                 var nick = RegExp.$1;
616                                 var reason = RegExp.$2;
617                                 var nXID = getMUCUserRealXID(xid, nick);
618                                 
619                                 // We check if the user exists
620                                 if(!nXID)
621                                         openThisInfo(6);
622                                 
623                                 else {
624                                         // We generate the ban IQ
625                                         var iq = new JSJaCIQ();
626                                         iq.setTo(xid);
627                                         iq.setType('set');
628                                         
629                                         var iqQuery = iq.setQuery(NS_MUC_ADMIN);
630                                         var item = iqQuery.appendChild(iq.buildNode('item', {'affiliation': 'outcast', 'jid': nXID, 'xmlns': NS_MUC_ADMIN}));
631                                         
632                                         if(reason)
633                                                 item.appendChild(iq.buildNode('reason', {'xmlns': NS_MUC_ADMIN}, reason));
634                                         
635                                         con.send(iq, handleErrorReply);
636                                 }
637                                 
638                                 // Reset chatstate
639                                 chatStateSend('active', xid, hash);
640                         }
641                         
642                         // /kick shortcut
643                         else if(body.match(/^\/kick (\S+)\s*(.*)/)) {
644                                 var nick = RegExp.$1;
645                                 var reason = RegExp.$2;
646                                 var nXID = getMUCUserXID(xid, nick);
647                                 
648                                 // We check if the user exists
649                                 if(!nXID)
650                                         openThisInfo(6);
651                                 
652                                 else {
653                                         // We generate the kick IQ
654                                         var iq = new JSJaCIQ();
655                                         iq.setTo(xid);
656                                         iq.setType('set');
657                                         
658                                         var iqQuery = iq.setQuery(NS_MUC_ADMIN);
659                                         var item = iqQuery.appendChild(iq.buildNode('item', {'nick': nick, 'role': 'none', 'xmlns': NS_MUC_ADMIN}));
660                                         
661                                         if(reason)
662                                                 item.appendChild(iq.buildNode('reason', {'xmlns': NS_MUC_ADMIN}, reason));
663                                         
664                                         con.send(iq, handleErrorReply);
665                                 }
666                                 
667                                 // Reset chatstate
668                                 chatStateSend('active', xid, hash);
669                         }
670                         
671                         // /invite shortcut
672                         else if(body.match(/^\/invite (\S+)\s*(.*)/)) {
673                                 var i_xid = RegExp.$1;
674                                 var reason = RegExp.$2;
675                                 
676                                 var x = aMsg.appendNode('x', {'xmlns': NS_MUC_USER});
677                                 var aNode = x.appendChild(aMsg.buildNode('invite', {'to': i_xid, 'xmlns': NS_MUC_USER}));
678                                 
679                                 if(reason)
680                                         aNode.appendChild(aMsg.buildNode('reason', {'xmlns': NS_MUC_USER}, reason));
681                                 
682                                 con.send(aMsg, handleErrorReply);
683                                 
684                                 // Reset chatstate
685                                 chatStateSend('active', xid, hash);
686                         }
687                         
688                         // No shortcut, this is a message
689                         else {
690                                 aMsg.setType('groupchat');
691                                 
692                                 // Chatstate
693                                 aMsg.appendNode('active', {'xmlns': NS_CHATSTATES});
694                                 
695                                 generateMessage(aMsg, body, hash);
696                                 
697                                 con.send(aMsg, handleMessageError);
698                                 
699                                 logThis('Message sent to: ' + xid + ' / ' + type, 3);
700                         }
701                 }
702                 
703                 // We reset the message input
704                 $('#' + hash + ' .message-area').val('');
705         }
706         
707         finally {
708                 return false;
709         }
710 }
711
712 // Generates the correct message area style
713 function generateStyle(hash) {
714         // Initialize the vars
715         var styles = '#' + hash + ' div.bubble-style';
716         var checkbox = styles + ' input[type=checkbox]';
717         var color = styles + ' a.color.selected';
718         var style = '';
719         
720         // Loop the input values
721         $(checkbox).filter(':checked').each(function() {
722                 // If there is a previous element
723                 if(style)
724                         style += ' ';
725                 
726                 // Get the current style
727                 switch($(this).attr('class')) {
728                         case 'bold':
729                                 style += 'font-weight: bold;';
730                                 break;
731                         
732                         case 'italic':
733                                 style += 'font-style: italic;';
734                                 break;
735                         
736                         case 'underline':
737                                 style += 'text-decoration: underline;';
738                                 break;
739                 }
740         });
741         
742         // Get the color value
743         $(color).each(function() {
744                 style += 'color: #' + $(this).attr('data-color');
745         });
746         
747         return style;
748 }
749
750 // Generates the correct message code
751 function generateMessage(aMsg, body, hash) {
752         // Create the classical body
753         aMsg.setBody(body);
754         
755         // Get the style
756         var style = $('#' + hash + ' .message-area').attr('style');
757         
758         // A message style is choosen
759         if(style) {
760                 // Explode the message body new lines (to create one <p /> element by line)
761                 var new_lines = new Array(body);
762                 
763                 if(body.match(/\n/))
764                         new_lines = body.split('\n');
765                 
766                 // Create the XML elements
767                 var aHtml = aMsg.appendNode('html', {'xmlns': NS_XHTML_IM});
768                 var aBody = aHtml.appendChild(aMsg.buildNode('body', {'xmlns': NS_XHTML}));
769                 
770                 // Use the exploded body array to create one element per entry
771                 for(i in new_lines) {
772                         // Current line
773                         var cLine = new_lines[i];
774                         
775                         // Blank line, we put a <br />
776                         if(cLine.match(/(^)(\s+)($)/) || !cLine)
777                                 aBody.appendChild(aMsg.buildNode('br', {'xmlns': NS_XHTML}));
778                         
779                         // Line with content, we put a <p />
780                         else {
781                                 // HTML encode the line
782                                 cLine = cLine.htmlEnc();
783                                 
784                                 // Filter the links
785                                 cLine = applyLinks(cLine, 'xhtml-im', style);
786                                 
787                                 // Append the filtered line
788                                 $(aBody).append($('<p style="' + style + '">' + cLine + '</p>'));
789                         }
790                 }
791                 
792                 return 'XHTML';
793         }
794         
795         return 'PLAIN';
796 }
797
798 // Displays a given message in a chat tab
799 function displayMessage(type, xid, hash, name, body, time, stamp, message_type, is_xhtml, nick_quote, mode, id) {
800         // Generate some stuffs
801         var has_avatar = false;
802         var xid_hash = '';
803         
804         if(!nick_quote)
805                 nick_quote = '';
806         
807         if(message_type != 'system-message') {
808                 has_avatar = true;
809                 xid_hash = hex_md5(xid);
810         }
811         
812         // Can scroll?
813         var cont_scroll = document.getElementById('chat-content-' + hash);
814         var can_scroll = false;
815         
816         if(!cont_scroll.scrollTop || ((cont_scroll.clientHeight + cont_scroll.scrollTop) == cont_scroll.scrollHeight))
817                 can_scroll = true;
818         
819         // Any ID?
820         var data_id = '';
821         
822         if(id)
823                 data_id = ' data-id="' + id + '"';
824         
825         // Filter the message
826         var filteredMessage = filterThisMessage(body, name, is_xhtml);
827         
828         // Display the received message in the room
829         var messageCode = '<div class="one-line ' + message_type + nick_quote + '"' + data_id + '>';
830         
831         // Name color attribute
832         if(type == 'groupchat')
833                 attribute = ' style="color: ' + generateColor(name) + ';" class="name';
834         else {
835                 attribute = ' class="name';
836                 
837                 if(mode)
838                         attribute += ' ' + mode;
839         }
840         
841         // Close the class attribute
842         if(message_type == 'system-message')
843                 attribute += ' hidden"';
844         else
845                 attribute += '"';
846         
847         // Filter the previous displayed message
848         var last = $('#' + hash + ' .one-group:last');
849         var last_name = last.find('b.name').attr('data-xid');
850         var last_type = last.attr('data-type');
851         var last_stamp = parseInt(last.attr('data-stamp'));
852         var grouped = false;
853         
854         // We can group it with another previous message
855         if((last_name == xid) && (message_type == last_type) && ((stamp - last_stamp) <= 1800))
856                 grouped = true;
857         
858         // Is it a /me command?
859         if(body.match(/(^|>)(\/me )([^<]+)/))
860                 filteredMessage = '<i>' + filteredMessage + '</i>';
861         
862         messageCode += filteredMessage + '</div>';
863         
864         // Must group it?
865         var group_path = ' .one-group:last';
866         
867         if(!grouped) {
868                 // Generate message headers
869                 var message_head = '';
870                 
871                 // Any avatar to add?
872                 if(has_avatar)
873                         message_head += '<div class="avatar-container"><img class="avatar" src="' + './img/others/default-avatar.png' + '" alt="" /></div>';
874                 
875                 // Add the date & the name
876                 message_head += '<span class="date">' + time + '</span><b data-xid="' + encodeQuotes(xid) + '" ' + attribute + '>' + name + '</b>';
877                 
878                 // Generate message code
879                 group_path = '';
880                 messageCode = '<div class="one-group ' + xid_hash + '" data-type="' + message_type + '" data-stamp="' + stamp + '">' + message_head + messageCode + '</div>';
881         }
882         
883         // Archive message
884         if(hash == 'archives')
885                 $('#archives .logs' + group_path).append(messageCode);
886         
887         // Instant message
888         else {
889                 // Write the code in the DOM
890                 $('#' + hash + ' .content' + group_path).append(messageCode);
891                 
892                 // Must get the avatar?
893                 if(has_avatar && xid)
894                         getAvatar(xid, 'cache', 'true', 'forget');
895         }
896         
897         // Scroll to this message
898         if(can_scroll)
899                 autoScroll(hash);
900 }