Merge M2Ys4U-joinfix
[KiwiIRC.git] / server / irc / commands.js
index 3903f320a78f6e40db0da4f9f27e1f0ec765df37..b17ec4f3a4bff2c49643075590637afe6d8249bf 100644 (file)
@@ -6,6 +6,15 @@ var irc_numerics = {
     RPL_ISUPPORT:           '005',
     RPL_MAPMORE:            '006',
     RPL_MAPEND:             '007',
+    RPL_STATSCONN:          '250',
+    RPL_LUSERCLIENT:        '251',
+    RPL_LUSEROP:            '252',
+    RPL_LUSERUNKNOWN:       '253',
+    RPL_LUSERCHANNELS:      '254',
+    RPL_LUSERME:            '255',
+    RPL_LOCALUSERS:         '265',
+    RPL_GLOBALUSERS:        '266',
+    RPL_AWAY:               '301',
     RPL_WHOISREGNICK:       '307',
     RPL_WHOISUSER:          '311',
     RPL_WHOISSERVER:        '312',
@@ -37,6 +46,7 @@ var irc_numerics = {
     ERR_NICKNAMEINUSE:      '433',
     ERR_USERNOTINCHANNEL:   '441',
     ERR_NOTONCHANNEL:       '442',
+    ERR_PASSWDMISMATCH:     '464',
     ERR_NOTREGISTERED:      '451',
     ERR_LINKCHANNEL:        '470',
     ERR_CHANNELISFULL:      '471',
@@ -87,7 +97,9 @@ var listeners = {
         var nick =  command.params[0];
         this.irc_connection.registered = true;
         this.cap_negotation = false;
-        this.client.sendIrcCommand('connect', {server: this.con_num, nick: nick});
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' connect', {
+            nick: nick
+        });
     },
     'RPL_ISUPPORT': function (command) {
         var options, i, option, matches, j;
@@ -114,68 +126,91 @@ var listeners = {
                 }
             }
         }
-        this.client.sendIrcCommand('options', {server: this.con_num, options: this.irc_connection.options, cap: this.irc_connection.cap.enabled});
+        this.irc_connection.emit('server '  + this.irc_connection.irc_host.hostname + ' options', {
+            options: this.irc_connection.options,
+            cap: this.irc_connection.cap.enabled
+        });
     },
     'RPL_ENDOFWHOIS': function (command) {
-        this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: true});
+        this.irc_connection.emit('user ' + command.params[1] + ' endofwhois', {
+            nick: command.params[1],
+            msg: command.trailing
+        });
+    },
+    'RPL_AWAY': function (command) {
+        this.irc_connection.emit('user ' + command.params[1] + ' whoisaway', {
+            nick: command.params[1],
+            reason: command.trailing
+        });
     },
     'RPL_WHOISUSER': function (command) {
-        this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], ident: command.params[2], host: command.params[3], msg: command.trailing, end: false});
+        this.irc_connection.emit('user ' + command.params[1] + ' whoisuser', {
+            nick: command.params[1],
+            ident: command.params[2],
+            host: command.params[3],
+            msg: command.trailing
+        });
     },
     'RPL_WHOISSERVER': function (command) {
-        this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], irc_server: command.params[2], end: false});
+        this.irc_connection.emit('user ' + command.params[1] + ' whoisserver', {
+            nick: command.params[1],
+            irc_server: command.params[2]
+        });
     },
     'RPL_WHOISOPERATOR': function (command) {
-        this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: false});
+        this.irc_connection.emit('user ' + command.params[1] + ' whoisoperator', {
+            nick: command.params[1],
+            msg: command.trailing
+        });
     },
     'RPL_WHOISCHANNELS':       function (command) {
-        this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], chans: command.trailing, end: false});
+        this.irc_connection.emit('user ' + command.params[1] + ' whoischannels', {
+            nick: command.params[1],
+            chans: command.trailing
+        });
     },
     'RPL_WHOISMODES': function (command) {
-        this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: false});
+        this.irc_connection.emit('user ' + command.params[1] + ' whoismodes', {
+            nick: command.params[1],
+            msg: command.trailing
+        });
     },
     'RPL_WHOISIDLE': function (command) {
-        if (command.params[3]) {
-            this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], idle: command.params[2], logon: command.params[3], end: false});
-        } else {
-            this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], idle: command.params[2], end: false});
-        }
+        this.irc_connection.emit('user ' + command.params[1] + ' whoisidle', {
+            nick: command.params[1],
+            idle: command.params[2],
+            logon: command.params[3] || undefined
+        });
     },
     'RPL_WHOISREGNICK': function (command) {
-        this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: false});
+        this.irc_connection.emit('user ' + command.params[1] + ' whoisregnick', {
+            nick: command.params[1],
+            msg: command.trailing
+        });
     },
     'RPL_LISTSTART': function (command) {
-        this.client.sendIrcCommand('list_start', {server: this.con_num});
-        this.client.buffer.list = [];
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' list_start', {});
     },
     'RPL_LISTEND': function (command) {
-        if (this.client.buffer.list.length > 0) {
-            this.client.buffer.list = _.sortBy(this.client.buffer.list, function (channel) {
-                return channel.num_users;
-            });
-            this.client.sendIrcCommand('list_channel', {server: this.con_num, chans: this.client.buffer.list});
-            this.client.buffer.list = [];
-        }
-        this.client.sendIrcCommand('list_end', {server: this.con_num});
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' list_end', {});
     },
     'RPL_LIST': function (command) {
-        this.client.buffer.list.push({server: this.con_num, channel: command.params[1], num_users: parseInt(command.params[2], 10), topic: command.trailing});
-        if (this.client.buffer.list.length > 200){
-            this.client.buffer.list = _.sortBy(this.client.buffer.list, function (channel) {
-                return channel.num_users;
-            });
-            this.client.sendIrcCommand('list_channel', {server: this.con_num, chans: this.client.buffer.list});
-            this.client.buffer.list = [];
-        }
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' list_channel', {
+            channel: command.params[1],
+            num_users: parseInt(command.params[2], 10),
+            topic: command.trailing
+        });
     },
     'RPL_MOTD': function (command) {
-        this.client.buffer.motd += command.trailing + '\n';
+        this.irc_connection.emit('server '  + this.irc_connection.irc_host.hostname + ' motd', {
+            motd: command.trailing + '\n'
+        });
     },
     'RPL_MOTDSTART': function (command) {
-        this.client.buffer.motd = '';
+        this.irc_connection.emit('server '  + this.irc_connection.irc_host.hostname + ' motd_start', {});
     },
     'RPL_ENDOFMOTD': function (command) {
-        this.client.sendIrcCommand('motd', {server: this.con_num, msg: this.client.buffer.motd});
+        this.irc_connection.emit('server '  + this.irc_connection.irc_host.hostname + ' motd_end', {});
     },
     'RPL_NAMEREPLY': function (command) {
         var members = command.trailing.split(' ');
@@ -200,7 +235,7 @@ var listeners = {
             member_list.push({nick: member, modes: modes});
         });
 
