diff --git a/asyncoperations.lua b/asyncoperations.lua index 9e9ba13..7e65e46 100644 --- a/asyncoperations.lua +++ b/asyncoperations.lua @@ -4,9 +4,7 @@ local error = error local select = select local pairs = pairs -module "irc" - -local meta = _META +local meta = {} function meta:send(msg, ...) if select("#", ...) > 0 then @@ -87,3 +85,5 @@ function meta:setMode(t) self:send("MODE %s %s", verify(target, 3), mode) end + +return meta diff --git a/doc/irc.luadoc b/doc/irc.luadoc index 111de8e..7c175cd 100644 --- a/doc/irc.luadoc +++ b/doc/irc.luadoc @@ -132,10 +132,10 @@ function irc:shutdown() --
  • OnChat(user, channel, message)
  • --
  • OnNotice(user, channel, message)
  • --
  • OnJoin(user, channel)*
  • ---
  • OnPart(user, channel)*
  • +--
  • OnPart(user, channel, reason)*
  • --
  • OnQuit(user, message)
  • --
  • NickChange(user, newnick, channel)*†
  • ---
  • NameList(channel, names)
  • +--
  • NameList(channel, names, message)
  • --
  • OnTopic(channel, topic)
  • --
  • OnTopicInfo(channel, creator, timeCreated)
  • --
  • OnKick(channel, nick, kicker, reason)* (kicker is a user table)
  • @@ -154,7 +154,7 @@ function irc:shutdown() --
  • username - User username.
  • --
  • host - User hostname.
  • --
  • realname - User real name.
  • ---
  • access - User access, available in channel-oriented callbacks. A table containing the boolean fields 'op', 'halfop', and 'voice'.
  • +--
  • access - User access, available in channel-oriented callbacks. A table containing the boolean fields 'owner', 'admin', 'op', 'halfop', and 'voice'.
  • -- -- Apart from nick, fields may be missing. To fill them in, enable user tracking and use irc:whois. -- @name User diff --git a/handlers.lua b/handlers.lua index cbd1c9e..dc71bb2 100644 --- a/handlers.lua +++ b/handlers.lua @@ -3,9 +3,9 @@ local error = error local tonumber = tonumber local table = table -module "irc" +local util = require "irc.util" -handlers = {} +local handlers = {} handlers["PING"] = function(o, prefix, query) o:send("PONG :%s", query) @@ -17,15 +17,15 @@ handlers["001"] = function(o, prefix, me) end handlers["PRIVMSG"] = function(o, prefix, channel, message) - o:invoke("OnChat", parsePrefix(prefix), channel, message) + o:invoke("OnChat", util.parsePrefix(prefix), channel, message) end handlers["NOTICE"] = function(o, prefix, channel, message) - o:invoke("OnNotice", parsePrefix(prefix), channel, message) + o:invoke("OnNotice", util.parsePrefix(prefix), channel, message) end handlers["JOIN"] = function(o, prefix, channel) - local user = parsePrefix(prefix) + local user = util.parsePrefix(prefix) if o.track_users then if user.nick == o.nick then o.channels[channel] = {users = {}} @@ -38,7 +38,7 @@ handlers["JOIN"] = function(o, prefix, channel) end handlers["PART"] = function(o, prefix, channel, reason) - local user = parsePrefix(prefix) + local user = util.parsePrefix(prefix) if o.track_users then if user.nick == o.nick then o.channels[channel] = nil @@ -50,7 +50,7 @@ handlers["PART"] = function(o, prefix, channel, reason) end handlers["QUIT"] = function(o, prefix, msg) - local user = parsePrefix(prefix) + local user = util.parsePrefix(prefix) if o.track_users then for channel, v in pairs(o.channels) do v.users[user.nick] = nil @@ -60,7 +60,7 @@ handlers["QUIT"] = function(o, prefix, msg) end handlers["NICK"] = function(o, prefix, newnick) - local user = parsePrefix(prefix) + local user = util.parsePrefix(prefix) if o.track_users then for channel, v in pairs(o.channels) do local users = v.users @@ -97,8 +97,11 @@ handlers["353"] = function(o, prefix, me, chanType, channel, names) local users = o.channels[channel].users for nick in names:gmatch("(%S+)") do - local access, name = parseNick(nick) - users[name] = {access = access} + local access, name = util.parseNick(nick) + users[name] = { + nick = name; + access = access; + } end end end @@ -106,7 +109,7 @@ end --end of NAMES handlers["366"] = function(o, prefix, me, channel, msg) if o.track_users then - o:invoke("NameList", channel, msg) + o:invoke("NameList", channel, o.channels[channel].users, msg) end end @@ -130,7 +133,15 @@ handlers["333"] = function(o, prefix, me, channel, nick, time) end handlers["KICK"] = function(o, prefix, channel, kicked, reason) - o:invoke("OnKick", channel, kicked, parsePrefix(prefix), reason) + local user = util.parsePrefix(prefix) + if o.track_users then + if user.nick == o.nick then + o.channels[channel] = nil + else + o.channels[channel].users[user.nick] = nil + end + end + o:invoke("OnKick", channel, kicked, user, reason) end --RPL_UMODEIS @@ -164,7 +175,7 @@ handlers["MODE"] = function(o, prefix, target, modes, ...) end end end - o:invoke("OnModeChange", parsePrefix(prefix), target, modes, ...) + o:invoke("OnModeChange", util.parsePrefix(prefix), target, modes, ...) end handlers["ERROR"] = function(o, prefix, message) @@ -172,3 +183,5 @@ handlers["ERROR"] = function(o, prefix, message) o:shutdown() error(message, 3) end + +return handlers diff --git a/init.lua b/init.lua index 99ae7f5..53fabc3 100644 --- a/init.lua +++ b/init.lua @@ -7,19 +7,15 @@ local unpack = unpack local pairs = pairs local assert = assert local require = require -local tonumber = tonumber local type = type local pcall = pcall -module "irc" - local meta = {} meta.__index = meta -_META = meta -require "irc.util" -require "irc.asyncoperations" -require "irc.handlers" +local util = require "irc.util" +for k, v in pairs(require "irc.asyncoperations") do meta[k] = v end +local handlers = require "irc.handlers" local meta_preconnect = {} function meta_preconnect.__index(o, k) @@ -31,16 +27,16 @@ function meta_preconnect.__index(o, k) return v end -function new(data) +local function new(data) local o = { nick = assert(data.nick, "Field 'nick' is required"); username = data.username or "lua"; realname = data.realname or "Lua owns"; - nickGenerator = data.nickGenerator or defaultNickGenerator; + nickGenerator = data.nickGenerator or util.defaultNickGenerator; hooks = {}; track_users = true; } - assert(checkNick(o.nick), "Erroneous nickname passed to irc.new") + assert(util.checkNick(o.nick), "Erroneous nickname passed to irc.new") return setmetatable(o, meta_preconnect) end @@ -172,7 +168,7 @@ function meta:think() local line = getline(self, 3) if line and #line > 0 then if not self:invoke("OnRaw", line) then - self:handle(parse(line)) + self:handle(util.parse(line)) end else break @@ -180,8 +176,6 @@ function meta:think() end end -local handlers = handlers - function meta:handle(prefix, cmd, params) local handler = handlers[cmd] if handler then @@ -205,7 +199,7 @@ function meta:whois(nick) while true do local line = getline(self, 3) if line then - local prefix, cmd, args = parse(line) + local prefix, cmd, args = util.parse(line) local handler = whoisHandlers[cmd] if handler then @@ -231,3 +225,7 @@ function meta:topic(channel) self:send("TOPIC %s", channel) end +return { + _META = meta; + new = new; +} diff --git a/util.lua b/util.lua index 2bdb222..ca262f6 100644 --- a/util.lua +++ b/util.lua @@ -8,10 +8,8 @@ local tostring = tostring local type = type local random = math.random -module "irc" - --protocol parsing -function parse(line) +local function parse(line) local prefix local lineStart = 1 if line:sub(1,1) == ":" then @@ -50,33 +48,41 @@ function parse(line) return prefix, cmd, params end -function parseNick(nick) - local access, name = nick:match("^([%+@]*)(.+)$") +local function parseAccess(accessString) + local access = { + owner = false; + admin = false; + op = false; + halfop = false; + voice = false; + } + for c in accessString:gmatch(".") do + if c == "~" then access.owner = true + elseif c == "&" then access.admin = true + elseif c == "@" then access.op = true + elseif c == "%" then access.halfop = true + elseif c == "+" then access.voice = true + end + end + return access +end + +local function parseNick(nick) + local access, name = nick:match("^([%%+@&~]*)(.+)$") return parseAccess(access or ""), name end -function parsePrefix(prefix) +local function parsePrefix(prefix) local user = {} if prefix then - user.access, user.nick, user.username, user.host = prefix:match("^([%+@]*)(.+)!(.+)@(.+)$") + user.access, user.nick, user.username, user.host = prefix:match("^([%%+@&~]*)(.+)!(.+)@(.+)$") end user.access = parseAccess(user.access or "") return user end -function parseAccess(accessString) - local access = {op = false, halfop = false, voice = false} - for c in accessString:gmatch(".") do - if c == "@" then access.op = true - elseif c == "%" then access.halfop = true - elseif c == "+" then access.voice = true - end - end - return access -end - --mIRC markup scheme (de-facto standard) -color = { +local color = { black = 1, blue = 2, green = 3, @@ -102,20 +108,20 @@ setmetatable(color, {__call = function(_, text, colornum) end}) local boldByte = char(2) -function bold(text) +local function bold(text) return boldByte..text..boldByte end local underlineByte = char(31) -function underline(text) +local function underline(text) return underlineByte..text..underlineByte end -function checkNick(nick) +local function checkNick(nick) return nick:find("^[a-zA-Z_%-%[|%]%^{|}`][a-zA-Z0-9_%-%[|%]%^{|}`]*$") ~= nil end -function defaultNickGenerator(nick) +local function defaultNickGenerator(nick) -- LuaBot -> LuaCot -> LuaCou -> ... -- We change a random charachter rather than appending to the -- nickname as otherwise the new nick could exceed the ircd's @@ -134,3 +140,15 @@ function defaultNickGenerator(nick) return nick end +return { + parse = parse; + parseNick = parseNick; + parsePrefix = parsePrefix; + parseAccess = parseAccess; + + color = color; + bold = bold; + underline = underline; + checkNick = checkNick; + defaultNickGenerator = defaultNickGenerator; +}