-- 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'
local requestinfo = {whois = {}}
local handlers = {}
local ctcp_handlers = {}
+local user_handlers = {}
local serverinfo = {}
local ip = nil
-- }}}
return true
end
-- }}}
+
+-- callback {{{
+local function callback(name, ...)
+ return misc._try_call(user_handlers[name], ...)
+end
+-- }}}
-- }}}
-- internal message handlers {{{
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
-- }}}
"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
-- }}}
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
-- }}}
-- 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
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
-- }}}
"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
-- }}}
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
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
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
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
-- }}}
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
if not serverinfo.connected then
serverinfo.connected = true
serverinfo.connecting = false
- misc._try_call(on_connect)
+ callback("connect")
end
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
-- }}}
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
-- 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
-- }}}
-- }}}
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
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
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
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
-- }}}
-- }}}
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
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
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
-- }}}
-- }}}
+-- 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
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