butler 1.8.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. data/CHANGELOG +40 -0
  2. data/README +9 -9
  3. data/Rakefile +15 -71
  4. data/bin/botcontrol +151 -146
  5. data/data/butler/dialogs/botcontrol.rb +8 -3
  6. data/data/butler/dialogs/create.rb +18 -18
  7. data/data/butler/dialogs/create_config.rb +8 -0
  8. data/data/butler/dialogs/en/create_config.yaml +2 -0
  9. data/data/butler/dialogs/en/list.yaml +2 -1
  10. data/data/butler/dialogs/info.rb +2 -2
  11. data/data/butler/dialogs/list.rb +13 -8
  12. data/data/butler/plugins/games/countdown.rb +41 -0
  13. data/data/butler/plugins/games/roll.rb +59 -0
  14. data/lib/access.rb +6 -107
  15. data/lib/access/admin.rb +3 -0
  16. data/lib/access/role.rb +37 -2
  17. data/lib/access/savable.rb +5 -0
  18. data/lib/access/user.rb +21 -2
  19. data/lib/access/yamlbase.rb +4 -0
  20. data/lib/butler.rb +4 -4
  21. data/lib/butler/bot.rb +13 -13
  22. data/lib/butler/irc/client.rb +10 -2
  23. data/lib/butler/irc/parser.rb +7 -2
  24. data/lib/butler/irc/parser/commands.rb +24 -7
  25. data/lib/butler/irc/parser/generic.rb +27 -315
  26. data/lib/butler/irc/parser/rfc2812.rb +328 -0
  27. data/lib/butler/irc/socket.rb +1 -1
  28. data/lib/butler/irc/user.rb +13 -0
  29. data/lib/butler/plugin.rb +1 -1
  30. data/lib/butler/plugin/configproxy.rb +4 -4
  31. data/lib/butler/plugins.rb +1 -1
  32. data/lib/butler/version.rb +1 -1
  33. data/lib/configuration.rb +22 -71
  34. data/lib/dialogline.rb +12 -0
  35. data/lib/event.rb +5 -2
  36. data/lib/installer.rb +52 -24
  37. data/lib/iterator.rb +17 -7
  38. data/lib/log.rb +32 -5
  39. data/lib/log/comfort.rb +33 -16
  40. data/lib/log/entry.rb +25 -5
  41. data/lib/log/fakeio.rb +1 -0
  42. data/lib/log/splitter.rb +6 -2
  43. data/lib/ostructfixed.rb +5 -0
  44. data/lib/ruby/exception/detailed.rb +3 -3
  45. data/lib/scheduler.rb +19 -4
  46. data/lib/scriptfile.rb +9 -2
  47. data/lib/string.rb +176 -0
  48. data/lib/string/ascii.rb +31 -0
  49. data/lib/string/mbencoded.rb +79 -0
  50. data/lib/string/sbencoded.rb +77 -0
  51. data/lib/string/utf8.rb +157 -0
  52. data/lib/templater.rb +68 -10
  53. data/lib/w3validator.rb +86 -0
  54. data/test/irc/serverlistings/test_rpl_hiddenhost.txt +60 -0
  55. data/test/test_access.rb +101 -0
  56. data/test/test_configuration.rb +63 -0
  57. metadata +19 -2
data/CHANGELOG CHANGED
@@ -1,4 +1,44 @@
1
1
  = Butler2
2
2
 
