irce = require "irce" util = require "irce.util" stringx = require "pl.stringx" moon = require "moon" ln = require "ln" { init: (state) => state.servers = {} state.clients = {} state.channels = {} senders: ["REGISTER"]: (state, password, software, version, sname, real, nicklen) => assert self\PASS password, software, version assert self\SERVER sname, real assert self\NICKLEN nicklen assert self\EMOTD! string.format ":%s PING :%s", sname, sname ["PASS"]: (state, password, software, version) => state.pass = password string.format "PASS %s 0210-IRC+ %s|%s:CHLMSXo", password, software, version ["SERVER"]: (state, sname, real) => state.sname = sname state.servers[sname] = real string.format "SERVER %s 1 :%s", sname, real ["NICKLEN"]: (state, len) => string.format ":%s 005 * NICKLEN=%s :are supported on this server", state.sname, len ["EMOTD"]: (state) => string.format ":%s 376 * :End of MOTD command", state.sname ["KILL"]: (state, who, reason) => string.format ":%s KILL %s :%s: %s", state.sname, who, state.sname, reason ["PING"]: (state, param) => ":" .. state.sname .. " PING :" .. param ["PONG"]: (state, param) => ":" .. state.sname .. " PONG :" .. param ["NICK"]: (state, nick, user, host, modes, real) => state.clients[string.lower nick] = :nick, :user, :host, :modes, :real, metadata: {} string.format ":%s NICK %s 1 %s %s 1 %s :%s", state.sname, nick, user, host, modes, real ["NJOIN"]: (state, channame, who) => string.format ":%s NJOIN %s :%s", state.sname, channame, who ["METADATA"]: (state, nick, key, val) => state.clients[string.lower nick].metadata[key] = val string.format ":%s METADATA %s %s :%s", state.sname, nick, key, val ["VHOST"]: (state, nick, vhost) => self\METADATA nick, "cloakhost", vhost string.format ":%s MODE %s +x", state.sname, nick ["PRIVMSG"]: (state, nick, target, message) => string.format ":%s PRIVMSG %s :%s", nick, target, message ["NOTICE"]: (state, nick, target, message) => string.format ":%s NOTICE %s :%s", nick, target, message ["PART"]: (state, nick, chan, why) => state.channels[chan].members[nick] = nil if #state.channels[chan].members == 0 state.channels[chan] = nil string.format ":%s PART %s :%s", nick, chan, why handlers: ["461"]: (state, sender, params) => self\handle "DIE", string.format("%s: %s", sender[1], params[1]) ["ERROR"]: (state, sender, params) => error string.format "%s: %s", sender[1], params[1] ["PING"]: (state, sender, params) => self\send "PONG", params[1] sender, params[1] ["PONG"]: (state, sender, params) => sender, params[1] ["JOIN"]: (state, sender, params) => chan = params[1] mode = {} bell = string.find chan, "\x07" if bell sp = {string.sub(chan, 1, bell - 1), string.sub(chan, bell + 1)} chan = sp[1] mode = if sp[2] == "o" {"@"} nick = string.lower sender[1] if not state.channels[chan] state.channels[chan] = {name: chan, mode: "", members: {}, topic: ""} state.channels[chan].members[nick] = mode sender[1], state.channels[chan] ["PART"]: (state, sender, params) => chan = params[1] nick = string.lower sender[1] cinfo = state.channels[chan] state.channels[chan].members[nick] = nil if #state.channels[chan].members == 0 state.channels[chan] = nil sender[1], cinfo ["QUIT"]: (state, sender, params) => nick = string.lower sender[1] state.clients[nick] = nil for k, v in pairs state.channels v.members[nick] = nil sender[1], params[1] ["NICK"]: (state, sender, params) => if #params == 1 oldnick = sender[1] oldnicksmall = string.lower oldnick newnick = params[1] cli = state.clients[oldnicksmall] cli.nick = newnick state.clients[string.lower oldnicksmall] = nil nick = string.lower newnick state.clients[string.lower newnick] = cli for k, v in pairs state.channels for kk, vv in pairs v.members if kk == oldnicksmall v.members[nick] = v.members[oldnicksmall] v.members[oldnicksmall] = nil @handle "NICKCHG", sender, state.clients[nick] return nick = params[1] user = params[3] host = params[4] modes = string.sub params[6], 2 real = params[7] metadata = {} state.clients[string.lower nick] = :nick, :user, :host, :modes, :real, :metadata sender, state.clients[string.lower nick] ["METADATA"]: (state, sender, params) => nick = params[1] key = params[2] value = params[3] state.clients[string.lower nick].metadata[key] = value sender, nick, key: value ["NJOIN"]: (state, sender, params) => chan = params[1] whose = stringx.split tostring(params[2]), "," if state.channels[chan] == nil state.channels[chan] = name: chan mode: "" topic: "" members: {} for k, v in pairs whose pfxlen = string.find v, "%a+" nick = string.lower string.sub v, pfxlen prefix = string.sub v, 1, pfxlen - 1 pfxarr = {} for i = 1, #prefix pfxarr[i] = string.sub prefix, i, i state.channels[chan].members[nick] = pfxarr chan, whose ["CHANINFO"]: (state, sender, params) => name = params[1] mode = string.sub params[2], 2 topic = params[#params] key = nil limit = nil if #params == 5 key = params[3] if key == "*" key = nil limit = params[4] if limit == "0" limit = nil state.channels[name] = :name, :mode, :topic, :key, :limit, members: {} state.channels[name] ["PRIVMSG"]: (state, sender, params) => if params[2] == "?state" moon.p state return sender, params if sender[1] == "Cadey" and stringx.startswith params[2], "?eval" code = string.sub(params[2], 7) print string.format "%s %s %s - evaling", params[1], sender[1], code fun, err = load(code, sender[1].."-"..params[1], "t", { state: state, :string, }) if err ~= nil error err result = fun! if result ~= nil self\PRIVMSG state.sname, params[1], tostring result sender, params ["SERVER"]: (state, sender, params) => sname = params[1] real = params[#params] state.servers[sname] = real sender, sname, real ["PASS"]: (state, sender, params) => if params[1] ~= state.pass error "got wrong password from " .. sender[1] state.pass = nil }