mirror of
				https://github.com/MinetestForFun/irc_modpack.git
				synced 2025-11-04 06:55:31 +01:00 
			
		
		
		
	Update whole modpack to 'master' branch
'master' branch from @minetest-mods.
This commit is contained in:
		
							
								
								
									
										14
									
								
								irc/.luacheckrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								irc/.luacheckrc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					allow_defined_top = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					read_globals = {
 | 
				
			||||||
 | 
						"minetest",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exclude_files = {
 | 
				
			||||||
 | 
						"irc/*",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					globals = {
 | 
				
			||||||
 | 
						"irc",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										16
									
								
								irc/API.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								irc/API.md
									
									
									
									
									
								
							@@ -13,14 +13,14 @@ to your mod's `depends.txt` file.
 | 
				
			|||||||
Reference
 | 
					Reference
 | 
				
			||||||
---------
 | 
					---------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
irc:say([name,] message)
 | 
					irc.say([name,] message)
 | 
				
			||||||
Sends <message> to either the channel (if <name> is nil or not specified),
 | 
					Sends <message> to either the channel (if <name> is nil or not specified),
 | 
				
			||||||
or to the given user (if <name> is specified).
 | 
					or to the given user (if <name> is specified).
 | 
				
			||||||
Example:
 | 
					Example:
 | 
				
			||||||
	irc:say("Hello, Channel!")
 | 
						irc.say("Hello, Channel!")
 | 
				
			||||||
	irc:say("john1234", "How are you?")
 | 
						irc.say("john1234", "How are you?")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
irc:register_bot_command(name, cmdDef)
 | 
					irc.register_bot_command(name, cmdDef)
 | 
				
			||||||
	Registers a new bot command named <name>.
 | 
						Registers a new bot command named <name>.
 | 
				
			||||||
	When an user sends a private message to the bot with the command name, the
 | 
						When an user sends a private message to the bot with the command name, the
 | 
				
			||||||
	command's function is called.
 | 
						command's function is called.
 | 
				
			||||||
@@ -38,7 +38,7 @@ irc:register_bot_command(name, cmdDef)
 | 
				
			|||||||
			end,
 | 
								end,
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
	Example:
 | 
						Example:
 | 
				
			||||||
		irc:register_bot_command("hello", {
 | 
							irc.register_bot_command("hello", {
 | 
				
			||||||
			params = "",
 | 
								params = "",
 | 
				
			||||||
			description = "Greet user",
 | 
								description = "Greet user",
 | 
				
			||||||
			func = function(user, param)
 | 
								func = function(user, param)
 | 
				
			||||||
@@ -55,12 +55,12 @@ irc.joined_players[name]
 | 
				
			|||||||
		-- Joe is talking on IRC
 | 
							-- Joe is talking on IRC
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
irc:register_hook(name, func)
 | 
					irc.register_hook(name, func)
 | 
				
			||||||
	Registers a function to be called when an event happens. <name> is the name
 | 
						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
 | 
						of the event, and <func> is the function to be called. See HOOKS below
 | 
				
			||||||
	for more information
 | 
						for more information
 | 
				
			||||||
	Example:
 | 
						Example:
 | 
				
			||||||
	irc:register_hook("OnSend", function(line)
 | 
						irc.register_hook("OnSend", function(line)
 | 
				
			||||||
		print("SEND: "..line)
 | 
							print("SEND: "..line)
 | 
				
			||||||
	end)
 | 
						end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -83,7 +83,7 @@ not modify these settings at runtime or you might crash the server!
 | 
				
			|||||||
Hooks
 | 
					Hooks
 | 
				
			||||||
-----
 | 
					-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The `irc:register_hook` function can register functions to be called
 | 
					The `irc.register_hook` function can register functions to be called
 | 
				
			||||||
when some events happen. The events supported are the same as the LuaIRC
 | 
					when some events happen. The events supported are the same as the LuaIRC
 | 
				
			||||||
ones with a few added (mostly for internal use).
 | 
					ones with a few added (mostly for internal use).
 | 
				
			||||||
See src/LuaIRC/doc/irc.luadoc for more information.
 | 
					See src/LuaIRC/doc/irc.luadoc for more information.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										143
									
								
								irc/README.md
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								irc/README.md
									
									
									
									
									
								
							@@ -1,122 +1,138 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
IRC Mod for Minetest
 | 
					IRC Mod for Minetest
 | 
				
			||||||
====================
 | 
					====================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Introduction
 | 
					Introduction
 | 
				
			||||||
------------
 | 
					------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This mod is just a glue between IRC and Minetest. It provides two-way
 | 
					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.
 | 
					 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 [here][forum].
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[forum]: https://forum.minetest.net/viewtopic.php?f=11&t=3905
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Installing
 | 
					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/minetest-mods/irc.git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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).
 | 
					For more information, see [the wiki][wiki].
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The Minetest IRC mod uses submodules, therefore you will have to run
 | 
					The IRC mod's git repository uses submodules, therefore you will have to run
 | 
				
			||||||
`git submodule init` when first installing the mod, and `git submodule update`
 | 
					`git submodule init` when first installing the mod (unless you used
 | 
				
			||||||
every time that a submodule is updated.  These steps can be combined as
 | 
					`--recursive` as above), and `git submodule update` every time that a submodule
 | 
				
			||||||
`git submodule update --init`.
 | 
					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
 | 
					You'll need to install LuaSocket. You can do so with your package manager on
 | 
				
			||||||
package manager on many distributions, for example on Arch Linux:
 | 
					many distributions, for example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# # On Arch Linux:
 | 
				
			||||||
	# pacman -S lua51-socket
 | 
						# pacman -S lua51-socket
 | 
				
			||||||
 | 
						# # On Debian/Ubuntu:
 | 
				
			||||||
 | 
						# # Debian/Ubuntu's LuaSocket packages are broken, so use LuaRocks.
 | 
				
			||||||
 | 
						# apt-get install luarocks
 | 
				
			||||||
 | 
						# luarocks install luasocket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You will also need to add IRC to your trusted mods if you haven't disabled mod
 | 
				
			||||||
 | 
					security. Here's an example configuration line:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						secure.trusted_mods = irc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[wiki]: https://wiki.minetest.net/Installing_mods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Settings
 | 
					Settings
 | 
				
			||||||
--------
 | 
					--------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
All settings are changed in `minetest.conf`. If any of these settings
 | 
					All settings are changed in `minetest.conf`. If any of these settings
 | 
				
			||||||
are not set, the default value is used.
 | 
					are not set, the default value is used.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `irc.server` (string, default "irc.freenode.net")
 | 
					* `irc.server` (string):
 | 
				
			||||||
	This is the IRC server the mod connects to.
 | 
					  The address of the IRC server to connect to.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `irc.channel` (string, default "##mt-irc-mod")
 | 
					* `irc.channel` (string):
 | 
				
			||||||
  The IRC channel to join.
 | 
					  The IRC channel to join.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `irc.interval` (number, default 2.0)
 | 
					* `irc.interval` (number, default 2.0):
 | 
				
			||||||
  This prevents the server from flooding. It should be at
 | 
					  This prevents the server from flooding. It should be at
 | 
				
			||||||
  least 2.0 but can be higher. After four messages this much
 | 
					  least 2.0 but can be higher. After four messages this much
 | 
				
			||||||
  time must pass between folowing messages.
 | 
					  time must pass between folowing messages.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `irc.nick` (string, default "MT-FFFFFF")
 | 
					* `irc.nick` (string):
 | 
				
			||||||
	Nickname used as "proxy" for the in-game chat. 
 | 
					  Nickname the server uses when it connects to IRC.
 | 
				
			||||||
	'F' stands for a random base-16 number.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `irc.password` (string, default "")
 | 
					* `irc.password` (string, default nil):
 | 
				
			||||||
  Password to use when connecting to the server.
 | 
					  Password to use when connecting to the server.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `irc.NSPass` (string, default nil)
 | 
					* `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.sasl.pass` (string, default nil)
 | 
					* `irc.sasl.pass` (string, default nil):
 | 
				
			||||||
  SASL password, same as nickserv password.
 | 
					  SASL password, same as nickserv password.
 | 
				
			||||||
  You should use this instead of NickServ authentication
 | 
					  You should use this instead of NickServ authentication
 | 
				
			||||||
  if the server supports it.
 | 
					  if the server supports it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `irc.sasl.user` (string, default `irc.nick`)
 | 
					* `irc.sasl.user` (string, default `irc.nick`):
 | 
				
			||||||
	The SASL username. This should normaly be set to your main NickServ account name.
 | 
					  The SASL username. This should normaly be set to your
 | 
				
			||||||
 | 
					  NickServ account name.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `irc.debug` (boolean, default false)
 | 
					* `irc.debug` (boolean, default false):
 | 
				
			||||||
  Whether to output debug information.
 | 
					  Whether to output debug information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `irc.disable_auto_connect` (boolean, default false)
 | 
					* `irc.disable_auto_connect` (boolean, default false):
 | 
				
			||||||
  If false, the bot is connected by default. If true, a player with
 | 
					  If false, the bot is connected by default. If true, a player with
 | 
				
			||||||
	the 'irc_admin' privilege has to use the /irc_connect command to
 | 
					  the 'irc_admin' privilege has to use the `/irc_connect` command to
 | 
				
			||||||
  connect to the server.
 | 
					  connect to the server.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `irc.disable_auto_join` (boolean, default false)
 | 
					* `irc.disable_auto_join` (boolean, default false):
 | 
				
			||||||
  If false, players join the channel automatically upon entering the
 | 
					  If false, players join the channel automatically upon entering the
 | 
				
			||||||
	game. If true, each user must manually use the /join command to
 | 
					  game. If true, each user must manually use the `/join` command to
 | 
				
			||||||
	join the channel. In any case, the players may use the /part
 | 
					  join the channel. In any case, the players may use the `/part`
 | 
				
			||||||
  command to opt-out of being in the channel.
 | 
					  command to opt-out of being in the channel.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `irc.send_join_part` (boolean, default true)
 | 
					* `irc.send_join_part` (boolean, default true):
 | 
				
			||||||
  Determines whether to send player join and part messages to the channel.
 | 
					  Determines whether to send player join and part messages to the channel.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Usage
 | 
					Usage
 | 
				
			||||||
-----
 | 
					-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Once the game is connected to the IRC channel, chatting using the 'T' or
 | 
					Once the game is connected to the IRC channel, chatting in-game will send
 | 
				
			||||||
F10 hotkeys will send the messages to the channel, and will be visible
 | 
					messages to the channel, and will be visible by anyone. Also, messages sent
 | 
				
			||||||
by anyone. Also, when someone sends a message to the channel, that text
 | 
					to the channel will be visible in-game.
 | 
				
			||||||
will be visible in-game.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Messages that begin with `[off]` from in-game or IRC are not sent to the
 | 
					Messages that begin with `[off]` from in-game or IRC are not sent to the
 | 
				
			||||||
other side.
 | 
					other side.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This mod also adds a few chat commands:
 | 
					This mod also adds a few chat commands:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `/irc_msg <nick> <message>`
 | 
					* `/irc_msg <nick> <message>`:
 | 
				
			||||||
	Sends a private message to a IRC user.
 | 
					  Send a private message to a IRC user.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `/join`
 | 
					* `/join`:
 | 
				
			||||||
  Join the IRC chat.
 | 
					  Join the IRC chat.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `/part`
 | 
					* `/part`:
 | 
				
			||||||
  Part the IRC chat.
 | 
					  Part the IRC chat.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `/irc_connect`
 | 
					* `/irc_connect`:
 | 
				
			||||||
  Connect the bot manually to the IRC network.
 | 
					  Connect the bot manually to the IRC network.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `/irc_disconnect`
 | 
					* `/irc_disconnect`:
 | 
				
			||||||
  Disconnect the bot manually from the IRC network (this does not
 | 
					  Disconnect the bot manually from the IRC network (this does not
 | 
				
			||||||
  shutdown the game).
 | 
					  shutdown the game).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * `/irc_reconnect`
 | 
					* `/irc_reconnect`:
 | 
				
			||||||
	Equivilant to `/irc_disconnect` followed by `/irc_connect`.
 | 
					  Equivalent to `/irc_disconnect` followed by `/irc_connect`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You can also send private messages from IRC to in-game players.
 | 
					You can also send private messages from IRC to in-game players
 | 
				
			||||||
 | 
					by sending a private message to the bot (set with the `irc.nick`
 | 
				
			||||||
To do it, you must send a private message to the bot (set with
 | 
					option above), in the following format:
 | 
				
			||||||
the `irc.nick` option above), in the following format:
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@playername message
 | 
						@playername message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -125,21 +141,29 @@ a private message from IRC with:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/msg server_nick @mtuser Hello!
 | 
						/msg server_nick @mtuser Hello!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To avoid possible misunderstandings (since all in-game players use the
 | 
					The bot also supports some basic commands, which are invoked by saying
 | 
				
			||||||
same IRC user to converse with you), the "proxy" user will reject any
 | 
					the bot name followed by either a colon or a comma and the command, or
 | 
				
			||||||
private messages that are not in that format, and will send back a
 | 
					sending a private message to it. For example: `ServerBot: help whereis`.
 | 
				
			||||||
nice reminder as a private message.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
The bot also supports some basic commands, which are invoked by sending
 | 
					* `help [<command>]`:
 | 
				
			||||||
a private message to it. Use `!list` to get a list of commands, and
 | 
					  Prints help about a command, or a list of supported commands if no
 | 
				
			||||||
`!help <command>` to get help about a specific command.
 | 
					  command is given.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `uptime`:
 | 
				
			||||||
 | 
					  Prints the server's running time.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `whereis <player>`:
 | 
				
			||||||
 | 
					  Prints the coordinates of the given player.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `players`:
 | 
				
			||||||
 | 
					  Lists players currently in the server.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Thanks
 | 
					Thanks
 | 
				
			||||||
------
 | 
					------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
I'd like to thank the users who supported this mod both on the Minetest
 | 
					I'd like to thank the users who supported this mod both on the Minetest
 | 
				
			||||||
Forums and on the #minetest channel. In no particular order:
 | 
					Forums and on the `#minetest` channel. In no particular order:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
0gb.us, ShadowNinja, Shaun/kizeren, RAPHAEL, DARGON, Calinou, Exio,
 | 
					0gb.us, ShadowNinja, Shaun/kizeren, RAPHAEL, DARGON, Calinou, Exio,
 | 
				
			||||||
vortexlabs/mrtux, marveidemanis, marktraceur, jmf/john\_minetest,
 | 
					vortexlabs/mrtux, marveidemanis, marktraceur, jmf/john\_minetest,
 | 
				
			||||||
@@ -151,10 +175,7 @@ forum topic. Thanks to you all!
 | 
				
			|||||||
License
 | 
					License
 | 
				
			||||||
-------
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(C) 2012-2013 Diego Martínez <kaeza@users.sf.net>
 | 
					See `LICENSE.txt` for details.
 | 
				
			||||||
 | 
					 | 
				
			||||||
See LICENSE.txt for licensing information.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The files in the irc directory are part of the LuaIRC project.
 | 
					 | 
				
			||||||
See irc/LICENSE.txt for licensing information.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The files in the `irc` directory are part of the LuaIRC project.
 | 
				
			||||||
 | 
					See `irc/LICENSE.txt` for details.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										113
									
								
								irc/botcmds.lua
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								irc/botcmds.lua
									
									
									
									
									
								
							@@ -1,40 +1,59 @@
 | 
				
			|||||||
irc.whereis_timer = {}
 | 
					
 | 
				
			||||||
irc.whereis_timer_max_limit = 120
 | 
					 | 
				
			||||||
irc.bot_commands = {}
 | 
					irc.bot_commands = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:check_botcmd(msg)
 | 
					-- From RFC1459:
 | 
				
			||||||
 | 
					-- "Because of IRC’s scandanavian origin, the characters {}| are
 | 
				
			||||||
 | 
					--  considered to be the lower case equivalents of the characters
 | 
				
			||||||
 | 
					--  []\, respectively."
 | 
				
			||||||
 | 
					local irctolower = { ["["]="{", ["\\"]="|", ["]"]="}" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function irclower(s)
 | 
				
			||||||
 | 
						return (s:lower():gsub("[%[%]\\]", irctolower))
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function nickequals(nick1, nick2)
 | 
				
			||||||
 | 
						return irclower(nick1) == irclower(nick2)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function irc.check_botcmd(msg)
 | 
				
			||||||
	local prefix = irc.config.command_prefix
 | 
						local prefix = irc.config.command_prefix
 | 
				
			||||||
	local nick = irc.conn.nick:lower()
 | 
						local nick = irc.conn.nick
 | 
				
			||||||
	local text = msg.args[2]
 | 
						local text = msg.args[2]
 | 
				
			||||||
	local nickpart = text:sub(1, #nick + 2):lower()
 | 
						local nickpart = text:sub(1, #nick)
 | 
				
			||||||
 | 
						local suffix = text:sub(#nick+1, #nick+2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	-- First check for a nick prefix
 | 
						-- First check for a nick prefix
 | 
				
			||||||
	if nickpart == nick..": " or
 | 
						if nickequals(nickpart, nick)
 | 
				
			||||||
	   nickpart == nick..", " then
 | 
								and (suffix == ": " or suffix == ", ") then
 | 
				
			||||||
		self:bot_command(msg, text:sub(#nick + 3))
 | 
							irc.bot_command(msg, text:sub(#nick + 3))
 | 
				
			||||||
		return true
 | 
							return true
 | 
				
			||||||
	-- Then check for the configured prefix
 | 
						-- Then check for the configured prefix
 | 
				
			||||||
	elseif prefix and text:sub(1, #prefix):lower() == prefix:lower() then
 | 
						elseif prefix and text:sub(1, #prefix):lower() == prefix:lower() then
 | 
				
			||||||
		self:bot_command(msg, text:sub(#prefix + 1))
 | 
							irc.bot_command(msg, text:sub(#prefix + 1))
 | 
				
			||||||
		return true
 | 
							return true
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	return false
 | 
						return false
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:bot_command(msg, text)
 | 
					function irc.bot_command(msg, text)
 | 
				
			||||||
 | 
						-- Remove leading whitespace
 | 
				
			||||||
 | 
						text = text:match("^%s*(.*)")
 | 
				
			||||||
	if text:sub(1, 1) == "@" then
 | 
						if text:sub(1, 1) == "@" then
 | 
				
			||||||
		local found, _, player_to, message = text:find("^.([^%s]+)%s(.+)$")
 | 
							local _, _, player_to, message = text:find("^.([^%s]+)%s(.+)$")
 | 
				
			||||||
		if not minetest.get_player_by_name(player_to) then
 | 
							if not player_to then
 | 
				
			||||||
			irc:reply("User '"..player_to.."' is not in the game.")
 | 
								return
 | 
				
			||||||
 | 
							elseif not minetest.get_player_by_name(player_to) then
 | 
				
			||||||
 | 
								irc.reply("User '"..player_to.."' is not in the game.")
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		elseif not irc.joined_players[player_to] then
 | 
							elseif not irc.joined_players[player_to] then
 | 
				
			||||||
			irc:reply("User '"..player_to.."' is not using IRC.")
 | 
								irc.reply("User '"..player_to.."' is not using IRC.")
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		minetest.chat_send_player(player_to,
 | 
							minetest.chat_send_player(player_to,
 | 
				
			||||||
				"PM from "..msg.user.nick.."@IRC: "..message, false)
 | 
									minetest.colorize(irc.config.pm_color,
 | 
				
			||||||
		irc:reply("Message sent!")
 | 
									"PM from "..msg.user.nick.."@IRC: "..message, false))
 | 
				
			||||||
 | 
							irc.reply("Message sent!")
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	local pos = text:find(" ", 1, true)
 | 
						local pos = text:find(" ", 1, true)
 | 
				
			||||||
@@ -47,35 +66,41 @@ function irc:bot_command(msg, text)
 | 
				
			|||||||
		args = ""
 | 
							args = ""
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if not self.bot_commands[cmd] then
 | 
						if not irc.bot_commands[cmd] then
 | 
				
			||||||
		self:reply("Unknown command '"..cmd.."'. Try 'list'."
 | 
							irc.reply("Unknown command '"..cmd.."'. Try 'help'."
 | 
				
			||||||
			.." Or use @playername <message> to send a private message")
 | 
								.." Or use @playername <message> to send a private message")
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local success, message = self.bot_commands[cmd].func(msg.user, args)
 | 
						local _, message = irc.bot_commands[cmd].func(msg.user, args)
 | 
				
			||||||
	if message then
 | 
						if message then
 | 
				
			||||||
		self:reply(message)
 | 
							irc.reply(message)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:register_bot_command(name, def)
 | 
					function irc.register_bot_command(name, def)
 | 
				
			||||||
	if (not def.func) or (type(def.func) ~= "function") then
 | 
						if (not def.func) or (type(def.func) ~= "function") then
 | 
				
			||||||
		error("Erroneous bot command definition. def.func missing.", 2)
 | 
							error("Erroneous bot command definition. def.func missing.", 2)
 | 
				
			||||||
	elseif name:sub(1, 1) == "@" then
 | 
						elseif name:sub(1, 1) == "@" then
 | 
				
			||||||
		error("Erroneous bot command name. Command name begins with '@'.", 2)
 | 
							error("Erroneous bot command name. Command name begins with '@'.", 2)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	self.bot_commands[name] = def
 | 
						irc.bot_commands[name] = def
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
irc:register_bot_command("help", {
 | 
					irc.register_bot_command("help", {
 | 
				
			||||||
	params = "<command>",
 | 
						params = "<command>",
 | 
				
			||||||
	description = "Get help about a command",
 | 
						description = "Get help about a command",
 | 
				
			||||||
	func = function(user, args)
 | 
						func = function(_, args)
 | 
				
			||||||
		if args == "" then
 | 
							if args == "" then
 | 
				
			||||||
			return false, "No command name specified. Use 'list' for a list of commands."
 | 
								local cmdlist = { }
 | 
				
			||||||
 | 
								for name in pairs(irc.bot_commands) do
 | 
				
			||||||
 | 
									cmdlist[#cmdlist+1] = name
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
								return true, "Available commands: "..table.concat(cmdlist, ", ")
 | 
				
			||||||
 | 
										.." -- Use 'help <command name>' to get"
 | 
				
			||||||
 | 
										.." help about a specific command."
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		local cmd = irc.bot_commands[args]
 | 
							local cmd = irc.bot_commands[args]
 | 
				
			||||||
@@ -84,7 +109,7 @@ irc:register_bot_command("help", {
 | 
				
			|||||||
		end
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return true, ("Usage: %s%s %s -- %s"):format(
 | 
							return true, ("Usage: %s%s %s -- %s"):format(
 | 
				
			||||||
				irc.config.command_prefix,
 | 
									irc.config.command_prefix or "",
 | 
				
			||||||
				args,
 | 
									args,
 | 
				
			||||||
				cmd.params or "<no parameters>",
 | 
									cmd.params or "<no parameters>",
 | 
				
			||||||
				cmd.description or "<no description>")
 | 
									cmd.description or "<no description>")
 | 
				
			||||||
@@ -92,24 +117,20 @@ irc:register_bot_command("help", {
 | 
				
			|||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
irc:register_bot_command("list", {
 | 
					irc.register_bot_command("list", {
 | 
				
			||||||
	params = "",
 | 
						params = "",
 | 
				
			||||||
	description = "List available commands.",
 | 
						description = "List available commands.",
 | 
				
			||||||
	func = function(user, args)
 | 
						func = function()
 | 
				
			||||||
		local cmdlist = "Available commands: "
 | 
							return false, "The `list` command has been merged into `help`."
 | 
				
			||||||
		for name, cmd in pairs(irc.bot_commands) do
 | 
									.." Use `help` with no arguments to get a list."
 | 
				
			||||||
			cmdlist = cmdlist..name..", "
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
		return true, cmdlist.." -- Use 'help <command name>' to get"
 | 
					 | 
				
			||||||
			.." help about a specific command."
 | 
					 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
irc:register_bot_command("whereis", {
 | 
					irc.register_bot_command("whereis", {
 | 
				
			||||||
	params = "<player>",
 | 
						params = "<player>",
 | 
				
			||||||
	description = "Tell the location of <player>",
 | 
						description = "Tell the location of <player>",
 | 
				
			||||||
	func = function(user, args)
 | 
						func = function(_, args)
 | 
				
			||||||
		if args == "" then
 | 
							if args == "" then
 | 
				
			||||||
			return false, "Player name required."
 | 
								return false, "Player name required."
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
@@ -117,27 +138,17 @@ irc:register_bot_command("whereis", {
 | 
				
			|||||||
		if not player then
 | 
							if not player then
 | 
				
			||||||
			return false, "There is no player named '"..args.."'"
 | 
								return false, "There is no player named '"..args.."'"
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		if irc.whereis_timer[user.nick] ~= nil then
 | 
					 | 
				
			||||||
			local timer_player = os.difftime(os.time(),irc.whereis_timer[user.nick])
 | 
					 | 
				
			||||||
			if timer_player < irc.whereis_timer_max_limit then
 | 
					 | 
				
			||||||
				local answer = "Command used too often, retry in %d seconds."
 | 
					 | 
				
			||||||
				return false,answer:format(irc.whereis_timer_max_limit - timer_player)
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
		local fmt = "Player %s is at (%.2f,%.2f,%.2f)"
 | 
							local fmt = "Player %s is at (%.2f,%.2f,%.2f)"
 | 
				
			||||||
		local pos = player:getpos()
 | 
							local pos = player:get_pos()
 | 
				
			||||||
		irc.whereis_timer[user.nick] = os.time()
 | 
					 | 
				
			||||||
		minetest.log("action","IRC user ".. user.nick.."!"..user.username.."@"..user.host.." asked for position of player "..player:get_player_name())
 | 
					 | 
				
			||||||
		minetest.chat_send_player(player:get_player_name(),"IRC user ".. user.nick.."!"..user.username.."@"..user.host.." asked for your position")
 | 
					 | 
				
			||||||
		return true, fmt:format(args, pos.x, pos.y, pos.z)
 | 
							return true, fmt:format(args, pos.x, pos.y, pos.z)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local starttime = os.time()
 | 
					local starttime = os.time()
 | 
				
			||||||
irc:register_bot_command("uptime", {
 | 
					irc.register_bot_command("uptime", {
 | 
				
			||||||
	description = "Tell how much time the server has been up",
 | 
						description = "Tell how much time the server has been up",
 | 
				
			||||||
	func = function(user, args)
 | 
						func = function()
 | 
				
			||||||
		local cur_time = os.time()
 | 
							local cur_time = os.time()
 | 
				
			||||||
		local diff = os.difftime(cur_time, starttime)
 | 
							local diff = os.difftime(cur_time, starttime)
 | 
				
			||||||
		local fmt = "Server has been running for %d:%02d:%02d"
 | 
							local fmt = "Server has been running for %d:%02d:%02d"
 | 
				
			||||||
@@ -150,9 +161,9 @@ irc:register_bot_command("uptime", {
 | 
				
			|||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
irc:register_bot_command("players", {
 | 
					irc.register_bot_command("players", {
 | 
				
			||||||
	description = "List the players on the server",
 | 
						description = "List the players on the server",
 | 
				
			||||||
	func = function(user, args)
 | 
						func = function()
 | 
				
			||||||
		local players = minetest.get_connected_players()
 | 
							local players = minetest.get_connected_players()
 | 
				
			||||||
		local names = {}
 | 
							local names = {}
 | 
				
			||||||
		for _, player in pairs(players) do
 | 
							for _, player in pairs(players) do
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,15 +5,16 @@
 | 
				
			|||||||
minetest.register_on_joinplayer(function(player)
 | 
					minetest.register_on_joinplayer(function(player)
 | 
				
			||||||
	local name = player:get_player_name()
 | 
						local name = player:get_player_name()
 | 
				
			||||||
	if irc.connected and irc.config.send_join_part then
 | 
						if irc.connected and irc.config.send_join_part then
 | 
				
			||||||
		irc:say("*** "..name.." joined the game")
 | 
							irc.say("*** "..name.." joined the game")
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
end)
 | 
					end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
minetest.register_on_leaveplayer(function(player)
 | 
					minetest.register_on_leaveplayer(function(player, timed_out)
 | 
				
			||||||
	local name = player:get_player_name()
 | 
						local name = player:get_player_name()
 | 
				
			||||||
	if irc.connected and irc.config.send_join_part then
 | 
						if irc.connected and irc.config.send_join_part then
 | 
				
			||||||
		irc:say("*** "..name.." left the game")
 | 
							irc.say("*** "..name.." left the game"..
 | 
				
			||||||
 | 
									(timed_out and " (Timed out)" or ""))
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
end)
 | 
					end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,11 +31,11 @@ minetest.register_on_chat_message(function(name, message)
 | 
				
			|||||||
	if nl then
 | 
						if nl then
 | 
				
			||||||
		message = message:sub(1, nl - 1)
 | 
							message = message:sub(1, nl - 1)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	irc:say(irc:playerMessage(name, message))
 | 
						irc.say(irc.playerMessage(name, core.strip_colors(message)))
 | 
				
			||||||
end)
 | 
					end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
minetest.register_on_shutdown(function()
 | 
					minetest.register_on_shutdown(function()
 | 
				
			||||||
	irc:disconnect("Game shutting down.")
 | 
						irc.disconnect("Game shutting down.")
 | 
				
			||||||
end)
 | 
					end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,32 +11,30 @@ minetest.register_chatcommand("irc_msg", {
 | 
				
			|||||||
	privs = {shout=true},
 | 
						privs = {shout=true},
 | 
				
			||||||
	func = function(name, param)
 | 
						func = function(name, param)
 | 
				
			||||||
		if not irc.connected then
 | 
							if not irc.connected then
 | 
				
			||||||
			minetest.chat_send_player(name, "Not connected to IRC. Use /irc_connect to connect.")
 | 
								return false, "Not connected to IRC. Use /irc_connect to connect."
 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		local found, _, toname, message = param:find("^([^%s]+)%s(.+)")
 | 
							local found, _, toname, message = param:find("^([^%s]+)%s(.+)")
 | 
				
			||||||
		if not found then
 | 
							if not found then
 | 
				
			||||||
			minetest.chat_send_player(name, "Invalid usage, see /help irc_msg.")
 | 
								return false, "Invalid usage, see /help irc_msg."
 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		local toname_l = toname:lower()
 | 
							local toname_l = toname:lower()
 | 
				
			||||||
		local validNick = false
 | 
							local validNick = false
 | 
				
			||||||
		for nick, user in pairs(irc.conn.channels[irc.config.channel].users) do
 | 
							local hint = "They have to be in the channel"
 | 
				
			||||||
 | 
							for nick in pairs(irc.conn.channels[irc.config.channel].users) do
 | 
				
			||||||
			if nick:lower() == toname_l then
 | 
								if nick:lower() == toname_l then
 | 
				
			||||||
				validNick = true
 | 
									validNick = true
 | 
				
			||||||
				break
 | 
									break
 | 
				
			||||||
			end
 | 
								end
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		if toname_l:find("serv$") or toname_l:find("bot$") then
 | 
							if toname_l:find("serv$") or toname_l:find("bot$") then
 | 
				
			||||||
 | 
								hint = "it looks like a bot or service"
 | 
				
			||||||
			validNick = false
 | 
								validNick = false
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		if not validNick then
 | 
							if not validNick then
 | 
				
			||||||
			minetest.chat_send_player(name,
 | 
								return false, "You can not message that user. ("..hint..")"
 | 
				
			||||||
				"You can not message that user. (Hint: They have to be in the channel)")
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		irc:say(toname, irc:playerMessage(name, message))
 | 
							irc.say(toname, irc.playerMessage(name, message))
 | 
				
			||||||
		minetest.chat_send_player(name, "Message sent!")
 | 
							return true, "Message sent!"
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -44,16 +42,15 @@ minetest.register_chatcommand("irc_msg", {
 | 
				
			|||||||
minetest.register_chatcommand("irc_names", {
 | 
					minetest.register_chatcommand("irc_names", {
 | 
				
			||||||
	params = "",
 | 
						params = "",
 | 
				
			||||||
	description = "List the users in IRC.",
 | 
						description = "List the users in IRC.",
 | 
				
			||||||
	func = function(name, param)
 | 
						func = function()
 | 
				
			||||||
		if not irc.connected then
 | 
							if not irc.connected then
 | 
				
			||||||
			minetest.chat_send_player(name, "Not connected to IRC. Use /irc_connect to connect.")
 | 
								return false, "Not connected to IRC. Use /irc_connect to connect."
 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		local users = { }
 | 
							local users = { }
 | 
				
			||||||
		for k, v in pairs(irc.conn.channels[irc.config.channel].users) do
 | 
							for nick in pairs(irc.conn.channels[irc.config.channel].users) do
 | 
				
			||||||
			table.insert(users, k)
 | 
								table.insert(users, nick)
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		minetest.chat_send_player(name, "Users in IRC: "..table.concat(users, ", "))
 | 
							return true, "Users in IRC: "..table.concat(users, ", ")
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -61,13 +58,12 @@ minetest.register_chatcommand("irc_names", {
 | 
				
			|||||||
minetest.register_chatcommand("irc_connect", {
 | 
					minetest.register_chatcommand("irc_connect", {
 | 
				
			||||||
	description = "Connect to the IRC server.",
 | 
						description = "Connect to the IRC server.",
 | 
				
			||||||
	privs = {irc_admin=true},
 | 
						privs = {irc_admin=true},
 | 
				
			||||||
	func = function(name, param)
 | 
						func = function(name)
 | 
				
			||||||
		if irc.connected then
 | 
							if irc.connected then
 | 
				
			||||||
			minetest.chat_send_player(name, "You are already connected to IRC.")
 | 
								return false, "You are already connected to IRC."
 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		minetest.chat_send_player(name, "IRC: Connecting...")
 | 
							minetest.chat_send_player(name, "IRC: Connecting...")
 | 
				
			||||||
		irc:connect()
 | 
							irc.connect()
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -78,13 +74,12 @@ minetest.register_chatcommand("irc_disconnect", {
 | 
				
			|||||||
	privs = {irc_admin=true},
 | 
						privs = {irc_admin=true},
 | 
				
			||||||
	func = function(name, param)
 | 
						func = function(name, param)
 | 
				
			||||||
		if not irc.connected then
 | 
							if not irc.connected then
 | 
				
			||||||
			minetest.chat_send_player(name, "You are not connected to IRC.")
 | 
								return false, "Not connected to IRC. Use /irc_connect to connect."
 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		if param == "" then
 | 
							if param == "" then
 | 
				
			||||||
			param = "Manual disconnect by "..name
 | 
								param = "Manual disconnect by "..name
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		irc:disconnect(param)
 | 
							irc.disconnect(param)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -92,13 +87,13 @@ minetest.register_chatcommand("irc_disconnect", {
 | 
				
			|||||||
minetest.register_chatcommand("irc_reconnect", {
 | 
					minetest.register_chatcommand("irc_reconnect", {
 | 
				
			||||||
	description = "Reconnect to the IRC server.",
 | 
						description = "Reconnect to the IRC server.",
 | 
				
			||||||
	privs = {irc_admin=true},
 | 
						privs = {irc_admin=true},
 | 
				
			||||||
	func = function(name, param)
 | 
						func = function(name)
 | 
				
			||||||
		if not irc.connected then
 | 
							if not irc.connected then
 | 
				
			||||||
			minetest.chat_send_player(name, "You are not connected to IRC.")
 | 
								return false, "Not connected to IRC. Use /irc_connect to connect."
 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		irc:disconnect("Reconnecting...")
 | 
							minetest.chat_send_player(name, "IRC: Reconnecting...")
 | 
				
			||||||
		irc:connect()
 | 
							irc.disconnect("Reconnecting...")
 | 
				
			||||||
 | 
							irc.connect()
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -109,34 +104,31 @@ minetest.register_chatcommand("irc_quote", {
 | 
				
			|||||||
	privs = {irc_admin=true},
 | 
						privs = {irc_admin=true},
 | 
				
			||||||
	func = function(name, param)
 | 
						func = function(name, param)
 | 
				
			||||||
		if not irc.connected then
 | 
							if not irc.connected then
 | 
				
			||||||
			minetest.chat_send_player(name, "You are not connected to IRC.")
 | 
								return false, "Not connected to IRC. Use /irc_connect to connect."
 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		irc:queue(param)
 | 
							irc.queue(param)
 | 
				
			||||||
		minetest.chat_send_player(name, "Command sent!")
 | 
							minetest.chat_send_player(name, "Command sent!")
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local oldme = minetest.chatcommands["me"].func
 | 
					local oldme = minetest.chatcommands["me"].func
 | 
				
			||||||
 | 
					-- luacheck: ignore
 | 
				
			||||||
minetest.chatcommands["me"].func = function(name, param, ...)
 | 
					minetest.chatcommands["me"].func = function(name, param, ...)
 | 
				
			||||||
	oldme(name, param, ...)
 | 
						irc.say(("* %s %s"):format(name, param))
 | 
				
			||||||
	irc:say(("* %s %s"):format(name, param))
 | 
						return oldme(name, param, ...)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
minetest.register_chatcommand("irc_change_server", {
 | 
					if irc.config.send_kicks and minetest.chatcommands["kick"] then
 | 
				
			||||||
	params = "<servername>",
 | 
						local oldkick = minetest.chatcommands["kick"].func
 | 
				
			||||||
	description = "Change the IRC server.",
 | 
						-- luacheck: ignore
 | 
				
			||||||
	privs = {irc_admin=true},
 | 
						minetest.chatcommands["kick"].func = function(name, param, ...)
 | 
				
			||||||
	func = function(name, param)
 | 
							local plname, reason = param:match("^(%S+)%s*(.*)$")
 | 
				
			||||||
		if param == "" then
 | 
							if not plname then
 | 
				
			||||||
			minetest.chat_send_player(name, "Missing argument servername")
 | 
								return false, "Usage: /kick player [reason]"
 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		irc.config.server = param
 | 
							irc.say(("*** Kicked %s.%s"):format(name,
 | 
				
			||||||
		irc.save_config()
 | 
									reason~="" and " Reason: "..reason or ""))
 | 
				
			||||||
		minetest.chat_send_player(name, "New server IRC is \"".. param.."\".")
 | 
							return oldkick(name, param, ...)
 | 
				
			||||||
		minetest.chat_send_player(name, "type \"/irc_reconnect\" to reconnect IRC.")
 | 
					 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
})
 | 
					end
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,16 +4,22 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
irc.config = {}
 | 
					irc.config = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local function setting(stype, name, default)
 | 
					local function setting(stype, name, default, required)
 | 
				
			||||||
	local value
 | 
						local value
 | 
				
			||||||
 | 
						if minetest.settings and minetest.settings.get and minetest.settings.get_bool then
 | 
				
			||||||
		if stype == "bool" then
 | 
							if stype == "bool" then
 | 
				
			||||||
		value = minetest.setting_getbool("irc."..name)
 | 
								value = minetest.settings:get_bool("irc."..name)
 | 
				
			||||||
		elseif stype == "string" then
 | 
							elseif stype == "string" then
 | 
				
			||||||
		value = minetest.setting_get("irc."..name)
 | 
								value = minetest.settings:get("irc."..name)
 | 
				
			||||||
		elseif stype == "number" then
 | 
							elseif stype == "number" then
 | 
				
			||||||
		value = tonumber(minetest.setting_get("irc."..name))
 | 
								value = tonumber(minetest.settings:get("irc."..name))
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	if value == nil then
 | 
						if value == nil then
 | 
				
			||||||
 | 
							if required then
 | 
				
			||||||
 | 
								error("Required configuration option irc."..
 | 
				
			||||||
 | 
									name.." missing.")
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
		value = default
 | 
							value = default
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	irc.config[name] = value
 | 
						irc.config[name] = value
 | 
				
			||||||
@@ -23,15 +29,18 @@ end
 | 
				
			|||||||
-- BASIC USER SETTINGS --
 | 
					-- BASIC USER SETTINGS --
 | 
				
			||||||
-------------------------
 | 
					-------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setting("string", "nick") -- Nickname (default "MT-<hash>", <hash> 6 random hexidecimal characters)
 | 
					setting("string", "nick", nil, true) -- Nickname
 | 
				
			||||||
setting("string", "server", "irc.freenode.net") -- Server to connect on joinplayer
 | 
					setting("string", "server", nil, true) -- Server address to connect to
 | 
				
			||||||
setting("number", "port", 6667) -- Port to connect on joinplayer
 | 
					setting("number", "port", 6667) -- Server port to connect to
 | 
				
			||||||
setting("string", "NSPass") -- NickServ password
 | 
					setting("string", "NSPass") -- NickServ password
 | 
				
			||||||
setting("string", "sasl.user", irc.config.nick) -- SASL username
 | 
					setting("string", "sasl.user", irc.config.nick) -- SASL username
 | 
				
			||||||
 | 
					setting("string", "username", "Minetest") -- Username/ident
 | 
				
			||||||
 | 
					setting("string", "realname", "Minetest") -- Real name/GECOS
 | 
				
			||||||
setting("string", "sasl.pass") -- SASL password
 | 
					setting("string", "sasl.pass") -- SASL password
 | 
				
			||||||
setting("string", "channel", "##mt-irc-mod") -- Channel to join
 | 
					setting("string", "channel", nil, true) -- Channel to join
 | 
				
			||||||
setting("string", "key") -- Key for the channel
 | 
					setting("string", "key") -- Key for the channel
 | 
				
			||||||
setting("bool",   "send_join_part", true) -- Whether to send player join and part messages to the channel
 | 
					setting("bool",   "send_join_part", true) -- Whether to send player join and part messages to the channel
 | 
				
			||||||
 | 
					setting("bool",   "send_kicks", false) -- Whether to send player kicked messages to the channel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-----------------------
 | 
					-----------------------
 | 
				
			||||||
-- ADVANCED SETTINGS --
 | 
					-- ADVANCED SETTINGS --
 | 
				
			||||||
@@ -40,50 +49,11 @@ setting("bool",   "send_join_part", true) -- Whether to send player join and par
 | 
				
			|||||||
setting("string", "password") -- Server password
 | 
					setting("string", "password") -- Server password
 | 
				
			||||||
setting("bool",   "secure", false) -- Enable a TLS connection, requires LuaSEC
 | 
					setting("bool",   "secure", false) -- Enable a TLS connection, requires LuaSEC
 | 
				
			||||||
setting("number", "timeout", 60) -- Underlying socket timeout in seconds.
 | 
					setting("number", "timeout", 60) -- Underlying socket timeout in seconds.
 | 
				
			||||||
setting("string", "command_prefix", "/") -- Prefix to use for bot commands
 | 
					setting("number", "reconnect", 600) -- Time between reconnection attempts, in seconds.
 | 
				
			||||||
 | 
					setting("string", "command_prefix") -- Prefix to use for bot commands
 | 
				
			||||||
setting("bool",   "debug", false) -- Enable debug output
 | 
					setting("bool",   "debug", false) -- Enable debug output
 | 
				
			||||||
setting("bool",   "enable_player_part", true) -- Whether to enable players joining and parting the channel
 | 
					setting("bool",   "enable_player_part", true) -- Whether to enable players joining and parting the channel
 | 
				
			||||||
setting("bool",   "auto_join", true) -- Whether to automatically show players in the channel when they join
 | 
					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
 | 
					setting("bool",   "auto_connect", true) -- Whether to automatically connect to the server on mod load
 | 
				
			||||||
 | 
					setting("string", "chat_color", "#339933") -- Color of IRC chat in-game, green by default
 | 
				
			||||||
-- Generate a random nickname if one isn't specified.
 | 
					setting("string", "pm_color", "#8800AA") -- Color of IRC PMs in-game, purple by default
 | 
				
			||||||
if not irc.config.nick then
 | 
					 | 
				
			||||||
	local pr = PseudoRandom(os.time())
 | 
					 | 
				
			||||||
	-- Workaround for bad distribution in minetest PRNG implementation.
 | 
					 | 
				
			||||||
	irc.config.nick = ("MT-%02X%02X%02X"):format(
 | 
					 | 
				
			||||||
		pr:next(0, 255),
 | 
					 | 
				
			||||||
		pr:next(0, 255),
 | 
					 | 
				
			||||||
		pr:next(0, 255)
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
local config_file = minetest.get_worldpath() .. "/irc.txt"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function irc.save_config()
 | 
					 | 
				
			||||||
	local input, err = io.open(config_file, "w")
 | 
					 | 
				
			||||||
	if input then
 | 
					 | 
				
			||||||
		local conf = {server = irc.config.server}
 | 
					 | 
				
			||||||
		input:write(minetest.serialize(conf))
 | 
					 | 
				
			||||||
		input:close()
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		minetest.log("error", "open(" .. config_file .. ", 'w') failed: " .. err)
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function irc.load_config()
 | 
					 | 
				
			||||||
	local file = io.open(config_file, "r")
 | 
					 | 
				
			||||||
	local settings = {}
 | 
					 | 
				
			||||||
	if file then
 | 
					 | 
				
			||||||
		settings = minetest.deserialize(file:read("*all"))
 | 
					 | 
				
			||||||
		file:close()
 | 
					 | 
				
			||||||
		if settings and type(settings) == "table" then
 | 
					 | 
				
			||||||
			if settings["server"] ~= nil then
 | 
					 | 
				
			||||||
				 irc.config.server = settings["server"]
 | 
					 | 
				
			||||||
			end
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
irc.load_config()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,30 +1,27 @@
 | 
				
			|||||||
-- This file is licensed under the terms of the BSD 2-clause license.
 | 
					-- This file is licensed under the terms of the BSD 2-clause license.
 | 
				
			||||||
-- See LICENSE.txt for details.
 | 
					-- See LICENSE.txt for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local ie = ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- MIME is part of LuaSocket
 | 
					-- MIME is part of LuaSocket
 | 
				
			||||||
local b64e = require("mime").b64
 | 
					local b64e = ie.require("mime").b64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
irc.hooks = {}
 | 
					irc.hooks = {}
 | 
				
			||||||
irc.registered_hooks = {}
 | 
					irc.registered_hooks = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- TODO: Add proper conversion from CP1252 to UTF-8.
 | 
					local stripped_chars = "[\2\31]"
 | 
				
			||||||
local stripped_chars = {"\2", "\31"}
 | 
					 | 
				
			||||||
for c = 127, 255 do
 | 
					 | 
				
			||||||
	table.insert(stripped_chars, string.char(c))
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
stripped_chars = "["..table.concat(stripped_chars, "").."]"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
local function normalize(text)
 | 
					local function normalize(text)
 | 
				
			||||||
	-- Strip colors
 | 
						-- Strip colors
 | 
				
			||||||
	text = text:gsub("\3[0-9][0-9,]*", "")
 | 
						text = text:gsub("\3[0-9][0-9,]*", "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return text --:gsub(stripped_chars, "")
 | 
						return text:gsub(stripped_chars, "")
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:doHook(conn)
 | 
					function irc.doHook(conn)
 | 
				
			||||||
	for name, hook in pairs(self.registered_hooks) do
 | 
						for name, hook in pairs(irc.registered_hooks) do
 | 
				
			||||||
		for _, func in pairs(hook) do
 | 
							for _, func in pairs(hook) do
 | 
				
			||||||
			conn:hook(name, func)
 | 
								conn:hook(name, func)
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
@@ -32,9 +29,9 @@ function irc:doHook(conn)
 | 
				
			|||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:register_hook(name, func)
 | 
					function irc.register_hook(name, func)
 | 
				
			||||||
	self.registered_hooks[name] = self.registered_hooks[name] or {}
 | 
						irc.registered_hooks[name] = irc.registered_hooks[name] or {}
 | 
				
			||||||
	table.insert(self.registered_hooks[name], func)
 | 
						table.insert(irc.registered_hooks[name], func)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -83,13 +80,13 @@ function irc.hooks.ctcp(msg)
 | 
				
			|||||||
	local command = args[1]:upper()
 | 
						local command = args[1]:upper()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local function reply(s)
 | 
						local function reply(s)
 | 
				
			||||||
		irc:queue(irc.msgs.notice(msg.user.nick,
 | 
							irc.queue(irc.msgs.notice(msg.user.nick,
 | 
				
			||||||
				("\1%s %s\1"):format(command, s)))
 | 
									("\1%s %s\1"):format(command, s)))
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if command == "ACTION" and msg.args[1] == irc.config.channel then
 | 
						if command == "ACTION" and msg.args[1] == irc.config.channel then
 | 
				
			||||||
		local action = text:sub(8, -1)
 | 
							local action = text:sub(8, -1)
 | 
				
			||||||
		irc:sendLocal(("* %s@IRC %s"):format(msg.user.nick, action))
 | 
							irc.sendLocal(("* %s@IRC %s"):format(msg.user.nick, action))
 | 
				
			||||||
	elseif command == "VERSION" then
 | 
						elseif command == "VERSION" then
 | 
				
			||||||
		reply(("Minetest version %s, IRC mod version %s.")
 | 
							reply(("Minetest version %s, IRC mod version %s.")
 | 
				
			||||||
			:format(get_core_version(), irc.version))
 | 
								:format(get_core_version(), irc.version))
 | 
				
			||||||
@@ -104,11 +101,12 @@ end
 | 
				
			|||||||
function irc.hooks.channelChat(msg)
 | 
					function irc.hooks.channelChat(msg)
 | 
				
			||||||
	local text = normalize(msg.args[2])
 | 
						local text = normalize(msg.args[2])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	irc:check_botcmd(msg)
 | 
						irc.check_botcmd(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	-- Don't let a user impersonate someone else by using the nick "IRC"
 | 
						-- Don't let a user impersonate someone else by using the nick "IRC"
 | 
				
			||||||
	if msg.user.nick == "IRC" then
 | 
						local fake = msg.user.nick:lower():match("^[il|]rc$")
 | 
				
			||||||
		irc:sendLocal("<IRC@IRC> "..text)
 | 
						if fake then
 | 
				
			||||||
 | 
							irc.sendLocal("<"..msg.user.nick.."@IRC> "..text)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -122,25 +120,30 @@ function irc.hooks.channelChat(msg)
 | 
				
			|||||||
		text:find("^%*%*%* ([^%s]+) joined the game$")
 | 
							text:find("^%*%*%* ([^%s]+) joined the game$")
 | 
				
			||||||
	local foundleave, _, leavenick =
 | 
						local foundleave, _, leavenick =
 | 
				
			||||||
		text:find("^%*%*%* ([^%s]+) left the game$")
 | 
							text:find("^%*%*%* ([^%s]+) left the game$")
 | 
				
			||||||
 | 
						local foundtimedout, _, timedoutnick =
 | 
				
			||||||
 | 
							text:find("^%*%*%* ([^%s]+) left the game %(Timed out%)$")
 | 
				
			||||||
	local foundaction, _, actionnick, actionmessage =
 | 
						local foundaction, _, actionnick, actionmessage =
 | 
				
			||||||
		text:find("^%* ([^%s]+) (.*)$")
 | 
							text:find("^%* ([^%s]+) (.*)$")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if text:sub(1, 5) == "[off]" then
 | 
						if text:sub(1, 5) == "[off]" then
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	elseif foundchat then
 | 
						elseif foundchat then
 | 
				
			||||||
		irc:sendLocal(("<%s@%s> %s")
 | 
							irc.sendLocal(("<%s@%s> %s")
 | 
				
			||||||
				:format(chatnick, msg.user.nick, chatmessage))
 | 
									:format(chatnick, msg.user.nick, chatmessage))
 | 
				
			||||||
	elseif foundjoin then
 | 
						elseif foundjoin then
 | 
				
			||||||
		irc:sendLocal(("*** %s joined %s")
 | 
							irc.sendLocal(("*** %s joined %s")
 | 
				
			||||||
				:format(joinnick, msg.user.nick))
 | 
									:format(joinnick, msg.user.nick))
 | 
				
			||||||
	elseif foundleave then
 | 
						elseif foundleave then
 | 
				
			||||||
		irc:sendLocal(("*** %s left %s")
 | 
							irc.sendLocal(("*** %s left %s")
 | 
				
			||||||
				:format(leavenick, msg.user.nick))
 | 
									:format(leavenick, msg.user.nick))
 | 
				
			||||||
 | 
						elseif foundtimedout then
 | 
				
			||||||
 | 
							irc.sendLocal(("*** %s left %s (Timed out)")
 | 
				
			||||||
 | 
									:format(timedoutnick, msg.user.nick))
 | 
				
			||||||
	elseif foundaction then
 | 
						elseif foundaction then
 | 
				
			||||||
		irc:sendLocal(("* %s@%s %s")
 | 
							irc.sendLocal(("* %s@%s %s")
 | 
				
			||||||
				:format(actionnick, msg.user.nick, actionmessage))
 | 
									:format(actionnick, msg.user.nick, actionmessage))
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		irc:sendLocal(("<%s@IRC> %s"):format(msg.user.nick, text))
 | 
							irc.sendLocal(("<%s@IRC> %s"):format(msg.user.nick, text))
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -152,16 +155,16 @@ function irc.hooks.pm(msg)
 | 
				
			|||||||
	if prefix and text:sub(1, #prefix) == prefix then
 | 
						if prefix and text:sub(1, #prefix) == prefix then
 | 
				
			||||||
		text = text:sub(#prefix + 1)
 | 
							text = text:sub(#prefix + 1)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	irc:bot_command(msg, text)
 | 
						irc.bot_command(msg, text)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc.hooks.kick(channel, target, prefix, reason)
 | 
					function irc.hooks.kick(channel, target, prefix, reason)
 | 
				
			||||||
	if target == irc.conn.nick then
 | 
						if target == irc.conn.nick then
 | 
				
			||||||
		minetest.chat_send_all("IRC: kicked from "..channel.." by "..prefix.nick..".")
 | 
							minetest.chat_send_all("IRC: kicked from "..channel.." by "..prefix.nick..".")
 | 
				
			||||||
		irc:disconnect("Kicked")
 | 
							irc.disconnect("Kicked")
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		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))
 | 
									:format(target, channel, prefix.nick, reason))
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
@@ -169,7 +172,7 @@ end
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
function irc.hooks.notice(user, target, message)
 | 
					function irc.hooks.notice(user, target, message)
 | 
				
			||||||
	if user.nick and target == irc.config.channel then
 | 
						if user.nick and target == irc.config.channel then
 | 
				
			||||||
		irc:sendLocal("-"..user.nick.."@IRC- "..message)
 | 
							irc.sendLocal("-"..user.nick.."@IRC- "..message)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -190,31 +193,31 @@ end
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc.hooks.nick(user, newNick)
 | 
					function irc.hooks.nick(user, newNick)
 | 
				
			||||||
	irc:sendLocal(("-!- %s is now known as %s")
 | 
						irc.sendLocal(("-!- %s is now known as %s")
 | 
				
			||||||
			:format(user.nick, newNick))
 | 
								:format(user.nick, newNick))
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc.hooks.join(user, channel)
 | 
					function irc.hooks.join(user, channel)
 | 
				
			||||||
	irc:sendLocal(("-!- %s joined %s")
 | 
						irc.sendLocal(("-!- %s joined %s")
 | 
				
			||||||
			:format(user.nick, channel))
 | 
								:format(user.nick, channel))
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc.hooks.part(user, channel, reason)
 | 
					function irc.hooks.part(user, channel, reason)
 | 
				
			||||||
	reason = reason or ""
 | 
						reason = reason or ""
 | 
				
			||||||
	irc:sendLocal(("-!- %s has left %s [%s]")
 | 
						irc.sendLocal(("-!- %s has left %s [%s]")
 | 
				
			||||||
			:format(user.nick, channel, reason))
 | 
								:format(user.nick, channel, reason))
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc.hooks.quit(user, reason)
 | 
					function irc.hooks.quit(user, reason)
 | 
				
			||||||
	irc:sendLocal(("-!- %s has quit [%s]")
 | 
						irc.sendLocal(("-!- %s has quit [%s]")
 | 
				
			||||||
			:format(user.nick, reason))
 | 
								:format(user.nick, reason))
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc.hooks.disconnect(message, isError)
 | 
					function irc.hooks.disconnect(_, isError)
 | 
				
			||||||
	irc.connected = false
 | 
						irc.connected = false
 | 
				
			||||||
	if isError then
 | 
						if isError then
 | 
				
			||||||
		minetest.log("error",  "IRC: Error: Disconnected, reconnecting in one minute.")
 | 
							minetest.log("error",  "IRC: Error: Disconnected, reconnecting in one minute.")
 | 
				
			||||||
@@ -238,23 +241,23 @@ function irc.hooks.preregister(conn)
 | 
				
			|||||||
	conn:send("CAP REQ sasl")
 | 
						conn:send("CAP REQ sasl")
 | 
				
			||||||
	conn:send("AUTHENTICATE PLAIN")
 | 
						conn:send("AUTHENTICATE PLAIN")
 | 
				
			||||||
	conn:send("AUTHENTICATE "..authString)
 | 
						conn:send("AUTHENTICATE "..authString)
 | 
				
			||||||
	--LuaIRC will send CAP END
 | 
						conn:send("CAP END")
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
irc:register_hook("PreRegister",     irc.hooks.preregister)
 | 
					irc.register_hook("PreRegister",     irc.hooks.preregister)
 | 
				
			||||||
irc:register_hook("OnRaw",           irc.hooks.raw)
 | 
					irc.register_hook("OnRaw",           irc.hooks.raw)
 | 
				
			||||||
irc:register_hook("OnSend",          irc.hooks.send)
 | 
					irc.register_hook("OnSend",          irc.hooks.send)
 | 
				
			||||||
irc:register_hook("DoPrivmsg",       irc.hooks.chat)
 | 
					irc.register_hook("DoPrivmsg",       irc.hooks.chat)
 | 
				
			||||||
irc:register_hook("OnPart",          irc.hooks.part)
 | 
					irc.register_hook("OnPart",          irc.hooks.part)
 | 
				
			||||||
irc:register_hook("OnKick",          irc.hooks.kick)
 | 
					irc.register_hook("OnKick",          irc.hooks.kick)
 | 
				
			||||||
irc:register_hook("OnJoin",          irc.hooks.join)
 | 
					irc.register_hook("OnJoin",          irc.hooks.join)
 | 
				
			||||||
irc:register_hook("OnQuit",          irc.hooks.quit)
 | 
					irc.register_hook("OnQuit",          irc.hooks.quit)
 | 
				
			||||||
irc:register_hook("NickChange",      irc.hooks.nick)
 | 
					irc.register_hook("NickChange",      irc.hooks.nick)
 | 
				
			||||||
irc:register_hook("OnCTCP",          irc.hooks.ctcp)
 | 
					irc.register_hook("OnCTCP",          irc.hooks.ctcp)
 | 
				
			||||||
irc:register_hook("PrivateMessage",  irc.hooks.pm)
 | 
					irc.register_hook("PrivateMessage",  irc.hooks.pm)
 | 
				
			||||||
irc:register_hook("OnNotice",        irc.hooks.notice)
 | 
					irc.register_hook("OnNotice",        irc.hooks.notice)
 | 
				
			||||||
irc:register_hook("OnChannelChat",   irc.hooks.channelChat)
 | 
					irc.register_hook("OnChannelChat",   irc.hooks.channelChat)
 | 
				
			||||||
irc:register_hook("OnModeChange",    irc.hooks.mode)
 | 
					irc.register_hook("OnModeChange",    irc.hooks.mode)
 | 
				
			||||||
irc:register_hook("OnDisconnect",    irc.hooks.disconnect)
 | 
					irc.register_hook("OnDisconnect",    irc.hooks.disconnect)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										181
									
								
								irc/init.lua
									
									
									
									
									
								
							
							
						
						
									
										181
									
								
								irc/init.lua
									
									
									
									
									
								
							@@ -3,25 +3,49 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
 | 
					local modpath = minetest.get_modpath(minetest.get_current_modname())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package.path =
 | 
					-- Handle mod security if needed
 | 
				
			||||||
 | 
					local ie, req_ie = _G, minetest.request_insecure_environment
 | 
				
			||||||
 | 
					if req_ie then ie = req_ie() end
 | 
				
			||||||
 | 
					if not ie then
 | 
				
			||||||
 | 
						error("The IRC mod requires access to insecure functions in order "..
 | 
				
			||||||
 | 
							"to work.  Please add the irc mod to your secure.trusted_mods "..
 | 
				
			||||||
 | 
							"setting or disable the irc mod.")
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ie.package.path =
 | 
				
			||||||
		-- To find LuaIRC's init.lua
 | 
							-- To find LuaIRC's init.lua
 | 
				
			||||||
		modpath.."/?/init.lua;"
 | 
							modpath.."/?/init.lua;"
 | 
				
			||||||
		-- For LuaIRC to find its files
 | 
							-- For LuaIRC to find its files
 | 
				
			||||||
		..modpath.."/?.lua;"
 | 
							..modpath.."/?.lua;"
 | 
				
			||||||
		..package.path
 | 
							..ie.package.path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- The build of Lua that Minetest comes with only looks for libraries under
 | 
					-- 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/local/share and /usr/local/lib but LuaSocket is often installed under
 | 
				
			||||||
-- /usr/share and /usr/lib.
 | 
					-- /usr/share and /usr/lib.
 | 
				
			||||||
if not rawget(_G,"jit") and package.config:sub(1, 1) == "/" then
 | 
					if not rawget(_G, "jit") and package.config:sub(1, 1) == "/" then
 | 
				
			||||||
	package.path = package.path..
 | 
					
 | 
				
			||||||
 | 
						ie.package.path = ie.package.path..
 | 
				
			||||||
			";/usr/share/lua/5.1/?.lua"..
 | 
								";/usr/share/lua/5.1/?.lua"..
 | 
				
			||||||
			";/usr/share/lua/5.1/?/init.lua"
 | 
								";/usr/share/lua/5.1/?/init.lua"
 | 
				
			||||||
   	package.cpath = package.cpath..
 | 
					
 | 
				
			||||||
 --			";/usr/lib/lua/5.1/?.so"
 | 
						ie.package.cpath = ie.package.cpath..
 | 
				
			||||||
			";/usr/lib/x86_64-linux-gnu/lua/5.1/?.so"
 | 
								";/usr/lib/lua/5.1/?.so"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ie.package.cpath = "/usr/lib/x86_64-linux-gnu/lua/5.1/?.so;"..ie.package.cpath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Temporarily set require so that LuaIRC can access it
 | 
				
			||||||
 | 
					local old_require = require
 | 
				
			||||||
 | 
					require = ie.require
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Silence warnings about `module` in `ltn12`.
 | 
				
			||||||
 | 
					local old_module = rawget(_G, "module")
 | 
				
			||||||
 | 
					rawset(_G, "module", ie.module)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local lib = ie.require("irc")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
irc = {
 | 
					irc = {
 | 
				
			||||||
	version = "0.2.0",
 | 
						version = "0.2.0",
 | 
				
			||||||
	connected = false,
 | 
						connected = false,
 | 
				
			||||||
@@ -30,45 +54,82 @@ irc = {
 | 
				
			|||||||
	recent_message_count = 0,
 | 
						recent_message_count = 0,
 | 
				
			||||||
	joined_players = {},
 | 
						joined_players = {},
 | 
				
			||||||
	modpath = modpath,
 | 
						modpath = modpath,
 | 
				
			||||||
	lib = require("irc"),
 | 
						lib = lib,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- Compatibility
 | 
					-- Compatibility
 | 
				
			||||||
mt_irc = irc
 | 
					rawset(_G, "mt_irc", irc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local getinfo = debug.getinfo
 | 
				
			||||||
 | 
					local warned = { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function warn_deprecated(k)
 | 
				
			||||||
 | 
						local info = getinfo(3)
 | 
				
			||||||
 | 
						local loc = info.source..":"..info.currentline
 | 
				
			||||||
 | 
						if warned[loc] then return end
 | 
				
			||||||
 | 
						warned[loc] = true
 | 
				
			||||||
 | 
						print("COLON: "..tostring(k))
 | 
				
			||||||
 | 
						minetest.log("warning", "Deprecated use of colon notation when calling"
 | 
				
			||||||
 | 
								.." method `"..tostring(k).."` at "..loc)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- This is a hack.
 | 
				
			||||||
 | 
					setmetatable(irc, {
 | 
				
			||||||
 | 
						__newindex = function(t, k, v)
 | 
				
			||||||
 | 
							if type(v) == "function" then
 | 
				
			||||||
 | 
								local f = v
 | 
				
			||||||
 | 
								v = function(me, ...)
 | 
				
			||||||
 | 
									if rawequal(me, t) then
 | 
				
			||||||
 | 
										warn_deprecated(k)
 | 
				
			||||||
 | 
										return f(...)
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
										return f(me, ...)
 | 
				
			||||||
 | 
									end
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
							rawset(t, k, v)
 | 
				
			||||||
 | 
						end,
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dofile(modpath.."/config.lua")
 | 
					dofile(modpath.."/config.lua")
 | 
				
			||||||
dofile(modpath.."/messages.lua")
 | 
					dofile(modpath.."/messages.lua")
 | 
				
			||||||
dofile(modpath.."/hooks.lua")
 | 
					loadfile(modpath.."/hooks.lua")(ie)
 | 
				
			||||||
dofile(modpath.."/callback.lua")
 | 
					dofile(modpath.."/callback.lua")
 | 
				
			||||||
dofile(modpath.."/chatcmds.lua")
 | 
					dofile(modpath.."/chatcmds.lua")
 | 
				
			||||||
dofile(modpath.."/botcmds.lua")
 | 
					dofile(modpath.."/botcmds.lua")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- Restore old (safe) functions
 | 
				
			||||||
 | 
					require = old_require
 | 
				
			||||||
 | 
					rawset(_G, "module", old_module)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if irc.config.enable_player_part then
 | 
					if irc.config.enable_player_part then
 | 
				
			||||||
	dofile(modpath.."/player_part.lua")
 | 
						dofile(modpath.."/player_part.lua")
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
	setmetatable(irc.joined_players, {__index = function(index) return true end})
 | 
						setmetatable(irc.joined_players, {__index = function() return true end})
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
minetest.register_privilege("irc_admin", {
 | 
					minetest.register_privilege("irc_admin", {
 | 
				
			||||||
	description = "Allow IRC administrative tasks to be performed.",
 | 
						description = "Allow IRC administrative tasks to be performed.",
 | 
				
			||||||
	give_to_singleplayer = true
 | 
						give_to_singleplayer = true,
 | 
				
			||||||
 | 
						give_to_admin = true,
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local stepnum = 0
 | 
					local stepnum = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
minetest.register_globalstep(function(dtime) return irc:step(dtime) end)
 | 
					minetest.register_globalstep(function(dtime) return irc.step(dtime) end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:step(dtime)
 | 
					function irc.step()
 | 
				
			||||||
	if stepnum == 3 then
 | 
						if stepnum == 3 then
 | 
				
			||||||
		if self.config.auto_connect then
 | 
							if irc.config.auto_connect then
 | 
				
			||||||
			self:connect()
 | 
								irc.connect()
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	stepnum = stepnum + 1
 | 
						stepnum = stepnum + 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if not self.connected then return end
 | 
						if not irc.connected then return end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	-- Hooks will manage incoming messages and errors
 | 
						-- Hooks will manage incoming messages and errors
 | 
				
			||||||
	local good, err = xpcall(function() self.conn:think() end, debug.traceback)
 | 
						local good, err = xpcall(function() irc.conn:think() end, debug.traceback)
 | 
				
			||||||
	if not good then
 | 
						if not good then
 | 
				
			||||||
		print(err)
 | 
							print(err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
@@ -76,79 +137,89 @@ function irc:step(dtime)
 | 
				
			|||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:connect()
 | 
					function irc.connect()
 | 
				
			||||||
	if self.connected then
 | 
						if irc.connected then
 | 
				
			||||||
		minetest.log("error", "IRC: Ignoring attempt to connect when already connected.")
 | 
							minetest.log("error", "IRC: Ignoring attempt to connect when already connected.")
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	self.conn = irc.lib.new({
 | 
						irc.conn = irc.lib.new({
 | 
				
			||||||
		nick = self.config.nick,
 | 
							nick = irc.config.nick,
 | 
				
			||||||
		username = "Minetest",
 | 
							username = irc.config.username,
 | 
				
			||||||
		realname = "Minetest",
 | 
							realname = irc.config.realname,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	self:doHook(self.conn)
 | 
						irc.doHook(irc.conn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						-- We need to swap the `require` function again since
 | 
				
			||||||
 | 
						-- LuaIRC `require`s `ssl` if `irc.secure` is true.
 | 
				
			||||||
 | 
						old_require = require
 | 
				
			||||||
 | 
						require = ie.require
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local good, message = pcall(function()
 | 
						local good, message = pcall(function()
 | 
				
			||||||
		self.conn:connect({
 | 
							irc.conn:connect({
 | 
				
			||||||
			host = self.config.server,
 | 
								host = irc.config.server,
 | 
				
			||||||
			port = self.config.port,
 | 
								port = irc.config.port,
 | 
				
			||||||
			password = self.config.password,
 | 
								password = irc.config.password,
 | 
				
			||||||
			timeout = self.config.timeout,
 | 
								timeout = irc.config.timeout,
 | 
				
			||||||
			secure = self.config.secure
 | 
								reconnect = irc.config.reconnect,
 | 
				
			||||||
 | 
								secure = irc.config.secure
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	end)
 | 
						end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						require = old_require
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if not good then
 | 
						if not good then
 | 
				
			||||||
		minetest.log("error", ("IRC: Connection error: %s: %s -- Reconnecting in ten minutes...")
 | 
							minetest.log("error", ("IRC: Connection error: %s: %s -- Reconnecting in %d seconds...")
 | 
				
			||||||
					:format(self.config.server, message))
 | 
										:format(irc.config.server, message, irc.config.reconnect))
 | 
				
			||||||
		minetest.after(600, function() self:connect() end)
 | 
							minetest.after(irc.config.reconnect, function() irc.connect() end)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if self.config.NSPass then
 | 
						if irc.config.NSPass then
 | 
				
			||||||
		self:say("NickServ", "IDENTIFY "..self.config.NSPass)
 | 
							irc.conn:queue(irc.msgs.privmsg(
 | 
				
			||||||
 | 
									"NickServ", "IDENTIFY "..irc.config.NSPass))
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	self.conn:join(self.config.channel, self.config.key)
 | 
						irc.conn:join(irc.config.channel, irc.config.key)
 | 
				
			||||||
	self.connected = true
 | 
						irc.connected = true
 | 
				
			||||||
	minetest.log("action", "IRC: Connected!")
 | 
						minetest.log("action", "IRC: Connected!")
 | 
				
			||||||
	minetest.chat_send_all("IRC: Connected!")
 | 
						minetest.chat_send_all("IRC: Connected!")
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:disconnect(message)
 | 
					function irc.disconnect(message)
 | 
				
			||||||
	if self.connected then
 | 
						if irc.connected then
 | 
				
			||||||
		--The OnDisconnect hook will clear self.connected and print a disconnect message
 | 
							--The OnDisconnect hook will clear irc.connected and print a disconnect message
 | 
				
			||||||
		self.conn:disconnect(message)
 | 
							irc.conn:disconnect(message)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:say(to, message)
 | 
					function irc.say(to, message)
 | 
				
			||||||
	if not message then
 | 
						if not message then
 | 
				
			||||||
		message = to
 | 
							message = to
 | 
				
			||||||
		to = self.config.channel
 | 
							to = irc.config.channel
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	to = to or self.config.channel
 | 
						to = to or irc.config.channel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	self:queue(irc.msgs.privmsg(to, message))
 | 
						irc.queue(irc.msgs.privmsg(to, message))
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:reply(message)
 | 
					function irc.reply(message)
 | 
				
			||||||
	if not self.last_from then
 | 
						if not irc.last_from then
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	message = message:gsub("[\r\n%z]", " \\n ")
 | 
						message = message:gsub("[\r\n%z]", " \\n ")
 | 
				
			||||||
	self:say(self.last_from, message)
 | 
						irc.say(irc.last_from, message)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:send(msg)
 | 
					function irc.send(msg)
 | 
				
			||||||
	if not self.connected then return end
 | 
						if not irc.connected then return end
 | 
				
			||||||
	self.conn:send(msg)
 | 
						irc.conn:send(msg)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:queue(msg)
 | 
					function irc.queue(msg)
 | 
				
			||||||
	if not self.connected then return end
 | 
						if not irc.connected then return end
 | 
				
			||||||
	self.conn:queue(msg)
 | 
						irc.conn:queue(msg)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								irc/irc/.travis.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								irc/irc/.travis.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					language: lua
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					notifications:
 | 
				
			||||||
 | 
					  email: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					env:
 | 
				
			||||||
 | 
					  global:
 | 
				
			||||||
 | 
					    - secure: "kFhU+DZjhq/KbDt0DIDWnlskXMa12miNelmhhy30fQGgVIdiibDGKMNGyLahWp8CnPu1DARb5AZWK2TDfARdnURT2pgcsG83M7bYIY6cR647BWjL7oAhJ6CYEzTWJTBjeUjpN/o4vIgfXSDR0c7vboDi7Xz8ilfrBujPL2Oi/og="
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					install:
 | 
				
			||||||
 | 
					  - sudo apt-get -y update
 | 
				
			||||||
 | 
					  - sudo apt-get -y install lua5.1 luadoc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					script:
 | 
				
			||||||
 | 
					  - ./push-luadoc.sh
 | 
				
			||||||
@@ -1,7 +1,8 @@
 | 
				
			|||||||
 | 
					[](https://travis-ci.org/JakobOvrum/LuaIRC)
 | 
				
			||||||
LuaIRC
 | 
					LuaIRC
 | 
				
			||||||
============
 | 
					============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
IRC library for Lua.
 | 
					IRC client library for Lua.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Dependencies
 | 
					Dependencies
 | 
				
			||||||
-------------
 | 
					-------------
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
local irc = require("irc.main")
 | 
					local msgs = require("irc.messages")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local meta = irc.meta
 | 
					local meta = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function meta:send(msg, ...)
 | 
					function meta:send(msg, ...)
 | 
				
			||||||
	if type(msg) == "table" then
 | 
						if type(msg) == "table" then
 | 
				
			||||||
@@ -36,26 +36,26 @@ end
 | 
				
			|||||||
function meta:sendChat(target, msg)
 | 
					function meta:sendChat(target, msg)
 | 
				
			||||||
	-- Split the message into segments if it includes newlines.
 | 
						-- Split the message into segments if it includes newlines.
 | 
				
			||||||
	for line in msg:gmatch("([^\r\n]+)") do
 | 
						for line in msg:gmatch("([^\r\n]+)") do
 | 
				
			||||||
		self:queue(irc.msgs.privmsg(verify(target, 3), line))
 | 
							self:queue(msgs.privmsg(verify(target, 3), line))
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function meta:sendNotice(target, msg)
 | 
					function meta:sendNotice(target, msg)
 | 
				
			||||||
	-- Split the message into segments if it includes newlines.
 | 
						-- Split the message into segments if it includes newlines.
 | 
				
			||||||
	for line in msg:gmatch("([^\r\n]+)") do
 | 
						for line in msg:gmatch("([^\r\n]+)") do
 | 
				
			||||||
		self:queue(irc.msgs.notice(verify(target, 3), line))
 | 
							self:queue(msgs.notice(verify(target, 3), line))
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function meta:join(channel, key)
 | 
					function meta:join(channel, key)
 | 
				
			||||||
	self:queue(irc.msgs.join(
 | 
						self:queue(msgs.join(
 | 
				
			||||||
			verify(channel, 3),
 | 
								verify(channel, 3),
 | 
				
			||||||
			key and verify(key, 3) or nil))
 | 
								key and verify(key, 3) or nil))
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function meta:part(channel, reason)
 | 
					function meta:part(channel, reason)
 | 
				
			||||||
	channel = verify(channel, 3)
 | 
						channel = verify(channel, 3)
 | 
				
			||||||
	self:queue(irc.msgs.part(channel, reason))
 | 
						self:queue(msgs.part(channel, reason))
 | 
				
			||||||
	if self.track_users then
 | 
						if self.track_users then
 | 
				
			||||||
		self.channels[channel] = nil
 | 
							self.channels[channel] = nil
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
@@ -85,6 +85,8 @@ function meta:setMode(t)
 | 
				
			|||||||
		mode = table.concat{mode, "-", verify(rem, 3)}
 | 
							mode = table.concat{mode, "-", verify(rem, 3)}
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	self:queue(irc.msgs.mode(verify(target, 3), mode))
 | 
						self:queue(msgs.mode(verify(target, 3), mode))
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					return meta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
--- LuaIRC is a low-level IRC library for Lua.
 | 
					--- LuaIRC is a low-level IRC library for Lua.
 | 
				
			||||||
-- All functions raise Lua exceptions on error.
 | 
					-- All functions raise Lua exceptions on error.
 | 
				
			||||||
--
 | 
					--
 | 
				
			||||||
-- Use <code>new</code> to create a new IRC object.<br/>
 | 
					-- Use <code>new</code> to create a new Connection object.<br/>
 | 
				
			||||||
-- Example:<br/><br/>
 | 
					-- Example:<br/><br/>
 | 
				
			||||||
--<code>
 | 
					--<code>
 | 
				
			||||||
--require "irc"<br/>
 | 
					--require "irc"<br/>
 | 
				
			||||||
@@ -24,11 +24,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
module "irc"
 | 
					module "irc"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--- Create a new IRC object. Use <code>irc:connect</code> to connect to a server.
 | 
					--- Create a new Connection object. Use <code>irc:connect</code> to connect to a server.
 | 
				
			||||||
-- @param user Table with fields <code>nick</code>, <code>username</code> and <code>realname</code>.
 | 
					-- @param user Table with fields <code>nick</code>, <code>username</code> and <code>realname</code>.
 | 
				
			||||||
-- The <code>nick</code> field is required.
 | 
					-- The <code>nick</code> field is required.
 | 
				
			||||||
--
 | 
					--
 | 
				
			||||||
-- @return Returns a new <code>irc</code> object.
 | 
					-- @return Returns a new Connection object.
 | 
				
			||||||
 | 
					-- @see Connection
 | 
				
			||||||
function new(user)
 | 
					function new(user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--- Hook a function to an event.
 | 
					--- Hook a function to an event.
 | 
				
			||||||
@@ -46,10 +47,10 @@ function irc:unhook(name, id)
 | 
				
			|||||||
--- Connect <code>irc</code> to an IRC server.
 | 
					--- Connect <code>irc</code> to an IRC server.
 | 
				
			||||||
-- @param host Host address.
 | 
					-- @param host Host address.
 | 
				
			||||||
-- @param port Server port. [default 6667]
 | 
					-- @param port Server port. [default 6667]
 | 
				
			||||||
function irc:connect(server, port)
 | 
					function irc:connect(host, port)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- @param table Table of connection details
 | 
					-- @param table Table of connection details
 | 
				
			||||||
-- @see Connection
 | 
					-- @see ConnectOptions
 | 
				
			||||||
function irc:connect(table)
 | 
					function irc:connect(table)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--- Disconnect <code>irc</code> from the server.
 | 
					--- Disconnect <code>irc</code> from the server.
 | 
				
			||||||
@@ -116,16 +117,26 @@ function irc:handle(msg)
 | 
				
			|||||||
function irc:shutdown()
 | 
					function irc:shutdown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--- Table with connection information.
 | 
					--- Table with connection information.
 | 
				
			||||||
-- <ul>
 | 
					-- @name ConnectOptions
 | 
				
			||||||
-- <li><code>host</code> - Server host name.</li>
 | 
					-- @class table
 | 
				
			||||||
-- <li><code>port</code> - Server port. [defaults to <code>6667</code>]</li>
 | 
					-- @field host Server host name.
 | 
				
			||||||
-- <li><code>timeout</code> - Connect timeout. [defaults to <code>30</code>]</li>
 | 
					-- @field port Server port. [defaults to <code>6667</code>]
 | 
				
			||||||
-- <li><code>password</code> - Server password.</li>
 | 
					-- @field timeout Connect timeout. [defaults to <code>30</code>]
 | 
				
			||||||
-- <li><code>secure</code> - Boolean to enable TLS connection, pass a params table (described, [luasec]) to control</li>
 | 
					-- @field password Server password.
 | 
				
			||||||
-- </ul>
 | 
					-- @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
 | 
					-- [luasec]: http://www.inf.puc-rio.br/~brunoos/luasec/reference.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--- Class representing a connection.
 | 
				
			||||||
-- @name Connection
 | 
					-- @name Connection
 | 
				
			||||||
-- @class table
 | 
					-- @class table
 | 
				
			||||||
 | 
					-- @field authed Boolean indicating whether the connection has completed registration.
 | 
				
			||||||
 | 
					-- @field connected Whether the connection is currently connected.
 | 
				
			||||||
 | 
					-- @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.
 | 
					--- Class representing an IRC message.
 | 
				
			||||||
-- @name Message
 | 
					-- @name Message
 | 
				
			||||||
@@ -145,8 +156,8 @@ function irc:shutdown()
 | 
				
			|||||||
--- List of hooks you can use with irc:hook.
 | 
					--- List of hooks you can use with irc:hook.
 | 
				
			||||||
-- The parameter list describes the parameters passed to the callback function.
 | 
					-- The parameter list describes the parameters passed to the callback function.
 | 
				
			||||||
-- <ul>
 | 
					-- <ul>
 | 
				
			||||||
-- <li><code>PreRegister(connection)</code>Useful for CAP commands and SASL.</li>
 | 
					-- <li><code>PreRegister()</code> - Usefull for requesting capabilities.</li>
 | 
				
			||||||
-- <li><code>OnRaw(line) - (any non false/nil return value assumes line handled and will not be further processed)</code></li>
 | 
					-- <li><code>OnRaw(line)</code> - Any non false/nil return value assumes line handled and will not be further processed.</li>
 | 
				
			||||||
-- <li><code>OnSend(line)</code></li>
 | 
					-- <li><code>OnSend(line)</code></li>
 | 
				
			||||||
-- <li><code>OnDisconnect(message, errorOccurred)</code></li>
 | 
					-- <li><code>OnDisconnect(message, errorOccurred)</code></li>
 | 
				
			||||||
-- <li><code>OnChat(user, channel, message)</code></li>
 | 
					-- <li><code>OnChat(user, channel, message)</code></li>
 | 
				
			||||||
@@ -162,7 +173,10 @@ function irc:shutdown()
 | 
				
			|||||||
-- <li><code>OnUserMode(modes)</code></li>
 | 
					-- <li><code>OnUserMode(modes)</code></li>
 | 
				
			||||||
-- <li><code>OnChannelMode(user, channel, modes)</code></li>
 | 
					-- <li><code>OnChannelMode(user, channel, modes)</code></li>
 | 
				
			||||||
-- <li><code>OnModeChange(user, target, modes, ...)</code>* ('...' contains mode options such as banmasks)</li>
 | 
					-- <li><code>OnModeChange(user, target, modes, ...)</code>* ('...' contains mode options such as banmasks)</li>
 | 
				
			||||||
-- <li><code>DoX(msg)</code>'X' is any IRC command or numeric with the first letter capitalized (eg, DoPing and Do001)</li>
 | 
					-- <li><code>OnCapabilityList(caps)</code></li>
 | 
				
			||||||
 | 
					-- <li><code>OnCapabilityAvailable(cap, value)</code> Called only when a capability becomes available or changes.</li>
 | 
				
			||||||
 | 
					-- <li><code>OnCapabilitySet(cap, enabled)</code>*</li>
 | 
				
			||||||
 | 
					-- <li><code>DoX(msg)</code>* - 'X' is any IRC command or numeric with the first letter capitalized (eg, DoPing and Do001)</li>
 | 
				
			||||||
-- </ul>
 | 
					-- </ul>
 | 
				
			||||||
-- * Event also invoked for yourself.
 | 
					-- * Event also invoked for yourself.
 | 
				
			||||||
-- <20> Channel passed only when user tracking is enabled
 | 
					-- <20> Channel passed only when user tracking is enabled
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,72 @@
 | 
				
			|||||||
local irc = require("irc.main")
 | 
					local util = require("irc.util")
 | 
				
			||||||
 | 
					local msgs = require("irc.messages")
 | 
				
			||||||
 | 
					local Message = msgs.Message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
irc.handlers = {}
 | 
					local handlers = {}
 | 
				
			||||||
local handlers = irc.handlers
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
handlers["PING"] = function(conn, msg)
 | 
					handlers["PING"] = function(conn, msg)
 | 
				
			||||||
	conn:send(irc.Message({command="PONG", args=msg.args}))
 | 
						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
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
handlers["001"] = function(conn, msg)
 | 
					handlers["001"] = function(conn, msg)
 | 
				
			||||||
@@ -16,7 +78,6 @@ handlers["PRIVMSG"] = function(conn, msg)
 | 
				
			|||||||
	conn:invoke("OnChat", msg.user, msg.args[1], msg.args[2])
 | 
						conn:invoke("OnChat", msg.user, msg.args[1], msg.args[2])
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
handlers["NOTICE"] = function(conn, msg)
 | 
					handlers["NOTICE"] = function(conn, msg)
 | 
				
			||||||
	conn:invoke("OnNotice", msg.user, msg.args[1], msg.args[2])
 | 
						conn:invoke("OnNotice", msg.user, msg.args[1], msg.args[2])
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
@@ -71,15 +132,13 @@ handlers["NICK"] = function(conn, msg)
 | 
				
			|||||||
		conn:invoke("NickChange", msg.user, newNick)
 | 
							conn:invoke("NickChange", msg.user, newNick)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	if msg.user.nick == conn.nick then
 | 
						if msg.user.nick == conn.nick then
 | 
				
			||||||
		conn.nick = newnick
 | 
							conn.nick = newNick
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local function needNewNick(conn, msg)
 | 
					local function needNewNick(conn, msg)
 | 
				
			||||||
	local newnick = conn.nickGenerator(msg.args[2])
 | 
						local newnick = conn.nickGenerator(msg.args[2])
 | 
				
			||||||
	if msg.nick then
 | 
						conn:queue(irc.msgs.nick(newnick))
 | 
				
			||||||
		conn:queue(msg.nick(newnick))
 | 
					 | 
				
			||||||
	end -- Ugly fix
 | 
					 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- ERR_ERRONEUSNICKNAME (Misspelt but remains for historical reasons)
 | 
					-- ERR_ERRONEUSNICKNAME (Misspelt but remains for historical reasons)
 | 
				
			||||||
@@ -88,6 +147,13 @@ handlers["432"] = needNewNick
 | 
				
			|||||||
-- ERR_NICKNAMEINUSE
 | 
					-- ERR_NICKNAMEINUSE
 | 
				
			||||||
handlers["433"] = needNewNick
 | 
					handlers["433"] = needNewNick
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- ERR_UNAVAILRESOURCE
 | 
				
			||||||
 | 
					handlers["437"] = function(conn, msg)
 | 
				
			||||||
 | 
						if not conn.authed then
 | 
				
			||||||
 | 
							needNewNick(conn, msg)
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- RPL_ISUPPORT
 | 
					-- RPL_ISUPPORT
 | 
				
			||||||
handlers["005"] = function(conn, msg)
 | 
					handlers["005"] = function(conn, msg)
 | 
				
			||||||
	local arglen = #msg.args
 | 
						local arglen = #msg.args
 | 
				
			||||||
@@ -124,7 +190,7 @@ handlers["353"] = function(conn, msg)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		local users = conn.channels[channel].users
 | 
							local users = conn.channels[channel].users
 | 
				
			||||||
		for nick in names:gmatch("(%S+)") do
 | 
							for nick in names:gmatch("(%S+)") do
 | 
				
			||||||
			local access, name = irc.parseNick(conn, nick)
 | 
								local access, name = util.parseNick(conn, nick)
 | 
				
			||||||
			users[name] = {access = access}
 | 
								users[name] = {access = access}
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
@@ -181,7 +247,7 @@ handlers["MODE"] = function(conn, msg)
 | 
				
			|||||||
	if conn.track_users and target ~= conn.nick then
 | 
						if conn.track_users and target ~= conn.nick then
 | 
				
			||||||
		local add = true
 | 
							local add = true
 | 
				
			||||||
		local argNum = 1
 | 
							local argNum = 1
 | 
				
			||||||
		irc.updatePrefixModes(conn)
 | 
							util.updatePrefixModes(conn)
 | 
				
			||||||
		for c in modes:gmatch(".") do
 | 
							for c in modes:gmatch(".") do
 | 
				
			||||||
			if     c == "+" then add = true
 | 
								if     c == "+" then add = true
 | 
				
			||||||
			elseif c == "-" then add = false
 | 
								elseif c == "-" then add = false
 | 
				
			||||||
@@ -207,3 +273,5 @@ handlers["ERROR"] = function(conn, msg)
 | 
				
			|||||||
	error(msg.args[1], 3)
 | 
						error(msg.args[1], 3)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					return handlers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										260
									
								
								irc/irc/init.lua
									
									
									
									
									
								
							
							
						
						
									
										260
									
								
								irc/irc/init.lua
									
									
									
									
									
								
							@@ -1,9 +1,257 @@
 | 
				
			|||||||
 | 
					local socket = require("socket")
 | 
				
			||||||
 | 
					local util = require("irc.util")
 | 
				
			||||||
 | 
					local handlers = require("irc.handlers")
 | 
				
			||||||
 | 
					local msgs = require("irc.messages")
 | 
				
			||||||
 | 
					local Message = msgs.Message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local irc = require("irc.main")
 | 
					local meta = {}
 | 
				
			||||||
require("irc.util")
 | 
					meta.__index = meta
 | 
				
			||||||
require("irc.asyncoperations")
 | 
					 | 
				
			||||||
require("irc.handlers")
 | 
					 | 
				
			||||||
require("irc.messages")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
return irc
 | 
					
 | 
				
			||||||
 | 
					for k, v in pairs(require("irc.asyncoperations")) do
 | 
				
			||||||
 | 
						meta[k] = v
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local meta_preconnect = {}
 | 
				
			||||||
 | 
					function meta_preconnect.__index(o, k)
 | 
				
			||||||
 | 
						local v = rawget(meta_preconnect, k)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if v == nil and meta[k] ~= nil then
 | 
				
			||||||
 | 
							error(("field '%s' is not accessible before connecting"):format(k), 2)
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						return v
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					meta.connected = true
 | 
				
			||||||
 | 
					meta_preconnect.connected = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function new(data)
 | 
				
			||||||
 | 
						local o = {
 | 
				
			||||||
 | 
							nick = assert(data.nick, "Field 'nick' is required");
 | 
				
			||||||
 | 
							username = data.username or "lua";
 | 
				
			||||||
 | 
							realname = data.realname or "Lua owns";
 | 
				
			||||||
 | 
							nickGenerator = data.nickGenerator or util.defaultNickGenerator;
 | 
				
			||||||
 | 
							hooks = {};
 | 
				
			||||||
 | 
							track_users = true;
 | 
				
			||||||
 | 
							supports = {};
 | 
				
			||||||
 | 
							messageQueue = {};
 | 
				
			||||||
 | 
							lastThought = 0;
 | 
				
			||||||
 | 
							recentMessages = 0;
 | 
				
			||||||
 | 
							availableCapabilities = {};
 | 
				
			||||||
 | 
							wantedCapabilities = {};
 | 
				
			||||||
 | 
							capabilities = {};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						assert(util.checkNick(o.nick), "Erroneous nickname passed to irc.new")
 | 
				
			||||||
 | 
						return setmetatable(o, meta_preconnect)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function meta:hook(name, id, f)
 | 
				
			||||||
 | 
						f = f or id
 | 
				
			||||||
 | 
						self.hooks[name] = self.hooks[name] or {}
 | 
				
			||||||
 | 
						self.hooks[name][id] = f
 | 
				
			||||||
 | 
						return id or f
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					meta_preconnect.hook = meta.hook
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function meta:unhook(name, id)
 | 
				
			||||||
 | 
						local hooks = self.hooks[name]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert(hooks, "no hooks exist for this event")
 | 
				
			||||||
 | 
						assert(hooks[id], "hook ID not found")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hooks[id] = nil
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					meta_preconnect.unhook = meta.unhook
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function meta:invoke(name, ...)
 | 
				
			||||||
 | 
						local hooks = self.hooks[name]
 | 
				
			||||||
 | 
						if hooks then
 | 
				
			||||||
 | 
							for id, f in pairs(hooks) do
 | 
				
			||||||
 | 
								local ret = f(...)
 | 
				
			||||||
 | 
								if ret then
 | 
				
			||||||
 | 
									return ret
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function meta_preconnect:connect(_host, _port)
 | 
				
			||||||
 | 
						local host, port, password, secure, timeout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if type(_host) == "table" then
 | 
				
			||||||
 | 
							host = _host.host
 | 
				
			||||||
 | 
							port = _host.port
 | 
				
			||||||
 | 
							timeout = _host.timeout
 | 
				
			||||||
 | 
							password = _host.password
 | 
				
			||||||
 | 
							secure = _host.secure
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							host = _host
 | 
				
			||||||
 | 
							port = _port
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						host = host or error("host name required to connect", 2)
 | 
				
			||||||
 | 
						port = port or 6667
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local s = socket.tcp()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						s:settimeout(timeout or 30)
 | 
				
			||||||
 | 
						assert(s:connect(host, port))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if secure then
 | 
				
			||||||
 | 
							local work, ssl = pcall(require, "ssl")
 | 
				
			||||||
 | 
							if not work then
 | 
				
			||||||
 | 
								error("LuaSec required for secure connections", 2)
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							local params
 | 
				
			||||||
 | 
							if type(secure) == "table" then
 | 
				
			||||||
 | 
								params = secure
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								params = {mode = "client", protocol = "tlsv1"}
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							s = ssl.wrap(s, params)
 | 
				
			||||||
 | 
							local success, errmsg = s:dohandshake()
 | 
				
			||||||
 | 
							if not success then
 | 
				
			||||||
 | 
								error(("could not make secure connection: %s"):format(errmsg), 2)
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						self.socket = s
 | 
				
			||||||
 | 
						setmetatable(self, meta)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						self:invoke("PreRegister", self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if password then
 | 
				
			||||||
 | 
							self:queue(Message({command="PASS", args={password}}))
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						self:queue(msgs.nick(self.nick))
 | 
				
			||||||
 | 
						self:queue(Message({command="USER", args={self.username, "0", "*", self.realname}}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						self.channels = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						s:settimeout(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						repeat
 | 
				
			||||||
 | 
							self:think()
 | 
				
			||||||
 | 
							socket.sleep(0.1)
 | 
				
			||||||
 | 
						until self.authed
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function meta:disconnect(message)
 | 
				
			||||||
 | 
						message = message or "Bye!"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						self:invoke("OnDisconnect", message, false)
 | 
				
			||||||
 | 
						self:send(msgs.quit(message))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						self:shutdown()
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function meta:shutdown()
 | 
				
			||||||
 | 
						self.socket:close()
 | 
				
			||||||
 | 
						setmetatable(self, meta_preconnect)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local function getline(self, errlevel)
 | 
				
			||||||
 | 
						local line, err = self.socket:receive("*l")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if not line and err ~= "timeout" and err ~= "wantread" then
 | 
				
			||||||
 | 
							self:invoke("OnDisconnect", err, true)
 | 
				
			||||||
 | 
							self:shutdown()
 | 
				
			||||||
 | 
							error(err, errlevel)
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return line
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function meta:think()
 | 
				
			||||||
 | 
						while true do
 | 
				
			||||||
 | 
							local line = getline(self, 3)
 | 
				
			||||||
 | 
							if line and #line > 0 then
 | 
				
			||||||
 | 
								if not self:invoke("OnRaw", line) then
 | 
				
			||||||
 | 
									self:handle(Message({raw=line}))
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						-- Handle outgoing message queue
 | 
				
			||||||
 | 
						local diff = socket.gettime() - self.lastThought
 | 
				
			||||||
 | 
						self.recentMessages = self.recentMessages - (diff * 2)
 | 
				
			||||||
 | 
						if self.recentMessages < 0 then
 | 
				
			||||||
 | 
							self.recentMessages = 0
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						for i = 1, #self.messageQueue do
 | 
				
			||||||
 | 
							if self.recentMessages > 4 then
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
							self:send(table.remove(self.messageQueue, 1))
 | 
				
			||||||
 | 
							self.recentMessages = self.recentMessages + 1
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						self.lastThought = socket.gettime()
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function meta:handle(msg)
 | 
				
			||||||
 | 
						local handler = handlers[msg.command]
 | 
				
			||||||
 | 
						if handler then
 | 
				
			||||||
 | 
							handler(self, msg)
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						self:invoke("Do" .. util.capitalize(msg.command), msg)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local whoisHandlers = {
 | 
				
			||||||
 | 
						["311"] = "userinfo";
 | 
				
			||||||
 | 
						["312"] = "node";
 | 
				
			||||||
 | 
						["319"] = "channels";
 | 
				
			||||||
 | 
						["330"] = "account"; -- Freenode
 | 
				
			||||||
 | 
						["307"] = "registered"; -- Unreal
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function meta:whois(nick)
 | 
				
			||||||
 | 
						self:send(msgs.whois(nick))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local result = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while true do
 | 
				
			||||||
 | 
							local line = getline(self, 3)
 | 
				
			||||||
 | 
							if line then
 | 
				
			||||||
 | 
								local msg = Message({raw=line})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								local handler = whoisHandlers[msg.command]
 | 
				
			||||||
 | 
								if handler then
 | 
				
			||||||
 | 
									result[handler] = msg.args
 | 
				
			||||||
 | 
								elseif msg.command == "318" then
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									self:handle(msg)
 | 
				
			||||||
 | 
								end
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if result.account then
 | 
				
			||||||
 | 
							result.account = result.account[3]
 | 
				
			||||||
 | 
						elseif result.registered then
 | 
				
			||||||
 | 
							result.account = result.registered[2]
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function meta:topic(channel)
 | 
				
			||||||
 | 
						self:queue(msgs.topic(channel))
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					return {
 | 
				
			||||||
 | 
						new = new;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Message = Message;
 | 
				
			||||||
 | 
						msgs = msgs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						color = util.color;
 | 
				
			||||||
 | 
						bold = util.bold;
 | 
				
			||||||
 | 
						underline = util.underline;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,11 @@
 | 
				
			|||||||
local irc = require("irc.main")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
irc.msgs = {}
 | 
					-- Module table
 | 
				
			||||||
local msgs = irc.msgs
 | 
					local m = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local msg_meta = {}
 | 
					local msg_meta = {}
 | 
				
			||||||
msg_meta.__index = msg_meta
 | 
					msg_meta.__index = msg_meta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc.Message(opts)
 | 
					local function Message(opts)
 | 
				
			||||||
	opts = opts or {}
 | 
						opts = opts or {}
 | 
				
			||||||
	setmetatable(opts, msg_meta)
 | 
						setmetatable(opts, msg_meta)
 | 
				
			||||||
	if opts.raw then
 | 
						if opts.raw then
 | 
				
			||||||
@@ -15,6 +14,8 @@ function irc.Message(opts)
 | 
				
			|||||||
	return opts
 | 
						return opts
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					m.Message = Message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local tag_escapes = {
 | 
					local tag_escapes = {
 | 
				
			||||||
	[";"] = "\\:",
 | 
						[";"] = "\\:",
 | 
				
			||||||
	[" "] = "\\s",
 | 
						[" "] = "\\s",
 | 
				
			||||||
@@ -47,7 +48,7 @@ function msg_meta:toRFC1459()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	s = s..self.command
 | 
						s = s..self.command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local argnum = #self.args
 | 
						local argnum = self.args and #self.args or 0
 | 
				
			||||||
	for i = 1, argnum do
 | 
						for i = 1, argnum do
 | 
				
			||||||
		local arg = self.args[i]
 | 
							local arg = self.args[i]
 | 
				
			||||||
		local startsWithColon = (arg:sub(1, 1) == ":")
 | 
							local startsWithColon = (arg:sub(1, 1) == ":")
 | 
				
			||||||
@@ -116,85 +117,91 @@ function msg_meta:fromRFC1459(line)
 | 
				
			|||||||
	end
 | 
						end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function msgs.privmsg(to, text)
 | 
					function m.privmsg(to, text)
 | 
				
			||||||
	return irc.Message({command="PRIVMSG", args={to, text}})
 | 
						return Message({command="PRIVMSG", args={to, text}})
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function msgs.notice(to, text)
 | 
					function m.notice(to, text)
 | 
				
			||||||
	return irc.Message({command="NOTICE", args={to, text}})
 | 
						return Message({command="NOTICE", args={to, text}})
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function msgs.action(to, text)
 | 
					function m.action(to, text)
 | 
				
			||||||
	return irc.Message({command="PRIVMSG", args={to, ("\x01ACTION %s\x01"):format(text)}})
 | 
						return Message({command="PRIVMSG", args={to, ("\x01ACTION %s\x01"):format(text)}})
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function msgs.ctcp(command, to, args)
 | 
					function m.ctcp(command, to, args)
 | 
				
			||||||
	s = "\x01"..command
 | 
						s = "\x01"..command
 | 
				
			||||||
	if args then
 | 
						if args then
 | 
				
			||||||
		s = ' '..args
 | 
							s = ' '..args
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	s = s..'\x01'
 | 
						s = s..'\x01'
 | 
				
			||||||
	return irc.Message({command="PRIVMSG", args={to, s}})
 | 
						return Message({command="PRIVMSG", args={to, s}})
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function msgs.kick(channel, target, reason)
 | 
					function m.kick(channel, target, reason)
 | 
				
			||||||
	return irc.Message({command="KICK", args={channel, target, reason}})
 | 
						return Message({command="KICK", args={channel, target, reason}})
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function msgs.join(channel, key)
 | 
					function m.join(channel, key)
 | 
				
			||||||
	return irc.Message({command="JOIN", args={channel, key}})
 | 
						return Message({command="JOIN", args={channel, key}})
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function msgs.part(channel, reason)
 | 
					function m.part(channel, reason)
 | 
				
			||||||
	return irc.Message({command="PART", args={channel, reason}})
 | 
						return Message({command="PART", args={channel, reason}})
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function msgs.quit(reason)
 | 
					function m.quit(reason)
 | 
				
			||||||
	return irc.Message({command="QUIT", args={reason}})
 | 
						return Message({command="QUIT", args={reason}})
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function msgs.kill(target, reason)
 | 
					function m.kill(target, reason)
 | 
				
			||||||
	return irc.Message({command="KILL", args={target, reason}})
 | 
						return Message({command="KILL", args={target, reason}})
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function msgs.kline(time, mask, reason, operreason)
 | 
					function m.kline(time, mask, reason, operreason)
 | 
				
			||||||
	local args = nil
 | 
						local args = nil
 | 
				
			||||||
	if time then
 | 
						if time then
 | 
				
			||||||
		args = {time, mask, reason..'|'..operreason}
 | 
							args = {time, mask, reason..'|'..operreason}
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		args = {mask, reason..'|'..operreason}
 | 
							args = {mask, reason..'|'..operreason}
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	return irc.Message({command="KLINE", args=args})
 | 
						return Message({command="KLINE", args=args})
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function msgs.whois(nick, server)
 | 
					function m.whois(nick, server)
 | 
				
			||||||
	local args = nil
 | 
						local args = nil
 | 
				
			||||||
	if server then
 | 
						if server then
 | 
				
			||||||
		args = {server, nick}
 | 
							args = {server, nick}
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		args = {nick}
 | 
							args = {nick}
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	return irc.Message({command="WHOIS", args=args})
 | 
						return Message({command="WHOIS", args=args})
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function msgs.topic(channel, text)
 | 
					function m.topic(channel, text)
 | 
				
			||||||
	return irc.Message({command="TOPIC", args={channel, text}})
 | 
						return Message({command="TOPIC", args={channel, text}})
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function msgs.invite(channel, target)
 | 
					function m.invite(channel, target)
 | 
				
			||||||
	return irc.Message({command="INVITE", args={channel, target}})
 | 
						return Message({command="INVITE", args={channel, target}})
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function msgs.nick(nick)
 | 
					function m.nick(nick)
 | 
				
			||||||
	return irc.Message({command="NICK", args={nick}})
 | 
						return Message({command="NICK", args={nick}})
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function msgs.mode(target, modes)
 | 
					function m.mode(target, modes)
 | 
				
			||||||
	-- We have to split the modes parameter because the mode string and
 | 
						-- We have to split the modes parameter because the mode string and
 | 
				
			||||||
	-- each parameter are seperate arguments (The first command is incorrect)
 | 
						-- each parameter are seperate arguments (The first command is incorrect)
 | 
				
			||||||
	--   MODE foo :+ov Nick1 Nick2
 | 
						--   MODE foo :+ov Nick1 Nick2
 | 
				
			||||||
	--   MODE foo +ov Nick1 Nick2
 | 
						--   MODE foo +ov Nick1 Nick2
 | 
				
			||||||
	local mt = irc.split(modes)
 | 
						local mt = util.split(modes)
 | 
				
			||||||
	return irc.Message({command="MODE", args={target, unpack(mt)}})
 | 
						return Message({command="MODE", args={target, unpack(mt)}})
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function m.cap(cmd, ...)
 | 
				
			||||||
 | 
						return Message({command="CAP", args={cmd, ...}})
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					return m
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
local select = require "socket".select
 | 
					local select = require("socket").select
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local m = {}
 | 
					local m = {}
 | 
				
			||||||
local set = {}
 | 
					local set = {}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,25 +1,8 @@
 | 
				
			|||||||
local irc = require("irc.main")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc.parseNick(conn, nick)
 | 
					-- Module table
 | 
				
			||||||
	local access = {}
 | 
					local m = {}
 | 
				
			||||||
	irc.updatePrefixModes(conn)
 | 
					 | 
				
			||||||
	local namestart = 1
 | 
					 | 
				
			||||||
	for i = 1, #nick - 1 do
 | 
					 | 
				
			||||||
		local c = nick:sub(i, i)
 | 
					 | 
				
			||||||
		if conn.prefixmode[c] then
 | 
					 | 
				
			||||||
			access[conn.prefixmode[c]] = true
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			namestart = i
 | 
					 | 
				
			||||||
			break
 | 
					 | 
				
			||||||
		end
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
	access.op = access.o
 | 
					 | 
				
			||||||
	access.voice = access.v
 | 
					 | 
				
			||||||
	local name = nick:sub(namestart)
 | 
					 | 
				
			||||||
	return access, name
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc.updatePrefixModes(conn)
 | 
					function m.updatePrefixModes(conn)
 | 
				
			||||||
	if conn.prefixmode and conn.modeprefix then
 | 
						if conn.prefixmode and conn.modeprefix then
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
@@ -39,8 +22,27 @@ function irc.updatePrefixModes(conn)
 | 
				
			|||||||
	end
 | 
						end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function m.parseNick(conn, nick)
 | 
				
			||||||
 | 
						local access = {}
 | 
				
			||||||
 | 
						m.updatePrefixModes(conn)
 | 
				
			||||||
 | 
						local namestart = 1
 | 
				
			||||||
 | 
						for i = 1, #nick - 1 do
 | 
				
			||||||
 | 
							local c = nick:sub(i, i)
 | 
				
			||||||
 | 
							if conn.prefixmode[c] then
 | 
				
			||||||
 | 
								access[conn.prefixmode[c]] = true
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								namestart = i
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							end
 | 
				
			||||||
 | 
						end
 | 
				
			||||||
 | 
						access.op = access.o
 | 
				
			||||||
 | 
						access.voice = access.v
 | 
				
			||||||
 | 
						local name = nick:sub(namestart)
 | 
				
			||||||
 | 
						return access, name
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- mIRC markup scheme (de-facto standard)
 | 
					-- mIRC markup scheme (de-facto standard)
 | 
				
			||||||
irc.color = {
 | 
					m.color = {
 | 
				
			||||||
	black = 1,
 | 
						black = 1,
 | 
				
			||||||
	blue = 2,
 | 
						blue = 2,
 | 
				
			||||||
	green = 3,
 | 
						green = 3,
 | 
				
			||||||
@@ -60,28 +62,28 @@ irc.color = {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local colByte = string.char(3)
 | 
					local colByte = string.char(3)
 | 
				
			||||||
setmetatable(irc.color, {__call = function(_, text, colornum)
 | 
					setmetatable(m.color, {__call = function(_, text, colornum)
 | 
				
			||||||
	colornum = (type(colornum) == "string" and
 | 
						colornum = (type(colornum) == "string" and
 | 
				
			||||||
			assert(irc.color[colornum], "Invalid color '"..colornum.."'") or
 | 
								assert(color[colornum], "Invalid color '"..colornum.."'") or
 | 
				
			||||||
			colornum)
 | 
								colornum)
 | 
				
			||||||
	return table.concat{colByte, tostring(colornum), text, colByte}
 | 
						return table.concat{colByte, tostring(colornum), text, colByte}
 | 
				
			||||||
end})
 | 
					end})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local boldByte = string.char(2)
 | 
					local boldByte = string.char(2)
 | 
				
			||||||
function irc.bold(text)
 | 
					function m.bold(text)
 | 
				
			||||||
	return boldByte..text..boldByte
 | 
						return boldByte..text..boldByte
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local underlineByte = string.char(31)
 | 
					local underlineByte = string.char(31)
 | 
				
			||||||
function irc.underline(text)
 | 
					function m.underline(text)
 | 
				
			||||||
	return underlineByte..text..underlineByte
 | 
						return underlineByte..text..underlineByte
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc.checkNick(nick)
 | 
					function m.checkNick(nick)
 | 
				
			||||||
	return nick:find("^[a-zA-Z_%-%[|%]%^{|}`][a-zA-Z0-9_%-%[|%]%^{|}`]*$") ~= nil
 | 
						return nick:find("^[a-zA-Z_%-%[|%]%^{|}`][a-zA-Z0-9_%-%[|%]%^{|}`]*$") ~= nil
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc.defaultNickGenerator(nick)
 | 
					function m.defaultNickGenerator(nick)
 | 
				
			||||||
	-- LuaBot -> LuaCot -> LuaCou -> ...
 | 
						-- LuaBot -> LuaCot -> LuaCou -> ...
 | 
				
			||||||
	-- We change a random character rather than appending to the
 | 
						-- We change a random character rather than appending to the
 | 
				
			||||||
	-- nickname as otherwise the new nick could exceed the ircd's
 | 
						-- nickname as otherwise the new nick could exceed the ircd's
 | 
				
			||||||
@@ -100,13 +102,13 @@ function irc.defaultNickGenerator(nick)
 | 
				
			|||||||
	return nick
 | 
						return nick
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc.capitalize(text)
 | 
					function m.capitalize(text)
 | 
				
			||||||
  -- Converts first character to upercase and the rest to lowercase.
 | 
					  -- Converts first character to upercase and the rest to lowercase.
 | 
				
			||||||
  -- "PING" -> "Ping" | "hello" -> "Hello" | "123" -> "123"
 | 
					  -- "PING" -> "Ping" | "hello" -> "Hello" | "123" -> "123"
 | 
				
			||||||
  return text:sub(1, 1):upper()..text:sub(2):lower()
 | 
					  return text:sub(1, 1):upper()..text:sub(2):lower()
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc.split(str, sep)
 | 
					function m.split(str, sep)
 | 
				
			||||||
	local t = {}
 | 
						local t = {}
 | 
				
			||||||
	for s in str:gmatch("%S+") do
 | 
						for s in str:gmatch("%S+") do
 | 
				
			||||||
		table.insert(t, s)
 | 
							table.insert(t, s)
 | 
				
			||||||
@@ -114,3 +116,5 @@ function irc.split(str, sep)
 | 
				
			|||||||
	return t
 | 
						return t
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					return m
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,11 +3,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
irc.msgs = irc.lib.msgs
 | 
					irc.msgs = irc.lib.msgs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:sendLocal(message)
 | 
					function irc.logChat(message)
 | 
				
			||||||
	minetest.chat_send_all(message)
 | 
						minetest.log("action", "IRC CHAT: "..message)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:playerMessage(name, message)
 | 
					function irc.sendLocal(message)
 | 
				
			||||||
 | 
						minetest.chat_send_all(minetest.colorize(irc.config.chat_color, message))
 | 
				
			||||||
 | 
						irc.logChat(message)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function irc.playerMessage(name, message)
 | 
				
			||||||
	return ("<%s> %s"):format(name, message)
 | 
						return ("<%s> %s"):format(name, message)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								irc/mod.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								irc/mod.conf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					name = irc
 | 
				
			||||||
 | 
					description = 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.
 | 
				
			||||||
@@ -2,50 +2,52 @@
 | 
				
			|||||||
-- See LICENSE.txt for details.
 | 
					-- See LICENSE.txt for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:player_part(name)
 | 
					function irc.player_part(name)
 | 
				
			||||||
	if not self.joined_players[name] then
 | 
						if not irc.joined_players[name] then
 | 
				
			||||||
		minetest.chat_send_player(name, "IRC: You are not in the channel.")
 | 
							return false, "You are not in the channel"
 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	self.joined_players[name] = nil
 | 
						irc.joined_players[name] = nil
 | 
				
			||||||
	minetest.chat_send_player(name, "IRC: You are now out of the channel.")
 | 
						return true, "You left the channel"
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:player_join(name)
 | 
					function irc.player_join(name)
 | 
				
			||||||
	if self.joined_players[name] then
 | 
						if irc.joined_players[name] then
 | 
				
			||||||
		minetest.chat_send_player(name, "IRC: You are already in the channel.")
 | 
							return false, "You are already in the channel"
 | 
				
			||||||
		return
 | 
						elseif not minetest.get_player_by_name(name) then
 | 
				
			||||||
 | 
							return false, "You need to be in-game to join the channel"
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
	self.joined_players[name] = true
 | 
						irc.joined_players[name] = true
 | 
				
			||||||
	minetest.chat_send_player(name, "IRC: You are now in the channel.")
 | 
						return true, "You joined the channel"
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
minetest.register_chatcommand("join", {
 | 
					minetest.register_chatcommand("join", {
 | 
				
			||||||
	description = "Join the IRC channel",
 | 
						description = "Join the IRC channel",
 | 
				
			||||||
	privs = {shout=true},
 | 
						privs = {shout=true},
 | 
				
			||||||
	func = function(name, param)
 | 
						func = function(name)
 | 
				
			||||||
		irc:player_join(name)
 | 
							return irc.player_join(name)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
minetest.register_chatcommand("part", {
 | 
					minetest.register_chatcommand("part", {
 | 
				
			||||||
	description = "Part the IRC channel",
 | 
						description = "Part the IRC channel",
 | 
				
			||||||
	privs = {shout=true},
 | 
						privs = {shout=true},
 | 
				
			||||||
	func = function(name, param)
 | 
						func = function(name)
 | 
				
			||||||
		irc:player_part(name)
 | 
							return irc.player_part(name)
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
minetest.register_chatcommand("who", {
 | 
					minetest.register_chatcommand("who", {
 | 
				
			||||||
	description = "Tell who is currently on the channel",
 | 
						description = "Tell who is currently on the channel",
 | 
				
			||||||
	privs = {},
 | 
						privs = {},
 | 
				
			||||||
	func = function(name, param)
 | 
						func = function()
 | 
				
			||||||
		local s = ""
 | 
							local out, n = { }, 0
 | 
				
			||||||
		for name, _ in pairs(irc.joined_players) do
 | 
							for plname in pairs(irc.joined_players) do
 | 
				
			||||||
			s = s..", "..name
 | 
								n = n + 1
 | 
				
			||||||
 | 
								out[n] = plname
 | 
				
			||||||
		end
 | 
							end
 | 
				
			||||||
		minetest.chat_send_player(name, "Players On Channel:"..s)
 | 
							table.sort(out)
 | 
				
			||||||
 | 
							return true, "Players in channel: "..table.concat(out, ", ")
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -61,9 +63,10 @@ minetest.register_on_leaveplayer(function(player)
 | 
				
			|||||||
	irc.joined_players[name] = nil
 | 
						irc.joined_players[name] = nil
 | 
				
			||||||
end)
 | 
					end)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function irc:sendLocal(message)
 | 
					function irc.sendLocal(message)
 | 
				
			||||||
        for name, _ in pairs(self.joined_players) do
 | 
						for name, _ in pairs(irc.joined_players) do
 | 
				
			||||||
		minetest.chat_send_player(name, message)
 | 
							minetest.chat_send_player(name,
 | 
				
			||||||
 | 
										minetest.colorize(irc.config.chat_color, message))
 | 
				
			||||||
	end
 | 
						end
 | 
				
			||||||
 | 
						irc.logChat(message)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										75
									
								
								irc/settingtypes.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								irc/settingtypes.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					[Basic]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Whether to automatically connect to the server on mod load.
 | 
				
			||||||
 | 
					# If false, you must use /irc_connect to connect.
 | 
				
			||||||
 | 
					irc.auto_connect (Auto-connect on load) bool true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Nickname for the bot. May only contain characters A-Z, 0-9
 | 
				
			||||||
 | 
					# '{', '}', '[', ']', '|', '^', '-', or '_'.
 | 
				
			||||||
 | 
					irc.nick (Bot nickname) string Minetest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Server to connect to.
 | 
				
			||||||
 | 
					irc.server (IRC server) string irc.freenode.net
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Server port.
 | 
				
			||||||
 | 
					# The standard IRC protocol port is 6667 for regular servers,
 | 
				
			||||||
 | 
					# or 6697 for SSL-enabled servers.
 | 
				
			||||||
 | 
					# If unsure, leave at 6667.
 | 
				
			||||||
 | 
					irc.port (IRC server port) int 6667 1 65535
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Channel the bot joins after connecting.
 | 
				
			||||||
 | 
					irc.channel (Channel to join) string ##mt-irc-mod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Authentication]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Password for authenticating to NickServ.
 | 
				
			||||||
 | 
					# Leave empty to not authenticate with NickServ.
 | 
				
			||||||
 | 
					irc.NSPass (NickServ password) string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# IRC server password.
 | 
				
			||||||
 | 
					# Leave empty for no password.
 | 
				
			||||||
 | 
					irc.password (Server password) string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Password for joining the channel.
 | 
				
			||||||
 | 
					# Leave empty if your channel is not protected.
 | 
				
			||||||
 | 
					irc.key (Channel key) string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Enable TLS connection.
 | 
				
			||||||
 | 
					# Requires LuaSEC <https://github.com/brunoos/luasec>.
 | 
				
			||||||
 | 
					irc.secure (Use TLS) bool false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Username for SASL authentication.
 | 
				
			||||||
 | 
					# Leave empty to use the nickname.
 | 
				
			||||||
 | 
					irc.sasl.user (SASL username) string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Password for SASL authentication.
 | 
				
			||||||
 | 
					# Leave empty to not authenticate via SASL.
 | 
				
			||||||
 | 
					irc.sasl.pass (SASL password) string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Advanced]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Enable this to make the bot send messages when players join
 | 
				
			||||||
 | 
					# or leave the game server.
 | 
				
			||||||
 | 
					irc.send_join_part (Send join and part messages) bool true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Enable this to make the bot send messages when players are kicked.
 | 
				
			||||||
 | 
					irc.send_kicks (Send kick messages) bool false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Underlying socket timeout in seconds.
 | 
				
			||||||
 | 
					irc.timeout (Timeout) int 60 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Time between reconnection attempts, in seconds.
 | 
				
			||||||
 | 
					irc.reconnect (Reconnect delay) int 600 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Prefix to use for bot commands.
 | 
				
			||||||
 | 
					irc.command_prefix (Command prefix) string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Enable debug output.
 | 
				
			||||||
 | 
					irc.debug (Debug mode) bool false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Whether to enable players joining and parting the channel.
 | 
				
			||||||
 | 
					irc.enable_player_part (Allow player join/part) bool true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Whether to automatically show players in the channel when they join.
 | 
				
			||||||
 | 
					irc.auto_join (Auto join players) bool true
 | 
				
			||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
irc
 | 
					 | 
				
			||||||
							
								
								
									
										2
									
								
								irc_commands/mod.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								irc_commands/mod.conf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					name = irc_commands
 | 
				
			||||||
 | 
					depends = irc
 | 
				
			||||||
		Reference in New Issue
	
	Block a user