var protocol = { connected: function(){ ircSend(null, settings.ID, 'PASS', [settings.password]); ircSend(null, settings.ID, 'PROTOCTL', ['NICKv2', 'VHP', 'UMODE2', 'NICKIP', 'SJOIN', 'SJOIN2', 'SJ3', 'NOQUIT', 'TKLEXT', 'MLOCK', 'SID', 'MTAGS']); ircSend(null, settings.ID, 'PROTOCTL', ['EAUTH=' + settings.name + ',,,' + settings.version]); ircSend(null, settings.ID, 'PROTOCTL', ['SID=' + settings.ID]); ircSend(null, settings.ID, 'SERVER', [settings.name, '1', settings.description]); }, processMessage: function(msg){ if(!msg) return; if(msg.command in cmdBinds){ cmdBinds[msg.command](msg); } else { console.log('Unhandled cmd: '+msg.command); console.log(msg); } }, processSender: function(sender){ if(sender.nick){ if(server = handlers.findServer(sender.nick)){ sender.nick = server.name; sender.server = server; } else if(user = handlers.findUser(sender.nick)){ sender.nick = user.name sender.ident = user.ident; sender.host = user.host; sender.user = user; } else { handlers.killUser(sender.nick); return false; } } return sender; }, setHandlers: function(newHandlers){ handlers = newHandlers; }, setSettings: function(newSettings){ settings = newSettings; } } module.exports = protocol; var handlers = { sendHandler: null, findServer: null, findUser: null, killUser: null, newServer: null, newUser: null, getChannel: null, findChannel: null, quitUser: null, removeServer: null }; var settings = { ID: null, password: null, name: null, description: null, version: null, me: null, maxUsers: null }; var connection = { 'protoctl': {}, 'prefixes': {}, 'statusmodes': [], 'chmodes': [], // 0 - list modes, 1 - argument modes, 2 - argument modes (add only), 3 - standard modes 'umodes': {} }; var chmodeMap = { 'b': { 'name': 'BAN', 'user': true, 'services': true }, 'e': { 'name': 'EXCEPT', 'user': true, 'services': true }, 'I': { 'name': 'INVEX', 'user': true, 'services': true }, 'v': { 'name': 'VOICE', 'user': true, 'services': true }, 'h': { 'name': 'HALFOP', 'user': true, 'services': true }, 'o': { 'name': 'OP', 'user': true, 'services': true }, 'a': { 'name': 'PROTECT', 'user': true, 'services': true }, 'q': { 'name': 'OWNER', 'user': true, 'services': true }, 'k': { 'name': 'KEY', 'user': true, 'services': true }, 'L': { 'name': 'CHANNELLINK', 'user': true, 'services': true }, 'f': { 'name': 'FLOODPROT', 'user': true, 'services': true }, 'l': { 'name': 'LIMIT', 'user': true, 'services': true }, 'H': { 'name': 'HISTORY', 'user': true, 'services': true }, 'p': { 'name': 'PRIVATE', 'user': true, 'services': true }, 's': { 'name': 'SECRET', 'user': true, 'services': true }, 'm': { 'name': 'MODERATED', 'user': true, 'services': true }, 'n': { 'name': 'NOEXTERNAL', 'user': true, 'services': true }, 't': { 'name': 'TOPIC', 'user': true, 'services': true }, 'i': { 'name': 'INVITE', 'user': true, 'services': true }, 'r': { 'name': 'REGISTERED', 'user': false, 'services': true }, 'z': { 'name': 'SECUREONLY', 'user': true, 'services': true }, 'M': { 'name': 'NONREGMODERATED', 'user': true, 'services': true }, 'Q': { 'name': 'NOKICK', 'user': true, 'services': true }, 'N': { 'name': 'NONICK', 'user': true, 'services': true }, 'R': { 'name': 'NONREGINVITE', 'user': true, 'services': true }, 'T': { 'name': 'NOCTCPS', 'user': true, 'services': true }, 'O': { 'name': 'OPERS', 'user': false, 'services': true }, 'V': { 'name': 'NOINVITE', 'user': true, 'services': true }, 'K': { 'name': 'NOKNOCK', 'user': true, 'services': true }, 'D': { 'name': 'OLDDELAYJOIN', 'user': false, 'services': false }, 'd': { 'name': 'DELAYJOIN', 'user': true, 'services': true }, 'G': { 'name': 'CENSOR', 'user': true, 'services': true }, 'P': { 'name': 'PERMANENT', 'user': false, 'services': true }, 'Z': { 'name': 'SECURE', 'user': false, 'services': false }, 'S': { 'name': 'COLORFILTER', 'user': true, 'services': true }, 'C': { 'name': 'NOCTCP', 'user': true, 'services': true }, 'c': { 'name': 'NOCOLOR', 'user': true, 'services': true } }; var umodeMap = { 'i': { 'name': 'INVISIBLE', 'user': true, 'services': true }, 'o': { 'name': 'OPER', 'user': false, 'services': false }, 'w': { 'name': 'WALLOP', 'user': true, 'services': true }, 'r': { 'name': 'REGISTEREDNICK', 'user': false, 'services': true }, 's': { 'name': 'SNOTICE', 'user': true, 'services': true }, 'x': { 'name': 'CLOAK', 'user': true, 'services': true }, 'z': { 'name': 'SECUREUSER', 'user': false, 'services': false }, 'd': { 'name': 'DEAF', 'user': true, 'services': true }, 'H': { 'name': 'HIDEIRCOP', 'user': false, 'services': false }, 't': { 'name': 'VHOST', 'user': false, 'services': true }, 'I': { 'name': 'HIDEIDLE', 'user': false, 'services': false }, 'D': { 'name': 'PRIVDEAF', 'user': true, 'services': true }, 'Z': { 'name': 'SECUREMESSAGES', 'user': true, 'services': true }, 'R': { 'name': 'REGISTEREDMESSAGES', 'user': true, 'services': true }, 'q': { 'name': 'UNKICKABLE', 'user': false, 'services': false }, 'p': { 'name': 'HIDECHANNELS', 'user': true, 'services': true }, 'W': { 'name': 'WHOISNOTICE', 'user': false, 'services': false }, 'G': { 'name': 'CENSORMESSAGES', 'user': true, 'services': true }, 'T': { 'name': 'NOCTCPMESSAGES', 'user': true, 'services': true }, 'S': { 'name': 'SERVICEUSER', 'user': false, 'services': true }, 'B': { 'name': 'BOT', 'user': true, 'services': true } }; function parseChannelModes(modes, args){ var plus = true; var argIndex = 0; var output = {}; output['status'] = []; output['list'] = []; for(var i=0; i= 0){ output['list'].push({ 'name': name, 'value': args[argIndex++], 'status': plus }); } else if(connection.chmodes[1].indexOf(c) >= 0){ if(plus){ output[name] = args[argIndex++]; } else { output[name] = false; argIndex++; } } else if(connection.chmodes[2].indexOf(c) >= 0){ if(plus){ output[name] = args[argIndex++]; } else { output[name] = false; } } else if(connection.statusmodes.indexOf(c) >= 0){ var user = handlers.findUser(args[argIndex++]); if(user){ output['status'].push({ 'name': name, 'user': user, 'status': plus }); } else { throw 'User not found'; } } else { // treat unknown chars as type 3 if(connection.chmodes[3].indexOf(c) < 0){ console.log('Unknown mode '+name); } output[name] = plus; } } return output; } function parseUmodes(modeString){ var plus = true; var modes = {}; for(var i=0; i 0) ip += ':'; ip += ipBinary[i*2].toString(16).padStart(2, '0') + ipBinary[i*2+1].toString(16).padStart(2, '0'); } } else { throw 'unknown IP format'; } } else { ip = null; } if(vhost == '*'){ vhost = null; } if(cloakedHost == '*'){ cloakedHost = null; } if(account == '0'){ account = null; } handlers.newUser(nick, distance, TS, ident, host, uid, account, parseUmodes(umodes), vhost, cloakedHost, ip, realname, msg.sender.server); }, 'SJOIN': function(msg){ var channel = handlers.getChannel(msg.args[1]); channel.setTS(msg.args[0]); if(msg.args.length > 3){ var modeArgs = []; for(var i=3; i