diff --git a/doc/irc.luadoc b/doc/irc.luadoc index 8442cce..4025910 100644 --- a/doc/irc.luadoc +++ b/doc/irc.luadoc @@ -1,7 +1,7 @@ --- LuaIRC is a low-level IRC library for Lua. -- All functions raise Lua exceptions on error. -- --- Use new to create a new IRC object.
+-- Use new to create a new Connection object.
-- Example:

-- --require "irc"
@@ -24,11 +24,12 @@ module "irc" ---- Create a new IRC object. Use irc:connect to connect to a server. +--- Create a new Connection object. Use irc:connect to connect to a server. -- @param user Table with fields nick, username and realname. -- The nick field is required. -- --- @return Returns a new irc object. +-- @return Returns a new Connection object. +-- @see Connection function new(user) --- Hook a function to an event. @@ -49,7 +50,7 @@ function irc:unhook(name, id) function irc:connect(host, port) -- @param table Table of connection details --- @see Connection +-- @see ConnectOptions function irc:connect(table) --- Disconnect irc from the server. @@ -116,16 +117,25 @@ function irc:handle(msg) function irc:shutdown() --- Table with connection information. --- +-- @name ConnectOptions +-- @class table +-- @field host Server host name. +-- @field port Server port. [defaults to 6667] +-- @field timeout Connect timeout. [defaults to 30] +-- @field password Server password. +-- @field secure Boolean to enable TLS connection, pass a params table (described, [luasec]) to control -- [luasec]: http://www.inf.puc-rio.br/~brunoos/luasec/reference.html + +--- Class representing a connection. -- @name Connection -- @class table +-- @field authed Boolean indicating whether the connection has completed registration. +-- @field motd The server's message of the day. Can be nil. +-- @field nick The current nickname. +-- @field realname The real name sent to the server. +-- @field username The username/ident sent to the server. +-- @field socket Raw socket used by the library. +-- @field supports What the server claims to support in it's ISUPPORT message. --- Class representing an IRC message. -- @name Message @@ -145,8 +155,8 @@ 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 diff --git a/handlers.lua b/handlers.lua index d89247c..bc301ab 100644 --- a/handlers.lua +++ b/handlers.lua @@ -8,6 +8,67 @@ handlers["PING"] = function(conn, msg) conn:send(Message({command="PONG", args=msg.args})) end +local function requestWanted(conn, wanted) + local args = {} + for cap, value in pairs(wanted) do + if type(value) == "string" then + cap = cap .. "=" .. value + end + if not conn.capabilities[cap] then + table.insert(args, cap) + end + end + conn:queue(Message({ + command = "CAP", + args = {"REQ", table.concat(args, " ")} + }) + ) +end + +handlers["CAP"] = function(conn, msg) + local cmd = msg.args[2] + if not cmd then + return + end + if cmd == "LS" then + local list = msg.args[3] + local last = false + if list == "*" then + list = msg.args[4] + else + last = true + end + local avail = conn.availableCapabilities + local wanted = conn.wantedCapabilities + for item in list:gmatch("(%S+)") do + local eq = item:find("=", 1, true) + local k, v + if eq then + k, v = item:sub(1, eq - 1), item:sub(eq + 1) + else + k, v = item, true + end + if not avail[k] or avail[k] ~= v then + wanted[k] = conn:invoke("OnCapabilityAvailable", k, v) + end + avail[k] = v + end + if last then + if next(wanted) then + requestWanted(conn, wanted) + end + conn:invoke("OnCapabilityList", conn.availableCapabilities) + end + elseif cmd == "ACK" then + for item in msg.args[3]:gmatch("(%S+)") do + local enabled = (item:sub(1, 1) ~= "-") + local name = enabled and item or item:sub(2) + conn:invoke("OnCapabilitySet", name, enabled) + conn.capabilities[name] = enabled + end + end +end + handlers["001"] = function(conn, msg) conn.authed = true conn.nick = msg.args[1] @@ -17,7 +78,6 @@ handlers["PRIVMSG"] = function(conn, msg) conn:invoke("OnChat", msg.user, msg.args[1], msg.args[2]) end - handlers["NOTICE"] = function(conn, msg) conn:invoke("OnNotice", msg.user, msg.args[1], msg.args[2]) end diff --git a/init.lua b/init.lua index 24a5ff8..a407ca8 100644 --- a/init.lua +++ b/init.lua @@ -7,6 +7,7 @@ local Message = msgs.Message local meta = {} meta.__index = meta + for k, v in pairs(require("irc.asyncoperations")) do meta[k] = v end @@ -33,6 +34,9 @@ function new(data) messageQueue = {}; lastThought = 0; recentMessages = 0; + availableCapabilities = {}; + wantedCapabilities = {}; + capabilities = {}; } assert(util.checkNick(o.nick), "Erroneous nickname passed to irc.new") return setmetatable(o, meta_preconnect) @@ -61,8 +65,9 @@ function meta:invoke(name, ...) local hooks = self.hooks[name] if hooks then for id, f in pairs(hooks) do - if f(...) then - return true + local ret = f(...) + if ret then + return ret end end end @@ -113,10 +118,7 @@ function meta_preconnect:connect(_host, _port) self.socket = s setmetatable(self, meta) - self:queue(Message({command="CAP", args={"REQ", "multi-prefix"}})) - self:invoke("PreRegister", self) - self:queue(Message({command="CAP", args={"END"}})) if password then self:queue(Message({command="PASS", args={password}})) diff --git a/messages.lua b/messages.lua index 46cf8c0..48aa687 100644 --- a/messages.lua +++ b/messages.lua @@ -199,5 +199,9 @@ function m.mode(target, modes) return Message({command="MODE", args={target, unpack(mt)}}) end +function m.cap(cmd, ...) + return Message({command="CAP", args={cmd, ...}}) +end + return m