1
0
mirror of https://github.com/minetest-mods/irc.git synced 2025-06-29 22:50:32 +02:00

20 Commits

Author SHA1 Message Date
5d53641a09 Split messages going out to avoid cutouts. 2015-05-03 20:23:22 -03:00
38832b3c55 Improve README 2015-04-03 13:18:38 -04:00
fd1a570794 Remove undefined global warning without LuaJIT 2015-04-03 12:42:57 -04:00
18b80bd127 Remove default values for some settings 2015-03-10 18:43:56 -04:00
43cb77fab8 Send CAP END for SASL 2015-03-10 13:33:41 -04:00
df229cabe6 Update LuaIRC 2015-02-07 13:21:22 -05:00
30fa81a3ab Don't allow a user with the nick "IRC" to impersonate other users 2015-01-27 11:36:29 -05:00
32294995be Fix /irc_names crashing if not connected. 2015-01-17 22:41:24 -03:00
d0ebde3884 Add Minetest version to CTCP VERSION reply 2014-10-01 16:19:10 -04:00
9e15a886b4 Work around missing package search paths of Minetest's built-in Lua 2014-09-10 14:00:49 -04:00
12b1b07afe Remove newlines from replies 2014-07-07 23:22:52 -04:00
e92eec3987 Change load order so that LuaIRC loads first 2014-06-06 11:06:18 -04:00
8aa442e87f Update LuaIRC 2014-06-03 15:00:55 -04:00
5655f75946 Add success and message return values to bot commands 2014-05-28 20:05:26 -04:00
8e6a9a287f Use LuaSocket's base 64 encoding function 2014-05-28 19:38:24 -04:00
26ca287b09 Check connectivity before sending messages 2014-05-28 19:38:23 -04:00
3b35bb1871 Fix leaked globals. 2014-05-28 12:05:08 -03:00
56a5de4a91 Fix typo in connect.
This caused bot to fail to connect to servers protected with passwords.

Reported by reactor.
2014-05-28 11:59:10 -03:00
706a6fbe27 Rename "mt_irc" namespace to "irc"
The underlying IRC library is now available as irc.lib.
2014-05-25 22:52:24 -04:00
e87d2e5bf2 Rename SASLPass and SASLUser settings to sasl.pass and sasl.user 2014-05-15 20:51:29 -04:00
12 changed files with 313 additions and 278 deletions

View File

