Skip to content

Instantly share code, notes, and snippets.

@raelik
Last active January 15, 2018 16:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save raelik/0dd5856d74d1839aeaa8bdc7e0475ba7 to your computer and use it in GitHub Desktop.
Save raelik/0dd5856d74d1839aeaa8bdc7e0475ba7 to your computer and use it in GitHub Desktop.
IRC Bridge for Eluna
package.path = package.path .. ';lua_lib/?.lua;lua_lib/?/init.lua'
local irc = require("irc")
local mirc_colors = {
'FFFFFF', -- White
'000000', -- Black
'00007F', -- Blue
'009300', -- Green
'FF0000', -- Light Red
'7F0000', -- Brown
'9C009C', -- Purple
'FC7F00', -- Orange
'FFFF00', -- Yellow
'00FC00', -- Light Green
'009393', -- Cyan
'00FFFF', -- Light Cyan
'0000FC', -- Light Blue
'FF00FF', -- Pink
'7F7F7F', -- Grey
'D2D2D2' -- Light Grey
}
local repl = {
["\15"]="|cFF40FB40",
["\2"]="",
["\7"]="",
["\22"]="",
["\31"]=""
}
local events = {}
local bot = nil
local reg = false
local guid = CreateUint64(nil) -- empty guid for GM message
local function configure()
local output = { prefixes={}, channels={}, guilds={}, default_prefix={ text="IRC", color=11 } }
local results = CharDBQuery("SELECT * FROM irc_config LIMIT 1")
if results then
local row = results:GetRow()
output.user = { nick=row.nick, username=row.username, realname=row.realname }
output.connect = { host=row.host, port=row.port }
if row.secure == 1 then output.connect.secure = true end
output.connect_modes = row.connect_modes
if row.password then output.connect.password = row.password end
if row.nickserv_password then
output.nickserv = { name=row.nickserv, password=row.nickserv_password }
end
if row.add_modes or row.rem_modes then
output.modes = {}
if row.add_modes then output.modes.add = row.add_modes end
if row.rem_modes then output.modes.rem = row.add_modes end
end
end
results = CharDBQuery("SELECT * FROM irc_prefixes ORDER BY nick ASC")
if results then
repeat
local row = results:GetRow()
if row.nick == '' then
output.default_prefix = { text=row.prefix, color=row.color }
else
output.prefixes[row.nick] = { text=row.prefix, color=row.color }
end
until not results:NextRow()
end
results = CharDBQuery("SELECT * FROM irc_channels ORDER BY guildid ASC")
if results then
repeat
local row = results:GetRow()
output.channels[row.guildid] = row.channel
output.guilds[row.channel] = row.guildid
until not results:NextRow()
end
return output
end
local config = configure()
local function colorize(str, color)
return ("|cff%s%s|cff40FB40"):format(mirc_colors[color+1], str)
end
local function default_prefix()
return colorize(config.default_prefix.text, config.default_prefix.color)
end
local function register_chat()
return RegisterPlayerEvent(21, function(event, player, msg, chat_type, lang, guild)
local channel = config.channels[guild:GetId()]
if chat_type == 4 and channel then
bot:sendChat(channel, ("[\0038%s\15]: %s"):format(player:GetName(), msg))
end
end)
end
local function register_login()
return RegisterPlayerEvent(3, function(event, player)
local channel = config.channels[player:GetGuildId()]
if channel then bot:sendChat(channel, ("%s has logged in."):format(player:GetName())) end
end)
end
local function register_logout()
return RegisterPlayerEvent(4, function(event, player)
local channel = config.channels[player:GetGuildId()]
if channel then bot:sendChat(channel, ("%s has logged out."):format(player:GetName())) end
end)
end
local function convert_mirc(str)
return string.gsub(
string.gsub(
string.gsub(str, "[|\2\7\15\22\31]", repl), "(\3%d%d?),%d%d?", "%1"),
"\3(%d%d?)", function(code)
return "|cFF" .. mirc_colors[code+1]
end)
end
local function send_guild(guild, pre, message)
local msg = ("|cFF40FB40[Guild] [%s]: %s"):format(pre, message)
local presz = string.len(pre) + 1
local msgsz = string.len(msg) + 1
-- SMSG_MESSAGECHAT 0x96 = 150
-- 30 bytes is the non-string data length.
local packet = CreatePacket(150, msgsz + 30)
packet:WriteUByte(0) -- chat type (CHAT_MSG_SYSTEM)
packet:WriteLong(0) -- lang (Universal)
packet:WriteGUID(guid) -- sender guid (nil)
packet:WriteULong(0) -- flags
packet:WriteGUID(guid) -- recv guid (nil)
packet:WriteULong(msgsz) -- message size + 1
packet:WriteString(msg) -- message
packet:WriteUByte(0) -- chat tag
GetGuildById(guild):SendPacket(packet)
end
local function start()
bot = irc.new(config.user)
bot:hook("OnDisconnect", function(message, errorOccurred)
reg = false
for key, value in pairs(events) do
if type(value) == "function" then
value()
elseif value ~= nil then
RemoveEventById(value)
end
events[key] = nil
end
if errorOccurred then
CreateLuaEvent(start, 5000, 1)
end
end)
bot:hook("OnConnect", function()
if config.nickserv then bot:sendChat(config.nickserv.name, ("IDENTIFY %s"):format(config.nickserv.password)) end
events.main_loop = CreateLuaEvent(function(event, delay, repeats)
bot:think()
end, 500, 0)
events.keepalive = CreateLuaEvent(function(event, delay, repeats)
bot:send(("PING :%s"):format(config.user.nick))
end, 30000, 0)
-- events.packet_cancel = register_packet()
events.chat_cancel = register_chat()
events.login_cancel = register_login()
events.logout_cancel = register_logout()
end)
bot:hook("OnModeChange", function(user, target, modes)
local check_modes = ("+%s"):format(config.nickserv.password and "r" or config.connect_modes)
if (not reg) and target == config.user.nick and modes == check_modes then
reg = true
if config.modes then bot:setMode(config.modes) end
for k, channel in pairs(config.channels) do bot:join(channel) end
end
end)
bot:hook("OnJoin", function(user, channel)
local guild = config.guilds[channel]
if user.nick ~= config.user.nick and guild then
send_guild(guild, default_prefix(), ("%s has joined %s."):format(user.nick, channel))
end
end)
bot:hook("OnPart", function(user, channel)
local guild = config.guilds[channel]
if user.nick ~= config.user.nick and guild then
send_guild(guild, default_prefix(), ("%s has left %s."):format(user.nick, channel))
end
end)
bot:hook("OnQuitChannel", function(user, channel, msg)
local guild = config.guilds[channel]
if user.nick ~= config.user.nick and guild then
send_guild(guild, default_prefix(), ("%s has left %s. (Reason: %s)"):format(user.nick, channel, convert_mirc(msg)))
end
end)
bot:hook("OnChat", function(user, channel, message)
local guild = config.guilds[channel]
if guild then
local msg = string.gsub(message, "|", "||")
local pre = config.prefixes[user.nick]
if pre == nil then
pre = default_prefix()
msg = ("<%s> %s"):format(colorize(user.nick, 7), msg)
else
pre = colorize(pre.text, pre.color)
end
-- Convert mIRC codes
send_guild(guild, pre, convert_mirc(msg))
end
end)
bot:connect(config.connect)
end
RegisterServerEvent(11, function()
pcall(bot.disconnect)
end)
RegisterServerEvent(16, function()
pcall(bot.disconnect)
end)
CreateLuaEvent(start, 500, 1)
CREATE TABLE `irc_config` (
`nick` varchar(30) NOT NULL,
`username` varchar(32) NOT NULL,
`realname` varchar(255) NOT NULL,
`host` varchar(255) NOT NULL,
`port` smallint unsigned NOT NULL,
`secure` boolean NOT NULL DEFAULT 0,
`password` varchar(255),
`connect_modes` varchar(32) NOT NULL,
`add_modes` varchar(32),
`rem_modes` varchar(32),
`nickserv` varchar(30) NOT NULL DEFAULT 'NickServ',
`nickserv_password` varchar(32)
);
CREATE TABLE `irc_prefixes` (
`nick` varchar(30) NOT NULL DEFAULT '',
`prefix` varchar(32) NOT NULL,
`color` tinyint unsigned NOT NULL,
PRIMARY KEY (`nick`)
);
CREATE TABLE `irc_channels` (
`guildid` int(10) unsigned NOT NULL,
`channel` varchar(32) NOT NULL,
PRIMARY KEY (`guildid`),
UNIQUE KEY `channel` (`channel`)
);
diff --git a/handlers.lua b/handlers.lua
index cbd1c9e..8600bc4 100644
--- a/handlers.lua
+++ b/handlers.lua
@@ -54,6 +54,7 @@ handlers["QUIT"] = function(o, prefix, msg)
if o.track_users then
for channel, v in pairs(o.channels) do
v.users[user.nick] = nil
+ o:invoke("OnQuitChannel", channel, user, msg)
end
end
o:invoke("OnQuit", user, msg)
diff --git a/init.lua b/init.lua
index 99ae7f5..8c895d2 100644
--- a/init.lua
+++ b/init.lua
@@ -139,6 +139,8 @@ function meta_preconnect:connect(_host, _port)
self:think()
socket.select(nil, nil, 0.1) -- Sleep so that we don't eat CPU
until self.authed
+
+ self:invoke("OnConnect")
end
function meta:disconnect(message)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment