diff --git a/asyncoperations.lua b/asyncoperations.lua index bd0c652..a8ea2dd 100644 --- a/asyncoperations.lua +++ b/asyncoperations.lua @@ -1,12 +1,18 @@ local table = table local assert = assert +local select = select module "irc" local meta = _META -function meta:send(fmt, ...) - local bytes, err = self.socket:send(fmt:format(...) .. "\r\n") +function meta:send(msg, ...) + if select("#", ...) > 0 then + msg = msg:format(...) + end + self:invoke("OnSend", msg) + + local bytes, err = self.socket:send(msg .. "\r\n") if not bytes and err ~= "timeout" and err ~= "wantwrite" then self:invoke("OnDisconnect", err, true) diff --git a/doc/irc.luadoc b/doc/irc.luadoc index 85dc229..c8c5d8e 100644 --- a/doc/irc.luadoc +++ b/doc/irc.luadoc @@ -71,9 +71,9 @@ function irc:whois(nick) function irc:topic(channel) --- Send a raw line of IRC to the server. --- @param fmt Line to be sent, excluding newline characters. --- @param ... Format parameters for fmt, with string.format semantics. -function irc:send(fmt, ...) +-- @param msg Line to be sent, excluding newline characters. +-- @param ... Format parameters for msg, with string.format semantics. [optional] +function irc:send(msg, ...) --- Send a message to a channel or user. -- @param target Nick or channel to send to. @@ -125,7 +125,9 @@ function irc:shutdown() --- List of hooks you can use with irc:hook. The parameter list describes the parameters passed to the callback function. -- -- * Event also invoked for yourself. -- † Channel passed only when user tracking is enabled @@ -152,7 +154,7 @@ function irc:shutdown() --
  • username - User username.
  • --
  • host - User hostname.
  • --
  • realname - User real name.
  • ---
  • access - User access, available in channel-oriented callbacks. Can be '+', '@', and others, depending on the server.
  • +--
  • access - User access, available in channel-oriented callbacks. A table containing the boolean fields '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 39d6777..6b892f9 100644 --- a/handlers.lua +++ b/handlers.lua @@ -1,6 +1,7 @@ local pairs = pairs local error = error local tonumber = tonumber +local table = table module "irc" @@ -83,7 +84,7 @@ 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] = {type = access} + users[name] = {access = access} end end end @@ -130,8 +131,26 @@ handlers["324"] = function(o, prefix, user, channel, modes) o:invoke("OnChannelMode", channel, modes) end -handlers["MODE"] = function(o, prefix, target, modes) - o:invoke("OnModeChange", parsePrefix(prefix), target, modes) +handlers["MODE"] = function(o, prefix, target, modes, ...) + if o.track_users and target ~= o.nick then + local add = true + local optList = {...} + for c in modes:gmatch(".") do + if c == "+" then add = true + elseif c == "-" then add = false + elseif c == "o" then + local user = table.remove(optList, 1) + o.channels[target].users[user].access.op = add + elseif c == "h" then + local user = table.remove(optList, 1) + o.channels[target].users[user].access.halfop = add + elseif c == "v" then + local user = table.remove(optList, 1) + o.channels[target].users[user].access.voice = add + end + end + end + o:invoke("OnModeChange", parsePrefix(prefix), target, modes, ...) end handlers["ERROR"] = function(o, prefix, message) diff --git a/init.lua b/init.lua index 3c8aec3..e94aa24 100644 --- a/init.lua +++ b/init.lua @@ -26,7 +26,7 @@ function meta_preconnect.__index(o, k) local v = rawget(meta_preconnect, k) if not v and meta[k] then - error("field '"..k.."' is not accessible before connecting", 2) + error(("field '%s' is not accessible before connecting"):format(k), 2) end return v end @@ -117,6 +117,11 @@ function meta_preconnect:connect(_host, _port) self.socket = s setmetatable(self, meta) + self:send("CAP REQ multi-prefix") + + self:invoke("PreRegister", self) + self:send("CAP END") + if password then self:send("PASS %s", password) end diff --git a/util.lua b/util.lua index 91b9ad4..232ffd6 100644 --- a/util.lua +++ b/util.lua @@ -48,17 +48,30 @@ function parse(line) end function parseNick(nick) - return nick:match("^([%+@]?)(.+)$") + local access, name = nick:match("^([%+@]*)(.+)$") + return parseAccess(access or ""), name end 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 = { black = 1,