-
Notifications
You must be signed in to change notification settings - Fork 8
/
command.lua
174 lines (141 loc) · 4.29 KB
/
command.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
local error = error
local table = table
local type = type
local select = select
local pcall = pcall
local unpack = unpack
local assert = assert
local setmetatable = setmetatable
local setfenv = setfenv
local ipairs = ipairs
local format = string.format
module "ircbot"
local bot = _META
local argHandlers = {
string = function(expected, args)
if not args then
return nil, "arguments expected"
end
local t = {args:match(expected)}
if #t == 0 then
return nil, "invalid argument format"
end
return t
end;
number = function(expected, args)
if not args then
return nil, "arguments expected"
end
local t = {}
args:gsub("(%S+)", function(word) table.insert(t, word) end)
if expected > -1 and #t < expected then
return nil, ("got %d arguments, expected %d"):format(#t, expected)
end
return t
end;
}
function bot:registerCommand(plugin, names, tbl, errorlevel)
local function raise(message)
error(format("%s (in command \"%s\")", message, table.concat(names, ", ")), errorlevel + 2)
end
if type(tbl.callback) ~= "function" then
raise("callback is not a function")
end
tbl.admin = not not tbl.admin
tbl.help = tbl.help or "No description."
if tbl.expectedArgs then
tbl.ArgParser = argHandlers[type(tbl.expectedArgs)] or raise("\"expectedArgs\" is of unsupported type")
end
if tbl.blacklist and tbl.whitelist then
raise("commands can not have both a blacklist and whitelist")
end
local list = tbl.blacklist or tbl.whitelist
if list then
local newList = {}
for k, channel in ipairs(list) do
newList[channel] = true
end
tbl[tbl.blacklist and "blacklist" or "whitelist"] = newList
end
setmetatable(tbl, {__index = plugin})
setfenv(tbl.callback, tbl)
for k,name in ipairs(names) do
if name:find("%s") then
raise("command name can not contain whitespace")
end
plugin.commands[name] = tbl
end
end
local abort_uid = {}
--- Default command prefix for bots when not overriden by the bots configuration file or the plugin.
CommandPrefix = "!"
function bot:initCommandSystem(plugin)
local commands = plugin.commands
local config = self.config
local function report(user, channel, action)
self:log(("user '%s@%s' tried to %s (in %s)"):format(user.nick, user.host, action, channel))
end
plugin.CommandPrefix = plugin.CommandPrefix or config.CommandPrefix or CommandPrefix
local commandPattern = table.concat{"^", plugin.CommandPrefix, "(%S+)"}
self:hook("OnChat", plugin, function(user, channel, msg)
local cmdname = msg:match(commandPattern)
if not cmdname then return end
local cmd = commands[cmdname]
if not cmd then return end
local blacklist = cmd.blacklist
if blacklist and blacklist[channel] then return end
local whitelist = cmd.whitelist
if whitelist and not whitelist[channel] then return end
if cmd.admin == true and not self:isAdmin(user) then
if not config.ignore_lackofadmin_warnings then
report(user, channel, "run admin-only command " .. cmdname)
end
return
end
local function raise(err)
local errorMessage = ("Error in command \"%s\": %s"):format(cmdname, err)
self:log("[%s] %s", channel, errorMessage)
local redirect = config.redirect_errors
if redirect ~= true then
self:sendChat(type(redirect) == "string" and redirect or channel, errorMessage)
end
end
local args = msg:match("^%S+ (.+)$")
local argParser = cmd.ArgParser
if argParser then
local parsed, err = argParser(cmd.expectedArgs, args)
if not parsed then
return raise(err)
end
args = parsed
end
cmd.user, cmd.channel = user, channel
cmd.pm = channel == config.nick
cmd.reply = function(message, ...)
if type(message) ~= "string" then
error(("bad argument #1 to 'reply' (expected string, got %s)"):format(type(message)), 2)
end
message = ... and message:format(...) or message
self:sendChat(cmd.pm and user.nick or channel, message)
return message
end
cmd.raise = function(...)
cmd.reply(...)
error(abort_uid)
end
local succ, err
if type(args) == "table" then
succ, err = pcall(cmd.callback, unpack(args))
else
succ, err = pcall(cmd.callback, args)
end
if not succ and err ~= abort_uid then
return raise(err)
end
--signal to LuaIRC that this event was handled
return true
end)
end
function bot:shutdownCommandSystem(plugin)
self:unhook("OnChat", plugin)
end