diff --git a/lib/irc.js b/lib/irc.js index 45eba0ab..b8f57ed1 100644 --- a/lib/irc.js +++ b/lib/irc.js @@ -56,12 +56,14 @@ function Client(server, nick, opt) { channelPrefixes: '&#', messageSplit: 512, encoding: false, + capIdentifyMsg: false, webirc: { pass: '', ip: '', user: '' } }; + self.CAP = []; // Features supported by the server // (initial values are RFC 1459 defaults. Zeros signify @@ -557,10 +559,14 @@ function Client(server, nick, opt) { // 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'); + if (message.args[1] === 'NAK') { + self.emit('error', 'CAP ERROR for ": ' + self.CAP.join(' ') + '" CAP sent. Response:' + util.inspect(message)); + } else if (message.args[1] === 'ACK') { + if (message.args[0] === '*' && + message.args[2].indexOf('sasl')!== -1){ + self.send('AUTHENTICATE', 'PLAIN'); + } + } break; case 'AUTHENTICATE': if (message.args[0] === '+') self.send('AUTHENTICATE', @@ -714,10 +720,21 @@ Client.prototype.connect = function(retryCount, callback) { } self.conn.addListener('connect', function() { + + if (self.opt.capIdentifyMsg) { + self.CAP.push("identify-msg"); + } + if (self.opt.sasl) { + self.CAP.push("sasl"); // see http://ircv3.atheme.org/extensions/sasl-3.1 - self.send('CAP REQ', 'sasl'); } + + if (self.CAP.length > 0) { + self.send('CAP REQ', self.CAP.join(' ')); + self.send('CAP', 'END'); + } + if (self.opt.webirc.ip && self.opt.webirc.pass && self.opt.webirc.host) { self.send('WEBIRC', self.opt.webirc.pass, self.opt.userName, self.opt.webirc.host, self.opt.webirc.ip); } else if (self.opt.password) { diff --git a/package.json b/package.json index d759bc0f..164740f0 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "Mischa Spiegelmock ", "Justin Gallardo ", "Chris Nehren ", + "Dariusz Niemczyk ", "Henri Niemeläinen " ], "repository": { @@ -43,7 +44,7 @@ }, "devDependencies": { "faucet": "0.0.1", - "jscs": "1.9.0", + "jscs": "^1.9.0", "tape": "^3.0.3" } } diff --git a/test/data/fixtures.json b/test/data/fixtures.json index be47f9df..710e526d 100644 --- a/test/data/fixtures.json +++ b/test/data/fixtures.json @@ -148,6 +148,28 @@ "maxLineLength is as expected after 433" ] }, + "CAP": { + "ACK" : { + "sent" : [ + ["CAP REQ identify-msg"], + ["CAP END"] + ], + "received": [ + [":localhost CAP * ACK :identify-msg\r\n"], + [":localhost 001 testbot :Welcome to the Internet Relay Chat Network testbot\r\n", "Received welcome message"] + ] + }, + "NAK": { + "sent": [ + ["CAP REQ doesntExist"], + ["CAP END"] + ], + "received": [ + [":localhost CAP * NAK :doesntExist\r\n"], + [":localhost 001 testbot :Welcome to the Internet Relay Chat Network testbot\r\n", "Received welcome message"] + ] + } + }, "convert-encoding": { "causesException": [ ":ubottu!ubottu@ubuntu/bot/ubottu MODE #ubuntu -bo *!~Brian@* ubottu\r\n", diff --git a/test/test-cap.js b/test/test-cap.js new file mode 100644 index 00000000..cb323807 --- /dev/null +++ b/test/test-cap.js @@ -0,0 +1,53 @@ +var net = require('net'); + +var irc = require('../lib/irc'); +var test = require('tape'); + +var testHelpers = require('./helpers'); + +var expected = testHelpers.getFixtures('CAP'); +var greeting = ':localhost 001 testbot :Welcome to the Internet Relay Chat Network testbot\r\n'; + +test('CAP ACK', function(t) { + runTests(t, 'ACK'); +}); + +test('CAP NAK', function(t) { + runTests(t, 'NAK'); +}); + +function runTests(t, responseType) { + var port = 6667; + var mock = testHelpers.MockIrcd(); + var client = new irc.Client('localhost', 'testbot', { + selfSigned: true, + port: port, + retryCount: 0, + debug: true, + capIdentifyMsg: true + }); + + t.plan(1); + + mock.server.on('connection', function() { + mock.send(expected[responseType].received[0][0]); + mock.send(greeting); + }); + + if (responseType === 'NAK') { + client.on('error', function(err) { + t.equal(mock.outgoing[0], expected[responseType].received[0][0]); + client.disconnect(); + }); + } else { + client.on('registered', function() { + t.equal(mock.outgoing[0], expected[responseType].received[0][0]); + client.disconnect(); + }); + } + + mock.on('end', function() { + mock.close(); + }); + +}