4 # :title: rbot config management from IRC
\r
6 # Author:: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>
\r
7 # Copyright:: (C) 2006,2007 Giuseppe Bilotta
\r
10 class ConfigModule < CoreBotModule
\r
13 _("I'm a v. %{version} rubybot%{copyright}%{url}") % {
\r
14 :version => $version,
\r
15 :copyright => ", #{Irc::Bot::COPYRIGHT_NOTICE}",
\r
16 :url => " - #{Irc::Bot::SOURCE_URL}"
\r
24 def handle_list(m, params)
\r
27 @bot.config.items.each_key do |key|
\r
28 mod, name = key.to_s.split('.')
\r
29 next unless mod == params[:module]
\r
30 modules.push key unless modules.include?(name)
\r
33 m.reply _("no such module %{module}") % {:module => params[:module]}
\r
35 m.reply modules.join(", ")
\r
38 @bot.config.items.each_key do |key|
\r
39 name = key.to_s.split('.').first
\r
40 modules.push name unless modules.include?(name)
\r
42 m.reply "modules: " + modules.join(", ")
\r
46 def handle_get(m, params)
\r
47 key = params[:key].to_s.intern
\r
48 unless @bot.config.items.has_key?(key)
\r
49 m.reply _("no such config key %{key}") % {:key => key}
\r
52 return if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto)
\r
53 value = @bot.config.items[key].to_s
\r
54 m.reply "#{key}: #{value}"
\r
57 def handle_desc(m, params)
\r
58 key = params[:key].to_s.intern
\r
59 unless @bot.config.items.has_key?(key)
\r
60 m.reply _("no such config key %{key}") % {:key => key}
\r
62 m.reply "#{key}: #{@bot.config.items[key].desc}"
\r
65 def handle_search(m, params)
\r
66 rx = Regexp.new(params[:rx].to_s, true)
\r
68 @bot.config.items.each do |k, v|
\r
69 cfs << v if k.to_s.match(rx) or (v.desc.match(rx) rescue false)
\r
72 m.reply _("no config key found matching %{r}") % { :r => params[:rx].to_s}
\r
74 m.reply _("possible keys: %{kl}") % { :kl => cfs.map { |c| c.key}.join(', ') }
\r
75 m.reply cfs.map { |c| [c.key, c.desc].join(': ') }.join("\n")
\r
79 def handle_unset(m, params)
\r
80 key = params[:key].to_s.intern
\r
81 unless @bot.config.items.has_key?(key)
\r
82 m.reply _("no such config key %{key}") % {:key => key}
\r
84 return if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto)
\r
85 @bot.config.items[key].unset
\r
86 handle_get(m, params)
\r
87 m.reply _("this config change will take effect on the next restart") if @bot.config.items[key].requires_restart
\r
88 m.reply _("this config change will take effect on the next rescan") if @bot.config.items[key].requires_rescan
\r
91 def handle_set(m, params)
\r
92 key = params[:key].to_s.intern
\r
93 value = params[:value].join(" ")
\r
94 unless @bot.config.items.has_key?(key)
\r
95 m.reply _("no such config key %{key}") % {:key => key} unless params[:silent]
\r
98 return false if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto)
\r
100 @bot.config.items[key].set_string(value)
\r
101 rescue ArgumentError => e
\r
102 m.reply _("failed to set %{key}: %{error}") % {:key => key, :error => e.message} unless params[:silent]
\r
105 if @bot.config.items[key].requires_restart
\r
106 m.reply _("this config change will take effect on the next restart") unless params[:silent]
\r
108 elsif @bot.config.items[key].requires_rescan
\r
109 m.reply _("this config change will take effect on the next rescan") unless params[:silent]
\r
112 m.okay unless params[:silent]
\r
117 def handle_add(m, params)
\r
118 key = params[:key].to_s.intern
\r
119 value = params[:value]
\r
120 unless @bot.config.items.has_key?(key)
\r
121 m.reply _("no such config key %{key}") % {:key => key}
\r
124 unless @bot.config.items[key].kind_of?(Config::ArrayValue)
\r
125 m.reply _("config key %{key} is not an array") % {:key => key}
\r
128 return if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto)
\r
130 @bot.config.items[key].add(value)
\r
131 rescue ArgumentError => e
\r
132 m.reply _("failed to add %{value} to %{key}: %{error}") % {:value => value, :key => key, :error => e.message}
\r
135 handle_get(m,{:key => key})
\r
136 m.reply _("this config change will take effect on the next restart") if @bot.config.items[key].requires_restart
\r
137 m.reply _("this config change will take effect on the next rescan") if @bot.config.items[key].requires_rescan
\r
140 def handle_rm(m, params)
\r
141 key = params[:key].to_s.intern
\r
142 value = params[:value]
\r
143 unless @bot.config.items.has_key?(key)
\r
144 m.reply _("no such config key %{key}") % {:key => key}
\r
147 unless @bot.config.items[key].kind_of?(Config::ArrayValue)
\r
148 m.reply _("config key %{key} is not an array") % {:key => key}
\r
151 return if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto)
\r
153 @bot.config.items[key].rm(value)
\r
154 rescue ArgumentError => e
\r
155 m.reply _("failed to remove %{value} from %{key}: %{error}") % {:value => value, :key => key, :error => e.message}
\r
158 handle_get(m,{:key => key})
\r
159 m.reply _("this config change will take effect on the next restart") if @bot.config.items[key].requires_restart
\r
160 m.reply _("this config change will take effect on the next rescan") if @bot.config.items[key].requires_rescan
\r
163 def bot_save(m, param)
\r
168 def bot_rescan(m, param)
\r
169 m.reply _("saving ...")
\r
171 m.reply _("rescanning ...")
\r
173 m.reply _("done. %{plugin_status}") % {:plugin_status => @bot.plugins.status(true)}
\r
176 def bot_nick(m, param)
\r
177 @bot.nickchg(param[:nick])
\r
180 def bot_status(m, param)
\r
181 m.reply @bot.status
\r
184 # TODO is this one of the methods that disappeared when the bot was moved
\r
185 # from the single-file to the multi-file registry?
\r
187 # def bot_reg_stat(m, param)
\r
188 # m.reply @registry.stat.inspect
\r
191 def bot_version(m, param)
\r
192 m.reply version_string
\r
196 who = m.private? ? "me" : m.target
\r
199 m.ctcp_reply version_string
\r
200 @bot.irclog "@ #{m.source} asked #{who} about version info"
\r
202 m.ctcp_reply Irc::Bot::SOURCE_URL
\r
203 @bot.irclog "@ #{m.source} asked #{who} about source info"
\r
207 def handle_help(m, params)
\r
208 m.reply help(params[:topic])
\r
211 def help(plugin, topic="")
\r
216 _("config list => list configuration modules, config list <module> => list configuration keys for module <module>")
\r
218 _("config get <key> => get configuration value for key <key>")
\r
220 _("reset key <key> to the default")
\r
222 _("config set <key> <value> => set configuration value for key <key> to <value>")
\r
224 _("config desc <key> => describe what key <key> configures")
\r
226 _("config add <value> to <key> => add value <value> to key <key> if <key> is an array")
\r
228 _("config rm <value> from <key> => remove value <value> from key <key> if <key> is an array")
\r
230 _("config module - bot configuration. usage: list, desc, get, set, unset, add, rm")
\r
232 # "no help for config #{topic}"
\r
235 _("nick <newnick> => change the bot nick to <newnick>, if possible")
\r
237 _("status => display some information on the bot's status")
\r
239 _("save => save current dynamic data and configuration")
\r
241 _("rescan => reload modules and static facts")
\r
243 _("version => describes software version")
\r
245 _("config-related tasks: config, save, rescan, version, nick, status")
\r
251 conf = ConfigModule.new
\r
253 conf.map 'config list :module',
\r
254 :action => 'handle_list',
\r
255 :defaults => {:module => false},
\r
256 :auth_path => 'show'
\r
257 # TODO this one is presently a security risk, since the bot
\r
258 # stores the master password in the config. Do we need auth levels
\r
259 # on the Bot::Config keys too?
\r
260 conf.map 'config get :key',
\r
261 :action => 'handle_get',
\r
262 :auth_path => 'show'
\r
263 conf.map 'config desc :key',
\r
264 :action => 'handle_desc',
\r
265 :auth_path => 'show'
\r
266 conf.map 'config describe :key',
\r
267 :action => 'handle_desc',
\r
268 :auth_path => 'show::desc!'
\r
269 conf.map 'config search *rx',
\r
270 :action => 'handle_search',
\r
271 :auth_path => 'show'
\r
274 :action => 'bot_save'
\r
276 :action => 'bot_rescan'
\r
277 conf.map "nick :nick",
\r
278 :action => 'bot_nick'
\r
280 :action => 'bot_status',
\r
281 :auth_path => 'show::status'
\r
284 # conf.map "registry stats",
\r
285 # :action => 'bot_reg_stat',
\r
286 # :auth_path => '!config::status'
\r
287 conf.map "version",
\r
288 :action => 'bot_version',
\r
289 :auth_path => 'show::status'
\r
291 conf.map 'config set :key *value',
\r
292 :action => 'handle_set',
\r
293 :auth_path => 'edit'
\r
294 conf.map 'config add :value to :key',
\r
295 :action => 'handle_add',
\r
296 :auth_path => 'edit'
\r
297 conf.map 'config rm :value from :key',
\r
298 :action => 'handle_rm',
\r
299 :auth_path => 'edit'
\r
300 conf.map 'config del :value from :key',
\r
301 :action => 'handle_rm',
\r
302 :auth_path => 'edit'
\r
303 conf.map 'config delete :value from :key',
\r
304 :action => 'handle_rm',
\r
305 :auth_path => 'edit'
\r
306 conf.map 'config unset :key',
\r
307 :action => 'handle_unset',
\r
308 :auth_path => 'edit'
\r
309 conf.map 'config reset :key',
\r
310 :action => 'handle_unset',
\r
311 :auth_path => 'edit'
\r
313 conf.map 'config help :topic',
\r
314 :action => 'handle_help',
\r
315 :defaults => {:topic => false},
\r
316 :auth_path => '!help!'
\r
318 conf.default_auth('*', false)
\r
319 conf.default_auth('show', true)
\r
320 conf.default_auth('show::get', false)
\r
321 # TODO these shouldn't be set here, we need a way to let the default
\r
322 # permission be specified together with the ConfigValue
\r
323 conf.default_auth('key', true)
\r
324 conf.default_auth('key::auth::password', false)
\r