]> git.lizzy.rs Git - luairc.git/blobdiff - src/irc.lua
callbacks need to be able to return values (for, e.g. dcc accept callback)
[luairc.git] / src / irc.lua
index 9376efd3ffb2f98b8f962b844942a6254509aea4..eb75721010580281a15d657039a6773513a0a2f4 100644 (file)
@@ -4,6 +4,8 @@
 -- initialization {{{
 local base =      _G
 local constants = require 'irc.constants'
+local ctcp =      require 'irc.ctcp'
+local c =         ctcp._ctcp_quote
 local irc_debug = require 'irc.debug'
 local message =   require 'irc.message'
 local misc =      require 'irc.misc'
@@ -43,6 +45,7 @@ local icallbacks = {
 local requestinfo = {whois = {}}
 local handlers = {}
 local ctcp_handlers = {}
+local user_handlers = {}
 local serverinfo = {}
 local ip = nil
 -- }}}
@@ -104,6 +107,12 @@ local function incoming_message(sock)
     return true
 end
 -- }}}
+
+-- callback {{{
+local function callback(name, ...)
+    return misc._try_call(user_handlers[name], ...)
+end
+-- }}}
 -- }}}
 
 -- internal message handlers {{{
@@ -113,7 +122,7 @@ function handlers.on_nick(from, new_nick)
     for chan in channels() do
         chan:_change_nick(from, new_nick)
     end
-    misc._try_call(on_nick_change, new_nick, from)
+    callback("nick_change", new_nick, from)
 end
 -- }}}
 
@@ -123,7 +132,7 @@ function handlers.on_join(from, chan)
                 "Received join message for unknown channel: " .. chan)
     if serverinfo.channels[chan].join_complete then
         serverinfo.channels[chan]:_add_user(from)
-        misc._try_call(on_join, serverinfo.channels[chan], from)
+        callback("join", serverinfo.channels[chan], from)
     end
 end
 -- }}}
@@ -135,7 +144,7 @@ function handlers.on_part(from, chan, part_msg)
     if not serverinfo.channels[chan] then return end
     if serverinfo.channels[chan].join_complete then
         serverinfo.channels[chan]:_remove_user(from)
-        misc._try_call(on_part, serverinfo.channels[chan], from, part_msg)
+        callback("part", serverinfo.channels[chan], from, part_msg)
     end
 end
 -- }}}
@@ -159,14 +168,14 @@ function handlers.on_mode(from, to, mode_string, ...)
             -- information request commands
             if mode == "o" then -- channel op {{{
                 chan:_change_status(target, dir == "+", "o")
-                misc._try_call(({["+"] = on_op, ["-"] = on_deop})[dir],
-                               chan, from, target)
+                callback(({["+"] = "op", ["-"] = "deop"})[dir],
+                         chan, from, target)
                 ind = ind + 1
                 -- }}}
             elseif mode == "v" then -- voice {{{
                 chan:_change_status(target, dir == "+", "v")
-                misc._try_call(({["+"] = on_voice, ["-"] = on_devoice})[dir],
-                               chan, from, target)
+                callback(({["+"] = "voice", ["-"] = "devoice"})[dir],
+                         chan, from, target)
                 ind = ind + 1
                 -- }}}
             end
@@ -201,14 +210,14 @@ function handlers.on_topic(from, chan, new_topic)
     serverinfo.channels[chan]._topic.user = (misc.parse_user(from))
     serverinfo.channels[chan]._topic.time = os.time()
     if serverinfo.channels[chan].join_complete then
-        misc._try_call(on_topic_change, serverinfo.channels[chan])
+        callback("topic_change", serverinfo.channels[chan])
     end
 end
 -- }}}
 
 -- on_invite {{{
 function handlers.on_invite(from, to, chan)
-    misc._try_call(on_invite, from, chan)
+    callback("invite", from, chan)
 end
 -- }}}
 
@@ -218,7 +227,7 @@ function handlers.on_kick(from, chan, to)
                 "Received kick message for unknown channel: " .. chan)
     if serverinfo.channels[chan].join_complete then
         serverinfo.channels[chan]:_remove_user(to)
-        misc._try_call(on_kick, serverinfo.channels[chan], to, from)
+        callback("kick", serverinfo.channels[chan], to, from)
     end
 end
 -- }}}
@@ -239,7 +248,7 @@ function handlers.on_privmsg(from, to, msg)
             if base.type(ctcp_handlers[cb]) == "function" then
                 ctcp_handlers[cb](from, to, table.concat(words, " "))
             else
