rbot 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/AUTHORS +16 -0
  2. data/COPYING +21 -0
  3. data/ChangeLog +418 -0
  4. data/INSTALL +8 -0
  5. data/README +44 -0
  6. data/REQUIREMENTS +34 -0
  7. data/TODO +5 -0
  8. data/Usage_en.txt +129 -0
  9. data/bin/rbot +81 -0
  10. data/data/rbot/contrib/plugins/figlet.rb +20 -0
  11. data/data/rbot/contrib/plugins/ri.rb +83 -0
  12. data/data/rbot/contrib/plugins/stats.rb +232 -0
  13. data/data/rbot/contrib/plugins/vandale.rb +49 -0
  14. data/data/rbot/languages/dutch.lang +73 -0
  15. data/data/rbot/languages/english.lang +75 -0
  16. data/data/rbot/languages/french.lang +39 -0
  17. data/data/rbot/languages/german.lang +67 -0
  18. data/data/rbot/plugins/autoop.rb +68 -0
  19. data/data/rbot/plugins/autorejoin.rb +16 -0
  20. data/data/rbot/plugins/cal.rb +15 -0
  21. data/data/rbot/plugins/dice.rb +81 -0
  22. data/data/rbot/plugins/eightball.rb +19 -0
  23. data/data/rbot/plugins/excuse.rb +470 -0
  24. data/data/rbot/plugins/fish.rb +61 -0
  25. data/data/rbot/plugins/fortune.rb +22 -0
  26. data/data/rbot/plugins/freshmeat.rb +98 -0
  27. data/data/rbot/plugins/google.rb +51 -0
  28. data/data/rbot/plugins/host.rb +14 -0
  29. data/data/rbot/plugins/httpd.rb.disabled +35 -0
  30. data/data/rbot/plugins/insult.rb +258 -0
  31. data/data/rbot/plugins/karma.rb +85 -0
  32. data/data/rbot/plugins/lart.rb +181 -0
  33. data/data/rbot/plugins/math.rb +122 -0
  34. data/data/rbot/plugins/nickserv.rb +89 -0
  35. data/data/rbot/plugins/nslookup.rb +43 -0
  36. data/data/rbot/plugins/opme.rb +19 -0
  37. data/data/rbot/plugins/quakeauth.rb +51 -0
  38. data/data/rbot/plugins/quotes.rb +321 -0
  39. data/data/rbot/plugins/remind.rb +228 -0
  40. data/data/rbot/plugins/roshambo.rb +54 -0
  41. data/data/rbot/plugins/rot13.rb +10 -0
  42. data/data/rbot/plugins/roulette.rb +147 -0
  43. data/data/rbot/plugins/rss.rb.disabled +414 -0
  44. data/data/rbot/plugins/seen.rb +89 -0
  45. data/data/rbot/plugins/slashdot.rb +94 -0
  46. data/data/rbot/plugins/spell.rb +36 -0
  47. data/data/rbot/plugins/tube.rb +71 -0
  48. data/data/rbot/plugins/url.rb +88 -0
  49. data/data/rbot/plugins/weather.rb +649 -0
  50. data/data/rbot/plugins/wserver.rb +71 -0
  51. data/data/rbot/plugins/xmlrpc.rb.disabled +52 -0
  52. data/data/rbot/templates/keywords.rbot +4 -0
  53. data/data/rbot/templates/lart/larts +98 -0
  54. data/data/rbot/templates/lart/praises +5 -0
  55. data/data/rbot/templates/levels.rbot +30 -0
  56. data/data/rbot/templates/users.rbot +1 -0
  57. data/lib/rbot/auth.rb +203 -0
  58. data/lib/rbot/channel.rb +54 -0
  59. data/lib/rbot/config.rb +363 -0
  60. data/lib/rbot/dbhash.rb +112 -0
  61. data/lib/rbot/httputil.rb +141 -0
  62. data/lib/rbot/ircbot.rb +808 -0
  63. data/lib/rbot/ircsocket.rb +185 -0
  64. data/lib/rbot/keywords.rb +433 -0
  65. data/lib/rbot/language.rb +69 -0
  66. data/lib/rbot/message.rb +256 -0
  67. data/lib/rbot/messagemapper.rb +262 -0
  68. data/lib/rbot/plugins.rb +291 -0
  69. data/lib/rbot/post-install.rb +8 -0
  70. data/lib/rbot/rbotconfig.rb +36 -0
  71. data/lib/rbot/registry.rb +271 -0
  72. data/lib/rbot/rfc2812.rb +1104 -0
  73. data/lib/rbot/timer.rb +201 -0
  74. data/lib/rbot/utils.rb +83 -0
  75. data/setup.rb +1360 -0
  76. metadata +129 -0