-        that.irc_connection.emit('channel:' + command.params[2] + ':userlist', {
+        this.irc_connection.emit('channel ' + command.params[2] + ' userlist', {
             users: member_list,
             channel: command.params[2]
         });
@@ -208,26 +243,43 @@ var listeners = {
 
     
     'RPL_ENDOFNAMES': function (command) {
-        that.irc_connection.emit('channel:' + command.params[1] + ':userlist_end', {
+        this.irc_connection.emit('channel ' + command.params[1] + ' userlist_end', {
             channel: command.params[1]
         });
     },
 
 
     'RPL_BANLIST': function (command) {
-        this.client.sendIrcCommand('banlist', {server: this.con_num, channel: command.params[1], banned: command.params[2], banned_by: command.params[3], banned_at: command.params[4]});
+        this.irc_connection.emit('channel ' + command.params[1] + ' banlist', {
+            channel: command.params[1],
+            banned: command.params[2],
+            banned_by: command.params[3],
+            banned_at: command.params[4]
+        });
     },
     'RPL_ENDOFBANLIST': function (command) {
-        this.client.sendIrcCommand('banlist_end', {server: this.con_num, channel: command.params[1]});
+        this.irc_connection.emit('channel ' + command.params[1] + ' banlist_end', {
+            channel: command.params[1]
+        });
     },
     'RPL_TOPIC': function (command) {
-        this.client.sendIrcCommand('topic', {server: this.con_num, nick: '', channel: command.params[1], topic: command.trailing});
+        this.irc_connection.emit('channel ' + command.params[1] + ' topic', {
+            channel: command.params[1],
+            topic: command.trailing
+        });
     },
     'RPL_NOTOPIC': function (command) {
-        this.client.sendIrcCommand('topic', {server: this.con_num, nick: '', channel: command.params[1], topic: ''});
+        this.irc_connection.emit('channel ' + command.params[1] + ' topic', {
+            channel: command.params[1],
+            topic: ''
+        });
     },
     'RPL_TOPICWHOTIME': function (command) {
-        this.client.sendIrcCommand('topicsetby', {server: this.con_num, nick: command.params[2], channel: command.params[1], when: command.params[3]});
+        this.irc_connection.emit('channel ' + command.params[1] + ' topicsetby', {
+            nick: command.params[2],
+            channel: command.params[1],
+            when: command.params[3]
+        });
     },
     'PING': function (command) {
         this.irc_connection.write('PONG ' + command.trailing);
@@ -242,7 +294,7 @@ var listeners = {
             channel = command.params[0];
         }
         
-        this.irc_connection.emit('channel:' + channel + ':join', {
+        this.irc_connection.emit('channel ' + channel + ' join', {
             nick: command.nick,
             ident: command.ident,
             hostname: command.hostname,
@@ -252,7 +304,7 @@ var listeners = {
 
 
     'PART': function (command) {
-        this.irc_connection.emit('channel:' + command.params[0] + ':part', {
+        this.irc_connection.emit('channel ' + command.params[0] + ' part', {
             nick: command.nick,
             ident: command.ident,
             hostname: command.hostname,
@@ -263,7 +315,7 @@ var listeners = {
 
 
     'KICK': function (command) {
-        this.irc_connection.emit('channel:' + command.params[0] + ':kick', {
+        this.irc_connection.emit('channel ' + command.params[0] + ' kick', {
             kicked: command.params[1],
             nick: command.nick,
             ident: command.ident,
@@ -275,7 +327,7 @@ var listeners = {
 
 
     'QUIT': function (command) {
-        this.irc_connection.emit('user:' + command.nick + ':quit', {
+        this.irc_connection.emit('user ' + command.nick + ' quit', {
             nick: command.nick,
             ident: command.ident,
             hostname: command.hostname,
@@ -290,7 +342,7 @@ var listeners = {
         if ((command.trailing.charAt(0) === String.fromCharCode(1)) && (command.trailing.charAt(command.trailing.length - 1) === String.fromCharCode(1))) {
             // It's a CTCP response
             namespace = (command.params[0] == this.irc_connection.nick) ? 'user' : 'channel';
-            this.irc_connection.emit(namespace + ':' + command.params[0] + ':ctcp_response', {
+            this.irc_connection.emit(namespace + ' ' + command.params[0] + ' ctcp_response', {
                 nick: command.nick,
                 ident: command.ident,
                 hostname: command.hostname,
@@ -298,9 +350,13 @@ var listeners = {
                 msg: command.trailing.substr(1, command.trailing.length - 2)
             });
         } else {
-            namespace = (command.params[0] == this.irc_connection.nick) ? 'user' : 'channel';
-            this.irc_connection.emit(namespace + ':' + command.params[0] + ':notice', {
-                nick: command.nick,
+            namespace = (command.params[0] == this.irc_connection.nick || command.params[0] == '*') ?
+                'user' :
+                'channel';
+
+            this.irc_connection.emit(namespace + ' ' + command.params[0] + ' notice', {
+                from_server: command.prefix ? true : false,
+                nick: command.nick || command.prefix || undefined,
                 ident: command.ident,
                 hostname: command.hostname,
                 target: command.params[0],
@@ -309,7 +365,12 @@ var listeners = {
         }
     },
     'NICK': function (command) {
-        this.client.sendIrcCommand('nick', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, newnick: command.trailing || command.params[0]});
+        this.irc_connection.emit('user ' + command.nick + ' nick', {
+            nick: command.nick,
+            ident: command.ident,
+            hostname: command.hostname,
+            newnick: command.trailing || command.params[0]
+        });
     },
     'TOPIC': function (command) {
         // If we don't have an associated channel, no need to continue
@@ -318,18 +379,18 @@ var listeners = {
         var channel = command.params[0],
             topic = command.trailing || '';
 
-        this.irc_connection.emit('channel:' + channel + ':topic', {
+        this.irc_connection.emit('channel ' + channel + ' topic', {
             nick: command.nick,
             channel: channel,
             topic: topic
         });
     },
-    'MODE': function (command) {                
+    'MODE': function (command) {
         var chanmodes = this.irc_connection.options.CHANMODES || [],
             prefixes = this.irc_connection.options.PREFIX || [],
             always_param = (chanmodes[0] || '').concat((chanmodes[1] || '')),
             modes = [],
-            has_param, i, j, add;
+            has_param, i, j, add, event;
         
         prefixes = _.reduce(prefixes, function (list, prefix) {
             list.push(prefix.mode);
@@ -373,8 +434,9 @@ var listeners = {
             }
         }
         
-        this.client.sendIrcCommand('mode', {
-            server: this.con_num,
+        event = (_.contains(this.irc_connection.options.CHANTYPES, command.params[0][0]) ? 'channel ' : 'user ') + command.params[0] + ' mode';
+        
+        this.irc_connection.emit(event, {
             target: command.params[0],
             nick: command.nick || command.prefix || '',
             modes: modes
@@ -397,8 +459,8 @@ var listeners = {
             } else if (command.trailing.substr(1, 10) === 'CLIENTINFO') {
                 this.irc_connection.write('NOTICE ' + command.nick + ' :' + String.fromCharCode(1) + 'CLIENTINFO SOURCE VERSION TIME' + String.fromCharCode(1));
             } else {
-                namespace = (command.target == this.irc_connection.nick) ? 'user' : 'channel';
-                this.irc_connection.emit(namespace + ':' + command.nick + ':ctcp_request', {
+                namespace = (command.params[0].toLowerCase() == this.irc_connection.nick.toLowerCase()) ? 'user' : 'channel';
+                this.irc_connection.emit(namespace + ' ' + command.nick + ' ctcp_request', {
                     nick: command.nick,
                     ident: command.ident,
                     hostname: command.hostname,
@@ -409,8 +471,8 @@ var listeners = {
             }
         } else {
             // A message to a user (private message) or to a channel?
-            namespace = (command.target == this.irc_connection.nick) ? 'user' : 'channel';
-            this.irc_connection.emit(namespace + ':' + command.nick + ':privmsg', {
+            namespace = (command.params[0] === this.irc_connection.nick) ? 'user ' + command.nick : 'channel ' + command.params[0];
+            this.irc_connection.emit(namespace + ' privmsg', {
                 nick: command.nick,
                 ident: command.ident,
                 hostname: command.hostname,
@@ -424,14 +486,17 @@ var listeners = {
         // i.e. - for disable, ~ for requires ACK, = for sticky
         var capabilities = command.trailing.replace(/[\-~=]/, '').split(' ');
         var request;
+
+        // Which capabilities we want to enable
         var want = ['multi-prefix', 'away-notify'];
-        
+
         if (this.irc_connection.password) {
             want.push('sasl');
         }
-        
+
         switch (command.params[1]) {
             case 'LS':
+                // Compute which of the available capabilities we want and request them
                 request = _.intersection(capabilities, want);
                 if (request.length > 0) {
                     this.irc_connection.cap.requested = request;
@@ -443,10 +508,12 @@ var listeners = {
                 break;
             case 'ACK':
                 if (capabilities.length > 0) {
+                    // Update list of enabled capabilities
                     this.irc_connection.cap.enabled = capabilities;
+                    // Update list of capabilities we would like to have but that aren't enabled
                     this.irc_connection.cap.requested = _.difference(this.irc_connection.cap.requested, capabilities);
                 }
-                if (this.irc_connection.cap.requested.length > 0) {
+                if (this.irc_connection.cap.enabled.length > 0) {
                     if (_.contains(this.irc_connection.cap.enabled, 'sasl')) {
                         this.irc_connection.sasl = true;
                         this.irc_connection.write('AUTHENTICATE PLAIN');
@@ -489,7 +556,10 @@ var listeners = {
         }
     },
     'AWAY': function (command) {
-        this.client.sendIrcCommand('away', {server: this.con_num, nick: command.nick, msg: command.trailing});
+        this.irc_connection.emit('user ' + command.nick + ' away', {
+            nick: command.nick,
+            msg: command.trailing
+        });
     },
     'RPL_SASLAUTHENTICATED': function (command) {
         this.irc_connection.write('CAP END');
@@ -513,43 +583,85 @@ var listeners = {
         // noop
     },
     'ERROR': function (command) {
-        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'error', reason: command.trailing});
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' error', {
+            reason: command.trailing
+        });
+    },
+    ERR_PASSWDMISMATCH: function (command) {
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' password_mismatch', {});
     },
     ERR_LINKCHANNEL: function (command) {
-        this.client.sendIrcCommand('channel_redirect', {server: this.con_num, from: command.params[1], to: command.params[2]});
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' channel_redirect', {
+            from: command.params[1],
+            to: command.params[2]
+        });
     },
     ERR_NOSUCHNICK: function (command) {
-        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'no_such_nick', nick: command.params[1], reason: command.trailing});
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' no_such_nick', {
+            nick: command.params[1],
+            reason: command.trailing
+        });
     },
     ERR_CANNOTSENDTOCHAN: function (command) {
-        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'cannot_send_to_chan', channel: command.params[1], reason: command.trailing});
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' cannot_send_to_chan', {
+            channel: command.params[1],
+            reason: command.trailing
+        });
     },
     ERR_TOOMANYCHANNELS: function (command) {
-        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'too_many_channels', channel: command.params[1], reason: command.trailing});
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' too_many_channels', {
+            channel: command.params[1],
+            reason: command.trailing
+        });
     },
     ERR_USERNOTINCHANNEL: function (command) {
-        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'user_not_in_channel', nick: command.params[0], channel: command.params[1], reason: command.trailing});
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' user_not_in_channel', {
+            nick: command.params[0],
+            channel: command.params[1],
+            reason: command.trailing
+        });
     },
     ERR_NOTONCHANNEL: function (command) {
-        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'not_on_channel', channel: command.params[1], reason: command.trailing});
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' not_on_channel', {
+            channel: command.params[1],
+            reason: command.trailing
+        });
     },
     ERR_CHANNELISFULL: function (command) {
-            this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'channel_is_full', channel: command.params[1], reason: command.trailing});
+            this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' channel_is_full', {
+                channel: command.params[1],
+                reason: command.trailing
+            });
         },
     ERR_INVITEONLYCHAN: function (command) {
-        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'invite_only_channel', channel: command.params[1], reason: command.trailing});
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' invite_only_channel', {
+            channel: command.params[1],
+            reason: command.trailing
+        });
     },
     ERR_BANNEDFROMCHAN: function (command) {
-        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'banned_from_channel', channel: command.params[1], reason: command.trailing});
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' banned_from_channel', {
+            channel: command.params[1],
+            reason: command.trailing
+        });
     },
     ERR_BADCHANNELKEY: function (command) {
-        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'bad_channel_key', channel: command.params[1], reason: command.trailing});
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' bad_channel_key', {
+            channel: command.params[1],
+            reason: command.trailing
+        });
     },
     ERR_CHANOPRIVSNEEDED: function (command) {
-        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'chanop_privs_needed', channel: command.params[1], reason: command.trailing});
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' chanop_privs_needed', {
+            channel: command.params[1],
+            reason: command.trailing
+        });
     },
     ERR_NICKNAMEINUSE: function (command) {
-        this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'nickname_in_use', nick: command.params[1], reason: command.trailing});
+        this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' nickname_in_use', {
+            nick: command.params[1],
+            reason: command.trailing
+        });
     },
     ERR_NOTREGISTERED: function (command) {
     },
@@ -592,6 +704,54 @@ var listeners = {
         var params = _.clone(command.params);
         params.shift();
         genericNotice.call(this, command, command.trailing);
+    },
+
+    RPL_STATSCONN: function (command) {
+        var params = _.clone(command.params);
+        params.shift();
+        genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+    },
+
+    RPL_LUSERCLIENT: function (command) {
+        var params = _.clone(command.params);
+        params.shift();
+        genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+    },
+
+    RPL_LUSEROP: function (command) {
+        var params = _.clone(command.params);
+        params.shift();
+        genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+    },
+
+    RPL_LUSERUNKNOWN: function (command) {
+        var params = _.clone(command.params);
+        params.shift();
+        genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+    },
+
+    RPL_LUSERCHANNELS: function (command) {
+        var params = _.clone(command.params);
+        params.shift();
+        genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+    },
+
+    RPL_LUSERME: function (command) {
+        var params = _.clone(command.params);
+        params.shift();
+        genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+    },
+
+    RPL_LOCALUSERS: function (command) {
+        var params = _.clone(command.params);
+        params.shift();
+        genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+    },
+    
+    RPL_GLOBALUSERS: function (command) {
+        var params = _.clone(command.params);
+        params.shift();
+        genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
     }
 };
 
@@ -605,6 +765,7 @@ function genericNotice (command, msg, is_error) {
 
     this.client.sendIrcCommand('notice', {
         server: this.con_num,
+        from_server: true,
         nick: command.prefix,
         ident: '',
         hostname: '',