-                notice(from, {"ERRMSG Unknown query: " .. received_command})
+                notice(from, c("ERRMSG", received_command, ":Unknown query"))
             end
             -- }}}
         else
@@ -247,10 +256,9 @@ function handlers.on_privmsg(from, to, msg)
             if to:sub(1, 1) == "#" then
                 base.assert(serverinfo.channels[to],
                             "Received channel msg from unknown channel: " .. to)
-                misc._try_call(on_channel_msg, serverinfo.channels[to], from,
-                                               msg)
+                callback("channel_msg", serverinfo.channels[to], from, msg)
             else
-                misc._try_call(on_private_msg, from, msg)
+                callback("private_msg", from, msg)
             end
             -- }}}
         end
@@ -277,10 +285,9 @@ function handlers.on_notice(from, to, msg)
             if to:sub(1, 1) == "#" then
                 base.assert(serverinfo.channels[to],
                             "Received channel msg from unknown channel: " .. to)
-                misc._try_call(on_channel_notice, serverinfo.channels[to],
-                               from, msg)
+                callback("channel_notice", serverinfo.channels[to], from, msg)
             else
-                misc._try_call(on_private_notice, from, msg)
+                callback("private_notice", from, msg)
             end
             -- }}}
         end
@@ -293,7 +300,7 @@ function handlers.on_quit(from, quit_msg)
     for name, chan in base.pairs(serverinfo.channels) do
         chan:_remove_user(from)
     end
-    misc._try_call(on_quit, from, quit_msg)
+    callback("quit", from, quit_msg)
 end
 -- }}}
 
@@ -358,7 +365,7 @@ function handlers.on_rpl_endofnames(from, chan)
     base.assert(serverinfo.channels[chan],
                 "Received user information about unknown channel: " .. chan)
     if not serverinfo.channels[chan].join_complete then
-        misc._try_call(on_me_join, serverinfo.channels[chan])
+        callback("me_join", serverinfo.channels[chan])
         serverinfo.channels[chan].join_complete = true
     end
 end
@@ -397,7 +404,7 @@ function handlers.on_rpl_endofmotd(from)
     if not serverinfo.connected then
         serverinfo.connected = true
         serverinfo.connecting = false
-        misc._try_call(on_connect)
+        callback("connect")
     end
 end
 -- }}}
@@ -492,10 +499,10 @@ end
 function ctcp_handlers.on_action(from, to, message)
     if to:sub(1, 1) == "#" then
         base.assert(serverinfo.channels[to],
-        "Received channel msg from unknown channel: " .. to)
-        misc._try_call(on_channel_act, serverinfo.channels[to], from, message)
+                    "Received channel msg from unknown channel: " .. to)
+        callback("channel_act", serverinfo.channels[to], from, message)
     else
-        misc._try_call(on_private_act, from, message)
+        callback("private_act", from, message)
     end
 end
 -- }}}
@@ -506,7 +513,7 @@ end
 function ctcp_handlers.on_dcc(from, to, message)
     local type, argument, address, port, size = base.unpack(misc._split(message, " ", nil, '"', '"'))
     if type == "SEND" then
-        if misc._try_call(on_dcc, from, to, argument, address, port, size) then
+        if callback("dcc", from, to, argument, address, port, size) then
             dcc._accept(argument, address, port)
         end
     elseif type == "CHAT" then
@@ -517,25 +524,25 @@ end
 
 -- on_version {{{
 function ctcp_handlers.on_version(from, to)
-    notice(from, {"VERSION " .. _VERSION .. " running under " .. base._VERSION .. " with " .. socket._VERSION})
+    notice(from, c("VERSION", _VERSION .. " running under " .. base._VERSION .. " with " .. socket._VERSION))
 end
 -- }}}
 
 -- on_errmsg {{{
 function ctcp_handlers.on_errmsg(from, to, message)
-    notice(from, {"ERRMSG " .. message .. "No error has occurred"})
+    notice(from, c("ERRMSG", message, ":No error has occurred"))
 end
 -- }}}
 
 -- on_ping {{{
 function ctcp_handlers.on_ping(from, to, timestamp)
-    notice(from, {"PING " .. timestamp})
+    notice(from, c("PING", timestamp))
 end
 -- }}}
 
 -- on_time {{{
 function ctcp_handlers.on_time(from, to)
-    notice(from, {"TIME " .. os.date()})
+    notice(from, c("TIME", os.date()))
 end
 -- }}}
 -- }}}
