/** * From https://github.com/felixge/nodelog/ */ var sys = require( 'util' ); var tcp = require( 'net' ); var irc = exports; function bind( fn, scope ) { var bindArgs = Array.prototype.slice.call( arguments ); bindArgs.shift(); bindArgs.shift(); return function () { var args = Array.prototype.slice.call( arguments ); fn.apply( scope, bindArgs.concat( args ) ); }; } function each( set, iterator ) { for ( var i = 0; i < set.length; i++ ) { var r = iterator( set[i], i ); if ( r === false ) { return; } } } var Client = irc.Client = function ( host, port ) { this.host = host || 'localhost'; this.port = port || 6667; this.connection = null; this.buffer = ''; this.encoding = 'utf8'; this.timeout = 10 * 60 * 60 * 1000; this.nick = null; this.user = null; this.real = null; } sys.inherits( Client, process.EventEmitter ); Client.prototype.connect = function ( nick, user, real ) { var connection = tcp.createConnection( this.port, this.host ); connection.setEncoding( this.encoding ); connection.setTimeout( this.timeout ); connection.addListener( 'connect', bind( this.onConnect, this ) ); connection.addListener( 'data', bind( this.onReceive, this ) ); connection.addListener( 'end', bind( this.onEof, this ) ); connection.addListener( 'timeout', bind( this.onTimeout, this ) ); connection.addListener( 'close', bind( this.onClose, this ) ); this.nick = nick; this.user = user || 'guest'; this.real = real || 'Guest'; this.connection = connection; }; Client.prototype.disconnect = function ( why ) { if ( this.connection.readyState !== 'closed' ) { this.connection.close(); sys.puts( 'disconnected (reason: ' + why + ')' ); this.emit( 'DISCONNECT', why ); } }; Client.prototype.send = function ( arg1 ) { if ( this.connection.readyState !== 'open' ) { return this.disconnect( 'cannot send with readyState: ' + this.connection.readyState ); } var message = []; for ( var i = 0; i < arguments.length; i++ ) { if ( arguments[i] ) { message.push( arguments[i] ); } } message = message.join( ' ' ); sys.puts( '> ' + message ); message = message + "\r\n"; this.connection.write( message, this.encoding ); }; Client.prototype.parse = function ( message ) { var match = message.match( /(?:(:[^\s]+) )?([^\s]+) (.+)/ ); var parsed = { prefix : match[1], command : match[2] }; var params = match[3].match( /(.*?) ?:(.*)/ ); if ( params ) { // Params before : params[1] = (params[1]) ? params[1].split( ' ' ) : []; // Rest after : params[2] = params[2] ? [params[2]] : []; params = params[1].concat( params[2] ); } else { params = match[3].split( ' ' ); } parsed.params = params; return parsed; }; Client.prototype.onConnect = function () { this.send( 'NICK', this.nick ); this.send( 'USER', this.user, '0', '*', ':' + this.real ); }; Client.prototype.onReceive = function ( chunk ) { this.buffer = this.buffer + chunk; while ( this.buffer ) { var offset = this.buffer.indexOf( "\r\n" ); if ( offset < 0 ) { return; } var message = this.buffer.substr( 0, offset ); this.buffer = this.buffer.substr( offset + 2 ); sys.puts( '< ' + message ); message = this.parse( message ); this.emit.apply( this, [message.command, message.prefix].concat( message.params ) ); if ( message !== false ) { this.onMessage( message ); } } }; Client.prototype.onMessage = function ( message ) { switch ( message.command ) { case 'PING': this.send( 'PONG', ':' + message.params[0] ); break; } }; Client.prototype.onEof = function () { this.disconnect( 'eof' ); }; Client.prototype.onTimeout = function () { this.disconnect( 'timeout' ); }; Client.prototype.onClose = function () { this.disconnect( 'close' ); }; exports.user = function ( prefix ) { return prefix.match( /:([^!]+)!/ )[1] };