]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - lib/rbot/core/config.rb
Unixify all line endings.
[user/henk/code/ruby/rbot.git] / lib / rbot / core / config.rb
1 #-- vim:sw=2:et
2 #++
3 #
4 # :title: rbot config management from IRC
5 #
6 # Author:: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>
7 # Copyright:: (C) 2006,2007 Giuseppe Bilotta
8 # License:: GPL v2
9
10 class ConfigModule < CoreBotModule
11
12   def version_string
13     _("I'm a v. %{version} rubybot%{copyright}%{url}") % {
14       :version => $version,
15       :copyright => ", #{Irc::Bot::COPYRIGHT_NOTICE}",
16       :url => " - #{Irc::Bot::SOURCE_URL}"
17     }
18   end
19
20   def save
21     @bot.config.save
22   end
23
24   def handle_list(m, params)
25     modules = []
26     if params[:module]
27       @bot.config.items.each_key do |key|
28         mod, name = key.to_s.split('.')
29         next unless mod == params[:module]
30         modules.push key unless modules.include?(name)
31       end
32       if modules.empty?
33         m.reply _("no such module %{module}") % {:module => params[:module]}
34       else
35         m.reply modules.join(", ")
36       end
37     else
38       @bot.config.items.each_key do |key|
39         name = key.to_s.split('.').first
40         modules.push name unless modules.include?(name)
41       end
42       m.reply "modules: " + modules.join(", ")
43     end
44   end
45
46   def handle_get(m, params)
47     key = params[:key].to_s.intern
48     unless @bot.config.items.has_key?(key)
49       m.reply _("no such config key %{key}") % {:key => key}
50       return
51     end
52     return if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto)
53     value = @bot.config.items[key].to_s
54     m.reply "#{key}: #{value}"
55   end
56
57   def handle_desc(m, params)
58     key = params[:key].to_s.intern
59     unless @bot.config.items.has_key?(key)
60       m.reply _("no such config key %{key}") % {:key => key}
61     end
62     m.reply "#{key}: #{@bot.config.items[key].desc}"
63   end
64
65   def handle_search(m, params)
66     rx = Regexp.new(params[:rx].to_s, true)
67     cfs = []
68     @bot.config.items.each do |k, v|
69       cfs << v if k.to_s.match(rx) or (v.desc.match(rx) rescue false)
70     end
71     if cfs.empty?
72       m.reply _("no config key found matching %{r}") % { :r => params[:rx].to_s}
73     else
74       m.reply _("possible keys: %{kl}") % { :kl => cfs.map { |c| c.key}.join(', ') }
75       m.reply cfs.map { |c| [c.key, c.desc].join(': ') }.join("\n")
76     end
77   end
78
79   def handle_unset(m, params)
80     key = params[:key].to_s.intern
81     unless @bot.config.items.has_key?(key)
82       m.reply _("no such config key %{key}") % {:key => key}
83     end
84     return if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto)
85     @bot.config.items[key].unset
86     handle_get(m, params)
87     m.reply _("this config change will take effect on the next restart") if @bot.config.items[key].requires_restart
88     m.reply _("this config change will take effect on the next rescan") if @bot.config.items[key].requires_rescan
89   end
90
91   def handle_set(m, params)
92     key = params[:key].to_s.intern
93     value = params[:value].join(" ")
94     unless @bot.config.items.has_key?(key)
95       m.reply _("no such config key %{key}") % {:key => key} unless params[:silent]
96       return false
97     end
98     return false if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto)
99     begin
100       @bot.config.items[key].set_string(value)
101     rescue ArgumentError => e
102       m.reply _("failed to set %{key}: %{error}") % {:key => key, :error => e.message} unless params[:silent]
103       return false
104     end
105     if @bot.config.items[key].requires_restart
106       m.reply _("this config change will take effect on the next restart") unless params[:silent]
107       return :restart
108     elsif @bot.config.items[key].requires_rescan
109       m.reply _("this config change will take effect on the next rescan") unless params[:silent]
110       return :rescan
111     else
112       m.okay unless params[:silent]
113       return true
114     end
115   end
116
117   def handle_add(m, params)
118     key = params[:key].to_s.intern
119     value = params[:value]
120     unless @bot.config.items.has_key?(key)
121       m.reply _("no such config key %{key}") % {:key => key}
122       return
123     end
124     unless @bot.config.items[key].kind_of?(Config::ArrayValue)
125       m.reply _("config key %{key} is not an array") % {:key => key}
126       return
127     end
128     return if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto)
129     begin
130       @bot.config.items[key].add(value)
131     rescue ArgumentError => e
132       m.reply _("failed to add %{value} to %{key}: %{error}") % {:value => value, :key => key, :error => e.message}
133       return
134     end
135     handle_get(m,{:key => key})
136     m.reply _("this config change will take effect on the next restart") if @bot.config.items[key].requires_restart
137     m.reply _("this config change will take effect on the next rescan") if @bot.config.items[key].requires_rescan
138   end
139
140   def handle_rm(m, params)
141     key = params[:key].to_s.intern
142     value = params[:value]
143     unless @bot.config.items.has_key?(key)
144       m.reply _("no such config key %{key}") % {:key => key}
145       return
146     end
147     unless @bot.config.items[key].kind_of?(Config::ArrayValue)
148       m.reply _("config key %{key} is not an array") % {:key => key}
149       return
150     end
151     return if !@bot.auth.allow?(@bot.config.items[key].auth_path, m.source, m.replyto)
152     begin
153       @bot.config.items[key].rm(value)
154     rescue ArgumentError => e
155       m.reply _("failed to remove %{value} from %{key}: %{error}") % {:value => value, :key => key, :error => e.message}
156       return
157     end
158     handle_get(m,{:key => key})
159     m.reply _("this config change will take effect on the next restart") if @bot.config.items[key].requires_restart
160     m.reply _("this config change will take effect on the next rescan") if @bot.config.items[key].requires_rescan
161   end
162
163   def bot_save(m, param)
164     @bot.save
165     m.okay
166   end
167
168   def bot_rescan(m, param)
169     m.reply _("saving ...")
170     @bot.save
171     m.reply _("rescanning ...")
172     @bot.rescan
173     m.reply _("done. %{plugin_status}") % {:plugin_status => @bot.plugins.status(true)}
174   end
175
176   def bot_nick(m, param)
177     @bot.nickchg(param[:nick])
178   end
179
180   def bot_status(m, param)
181     m.reply @bot.status
182   end
183
184   # TODO is this one of the methods that disappeared when the bot was moved
185   # from the single-file to the multi-file registry?
186   #
187   #  def bot_reg_stat(m, param)
188   #    m.reply @registry.stat.inspect
189   #  end
190
191   def bot_version(m, param)
192     m.reply version_string
193   end
194
195   def ctcp_listen(m)
196     who = m.private? ? "me" : m.target
197     case m.ctcp.intern
198     when :VERSION
199       m.ctcp_reply version_string
200       @bot.irclog "@ #{m.source} asked #{who} about version info"
201     when :SOURCE
202       m.ctcp_reply Irc::Bot::SOURCE_URL
203       @bot.irclog "@ #{m.source} asked #{who} about source info"
204     end
205   end
206
207   def handle_help(m, params)
208     m.reply help(params[:topic])
209   end
210
211   def help(plugin, topic="")
212     case plugin
213     when "config"
214       case topic
215       when "list"
216       _("config list => list configuration modules, config list <module> => list configuration keys for module <module>")
217       when "get"
218       _("config get <key> => get configuration value for key <key>")
219       when "unset"
220       _("reset key <key> to the default")
221       when "set"
222       _("config set <key> <value> => set configuration value for key <key> to <value>")
223       when "desc"
224       _("config desc <key> => describe what key <key> configures")
225       when "add"
226       _("config add <value> to <key> => add value <value> to key <key> if <key> is an array")
227       when "rm"
228       _("config rm <value> from <key> => remove value <value> from key <key> if <key> is an array")
229       else
230       _("config module - bot configuration. usage: list, desc, get, set, unset, add, rm")
231       # else
232       #   "no help for config #{topic}"
233       end
234     when "nick"
235       _("nick <newnick> => change the bot nick to <newnick>, if possible")
236     when "status"
237       _("status => display some information on the bot's status")
238     when "save"
239       _("save => save current dynamic data and configuration")
240     when "rescan"
241       _("rescan => reload modules and static facts")
242     when "version"
243       _("version => describes software version")
244     else
245       _("config-related tasks: config, save, rescan, version, nick, status")
246     end
247   end
248
249 end
250
251 conf = ConfigModule.new
252
253 conf.map 'config list :module',
254   :action => 'handle_list',
255   :defaults => {:module => false},
256   :auth_path => 'show'
257 # TODO this one is presently a security risk, since the bot
258 # stores the master password in the config. Do we need auth levels
259 # on the Bot::Config keys too?
260 conf.map 'config get :key',
261   :action => 'handle_get',
262   :auth_path => 'show'
263 conf.map 'config desc :key',
264   :action => 'handle_desc',
265   :auth_path => 'show'
266 conf.map 'config describe :key',
267   :action => 'handle_desc',
268   :auth_path => 'show::desc!'
269 conf.map 'config search *rx',
270   :action => 'handle_search',
271   :auth_path => 'show'
272
273 conf.map "save",
274   :action => 'bot_save'
275 conf.map "rescan",
276   :action => 'bot_rescan'
277 conf.map "nick :nick",
278   :action => 'bot_nick'
279 conf.map "status",
280   :action => 'bot_status',
281   :auth_path => 'show::status'
282 # TODO see above
283 #
284 # conf.map "registry stats",
285 #   :action => 'bot_reg_stat',
286 #   :auth_path => '!config::status'
287 conf.map "version",
288   :action => 'bot_version',
289   :auth_path => 'show::status'
290
291 conf.map 'config set :key *value',
292   :action => 'handle_set',
293   :auth_path => 'edit'
294 conf.map 'config add :value to :key',
295   :action => 'handle_add',
296   :auth_path => 'edit'
297 conf.map 'config rm :value from :key',
298   :action => 'handle_rm',
299   :auth_path => 'edit'
300 conf.map 'config del :value from :key',
301   :action => 'handle_rm',
302   :auth_path => 'edit'
303 conf.map 'config delete :value from :key',
304   :action => 'handle_rm',
305   :auth_path => 'edit'
306 conf.map 'config unset :key',
307   :action => 'handle_unset',
308   :auth_path => 'edit'
309 conf.map 'config reset :key',
310   :action => 'handle_unset',
311   :auth_path => 'edit'
312
313 conf.map 'config help :topic',
314   :action => 'handle_help',
315   :defaults => {:topic => false},
316   :auth_path => '!help!'
317
318 conf.default_auth('*', false)
319 conf.default_auth('show', true)
320 conf.default_auth('show::get', false)
321 # TODO these shouldn't be set here, we need a way to let the default
322 # permission be specified together with the ConfigValue
323 conf.default_auth('key', true)
324 conf.default_auth('key::auth::password', false)
325