hexchat-plugins/hexchat-cw1.lua

212 lines
7.0 KiB
Lua

local hexchat = hexchat
hexchat.register("rot13", "3.0.1", "rot13")
local rot13 = {}
for i = string.byte('a'), string.byte('m') do
local a, b = string.char(i), string.char(i+13)
local A, B = a:upper(), b:upper()
rot13[a] = b
rot13[b] = a
rot13[A] = B
rot13[B] = A
end
local function do_rot13(arg, arg_eol)
if not arg[3] then
hexchat.print("Usage: /" .. arg[1] .. " <reason> <content>")
return hexchat.EAT_ALL
end
hexchat.command("say " .. arg[2] .. "\x01CW1 " .. arg_eol[3]:gsub("[A-Za-z]", rot13) .. "\x01")
return hexchat.EAT_ALL
end
hexchat.hook_command("cw-rot13", do_rot13)
local function startswith(str1, str2)
return str1:sub(1, #str2) == str2
end
local function parsecw(msg)
local hidden = {}
msg = msg:gsub("()(\1([^\1]*)\1)()", function(start, ctcp, contents, finish)
if startswith(contents, "CW1 ") then
local cw = contents:sub(5)
hidden[#hidden + 1] = cw:gsub("[A-Za-z]", rot13)
return " [Hidden Text " .. #hidden .. "] "
end
return ctcp
end)
return msg, hidden
end
local invert_notice = false
local last_notice = false
local tunpack = unpack or table.unpack
local skip = false
local function mkparse(event, pos)
return function(word, attributes)
if skip then return end
if event:find("Notice$") then
if invert_notice then
word[pos] = '\1'.. word[pos]
if last_notice then
word[pos] = word[pos] .. '\1'
end
end
end
invert_notice = false
local old_msg = word[pos]
local hidden
word[pos], hidden = parsecw(word[pos])
if word[pos] ~= old_msg then
skip = true
hexchat.emit_print_attrs(attributes, event, tunpack(word))
for i, v in ipairs(hidden) do
hexchat.print("\00326*\tHidden Text " .. i .. "\3 > \8"..v.."\8 < (Copy and paste to expand)")
end
skip = false
return hexchat.EAT_ALL
end
end
end
local function hookparse(event, pos)
return hexchat.hook_print_attrs(event, mkparse(event, pos))
end
do
(function(f,...)return f(f,...) end)(function(f, a, b, ...)
if a then
hookparse(a, b)
return f(f, ...)
end
end,
"Channel Message", 2,
"Channel Msg Hilight", 2,
"Channel Notice", 3,
"Private Message", 2,
"Private Message to Dialog", 2,
"Notice", 2,
"Your Message", 2,
"Notice Send", 2,
"Message Send", 2,
nil)
end
-- from here on: 3.0.1 bugfix
-- TODO maybe move these to a separate plugin. (or integrate them in hexchat)
local function tooct(n)
return string.format("%o", n)
end
local function on_privmsg(word, word_eol, attrs)
-- fix up some PRIVMSGs, pass them on to our handlers above
local i_at = 0
for i,v in ipairs(word) do
if v == "PRIVMSG" then
i_at = i + 2
break
end
end
if i_at == 0 then return end
if word_eol[i_at]:sub(1, 2):find(":[-+]") and tooct(hexchat.props["flags"]):find("[4-7].$") then -- bleh
word_eol[i_at] = ":" .. word_eol[i_at]:sub(3)
end
if word_eol[i_at]:sub(1, 6) == ":\1CW1 " then
if not word_eol[i_at]:find("\1", 7, true) == #word_eol[i_at] then
return hexchat.EAT_NONE -- let hexchat handle it normally
end
local target = word[i_at - 1]
local source
if word[1]:sub(1,1) ~= "@" then
source = word[1]
else
source = word[2]
end
source = source:match("^:([^!]+)!") -- this seems easy, right?
local context = hexchat.find_context(hexchat.get_info("server"), target)
if context then
local old_ctx = hexchat.get_context()
local serv_id = hexchat.props["id"]
-- sanity check
if hexchat.set_context(context) and hexchat.props["id"] == serv_id then
if hexchat.props["type"] == 2 then
local prefix = ""
for user in hexchat.iterate("users") do
if user.nick == source then
prefix = user.prefix
end
end
-- TODO fix highlights
hexchat.emit_print_attrs(attrs, "Channel Message", source, word_eol[i_at]:sub(2), prefix)
return hexchat.EAT_HEXCHAT
elseif hexchat.props["type"] == 3 then
hexchat.emit_print_attrs(attrs, "Private Message to Dialog", source, word_eol[i_at]:sub(2))
return hexchat.EAT_HEXCHAT
end
end
-- assume it's a query, because usually you only get channel messages if you're in the channel
if not hexchat.set_context(old_ctx) then return end -- how did we get this far without segfaulting?
end
if hexchat.prefs["gui_autoopen_dialog"] then
hexchat.command("query -nofocus " .. target)
local context = hexchat.find_context(hexchat.get_info("server"), target)
if context then
local old_ctx = hexchat.get_context()
local serv_id = hexchat.props["id"]
-- sanity check
if hexchat.set_context(context) and hexchat.props["id"] == serv_id then
-- meh, go hardmode on this (this shouldn't happen unless find_context returns the server context for some reason)
if hexchat.props["type"] ~= 3 then
local found = false
for chan in hexchat.iterate("channels") do
if chan.id == serv_id and chan.type == 3 and chan.channel == source then
found = true
hexchat.set_context(chan.context)
end
end
-- still not found? ragequit!
if not found then return hexchat.EAT_HEXCHAT end
end
hexchat.emit_print_attrs(attrs, "Private Message to Dialog", source, word_eol[i_at]:sub(2))
end
end
return hexchat.EAT_HEXCHAT
end
hexchat.emit_print_attrs(attrs, "Private Message", source, word_eol[i_at]:sub(2))
return hexchat.EAT_HEXCHAT
end
end
local function on_notice(word, word_eol, attrs) -- this one is much simpler
local i_at = 0
for i,v in ipairs(word) do
if v == "NOTICE" then
i_at = i + 2
break
end
end
if i_at == 0 then return end
if word_eol[i_at]:sub(1, 2):find(":[-+]") and tooct(hexchat.props["flags"]):find("[4-7].$") then -- bleh
word_eol[i_at] = ":" .. word_eol[i_at]:sub(3)
end
if word_eol[i_at]:sub(1, 6) == ":\1CW1 " then
-- workaround
invert_notice = true
last_notice = word_eol[i_at]:sub(-1,-1) == "\1"
-- then just let hexchat handle it
end
end
hexchat.hook_server_attrs("PRIVMSG", on_privmsg)
hexchat.hook_server_attrs("NOTICE", on_notice)
hexchat.print("rot13 loaded") -- this was in 3.0.0 too