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