@@ -551,7 +558,7 @@ function ctcp_handlers.on_rpl_version(from, to, version)
     local lfrom = from:lower()
     local cb = table.remove(icallbacks.ctcp_version[lfrom], 1)
     cb({version = version, nick = from})
-    if #icallbacks.ctcp_version[lfrom] > 0 then say(from, {"VERSION"})
+    if #icallbacks.ctcp_version[lfrom] > 0 then say(from, c("VERSION"))
     else icallbacks.ctcp_version[lfrom] = nil
     end
 end
@@ -568,7 +575,7 @@ function ctcp_handlers.on_rpl_ping(from, to, timestamp)
     local lfrom = from:lower()
     local cb = table.remove(icallbacks.ctcp_ping[lfrom], 1)
     cb({time = os.time() - timestamp, nick = from})
-    if #icallbacks.ctcp_ping[lfrom] > 0 then say(from, {"PING " .. os.time()})
+    if #icallbacks.ctcp_ping[lfrom] > 0 then say(from, c("PING", os.time()))
     else icallbacks.ctcp_ping[lfrom] = nil
     end
 end
@@ -579,7 +586,7 @@ function ctcp_handlers.on_rpl_time(from, to, time)
     local lfrom = from:lower()
     local cb = table.remove(icallbacks.ctcp_time[lfrom], 1)
     cb({time = time, nick = from})
-    if #icallbacks.ctcp_time[lfrom] > 0 then say(from, {"TIME"})
+    if #icallbacks.ctcp_time[lfrom] > 0 then say(from, c("TIME"))
     else icallbacks.ctcp_time[lfrom] = nil
     end
 end
@@ -747,7 +754,7 @@ end
 function act(name, action)
     if not name then return end
     action = action or ""
-    send("PRIVMSG", name, {"ACTION", action})
+    send("PRIVMSG", name, c("ACTION", action))
 end
 -- }}}
 -- }}}
@@ -850,7 +857,7 @@ function ctcp_ping(cb, nick)
     nick = nick:lower()
     if not icallbacks.ctcp_ping[nick] then
         icallbacks.ctcp_ping[nick] = {cb}
-        say(nick, {"PING " .. os.time()})
+        say(nick, c("PING", os.time()))
     else
         table.insert(icallbacks.ctcp_ping[nick], cb)
     end
@@ -871,7 +878,7 @@ function ctcp_time(cb, nick)
     nick = nick:lower()
     if not icallbacks.ctcp_time[nick] then
         icallbacks.ctcp_time[nick] = {cb}
-        say(nick, {"TIME"})
+        say(nick, c("TIME"))
     else
         table.insert(icallbacks.ctcp_time[nick], cb)
     end
@@ -892,7 +899,7 @@ function ctcp_version(cb, nick)
     nick = nick:lower()
     if not icallbacks.ctcp_version[nick] then
         icallbacks.ctcp_version[nick] = {cb}
-        say(nick, {"VERSION"})
+        say(nick, c("VERSION"))
     else
         table.insert(icallbacks.ctcp_version[nick], cb)
     end
@@ -900,6 +907,23 @@ end
 -- }}}
 -- }}}
 
+-- callback functions {{{
+-- register_callback {{{
+---
+-- Register a user function to be called when a specific event occurs.
+-- @param name Name of the event
+-- @param fn   Function to call when the event occurs, or nil to clear the
+--             callback for this event
+-- @return Value of the original callback for this event (or nil if no previous
+--         callback had been set)
+function register_callback(name, fn)
+    local old_handler = user_handlers[name]
+    user_handlers[name] = fn
+    return old_handler
+end
+-- }}}
+-- }}}
+
 -- misc functions {{{
 -- send {{{
 -- TODO: CTCP quoting should be explicit, this table thing is quite ugly (if
@@ -915,18 +939,10 @@ function send(command, ...)
     if not serverinfo.connected and not serverinfo.connecting then return end
     local message = command
     for i, v in base.ipairs({...}) do
-        local arg
-        -- passing a table in as an argument means to treat that table as a
-        -- CTCP command, so quote it appropriately
-        if base.type(v) == "string" then
-            arg = v
-        elseif base.type(v) == "table" then
-            arg = ctcp._ctcp_quote(table.concat(v, " "))
-        end
         if i == #{...} then
-            arg = ":" .. arg
+            v = ":" .. v
         end
-        message = message .. " " .. arg
+        message = message .. " " .. v
     end
     message = ctcp._low_quote(message)
     -- we just truncate for now. -2 to account for the \r\n