@ -1,24 +1,26 @@
IRC Mod API
-----------
===========
This file documents the Minetest IRC mod API.
BASICS
Basics
------
In order to allow your mod to interface with this mod, you must add 'irc'
(without the quotes) to your mod's 'depends.txt' file.
In order to allow your mod to interface with this mod, you must add `irc`
to your mod's `depends.txt` file.
REFERENCE
Reference
---------
mt_irc:say([name, ]message)
irc:say([name,] message)
Sends <message> to either the channel (if <name> is nil or not specified),
or to the given user (if <name> is specified).
Example:
mt_irc:say("Hello, Channel!")
mt_irc:say("john1234", "How are you?")
irc:say("Hello, Channel!")
irc:say("john1234", "How are you?")
mt_irc:register_bot_command(name, cmdDef)
irc:register_bot_command(name, cmdDef)
Registers a new bot command named <name>.
When an user sends a private message to the bot with the command name, the
command's function is called.
@ -26,38 +28,39 @@ mt_irc:register_bot_command(name, cmdDef)
cmdDef = {
params = "<param1> ...", -- A description of the command's parameters
description = "My command", -- A description of what the command does. (one-liner)
func = function(user, param)
func = function(user, args)
-- This function gets called when the command is invoked.
-- <user> is a user table for the user that ran the command.
-- (See the LuaIRC documentation for details.)
-- It contains fields such as 'nick' and 'ident'
-- <param> is a string of parameters to the command (may be "")
-- <args> is a string of arguments to the command (may be "")
-- This function should return boolean success and a message.
end,
};
Example:
mt_irc:register_bot_command("hello", {
irc:register_bot_command("hello", {
params = "",
description = "Greet user",
func = function(user, param)
mt_irc:say(user.nick, "Hello!")
return true, "Hello!"
end,
});
mt_irc.joined_players[name]
irc.joined_players[name]
This table holds the players who are currently on the channel (may be less
than the players in the game). It is modified by the /part and /join chat
commands.
Example:
if mt_irc.joined_players["joe"] then
if irc.joined_players["joe"] then
-- Joe is talking on IRC
end
mt_irc:register_hook(name, func)
irc:register_hook(name, func)
Registers a function to be called when an event happens. <name> is the name
of the event, and <func> is the function to be called. See HOOKS below
for more information
Example:
mt_irc:register_hook("OnSend", function(line)
irc:register_hook("OnSend", function(line)
print("SEND: "..line)
end)
@ -69,18 +72,18 @@ string.expandvars(string, vars)
are left verbatim in the string.
Example:
local tpl = "$(foo) $(bar) $(baz)"
local s = tpl:expandvars({ foo=1, bar="Hello" })
local s = tpl:expandvars({foo=1, bar="Hello"})
assert(s == "1 Hello $(baz)")
In addition, all the configuration options decribed in `README.txt' are
available to other mods, though they should be considered "read only". Do
not modify these settings at runtime or you will most likely crash the
server!
In addition, all the configuration options decribed in `README.txt` are
available to other mods, though they should be considered read-only. Do
not modify these settings at runtime or you might crash the server!
HOOKS
---------
The 'mt_irc:register_hook' function can register functions to be called
Hooks
-----
The `irc:register_hook` function can register functions to be called
when some events happen. The events supported are the same as the LuaIRC
ones with a few added (mostly for internal use).
See src/LuaIRC/doc/irc.luadoc for more information.

View File

@ -6,28 +6,31 @@ Introduction
This mod is just a glue between IRC and Minetest. It provides two-way
communication between the in-game chat, and an arbitrary IRC channel.
The forum topic is at http://minetest.net/forum/viewtopic.php?id=3905
The forum topic is at https://forum.minetest.net/viewtopic.php?f=11&t=3905
Installing
----------
Quick one line install for linux:
Quick one line install for Linux:
cd <Mod directory> && git clone https://github.com/kaeza/minetest-irc.git irc && cd irc && git submodule update --init
cd <Mods directory> && git clone --recursive https://github.com/kaeza/minetest-irc.git irc
Please change `<Mod directory>` to fit your installation of minetest.
Please change `<Mods directory>` to fit your installation of Minetest.
For more information, see [the wiki](http://wiki.minetest.net/Installing_mods).
The Minetest IRC mod uses submodules, therefore you will have to run
`git submodule init` when first installing the mod, and `git submodule update`
every time that a submodule is updated. These steps can be combined as
`git submodule update --init`.
The IRC mod's git repository uses submodules, therefore you will have to run
`git submodule init` when first installing the mod (unless you used
`--recursive` as above), and `git submodule update` every time that a submodule
is updated. These steps can be combined into `git submodule update --init`.
The Minetest IRC mod also requires LuaSocket. This can be installed using your
package manager on many distributions, for example on Arch Linux:
You'll need to install LuaSocket. You can do so with your package manager on
many distributions, for example:
# # On Arch Linux:
# pacman -S lua51-socket
# # On Debian/Ubuntu:
# apt-get install lua-socket
Settings
@ -35,10 +38,10 @@ Settings
All settings are changed in `minetest.conf`. If any of these settings
are not set, the default value is used.
* `irc.server` (string, default "irc.freenode.net")
This is the IRC server the mod connects to.
* `irc.server` (string)
The address of the IRC server to connect to.
* `irc.channel` (string, default "##mt-irc-mod")
* `irc.channel` (string)
The IRC channel to join.
* `irc.interval` (number, default 2.0)
@ -46,23 +49,22 @@ are not set, the default value is used.
least 2.0 but can be higher. After four messages this much
time must pass between folowing messages.
* `irc.nick` (string, default "MT-FFFFFF")
Nickname used as "proxy" for the in-game chat.
'F' stands for a random base-16 number.
* `irc.nick` (string)
Nickname the server uses when it connects to IRC.
* `irc.password` (string, default "")
* `irc.password` (string, default nil)
Password to use when connecting to the server.
* `irc.NSPass` (string, default nil)
NickServ password. Don't use this if you use SASL authentication.
NickServ password. Don't set this if you use SASL authentication.
* `irc.SASLPass` (string, default nil)
* `irc.sasl.pass` (string, default nil)
SASL password, same as nickserv password.
You should use this instead of NickServ authentication
if the server supports it.
* `irc.SASLUser` (string, default irc.nick)
The SASL username. This should normaly be set to your main NickServ account name.
* `irc.sasl.user` (string, default `irc.nick`)
The SASL username. This should normaly be set to your NickServ account name.
* `irc.debug` (boolean, default false)
Whether to output debug information.
@ -84,13 +86,11 @@ are not set, the default value is used.
Usage
-----
Once the game is connected to the IRC channel, chatting using the 'T' or
F10 hotkeys will send the messages to the channel, and will be visible
by anyone. Also, when someone sends a message to the channel, that text
will be visible in-game.
Once the game is connected to the IRC channel, chatting in-game will send
messages to the channel, and will be visible by anyone. Also, messages sent
to the channel will be visible in-game.
Messages that begin with `[off]` from in-game or IRC are not sent to the
other side.
Messages that begin with `[off]` from in-game or IRC are not sent to the other side.
This mod also adds a few chat commands:
@ -115,7 +115,7 @@ This mod also adds a few chat commands:
You can also send private messages from IRC to in-game players.
To do it, you must send a private message to the bot (set with
To do so, you must send a private message to the bot (set with
the `irc.nick` option above), in the following format:
@playername message
@ -151,7 +151,7 @@ forum topic. Thanks to you all!
License
-------
(C) 2012-2013 Diego Martínez <kaeza@users.sf.net>
Copyright © 2012-2013 Diego Martínez <kaeza@users.sf.net>
See LICENSE.txt for licensing information.

View File

@ -1,9 +1,9 @@
mt_irc.bot_commands = {}
irc.bot_commands = {}
function mt_irc:check_botcmd(msg)
local prefix = mt_irc.config.command_prefix
local nick = mt_irc.conn.nick:lower()
function irc:check_botcmd(msg)
local prefix = irc.config.command_prefix
local nick = irc.conn.nick:lower()
local text = msg.args[2]
local nickpart = text:sub(1, #nick + 2):lower()
@ -21,19 +21,19 @@ function mt_irc:check_botcmd(msg)
end
function mt_irc:bot_command(msg, text)
function irc:bot_command(msg, text)
if text:sub(1, 1) == "@" then
local found, _, player_to, message = text:find("^.([^%s]+)%s(.+)$")
if not minetest.get_player_by_name(player_to) then
mt_irc:reply("User '"..player_to.."' is not in the game.")
irc:reply("User '"..player_to.."' is not in the game.")
return
elseif not mt_irc.joined_players[player_to] then
mt_irc:reply("User '"..player_to.."' is not using IRC.")
elseif not irc.joined_players[player_to] then
irc:reply("User '"..player_to.."' is not using IRC.")
return
end
minetest.chat_send_player(player_to,
"PM from "..msg.user.nick.."@IRC: "..message, false)
mt_irc:reply("Message sent!")
irc:reply("Message sent!")
return
end
local pos = text:find(" ", 1, true)
@ -52,11 +52,14 @@ function mt_irc:bot_command(msg, text)
return
end
self.bot_commands[cmd].func(msg.user, args)
local success, message = self.bot_commands[cmd].func(msg.user, args)
if message then
self:reply(message)
end
end
function mt_irc:register_bot_command(name, def)
function irc:register_bot_command(name, def)
if (not def.func) or (type(def.func) ~= "function") then
error("Erroneous bot command definition. def.func missing.", 2)
elseif name:sub(1, 1) == "@" then
@ -66,81 +69,77 @@ function mt_irc:register_bot_command(name, def)
end
mt_irc:register_bot_command("help", {
irc:register_bot_command("help", {
params = "<command>",
description = "Get help about a command",
func = function(user, args)
if args == "" then
mt_irc:reply("No command name specified. Use 'list' for a list of commands")
return
return false, "No command name specified. Use 'list' for a list of commands."
end
local cmd = mt_irc.bot_commands[args]
local cmd = irc.bot_commands[args]
if not cmd then
mt_irc:reply("Unknown command '"..cmdname.."'.")
return
return false, "Unknown command '"..cmdname.."'."
end
mt_irc:reply(("Usage: %c%s %s -- %s"):format(
mt_irc.config.command_prefix,
return true, ("Usage: %c%s %s -- %s"):format(
irc.config.command_prefix,
args,
cmd.params or "<no parameters>",
cmd.description or "<no description>"))
cmd.description or "<no description>")
end
})
mt_irc:register_bot_command("list", {
irc:register_bot_command("list", {
params = "",
description = "List available commands.",
func = function(user, args)
local cmdlist = "Available commands: "
for name, cmd in pairs(mt_irc.bot_commands) do
for name, cmd in pairs(irc.bot_commands) do
cmdlist = cmdlist..name..", "
end
mt_irc:reply(cmdlist.." -- Use 'help <command name>' to get"
.." help about a specific command.")
return true, cmdlist.." -- Use 'help <command name>' to get"
.." help about a specific command."
end
})
mt_irc:register_bot_command("whereis", {
irc:register_bot_command("whereis", {
params = "<player>",
description = "Tell the location of <player>",
func = function(user, args)
if args == "" then
mt_irc:bot_help(user, "whereis")
return
return false, "Player name required."
end
local player = minetest.get_player_by_name(args)
if not player then
return false, "There is no player named '"..args.."'"
end
local player = minetest.env:get_player_by_name(args)
if player then
local fmt = "Player %s is at (%.2f,%.2f,%.2f)"
local pos = player:getpos()
mt_irc:reply(fmt:format(args, pos.x, pos.y, pos.z))
return
end
mt_irc:reply("There is no player named '"..args.."'")
return true, fmt:format(args, pos.x, pos.y, pos.z)
end
})
local starttime = os.time()
mt_irc:register_bot_command("uptime", {
irc:register_bot_command("uptime", {
description = "Tell how much time the server has been up",
func = function(user, args)
local cur_time = os.time()
local diff = os.difftime(cur_time, starttime)
local fmt = "Server has been running for %d:%02d:%02d"
mt_irc:reply(fmt:format(
return true, fmt:format(
math.floor(diff / 60 / 60),
math.mod(math.floor(diff / 60), 60),
math.mod(math.floor(diff), 60)
))
math.floor(diff / 60) % 60,
math.floor(diff) % 60
)
end
})
mt_irc:register_bot_command("players", {
irc:register_bot_command("players", {
description = "List the players on the server",
func = function(user, args)
local players = minetest.get_connected_players()
@ -148,8 +147,8 @@ mt_irc:register_bot_command("players", {
for _, player in pairs(players) do
table.insert(names, player:get_player_name())
end
mt_irc:reply("Connected players: "
..table.concat(names, ", "))
return true, "Connected players: "
..table.concat(names, ", ")
end
})

View File

@ -4,25 +4,25 @@
minetest.register_on_joinplayer(function(player)
local name = player:get_player_name()
if mt_irc.connected and mt_irc.config.send_join_part then
mt_irc:say("*** "..name.." joined the game")
if irc.connected and irc.config.send_join_part then
irc:say("*** "..name.." joined the game")
end
end)
minetest.register_on_leaveplayer(function(player)
local name = player:get_player_name()
if mt_irc.connected and mt_irc.config.send_join_part then
mt_irc:say("*** "..name.." left the game")
if irc.connected and irc.config.send_join_part then
irc:say("*** "..name.." left the game")
end
end)
minetest.register_on_chat_message(function(name, message)
if not mt_irc.connected
if not irc.connected
or message:sub(1, 1) == "/"
or message:sub(1, 5) == "[off]"
or not mt_irc.joined_players[name]
or not irc.joined_players[name]
or (not minetest.check_player_privs(name, {shout=true})) then
return
end
@ -30,11 +30,11 @@ minetest.register_on_chat_message(function(name, message)
if nl then
message = message:sub(1, nl - 1)
end
mt_irc:say(mt_irc:playerMessage(name, message))
irc:say(irc:playerMessage(name, message))
end)
minetest.register_on_shutdown(function()
mt_irc:disconnect("Game shutting down.")
irc:disconnect("Game shutting down.")
end)

View File

@ -10,7 +10,7 @@ minetest.register_chatcommand("irc_msg", {
description = "Send a private message to an IRC user",
privs = {shout=true},
func = function(name, param)
if not mt_irc.connected then
if not irc.connected then
minetest.chat_send_player(name, "Not connected to IRC. Use /irc_connect to connect.")
return
end
@ -21,7 +21,7 @@ minetest.register_chatcommand("irc_msg", {
end
local toname_l = toname:lower()
local validNick = false
for nick, user in pairs(mt_irc.conn.channels[mt_irc.config.channel].users) do
for nick, user in pairs(irc.conn.channels[irc.config.channel].users) do
if nick:lower() == toname_l then
validNick = true
break
@ -35,7 +35,7 @@ minetest.register_chatcommand("irc_msg", {
"You can not message that user. (Hint: They have to be in the channel)")
return
end
mt_irc:say(toname, mt_irc:playerMessage(name, message))
irc:say(toname, irc:playerMessage(name, message))
minetest.chat_send_player(name, "Message sent!")
end
})
@ -45,8 +45,12 @@ minetest.register_chatcommand("irc_names", {
params = "",
description = "List the users in IRC.",
func = function(name, params)
if not irc.connected then
minetest.chat_send_player(name, "Not connected to IRC. Use /irc_connect to connect.")
return
end
local users = { }
for k, v in pairs(mt_irc.conn.channels[mt_irc.config.channel].users) do
for k, v in pairs(irc.conn.channels[irc.config.channel].users) do
table.insert(users, k)
end
minetest.chat_send_player(name, "Users in IRC: "..table.concat(users, ", "))
@ -58,12 +62,12 @@ minetest.register_chatcommand("irc_connect", {
description = "Connect to the IRC server.",
privs = {irc_admin=true},
func = function(name, param)
if mt_irc.connected then
if irc.connected then
minetest.chat_send_player(name, "You are already connected to IRC.")
return
end
minetest.chat_send_player(name, "IRC: Connecting...")
mt_irc:connect()
irc:connect()
end
})
@ -73,14 +77,14 @@ minetest.register_chatcommand("irc_disconnect", {
description = "Disconnect from the IRC server.",
privs = {irc_admin=true},
func = function(name, param)
if not mt_irc.connected then
if not irc.connected then
minetest.chat_send_player(name, "You are not connected to IRC.")
return
end
if params == "" then
params = "Manual disconnect by "..name
end
mt_irc:disconnect(param)
irc:disconnect(param)
end
})
@ -89,12 +93,12 @@ minetest.register_chatcommand("irc_reconnect", {
description = "Reconnect to the IRC server.",
privs = {irc_admin=true},
func = function(name, param)
if not mt_irc.connected then
if not irc.connected then
minetest.chat_send_player(name, "You are not connected to IRC.")
return
end
mt_irc:disconnect("Reconnecting...")
mt_irc:connect()
irc:disconnect("Reconnecting...")
irc:connect()
end
})
@ -104,11 +108,11 @@ minetest.register_chatcommand("irc_quote", {
description = "Send a raw command to the IRC server.",
privs = {irc_admin=true},
func = function(name, param)
if not mt_irc.connected then
if not irc.connected then
minetest.chat_send_player(name, "You are not connected to IRC.")
return
end
mt_irc:queue(param)
irc:queue(param)
minetest.chat_send_player(name, "Command sent!")
end
})
@ -117,6 +121,6 @@ minetest.register_chatcommand("irc_quote", {
local oldme = minetest.chatcommands["me"].func
minetest.chatcommands["me"].func = function(name, param, ...)
oldme(name, param, ...)
mt_irc:say(("* %s %s"):format(name, param))
irc:say(("* %s %s"):format(name, param))
end

View File

@ -2,9 +2,9 @@
-- See LICENSE.txt for details.
mt_irc.config = {}
irc.config = {}
local function setting(stype, name, default)
local function setting(stype, name, default, required)
local value
if stype == "bool" then
value = minetest.setting_getbool("irc."..name)
@ -14,22 +14,26 @@ local function setting(stype, name, default)
value = tonumber(minetest.setting_get("irc."..name))
end
if value == nil then
if required then
error("Required configuration option irc."..
name.." missing.")
end
value = default
end
mt_irc.config[name] = value
irc.config[name] = value
end
-------------------------
-- BASIC USER SETTINGS --
-------------------------
setting("string", "nick") -- Nickname (default "MT-<hash>", <hash> 6 random hexidecimal characters)
setting("string", "server", "irc.freenode.net") -- Server to connect on joinplayer
setting("number", "port", 6667) -- Port to connect on joinplayer
setting("string", "nick", nil, true) -- Nickname
setting("string", "server", nil, true) -- Server address to connect to
setting("number", "port", 6667) -- Server port to connect to
setting("string", "NSPass") -- NickServ password
setting("string", "SASLUser", mt_irc.config.nick) -- SASL username
setting("string", "SASLPass") -- SASL password
setting("string", "channel", "##mt-irc-mod") -- Channel to join
setting("string", "sasl.user", irc.config.nick) -- SASL username
setting("string", "sasl.pass") -- SASL password
setting("string", "channel", nil, true) -- Channel to join
setting("string", "key") -- Key for the channel
setting("bool", "send_join_part", true) -- Whether to send player join and part messages to the channel
@ -46,14 +50,3 @@ setting("bool", "enable_player_part", true) -- Whether to enable players joini
setting("bool", "auto_join", true) -- Whether to automatically show players in the channel when they join
setting("bool", "auto_connect", true) -- Whether to automatically connect to the server on mod load
-- Generate a random nickname if one isn't specified.
if not mt_irc.config.nick then
local pr = PseudoRandom(os.time())
-- Workaround for bad distribution in minetest PRNG implementation.
mt_irc.config.nick = ("MT-%02X%02X%02X"):format(
pr:next(0, 255),
pr:next(0, 255),
pr:next(0, 255)
)
end

162
hooks.lua
View File

@ -1,9 +1,11 @@
-- This file is licensed under the terms of the BSD 2-clause license.
-- See LICENSE.txt for details.
-- MIME is part of LuaSocket
local b64e = require("mime").b64
mt_irc.hooks = {}
mt_irc.registered_hooks = {}
irc.hooks = {}
irc.registered_hooks = {}
-- TODO: Add proper conversion from CP1252 to UTF-8.
@ -21,7 +23,7 @@ local function normalize(text)
end
function mt_irc:doHook(conn)
function irc:doHook(conn)
for name, hook in pairs(self.registered_hooks) do
for _, func in pairs(hook) do
conn:hook(name, func)
@ -30,59 +32,67 @@ function mt_irc:doHook(conn)
end
function mt_irc:register_hook(name, func)
function irc:register_hook(name, func)
self.registered_hooks[name] = self.registered_hooks[name] or {}
table.insert(self.registered_hooks[name], func)
end
function mt_irc.hooks.raw(line)
if mt_irc.config.debug then
function irc.hooks.raw(line)
if irc.config.debug then
print("RECV: "..line)
end
end
function mt_irc.hooks.send(line)
if mt_irc.config.debug then
function irc.hooks.send(line)
if irc.config.debug then
print("SEND: "..line)
end
end
function mt_irc.hooks.chat(msg)
function irc.hooks.chat(msg)
local channel, text = msg.args[1], msg.args[2]
if text:sub(1, 1) == string.char(1) then
mt_irc.conn:invoke("OnCTCP", msg)
irc.conn:invoke("OnCTCP", msg)
return
end
if channel == mt_irc.conn.nick then
mt_irc.last_from = msg.user.nick
mt_irc.conn:invoke("PrivateMessage", msg)
if channel == irc.conn.nick then
irc.last_from = msg.user.nick
irc.conn:invoke("PrivateMessage", msg)
else
mt_irc.last_from = channel
mt_irc.conn:invoke("OnChannelChat", msg)
irc.last_from = channel
irc.conn:invoke("OnChannelChat", msg)
end
end
function mt_irc.hooks.ctcp(msg)
local function get_core_version()
local status = minetest.get_server_status()
local start_pos = select(2, status:find("version=", 1, true))
local end_pos = status:find(",", start_pos, true)
return status:sub(start_pos + 1, end_pos - 1)
end
function irc.hooks.ctcp(msg)
local text = msg.args[2]:sub(2, -2) -- Remove ^C
local args = text:split(' ')
local command = args[1]:upper()
local function reply(s)
mt_irc:queue(irc.msgs.notice(msg.user.nick,
irc:queue(irc.msgs.notice(msg.user.nick,
("\1%s %s\1"):format(command, s)))
end
if command == "ACTION" and msg.args[1] == mt_irc.config.channel then
if command == "ACTION" and msg.args[1] == irc.config.channel then
local action = text:sub(8, -1)
mt_irc:sendLocal(("* %s@IRC %s"):format(msg.user.nick, action))
irc:sendLocal(("* %s@IRC %s"):format(msg.user.nick, action))
elseif command == "VERSION" then
reply(("Minetest IRC mod version %s.")
:format(mt_irc.version))
reply(("Minetest version %s, IRC mod version %s.")
:format(get_core_version(), irc.version))
elseif command == "PING" then
reply(args[2])
elseif command == "TIME" then
@ -91,9 +101,17 @@ function mt_irc.hooks.ctcp(msg)
end
function mt_irc.hooks.channelChat(msg)
function irc.hooks.channelChat(msg)
local text = normalize(msg.args[2])
irc:check_botcmd(msg)
-- Don't let a user impersonate someone else by using the nick "IRC"
if msg.user.nick == "IRC" then
irc:sendLocal("<IRC@IRC> "..text)
return
end
-- Support multiple servers in a channel better by converting:
-- "<server@IRC> <player> message" into "<player@server> message"
-- "<server@IRC> *** player joined/left the game" into "*** player joined/left server"
@ -107,58 +125,56 @@ function mt_irc.hooks.channelChat(msg)
local foundaction, _, actionnick, actionmessage =
text:find("^%* ([^%s]+) (.*)$")
mt_irc:check_botcmd(msg)
if text:sub(1, 5) == "[off]" then
return
elseif foundchat then
mt_irc:sendLocal(("<%s@%s> %s")
irc:sendLocal(("<%s@%s> %s")
:format(chatnick, msg.user.nick, chatmessage))
elseif foundjoin then
mt_irc:sendLocal(("*** %s joined %s")
irc:sendLocal(("*** %s joined %s")
:format(joinnick, msg.user.nick))
elseif foundleave then
mt_irc:sendLocal(("*** %s left %s")
irc:sendLocal(("*** %s left %s")
:format(leavenick, msg.user.nick))
elseif foundaction then
mt_irc:sendLocal(("* %s@%s %s")
irc:sendLocal(("* %s@%s %s")
:format(actionnick, msg.user.nick, actionmessage))
else
mt_irc:sendLocal(("<%s@IRC> %s"):format(msg.user.nick, text))
irc:sendLocal(("<%s@IRC> %s"):format(msg.user.nick, text))
end
end
function mt_irc.hooks.pm(msg)
function irc.hooks.pm(msg)
-- Trim prefix if it is found
local text = msg.args[2]
local prefix = mt_irc.config.command_prefix
local prefix = irc.config.command_prefix
if prefix and text:sub(1, #prefix) == prefix then
text = text:sub(#prefix + 1)
end
mt_irc:bot_command(msg, text)
irc:bot_command(msg, text)
end
function mt_irc.hooks.kick(channel, target, prefix, reason)
if target == mt_irc.conn.nick then
function irc.hooks.kick(channel, target, prefix, reason)
if target == irc.conn.nick then
minetest.chat_send_all("IRC: kicked from "..channel.." by "..prefix.nick..".")
mt_irc:disconnect("Kicked")
irc:disconnect("Kicked")
else
mt_irc:sendLocal(("-!- %s was kicked from %s by %s [%s]")
irc:sendLocal(("-!- %s was kicked from %s by %s [%s]")
:format(target, channel, prefix.nick, reason))
end
end
function mt_irc.hooks.notice(user, target, message)
if user.nick and target == mt_irc.config.channel then
mt_irc:sendLocal("-"..user.nick.."@IRC- "..message)
function irc.hooks.notice(user, target, message)
if user.nick and target == irc.config.channel then
irc:sendLocal("-"..user.nick.."@IRC- "..message)
end
end
function mt_irc.hooks.mode(user, target, modes, ...)
function irc.hooks.mode(user, target, modes, ...)
local by = ""
if user.nick then
by = " by "..user.nick
@ -173,37 +189,37 @@ function mt_irc.hooks.mode(user, target, modes, ...)
end
function mt_irc.hooks.nick(user, newNick)
mt_irc:sendLocal(("-!- %s is now known as %s")
function irc.hooks.nick(user, newNick)
irc:sendLocal(("-!- %s is now known as %s")
:format(user.nick, newNick))
end
function mt_irc.hooks.join(user, channel)
mt_irc:sendLocal(("-!- %s joined %s")
function irc.hooks.join(user, channel)
irc:sendLocal(("-!- %s joined %s")
:format(user.nick, channel))
end
function mt_irc.hooks.part(user, channel, reason)
function irc.hooks.part(user, channel, reason)
reason = reason or ""
mt_irc:sendLocal(("-!- %s has left %s [%s]")
irc:sendLocal(("-!- %s has left %s [%s]")
:format(user.nick, channel, reason))
end
function mt_irc.hooks.quit(user, reason)
mt_irc:sendLocal(("-!- %s has quit [%s]")
function irc.hooks.quit(user, reason)
irc:sendLocal(("-!- %s has quit [%s]")
:format(user.nick, reason))
end
function mt_irc.hooks.disconnect(message, isError)
mt_irc.connected = false
function irc.hooks.disconnect(message, isError)
irc.connected = false
if isError then
minetest.log("error", "IRC: Error: Disconnected, reconnecting in one minute.")
minetest.chat_send_all("IRC: Error: Disconnected, reconnecting in one minute.")
minetest.after(60, mt_irc.connect, mt_irc)
minetest.after(60, irc.connect, irc)
else
minetest.log("action", "IRC: Disconnected.")
minetest.chat_send_all("IRC: Disconnected.")
@ -211,34 +227,34 @@ function mt_irc.hooks.disconnect(message, isError)
end
function mt_irc.hooks.preregister(conn)
if not (mt_irc.config.SASLUser and mt_irc.config.SASLPass) then return end
local authString = mt_irc.b64e(
function irc.hooks.preregister(conn)
if not (irc.config["sasl.user"] and irc.config["sasl.pass"]) then return end
local authString = b64e(
("%s\x00%s\x00%s"):format(
mt_irc.config.SASLUser,
mt_irc.config.SASLUser,
mt_irc.config.SASLPass)
irc.config["sasl.user"],
irc.config["sasl.user"],
irc.config["sasl.pass"])
)
conn:send("CAP REQ sasl")
conn:send("AUTHENTICATE PLAIN")
conn:send("AUTHENTICATE "..authString)
--LuaIRC will send CAP END
conn:send("CAP END")
end
mt_irc:register_hook("PreRegister", mt_irc.hooks.preregister)
mt_irc:register_hook("OnRaw", mt_irc.hooks.raw)
mt_irc:register_hook("OnSend", mt_irc.hooks.send)
mt_irc:register_hook("DoPrivmsg", mt_irc.hooks.chat)
mt_irc:register_hook("OnPart", mt_irc.hooks.part)
mt_irc:register_hook("OnKick", mt_irc.hooks.kick)
mt_irc:register_hook("OnJoin", mt_irc.hooks.join)
mt_irc:register_hook("OnQuit", mt_irc.hooks.quit)
mt_irc:register_hook("NickChange", mt_irc.hooks.nick)
mt_irc:register_hook("OnCTCP", mt_irc.hooks.ctcp)
mt_irc:register_hook("PrivateMessage", mt_irc.hooks.pm)
mt_irc:register_hook("OnNotice", mt_irc.hooks.notice)
mt_irc:register_hook("OnChannelChat", mt_irc.hooks.channelChat)
mt_irc:register_hook("OnModeChange", mt_irc.hooks.mode)
mt_irc:register_hook("OnDisconnect", mt_irc.hooks.disconnect)
irc:register_hook("PreRegister", irc.hooks.preregister)
irc:register_hook("OnRaw", irc.hooks.raw)
irc:register_hook("OnSend", irc.hooks.send)
irc:register_hook("DoPrivmsg", irc.hooks.chat)
irc:register_hook("OnPart", irc.hooks.part)
irc:register_hook("OnKick", irc.hooks.kick)
irc:register_hook("OnJoin", irc.hooks.join)
irc:register_hook("OnQuit", irc.hooks.quit)
irc:register_hook("NickChange", irc.hooks.nick)
irc:register_hook("OnCTCP", irc.hooks.ctcp)
irc:register_hook("PrivateMessage", irc.hooks.pm)
irc:register_hook("OnNotice", irc.hooks.notice)
irc:register_hook("OnChannelChat", irc.hooks.channelChat)
irc:register_hook("OnModeChange", irc.hooks.mode)
irc:register_hook("OnDisconnect", irc.hooks.disconnect)

View File

@ -4,13 +4,24 @@
local modpath = minetest.get_modpath(minetest.get_current_modname())
package.path =
package.path..";"
-- To find LuaIRC's init.lua
..modpath.."/?/init.lua;"
modpath.."/?/init.lua;"
-- For LuaIRC to find its files
..modpath.."/?.lua"
..modpath.."/?.lua;"
..package.path
mt_irc = {
-- The build of Lua that Minetest comes with only looks for libraries under
-- /usr/local/share and /usr/local/lib but LuaSocket is often installed under
-- /usr/share and /usr/lib.
if not rawget(_G, "jit") and package.config:sub(1, 1) == "/" then
package.path = package.path..
";/usr/share/lua/5.1/?.lua"..
";/usr/share/lua/5.1/?/init.lua"
package.cpath = package.cpath..
";/usr/lib/lua/5.1/?.so"
end
irc = {
version = "0.2.0",
connected = false,
cur_time = 0,
@ -20,7 +31,9 @@ mt_irc = {
modpath = modpath,
lib = require("irc"),
}
local irc = mt_irc.lib
-- Compatibility
mt_irc = irc
dofile(modpath.."/config.lua")
dofile(modpath.."/messages.lua")
@ -28,11 +41,10 @@ dofile(modpath.."/hooks.lua")
dofile(modpath.."/callback.lua")
dofile(modpath.."/chatcmds.lua")
dofile(modpath.."/botcmds.lua")
dofile(modpath.."/util.lua")
if mt_irc.config.enable_player_part then
if irc.config.enable_player_part then
dofile(modpath.."/player_part.lua")
else
setmetatable(mt_irc.joined_players, {__index = function(index) return true end})
setmetatable(irc.joined_players, {__index = function(index) return true end})
end
minetest.register_privilege("irc_admin", {
@ -42,9 +54,9 @@ minetest.register_privilege("irc_admin", {
local stepnum = 0
minetest.register_globalstep(function(dtime) return mt_irc:step(dtime) end)
minetest.register_globalstep(function(dtime) return irc:step(dtime) end)
function mt_irc:step(dtime)
function irc:step(dtime)
if stepnum == 3 then
if self.config.auto_connect then
self:connect()
@ -63,22 +75,22 @@ function mt_irc:step(dtime)
end
function mt_irc:connect()
function irc:connect()
if self.connected then
minetest.log("error", "IRC: Ignoring attempt to connect when already connected.")
return
end
self.conn = irc.new({
self.conn = irc.lib.new({
nick = self.config.nick,
username = "Minetest",
realname = "Minetest",
})
self:doHook(self.conn)
good, message = pcall(function()
local good, message = pcall(function()
self.conn:connect({
host = self.config.server,
port = self.config.port,
pass = self.config.password,
password = self.config.password,
timeout = self.config.timeout,
secure = self.config.secure
})
@ -102,7 +114,7 @@ function mt_irc:connect()
end
function mt_irc:disconnect(message)
function irc:disconnect(message)
if self.connected then
--The OnDisconnect hook will clear self.connected and print a disconnect message
self.conn:disconnect(message)
@ -110,29 +122,57 @@ function mt_irc:disconnect(message)
end
function mt_irc:say(to, message)
-- Split messages into smaller messages of this size to avoid cutting
-- off large messages at the end.
-- Note: RFC 2812 specifies a maximum of 512 characters per "line"
-- (that includes the command, parameter(s), and the "\r\n" at the
-- end). We just use a smaller number to avoid having to compute the
-- actual max length ourselves, and because it makes it a nice round
-- number :)
local MESSAGE_CHUNK_SIZE = 400
-- Maximum message size processed.
local MESSAGE_MAX_SIZE = MESSAGE_CHUNK_SIZE * 4
function irc:say(to, message)
if not message then
message = to
to = self.config.channel
end
to = to or self.config.channel
self:queue(irc.msgs.privmsg(to, message))
message = message:sub(1, MESSAGE_MAX_SIZE)
-- Split the message into MESSAGE_CHUNK_SIZE chunks and queue each
-- chunk as a separate message. The message is split into at most
-- MAX_CHUNKS chunks. The rest of the message is dropped to prevent
-- flooding and/or locking up the server.
local msglen = #message
for pos = 1, msglen, MESSAGE_CHUNK_SIZE do
-- If we have more text to show, indicate so by appending an
-- ellipsis to this line.
local endl = (pos <= (msglen - MESSAGE_CHUNK_SIZE)) and "\2[…more…]\2" or ""
self:queue(irc.msgs.privmsg(to,
message:sub(pos, pos + MESSAGE_CHUNK_SIZE - 1)..endl))
end
end
function mt_irc:reply(message)
function irc:reply(message)
if not self.last_from then
return
end
message = message:gsub("[\r\n%z]", " \\n ")
self:say(self.last_from, message)
end
function mt_irc:send(msg)
function irc:send(msg)
if not self.connected then return end
self.conn:send(msg)
end
function mt_irc:queue(msg)
function irc:queue(msg)
if not self.connected then return end
self.conn:queue(msg)
end

2
irc

Submodule irc updated: bc9805a33c...e49a52ede1

View File

@ -1,13 +1,13 @@
-- This file is licensed under the terms of the BSD 2-clause license.
-- See LICENSE.txt for details.
mt_irc.msgs = mt_irc.lib.msgs
irc.msgs = irc.lib.msgs
function mt_irc:sendLocal(message)
function irc:sendLocal(message)
minetest.chat_send_all(message)
end
function mt_irc:playerMessage(name, message)
function irc:playerMessage(name, message)
return ("<%s> %s"):format(name, message)
end

View File

@ -2,7 +2,7 @@
-- See LICENSE.txt for details.
function mt_irc:player_part(name)
function irc:player_part(name)
if not self.joined_players[name] then
minetest.chat_send_player(name, "IRC: You are not in the channel.")
return
@ -11,7 +11,7 @@ function mt_irc:player_part(name)
minetest.chat_send_player(name, "IRC: You are now out of the channel.")
end
function mt_irc:player_join(name)
function irc:player_join(name)
if self.joined_players[name] then
minetest.chat_send_player(name, "IRC: You are already in the channel.")
return
@ -25,7 +25,7 @@ minetest.register_chatcommand("join", {
description = "Join the IRC channel",
privs = {shout=true},
func = function(name, param)
mt_irc:player_join(name)
irc:player_join(name)
end
})
@ -33,7 +33,7 @@ minetest.register_chatcommand("part", {
description = "Part the IRC channel",
privs = {shout=true},
func = function(name, param)
mt_irc:player_part(name)
irc:player_part(name)
end
})
@ -42,7 +42,7 @@ minetest.register_chatcommand("who", {
privs = {},
func = function(name, param)
local s = ""
for name, _ in pairs(mt_irc.joined_players) do
for name, _ in pairs(irc.joined_players) do
s = s..", "..name
end
minetest.chat_send_player(name, "Players On Channel:"..s)
@ -52,16 +52,16 @@ minetest.register_chatcommand("who", {
minetest.register_on_joinplayer(function(player)
local name = player:get_player_name()
mt_irc.joined_players[name] = mt_irc.config.auto_join
irc.joined_players[name] = irc.config.auto_join
end)
minetest.register_on_leaveplayer(function(player)
local name = player:get_player_name()
mt_irc.joined_players[name] = nil
irc.joined_players[name] = nil
end)
function mt_irc:sendLocal(message)
function irc:sendLocal(message)
for name, _ in pairs(self.joined_players) do
minetest.chat_send_player(name, message)
end

View File

@ -1,20 +0,0 @@
--Base 64 encode -- for SASL authentication
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
function mt_irc.b64e(data)
return ((data:gsub('.', function(x)
local r,b='',x:byte()
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
return r;
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
if (#x < 6) then return '' end
local c=0
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
return b:sub(c+1,c+1)
end)..({ '', '==', '=' })[#data%3+1])
end
-- Requested by Exio
string.expandvars = function(s, vars)
return s:gsub("%$%(([^)]+)%)", vars)
end