├── LICENSE ├── README.md ├── lib └── client.js ├── package.json └── samples ├── commands.js └── events.js /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Cato Auestad 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DEPRECATION NOTICE: This library is no longer maintained. 2 | ============= 3 | 4 | node-irc 5 | ============= 6 | 7 | node-irc is a socket wrapper for the IRC protocol that extends Node.js' EventEmitter. node-irc aims to be an efficient, extremely easy to use IRC library used to build bots and clients. 8 | 9 | Get started 10 | ------------- 11 | 12 | ### Install node-irc with npm. 13 | 14 | ``` 15 | npm install node-irc 16 | ``` 17 | 18 | ### Import node-irc. 19 | 20 | 21 | ``` 22 | var ircClient = require('node-irc'); 23 | ``` 24 | 25 | ### Pass in the server, port, nickname and fullname as parameters to the constructor. 26 | 27 | ``` 28 | var client = new ircClient('irc.freenode.net', 6667, 'SomeNick', 'SomeFullname'); 29 | ``` 30 | 31 | ### Add an event handler for what to do When the server is ready, like joining a channel and say something weird. 32 | 33 | ``` 34 | client.on('ready', function () { 35 | client.join('#Node.js'); 36 | client.say('#Node.js', 'I see node people.'); 37 | }); 38 | ``` 39 | 40 | ### Connect to the server 41 | 42 | ``` 43 | client.connect() 44 | ``` 45 | 46 | ### More details 47 | See [samples](https://github.com/ninjacato/node-irc/tree/master/samples) and [wiki](https://github.com/ninjacato/node-irc/wiki) 48 | -------------------------------------------------------------------------------- /lib/client.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var events = require('events'); 3 | 4 | function ircClient(server, port, nickname, fullname, password, proxy) { 5 | this.host = server; 6 | this.port = port; 7 | this.nickname = nickname; 8 | this.fullname = fullname; 9 | this.verbosity = 1; // 0 => Silent, 1 => Normal, 2 => Info, 3 => Debug 10 | this.debug = false; 11 | this.password = password; 12 | this.proxy = proxy; // { host: , port: } 13 | events.EventEmitter.call(this); 14 | return this; 15 | } 16 | 17 | ircClient.super_ = events.EventEmitter; 18 | ircClient.prototype = Object.create(events.EventEmitter.prototype); 19 | 20 | ircClient.prototype.connect = function () { 21 | var that = this; 22 | var client; 23 | if(that.proxy) { 24 | try { 25 | var proxysocket = require('proxysocket'); 26 | } 27 | catch(e) { 28 | console.error('Module proxysocket not found'); 29 | process.exit(e.code); 30 | } 31 | client = proxysocket.create(that.proxy.host, that.proxy.port); 32 | } 33 | else { 34 | var net = require('net'); 35 | client = net.createConnection(that.port, that.host); 36 | } 37 | 38 | client.addListener('connect', function () { 39 | if(that.password) { 40 | client.write('PASS ' + that.password + '\r\n'); 41 | } 42 | client.write('NICK ' + that.nickname + '\r\n'); 43 | client.write('USER ' + that.nickname + ' 0 * :' + that.fullname + '\r\n'); 44 | that.logger('Client connected', 1); 45 | }); 46 | 47 | client.addListener('data', function (data) { 48 | if (that.debug) console.log(data.toString()); 49 | that.dispatcher(data.toString()); 50 | }); 51 | 52 | client.addListener('close', function (data) { 53 | that.logger('Disconnected from server', 1); 54 | }); 55 | 56 | if(that.proxy) { 57 | // Unlike net.Socket, proxysocket.Socket does not connect automatically upon creation 58 | client.connect(that.host, that.port); 59 | } 60 | this.client = client; 61 | }; 62 | 63 | // FORMALITY HANDLERS 64 | 65 | ircClient.prototype.dispatcher = function (data) { 66 | var response = data.split('\n'), 67 | formatResponse, 68 | preparedResponse, 69 | sortedResponse, 70 | i; 71 | this.emit('rawReceive', data); 72 | if (data.match('^PING')) { 73 | this.pingHandler(data); 74 | } else { 75 | for (i = response.length; i--;) { 76 | rawResponse = response[i].split(" "); 77 | if(rawResponse[1] === '004' || rawResponse[1] === '376') { // If registration was sucessful or MOTD has been written 78 | this.emit('ready'); 79 | } else { 80 | this.eventHandler(assembleResponse(rawResponse)); 81 | //console.log(rawResponse.toString()); 82 | } 83 | } 84 | } 85 | }; 86 | 87 | ircClient.prototype.eventHandler = function (data) { 88 | if (data.method === 'PRIVMSG') { 89 | data.message = data.message.join(" "); 90 | data.message = data.message.substring(1, (data.message.length-1)); 91 | if (data.receiver.match(/^#/)) { 92 | data.method = 'CHANMSG'; 93 | this.emit('CHANMSG', data); 94 | } else { 95 | this.emit('PRIVMSG', data); 96 | } 97 | } 98 | else if (data.method === 'JOIN') { 99 | // Remove preceding semi-colon 100 | data.receiver = data.receiver.substring(0, (data.receiver.length-1)); 101 | this.emit('JOIN', data); 102 | } 103 | else if (data.method === 'INVITE') { 104 | data.message = data.message[0].substring(1, (data.message[0].length-1)); 105 | this.emit('INVITE', data); 106 | } 107 | else if (data.method === 'TOPIC') { 108 | data.message = data.message.join(" "); 109 | data.message = data.message.substring(1, (data.message.length-1)); 110 | this.emit('TOPIC', data); 111 | } 112 | else if (data.method === 'PART') { 113 | data.receiver = data.receiver.substring(0, (data.receiver.length-1)); 114 | this.emit('PART', data); 115 | } 116 | else if (data.method === 'KICK') { 117 | data.message[1] = data.message.splice(1); 118 | data.message[1] = data.message[1].join(" "); 119 | data.message[1] = data.message[1].substring(1, (data.message[1].length-1)); 120 | this.emit('KICK', data); 121 | } 122 | else if (data.method === 'QUIT') { 123 | data.receiver = ''; 124 | this.emit('QUIT', data); 125 | } 126 | else if (data.method === 'NICK') { 127 | data.receiver = data.receiver.substring(1, (data.receiver.length-1)); 128 | this.emit('NICK', data); 129 | } 130 | }; 131 | 132 | ircClient.prototype.pingHandler = function (response) { 133 | var splitResponse = []; 134 | splitResponse = response.split(" "); 135 | this.logger('PING ' + splitResponse[1], 2); 136 | this.logger('PONG ' + splitResponse[1], 2); 137 | this.client.write('PONG ' + splitResponse[1] + '\r\n'); 138 | }; 139 | 140 | ircClient.prototype.logger = function (message, level) { 141 | if ((this.verbosity !== 0) && (this.verbosity >= level)) { 142 | console.log('Level ' + level + ': ' + message); 143 | } 144 | }; 145 | 146 | // USER COMMANDS 147 | 148 | ircClient.prototype.join = function (channel) { 149 | this.logger('JOIN ' + channel, 1); 150 | this.client.write('JOIN ' + channel + '\r\n'); 151 | }; 152 | 153 | ircClient.prototype.quit = function (message) { 154 | this.logger('QUIT :' + message, 2); 155 | this.client.write('QUIT :Quit: ' + message + '\r\n'); 156 | }; 157 | 158 | ircClient.prototype.part = function (channel) { 159 | this.logger('PART ' + channel, 2); 160 | this.client.write('PART ' + channel + '\r\n'); 161 | }; 162 | 163 | ircClient.prototype.say = function (receiver, message) { 164 | this.logger('PRIVMSG ' + receiver + ' ' + message, 2); 165 | this.client.write('PRIVMSG ' + receiver + ' :' + message + '\r\n'); 166 | }; 167 | ircClient.prototype.nick = function (newNick) { 168 | this.logger('NICK ' + newNick, 2); 169 | this.client.write('NICK ' + newNick + '\r\n'); 170 | }; 171 | ircClient.prototype.mode = function (channel, mode, nick) { 172 | this.logger('MODE ' + channel + ' ' + mode + ' ' + nick, 2); 173 | this.client.write('MODE ' + channel + ' ' + mode + ' ' + nick + '\r\n'); 174 | }; 175 | ircClient.prototype.kick = function (channel, nick, reason) { 176 | this.logger('KICK ' + channel + ' ' + nick + ' :' + reason, 2); 177 | this.client.write('KICK ' + channel + ' ' + nick + ' :' + reason + '\r\n'); 178 | }; 179 | ircClient.prototype.rawWrite = function (cmd) { 180 | this.logger(cmd, 2); 181 | this.client.write(cmd + '\r\n'); 182 | }; 183 | ircClient.prototype.notice = function (receiver, message) { 184 | this.logger('NOTICE ' + receiver + ' ' + message, 2); 185 | this.client.write('NOTICE ' + receiver + ' :' + message + '\r\n'); 186 | }; 187 | 188 | // TOOLBOX 189 | function trim (string) { 190 | string = string.replace(/(^\s*)|(\s*$)/gi,""); 191 | string = string.replace(/[ ]{2,}/gi," "); 192 | string = string.replace(/\n /,"\n"); 193 | return string; 194 | } 195 | 196 | function assembleResponse (response) { 197 | var sender, 198 | formatUserhost, 199 | formatNick, 200 | formattedReturn, 201 | host, 202 | formatHost, 203 | shost, 204 | nick; 205 | 206 | // In case sender is a nick!user@host, parse the nick. 207 | try { 208 | formatUserhost = new RegExp(/\b[^]*(.*?)!/); // :nick!user@host => 209 | nick = formatUserhost.exec(response[0]); // [n,i,c,k,!] => 210 | formatNick = nick.join(""); // nick! => 211 | sender = (formatNick.substring(0,(formatNick.length-1))); // nick => Done. 212 | } catch(e) { 213 | sender = undefined; 214 | } 215 | 216 | try { 217 | formatUserhost = new RegExp(/@\b[^]*(.*?)/); // :nick!user@host => 218 | host = formatUserhost.exec(response[0].substr(1)); // [h,o,s,t] => 219 | formatHost = host.join(""); // host => 220 | shost = formatHost.substr(1); // host => Done. 221 | } catch(e) { 222 | shost = undefined; 223 | } 224 | 225 | var returnObject = { 226 | method: response[1], 227 | receiver: response[2], 228 | sender: sender, 229 | message: response.slice(3), 230 | shost: shost 231 | }; 232 | 233 | return returnObject; 234 | } 235 | 236 | module.exports = ircClient; 237 | })(); 238 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Cato Auestad (https://github.com/ninjacato)", 3 | "name": "node-irc", 4 | "description": "An easy to use IRC socket wrapper", 5 | "keywords": [ 6 | "irc", 7 | "chat", 8 | "socket", 9 | "network" 10 | ], 11 | "version": "0.0.5", 12 | "homepage": "https://github.com/ninjacato", 13 | "repository": { 14 | "type": "git", 15 | "url": "git://github.com/ninjacato/node-irc.git" 16 | }, 17 | "main": "./lib/client.js", 18 | "engines": { 19 | "node": ">=0.4.7" 20 | }, 21 | "dependencies": {}, 22 | "devDependencies": {}, 23 | "optionalDependencies": { 24 | "proxysocket": "^1.2.0" 25 | }, 26 | "licenses": [ 27 | { 28 | "type": "ISC License", 29 | "url": "https://github.com/ninjacato/node-irc/blob/master/LICENSE" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /samples/commands.js: -------------------------------------------------------------------------------- 1 | var ircClient = require('node-irc'); 2 | 3 | var server = 'irc.freenode.net', 4 | port = 6667, 5 | myNick = 'lolznick', 6 | fullname = 'lolzname', 7 | chan = '#Nuug'; 8 | 9 | // Create client object, pass in constructor arguments 10 | var client = new ircClient(server, port, myNick, fullname); 11 | 12 | client.verbosity = 2; 13 | 14 | client.on('ready', function () { 15 | client.join(chan); 16 | }); 17 | 18 | client.on('PRIVMSG', function (data) { 19 | if (data.sender === 'bleakgadfly') { 20 | if (data.message.match('^SAY')) { 21 | var splitMessage = data.message.split(" "); 22 | var receiver = splitMessage[1] 23 | var message = splitMessage.splice(2); 24 | message = message.join(" "); 25 | client.say(receiver, message); 26 | } 27 | else if (data.message.match('^JOIN')) { 28 | var channel = data.message.split(" ")[1]; 29 | client.join(channel); 30 | } 31 | else if (data.message.match('^PART')) { 32 | var channel = data.message.split(" ")[1]; 33 | client.part(channel); 34 | } 35 | else if (data.message.match('^QUIT')) { 36 | var message = data.message.split(" ")[1]; 37 | client.quit(message); 38 | } 39 | else if (data.message.match('^KICK')) { 40 | var message = data.message.split(" "); 41 | var channel = message[1]; 42 | var nick = message[2]; 43 | var reason = message.splice(3).join(" "); 44 | client.kick(channel, nick, reason); 45 | } 46 | else if (data.message.match('^NICK')) { 47 | var newNick = data.message.split(" ")[1]; 48 | client.nick(newNick); 49 | } 50 | else if (data.message.match('^OP')) { 51 | var channel = data.message.split(" ")[1]; 52 | var opnick = data.message.split(" ")[2]; 53 | client.mode(channel, '+o', opnick); 54 | } 55 | else if (data.message.match('^PRIVATE')) { 56 | var channel = data.message.split(" ")[1]; 57 | client.mode(channel, '+p'); 58 | } 59 | } 60 | }); 61 | 62 | client.connect(); 63 | -------------------------------------------------------------------------------- /samples/events.js: -------------------------------------------------------------------------------- 1 | var ircClient = require('./client.js'); 2 | 3 | var server = 'irc.freenode.net', 4 | port = 6667, 5 | nick = 'lolznick', 6 | fullname = 'lolzname', 7 | chan = '#Nuug'; 8 | 9 | // Create client object, pass in constructor arguments 10 | var client = new ircClient(server, port, nick, fullname); 11 | 12 | // This decides the verbosity of the output, set to 1 as default 13 | client.verbosity = 2; // 0 == Silent, 1 == Normal, 2 == Info 14 | 15 | // This is set to false by defaults, prints out all raw server messages 16 | client.debug = false; 17 | 18 | // Key piece. 19 | client.on('ready', function () { 20 | client.join(chan); 21 | }); 22 | 23 | /** \** 24 | * * 25 | * THESE ARE THE AVAILABLE EVENT TRIGGERS * 26 | * * 27 | **\ **/ 28 | 29 | client.on('CHANMSG', function (data) { 30 | /** 31 | The data object contains 32 | data.receiver : The channel the message was written in prefixed with hash (#) 33 | data.sender : The nick of the person who sent the message 34 | data.message : The message the person sent 35 | **/ 36 | var message = data.sender + ' said: ' + data.message; 37 | if(data.sender !== nick) client.say(data.receiver, message); 38 | }); 39 | 40 | client.on('PRIVMSG', function (data) { 41 | /** 42 | The data object contains: 43 | data.receiver : The nick person who received the message (this should always be you) 44 | data.sender : The nick of the person who sent you the message 45 | data.message : The message the person sent 46 | **/ 47 | var message = 'Hi, ' + data.sender + 48 | ', nice of you to speak to a bot. I can only repeat what you said: ' + data.message; 49 | if(data.sender !== nick) client.say(data.sender, message); 50 | }); 51 | 52 | client.on('JOIN', function (data) { 53 | /** 54 | The data object contains: 55 | data.receiver : The channel the person joined, prefixed by a hash (#) 56 | data.sender : The nick of the person who joined 57 | **/ 58 | var message = 'Welcome to ' + data.receiver + ', ' + data.sender; 59 | if(data.sender !== nick) client.say(data.receiver, message); 60 | }); 61 | 62 | client.on('INVITE', function (data) { 63 | /** 64 | The data object contains: 65 | data.receiver : The nick of the person who was invited (this should always be you) 66 | data.sender : The nick of the person who invited you 67 | data.message : The channel you were invited to, prefixed by a hash (#) 68 | **/ 69 | var message = 'Thank you for your invite to ' + data.message + ', ' + data.sender; 70 | client.join(data.message); 71 | client.say(data.message, message); 72 | }); 73 | 74 | client.on('TOPIC', function (data) { 75 | /** 76 | The data object contains: 77 | data.receiver : The channel the topic was changed on, prefixed by a hash (#) 78 | data.sender : The nick of the person who changed the topic 79 | data.message : The new topic message 80 | **/ 81 | var message = 'Hmm, seems like ' + data.sender + 82 | ' changed the topic of ' + data.receiver + ' to: ' + data.message; 83 | client.say(data.receiver, message); 84 | }); 85 | 86 | client.on('PART', function (data) { 87 | /** 88 | The data object contains: 89 | data.receiver : The channel the person parted from, prefixed by a hash (#) 90 | data.sender : The nick of the person who parted 91 | **/ 92 | var privMessage = 'Sorry to see you leave from ' + data.receiver + 93 | ', ' + data.sender + '. Hope to see you again soon!'; 94 | var chanMessage = 'Hmm, seems like ' + data.sender + ' left us'; 95 | client.say(data.receiver, chanMessage); 96 | client.say(data.sender, privMessage); 97 | }); 98 | 99 | client.on('KICK', function (data) { 100 | /** 101 | The data object contains: 102 | data.receiver : The channel the person got kicked out of, prefixed by a hash (#) 103 | data.sender : The nick of the person who kicked out the other person 104 | data.message[0] : The nick of the person who got kicked out 105 | data.message[1] : The optional kick message, will default to the nick of the kicked user 106 | **/ 107 | var privMessage = 'Im sory but you seem to be some kind of an douche, ' + data.message[0] + 108 | ', or else you wouldnt have been kicked by ' + data.sender + 109 | ' on ' + data.receiver + ' because of ' + data.message[1]; 110 | var chanMessage = 'Sorry guys, but ' + data.message[0] + ' had to go!'; 111 | client.say(data.message[0], privMessage); 112 | client.say(data.receiver, chanMessage); 113 | }); 114 | 115 | client.on('QUIT', function (data) { 116 | /** 117 | The data object contains: 118 | data.sender : The nick of the person who quitted 119 | data.message : The quit message (usually deactivated on servers because of spam) 120 | **/ 121 | var message = data.sender + ' has left the building!'; 122 | client.say(chan, message); 123 | }); 124 | 125 | client.on('NICK', function (data) { 126 | /** 127 | The data object contains: 128 | data.receiver : The new nick of the person 129 | data.sender : The old nick of the person 130 | **/ 131 | var message = data.sender + ' changed his nick to ' + data.receiver + '! We got a badass in here ;-)'; 132 | client.say(chan, message); 133 | }); 134 | 135 | client.connect(); 136 | --------------------------------------------------------------------------------