import { logger } from "../log.js"; const net = require("net") , tls = require("tls") , EventEmitter = require("events").EventEmitter , util = require("util") , fs = require("fs"); class irc { constructor(options) { EventEmitter.call(this); this.options = options || {}; this.options.channels = this.options.channels || []; this.options.host = this.options.host || "127.0.0.1"; this.options.port = this.options.port || 6667; this.options.ssl = this.options.ssl || false; this.options.selfSigned = this.options.selfSigned || false; this.options.sasl = this.options.sasl || false; this.network = this.options.network || "test"; this.nickname = this.options.nickname || "test"; this.username = this.options.username || "test"; this.realname = this.options.realname || "test"; this.channels = this.options.channels || []; this._recachetime = 60 * 5; // 5 minutes this._cmd = new Map(); const files = fs.readdirSync(`${__dirname}/irc/`); for(let file in files) { if(files[file].substr(-3, 3) === ".js") { logger.debug(`(${this.network}) loading cmd: ${files[file]}`); require(`${__dirname}/irc/${files[file]}`)(this); } } this.server = { motd: "", me: {}, channel: [], user: new Map() }; this.socket = (this.options.ssl ? tls : net).connect({ host: this.options.host, port: this.options.port, rejectUnauthorized: !this.options.selfSigned }, () => { this.send(`NICK ${this.nickname}`); this.send(`USER ${this.username} 0 * : ${this.realname}`); if(this.options.sasl) this.send("CAP LS"); }); this.socket.setEncoding("utf-8"); this.socket.on("data", msg => { msg = msg.split(/\r?\n|\r/); for(let tmp in msg) { if(msg[tmp].length > 0) { const cmd = this.parse(msg[tmp]); if(this._cmd.has(cmd.command)) this._cmd.get(cmd.command)(cmd); } } }); } send(data) { this.socket.write(`${data}\n`); logger.debug(`(${this.network}) out: ${data}`); } parse(data, [a, ...b] = data.split(/ +:/)) { let tmp = a.split(" ").concat(b); logger.debug(`(${this.network}) in: ${[...tmp]}`); return data.charAt(0) === ":" ? { prefix: tmp.shift(), command: tmp.shift(), params: tmp } : { prefix: null, command: tmp.shift(), params: tmp }; } reply(tmp) { return { type: "irc", network: this.network, channel: tmp.params[0], user: this.parsePrefix(tmp.prefix), message: tmp.params[1], time: ~~(Date.now() / 1000), raw: tmp, reply: msg => this.send(`PRIVMSG ${tmp.params[0]} :${this.format(""+msg)}`), replyAction: msg => this.send(`PRIVMSG ${tmp.params[0]} :\u0001ACTION ${this.format(""+msg)}\u0001`), replyNotice: msg => this.send(`NOTICE ${tmp.params[0]} :${this.format(""+msg)}`), _chan: this.server.channel[tmp.params[0]], _user: this.server.user, _cmd: this._cmd, join: chan => this.join(chan), part: (chan, msg) => this.part(chan, msg), whois: user => this.whois(user), write: msg => this.send(msg) }; } join(channel) { this.send(`JOIN ${(typeof channel === "object") ? channel.join(",") : channel}`); } part(channel, msg=false) { this.send(`PART ${(typeof channel === "object") ? channel.join(",") : channel}${msg ? " " + msg : " part"}`); } whois(user, force = false) { user = user.toLowerCase(); if(this.server.user.hasi(user) && !force) if(this.server.user.geti(user).cached >= ~~(Date.now() / 1000) - this._recachetime) return; this.send(`WHOIS ${user}`); } parsePrefix(prefix) { prefix = /:?(.*)\!(.*)@(.*)/.exec(prefix); return { nick: prefix[1], username: prefix[2], hostname: prefix[3] }; } format(msg) { return msg; /*return msg .replace(/\[b\](.*?)\[\/b\]/g, "\x02$1\x0F") // bold .replace(/\[i\](.*?)\[\/i\]/g, "\x1D$1\x0F") // italic ;*/ } } module.exports = irc; util.inherits(irc, EventEmitter); Map.prototype.hasi = function(val) { for (let [key] of this) if(key.toLowerCase() === val.toLowerCase()) return true; return false; }; Map.prototype.geti = function(val) { for (let [key, value] of this) if(key.toLowerCase() === val.toLowerCase()) return value; return false; }; Map.prototype.deli = function(val) { for (let [key] of this) if(key.toLowerCase() === val.toLowerCase()) this.delete(key); };