forked from GitHub/dbot
PASS authentication and fixed PING-PONG
Signed-off-by: Georg <georg@lysergic.dev>
This commit is contained in:
parent
70a21d2b18
commit
ac3d2761bc
1
jsbot
1
jsbot
@ -1 +0,0 @@
|
|||||||
Subproject commit 4e6af64655674ba1a331910f3ed35b935eaba147
|
|
40
jsbot/README.md
Normal file
40
jsbot/README.md
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
## JSBot
|
||||||
|
|
||||||
|
JSBot is an IRC bot library written in Node JS.
|
||||||
|
|
||||||
|
With features like multiple server support and being 'pretty good, I guess,'
|
||||||
|
JSBot is designed to be the IRC bot library of the future! For an example of a
|
||||||
|
large project which uses JSBot, take a look at
|
||||||
|
[DepressionBot](http://github.com/reality/depressionbot/ "DepressionBot").
|
||||||
|
|
||||||
|
To get started with JSBot, take a look at the 'run.js' example provided with the
|
||||||
|
code, then head on over to the
|
||||||
|
[online documentation](https://github.com/reality/jsbot/wiki/Documentation "JSBot Docs").
|
||||||
|
|
||||||
|
## ChangeLog
|
||||||
|
|
||||||
|
### 0.3 I guess
|
||||||
|
|
||||||
|
* Fixed an edge case with the IRC line tokenisation /potentially/ causing events to be parsed twice
|
||||||
|
* Isolated all core channel/nick list logic in JOIN/PART/KICK/QUIT/NICK handlers
|
||||||
|
* Removed useless timeout in 004 handler, switched it to handle 001 instead
|
||||||
|
* Removed a duplicate send() call for IDENTIFY
|
||||||
|
* Semantically reorganised source code
|
||||||
|
* Various other improvements
|
||||||
|
|
||||||
|
speeddefrost <3
|
||||||
|
|
||||||
|
### 0.2
|
||||||
|
|
||||||
|
* Multiple server support.
|
||||||
|
* Functionality for certain users to ignore listeners with certain tags.
|
||||||
|
* Better 'event' object passed to listeners.
|
||||||
|
* Ability to 'reply' to events.
|
||||||
|
|
||||||
|
### 0.1
|
||||||
|
|
||||||
|
* It connects to a server
|
||||||
|
* Listeners
|
||||||
|
* Ping/Pong
|
||||||
|
* Some of the other functionality you'd expect, like, what do you want from me?
|
||||||
|
|
572
jsbot/jsbot.js
Normal file
572
jsbot/jsbot.js
Normal file
@ -0,0 +1,572 @@
|
|||||||
|
var _ = require('underscore')._,
|
||||||
|
net = require('net'),
|
||||||
|
async = require('async'),
|
||||||
|
tls = require('tls'),
|
||||||
|
Tokenizer = require('./tokenizer');
|
||||||
|
|
||||||
|
var JSBot = function(nick) {
|
||||||
|
this.nick = nick;
|
||||||
|
this.connections = {};
|
||||||
|
this.ignores = {};
|
||||||
|
this.preEmitHooks = [];
|
||||||
|
this.events = {
|
||||||
|
'JOIN': [],
|
||||||
|
'PART': [],
|
||||||
|
'QUIT': [],
|
||||||
|
'NICK': [],
|
||||||
|
'PRIVMSG': [],
|
||||||
|
'MODE': [],
|
||||||
|
'KICK': []
|
||||||
|
};
|
||||||
|
this.addDefaultListeners();
|
||||||
|
};
|
||||||
|
|
||||||
|
// connections
|
||||||
|
|
||||||
|
var Connection = function(name, instance, host, port, owner, onReady, nickserv, password, tlsOptions) {
|
||||||
|
this.name = name;
|
||||||
|
this.instance = instance;
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
this.owner = owner;
|
||||||
|
this.onReady = onReady;
|
||||||
|
this.nickserv = nickserv;
|
||||||
|
this.password = password;
|
||||||
|
this.tlsOptions = tlsOptions;
|
||||||
|
|
||||||
|
this.channels = {};
|
||||||
|
this.commands = {};
|
||||||
|
this.encoding = 'utf8';
|
||||||
|
this.netBuffer = '';
|
||||||
|
this.conn = null;
|
||||||
|
this.lastSent = Date.now();
|
||||||
|
};
|
||||||
|
|
||||||
|
Connection.prototype.connect = function() {
|
||||||
|
|
||||||
|
if((typeof this.port == 'string' || this.port instanceof String) && this.port.substring(0, 1) == '+') {
|
||||||
|
this.conn = tls.connect(parseInt(this.port.substring(1)), this.host, this.tlsOptions);
|
||||||
|
} else {
|
||||||
|
this.conn = net.createConnection(this.port, this.host);
|
||||||
|
}
|
||||||
|
console.log('trying to connect' + this.port + ' ' + this.host);
|
||||||
|
|
||||||
|
this.conn.setTimeout(60 * 60 * 1000);
|
||||||
|
this.conn.setEncoding(this.encoding);
|
||||||
|
this.conn.setKeepAlive(enable=true, 10000);
|
||||||
|
|
||||||
|
connectListener = function() {
|
||||||
|
this.send('NICK', this.instance.nick);
|
||||||
|
//this.send('USER', this.instance.nick, '0', '*', this.instance.nick);
|
||||||
|
this.send('PASS ' + this.instance.nick + ':' + this.password);
|
||||||
|
this.send('USER', this.instance.nick + ' ' + this.instance.nick + ' ' + this.instance.nick, ' ', this.instance.nick);
|
||||||
|
}.bind(this);
|
||||||
|
|
||||||
|
this.conn.addListener('connect', connectListener.bind(this));
|
||||||
|
this.conn.addListener('secureConnect', connectListener.bind(this));
|
||||||
|
this.conn.addListener('error', function(err) {
|
||||||
|
console.log('hi')
|
||||||
|
console.log(err);
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.conn.addListener('data', function(chunk) {
|
||||||
|
this.netBuffer += chunk;
|
||||||
|
console.log(chunk)
|
||||||
|
|
||||||
|
var t = new Tokenizer(this.netBuffer);
|
||||||
|
while(true) {
|
||||||
|
var line = t.tokenize('\r\n');
|
||||||
|
if(line == null) {
|
||||||
|
this.netBuffer = t.tokenize(null);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.instance.parse(this, line);
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
Connection.prototype.send = function() {
|
||||||
|
var message = [].splice.call(arguments, 0).join(' ');
|
||||||
|
//if(Date.now() > this.lastSent + 500) {
|
||||||
|
message += '\r\n';
|
||||||
|
this.conn.write(message, this.encoding);
|
||||||
|
this.lastSent = Date.now();
|
||||||
|
//} else {
|
||||||
|
/* setImmediate(function() {
|
||||||
|
this.send(message);
|
||||||
|
}.bind(this));
|
||||||
|
}*/
|
||||||
|
};
|
||||||
|
|
||||||
|
Connection.prototype.pong = function(message) {
|
||||||
|
this.send('PONG', ':' ); //+ message.split(':')[1]);
|
||||||
|
};
|
||||||
|
|
||||||
|
Connection.prototype.join = function(channel) {
|
||||||
|
this.send('JOIN', channel);
|
||||||
|
};
|
||||||
|
|
||||||
|
Connection.prototype.part = function(channel) {
|
||||||
|
this.send('PART', channel);
|
||||||
|
};
|
||||||
|
|
||||||
|
JSBot.prototype.addConnection = function(name, host, port, owner, onReady, nickserv, password, tlsOptions) {
|
||||||
|
tlsOptions = tlsOptions || {};
|
||||||
|
tlsOptions = _.defaults(tlsOptions, {rejectUnauthorized: false});
|
||||||
|
this.connections[name] = new Connection(name, this, host, port, owner, onReady,
|
||||||
|
nickserv, password, tlsOptions);
|
||||||
|
};
|
||||||
|
|
||||||
|
JSBot.prototype.connect = function(name) {
|
||||||
|
var conn = this.connections[name];
|
||||||
|
this.addListener('001', 'onReady', function(event) {
|
||||||
|
conn.instance.say(conn.name, conn.nickserv, 'IDENTIFY ' + this.nick + " " + conn.password);
|
||||||
|
setTimeout(function() {
|
||||||
|
if(conn.onReady != null)
|
||||||
|
conn.onReady(event);
|
||||||
|
}, 5000);
|
||||||
|
});
|
||||||
|
|
||||||
|
conn.connect();
|
||||||
|
};
|
||||||
|
|
||||||
|
JSBot.prototype.connectAll = function() {
|
||||||
|
_.each(this.connections, function(connection, name) {
|
||||||
|
this.connect(name);
|
||||||
|
}, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
// event parsing and processing
|
||||||
|
|
||||||
|
JSBot.prototype.parse = function(connection, input) {
|
||||||
|
var event = new Event(this),
|
||||||
|
t = new Tokenizer(input);
|
||||||
|
|
||||||
|
event.server = connection.name;
|
||||||
|
event.allChannels = this.connections[event.server].channels;
|
||||||
|
|
||||||
|
if(input[0] == ':') {
|
||||||
|
// consume to next whitespace, strip leading ':'
|
||||||
|
var prefix = t.tokenize(' '),
|
||||||
|
maskMatch = prefix.match(/:(.+)!(.+)@(.+)/);
|
||||||
|
|
||||||
|
if(maskMatch && maskMatch.length == 4) {
|
||||||
|
event.user = maskMatch[1];
|
||||||
|
event.ident = maskMatch[2];
|
||||||
|
event.host = maskMatch[3];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
event.host = prefix.substring(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parameter string extraction */
|
||||||
|
|
||||||
|
// try consuming to beginning of a message
|
||||||
|
var paramsStr = t.tokenize(' :');
|
||||||
|
if(!paramsStr) {
|
||||||
|
// if that fails (no message), fall back to line ending
|
||||||
|
paramsStr = t.tokenize(null);
|
||||||
|
} else {
|
||||||
|
// first attempt succeeded, extract message
|
||||||
|
event.message = t.tokenize(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// split the parameter string
|
||||||
|
event.args = paramsStr.split(' ');
|
||||||
|
// use first item as action, remove from list
|
||||||
|
event.action = event.args.shift();
|
||||||
|
|
||||||
|
// -- Common Event Variables --
|
||||||
|
// All channel/nick/target parameters in server-to-client events are accounted for here.
|
||||||
|
// Others need to be handled manually via event.params.
|
||||||
|
|
||||||
|
if (/^\d+$/.test(event.action)) {
|
||||||
|
var rsp = parseInt(event.action),
|
||||||
|
nickRsps = [ 301, 311, 312, 313, 317, 318, 319, 314,
|
||||||
|
369, 322, 324, 338, 401, 406, 432, 433, 436 ],
|
||||||
|
channelRsps = [ 322, 324, 331, 332, 346, 347, 348, 349,
|
||||||
|
366, 367, 368, 403, 404, 405, 467, 471,
|
||||||
|
473, 474, 475, 476, 477, 478, 482 ],
|
||||||
|
channelNickRsps = [ 325, 341 ],
|
||||||
|
targetRsps = [ 407, 437 ];
|
||||||
|
|
||||||
|
if(nickRsps.indexOf(rsp) != -1) {
|
||||||
|
event.user = event.args[0];
|
||||||
|
}
|
||||||
|
else if(channelRsps.indexOf(rsp) != -1) {
|
||||||
|
event.channel = event.args[0];
|
||||||
|
}
|
||||||
|
else if(channelNickRsps.indexOf(rsp) != -1) {
|
||||||
|
event.channel = event.args[0];
|
||||||
|
event.user = event.args[1];
|
||||||
|
}
|
||||||
|
else if(targetRsps.indexOf(rsp) != -1) {
|
||||||
|
if ('&#!+.~'.indexOf(event.args[0][0]) != -1) {
|
||||||
|
event.channel = event.args[0];
|
||||||
|
} else {
|
||||||
|
event.user = event.args[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(rsp == 352) {
|
||||||
|
event.channel = event.args[0];
|
||||||
|
event.user = event.args[4];
|
||||||
|
}
|
||||||
|
else if(rsp == 353) {
|
||||||
|
event.channel = event.args[2];
|
||||||
|
}
|
||||||
|
else if(rsp == 441) {
|
||||||
|
event.user = event.args[0];
|
||||||
|
event.channel = event.args[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(event.action == 'PRIVMSG') {
|
||||||
|
if('&#!+.~'.indexOf(event.args[0][0]) != -1) {
|
||||||
|
event.channel = event.args[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(event.action == 'JOIN' ||
|
||||||
|
event.action == 'PART' ||
|
||||||
|
event.action == 'TOPIC')
|
||||||
|
{
|
||||||
|
event.channel = event.args[0];
|
||||||
|
}
|
||||||
|
else if(event.action == 'KICK') {
|
||||||
|
event.channel = event.args[0];
|
||||||
|
event.targetUser = event.args[1];
|
||||||
|
}
|
||||||
|
else if(event.action == 'NICK') {
|
||||||
|
event.newNick = event.args[1];
|
||||||
|
event.multiChannel = true;
|
||||||
|
}
|
||||||
|
else if(event.action == 'MODE') {
|
||||||
|
event.channel = event.args[0];
|
||||||
|
event.modeChanges = event.args[1];
|
||||||
|
if(event.args.length > 2) {
|
||||||
|
event.targetUsers = event.args.slice(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(event.action == 'QUIT') {
|
||||||
|
event.multiChannel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(event.multiChannel) {
|
||||||
|
// populate a list of channels this event applies to
|
||||||
|
event.channels = [];
|
||||||
|
for(var ch in event.allChannels) {
|
||||||
|
for(var nick in event.allChannels[ch].nicks) {
|
||||||
|
if(nick == event.user) {
|
||||||
|
event.channels.push(event.allChannels[ch]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(event.channel && event.channel in event.allChannels) {
|
||||||
|
// replace the channel name with it's coresponding object
|
||||||
|
event.channel = event.allChannels[event.channel];
|
||||||
|
} else {
|
||||||
|
event.channel = {
|
||||||
|
'name': event.user,
|
||||||
|
'nicks': {},
|
||||||
|
'toString': function() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run any pre-emit hooks
|
||||||
|
async.eachSeries(this.preEmitHooks, function(hook, callback) {
|
||||||
|
hook(event, callback);
|
||||||
|
}, function(err) {
|
||||||
|
this.emit(event);
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
// for handlers
|
||||||
|
if(event.message) {
|
||||||
|
event.params = event.message.split(' ');
|
||||||
|
} else {
|
||||||
|
event.params = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
JSBot.prototype.addPreEmitHook = function(func) {
|
||||||
|
this.preEmitHooks.push(func);
|
||||||
|
};
|
||||||
|
|
||||||
|
JSBot.prototype.clearHooks = function() {
|
||||||
|
this.preEmitHooks = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
JSBot.prototype.emit = function(event) {
|
||||||
|
if(event.action in this.events) {
|
||||||
|
_.each(this.events[event.action], function(listener) {
|
||||||
|
var eventFunc = listener.listener;
|
||||||
|
|
||||||
|
var channel = false;
|
||||||
|
if(event.channel) {
|
||||||
|
channel = event.channel.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_.isFunction(eventFunc) && this.ignores &&
|
||||||
|
(_.has(this.ignores, event.user) && _.include(this.ignores[event.user], listener.tag)) == false &&
|
||||||
|
(_.has(this.ignores, channel) && _.include(this.ignores[channel], listener.tag)) == false) {
|
||||||
|
try {
|
||||||
|
eventFunc.call(this, event);
|
||||||
|
} catch(err) {
|
||||||
|
console.log('ERROR: ' + eventFunc + '\n' + err);
|
||||||
|
console.log(err.stack.split('\n')[1].trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// client functionality
|
||||||
|
|
||||||
|
JSBot.prototype.say = function(server, channel, msg) {
|
||||||
|
var event = new Event(this);
|
||||||
|
event.server = server;
|
||||||
|
event.channel = channel;
|
||||||
|
event.msg = msg;
|
||||||
|
event.reply(msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
JSBot.prototype.reply = function(event, msg) {
|
||||||
|
this.connections[event.server].send('PRIVMSG ' + event.channel + ' ' + ':' + msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
JSBot.prototype.act = function(event, msg) {
|
||||||
|
this.connections[event.server].send('PRIVMSG', event.channel, '\001ACTION ' + msg + '\001');
|
||||||
|
}
|
||||||
|
|
||||||
|
JSBot.prototype.replyNotice = function(event, msg) {
|
||||||
|
this.connections[event.server].send('NOTICE', event.user , ':' + msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSBot.prototype.join = function(event, channel) {
|
||||||
|
this.connections[event.server].join(channel);
|
||||||
|
};
|
||||||
|
|
||||||
|
JSBot.prototype.part = function(event, channel) {
|
||||||
|
this.connections[event.server].part(channel);
|
||||||
|
};
|
||||||
|
|
||||||
|
JSBot.prototype.mode = function(event, channel, msg) {
|
||||||
|
this.connections[event.server].send('MODE', channel, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSBot.prototype.nick = function(event, nick) {
|
||||||
|
this.connections[event.server].send('NICK', nick);
|
||||||
|
}
|
||||||
|
|
||||||
|
// listeners
|
||||||
|
|
||||||
|
JSBot.prototype.addListener = function(index, tag, func) {
|
||||||
|
if(!(index instanceof Array)) {
|
||||||
|
index = [index];
|
||||||
|
}
|
||||||
|
|
||||||
|
var listener = {
|
||||||
|
'listener': func,
|
||||||
|
'tag': tag
|
||||||
|
};
|
||||||
|
|
||||||
|
_.each(index, function(type) {
|
||||||
|
if(!_.has(this.events, type)) {
|
||||||
|
this.events[type] = [];
|
||||||
|
}
|
||||||
|
this.events[type].push(listener);
|
||||||
|
}, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
JSBot.prototype.removeListeners = function() {
|
||||||
|
this.events = {
|
||||||
|
'JOIN': [],
|
||||||
|
'PART': [],
|
||||||
|
'QUIT': [],
|
||||||
|
'NICK': [],
|
||||||
|
'PRIVMSG': [],
|
||||||
|
'MODE': [],
|
||||||
|
'KICK': []
|
||||||
|
};
|
||||||
|
this.addDefaultListeners();
|
||||||
|
};
|
||||||
|
|
||||||
|
JSBot.prototype.addDefaultListeners = function() {
|
||||||
|
// PING
|
||||||
|
this.addListener('PING', 'pong', function(event) {
|
||||||
|
this.connections[event.server].pong(event.message);
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
// JOIN
|
||||||
|
this.addListener('JOIN', 'joinname', function(event) {
|
||||||
|
if(event.user != this.nick) {
|
||||||
|
if(!_.has(this.connections[event.server].channels[event.channel].nicks, event.user)) {
|
||||||
|
this.connections[event.server].channels[event.channel].nicks[event.user] = {
|
||||||
|
'name': event.user,
|
||||||
|
'op': false,
|
||||||
|
'voice': false,
|
||||||
|
'toString': function() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
event.user = this.connections[event.server].channels[event.channel].nicks[event.user];
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
// PART
|
||||||
|
this.addListener('PART', 'partname', function(event) {
|
||||||
|
if(event.user == this.nick)
|
||||||
|
delete this.connections[event.server].channels[event.channel];
|
||||||
|
else
|
||||||
|
delete event.channel.nicks[event.user];
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
// KICK
|
||||||
|
this.addListener('KICK', 'kickname', function(event) {
|
||||||
|
if(event.targetUser == this.nick)
|
||||||
|
delete this.connections[event.server].channels[event.channel];
|
||||||
|
else
|
||||||
|
delete event.channel.nicks[event.user];
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
// QUIT
|
||||||
|
this.addListener('QUIT', 'quitname', function(event) {
|
||||||
|
_.each(event.allChannels, function(channel) {
|
||||||
|
delete event.allChannels[channel].nicks[event.user];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// NICK
|
||||||
|
this.addListener('NICK', 'nickchan', function(event) {
|
||||||
|
if(event.user == this.nick) {
|
||||||
|
this.nick = event.message;
|
||||||
|
} else {
|
||||||
|
_.each(event.allChannels, function(channel) {
|
||||||
|
if(_.has(channel, 'nicks')) {
|
||||||
|
if(event.user in channel.nicks) {
|
||||||
|
channel.nicks[event.message] = channel.nicks[event.user];
|
||||||
|
channel.nicks[event.message].name = event.message;
|
||||||
|
delete channel.nicks[event.user];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
// MODE
|
||||||
|
this.addListener('MODE', 'modop', function(event) {
|
||||||
|
if(!event.modeChanges || !event.targetUsers)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var changeSets = event.modeChanges.match(/[+-][ov]+/);
|
||||||
|
if(!changeSets)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for(var i=0; i < changeSets.length && i < event.targetUsers.length; ++i) {
|
||||||
|
var chanUser = event.channel.nicks[event.targetUsers[i]],
|
||||||
|
prefix = changeSets[i].match(/[+-]/)[0],
|
||||||
|
flags = changeSets[i].match(/[ov]+/)[0],
|
||||||
|
value = prefix == '+';
|
||||||
|
if(!chanUser) {
|
||||||
|
event.channel.nicks[event.targetUsers[i]] = {
|
||||||
|
'name': event.targetUsers[i],
|
||||||
|
'op': false,
|
||||||
|
'voice': false,
|
||||||
|
'toString': function() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
chanUser = event.channel.nicks[event.targetUsers[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var f=0; f < flags.length; ++f) {
|
||||||
|
if(flags[f] == 'o') {
|
||||||
|
chanUser.op = value;
|
||||||
|
}
|
||||||
|
else if(flags[f] == 'v')
|
||||||
|
chanUser.voice = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 353 replies
|
||||||
|
this.addListener('353', 'names', function(event) {
|
||||||
|
|
||||||
|
if(!_.has(this.connections[event.server].channels, event.channel)) {
|
||||||
|
this.connections[event.server].channels[event.channel] = {
|
||||||
|
'name': event.channel,
|
||||||
|
'nicks': {},
|
||||||
|
'toString': function() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
event.channel = this.connections[event.server].channels[event.channel];
|
||||||
|
|
||||||
|
for(var i=0; i < event.params.length; ++i) {
|
||||||
|
var hasFlag = '~&@%+'.indexOf(event.params[i][0]) != -1,
|
||||||
|
name = hasFlag ? event.params[i].slice(1) : event.params[i];
|
||||||
|
|
||||||
|
event.channel.nicks[name] = {
|
||||||
|
'name': name,
|
||||||
|
'op': hasFlag && event.params[i][0] == '@',
|
||||||
|
'voice': hasFlag && event.params[i][0] == '+',
|
||||||
|
'toString': function() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addListener('PRIVMSG', 'ping', function(event) {
|
||||||
|
//if(event.message.match(/\x01PING .+\x01/) != null)
|
||||||
|
event.replyNotice(event.message);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// ignore functionality
|
||||||
|
|
||||||
|
JSBot.prototype.ignoreTag = function(item, tag) {
|
||||||
|
if(_.has(this.ignores, item) == false)
|
||||||
|
this.ignores[item] = [];
|
||||||
|
|
||||||
|
this.ignores[item].push(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSBot.prototype.clearIgnores = function() {
|
||||||
|
this.ignores = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
JSBot.prototype.removeIgnore = function(item, tag) {
|
||||||
|
if(_.has(this.ignores, item) && _.include(this.ignores[item], tag))
|
||||||
|
this.ignores[item].slice(this.ignores[item].indexOf(tag), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// events
|
||||||
|
|
||||||
|
var Event = function(instance) {
|
||||||
|
this.instance = instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
Event.prototype.reply = function(msg) {
|
||||||
|
this.instance.reply(this, msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
Event.prototype.replyNotice = function(msg) {
|
||||||
|
this.instance.replyNotice(this, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// export that shit
|
||||||
|
|
||||||
|
exports.createJSBot = function(name) {
|
||||||
|
return new JSBot(name);
|
||||||
|
};
|
29
jsbot/package.json
Normal file
29
jsbot/package.json
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "jsbot",
|
||||||
|
"version": "0.3.0",
|
||||||
|
"description": "It's a JS IRC library.",
|
||||||
|
"main": "jsbot.js",
|
||||||
|
"dependencies": {
|
||||||
|
"async": "~0.2.9",
|
||||||
|
"underscore": "~1.4.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/reality/jsbot.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"irc",
|
||||||
|
"ssl",
|
||||||
|
"reality",
|
||||||
|
"dbot"
|
||||||
|
],
|
||||||
|
"author": "Luke Slater (reality) <tinmachin3@gmail.com>",
|
||||||
|
"license": "GPL",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/reality/jsbot/issues"
|
||||||
|
}
|
||||||
|
}
|
28
jsbot/run.js
Normal file
28
jsbot/run.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
jsbot = require('./jsbot');
|
||||||
|
|
||||||
|
var instance = jsbot.createJSBot('jsbottest');
|
||||||
|
|
||||||
|
instance.addConnection('aberwiki', 'irc.aberwiki.org', 6667, 'reality', function(event) {
|
||||||
|
instance.join(event, '#realitest');
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
instance.addConnection('freenode', 'irc.freenode.net', 6667, 'reality', function(event) {
|
||||||
|
instance.join(event, '#realitest');
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
instance.addConnection('darchoods', 'irc.darchoods.net', '+6697', 'reality', function(event) {
|
||||||
|
instance.join(event, '#realitest');
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
instance.addPreEmitHook(function(event, callback) {
|
||||||
|
if(event.user) event.user = event.user.toLowerCase();
|
||||||
|
callback(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.addListener('JOIN', 'join', function(event) {
|
||||||
|
event.reply('I love ' + event.user);
|
||||||
|
});
|
||||||
|
|
||||||
|
instance.ignoreTag('jsbottest', 'join');
|
||||||
|
|
||||||
|
instance.connectAll();
|
38
jsbot/tokenizer.js
Normal file
38
jsbot/tokenizer.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* String tokenizer thing.
|
||||||
|
* by speeddefrost <origin206@protonmail.ch>
|
||||||
|
*/
|
||||||
|
|
||||||
|
function Tokenizer(str) {
|
||||||
|
this.str = str;
|
||||||
|
this.pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tokenizer.prototype.tokenize = function(delim) {
|
||||||
|
if(this.pos == -1)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if(!delim) {
|
||||||
|
var leftover = this.str.slice(this.pos);
|
||||||
|
this.pos = -1;
|
||||||
|
return leftover;
|
||||||
|
}
|
||||||
|
|
||||||
|
var i = this.pos,
|
||||||
|
j = this.pos + delim.length
|
||||||
|
z = this.str.length - delim.length;
|
||||||
|
|
||||||
|
while(i <= z) {
|
||||||
|
if(this.str.substring(i,j) == delim) {
|
||||||
|
var token = this.str.substring(this.pos, i);
|
||||||
|
this.pos = j;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
++i; ++j;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Tokenizer;
|
Loading…
Reference in New Issue
Block a user