2016-11-14 15:20:27 +00:00
|
|
|
const EventEmitter = require('events').EventEmitter,
|
|
|
|
net = require('net'),
|
|
|
|
tls = require('tls'),
|
|
|
|
parse = require(__dirname+"/parser");
|
2016-09-23 21:38:09 +00:00
|
|
|
|
|
|
|
if (!String.prototype.format) {
|
|
|
|
String.prototype.format = function() {
|
|
|
|
var args = arguments;
|
|
|
|
return this.replace(/{(\d+)}/g, function(match, number) {
|
|
|
|
return typeof args[number] != undefined ? args[number] : match;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
class IRCConnectionHandler {
|
|
|
|
constructor(connection) {
|
|
|
|
this.conn = connection;
|
|
|
|
}
|
|
|
|
|
2016-09-23 22:35:30 +00:00
|
|
|
handleUserLine(data) {
|
2016-09-24 16:09:03 +00:00
|
|
|
switch(data.command) {
|
2016-09-27 15:13:24 +00:00
|
|
|
case "topic":
|
|
|
|
this.conn.write(('{0} {1}'+(data.message != '' ? ' :'+data.message : '')).format(data.command.toUpperCase(), data.arguments[0]));
|
|
|
|
break;
|
2016-09-24 16:09:03 +00:00
|
|
|
case "kick":
|
2016-09-27 15:13:24 +00:00
|
|
|
this.conn.write('{0} {1} :{2}'.format(data.command.toUpperCase(), data.arguments.join(' '), data.message));
|
|
|
|
break;
|
2016-09-24 16:09:03 +00:00
|
|
|
case "part":
|
|
|
|
this.conn.write('{0} {1} :{2}'.format(data.command.toUpperCase(), data.arguments[0], data.message));
|
|
|
|
break;
|
|
|
|
case "nick":
|
|
|
|
case "whois":
|
|
|
|
case "who":
|
2016-09-27 15:13:24 +00:00
|
|
|
case "names":
|
2016-09-24 16:09:03 +00:00
|
|
|
case "join":
|
|
|
|
this.conn.write('{0} {1}'.format(data.command.toUpperCase(), data.arguments[0]));
|
|
|
|
break;
|
|
|
|
case "quit":
|
2016-10-02 12:08:36 +00:00
|
|
|
this.conn.write('{0} :{1}'.format(data.command.toUpperCase(), (data.message == '' ?
|
|
|
|
this.conn.globalConfig.default_quit_msg : data.message)));
|
2016-09-24 16:09:03 +00:00
|
|
|
break;
|
|
|
|
case "privmsg":
|
|
|
|
this.conn.write('PRIVMSG {0} :{1}'.format(data.arguments[0], data.message));
|
|
|
|
this.conn.emit('pass_to_client', {type: "message", messageType: "privmsg", to: data.arguments[0],
|
|
|
|
user: {nickname: this.conn.config.nickname}, message: data.message, server: data.server});
|
|
|
|
break;
|
|
|
|
case "notice":
|
|
|
|
this.conn.write('NOTICE {0} :{1}'.format(data.arguments[0], data.message));
|
|
|
|
this.conn.emit('pass_to_client', {type: "message", messageType: "notice", to: data.arguments[0],
|
|
|
|
user: {nickname: this.conn.config.nickname}, message: data.message, server: data.server});
|
|
|
|
break;
|
|
|
|
case "list":
|
|
|
|
this.conn.write(data.command.toUpperCase());
|
|
|
|
break;
|
2016-10-01 19:42:17 +00:00
|
|
|
case "ctcp":
|
|
|
|
let ctcpmsg = '';
|
|
|
|
|
|
|
|
if(data.arguments[1].toLowerCase() == 'ping')
|
|
|
|
ctcpmsg = 'PING '+Math.floor(Date.now()/1000);
|
|
|
|
else
|
|
|
|
ctcpmsg = data.message;
|
|
|
|
|
|
|
|
this.conn.write('PRIVMSG {0} :\x01{1}\x01'.format(data.arguments[0], ctcpmsg));
|
|
|
|
this.conn.emit('pass_to_client', {type: "message", messageType: "ctcp_request", to: this.conn.config.nickname,
|
|
|
|
user: {nickname: data.arguments[0]}, message: ctcpmsg, server: data.server});
|
|
|
|
break;
|
2016-09-24 16:09:03 +00:00
|
|
|
default:
|
|
|
|
this.conn.write(data.command.toUpperCase()+' '+data.message);
|
|
|
|
}
|
2016-09-23 22:35:30 +00:00
|
|
|
if(data.targetType == "channel" || data.targetType == "message") {
|
2016-09-24 16:09:03 +00:00
|
|
|
this.conn.write('PRIVMSG {0} :{1}'.format(data.target, data.message));
|
2016-09-23 22:35:30 +00:00
|
|
|
this.conn.emit('pass_to_client', {type: "message", messageType: "privmsg", to: data.target,
|
|
|
|
user: {nickname: this.conn.config.nickname}, message: data.message, server: data.server});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:09:03 +00:00
|
|
|
whoisManage(whom, list) {
|
|
|
|
if(!this.conn.queue.whois)
|
|
|
|
this.conn.queue.whois = {};
|
|
|
|
|
|
|
|
if(!this.conn.queue.whois[whom])
|
|
|
|
this.conn.queue.whois[whom] = list;
|
|
|
|
else
|
|
|
|
for(let a in list)
|
|
|
|
this.conn.queue.whois[whom][a] = list[a];
|
|
|
|
}
|
|
|
|
|
2016-09-30 10:37:35 +00:00
|
|
|
ctcpManage(data) {
|
|
|
|
let line = data.trailing.replace(/\x01/g, '').trim().split(' ');
|
2016-10-02 12:08:36 +00:00
|
|
|
|
2016-09-30 10:37:35 +00:00
|
|
|
if(!line[0]) return;
|
2016-10-02 12:08:36 +00:00
|
|
|
line[0] = line[0].toUpperCase();
|
2016-09-30 10:37:35 +00:00
|
|
|
|
|
|
|
let resp = "\x01"+line[0]+" {0}\x01";
|
|
|
|
|
2016-10-02 12:08:36 +00:00
|
|
|
if(line[0] == "PING" && line[1] != null && line[1] != '') {
|
|
|
|
resp = resp.format(line.slice(1).join(' '));
|
2016-11-14 15:20:27 +00:00
|
|
|
} else if(line[0] == "CLIENTINFO") {
|
|
|
|
resp = resp.format("CLIENTINFO PING "+Object.keys(this.conn.extras.ctcps).join(" "));
|
2016-10-02 12:08:36 +00:00
|
|
|
} else if(this.conn.extras.ctcps && this.conn.extras.ctcps[line[0]] != null) {
|
|
|
|
resp = resp.format(this.conn.extras.ctcps[line[0]](data, this.conn));
|
|
|
|
} else {
|
|
|
|
resp = null;
|
2016-09-30 10:37:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (resp != null)
|
|
|
|
this.conn.write("NOTICE {0} :{1}".format(data.user.nickname, resp));
|
|
|
|
|
|
|
|
return resp != null;
|
|
|
|
}
|
|
|
|
|
2016-09-23 21:38:09 +00:00
|
|
|
handleServerLine(line) {
|
|
|
|
if(this.conn.queue["supportsmsg"] && line.command != "005") {
|
|
|
|
|
|
|
|
delete this.conn.queue["supportsmsg"];
|
|
|
|
|
|
|
|
if(this.conn.config.autojoin.length > 0)
|
|
|
|
for(let t in this.conn.config.autojoin)
|
2016-09-24 16:09:03 +00:00
|
|
|
this.conn.write('JOIN '+this.conn.config.autojoin[t]);
|
2016-09-23 21:38:09 +00:00
|
|
|
|
|
|
|
this.conn.emit('authenticated', {});
|
|
|
|
}
|
|
|
|
|
|
|
|
let serverName = this.conn.config.server;
|
|
|
|
let realServerName = this.conn.data.actualServer;
|
2016-09-24 17:30:39 +00:00
|
|
|
if(line.user.nickname == '')
|
|
|
|
realServerName = line.user.hostname;
|
2016-09-23 21:38:09 +00:00
|
|
|
|
2016-09-24 16:09:03 +00:00
|
|
|
let list = null;
|
2016-09-23 21:38:09 +00:00
|
|
|
switch(line.command) {
|
|
|
|
case "error":
|
2016-09-23 22:35:30 +00:00
|
|
|
this.conn.emit("connerror", {type: "irc_error", raw: line.raw});
|
2016-09-23 21:38:09 +00:00
|
|
|
break;
|
|
|
|
case "001":
|
2016-09-23 22:35:30 +00:00
|
|
|
this.conn.data.actualServer = line.user.hostname;
|
2016-09-23 21:38:09 +00:00
|
|
|
break
|
|
|
|
case "005":
|
|
|
|
if(!this.conn.queue["supportsmsg"])
|
|
|
|
this.conn.queue["supportsmsg"] = true;
|
|
|
|
|
2016-09-23 22:35:30 +00:00
|
|
|
this.conn.authenticated = true;
|
|
|
|
|
2016-09-23 21:38:09 +00:00
|
|
|
let argv = line.arguments.slice(1);
|
|
|
|
for(let a in argv) {
|
|
|
|
let t = argv[a];
|
|
|
|
if(t.indexOf('=') != -1) {
|
|
|
|
t = t.split('=');
|
|
|
|
if(t[0] === 'PREFIX') {
|
|
|
|
let d = t[1].match(/\((\w+)\)(.*)/);
|
|
|
|
let r = d[1].split('');
|
|
|
|
let aa = d[2].split('');
|
|
|
|
for(let b in r)
|
|
|
|
this.conn.data.supportedModes[r[b]] = aa[b];
|
|
|
|
} else if(t[0] === 'NETWORK') {
|
|
|
|
this.conn.data.network = t[1];
|
2016-09-24 16:09:03 +00:00
|
|
|
} else if(t[0] === 'CHANNELLEN') {
|
|
|
|
this.conn.data.max_channel_length = parseInt(t[1]);
|
2016-09-23 21:38:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this.conn.data.serverSupports[t[0]] = t[1];
|
|
|
|
} else {
|
|
|
|
this.conn.data.serverSupports[t] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "JOIN":
|
2016-11-14 15:20:27 +00:00
|
|
|
if(line.trailing) {
|
|
|
|
this.conn.emit('pass_to_client', {type: "event_join_channel", user: line.user, channel: line.trailing, server: serverName });
|
|
|
|
} else {
|
|
|
|
for(let i in line.arguments) {
|
|
|
|
this.conn.emit('pass_to_client', {type: "event_join_channel", user: line.user, channel: line.arguments[i], server: serverName });
|
|
|
|
}
|
|
|
|
}
|
2016-09-23 21:38:09 +00:00
|
|
|
break;
|
|
|
|
case "PART":
|
|
|
|
this.conn.emit('pass_to_client', {type: "event_part_channel", user: line.user, channel: line.arguments[0], reason: line.trailing, server: serverName });
|
|
|
|
break;
|
|
|
|
case "QUIT":
|
|
|
|
this.conn.emit('pass_to_client', {type: "event_quit", user: line.user, reason: line.trailing, server: serverName });
|
|
|
|
break;
|
|
|
|
case "353":
|
|
|
|
if(!this.conn.queue["names"])
|
|
|
|
this.conn.queue['names'] = {};
|
|
|
|
|
|
|
|
let splittrail = line.trailing.split(' ');
|
|
|
|
for(let a in splittrail) {
|
|
|
|
let nick = splittrail[a];
|
|
|
|
if(nick.trim() == "") continue;
|
|
|
|
if(this.conn.queue["names"][line.arguments[2]])
|
|
|
|
this.conn.queue["names"][line.arguments[2]].push(nick);
|
|
|
|
else
|
|
|
|
this.conn.queue["names"][line.arguments[2]] = [nick];
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case "366":
|
|
|
|
if(!this.conn.queue["names"]) break;
|
|
|
|
if(this.conn.queue["names"][line.arguments[1]]) {
|
|
|
|
this.conn.emit('pass_to_client', {type: "channel_nicks", channel: line.arguments[1], nicks: this.conn.queue["names"][line.arguments[1]], server: serverName});
|
|
|
|
delete this.conn.queue["names"][line.arguments[1]];
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Object.keys(this.conn.queue["names"]).length == 0)
|
|
|
|
delete this.conn.queue["names"];
|
2016-11-14 15:20:27 +00:00
|
|
|
|
2016-09-23 21:38:09 +00:00
|
|
|
break;
|
|
|
|
case "PRIVMSG":
|
2016-09-30 10:37:35 +00:00
|
|
|
if(line.trailing.indexOf('\x01') == 0 && line.trailing.indexOf('\x01ACTION') != 0)
|
|
|
|
return this.ctcpManage(line);
|
2016-09-23 21:38:09 +00:00
|
|
|
|
|
|
|
if(line.user.nickname != "")
|
2016-10-01 19:42:17 +00:00
|
|
|
this.conn.emit('pass_to_client', {type: "message", messageType: "privmsg", to: line.arguments[0],
|
2016-09-23 21:38:09 +00:00
|
|
|
user: line.user, message: line.trailing, server: serverName});
|
|
|
|
else
|
2016-10-01 19:42:17 +00:00
|
|
|
this.conn.emit('pass_to_client', {type: "server_message", messageType: "privmsg", message: line.trailing, server: serverName, from: realServerName});
|
2016-09-23 21:38:09 +00:00
|
|
|
break;
|
|
|
|
case "NOTICE":
|
2016-10-01 19:42:17 +00:00
|
|
|
if(line.trailing.indexOf('\x01') == 0 && line.trailing.indexOf('\x01ACTION') != 0) {
|
|
|
|
let composethis = line.trailing.replace(/\x01/g,'').trim().split(" ");
|
|
|
|
composethis[0] = composethis[0].toUpperCase();
|
|
|
|
let message = composethis.join(" ");
|
|
|
|
|
|
|
|
if(composethis[0] == 'PING')
|
|
|
|
message = Math.floor(Date.now()/1000) - composethis[1]+"s";
|
|
|
|
|
|
|
|
this.conn.emit('pass_to_client', {type: "message", messageType: "ctcp_response", to: line.arguments[0],
|
|
|
|
user: line.user, message: message, server: serverName});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-23 21:38:09 +00:00
|
|
|
if(line.user.nickname != "")
|
|
|
|
this.conn.emit('pass_to_client', {type: "message", messageType: "notice", to: line.arguments[0],
|
2016-09-25 14:13:14 +00:00
|
|
|
user: line.user, message: line.trailing, server: serverName});
|
2016-09-23 21:38:09 +00:00
|
|
|
else
|
|
|
|
this.conn.emit('pass_to_client', {type: "server_message", messageType: "notice", message: line.trailing, server: serverName, from: realServerName});
|
|
|
|
break;
|
|
|
|
case "NICK":
|
2016-09-24 16:09:03 +00:00
|
|
|
if(line.user.nickname == this.conn.config.nickname)
|
|
|
|
this.conn.config.nickname = line.arguments[0];
|
|
|
|
|
2016-09-23 21:38:09 +00:00
|
|
|
this.conn.emit('pass_to_client', {type: "nick_change", nick: line.user.nickname, newNick: line.arguments[0], server: serverName});
|
|
|
|
break;
|
|
|
|
case "KICK":
|
2016-09-25 18:48:35 +00:00
|
|
|
this.conn.emit('pass_to_client', {type: "event_kick_channel", user: line.user, channel: line.arguments[0], reason: line.trailing, kickee: line.arguments[1], server: serverName});
|
2016-09-23 21:38:09 +00:00
|
|
|
break;
|
|
|
|
case "TOPIC":
|
|
|
|
this.conn.emit('pass_to_client', {type: "channel_topic", channel: line.arguments[0], set_by: line.user.nickname, topic: line.trailing, server: serverName});
|
|
|
|
break;
|
|
|
|
case "332":
|
|
|
|
this.conn.emit('pass_to_client', {type: "channel_topic", channel: line.arguments[1], topic: line.trailing, server: serverName});
|
|
|
|
break;
|
|
|
|
case "333":
|
|
|
|
this.conn.emit('pass_to_client', {type: "channel_topic", channel: line.arguments[1], set_by: line.arguments[2], time: line.arguments[3], server: serverName});
|
|
|
|
break;
|
|
|
|
case "375":
|
|
|
|
case "372":
|
|
|
|
case "376":
|
|
|
|
this.conn.emit('pass_to_client', {type: "server_message", messageType: "motd", message: line.trailing, server: serverName, from: realServerName});
|
|
|
|
break;
|
2016-12-07 12:58:20 +00:00
|
|
|
case "006":
|
|
|
|
case "007":
|
2016-09-23 21:38:09 +00:00
|
|
|
case "251":
|
2016-12-07 12:58:20 +00:00
|
|
|
case "255":
|
|
|
|
case "270":
|
2016-09-24 16:09:03 +00:00
|
|
|
case "290":
|
|
|
|
case "292":
|
2016-12-07 12:58:20 +00:00
|
|
|
case "323":
|
|
|
|
case "351":
|
2016-09-28 18:51:25 +00:00
|
|
|
case "381":
|
2016-09-23 21:38:09 +00:00
|
|
|
this.conn.emit('pass_to_client', {type: "server_message", messageType: "regular", message: line.trailing, server: serverName, from: realServerName});
|
|
|
|
break;
|
|
|
|
case "252":
|
|
|
|
case "254":
|
2016-09-28 18:51:25 +00:00
|
|
|
case "396":
|
2016-09-23 21:38:09 +00:00
|
|
|
case "042":
|
|
|
|
this.conn.emit('pass_to_client', {type: "server_message", messageType: "regular", message: line.arguments[1] +" "+ line.trailing, server: serverName, from: realServerName});
|
|
|
|
break;
|
2016-09-27 15:59:09 +00:00
|
|
|
case "501":
|
2016-09-27 15:13:24 +00:00
|
|
|
case "401":
|
|
|
|
case "402":
|
|
|
|
case "421":
|
|
|
|
case "482":
|
|
|
|
case "331":
|
|
|
|
case "432":
|
|
|
|
this.conn.emit('pass_to_client', {type: "message", to: null, message: line.arguments[1]+': '+line.trailing,
|
|
|
|
server: serverName, user: {nickname: realServerName}, messageType: "error"});
|
|
|
|
break;
|
2016-09-24 12:25:47 +00:00
|
|
|
case "MODE":
|
|
|
|
let isChannelMode = false;
|
|
|
|
let method = '+';
|
|
|
|
if(line.arguments[0].indexOf('#') != -1)
|
|
|
|
isChannelMode = true;
|
|
|
|
|
|
|
|
let modes = line.arguments[1];
|
2016-09-28 18:51:25 +00:00
|
|
|
|
|
|
|
if(!modes && line.trailing != '')
|
|
|
|
modes = line.trailing;
|
|
|
|
|
|
|
|
let sender = line.user.nickname;
|
|
|
|
if(sender == '')
|
|
|
|
sender = line.user.hostname;
|
|
|
|
|
2016-09-24 12:25:47 +00:00
|
|
|
method = modes.substring(0, 1);
|
|
|
|
modes = modes.substring(1).split('');
|
|
|
|
let pass = [];
|
|
|
|
|
|
|
|
if(isChannelMode) {
|
|
|
|
for(let i in modes) {
|
|
|
|
let mode = modes[i];
|
|
|
|
if(this.conn.data.supportedModes[mode])
|
|
|
|
this.conn.emit('pass_to_client', {type: "mode_"+(method=='+'?'add':'del'), target: line.arguments[0], mode: mode,
|
2016-09-28 18:51:25 +00:00
|
|
|
modeTarget: line.arguments[2+parseInt(i)], server: serverName, user: {nickname: sender}});
|
2016-09-24 12:25:47 +00:00
|
|
|
else
|
|
|
|
pass.push(mode);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pass = modes;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pass.length > 0)
|
2016-09-28 18:51:25 +00:00
|
|
|
this.conn.emit('pass_to_client', {type: "mode", target: line.arguments[0], message: method+pass.join(''),
|
|
|
|
server: serverName, user: {nickname: sender}});
|
2016-09-24 12:25:47 +00:00
|
|
|
break;
|
2016-09-24 16:09:03 +00:00
|
|
|
case "433":
|
|
|
|
let newNick = this.conn.config.nickname + "_";
|
|
|
|
this.conn.write('NICK '+newNick);
|
|
|
|
this.conn.config.nickname = newNick;
|
|
|
|
break;
|
|
|
|
case "311":
|
|
|
|
// start whois queue
|
|
|
|
list = {
|
|
|
|
nickname: line.arguments[1],
|
|
|
|
hostmask: "{0}!{1}@{2}".format(line.arguments[1], line.arguments[2], line.arguments[3]),
|
|
|
|
realname: line.trailing || ""
|
|
|
|
};
|
|
|
|
this.whoisManage(line.arguments[1], list);
|
|
|
|
break;
|
|
|
|
case "319":
|
|
|
|
// whois: channels
|
|
|
|
list = {
|
|
|
|
channels: line.trailing.split(" "),
|
|
|
|
};
|
|
|
|
this.whoisManage(line.arguments[1], list);
|
|
|
|
break;
|
2016-09-25 13:22:20 +00:00
|
|
|
case "378":
|
|
|
|
list = {
|
|
|
|
connectingFrom: line.trailing,
|
|
|
|
};
|
|
|
|
this.whoisManage(line.arguments[1], list);
|
|
|
|
break;
|
|
|
|
case "379":
|
|
|
|
list = {
|
|
|
|
usingModes: line.trailing,
|
|
|
|
};
|
|
|
|
this.whoisManage(line.arguments[1], list);
|
|
|
|
break;
|
2016-09-24 16:09:03 +00:00
|
|
|
case "312":
|
|
|
|
list = {
|
|
|
|
server: line.arguments[2],
|
|
|
|
server_name: line.trailing || ""
|
|
|
|
}
|
|
|
|
this.whoisManage(line.arguments[1], list);
|
|
|
|
break;
|
|
|
|
case "313":
|
|
|
|
list = {
|
|
|
|
title: line.trailing
|
|
|
|
}
|
|
|
|
this.whoisManage(line.arguments[1], list);
|
|
|
|
break;
|
|
|
|
case "330":
|
|
|
|
list = {
|
|
|
|
loggedIn: line.trailing+' '+line.arguments[2]
|
|
|
|
}
|
|
|
|
this.whoisManage(line.arguments[1], list);
|
|
|
|
break;
|
|
|
|
case "335":
|
|
|
|
list = {
|
|
|
|
bot: true
|
|
|
|
}
|
|
|
|
this.whoisManage(line.arguments[1], list);
|
|
|
|
break;
|
|
|
|
case "307":
|
|
|
|
list = {
|
|
|
|
registered: line.trailing
|
|
|
|
}
|
|
|
|
this.whoisManage(line.arguments[1], list);
|
|
|
|
break;
|
|
|
|
case "671":
|
|
|
|
list = {
|
|
|
|
secure: true
|
|
|
|
}
|
|
|
|
this.whoisManage(line.arguments[1], list);
|
|
|
|
break;
|
|
|
|
case "317":
|
|
|
|
list = {
|
|
|
|
signonTime: line.arguments[3],
|
|
|
|
idleSeconds: line.arguments[2]
|
|
|
|
}
|
|
|
|
this.whoisManage(line.arguments[1], list);
|
|
|
|
break;
|
|
|
|
case "318":
|
|
|
|
if(!this.conn.queue.whois || !this.conn.queue.whois[line.arguments[1]])
|
|
|
|
return;
|
2016-11-14 15:20:27 +00:00
|
|
|
|
2016-09-24 16:09:03 +00:00
|
|
|
this.conn.emit('pass_to_client', {type: "whoisResponse", whois: this.conn.queue.whois[line.arguments[1]],
|
|
|
|
server: serverName, from: realServerName});
|
2016-11-14 15:20:27 +00:00
|
|
|
|
2016-09-24 16:09:03 +00:00
|
|
|
delete this.conn.queue.whois[line.arguments[1]];
|
|
|
|
break;
|
|
|
|
case "321":
|
|
|
|
this.conn.emit('pass_to_client', {type: "listedchan", channel: "Channel", users: "Users", topic: "Topic",
|
|
|
|
server: serverName, from: realServerName});
|
|
|
|
break;
|
|
|
|
case "322":
|
|
|
|
this.conn.emit('pass_to_client', {type: "listedchan", channel: line.arguments[1], users: line.arguments[2], topic: line.trailing,
|
|
|
|
server: serverName, from: realServerName});
|
|
|
|
break;
|
2016-10-01 19:42:17 +00:00
|
|
|
case "CAP":
|
|
|
|
// might come in the future, who knows
|
|
|
|
this.conn.write("CAP END");
|
|
|
|
break;
|
2016-09-23 21:38:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class IRCConnection extends EventEmitter {
|
2016-10-02 12:08:36 +00:00
|
|
|
constructor(providedInfo, globalConfig, extras) {
|
2016-09-23 21:38:09 +00:00
|
|
|
super();
|
|
|
|
|
2016-10-02 12:08:36 +00:00
|
|
|
this.globalConfig = globalConfig;
|
|
|
|
this.extras = extras || { authenticationSteps: [], ctcps: {} };
|
2016-09-24 13:24:55 +00:00
|
|
|
this.config = {
|
|
|
|
nickname: "teemant",
|
2016-10-02 12:08:36 +00:00
|
|
|
username: globalConfig.username,
|
|
|
|
realname: globalConfig.realname,
|
2016-09-24 13:24:55 +00:00
|
|
|
server: "localhost",
|
|
|
|
port: 6667,
|
|
|
|
autojoin: [],
|
2016-10-02 12:08:36 +00:00
|
|
|
secure: globalConfig.secure_by_default,
|
2016-09-24 13:24:55 +00:00
|
|
|
password: "",
|
2016-09-25 14:13:14 +00:00
|
|
|
address: "0.0.0.0",
|
2016-10-02 12:08:36 +00:00
|
|
|
rejectUnauthorized: globalConfig.rejectUnauthorizedCertificates
|
2016-09-24 13:24:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
for(let a in providedInfo) {
|
|
|
|
this.config[a] = providedInfo[a];
|
|
|
|
}
|
|
|
|
|
2016-09-23 21:38:09 +00:00
|
|
|
this.socket = null;
|
|
|
|
this.connected = false;
|
|
|
|
this.authenticated = false;
|
|
|
|
|
|
|
|
this.handler = new IRCConnectionHandler(this);
|
|
|
|
|
|
|
|
this.data = {
|
|
|
|
serverSupports: {},
|
|
|
|
network: this.config.server,
|
|
|
|
actualServer: this.config.server,
|
2016-09-24 16:09:03 +00:00
|
|
|
max_channel_length: 64,
|
2016-09-23 21:38:09 +00:00
|
|
|
supportedModes: {}
|
|
|
|
};
|
2016-09-25 14:13:14 +00:00
|
|
|
this.authorizationError = '';
|
2016-09-23 21:38:09 +00:00
|
|
|
this.queue = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
on(...args) {
|
|
|
|
return super.on(...args)
|
|
|
|
}
|
|
|
|
|
|
|
|
emit(...args) {
|
|
|
|
return super.emit(...args);
|
|
|
|
}
|
|
|
|
|
|
|
|
connect() {
|
2016-09-25 14:13:14 +00:00
|
|
|
this.socket = (this.config.secure ? tls : net).connect({port: this.config.port, host: this.config.server,
|
|
|
|
rejectUnauthorized: this.config.rejectUnauthorized}, () => {
|
2016-09-23 21:38:09 +00:00
|
|
|
this.connected = true;
|
|
|
|
this.authenticate();
|
|
|
|
});
|
|
|
|
|
2016-10-02 12:08:36 +00:00
|
|
|
this.socket.setEncoding(this.globalConfig.encoding);
|
|
|
|
this.socket.setTimeout(this.globalConfig.timeout);
|
2016-09-23 21:38:09 +00:00
|
|
|
|
|
|
|
this.socket.on('error', (data) => {
|
2016-09-23 22:35:30 +00:00
|
|
|
this.emit('connerror', {type: "sock_error", message: "A socket error occured.", raw: data});
|
2016-09-23 21:38:09 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
this.socket.on('lookup', (err, address, family, host) => {
|
|
|
|
if(err) {
|
2016-09-23 22:35:30 +00:00
|
|
|
this.emit('connerror', {type: "resolve_error", message: "Failed to resolve host."});
|
2016-09-23 21:38:09 +00:00
|
|
|
} else {
|
|
|
|
this.emit('lookup', {address: address, family: address, host: host});
|
|
|
|
this.config.address = address;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
let buffer = "";
|
|
|
|
this.socket.on('data', (chunk) => {
|
|
|
|
buffer += chunk;
|
|
|
|
let data = buffer.split('\r\n');
|
|
|
|
buffer = data.pop();
|
|
|
|
data.forEach((line) => {
|
|
|
|
if(line.indexOf('PING') === 0) {
|
|
|
|
this.socket.write('PONG'+line.substring(4)+'\r\n');
|
|
|
|
return
|
|
|
|
}
|
|
|
|
this.emit('raw', line);
|
|
|
|
let parsed = parse(line);
|
|
|
|
this.emit('line', parsed);
|
|
|
|
this.handler.handleServerLine(parsed);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
this.socket.on('close', (data) => {
|
2016-09-23 22:35:30 +00:00
|
|
|
if(!this.queue['close'])
|
2016-09-23 21:38:09 +00:00
|
|
|
this.emit('closed', {type: "sock_closed", raw: data, message: "Connection closed."});
|
|
|
|
|
|
|
|
this.connected = false;
|
|
|
|
this.authenticated = false;
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
authenticate() {
|
|
|
|
if (this.config.password)
|
|
|
|
this.socket.write('PASS {0}\r\n'.format(this.config.password));
|
|
|
|
|
2016-10-02 12:08:36 +00:00
|
|
|
if(this.extras.authenticationSteps) {
|
|
|
|
for(let i in this.extras.authenticationSteps) {
|
|
|
|
let step = this.extras.authenticationSteps[i];
|
|
|
|
step.authenticate(this);
|
|
|
|
}
|
|
|
|
}
|
2016-09-25 13:09:55 +00:00
|
|
|
|
2016-09-23 21:38:09 +00:00
|
|
|
this.socket.write('USER {0} 8 * :{1}\r\n'.format(this.config.username, this.config.realname));
|
|
|
|
this.socket.write('NICK {0}\r\n'.format(this.config.nickname));
|
|
|
|
}
|
|
|
|
|
|
|
|
disconnect(message) {
|
|
|
|
if(!this.connected) {
|
2016-09-24 16:09:03 +00:00
|
|
|
this.emit('connerror', {type: "sock_closed", message: "Connection already closed."});
|
2016-09-23 21:38:09 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.queue['close'] = true;
|
2016-10-02 12:08:36 +00:00
|
|
|
this.socket.write('QUIT :{0}\r\n'.format(message != null ? message : this.globalConfig.default_quit_msg));
|
2016-09-23 21:38:09 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 16:09:03 +00:00
|
|
|
write(message) {
|
|
|
|
if(!this.connected) {
|
|
|
|
this.emit('connerror', {type: "sock_closed", message: "Connection is closed."});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.socket.write(message+'\r\n');
|
|
|
|
}
|
2016-09-23 21:38:09 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = IRCConnection;
|