Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use CHANMODES for modifying channel modes and lists (v0.3) #270

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 107 additions & 55 deletions lib/irc.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,11 @@ function Client(server, nick, opt) {
match[1] = match[1].split('');
match[2] = match[2].split('');
while ( match[1].length ) {
self.modeForPrefix[match[2][0]] = match[1][0];
self.supported.channel.modes.b += match[1][0];
self.prefixForMode[match[1].shift()] = match[2].shift();
var prefix = match[1].shift();
var mode = match[2].shift();
self.modeForPrefix[mode] = prefix;
self.supported.channel.modes.b += prefix;
self.prefixForMode[prefix] = mode;
}
}
break;
Expand Down Expand Up @@ -219,51 +221,11 @@ function Client(server, nick, opt) {
break;
case "MODE":
if ( self.opt.debug )
util.log("MODE: " + message.args[0] + " sets mode: " + message.args[1]);
util.log("MODE:" + message.args[0] + " sets mode: " + message.args.slice(1).join(' '));

var channel = self.chanData(message.args[0]);
if ( !channel ) break;
var modeList = message.args[1].split('');
var adding = true;
var modeArgs = message.args.slice(2);
modeList.forEach(function(mode) {
if ( mode == '+' ) { adding = true; return; }
if ( mode == '-' ) { adding = false; return; }
if ( mode in self.prefixForMode ) {
// channel user modes
var user = modeArgs.shift();
if ( adding ) {
if ( channel.users[user].indexOf(self.prefixForMode[mode]) === -1 )
channel.users[user] += self.prefixForMode[mode];

self.emit('+mode', message.args[0], message.nick, mode, user, message);
}
else {
channel.users[user] = channel.users[user].replace(self.prefixForMode[mode], '');
self.emit('-mode', message.args[0], message.nick, mode, user, message);
}
}
else {
var modeArg;
// channel modes
if ( mode.match(/^[bkl]$/) ) {
modeArg = modeArgs.shift();
if ( modeArg.length === 0 )
modeArg = undefined;
}
// TODO - deal nicely with channel modes that take args
if ( adding ) {
if ( channel.mode.indexOf(mode) === -1 )
channel.mode += mode;

self.emit('+mode', message.args[0], message.nick, mode, modeArg, message);
}
else {
channel.mode = channel.mode.replace(mode, '');
self.emit('-mode', message.args[0], message.nick, mode, modeArg, message);
}
}
});
channel.setModes(self, message.args.slice(1), message);
break;
case "NICK":
if ( message.nick == self.nick )
Expand Down Expand Up @@ -393,7 +355,7 @@ function Client(server, nick, opt) {
case "rpl_channelmodeis":
var channel = self.chanData(message.args[1]);
if ( channel ) {
channel.mode = message.args[2];
channel.setModes(self, message.args.slice(2));
}
break;
case "rpl_creationtime":
Expand Down Expand Up @@ -579,19 +541,15 @@ Client.prototype.prefixForMode = {};
Client.prototype.modeForPrefix = {};
Client.prototype.chans = {};
Client.prototype._whoisData = {};

Client.prototype.chanData = function( name, create ) { // {{{
var key = name.toLowerCase();
if ( create ) {
this.chans[key] = this.chans[key] || {
key: key,
serverName: name,
users: {},
mode: '',
};
this.chans[key] = this.chans[key] || new Channel(name);
}

return this.chans[key];
} // }}}

Client.prototype.connect = function ( retryCount, callback ) { // {{{
if ( typeof(retryCount) === 'function' ) {
callback = retryCount;
Expand Down Expand Up @@ -811,9 +769,9 @@ Client.prototype.part = function(channel, message, callback) { // {{{
}

if (message) {
this.send('PART', channel, message);
this.send('PART', channel, message);
} else {
this.send('PART', channel);
this.send('PART', channel);
}
} // }}}
Client.prototype.say = function(target, text) { // {{{
Expand Down Expand Up @@ -889,6 +847,100 @@ Client.prototype.ctcp = function(to, type, text) {
return this[type === 'privmsg' ? 'say' : 'notice'](to, '\1'+text+'\1');
}

function Channel(name, users, mode){
this.key = name.toLowerCase();
this.serverName = name;
this.users = users || {};
this.mode = mode || '';
this.setting = {};
}
exports.Channel = Channel;
Channel.prototype.key = '';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't all of these properties already being defined on the instance above in the constructor?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just hinting at the type that each property will be once the constructor has finished its inititialization. It might be unnecessary for most purposes, and it definitely should't make a difference during execution.

Channel.prototype.serverName = '';
Channel.prototype.users = {};
Channel.prototype.mode = '';
Channel.prototype.setting = {};
Channel.prototype.setModes = function setModes(connection, modes, message){
var self = this;
var modeList = modes[0].split('');
var modeArgs = modes.slice(1);
var adding = true;
modeList.forEach(function(mode) {
if ( mode == '+' ) { adding = true; return; }
if ( mode == '-' ) { adding = false; return; }
self.setMode(connection, adding, mode, modeArgs, message);
});
}
Channel.prototype.setMode = function setModes(connection, adding, mode, modeArgs, message){
var channel = this;
var supports = connection.supported.channel.modes;
if(connection.prefixForMode[mode]) {
// channel user modes
var user = modeArgs.shift();
if(adding) {
if(channel.users[user] && channel.users[user].indexOf(connection.prefixForMode[mode]) === -1) {
channel.users[user] += connection.prefixForMode[mode];
if(message) connection.emit('+mode', message.args[0], message.nick, mode, user, message);
} else {
connection.emit('error', new Error('Unable to apply mode +'+mode+' to nickname '+user+ ' on channel '+channel.key));
}
} else {
if(channel.users[user] && channel.users[user].indexOf(connection.prefixForMode[mode]) === -1) {
channel.users[user] = channel.users[user].replace(connection.prefixForMode[mode], '');
if(message) connection.emit('-mode', message.args[0], message.nick, mode, user, message);
} else {
connection.emit('error', new Error('Unable to apply mode -'+mode+' to nickname '+user+ ' on channel '+channel.key));
}
}
} else if(supports.a.indexOf(mode)>=0 || supports.b.indexOf(mode)>=0) {
// Add or remove a nick/address from a list
// Any nicknames should already have been handled so just patterns now?
// If it is a nickname list, then it'll just end up being a list of nicknames which is acceptable
var list = channel.setting[mode];
if(!(list instanceof Array)) list = channel.setting[mode] = [];
var arg = modeArgs.shift();
if(adding){
if(list.indexOf(arg)>=0) return;
list.push(arg);
if(message) connection.emit('+mode', message.args[0], message.nick, mode, arg, message);
} else {
channel.setting[mode] = list.filter(function(v){ return v!=arg; });
if(message) connection.emit('-mode', message.args[0], message.nick, mode, arg, message);
}
} else if(supports.c.indexOf(mode) >= 0) {
// These set a value only when the mode is set
if(adding){
if ( channel.mode.indexOf(mode) === -1 ){
channel.mode += mode;
}
var arg = modeArgs.shift();
channel.setting[mode] = arg;
if(message) connection.emit('+mode', message.args[0], message.nick, mode, arg, message);
} else {
channel.mode = channel.mode.replace(mode, '');
delete channel.setting[mode];
if(message) connection.emit('-mode', message.args[0], message.nick, mode, arg, message);
}
} else if(supports.d.indexOf(mode) >= 0) {
if ( adding ) {
if ( channel.mode.indexOf(mode) === -1 ){
// FIXME - Some users may expect a particular order of channel modes
channel.mode += mode;
}
channel.setting[mode] = true;
if(message) connection.emit('+mode', message.args[0], message.nick, mode, undefined, message);
} else {
channel.mode = channel.mode.replace(mode, '');
delete channel.setting[mode];
if(message) connection.emit('-mode', message.args[0], message.nick, mode, undefined, message);
}
} else {
// Don't handle this, but emit an error.
// It may be in a fifth CHANMODES group which we were supposed to ignore.
connection.emit('error', new Error('Unhandled mode '+(adding?'+':'-')+mode));
}
}

/*
* parseMessage(line, stripColors)
*
Expand Down