Bugfixes
- Add global admins table, set disconnect and reload built-in handlers to be accessible by global admins only - Only send an unknown code error in private messages to avoid responding to other bots' codes when there is a prefix collision - Fix server contexts not being updated after a config reload - Fix service codes being improperly parsed in privmsgs when different code prefixes are used - Fix joining channels on some networks when connecting without authentication - Fix disconnecting from one server also causing disconnection from other serverstrunk
parent
9005c0fba5
commit
7963d7221c
|
@ -2,6 +2,16 @@
|
||||||
-- Server configuration
|
-- Server configuration
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- `itte_admins`
|
||||||
|
-- Users who can access administrative functions in the client, not limited to
|
||||||
|
-- the server instance. The username is for the client only and independent of
|
||||||
|
-- IRC network usernames.
|
||||||
|
--
|
||||||
|
-- This variable is optional, but certain handlers like server disconnection
|
||||||
|
-- will not work if it is unset.
|
||||||
|
itte_admins = { globaladmin = "password", }
|
||||||
|
|
||||||
|
|
||||||
-- `itte_servers`
|
-- `itte_servers`
|
||||||
-- Below is a sample server configuration.
|
-- Below is a sample server configuration.
|
||||||
-- If the server does not support CAP negotiation (used for SASL
|
-- If the server does not support CAP negotiation (used for SASL
|
||||||
|
@ -19,6 +29,6 @@ itte_servers = {
|
||||||
auth_user = "botuser",
|
auth_user = "botuser",
|
||||||
auth_pass = "password",
|
auth_pass = "password",
|
||||||
code_prefix = "!",
|
code_prefix = "!",
|
||||||
admins = { adminuser = "password" },
|
admins = { adminuser = "password", },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
196
itte.lua
196
itte.lua
|
@ -47,6 +47,9 @@ itte.servers = {}
|
||||||
-- Store custom handlers
|
-- Store custom handlers
|
||||||
itte.handlers = {}
|
itte.handlers = {}
|
||||||
|
|
||||||
|
-- Store global admins
|
||||||
|
itte.admins = {}
|
||||||
|
|
||||||
-- Internal only: store core handlers
|
-- Internal only: store core handlers
|
||||||
itte._h = {}
|
itte._h = {}
|
||||||
|
|
||||||
|
@ -57,8 +60,8 @@ itte.docs._h = {}
|
||||||
-- Internal only: track application state
|
-- Internal only: track application state
|
||||||
itte.state = {
|
itte.state = {
|
||||||
connected = false,
|
connected = false,
|
||||||
connections = {},
|
|
||||||
}
|
}
|
||||||
|
itte.contexts = {}
|
||||||
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
@ -79,7 +82,7 @@ end
|
||||||
itte.docs.get_config = [[ ()
|
itte.docs.get_config = [[ ()
|
||||||
Load the config file.
|
Load the config file.
|
||||||
]]
|
]]
|
||||||
function itte.get_config()
|
function itte.get_config(reload)
|
||||||
-- If prefix is not set, try custom file names or defaults
|
-- If prefix is not set, try custom file names or defaults
|
||||||
if itte.confs.prefix == nil then
|
if itte.confs.prefix == nil then
|
||||||
util.source_file(itte.confs.config)
|
util.source_file(itte.confs.config)
|
||||||
|
@ -103,6 +106,20 @@ function itte.get_config()
|
||||||
end
|
end
|
||||||
if itte_config ~= nil then itte.config = itte_config end
|
if itte_config ~= nil then itte.config = itte_config end
|
||||||
if itte_handlers ~= nil then itte.handlers = itte_handlers end
|
if itte_handlers ~= nil then itte.handlers = itte_handlers end
|
||||||
|
if itte_admins ~= nil then itte.admins = itte_admins end
|
||||||
|
|
||||||
|
-- If reloading, reconstruct the context tables.
|
||||||
|
-- This only works if the instance name has not changed between reloads.
|
||||||
|
if reload then
|
||||||
|
for instance, prop in pairs(itte.servers) do
|
||||||
|
cxt_old = itte.contexts[instance]
|
||||||
|
itte.contexts[instance] = prop
|
||||||
|
itte.contexts[instance].name = instance
|
||||||
|
itte.contexts[instance].cmds = itte.get_commands(prop)
|
||||||
|
itte.contexts[instance].con = cxt_old.con
|
||||||
|
itte.contexts[instance].con:settimeout(0.5)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -153,9 +170,9 @@ function itte.get_commands(svr)
|
||||||
},
|
},
|
||||||
-- Main commands
|
-- Main commands
|
||||||
join = {
|
join = {
|
||||||
-- 001 is a welcome message
|
|
||||||
-- Cannot join earlier on some servers if not registered
|
-- Cannot join earlier on some servers if not registered
|
||||||
check = "001 " .. svr.nick,
|
-- "MODE" seems to be a more reliable check
|
||||||
|
check = "MODE",
|
||||||
resp = "JOIN ",
|
resp = "JOIN ",
|
||||||
},
|
},
|
||||||
nick = {
|
nick = {
|
||||||
|
@ -177,7 +194,7 @@ function itte.get_commands(svr)
|
||||||
resp = "PONG ",
|
resp = "PONG ",
|
||||||
},
|
},
|
||||||
privmsg = {
|
privmsg = {
|
||||||
check = "PRIVMSG(.*):!",
|
check = "PRIVMSG(.*):" .. svr.code_prefix,
|
||||||
resp = "PRIVMSG ",
|
resp = "PRIVMSG ",
|
||||||
},
|
},
|
||||||
quit = {
|
quit = {
|
||||||
|
@ -214,14 +231,16 @@ function itte.message(cxt, users, str)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
itte.docs.connect_server = [[ (server_table)
|
itte.docs.connect_server = [[ (name_str, server_table)
|
||||||
Initialise a socket connection to a server and return a context table.
|
Initialise a socket connection to a server and return a context table.
|
||||||
]]
|
]]
|
||||||
function itte.connect_server(svr)
|
function itte.connect_server(name, svr)
|
||||||
-- Load server context
|
-- Load server context
|
||||||
local context = svr
|
local context = svr
|
||||||
|
context.name = name
|
||||||
context.cmds = itte.get_commands(svr)
|
context.cmds = itte.get_commands(svr)
|
||||||
context.state = {
|
context.state = {
|
||||||
|
connected = false,
|
||||||
cap_greeted = false,
|
cap_greeted = false,
|
||||||
cap_ls = false,
|
cap_ls = false,
|
||||||
cap_checked = false,
|
cap_checked = false,
|
||||||
|
@ -239,16 +258,43 @@ function itte.connect_server(svr)
|
||||||
verify = "none",
|
verify = "none",
|
||||||
options = "all",
|
options = "all",
|
||||||
}
|
}
|
||||||
|
|
||||||
util.debug("conn", "Connecting to " .. svr.host .. "/" .. svr.port ..
|
util.debug("conn", "Connecting to " .. svr.host .. "/" .. svr.port ..
|
||||||
" ...", itte.config.debug)
|
" ...", itte.config.debug)
|
||||||
context.con:connect(svr.host, svr.port)
|
context.con:connect(svr.host, svr.port)
|
||||||
context.con = ssl.wrap(context.con, con_params)
|
context.con = ssl.wrap(context.con, con_params)
|
||||||
context.con:dohandshake()
|
context.con:dohandshake()
|
||||||
|
-- Set a short timeout to be non-blocking
|
||||||
|
context.con:settimeout(0.1)
|
||||||
|
|
||||||
|
-- Set context and global states
|
||||||
context.state.connected = true
|
context.state.connected = true
|
||||||
|
itte.state.connected = true
|
||||||
|
|
||||||
return context
|
return context
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
itte.docs.disconnect_server = [[ (name_str)
|
||||||
|
Close a socket connection to a server.
|
||||||
|
]]
|
||||||
|
function itte.disconnect_server(name)
|
||||||
|
if itte.contexts[name] ~= nil then
|
||||||
|
util.debug("conn", "Connection to " .. name .. " closed.",
|
||||||
|
itte.config.debug)
|
||||||
|
end
|
||||||
|
itte.contexts[name].con:close()
|
||||||
|
itte.contexts[name] = nil
|
||||||
|
|
||||||
|
-- Check if it is the last connection and trigger client exit
|
||||||
|
-- if no connections remain
|
||||||
|
if #util.table_keys(itte.contexts) == 0 then
|
||||||
|
util.debug("conn", "Exiting ...", itte.config.debug)
|
||||||
|
itte.state.connected = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
itte.docs.negotiate_cap = [[ (context_table, data_str)
|
itte.docs.negotiate_cap = [[ (context_table, data_str)
|
||||||
Negotiate client capabilities and authenticate with SASL.
|
Negotiate client capabilities and authenticate with SASL.
|
||||||
]]
|
]]
|
||||||
|
@ -291,7 +337,7 @@ function itte.negotiate_cap(cxt, str)
|
||||||
cxt.state.authed = true
|
cxt.state.authed = true
|
||||||
cxt.state.cap_checked = true
|
cxt.state.cap_checked = true
|
||||||
if (cxt.state.cap_checked) and (not cxt.state.authed) and
|
if (cxt.state.cap_checked) and (not cxt.state.authed) and
|
||||||
(itte.config.notify_errors) then
|
(itte.config.notify_errors) and (cxt.admins ~= nil) then
|
||||||
itte.send_command(cxt.con, cxt.cmds.cap_end.resp)
|
itte.send_command(cxt.con, cxt.cmds.cap_end.resp)
|
||||||
itte.message(cxt, util.table_keys(cxt.admins),
|
itte.message(cxt, util.table_keys(cxt.admins),
|
||||||
itte.config.errors.sasl_auth_failed)
|
itte.config.errors.sasl_auth_failed)
|
||||||
|
@ -315,7 +361,7 @@ function itte.auth_nickserv(cxt, str)
|
||||||
elseif util.is_substr(str, cxt.cmds.ns_identify_pass.check) then
|
elseif util.is_substr(str, cxt.cmds.ns_identify_pass.check) then
|
||||||
cxt.state.authed = true
|
cxt.state.authed = true
|
||||||
if (cxt.state.ns_checked) and (not cxt.state.authed) and
|
if (cxt.state.ns_checked) and (not cxt.state.authed) and
|
||||||
(itte.config.notify_errors) then
|
(itte.config.notify_errors) and (cxt.admins ~= nil) then
|
||||||
itte.message(cxt, util.table_keys(cxt.admins).
|
itte.message(cxt, util.table_keys(cxt.admins).
|
||||||
itte.config.errors.ns_auth_failed)
|
itte.config.errors.ns_auth_failed)
|
||||||
end
|
end
|
||||||
|
@ -324,18 +370,29 @@ function itte.auth_nickserv(cxt, str)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
itte.docs.is_admin = [[ (context_table, message_table)
|
itte.docs.is_admin = [[ (admins_table, message_table, mode_str)
|
||||||
Check whether a user is an admin. Return true if the user and password are
|
Check whether a user is an admin. Modes: global, instance. If `mode` is
|
||||||
in the admin table, or false otherwise.
|
unspecified, check for the user in the instance's admins table. Return true
|
||||||
|
if the user and password are in the given admin table, or false otherwise.
|
||||||
]]
|
]]
|
||||||
function itte.is_admin(cxt, msg)
|
function itte.is_admin(admins, msg, mode)
|
||||||
-- No password provided
|
local in_admins = false
|
||||||
if table.concat(msg.code_params) == "" then
|
-- If no admin users set or no password provided
|
||||||
|
if (admins == nil) or (table.concat(msg.code_params) == "") then
|
||||||
do return false end
|
do return false end
|
||||||
-- Incorrect password provided
|
-- Incorrect password provided
|
||||||
elseif msg.code_params ~= nil then
|
elseif msg.code_params ~= nil then
|
||||||
local in_admins = util.is_entry(cxt.admins, msg.sender,
|
if mode == "global" then
|
||||||
msg.code_params[#msg.code_params])
|
-- For global admins, both user and password are supplied in the message
|
||||||
|
-- to keep the auth network-independent
|
||||||
|
in_admins = util.is_entry(admins, msg.code_params[1],
|
||||||
|
msg.code_params[#msg.code_params])
|
||||||
|
else
|
||||||
|
-- User is the IRC user, password is suppled in the message
|
||||||
|
in_admins = util.is_entry(admins, msg.sender,
|
||||||
|
msg.code_params[#msg.code_params])
|
||||||
|
end
|
||||||
|
|
||||||
if not in_admins then
|
if not in_admins then
|
||||||
do return false end
|
do return false end
|
||||||
else
|
else
|
||||||
|
@ -352,7 +409,7 @@ itte.docs.notify_no_perms = [[ (context_table, message_table)
|
||||||
function itte.notify_no_perms(cxt, msg)
|
function itte.notify_no_perms(cxt, msg)
|
||||||
itte.message(cxt, { msg.reply_to }, string.gsub(itte.config.errors.no_perm,
|
itte.message(cxt, { msg.reply_to }, string.gsub(itte.config.errors.no_perm,
|
||||||
"{{user}}", msg.sender))
|
"{{user}}", msg.sender))
|
||||||
if itte.config.notify_errors then
|
if (itte.config.notify_errors) and (cxt.admins ~= nil) then
|
||||||
local notify_msg = string.gsub(itte.config.errors.notify_no_perm,
|
local notify_msg = string.gsub(itte.config.errors.notify_no_perm,
|
||||||
"{{user}}", msg.sender)
|
"{{user}}", msg.sender)
|
||||||
notify_msg = string.gsub(notify_msg, "{{code}}", msg.code)
|
notify_msg = string.gsub(notify_msg, "{{code}}", msg.code)
|
||||||
|
@ -386,15 +443,22 @@ itte.docs.parse_privmsg = [[ (context_table, data_str)
|
||||||
return an associative table of values.
|
return an associative table of values.
|
||||||
]]
|
]]
|
||||||
function itte.parse_privmsg(cxt, str)
|
function itte.parse_privmsg(cxt, str)
|
||||||
local code_full = string.sub(str, string.find(str, ":" .. cxt.code_prefix) +
|
local code_full = ""
|
||||||
1 + string.len(cxt.code_prefix))
|
-- Separator marks the start of the message body
|
||||||
|
body_sep, _ = string.find(str, ":", 2)
|
||||||
|
-- Service code found with specified prefix
|
||||||
|
if util.is_substr(str, ":" .. cxt.code_prefix) then
|
||||||
|
code_full = string.sub(str, string.find(str, ":" ..
|
||||||
|
cxt.code_prefix) + 1 + string.len(cxt.code_prefix))
|
||||||
|
end
|
||||||
local msg = {
|
local msg = {
|
||||||
sender = string.sub(str, string.find(str, "!") + 2,
|
sender = string.sub(str, string.find(str, "!") + 2,
|
||||||
string.find(str, "@") - 1),
|
string.find(str, "@") - 1),
|
||||||
recipient = string.sub(str, string.find(str, "PRIVMSG") + 8,
|
recipient = string.sub(str, string.find(str, "PRIVMSG") + 8,
|
||||||
string.find(str, ":!") - 2),
|
string.find(str, ":" .. cxt.code_prefix) - 2),
|
||||||
reply_to = string.sub(str, string.find(str, "!") + 2,
|
reply_to = string.sub(str, string.find(str, "!") + 2,
|
||||||
string.find(str, "@") - 1),
|
string.find(str, "@") - 1),
|
||||||
|
body = string.sub(str, body_sep + 1),
|
||||||
}
|
}
|
||||||
if util.is_substr(code_full, " ") then
|
if util.is_substr(code_full, " ") then
|
||||||
msg.code = string.sub(code_full, 0, string.find(code_full, " ") - 1)
|
msg.code = string.sub(code_full, 0, string.find(code_full, " ") - 1)
|
||||||
|
@ -416,7 +480,8 @@ function itte.parse_privmsg(cxt, str)
|
||||||
", recipient: " .. msg.recipient ..
|
", recipient: " .. msg.recipient ..
|
||||||
", reply_to: " .. msg.reply_to ..
|
", reply_to: " .. msg.reply_to ..
|
||||||
", code: " .. msg.code ..
|
", code: " .. msg.code ..
|
||||||
", code_params: " .. table.concat(msg.code_params) ..
|
", code_params: " .. table.concat(msg.code_params, " ") ..
|
||||||
|
", body: " .. msg.body ..
|
||||||
" }", itte.config.debug)
|
" }", itte.config.debug)
|
||||||
return msg
|
return msg
|
||||||
end
|
end
|
||||||
|
@ -435,7 +500,7 @@ function itte._h.help(cxt, msg)
|
||||||
local codes = cxt.code_prefix .. table.concat(custom_h, ", " ..
|
local codes = cxt.code_prefix .. table.concat(custom_h, ", " ..
|
||||||
cxt.code_prefix)
|
cxt.code_prefix)
|
||||||
-- Core service codes are shown only to admins
|
-- Core service codes are shown only to admins
|
||||||
if itte.is_admin(cxt, msg) then
|
if itte.is_admin(cxt.admins, msg) then
|
||||||
local core_h = util.table_keys(itte._h)
|
local core_h = util.table_keys(itte._h)
|
||||||
codes = cxt.code_prefix .. table.concat(core_h, ", " .. cxt.code_prefix) ..
|
codes = cxt.code_prefix .. table.concat(core_h, ", " .. cxt.code_prefix) ..
|
||||||
", " .. cxt.code_prefix .. table.concat(custom_h, ", " ..
|
", " .. cxt.code_prefix .. table.concat(custom_h, ", " ..
|
||||||
|
@ -450,7 +515,7 @@ itte.docs._h.join = [[ (context_table, message_table)
|
||||||
Join specified channels.
|
Join specified channels.
|
||||||
]]
|
]]
|
||||||
function itte._h.join(cxt, msg)
|
function itte._h.join(cxt, msg)
|
||||||
if not itte.is_admin(cxt, msg) then
|
if not itte.is_admin(cxt.admins, msg) then
|
||||||
itte.notify_no_perms(cxt, msg)
|
itte.notify_no_perms(cxt, msg)
|
||||||
do return end
|
do return end
|
||||||
end
|
end
|
||||||
|
@ -465,7 +530,7 @@ itte.docs._h.part = [[ (context_table, message_table)
|
||||||
Leave specified channels.
|
Leave specified channels.
|
||||||
]]
|
]]
|
||||||
function itte._h.part(cxt, msg)
|
function itte._h.part(cxt, msg)
|
||||||
if not itte.is_admin(cxt, msg) then
|
if not itte.is_admin(cxt.admins, msg) then
|
||||||
itte.notify_no_perms(cxt, msg)
|
itte.notify_no_perms(cxt, msg)
|
||||||
do return end
|
do return end
|
||||||
end
|
end
|
||||||
|
@ -488,7 +553,7 @@ itte.docs._h.quit = [[ (context_table, message_table)
|
||||||
Disconnect from the server.
|
Disconnect from the server.
|
||||||
]]
|
]]
|
||||||
function itte._h.quit(cxt, msg)
|
function itte._h.quit(cxt, msg)
|
||||||
if not itte.is_admin(cxt, msg) then
|
if not itte.is_admin(itte.admins, msg, "global") then
|
||||||
itte.notify_no_perms(cxt, msg)
|
itte.notify_no_perms(cxt, msg)
|
||||||
do return end
|
do return end
|
||||||
end
|
end
|
||||||
|
@ -500,11 +565,11 @@ itte.docs._h.reload = [[ (context_table, message_table)
|
||||||
Reload the server config.
|
Reload the server config.
|
||||||
]]
|
]]
|
||||||
function itte._h.reload(cxt, msg)
|
function itte._h.reload(cxt, msg)
|
||||||
if not itte.is_admin(cxt, msg) then
|
if not itte.is_admin(itte.admins, msg, "global") then
|
||||||
itte.notify_no_perms(cxt, msg)
|
itte.notify_no_perms(cxt, msg)
|
||||||
do return end
|
do return end
|
||||||
end
|
end
|
||||||
itte.get_config()
|
itte.get_config(true)
|
||||||
itte.message(cxt, { msg.reply_to }, itte.config.messages.reload)
|
itte.message(cxt, { msg.reply_to }, itte.config.messages.reload)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -513,13 +578,15 @@ end
|
||||||
-- Service code mapping and runtime
|
-- Service code mapping and runtime
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
itte.docs.listen = [[ (context_table, data_str)
|
itte.docs.listen = [[ (name_str, data_str)
|
||||||
Parse the socket data string and trigger a response to the server if the
|
Parse the socket data string and trigger a response to the server if the
|
||||||
string matches preset patterns.
|
string matches preset patterns.
|
||||||
]]
|
]]
|
||||||
function itte.listen(cxt, str)
|
function itte.listen(name, str)
|
||||||
util.debug("listen", str, itte.config.debug)
|
util.debug("listen", str, itte.config.debug)
|
||||||
|
|
||||||
|
local cxt = itte.contexts[name]
|
||||||
|
|
||||||
-- Respond to server ping
|
-- Respond to server ping
|
||||||
if util.is_substr(str, cxt.cmds.ping.check) then
|
if util.is_substr(str, cxt.cmds.ping.check) then
|
||||||
itte.send_command(cxt.con, string.gsub(str, cxt.cmds.ping.check,
|
itte.send_command(cxt.con, string.gsub(str, cxt.cmds.ping.check,
|
||||||
|
@ -536,7 +603,11 @@ function itte.listen(cxt, str)
|
||||||
elseif util.has_key(itte.handlers, msg.code) then
|
elseif util.has_key(itte.handlers, msg.code) then
|
||||||
itte.handlers[msg.code](cxt, msg)
|
itte.handlers[msg.code](cxt, msg)
|
||||||
else
|
else
|
||||||
itte.message(cxt, { msg.reply_to }, itte.config.errors.unknown_code)
|
-- Only hint with unknown code error in private messages
|
||||||
|
-- as there may be prefix collision in channels.
|
||||||
|
if not util.is_substr(msg.reply_to, "#") then
|
||||||
|
itte.message(cxt, { msg.reply_to }, itte.config.errors.unknown_code)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -548,22 +619,12 @@ itte.docs.add_listener = [[ (context_table)
|
||||||
set `state.connected` to false to activate a client exit.
|
set `state.connected` to false to activate a client exit.
|
||||||
]]
|
]]
|
||||||
function itte.add_listener(cxt)
|
function itte.add_listener(cxt)
|
||||||
-- Set a short timeout to be non-blocking
|
|
||||||
cxt.con:settimeout(0.5)
|
|
||||||
local data, status = cxt.con:receive()
|
local data, status = cxt.con:receive()
|
||||||
if data ~= nil then
|
if data ~= nil then
|
||||||
itte.listen(cxt, data)
|
itte.listen(cxt.name, data)
|
||||||
|
|
||||||
elseif status == "closed" then
|
elseif status == "closed" then
|
||||||
util.debug("conn", "Connection " .. status, itte.config.debug)
|
itte.disconnect_server(cxt.name)
|
||||||
cxt.con:close()
|
|
||||||
itte.state.connections[cxt.name] = nil
|
|
||||||
-- Check if it is the last connection and trigger client exit
|
|
||||||
-- if no connections remain.
|
|
||||||
if #itte.state.connections == 0 then
|
|
||||||
util.debug("conn", "Exiting ...", itte.config.debug)
|
|
||||||
itte.state.connected = false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -575,50 +636,47 @@ function itte.run()
|
||||||
itte.get_config()
|
itte.get_config()
|
||||||
|
|
||||||
-- Connect to servers and get context with socket ref for each server
|
-- Connect to servers and get context with socket ref for each server
|
||||||
local contexts = {}
|
itte.contexts = {}
|
||||||
for instance, prop in pairs(itte.servers) do
|
for instance, prop in pairs(itte.servers) do
|
||||||
contexts[instance] = itte.connect_server(prop)
|
itte.contexts[instance] = itte.connect_server(instance, prop)
|
||||||
contexts[instance].name = instance
|
|
||||||
itte.state.connected = true
|
|
||||||
itte.state.connections[instance] = true
|
|
||||||
contexts[instance].con:settimeout(1)
|
|
||||||
|
|
||||||
-- For PASS-based authentication, send PASS before greeting the server
|
-- For PASS-based authentication, send PASS before greeting the server
|
||||||
if contexts[instance].auth_type == "pass" then
|
if itte.contexts[instance].auth_type == "pass" then
|
||||||
itte.send_command(contexts[instance].con,
|
itte.send_command(itte.contexts[instance].con,
|
||||||
contexts[instance].cmds.pass.resp)
|
itte.contexts[instance].cmds.pass.resp)
|
||||||
contexts[instance].state.authed = true
|
itte.contexts[instance].state.authed = true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Greet the server in all auth scenarios except SASL, which greets the
|
-- Greet the server in all auth scenarios except SASL, which greets the
|
||||||
-- server during CAP negotiation.
|
-- server during CAP negotiation.
|
||||||
if (contexts[instance].auth_type ~= "sasl") then
|
if (itte.contexts[instance].auth_type ~= "sasl") then
|
||||||
itte.send_command(contexts[instance].con,
|
itte.send_command(itte.contexts[instance].con,
|
||||||
contexts[instance].cmds.user.resp)
|
itte.contexts[instance].cmds.user.resp)
|
||||||
itte.send_command(contexts[instance].con,
|
itte.send_command(itte.contexts[instance].con,
|
||||||
contexts[instance].cmds.nick.resp)
|
itte.contexts[instance].cmds.nick.resp)
|
||||||
end
|
end
|
||||||
|
|
||||||
local joined_chans = false
|
local joined_chans = false
|
||||||
while (itte.state.connections[instance]) and (not joined_chans) do
|
while (itte.contexts[instance].state.connected) and (not joined_chans) do
|
||||||
local data, status = contexts[instance].con:receive()
|
local data, status = itte.contexts[instance].con:receive()
|
||||||
|
|
||||||
if contexts[instance].auth_type == "sasl" then
|
if itte.contexts[instance].auth_type == "sasl" then
|
||||||
itte.negotiate_cap(contexts[instance], data)
|
itte.negotiate_cap(itte.contexts[instance], data)
|
||||||
|
|
||||||
elseif contexts[instance].auth_type == "nickserv" then
|
elseif itte.contexts[instance].auth_type == "nickserv" then
|
||||||
itte.auth_nickserv(contexts[instance], data)
|
itte.auth_nickserv(itte.contexts[instance], data)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Minimum requirements for joining channels: client has authenticated if
|
-- Minimum requirements for joining channels: client has authenticated if
|
||||||
-- an auth type is set, or has received a NOTICE [nick] message during an
|
-- an auth type is set, or has received a NOTICE [nick] message during an
|
||||||
-- ident lookup.
|
-- ident lookup.
|
||||||
if contexts[instance].state.authed then
|
if itte.contexts[instance].state.authed then
|
||||||
itte.traverse_channels(contexts[instance], "join")
|
itte.traverse_channels(itte.contexts[instance], "join")
|
||||||
joined_chans = true
|
joined_chans = true
|
||||||
elseif (data ~= nil) then
|
elseif (data ~= nil) then
|
||||||
if util.is_substr(data, contexts[instance].cmds.join.check) then
|
if util.is_substr(data, itte.contexts[instance].cmds.join.check)
|
||||||
itte.traverse_channels(contexts[instance], "join")
|
then
|
||||||
|
itte.traverse_channels(itte.contexts[instance], "join")
|
||||||
joined_chans = true
|
joined_chans = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -627,7 +685,7 @@ function itte.run()
|
||||||
|
|
||||||
-- Add listeners
|
-- Add listeners
|
||||||
while itte.state.connected do
|
while itte.state.connected do
|
||||||
for instance, cxt in pairs(contexts) do
|
for instance, cxt in pairs(itte.contexts) do
|
||||||
itte.add_listener(cxt)
|
itte.add_listener(cxt)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue