Permalink
Browse files

Merge branch 'master' of git://github.com/martynsmith/node-irc into p…

…atch-messagelength
  • Loading branch information...
2 parents fa15d40 + 6fcda56 commit c6fd159a4a8279e234486289f69dc3d22d362467 @qsheets committed Sep 7, 2013
Showing with 102 additions and 35 deletions.
  1. +2 −2 README.rst
  2. +13 −6 docs/API.rst
  3. +20 −0 lib/codes.js
  4. +10 −3 lib/colors.js
  5. +57 −24 lib/irc.js
View
@@ -29,8 +29,8 @@ This library provides basic IRC client functionality. In the simplest case you
can connect to an IRC server like so::
var irc = require('irc');
- var client = new irc.Client('irc.dollyfish.net.nz', 'myNick', {
- channels: ['#blah'],
+ var client = new irc.Client('irc.yourserver.com', 'myNick', {
+ channels: ['#channel'],
});
Of course it's not much use once it's connected if that's all you have!
View
@@ -29,6 +29,7 @@ Client
certExpired: false,
floodProtection: false,
floodProtectionDelay: 1000,
+ sasl: false,
stripColors: false,
channelPrefixes: "&#",
messageLength: 512
@@ -47,6 +48,8 @@ Client
`floodProtectionDelay` sets the amount of time that the client will wait
between sending subsequent messages when `floodProtection` is enabled.
+ Set `sasl` to true to enable SASL support. You'll also want to set `nick`,
+ `userName`, and `password` for authentication.
`messageLength` sets the character length at which messages sent with `msg` will
be split into multiple messages. This value should not be changed unless the
server explicitly indicates another value.
@@ -79,11 +82,12 @@ Client
supports multiple JOIN arguments as a space separated string (similar to
the IRC protocol).
-.. js:function:: Client.part(channel, callback)
+.. js:function:: Client.part(channel, message, callback)
Parts the specified channel.
:param string channel: Channel to part
+ :param string message: Optional message to send upon leaving the channel
:param function callback: Callback to automatically subscribed to the
`part#channel` event, but removed after the first invocation.
@@ -310,28 +314,31 @@ Events
.. js:data:: 'ctcp'
- `function (from, to, text, type) { }`
+ `function (from, to, text, type, message) { }`
Emitted when a CTCP notice or privmsg was received (`type` is either `'notice'`
- or `'privmsg'`).
+ or `'privmsg'`). See the `raw` event for details on the `message` object.
.. js:data:: 'ctcp-notice'
- `function (from, to, text) { }`
+ `function (from, to, text, message) { }`
Emitted when a CTCP notice was received.
+ See the `raw` event for details on the `message` object.
.. js:data:: 'ctcp-privmsg'
- `function (from, to, text) { }`
+ `function (from, to, text, message) { }`
Emitted when a CTCP privmsg was received.
+ See the `raw` event for details on the `message` object.
.. js:data:: 'ctcp-version'
- `function (from, to) { }`
+ `function (from, to, message) { }`
Emitted when a CTCP VERSION request was received.
+ See the `raw` event for details on the `message` object.
.. js:data:: 'nick'
View
@@ -1,4 +1,16 @@
module.exports = { // {{{
+ "001" : {
+ "name" : "rpl_welcome",
+ "type" : "reply"
+ },
+ "002" : {
+ "name" : "rpl_yourhost",
+ "type" : "reply"
+ },
+ "003" : {
+ "name" : "rpl_created",
+ "type" : "reply"
+ },
"004" : {
"name" : "rpl_myinfo",
"type" : "reply"
@@ -215,6 +227,10 @@ module.exports = { // {{{
"name" : "rpl_channelmodeis",
"type" : "reply"
},
+ "329" : {
+ "name" : "rpl_creationtime",
+ "type" : "reply"
+ },
"331" : {
"name" : "rpl_notopic",
"type" : "reply"
@@ -223,6 +239,10 @@ module.exports = { // {{{
"name" : "rpl_topic",
"type" : "reply"
},
+ "333" : {
+ "name" : "rpl_topicwhotime",
+ "type" : "reply"
+ },
"341" : {
"name" : "rpl_inviting",
"type" : "reply"
View
@@ -1,4 +1,4 @@
-codes = {
+var codes = {
white: '\u000300',
black: '\u000301',
dark_blue: '\u000302',
@@ -15,13 +15,20 @@ codes = {
light_magenta: '\u000313',
gray: '\u000314',
light_gray: '\u000315',
+
+ bold: '\u000216',
+ underline: '\u001f17',
+
reset: '\u000f',
};
exports.codes = codes;
function wrap(color, text, reset_color) {
- reset_color = typeof(a) != 'undefined' ? a : 'reset';
- return codes[color] + text + codes[reset_color];
+ if(codes[color]) {
+ text = codes[color] + text;
+ text += (codes[reset_color]) ? codes[reset_color] : codes['reset'];
+ }
+ return text;
};
exports.wrap = wrap;
View
@@ -48,6 +48,7 @@ function Client(server, nick, opt) {
certExpired: false,
floodProtection: false,
floodProtectionDelay: 1000,
+ sasl: false,
stripColors: false,
channelPrefixes: "&#",
messageLength: 512
@@ -98,16 +99,14 @@ function Client(server, nick, opt) {
self.addListener("raw", function (message) { // {{{
switch ( message.command ) {
- case "001":
+ case "rpl_welcome":
// Set nick to whatever the server decided it really is
// (normally this is because you chose something too long and
// the server has shortened it
self.nick = message.args[0];
self.whois(self.nick, self._setUserhost);
self.emit('registered', message);
break;
- case "002":
- case "003":
case "rpl_myinfo":
self.supported.usermodes = message.args[3];
break;
@@ -128,7 +127,6 @@ function Client(server, nick, opt) {
value = value.split(',');
var type = ['a','b','c','d']
for (var i = 0; i < type.length; i++) {
-
self.supported.channel.modes[type[i]] += value[i];
}
break;
@@ -183,6 +181,8 @@ function Client(server, nick, opt) {
}
});
break;
+ case "rpl_yourhost":
+ case "rpl_created":
case "rpl_luserclient":
case "rpl_luserop":
case "rpl_luserchannels":
@@ -209,9 +209,9 @@ function Client(server, nick, opt) {
if (!to) {
to = null;
}
- var text = message.args[1];
+ var text = message.args[1] || '';
if (text[0] === '\1' && text.lastIndexOf('\1') > 0) {
- self._handleCTCP(from, to, text, 'notice');
+ self._handleCTCP(from, to, text, 'notice', message);
break;
}
self.emit('notice', from, to, text, message);
@@ -221,7 +221,7 @@ 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[1]);
var channel = self.chanData(message.args[0]);
if ( !channel ) break;
@@ -381,8 +381,7 @@ function Client(server, nick, opt) {
case "rpl_listend":
self.emit('channellist', self.channellist);
break;
- case "333":
- // TODO emit?
+ case "rpl_topicwhotime":
var channel = self.chanData(message.args[1]);
if ( channel ) {
channel.topicBy = message.args[2];
@@ -406,7 +405,7 @@ function Client(server, nick, opt) {
channel.mode = message.args[2];
}
break;
- case "329":
+ case "rpl_creationtime":
var channel = self.chanData(message.args[1]);
if ( channel ) {
channel.created = message.args[2];
@@ -474,9 +473,9 @@ function Client(server, nick, opt) {
case "PRIVMSG":
var from = message.nick;
var to = message.args[0];
- var text = message.args[1];
+ var text = message.args[1] || '';
if (text[0] === '\1' && text.lastIndexOf('\1') > 0) {
- self._handleCTCP(from, to, text, 'privmsg');
+ self._handleCTCP(from, to, text, 'privmsg', message);
break;
}
self.emit('message', from, to, text, message);
@@ -521,6 +520,26 @@ function Client(server, nick, opt) {
// who, reason, channels
self.emit('quit', message.nick, message.args[0], channels, message);
break;
+
+ // for sasl
+ case "CAP":
+ if ( message.args[0] === '*' &&
+ message.args[1] === 'ACK' &&
+ message.args[2] === 'sasl ' ) // there's a space after sasl
+ self.send("AUTHENTICATE", "PLAIN");
+ break;
+ case "AUTHENTICATE":
+ if ( message.args[0] === '+' ) self.send("AUTHENTICATE",
+ new Buffer(
+ self.opt.nick + '\0' +
+ self.opt.userName + '\0' +
+ self.opt.password
+ ).toString('base64'));
+ break;
+ case "903":
+ self.send("CAP", "END");
+ break;
+
case "err_umodeunknownflag":
if ( self.opt.showErrors )
util.log("\033[01;31mERROR: " + util.inspect(message) + "\033[0m");
@@ -595,8 +614,9 @@ Client.prototype.connect = function ( retryCount, callback ) { // {{{
self.conn.connected = true;
if (self.conn.authorized ||
(self.opt.selfSigned &&
- (self.conn.authorizationError === 'DEPTH_ZERO_SELF_SIGNED_CERT' ||
- self.conn.authorizationError === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE')) ||
+ (self.conn.authorizationError === 'DEPTH_ZERO_SELF_SIGNED_CERT' ||
+ self.conn.authorizationError === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' ||
+ self.conn.authorizationError === 'SELF_SIGNED_CERT_IN_CHAIN')) ||
(self.opt.certExpired &&
self.conn.authorizationError === 'CERT_HAS_EXPIRED')) {
// authorization successful
@@ -608,7 +628,8 @@ Client.prototype.connect = function ( retryCount, callback ) { // {{{
if ( self.opt.password !== null ) {
self.send( "PASS", self.opt.password );
}
- util.log('Sending irc NICK/USER');
+ if ( self.opt.debug )
+ util.log('Sending irc NICK/USER');
self.send("NICK", self.opt.nick);
self.nick = self.opt.nick;
self.send("USER", self.opt.userName, 8, "*", self.opt.realName);
@@ -625,7 +646,10 @@ Client.prototype.connect = function ( retryCount, callback ) { // {{{
self.conn.setTimeout(0);
self.conn.setEncoding('utf8');
self.conn.addListener("connect", function () {
- if ( self.opt.password !== null ) {
+ if ( self.opt.sasl ) {
+ // see http://ircv3.atheme.org/extensions/sasl-3.1
+ self.send("CAP REQ", ":sasl");
+ } else if ( self.opt.password !== null ) {
self.send( "PASS", self.opt.password );
}
self.send("NICK", self.opt.nick);
@@ -739,7 +763,8 @@ Client.prototype.activateFloodProtection = function(interval) { // {{{
}; // }}}
Client.prototype.join = function(channel, callback) { // {{{
- this.once('join' + channel, function () {
+ var channelName = channel.split(' ')[0];
+ this.once('join' + channelName, function () {
// if join is successful, add this channel to opts.channels
// so that it will be re-joined upon reconnect (as channels
// specified in options are)
@@ -753,7 +778,11 @@ Client.prototype.join = function(channel, callback) { // {{{
});
this.send.apply(this, ['JOIN'].concat(channel.split(' ')));
} // }}}
-Client.prototype.part = function(channel, callback) { // {{{
+Client.prototype.part = function(channel, message, callback) { // {{{
+ if ( typeof(message) === 'function' ) {
+ callback = message;
+ message = undefined;
+ }
if ( typeof(callback) == 'function' ) {
this.once('part' + channel, callback);
}
@@ -763,8 +792,12 @@ Client.prototype.part = function(channel, callback) { // {{{
if (this.opt.channels.indexOf(channel) != -1) {
this.opt.channels.splice(this.opt.channels.indexOf(channel), 1);
}
-
- this.send('PART', channel);
+
+ if (message) {
+ this.send('PART', channel, message);
+ } else {
+ this.send('PART', channel);
+ }
} // }}}
Client.prototype.say = function(target, text) { // {{{
var self = this;
@@ -838,12 +871,12 @@ Client.prototype._handleCTCP = function(from, to, text, type) {
text = text.slice(1)
text = text.slice(0, text.indexOf('\1'))
var parts = text.split(' ')
- this.emit('ctcp', from, to, text, type)
- this.emit('ctcp-'+type, from, to, text)
+ this.emit('ctcp', from, to, text, type, message)
+ this.emit('ctcp-'+type, from, to, text, message)
if (type === 'privmsg' && text === 'VERSION')
- this.emit('ctcp-version', from, to)
+ this.emit('ctcp-version', from, to, message)
if (parts[0] === 'ACTION' && parts.length > 1)
- this.emit('action', from, to, parts.slice(1).join(' '))
+ this.emit('action', from, to, parts.slice(1).join(' '), message)
if (parts[0] === 'PING' && type === 'privmsg' && parts.length > 1)
this.ctcp(from, 'notice', text)
}

0 comments on commit c6fd159

Please sign in to comment.