data/INSTALL ADDED
@@ -0,0 +1,8 @@
1
+ Just run rbot, it'll ask you for any core information it needs before it can
2
+ start, after that you can configure everything else online using the config
3
+ module.
4
+
5
+ You can maintain multiple configurations at once. Start rbot with the
6
+ location you want it to store runtime data in. By default, running rbot
7
+ uses the ~/.rbot config directory. If you run 'rbot /path/to/foo', then the
8
+ configuration will be stored to and read from there instead.
data/README ADDED
@@ -0,0 +1,44 @@
1
+ rbot README
2
+ ===========
3
+
4
+ rbot is a ruby IRC bot. Think of him as a ruby bot framework with a highly
5
+ modular design based around plugins.
6
+
7
+ rbot features
8
+ =============
9
+
10
+ * Runtime configuration via irc chat
11
+ * User authentication and access levels for using different bot features
12
+ * Built in infobot-style keywords. See example session below.
13
+ * Support for underlying fact database (infobot fact files), which can
14
+ be overridden or supplemented by runtime keyword controls
15
+ * Multi-language support - comes with english, dutch and german definitions
16
+ so far - more translations welcome
17
+ * Powerful plugin architecture, comes with plugins for:
18
+ o DNS queries
19
+ o Babelfish translation
20
+ o Google searching
21
+ o Excuse generation
22
+ o Insult generation
23
+ o Karma
24
+ o Checking the weather
25
+ o Querying slashdot
26
+ o Doing Math
27
+ o Per-channel quote storage, searching and retrieval
28
+ o Reminders
29
+ o rot13 translation
30
+ o Check the spelling of a word
31
+ o Webserver Server: header examination
32
+ o RPG dice rolling
33
+ o larting people
34
+ o conversation stats
35
+ o more...
36
+
37
+ Thanks are owed to the infobot developers - several of rbot's features are
38
+ inspired by infobot and so are some of the default plugins. Thanks are also
39
+ owed to RADKade1, as rbot's quote plugin is a direct reimplementation of his
40
+ "quotesaq" - simply because it's a great quote interface.
41
+
42
+ Mainly, rbot's fun to play with, although the plugin architecture can be used
43
+ to write very useful modules
44
+
@@ -0,0 +1,34 @@
1
+ Ruby modules needed for rbot
2
+ ============================
3
+
4
+ Core requirements
5
+ bdb (berkley db) http://www.ruby-lang.org/en/raa-list.rhtml?name=bdb
6
+ (which requires libdb2 or better, from
7
+ www.sleepycat.com)
8
+ net/http 1.1+
9
+ socket
10
+ uri
11
+
12
+ Plugin requirements
13
+ (these are all optional, if you don't have them, the plugins just won't
14
+ function)
15
+
16
+ babelfish, wserver:
17
+ net/http 1.2+
18
+
19
+ slashdot, freshmeat, rss:
20
+ REXML
21
+
22
+ External programs needed for rbot
23
+ =================================
24
+
25
+ Plugin requirements
26
+ (These are all optional)
27
+
28
+ host plugin:
29
+ host(1)
30
+
31
+ spell plugin:
32
+ ispell(1)
33
+
34
+
data/TODO ADDED
@@ -0,0 +1,5 @@
1
+ o freeze/thaw factoids (make them readonly) at higher auth
2
+ o respond to insults
3
+ o feed back errors from plugins (optional)
4
+ o Allow users to leave messages to named users.
5
+ o wtf plugin (bsdgames)
@@ -0,0 +1,129 @@
1
+ Installing Programs with setup.rb
2
+ =================================
3
+
4
+ Quick Start
5
+ -----------
6
+
7
+ Type this (You might needs super user previledge):
8
+
9
+ ($ su)
10
+ # ruby setup.rb
11
+
12
+ If you want to install a program in to your home directory
13
+ ($HOME), use following instead:
14
+
15
+ $ ruby setup.rb all --prefix=$HOME
16
+
17
+
18
+ Detailed Installtion Process
19
+ ----------------------------
20
+
21
+ setup.rb invokes installation by three steps. There are
22
+ "config", "setup" and "install". You can invoke each steps
23
+ separately as following:
24
+
25
+ $ ruby setup.rb config
26
+ $ ruby setup.rb setup
27
+ # ruby setup.rb install
28
+
29
+ You can controll installation process by giving detailed
30
+ options for each tasks. For example, --bin-dir=$HOME/bin
31
+ let setup.rb install commands in $HOME/bin.
32
+
33
+ For details, see "Task Options".
34
+
35
+ Global Options
36
+ --------------
37
+
38
+ "Global Option" is a command line option which you can use
39
+ for all tasks. You must give a global option before any task
40
+ name.
41
+
42
+ -q,--quiet
43
+ suppress message outputs
44
+ --verbose
45
+ output messages verbosely (default)
46
+ -h,--help
47
+ prints help and quit
48
+ -v,--version
49
+ prints version and quit
50
+ --copyright
51
+ prints copyright and quit
52
+
53
+ Tasks
54
+ -----
55
+ These are acceptable tasks:
56
+ all
57
+ Invokes `config', `setup', then `install'.
58
+ Task options for all is same with config.
59
+ config
60
+ Checks and saves configurations.
61
+ show
62
+ Prints current configurations.
63
+ setup
64
+ Compiles ruby extentions.
65
+ install
66
+ Installs files.
67
+ clean
68
+ Removes created files.
69
+ distclean
70
+ Removes all created files.
71
+
72
+ Task Options for CONFIG/ALL
73
+ ---------------------------
74
+
75
+ --prefix=PATH
76
+ a prefix of the installing directory path
77
+ --stdruby=PATH
78
+ the directory for standard ruby libraries
79
+ --siterubycommon=PATH
80
+ the directory for version-independent non-standard
81
+ ruby libraries
82
+ --siteruby=PATH
83
+ the directory for non-standard ruby libraries
84
+ --bindir=PATH
85
+ the directory for commands
86
+ --rbdir=PATH
87
+ the directory for ruby scripts
88
+ --sodir=PATH
89
+ the directory for ruby extentions
90
+ --datadir=PATH
91
+ the directory for shared data
92
+ --rubypath=PATH
93
+ path to set to #! line
94
+ --rubyprog=PATH
95
+ the ruby program using for installation
96
+ --makeprog=NAME
97
+ the make program to compile ruby extentions
98
+ --without-ext
99
+ forces to setup.rb never to compile/install
100
+ ruby extentions.
101
+ --rbconfig=PATH
102
+ your rbconfig.rb to load
103
+
104
+ You can view default values of these options by typing
105
+
106
+ $ ruby setup.rb --help
107
+
108
+
109
+ If there's the directory named "packages",
110
+ You can also use these options:
111
+ --with=NAME,NAME,NAME...
112
+ Package names which you want to install.
113
+ --without=NAME,NAME,NAME...
114
+ Package names which you do not want to install.
115
+
116
+ [NOTE] You can pass options for extconf.rb like this:
117
+
118
+ ruby setup.rb config -- --with-tklib=/usr/lib/libtk-ja.so.8.0
119
+
120
+
121
+ Task Options for INSTALL
122
+ ------------------------
123
+
124
+ --no-harm
125
+ prints what to do and done nothing really.
126
+ --prefix=PATH
127
+ The prefix of the installing directory path.
128
+ This option may help binary package maintainers.
129
+ A default value is an empty string.
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright (C) 2002 Tom Gilbert.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to
7
+ # deal in the Software without restriction, including without limitation the
8
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9
+ # sell copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies of the Software and its documentation and acknowledgment shall be
14
+ # given in the documentation and software packages that this Software was
15
+ # used.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20
+ # THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ $VERBOSE=true
25
+
26
+ require 'etc'
27
+ require 'getoptlong'
28
+ require 'fileutils'
29
+
30
+ $version="0.9.9"
31
+ $opts = Hash.new
32
+
33
+ orig_opts = ARGV.dup
34
+
35
+ opts = GetoptLong.new(
36
+ ["--debug", "-d", GetoptLong::NO_ARGUMENT],
37
+ ["--help", "-h", GetoptLong::NO_ARGUMENT],
38
+ ["--trace", "-t", GetoptLong::REQUIRED_ARGUMENT],
39
+ ["--version", "-v", GetoptLong::NO_ARGUMENT]
40
+ )
41
+
42
+ $debug = false
43
+ opts.each {|opt, arg|
44
+ $debug = true if(opt == "--debug")
45
+ $opts[opt.sub(/^-+/, "")] = arg
46
+ }
47
+
48
+ if ($opts["trace"])
49
+ set_trace_func proc { |event, file, line, id, binding, classname|
50
+ if classname.to_s == $opts["trace"]
51
+ printf "TRACE: %8s %s:%-2d %10s %8s\n", event, File.basename(file), line, id, classname
52
+ end
53
+ }
54
+ end
55
+
56
+ begin
57
+ require 'rbot/ircbot'
58
+ rescue LoadError => e
59
+ puts "Error: couldn't find the rbot/ircbot module for loading\n - did you install rbot using install.rb?"
60
+ exit 2
61
+ end
62
+
63
+ if ($opts["version"])
64
+ puts "rbot #{$version}"
65
+ exit 0
66
+ end
67
+
68
+ if ($opts["help"])
69
+ puts "usage: rbot [options] [config directory]"
70
+ puts " -h, --help this message"
71
+ puts " -v, --version version information"
72
+ puts " -d, --debug enable debug messages"
73
+ puts "config directory defaults to ~/.rbot"
74
+ exit 0
75
+ end
76
+
77
+ if(bot = Irc::IrcBot.new(ARGV.shift, :argv => orig_opts))
78
+ # just run the bot
79
+ bot.mainloop
80
+ end
81
+
@@ -0,0 +1,20 @@
1
+ class FigletPlugin < Plugin
2
+ def help(plugin, topic="")
3
+ "figlet [<message>] => print using figlet"
4
+ end
5
+ def privmsg(m)
6
+ case m.params
7
+ when nil
8
+ m.reply "incorrect usage: " + help(m.plugin)
9
+ return
10
+ when (/^-/)
11
+ m.reply "incorrect usage: " + help(m.plugin)
12
+ return
13
+ else
14
+ m.reply Utils.safe_exec("/usr/bin/figlet", "-k", "-f", "mini", m.params)
15
+ return
16
+ end
17
+ end
18
+ end
19
+ plugin = FigletPlugin.new
20
+ plugin.register("figlet")
@@ -0,0 +1,83 @@
1
+ # Author: Michael Brailsford <brailsmt@yahoo.com>
2
+ # aka brailsmt
3
+ # Purpose: To respond to requests for information from the ri command line
4
+ # utility.
5
+
6
+ class RiPlugin < Plugin
7
+
8
+ @@handlers = {
9
+ "ri" => "ri_handler",
10
+ "msgri" => "msgri_handler"
11
+ }
12
+
13
+ #{{{
14
+ def initialize
15
+ super
16
+ @cache = Hash.new
17
+ end
18
+ #}}}
19
+ #{{{
20
+ def privmsg(m)
21
+ if not m.params
22
+ m.reply "uhmm... whatever"
23
+ return
24
+ end
25
+
26
+ meth = self.method(@@handlers[m.plugin])
27
+ meth.call(m)
28
+ end
29
+ #}}}
30
+ #{{{
31
+ def cleanup
32
+ @cache = nil
33
+ end
34
+ #}}}
35
+ #{{{
36
+ def ri_handler(m)
37
+ response = ""
38
+ if @cache[m.params]
39
+ response = @cache[m.params]
40
+ else
41
+ IO.popen("-") {|p|
42
+ if(p)
43
+ response = p.readlines.join "\n"
44
+ @cache[m.params] = response
45
+ else
46
+ $stderr = $stdout
47
+ exec("ri", m.params)
48
+ end
49
+ }
50
+ @cache[m.params] = response
51
+ end
52
+
53
+ @bot.say m.sourcenick, response
54
+ m.reply "Finished \"ri #{m.params}\""
55
+ end
56
+ #}}}
57
+ #{{{
58
+ def msgri_handler(m)
59
+ response = ""
60
+ tell_nick, query = m.params.split()
61
+ if @cache[query]
62
+ response = @cache[query]
63
+ else
64
+ IO.popen("-") {|p|
65
+ if(p)
66
+ response = p.readlines.join "\n"
67
+ @cache[m.params] = response
68
+ else
69
+ $stderr = $stdout
70
+ exec("ri", query)
71
+ end
72
+ }
73
+ @cache[query] = response
74
+ end
75
+
76
+ @bot.say tell_nick, response
77
+ m.reply "Finished telling #{tell_nick} about \"ri #{query}\""
78
+ end
79
+ #}}}
80
+ end
81
+ plugin = RiPlugin.new
82
+ plugin.register("ri")
83
+ plugin.register("msgri")
@@ -0,0 +1,232 @@
1
+ # Author: Michael Brailsford <brailsmt@yahoo.com>
2
+ # aka brailsmt
3
+ # Purpose: Provides the ability to track various tokens that are spoken in a
4
+ # channel.
5
+ # Copyright: 2002 Michael Brailsford. All rights reserved.
6
+ # License: This plugin is licensed under the BSD license. The terms of
7
+ # which follow.
8
+ #
9
+ # Redistribution and use in source and binary forms, with or without
10
+ # modification, are permitted provided that the following conditions
11
+ # are met:
12
+ #
13
+ # 1. Redistributions of source code must retain the above copyright notice,
14
+ # this list of conditions and the following disclaimer.
15
+ #
16
+ # 2. Redistributions in binary form must reproduce the above copyright
17
+ # notice, this list of conditions and the following disclaimer in the
18
+ # documentation and/or other materials provided with the distribution.
19
+
20
+ class StatsPlugin < Plugin
21
+
22
+ @@commands = {
23
+ "stats" => "handle_stats",
24
+ "track" => "handle_track",
25
+ "untrack" => "handle_untrack",
26
+ "listtokens" => "handle_listtokens",
27
+ "rmabuser" => "handle_rmabuser"
28
+ }
29
+
30
+ #{{{
31
+ def initialize
32
+ super
33
+ @listen = true
34
+ @channels = Hash.new
35
+ #check to see if a stats token file already exists for this channel...
36
+ Dir["#{@bot.botclass}/stats/*"].each { |fname|
37
+ channel = File.basename fname
38
+ tokens = Hash.new
39
+ IO.foreach(fname) { |line|
40
+ if line =~ /^(\S+)\s*<=>(.*)/
41
+ tokens[$1] = parse_token_stats $2
42
+ end
43
+ }
44
+ @channels[channel] = tokens
45
+ }
46
+ end
47
+ #}}}
48
+ #{{{
49
+ def cleanup
50
+ @channels = nil
51
+ end
52
+ #}}}
53
+ #{{{
54
+ def help(plugin, topic="")
55
+ "Stats: The stats plugin tracks various tokens from users in the channel. The tokens are only tracked if it is the only thing on a line.\nUsage: stats <token> -- lists the stats for <token>\n [un]track <token> -- Adds or deletes <token> from the list of tokens\n listtokens -- lists the tokens that are currently being tracked"
56
+ end
57
+ #}}}
58
+ #{{{
59
+ def privmsg(m)
60
+ if not m.params and not m.plugin =~ /listtokens/
61
+ m.reply "What a crazy fool! Did you mean |help stats?"
62
+ return
63
+ end
64
+
65
+ meth = self.method(@@commands[m.plugin])
66
+ meth.call(m)
67
+ end
68
+ #}}}
69
+ #{{{
70
+ def save
71
+ Dir.mkdir("#{@bot.botclass}/stats") if not FileTest.directory?("#{@bot.botclass}/stats")
72
+ #save the tokens to a file...
73
+ @channels.each_pair { |channel, tokens|
74
+ if not tokens.empty?
75
+ File.open("#{@bot.botclass}/stats/#{channel}", "w") { |f|
76
+ tokens.each { |token, datahash|
77
+ f.puts "#{token} <=> #{datahash_to_s(datahash)}"
78
+ }
79
+ }
80
+ else
81
+ File.delete "#{@bot.botclass}/stats/#{channel}"
82
+ end
83
+ }
84
+ end
85
+ #}}}
86
+ #{{{
87
+ def listen(m)
88
+ if not m.private?
89
+ tokens = @channels[m.target]
90
+ if not @@commands[m.plugin]
91
+ tokens.each_pair { |key, hsh|
92
+ if not m.message.scan(/#{Regexp.escape(key)}/).empty?
93
+ if hsh[m.sourcenick]
94
+ hsh[m.sourcenick] += 1
95
+ else
96
+ hsh[m.sourcenick] = 1
97
+ end
98
+ end
99
+ }
100
+ end
101
+ end
102
+ #This is the old code {{{
103
+ # if not m.private?
104
+ # tokens = @channels[m.target]
105
+ # hsh = tokens[m.message]
106
+ # if hsh
107
+ # if hsh[m.sourcenick]
108
+ # hsh[m.sourcenick] += 1
109
+ # else
110
+ # hsh[m.sourcenick] = 1
111
+ # end
112
+ # end
113
+ # end }}}
114
+ end
115
+ #}}}
116
+ #The following are helper functions for the plugin {{{
117
+ def datahash_to_s(dhash)
118
+ rv = ""
119
+ dhash.each { |key, val|
120
+ rv << "#{key}:#{val} "
121
+ }
122
+ rv.chomp
123
+ end
124
+
125
+ def parse_token_stats(stats)
126
+ rv = Hash.new
127
+ stats.split(" ").each { |nickstat|
128
+ nick, stat = nickstat.split ":"
129
+ rv[nick] = stat.to_i
130
+ }
131
+ rv
132
+ end
133
+ #}}}
134
+ #The following are handler methods for dealing with each command from IRC {{{
135
+ #{{{
136
+ def handle_stats(m)
137
+ if not m.private?
138
+ total = 0
139
+ tokens = @channels[m.target]
140
+ hsh = tokens[m.params]
141
+ msg1 = ""
142
+ if not hsh.empty?
143
+ sorted = hsh.sort { |i, j| j[1] <=> i[1] }
144
+ sorted.each { |a|
145
+ total += a[1]
146
+ }
147
+
148
+ msg = "Stats for #{m.params}. Said #{total} times. The top sayers are "
149
+ if sorted[0..2]
150
+ msg << "#{sorted[0].join ':'}" if sorted[0]
151
+ msg << ", #{sorted[1].join ':'}" if sorted[1]
152
+ msg << ", and #{sorted[2].join ':'}" if sorted[2]
153
+ msg << "."
154
+
155
+ msg1 << "#{m.sourcenick} has said it "
156
+ if hsh[m.sourcenick]
157
+ msg1 << "#{hsh[m.sourcenick]} times."
158
+ else
159
+ msg1 << "0 times."
160
+ end
161
+ else
162
+ msg << "#{m.params} has not been said yet!"
163
+ end
164
+ @bot.action m.replyto, msg
165
+ @bot.action m.replyto, msg1 if msg1
166
+ else
167
+ m.reply "#{m.params} is not currently being tracked."
168
+ end
169
+ end
170
+ end
171
+ #}}}
172
+ #{{{
173
+ def handle_track(m)
174
+ if not m.private?
175
+ if @channels[m.target]
176
+ tokens = @channels[m.target]
177
+ else
178
+ tokens = Hash.new
179
+ @channels[m.target] = tokens
180
+ end
181
+ tokens[m.params] = Hash.new
182
+ m.reply "now tracking #{m.params}"
183
+ end
184
+ end
185
+ #}}}
186
+ #{{{
187
+ def handle_untrack(m)
188
+ if not m.private?
189
+ toks = @channels[m.target]
190
+ if toks.has_key? m.params
191
+ toks.delete m.params
192
+ m.reply "no longer tracking #{m.params}"
193
+ else
194
+ m.reply "Are your signals crossed? Since when have I tracked that?"
195
+ end
196
+ end
197
+
198
+ toks = nil
199
+ end
200
+ #}}}
201
+ #{{{
202
+ def handle_listtokens(m)
203
+ if not m.private? and not @channels.empty?
204
+ tokens = @channels[m.target]
205
+ unless tokens.empty?
206
+ toks = ""
207
+ tokens.each_key { |k|
208
+ toks << "#{k} "
209
+ }
210
+ @bot.action m.replyto, "is currently keeping stats for: #{toks}"
211
+ else
212
+ @bot.action m.replyto, "is not currently keeping stats for anything"
213
+ end
214
+ elsif not m.private?
215
+ @bot.action m.replyto, "is not currently keeping stats for anything"
216
+ end
217
+ end
218
+ #}}}
219
+ #{{{
220
+ def handle_rmabuser(m)
221
+ m.reply "This feature has not yet been implemented"
222
+ end
223
+ #}}}
224
+ #}}}
225
+
226
+ end
227
+ plugin = StatsPlugin.new
228
+ plugin.register("stats")
229
+ plugin.register("track")
230
+ plugin.register("untrack")
231
+ plugin.register("listtokens")
232
+ #plugin.register("rmabuser")