3
+ === 12th Oct, 2007
4
+ * Butler 1.8.1
5
+ * botcontrol
6
+ * New flag -l (lowercased L) overrides config and connects locally.
7
+ * Setup now allows to set botcontrol up for another user
8
+ * Fixed permissions of directories created for a user
9
+ * Log now uses logger instead of log_device, changes due to that in:
10
+ * lib/butler.rb
11
+ * lib/butler/bot.rb
12
+ * lib/butler/irc/socket.rb
13
+ * lib/butler/plugin.rb
14
+ * lib/irc/client.rb
15
+ * lib/log/comfort.rb
16
+ * lib/butler/irc/client.rb:
17
+ * Adapted to new Commands requiring specification of command-sets
18
+ * Added #load_command_set
19
+ * lib/butler/irc/parser/rfc2812.rb: Added, moved rfc2812 commands to it.
20
+ * lib/butler/irc/parser/generic.rb:
21
+ * moved rfc2812 commands to rfc2812.rb
22
+ * Added 396 RPL_HIDDENHOST
23
+ * lib/butler/irc/parser/commands.rb:
24
+ * Now loads only command-sets as specified
25
+ * Added #load, to post-load command-sets
26
+ * Added logging
27
+ * Added a warning if matching of a message fails
28
+ * lib/butler/irc/user.rb: Added #force_update.
29
+ * lib/butler/irc/parser.rb:
30
+ * Fixed logging of ParseErrors (forgot to initialize_details)
31
+ * Adapted to new Commands requiring specification of command-sets
32
+ * lib/configuration.rb: Changed separator from . to / to increase consistence.
33
+ * lib/log.rb: More documentation.
34
+ * lib/log/comfort.rb: Added #log_origin
35
+ * lib/log/entry.rb: Supports origin now.
36
+ * lib/butler.rb: Fixed a bug (::start wouldn't pass on the options param)
37
+ * lib/irc/client.rb: Now uses options[:server] if available
38
+ * lib/ruby/exception/detailed.rb: Hardened against misuse.
39
+ * lib/butler/irc/client.rb: Fixed a bug (forgot to include Log::Comfort)
40
+ * Rakefile: Added :website_docs task.
41
+ * README: updated.
42
+
3
43
  === 7th Oct, 2007
4
44
  * Initial release of Butler2. Butler 1.8.x series is the alpha series of Butler2.
data/README CHANGED
@@ -1,9 +1,9 @@
1
1
  = README for Butler2
2
2
 
3
3
  == Indexing
4
- Author: Stefan Rusterholz <apeiros@gmx.net>
5
- Version: 2.0.0
6
- Website: http://butler.rubyforge.org
4
+ * Author: Stefan Rusterholz <apeiros@gmx.net>
5
+ * Version: 2.0.0
6
+ * Website: http://butler.rubyforge.org
7
7
 
8
8
  == About
9
9
  Butler is an easy to use IRC bot, extensible via plugins, with a full
@@ -15,8 +15,8 @@ authorization system, a remote login server and thorough localization support.
15
15
  sudo botcontrol setup
16
16
 
17
17
  === From Tarball
18
- Download the latest release from
19
- cd butler2
18
+ Download the latest release from http://rubyforge.org/frs/?group_id=1349&release_id=15267
19
+ cd butler*
20
20
  sudo rake install
21
21
 
22
22
  === Notes
@@ -27,10 +27,10 @@ Botcontrol setup is only required once per user.
27
27
 
28
28
  == Synopsis
29
29
  botcontrol create butler
30
- botcontrol start butler
31
- botcontrol stop butler
32
- botcontrol list
33
- botcontrol delete butler
30
+ botcontrol start butler
31
+ botcontrol stop butler
32
+ botcontrol list
33
+ botcontrol delete butler
34
34
 
35
35
  == Links
36
36
  * Butlers home: http://butler.rubyforge.org
data/Rakefile CHANGED
@@ -84,7 +84,7 @@ GemSpec = Gem::Specification.new do |s|
84
84
  s.rdoc_options += RDOC_OPTS
85
85
  end
86
86
 
87
- Rake::RDocTask.new do |rdoc|
87
+ RDOC = Rake::RDocTask.new do |rdoc|
88
88
  rdoc.rdoc_dir = 'doc/rdoc'
89
89
  rdoc.options += RDOC_OPTS
90
90
  rdoc.main = "README"
@@ -111,6 +111,7 @@ end
111
111
  task :default => :install
112
112
  desc "Default task, will install butler from tarball"
113
113
 
114
+ desc 'Install butler from tarball'
114
115
  task :install do
115
116
  path = OpenStruct.new(
116
117
  :bin => Config::CONFIG["bindir"],
@@ -178,7 +179,6 @@ task :install do
178
179
 
179
180
  puts "Done."
180
181
  end
181
- desc 'Install butler from tarball'
182
182
 
183
183
  desc 'Release the website and new gem version'
184
184
  task :deploy => [:check_version, :website, :release] do
@@ -207,71 +207,6 @@ task :install_gem_nodoc => [:clean, :package] do
207
207
  sh "sudo gem install --no-rdoc --no-ri pkg/*.gem"
208
208
  end
209
209
 
210
- desc 'Generate plugins repository'
211
- task :generate_plugin_repository do
212
- fields = %w[PLUGIN REVISION VERSION AUTHOR DOWNLOAD SIZE]
213
- descriptions = Hash.new { |h,k| h[k] = {} }
214
- plugins = {}
215
- rm_r("web/compiled/downloads/plugins") if File.exist?("web/compiled/downloads/plugins")
216
- rm_r("web/compiled/repository/plugins") if File.exist?("web/compiled/repository/plugins")
217
- mkdir_p("web/compiled/downloads/plugins")
218
- mkdir_p("web/compiled/repository/plugins/descriptions")
219
- Dir.glob("data/plugins/**/*.rb") { |plugin|
220
- puts " - #{plugin}"
221
- begin
222
- yaml = YAML.load(ScriptFile.read(plugin))
223
- rescue => e
224
- puts e
225
- puts "failed to read data of #{plugin}, ignoring"
226
- next
227
- end
228
-
229
- unless yaml[:revision] && yaml[:revision][:plugin]
230
- puts "plugin #{plugin} does not have a plugin-revision, ignoring"
231
- next
232
- end
233
- unless yaml[:summary] && yaml[:summary]["en"]
234
- puts "plugin #{plugin} does not have a summary, ignoring"
235
- next
236
- end
237
-
238
- tbz = "web/compiled/downloads/plugins/#{plugin[13..-4]}.tgz"
239
- mkdir_p(File.dirname(tbz))
240
- begin
241
- sh %{ tar -czf #{tbz} #{plugin} }
242
- version = yaml[:about] && yaml[:about][:version]
243
- version = version[0,16] if version
244
- author = yaml[:about] && yaml[:about][:author]
245
- author = author[0,64] if author
246
- plugins[plugin] = {
247
- :plugin => plugin.sub(/\.rb$/,''),
248
- :revision => Integer(yaml[:revision][:plugin]),
249
- :version => version,
250
- :author => author,
251
- :download => "/downloads/plugins/#{plugin}.tgz",
252
- :size => File.size(tbz)
253
- }
254
- yaml[:summary].each { |k,v|
255
- descriptions[k][plugin] = v[0,128]
256
- }
257
- rescue => e
258
- puts e
259
- puts "plugin #{plugin} had an error, ignoring"
260
- plugins.delete(plugin)
261
- descriptions.each_value { |v| v.delete(plugin) }
262
- end
263
- }
264
- descriptions.reject! { |k,v| v.empty? }
265
- File.open("web/compiled/repository/plugins/list.yaml", "w") { |fh|
266
- fh.write(plugins.to_yaml)
267
- }
268
- descriptions.each { |k,v|
269
- dir = "web/compiled/repository/plugins/"+k
270
- mkdir(dir)
271
- File.open(dir+"/summaries.yaml", "w") { |fh| fh.write(v.to_yaml) }
272
- }
273
- end
274
-
275
210
  desc 'Generate website files'
276
211
  task :website_generate do
277
212
  cd "web" do
@@ -279,9 +214,19 @@ task :website_generate do
279
214
  end
280
215
  end
281
216
 
282
- # WARNING, this task is only intended for use on the authors system
283
- task :update_plugins do
284
- puts "This has been moved to botcontrol sync_plugins"
217
+ desc 'Validate website'
218
+ task :website_validate => :website_generate do
219
+ require 'w3validator'
220
+ validator = W3Validator.new("web/compiled/**/*.html")
221
+ unless validator.validate_changed("web/validation.cache") { |file, valid| puts "Invalid: #{file}" unless valid } then
222
+ raise "Website did not validate, aborting task"
223
+ end
224
+ validator.cache("web/validation.cache")
225
+ end
226
+
227
+ desc 'Create docs for the website'
228
+ task :website_docs => :rdoc do
229
+ mv(RDOC.rdoc_dir, "web/compiled/docs")
285
230
  end
286
231
 
287
232
  desc 'Upload website files to rubyforge'
@@ -293,7 +238,6 @@ task :website_upload do
293
238
  end
294
239
 
295
240
  desc 'Generate and upload website files'
296
- #, :generate_plugin_repository
297
241
  task :website => [:website_generate, :website_upload] # , :publish_docs
298
242
 
299
243
  desc 'Package and upload the release to rubyforge.'
@@ -40,14 +40,6 @@ rescue Errno::EACCES
40
40
  puts "Can't create initial configuration, you should run #{$0} with sudo."
41
41
  exit
42
42
  end
43
- begin
44
- botcontrol.configure_user unless botcontrol.configured?
45
- rescue Errno::EACCES
46
- puts "Can't configure for '#{botcontrol.user}', you should run #{$0} with sudo."
47
- exit
48
- end
49
- Butler.path = botcontrol.butler_path
50
-
51
43
 
52
44
  options = {}
53
45
  options["backup"] = CLOptions.new("[botname] [backupname] [directory]")
@@ -80,151 +72,164 @@ options["start"] = CLOptions.new("[botname]") {
80
72
  o '-n', '--nick', 'NICK', :nick, "Use NICK instead of configured"
81
73
  o '-p', '--port', 'PORT', :port, "Connect at PORT instead of configured"
82
74
  o '-r', '--remote', 'PORT', :remote_port, "Start remote control server and bind to PORT"
75
+ o '-l', '--local', nil, :local, "Don't connect to configured server:port but to 127.0.0.1:6667"
83
76
  o '-s', '--server', 'SERVER', :server, "Connect to SERVER instead of the configured."
84
77
  o '-w', '--warnings', "Will enable warnings on stderr."
85
78
  }
79
+ options["setup"] = CLOptions.new("[user]")
86
80
  options["stop"] = CLOptions.new("[botname]")
87
81
  options["sync_plugins"] = CLOptions.new("[botname] [user]")
88
82
  options.each { |name, opt| opt.application_name "#{File.basename($0)} #{name}" }
89
83
 
90
-
91
- if %w(-v --version).include?(ARGV[0]) then
92
- puts Butler::VERSION::STRING
93
- elsif ARGV[0] then
94
- command = ARGV.shift.downcase
95
- opt = options[command].parse if options[command]
96
- case command
97
- when "backup"
98
- botcontrol.discuss("backup", false,
99
- :bot => opt.argv.botname,
100
- :name => opt.argv.backupname,
101
- :dir => opt.argv.directory,
102
- :default_name => opt.argv.botname ? "#{opt.argv.botname}.bak" : nil,
103
- :default_dir => user_config.backups
104
- )
105
-
106
- when "config"
107
- botcontrol.discuss("config", false,
108
- :botname => opt.argv.botname
109
- )
110
-
111
- when "create"
112
- botcontrol.discuss("create", false, :name => opt.argv.botname)
113
-
114
- when "delete"
115
- botcontrol.discuss("delete", false, :name => opt.argv.botname)
116
-
117
- when "help"
118
- botcontrol.discuss("help", false,
119
- :command => opt.argv.command,
120
- :options => options
121
- )
122
-
123
- when "info"
124
- botcontrol.discuss("info", false, :user => opt.argv.user)
125
-
126
- when "log"
127
- if opt[:help] then
128
- puts opt.options.help
129
- exit
130
- end
131
-
132
- botname = opt.argv.botname
133
- p filename = Butler::Bot.new(nil, botname).path.log+'/error.log'
134
- logfile = Log::FileReader.new(filename)
135
- filters = []
136
-
137
- if opt[:grep] then
138
- regexp = Regexp.new(opt[:grep])
139
- filters << "matching #{regexp.inspect}"
140
- logfile.add_filter(:grep, regexp)
141
- end
142
- if opt[:no_grep] then
143
- regexp = Regexp.new(opt[:no_grep])
144
- filters << "not matching #{regexp.inspect}"
145
- logfile.add_filter(:no_grep, regexp)
146
- end
147
- if opt[:find] then
148
- filters << "containing #{opt[:find].inspect}"
149
- logfile.add_filter(:find, opt[:find])
150
- end
151
- if opt[:no_find] then
152
- filters << "not containing #{opt[:no_find].inspect}"
153
- logfile.add_filter(:no_find, opt[:no_find])
154
- end
155
- if opt[:start_date] then
156
- start_date = Time.parse(opt[:start_date])
157
- filters << "after #{start_date.strftime('%F %T')}"
158
- logfile.add_filter(:start_date, start_date)
159
- end
160
- if opt[:end_date] then
161
- end_date = Time.parse(opt[:end_date])
162
- filters << "before #{end_date.strftime('%F %T')}"
163
- logfile.add_filter(:end_date, end_date)
164
- end
165
- if opt[:level] then
166
- level = opt[:level]
167
- filters << "of level #{level[0..-2].join(', ')}#{' or ' if level.size > 1}#{level.last}"
168
- logfile.add_filter(:one_of_levels, level.map { |l| l.to_sym })
169
- end
170
- if opt[:no_level] then
171
- level = opt[:no_level]
172
- filters << "not of level #{level[0..-2].join(', ')}#{' or ' if level.size > 1}#{level.last}"
173
- logfile.add_filter(:none_of_levels, level.map { |l| l.to_sym })
174
- end
175
-
176
- abbrname = filename.count('/') > 3 ? '...'+filename[%r{(?:/[^/]+){3}$}] : filename
177
- if opt[:head] then
178
- print "First #{opt[:head]} entries in #{abbrname} "
179
- elsif opt[:tail] then
180
- print "Last #{opt[:tail]} entries in #{abbrname} "
181
- else
182
- print "Entries in #{filename} "
183
- end
184
-
185
- puts("#{filters[0..-2].join(', ')}#{' and ' if filters.size > 1}#{filters.last}")
186
- if opt[:head] then
187
- logfile.head(Integer(opt[:head])) { |entry| puts entry }
188
- elsif opt[:tail] then
189
- logfile.tail(Integer(opt[:tail])) { |entry| puts entry }
190
- else
191
- logfile.each { |entry| puts entry }
192
- end
193
-
194
- when "list"
195
- botcontrol.discuss("list", false, :user => opt.argv.user)
196
-
197
- when "rename"
198
- botcontrol.discuss("rename", false,
199
- :botname => opt.argv.botname,
200
- :newname => opt.argv.newname
201
- )
84
+ command = ARGV.shift.downcase
85
+ opt = options[command].parse if options[command]
86
+
87
+ case command
88
+ when nil
89
+ botcontrol.discuss("create_config", false, :user => nil)
90
+ botcontrol.discuss("interactive")
91
+
92
+ when "backup"
93
+ botcontrol.discuss("create_config", false, :user => nil)
94
+ botcontrol.discuss("backup", false,
95
+ :bot => opt.argv.botname,
96
+ :name => opt.argv.backupname,
97
+ :dir => opt.argv.directory,
98
+ :default_name => opt.argv.botname ? "#{opt.argv.botname}.bak" : nil,
99
+ :default_dir => user_config.backups
100
+ )
101
+
102
+ when "config"
103
+ botcontrol.discuss("create_config", false, :user => nil)
104
+ botcontrol.discuss("config", false,
105
+ :botname => opt.argv.botname
106
+ )
107
+
108
+ when "create"
109
+ botcontrol.discuss("create_config", false, :user => nil)
110
+ botcontrol.discuss("create", false, :name => opt.argv.botname)
111
+
112
+ when "delete"
113
+ botcontrol.discuss("create_config", false, :user => nil)
114
+ botcontrol.discuss("delete", false, :name => opt.argv.botname)
115
+
116
+ when "help"
117
+ botcontrol.discuss("help", false,
118
+ :command => opt.argv.command,
119
+ :options => options
120
+ )
121
+
122
+ when "info"
123
+ botcontrol.discuss("info", false, :user => opt.argv.user)
202
124
 
203
- when "setup"
204
- # prompt to delete old config and create a new one
205
-
206
- when "start"
207
- botname = botcontrol.discuss(:start, false, :botname => opt.argv.botname)[:botname]
208
- options = {:daemonize => !opt["-i"]}
209
- Butler.start(nil, botname, options)
210
-
211
- when "stop"
212
- botname = opt.argv.botname || botcontrol.discuss(:selectbot, false)[:botname]
213
- Butler.stop(nil, botname)
214
-
215
- when "sync_plugins"
216
- botcontrol.discuss("sync_plugins", false,
217
- :user => opt.argv.user,
218
- :path => botcontrol.user_config(opt.argv.user),
219
- :botname => opt.argv.botname
220
- )
221
-
222
- when "uninstall"
223
- botcontrol.discuss("uninstall", false, :path => path, :config => config)
224
-
125
+ when "log"
126
+ botcontrol.discuss("create_config", false, :user => nil)
127
+ if opt[:help] then
128
+ puts opt.options.help
129
+ exit
130
+ end
131
+
132
+ botname = opt.argv.botname
133
+ filename = Butler::Bot.new(nil, botname).path.log+'/error.log'
134
+ logfile = Log::FileReader.new(filename)
135
+ filters = []
136
+
137
+ if opt[:grep] then
138
+ regexp = Regexp.new(opt[:grep])
139
+ filters << "matching #{regexp.inspect}"
140
+ logfile.add_filter(:grep, regexp)
141
+ end
142
+ if opt[:no_grep] then
143
+ regexp = Regexp.new(opt[:no_grep])
144
+ filters << "not matching #{regexp.inspect}"
145
+ logfile.add_filter(:no_grep, regexp)
146
+ end
147
+ if opt[:find] then
148
+ filters << "containing #{opt[:find].inspect}"
149
+ logfile.add_filter(:find, opt[:find])
150
+ end
151
+ if opt[:no_find] then
152
+ filters << "not containing #{opt[:no_find].inspect}"
153
+ logfile.add_filter(:no_find, opt[:no_find])
154
+ end
155
+ if opt[:start_date] then
156
+ start_date = Time.parse(opt[:start_date])
157
+ filters << "after #{start_date.strftime('%F %T')}"
158
+ logfile.add_filter(:start_date, start_date)
159
+ end
160
+ if opt[:end_date] then
161
+ end_date = Time.parse(opt[:end_date])
162
+ filters << "before #{end_date.strftime('%F %T')}"
163
+ logfile.add_filter(:end_date, end_date)
164
+ end
165
+ if opt[:level] then
166
+ level = opt[:level]
167
+ filters << "of level #{level[0..-2].join(', ')}#{' or ' if level.size > 1}#{level.last}"
168
+ logfile.add_filter(:one_of_levels, level.map { |l| l.to_sym })
169
+ end
170
+ if opt[:no_level] then
171
+ level = opt[:no_level]
172
+ filters << "not of level #{level[0..-2].join(', ')}#{' or ' if level.size > 1}#{level.last}"
173
+ logfile.add_filter(:none_of_levels, level.map { |l| l.to_sym })
174
+ end
175
+
176
+ abbrname = filename.count('/') > 3 ? '...'+filename[%r{(?:/[^/]+){3}$}] : filename
177
+ if opt[:head] then
178
+ print "First #{opt[:head]} entries in #{abbrname} "
179
+ elsif opt[:tail] then
180
+ print "Last #{opt[:tail]} entries in #{abbrname} "
181
+ else
182
+ print "Entries in #{filename} "
183
+ end
184
+
185
+ puts("#{filters[0..-2].join(', ')}#{' and ' if filters.size > 1}#{filters.last}")
186
+ if opt[:head] then
187
+ logfile.head(Integer(opt[:head])) { |entry| puts entry }
188
+ elsif opt[:tail] then
189
+ logfile.tail(Integer(opt[:tail])) { |entry| puts entry }
225
190
  else
226
- botcontrol.discuss("unknown_command", false, :command => command)
227
- end
228
- else
229
- botcontrol.discuss("interactive")
191
+ logfile.each { |entry| puts entry }
192
+ end
193
+
194
+ when "list"
195
+ botcontrol.discuss("list", false, :user => opt.argv.user)
196
+
197
+ when "rename"
198
+ botcontrol.discuss("create_config", false, :user => nil)
199
+ botcontrol.discuss("rename", false,
200
+ :botname => opt.argv.botname,
201
+ :newname => opt.argv.newname
202
+ )
203
+
204
+ when "setup"
205
+ botcontrol.discuss("create_config", false, :user => opt.argv.user)
206
+
207
+ when "start"
208
+ botcontrol.discuss("create_config", false, :user => nil)
209
+ botname = botcontrol.discuss(:start, false, :botname => opt.argv.botname)[:botname]
210
+ options = {:daemonize => !opt["-i"]}
211
+ if opt[:local] then
212
+ options[:server] = "127.0.0.1"
213
+ options[:port] = 6667
214
+ end
215
+ Butler.start(nil, botname, options)
216
+
217
+ when "stop"
218
+ botcontrol.discuss("create_config", false, :user => nil)
219
+ botname = opt.argv.botname || botcontrol.discuss(:selectbot, false)[:botname]
220
+ Butler.stop(nil, botname)
221
+
222
+ when "sync_plugins"
223
+ botcontrol.discuss("create_config", false, :user => opt.argv.user)
224
+ botcontrol.discuss("sync_plugins", false,
225
+ :user => opt.argv.user,
226
+ :path => botcontrol.user_config(opt.argv.user),
227
+ :botname => opt.argv.botname
228
+ )
229
+
230
+ when "uninstall"
231
+ botcontrol.discuss("uninstall", false, :path => path, :config => config)
232
+
233
+ else
234
+ botcontrol.discuss("unknown_command", false, :command => command)
230
235
  end