rbot 0.9.9
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +16 -0
- data/COPYING +21 -0
- data/ChangeLog +418 -0
- data/INSTALL +8 -0
- data/README +44 -0
- data/REQUIREMENTS +34 -0
- data/TODO +5 -0
- data/Usage_en.txt +129 -0
- data/bin/rbot +81 -0
- data/data/rbot/contrib/plugins/figlet.rb +20 -0
- data/data/rbot/contrib/plugins/ri.rb +83 -0
- data/data/rbot/contrib/plugins/stats.rb +232 -0
- data/data/rbot/contrib/plugins/vandale.rb +49 -0
- data/data/rbot/languages/dutch.lang +73 -0
- data/data/rbot/languages/english.lang +75 -0
- data/data/rbot/languages/french.lang +39 -0
- data/data/rbot/languages/german.lang +67 -0
- data/data/rbot/plugins/autoop.rb +68 -0
- data/data/rbot/plugins/autorejoin.rb +16 -0
- data/data/rbot/plugins/cal.rb +15 -0
- data/data/rbot/plugins/dice.rb +81 -0
- data/data/rbot/plugins/eightball.rb +19 -0
- data/data/rbot/plugins/excuse.rb +470 -0
- data/data/rbot/plugins/fish.rb +61 -0
- data/data/rbot/plugins/fortune.rb +22 -0
- data/data/rbot/plugins/freshmeat.rb +98 -0
- data/data/rbot/plugins/google.rb +51 -0
- data/data/rbot/plugins/host.rb +14 -0
- data/data/rbot/plugins/httpd.rb.disabled +35 -0
- data/data/rbot/plugins/insult.rb +258 -0
- data/data/rbot/plugins/karma.rb +85 -0
- data/data/rbot/plugins/lart.rb +181 -0
- data/data/rbot/plugins/math.rb +122 -0
- data/data/rbot/plugins/nickserv.rb +89 -0
- data/data/rbot/plugins/nslookup.rb +43 -0
- data/data/rbot/plugins/opme.rb +19 -0
- data/data/rbot/plugins/quakeauth.rb +51 -0
- data/data/rbot/plugins/quotes.rb +321 -0
- data/data/rbot/plugins/remind.rb +228 -0
- data/data/rbot/plugins/roshambo.rb +54 -0
- data/data/rbot/plugins/rot13.rb +10 -0
- data/data/rbot/plugins/roulette.rb +147 -0
- data/data/rbot/plugins/rss.rb.disabled +414 -0
- data/data/rbot/plugins/seen.rb +89 -0
- data/data/rbot/plugins/slashdot.rb +94 -0
- data/data/rbot/plugins/spell.rb +36 -0
- data/data/rbot/plugins/tube.rb +71 -0
- data/data/rbot/plugins/url.rb +88 -0
- data/data/rbot/plugins/weather.rb +649 -0
- data/data/rbot/plugins/wserver.rb +71 -0
- data/data/rbot/plugins/xmlrpc.rb.disabled +52 -0
- data/data/rbot/templates/keywords.rbot +4 -0
- data/data/rbot/templates/lart/larts +98 -0
- data/data/rbot/templates/lart/praises +5 -0
- data/data/rbot/templates/levels.rbot +30 -0
- data/data/rbot/templates/users.rbot +1 -0
- data/lib/rbot/auth.rb +203 -0
- data/lib/rbot/channel.rb +54 -0
- data/lib/rbot/config.rb +363 -0
- data/lib/rbot/dbhash.rb +112 -0
- data/lib/rbot/httputil.rb +141 -0
- data/lib/rbot/ircbot.rb +808 -0
- data/lib/rbot/ircsocket.rb +185 -0
- data/lib/rbot/keywords.rb +433 -0
- data/lib/rbot/language.rb +69 -0
- data/lib/rbot/message.rb +256 -0
- data/lib/rbot/messagemapper.rb +262 -0
- data/lib/rbot/plugins.rb +291 -0
- data/lib/rbot/post-install.rb +8 -0
- data/lib/rbot/rbotconfig.rb +36 -0
- data/lib/rbot/registry.rb +271 -0
- data/lib/rbot/rfc2812.rb +1104 -0
- data/lib/rbot/timer.rb +201 -0
- data/lib/rbot/utils.rb +83 -0
- data/setup.rb +1360 -0
- metadata +129 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
class DnsPlugin < Plugin
|
2
|
+
require 'resolv'
|
3
|
+
def gethostname(address)
|
4
|
+
Resolv.getname(address)
|
5
|
+
end
|
6
|
+
def getaddresses(name)
|
7
|
+
Resolv.getaddresses(name)
|
8
|
+
end
|
9
|
+
|
10
|
+
def help(plugin, topic="")
|
11
|
+
"dns <hostname|ip> => show local resolution results for hostname or ip address"
|
12
|
+
end
|
13
|
+
|
14
|
+
def name_to_ip(m, params)
|
15
|
+
Thread.new do
|
16
|
+
begin
|
17
|
+
a = getaddresses(params[:host])
|
18
|
+
if a.length > 0
|
19
|
+
m.reply m.params + ": " + a.join(", ")
|
20
|
+
else
|
21
|
+
m.reply "#{params[:host]}: not found"
|
22
|
+
end
|
23
|
+
rescue StandardError => err
|
24
|
+
m.reply "#{params[:host]}: not found"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def ip_to_name(m, params)
|
30
|
+
Thread.new do
|
31
|
+
begin
|
32
|
+
a = gethostname(params[:ip])
|
33
|
+
m.reply m.params + ": " + a if a
|
34
|
+
rescue StandardError => err
|
35
|
+
m.reply "#{params[:ip]}: not found (does not reverse resolve)"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
plugin = DnsPlugin.new
|
41
|
+
plugin.map 'dns :ip', :action => 'ip_to_name',
|
42
|
+
:requirements => {:ip => /^\d+\.\d+\.\d+\.\d+$/}
|
43
|
+
plugin.map 'dns :host', :action => 'name_to_ip'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class OpMePlugin < Plugin
|
2
|
+
|
3
|
+
def help(plugin, topic="")
|
4
|
+
return "opme <channel> => grant user ops in <channel>"
|
5
|
+
end
|
6
|
+
|
7
|
+
def privmsg(m)
|
8
|
+
if(m.params)
|
9
|
+
channel = m.params
|
10
|
+
else
|
11
|
+
channel = m.channel
|
12
|
+
end
|
13
|
+
target = m.sourcenick
|
14
|
+
@bot.sendq("MODE #{channel} +o #{target}")
|
15
|
+
m.okay
|
16
|
+
end
|
17
|
+
end
|
18
|
+
plugin = OpMePlugin.new
|
19
|
+
plugin.register("opme")
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# automatically auths with Q on quakenet servers
|
2
|
+
|
3
|
+
class QPlugin < Plugin
|
4
|
+
|
5
|
+
def help(plugin, topic="")
|
6
|
+
case topic
|
7
|
+
when ""
|
8
|
+
return "quath plugin: handles Q auths. topics set, identify"
|
9
|
+
when "set"
|
10
|
+
return "nickserv set <user> <passwd>: set the Q user and password and use it to identify in future"
|
11
|
+
when "identify"
|
12
|
+
return "quath identify: identify with Q (if user and auth are set)"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
super
|
18
|
+
# this plugin only wants to store strings!
|
19
|
+
class << @registry
|
20
|
+
def store(val)
|
21
|
+
val
|
22
|
+
end
|
23
|
+
def restore(val)
|
24
|
+
val
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def set(m, params)
|
30
|
+
@registry['quakenet.user'] = params[:user]
|
31
|
+
@registry['quakenet.auth'] = params[:passwd]
|
32
|
+
m.okay
|
33
|
+
end
|
34
|
+
|
35
|
+
def connect
|
36
|
+
identify(nil, nil)
|
37
|
+
end
|
38
|
+
def identify(m, params)
|
39
|
+
if @registry.has_key?('quakenet.user') && @registry.has_key?('quakenet.auth')
|
40
|
+
debug "authing with Q using #{@registry['quakenet.user']} #{@registry['quakenet.auth']}"
|
41
|
+
@bot.sendmsg "PRIVMSG", "Q@CServe.quakenet.org", "auth #{@registry['quakenet.user']} #{@registry['quakenet.auth']}"
|
42
|
+
m.okay if m
|
43
|
+
else
|
44
|
+
m.reply "not configured, try 'qauth set :nick :passwd'" if m
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
plugin = QPlugin.new
|
50
|
+
plugin.map 'qauth set :nick :passwd', :action => "set"
|
51
|
+
plugin.map 'quath identify', :action => "identify"
|
@@ -0,0 +1,321 @@
|
|
1
|
+
Quote = Struct.new("Quote", "num", "date", "source", "quote")
|
2
|
+
|
3
|
+
class QuotePlugin < Plugin
|
4
|
+
def initialize
|
5
|
+
super
|
6
|
+
@lists = Hash.new
|
7
|
+
Dir["#{@bot.botclass}/quotes/*"].each {|f|
|
8
|
+
channel = File.basename(f)
|
9
|
+
@lists[channel] = Array.new if(!@lists.has_key?(channel))
|
10
|
+
IO.foreach(f) {|line|
|
11
|
+
if(line =~ /^(\d+) \| ([^|]+) \| (\S+) \| (.*)$/)
|
12
|
+
num = $1.to_i
|
13
|
+
@lists[channel][num] = Quote.new(num, $2, $3, $4)
|
14
|
+
end
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
def save
|
19
|
+
Dir.mkdir("#{@bot.botclass}/quotes") if(!FileTest.directory?("#{@bot.botclass}/quotes"))
|
20
|
+
@lists.each {|channel, quotes|
|
21
|
+
File.open("#{@bot.botclass}/quotes/#{channel}", "w") {|file|
|
22
|
+
quotes.compact.each {|q|
|
23
|
+
file.puts "#{q.num} | #{q.date} | #{q.source} | #{q.quote}"
|
24
|
+
}
|
25
|
+
}
|
26
|
+
}
|
27
|
+
end
|
28
|
+
def addquote(source, channel, quote)
|
29
|
+
@lists[channel] = Array.new if(!@lists.has_key?(channel))
|
30
|
+
num = @lists[channel].length
|
31
|
+
@lists[channel][num] = Quote.new(num, Time.new, source, quote)
|
32
|
+
return num
|
33
|
+
end
|
34
|
+
def getquote(source, channel, num=nil)
|
35
|
+
return nil unless(@lists.has_key?(channel))
|
36
|
+
return nil unless(@lists[channel].length > 0)
|
37
|
+
if(num)
|
38
|
+
if(@lists[channel][num])
|
39
|
+
return @lists[channel][num], @lists[channel].length - 1
|
40
|
+
end
|
41
|
+
else
|
42
|
+
# random quote
|
43
|
+
return @lists[channel].compact[rand(@lists[channel].nitems)],
|
44
|
+
@lists[channel].length - 1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
def delquote(channel, num)
|
48
|
+
return false unless(@lists.has_key?(channel))
|
49
|
+
return false unless(@lists[channel].length > 0)
|
50
|
+
if(@lists[channel][num])
|
51
|
+
@lists[channel][num] = nil
|
52
|
+
return true
|
53
|
+
end
|
54
|
+
return false
|
55
|
+
end
|
56
|
+
def countquote(source, channel=nil, regexp=nil)
|
57
|
+
unless(channel)
|
58
|
+
total=0
|
59
|
+
@lists.each_value {|l|
|
60
|
+
total += l.compact.length
|
61
|
+
}
|
62
|
+
return total
|
63
|
+
end
|
64
|
+
return 0 unless(@lists.has_key?(channel))
|
65
|
+
return 0 unless(@lists[channel].length > 0)
|
66
|
+
if(regexp)
|
67
|
+
matches = @lists[channel].compact.find_all {|a| a.quote =~ /#{regexp}/i }
|
68
|
+
else
|
69
|
+
matches = @lists[channel].compact
|
70
|
+
end
|
71
|
+
return matches.length
|
72
|
+
end
|
73
|
+
def searchquote(source, channel, regexp)
|
74
|
+
return nil unless(@lists.has_key?(channel))
|
75
|
+
return nil unless(@lists[channel].length > 0)
|
76
|
+
matches = @lists[channel].compact.find_all {|a| a.quote =~ /#{regexp}/i }
|
77
|
+
if(matches.length > 0)
|
78
|
+
return matches[rand(matches.length)], @lists[channel].length - 1
|
79
|
+
else
|
80
|
+
return nil
|
81
|
+
end
|
82
|
+
end
|
83
|
+
def help(plugin, topic="")
|
84
|
+
case topic
|
85
|
+
when "addquote"
|
86
|
+
return "addquote [<channel>] <quote> => Add quote <quote> for channel <channel>. You only need to supply <channel> if you are addressing #{@bot.nick} privately. Responds to !addquote without addressing if so configured"
|
87
|
+
when "delquote"
|
88
|
+
return "delquote [<channel>] <num> => delete quote from <channel> with number <num>. You only need to supply <channel> if you are addressing #{@bot.nick} privately. Responds to !delquote without addressing if so configured"
|
89
|
+
when "getquote"
|
90
|
+
return "getquote [<channel>] [<num>] => get quote from <channel> with number <num>. You only need to supply <channel> if you are addressing #{@bot.nick} privately. Without <num>, a random quote will be returned. Responds to !getquote without addressing if so configured"
|
91
|
+
when "searchquote"
|
92
|
+
return "searchquote [<channel>] <regexp> => search for quote from <channel> that matches <regexp>. You only need to supply <channel> if you are addressing #{@bot.nick} privately. Responds to !searchquote without addressing if so configured"
|
93
|
+
when "topicquote"
|
94
|
+
return "topicquote [<channel>] [<num>] => set topic to quote from <channel> with number <num>. You only need to supply <channel> if you are addressing #{@bot.nick} privately. Without <num>, a random quote will be set. Responds to !topicquote without addressing if so configured"
|
95
|
+
when "countquote"
|
96
|
+
return "countquote [<channel>] <regexp> => count quotes from <channel> that match <regexp>. You only need to supply <channel> if you are addressing #{@bot.nick} privately. Responds to !countquote without addressing if so configured"
|
97
|
+
when "whoquote"
|
98
|
+
return "whoquote [<channel>] <num> => show who added quote <num>. You only need to supply <channel> if you are addressing #{@bot.nick} privately"
|
99
|
+
when "whenquote"
|
100
|
+
return "whenquote [<channel>] <num> => show when quote <num> was added. You only need to supply <channel> if you are addressing #{@bot.nick} privately"
|
101
|
+
else
|
102
|
+
return "Quote module (Quote storage and retrieval) topics: addquote, getquote, searchquote, topicquote, countquote, whoquote, whenquote"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
def listen(m)
|
106
|
+
return unless(m.kind_of? PrivMessage)
|
107
|
+
|
108
|
+
command = m.message.dup
|
109
|
+
if(m.address? && m.private?)
|
110
|
+
case command
|
111
|
+
when (/^addquote\s+(#\S+)\s+(.*)/)
|
112
|
+
channel = $1
|
113
|
+
quote = $2
|
114
|
+
if(@bot.auth.allow?("addquote", m.source, m.replyto))
|
115
|
+
if(channel =~ /^#/)
|
116
|
+
num = addquote(m.source, channel, quote)
|
117
|
+
m.reply "added the quote (##{num})"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
when (/^getquote\s+(#\S+)$/)
|
121
|
+
channel = $1
|
122
|
+
if(@bot.auth.allow?("getquote", m.source, m.replyto))
|
123
|
+
quote, total = getquote(m.source, channel)
|
124
|
+
if(quote)
|
125
|
+
m.reply "[#{quote.num}] #{quote.quote}"
|
126
|
+
else
|
127
|
+
m.reply "quote not found!"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
when (/^getquote\s+(#\S+)\s+(\d+)$/)
|
131
|
+
channel = $1
|
132
|
+
num = $2.to_i
|
133
|
+
if(@bot.auth.allow?("getquote", m.source, m.replyto))
|
134
|
+
quote, total = getquote(m.source, channel, num)
|
135
|
+
if(quote)
|
136
|
+
m.reply "[#{quote.num}] #{quote.quote}"
|
137
|
+
else
|
138
|
+
m.reply "quote not found!"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
when (/^whoquote\s+(#\S+)\s+(\d+)$/)
|
142
|
+
channel = $1
|
143
|
+
num = $2.to_i
|
144
|
+
if(@bot.auth.allow?("getquote", m.source, m.replyto))
|
145
|
+
quote, total = getquote(m.source, channel, num)
|
146
|
+
if(quote)
|
147
|
+
m.reply "quote #{quote.num} added by #{quote.source}"
|
148
|
+
else
|
149
|
+
m.reply "quote not found!"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
when (/^whenquote\s+(#\S+)\s+(\d+)$/)
|
153
|
+
channel = $1
|
154
|
+
num = $2.to_i
|
155
|
+
if(@bot.auth.allow?("getquote", m.source, m.replyto))
|
156
|
+
quote, total = getquote(m.source, channel, num)
|
157
|
+
if(quote)
|
158
|
+
m.reply "quote #{quote.num} added on #{quote.date}"
|
159
|
+
else
|
160
|
+
m.reply "quote not found!"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
when (/^topicquote\s+(#\S+)$/)
|
164
|
+
channel = $1
|
165
|
+
if(@bot.auth.allow?("topicquote", m.source, m.replyto))
|
166
|
+
quote, total = getquote(m.source, channel)
|
167
|
+
if(quote)
|
168
|
+
@bot.topic channel, "[#{quote.num}] #{quote.quote}"
|
169
|
+
else
|
170
|
+
m.reply "quote not found!"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
when (/^topicquote\s+(#\S+)\s+(\d+)$/)
|
174
|
+
channel = $1
|
175
|
+
num = $2.to_i
|
176
|
+
if(@bot.auth.allow?("topicquote", m.source, m.replyto))
|
177
|
+
quote, total = getquote(m.source, channel, num)
|
178
|
+
if(quote)
|
179
|
+
@bot.topic channel, "[#{quote.num}] #{quote.quote}"
|
180
|
+
else
|
181
|
+
m.reply "quote not found!"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
when (/^delquote\s+(#\S+)\s+(\d+)$/)
|
185
|
+
channel = $1
|
186
|
+
num = $2.to_i
|
187
|
+
if(@bot.auth.allow?("delquote", m.source, m.replyto))
|
188
|
+
if(delquote(channel, num))
|
189
|
+
m.okay
|
190
|
+
else
|
191
|
+
m.reply "quote not found!"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
when (/^searchquote\s+(#\S+)\s+(.*)$/)
|
195
|
+
channel = $1
|
196
|
+
reg = $2
|
197
|
+
if(@bot.auth.allow?("getquote", m.source, m.replyto))
|
198
|
+
quote, total = searchquote(m.source, channel, reg)
|
199
|
+
if(quote)
|
200
|
+
m.reply "[#{quote.num}] #{quote.quote}"
|
201
|
+
else
|
202
|
+
m.reply "quote not found!"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
when (/^countquote$/)
|
206
|
+
if(@bot.auth.allow?("getquote", m.source, m.replyto))
|
207
|
+
total = countquote(m.source)
|
208
|
+
m.reply "#{total} quotes"
|
209
|
+
end
|
210
|
+
when (/^countquote\s+(#\S+)\s*(.*)$/)
|
211
|
+
channel = $1
|
212
|
+
reg = $2
|
213
|
+
if(@bot.auth.allow?("getquote", m.source, m.replyto))
|
214
|
+
total = countquote(m.source, channel, reg)
|
215
|
+
if(reg.length > 0)
|
216
|
+
m.reply "#{total} quotes match: #{reg}"
|
217
|
+
else
|
218
|
+
m.reply "#{total} quotes"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
elsif (m.address? || (@bot.config["QUOTE_LISTEN"] && command.gsub!(/^!/, "")))
|
223
|
+
case command
|
224
|
+
when (/^addquote\s+(.+)/)
|
225
|
+
if(@bot.auth.allow?("addquote", m.source, m.replyto))
|
226
|
+
num = addquote(m.source, m.target, $1)
|
227
|
+
m.reply "added the quote (##{num})"
|
228
|
+
end
|
229
|
+
when (/^getquote$/)
|
230
|
+
if(@bot.auth.allow?("getquote", m.source, m.replyto))
|
231
|
+
quote, total = getquote(m.source, m.target)
|
232
|
+
if(quote)
|
233
|
+
m.reply "[#{quote.num}] #{quote.quote}"
|
234
|
+
else
|
235
|
+
m.reply "no quotes found!"
|
236
|
+
end
|
237
|
+
end
|
238
|
+
when (/^getquote\s+(\d+)$/)
|
239
|
+
num = $1.to_i
|
240
|
+
if(@bot.auth.allow?("getquote", m.source, m.replyto))
|
241
|
+
quote, total = getquote(m.source, m.target, num)
|
242
|
+
if(quote)
|
243
|
+
m.reply "[#{quote.num}] #{quote.quote}"
|
244
|
+
else
|
245
|
+
m.reply "quote not found!"
|
246
|
+
end
|
247
|
+
end
|
248
|
+
when (/^whenquote\s+(\d+)$/)
|
249
|
+
num = $1.to_i
|
250
|
+
if(@bot.auth.allow?("getquote", m.source, m.replyto))
|
251
|
+
quote, total = getquote(m.source, m.target, num)
|
252
|
+
if(quote)
|
253
|
+
m.reply "quote #{quote.num} added on #{quote.date}"
|
254
|
+
else
|
255
|
+
m.reply "quote not found!"
|
256
|
+
end
|
257
|
+
end
|
258
|
+
when (/^whoquote\s+(\d+)$/)
|
259
|
+
num = $1.to_i
|
260
|
+
if(@bot.auth.allow?("getquote", m.source, m.replyto))
|
261
|
+
quote, total = getquote(m.source, m.target, num)
|
262
|
+
if(quote)
|
263
|
+
m.reply "quote #{quote.num} added by #{quote.source}"
|
264
|
+
else
|
265
|
+
m.reply "quote not found!"
|
266
|
+
end
|
267
|
+
end
|
268
|
+
when (/^topicquote$/)
|
269
|
+
if(@bot.auth.allow?("topicquote", m.source, m.replyto))
|
270
|
+
quote, total = getquote(m.source, m.target)
|
271
|
+
if(quote)
|
272
|
+
@bot.topic m.target, "[#{quote.num}] #{quote.quote}"
|
273
|
+
else
|
274
|
+
m.reply "no quotes found!"
|
275
|
+
end
|
276
|
+
end
|
277
|
+
when (/^topicquote\s+(\d+)$/)
|
278
|
+
num = $1.to_i
|
279
|
+
if(@bot.auth.allow?("topicquote", m.source, m.replyto))
|
280
|
+
quote, total = getquote(m.source, m.target, num)
|
281
|
+
if(quote)
|
282
|
+
@bot.topic m.target, "[#{quote.num}] #{quote.quote}"
|
283
|
+
else
|
284
|
+
m.reply "quote not found!"
|
285
|
+
end
|
286
|
+
end
|
287
|
+
when (/^delquote\s+(\d+)$/)
|
288
|
+
num = $1.to_i
|
289
|
+
if(@bot.auth.allow?("delquote", m.source, m.replyto))
|
290
|
+
if(delquote(m.target, num))
|
291
|
+
m.okay
|
292
|
+
else
|
293
|
+
m.reply "quote not found!"
|
294
|
+
end
|
295
|
+
end
|
296
|
+
when (/^searchquote\s+(.*)$/)
|
297
|
+
reg = $1
|
298
|
+
if(@bot.auth.allow?("getquote", m.source, m.replyto))
|
299
|
+
quote, total = searchquote(m.source, m.target, reg)
|
300
|
+
if(quote)
|
301
|
+
m.reply "[#{quote.num}] #{quote.quote}"
|
302
|
+
else
|
303
|
+
m.reply "quote not found!"
|
304
|
+
end
|
305
|
+
end
|
306
|
+
when (/^countquote(?:\s+(.*))?$/)
|
307
|
+
reg = $1
|
308
|
+
if(@bot.auth.allow?("getquote", m.source, m.replyto))
|
309
|
+
total = countquote(m.source, m.target, reg)
|
310
|
+
if(reg && reg.length > 0)
|
311
|
+
m.reply "#{total} quotes match: #{reg}"
|
312
|
+
else
|
313
|
+
m.reply "#{total} quotes"
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
plugin = QuotePlugin.new
|
321
|
+
plugin.register("quotes")
|
@@ -0,0 +1,228 @@
|
|
1
|
+
require 'rbot/utils'
|
2
|
+
|
3
|
+
class RemindPlugin < Plugin
|
4
|
+
# read a time in string format, turn it into "seconds from now".
|
5
|
+
# example formats handled are "5 minutes", "2 days", "five hours",
|
6
|
+
# "11:30", "15:45:11", "one day", etc.
|
7
|
+
#
|
8
|
+
# Throws:: RunTimeError "invalid time string" on parse failure
|
9
|
+
def timestr_offset(timestr)
|
10
|
+
case timestr
|
11
|
+
when (/^(\S+)\s+(\S+)$/)
|
12
|
+
mult = $1
|
13
|
+
unit = $2
|
14
|
+
if(mult =~ /^([\d.]+)$/)
|
15
|
+
num = $1.to_f
|
16
|
+
raise "invalid time string" unless num
|
17
|
+
else
|
18
|
+
case mult
|
19
|
+
when(/^(one|an|a)$/)
|
20
|
+
num = 1
|
21
|
+
when(/^two$/)
|
22
|
+
num = 2
|
23
|
+
when(/^three$/)
|
24
|
+
num = 3
|
25
|
+
when(/^four$/)
|
26
|
+
num = 4
|
27
|
+
when(/^five$/)
|
28
|
+
num = 5
|
29
|
+
when(/^six$/)
|
30
|
+
num = 6
|
31
|
+
when(/^seven$/)
|
32
|
+
num = 7
|
33
|
+
when(/^eight$/)
|
34
|
+
num = 8
|
35
|
+
when(/^nine$/)
|
36
|
+
num = 9
|
37
|
+
when(/^ten$/)
|
38
|
+
num = 10
|
39
|
+
when(/^fifteen$/)
|
40
|
+
num = 15
|
41
|
+
when(/^twenty$/)
|
42
|
+
num = 20
|
43
|
+
when(/^thirty$/)
|
44
|
+
num = 30
|
45
|
+
when(/^sixty$/)
|
46
|
+
num = 60
|
47
|
+
else
|
48
|
+
raise "invalid time string"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
case unit
|
52
|
+
when (/^(s|sec(ond)?s?)$/)
|
53
|
+
return num
|
54
|
+
when (/^(m|min(ute)?s?)$/)
|
55
|
+
return num * 60
|
56
|
+
when (/^(h|h(ou)?rs?)$/)
|
57
|
+
return num * 60 * 60
|
58
|
+
when (/^(d|days?)$/)
|
59
|
+
return num * 60 * 60 * 24
|
60
|
+
else
|
61
|
+
raise "invalid time string"
|
62
|
+
end
|
63
|
+
when (/^(\d+):(\d+):(\d+)$/)
|
64
|
+
hour = $1.to_i
|
65
|
+
min = $2.to_i
|
66
|
+
sec = $3.to_i
|
67
|
+
now = Time.now
|
68
|
+
later = Time.mktime(now.year, now.month, now.day, hour, min, sec)
|
69
|
+
return later - now
|
70
|
+
when (/^(\d+):(\d+)$/)
|
71
|
+
hour = $1.to_i
|
72
|
+
min = $2.to_i
|
73
|
+
now = Time.now
|
74
|
+
later = Time.mktime(now.year, now.month, now.day, hour, min, now.sec)
|
75
|
+
return later - now
|
76
|
+
when (/^(\d+):(\d+)(am|pm)$/)
|
77
|
+
hour = $1.to_i
|
78
|
+
min = $2.to_i
|
79
|
+
ampm = $3
|
80
|
+
if ampm == "pm"
|
81
|
+
hour += 12
|
82
|
+
end
|
83
|
+
now = Time.now
|
84
|
+
later = Time.mktime(now.year, now.month, now.day, hour, min, now.sec)
|
85
|
+
return later - now
|
86
|
+
when (/^(\S+)$/)
|
87
|
+
num = 1
|
88
|
+
unit = $1
|
89
|
+
case unit
|
90
|
+
when (/^(s|sec(ond)?s?)$/)
|
91
|
+
return num
|
92
|
+
when (/^(m|min(ute)?s?)$/)
|
93
|
+
return num * 60
|
94
|
+
when (/^(h|h(ou)?rs?)$/)
|
95
|
+
return num * 60 * 60
|
96
|
+
when (/^(d|days?)$/)
|
97
|
+
return num * 60 * 60 * 24
|
98
|
+
else
|
99
|
+
raise "invalid time string"
|
100
|
+
end
|
101
|
+
else
|
102
|
+
raise "invalid time string"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def initialize
|
107
|
+
super
|
108
|
+
@reminders = Hash.new
|
109
|
+
end
|
110
|
+
def cleanup
|
111
|
+
@reminders.each_value {|v|
|
112
|
+
v.each_value {|vv|
|
113
|
+
@bot.timer.remove(vv)
|
114
|
+
}
|
115
|
+
}
|
116
|
+
@reminders.clear
|
117
|
+
end
|
118
|
+
def help(plugin, topic="")
|
119
|
+
"reminder plugin: remind <who> [about] <message> in <time>, remind <who> [about] <message> every <time>, remind <who> [about] <message> at <time>, remind <who> no more [about] <message>, remind <who> no more. Generally <who> should be 'me', but you can remind others (nick or channel) if you have remind_others auth"
|
120
|
+
end
|
121
|
+
def add_reminder(who, subject, timestr, repeat=false)
|
122
|
+
begin
|
123
|
+
period = timestr_offset(timestr)
|
124
|
+
rescue RuntimeError
|
125
|
+
return "couldn't parse that time string (#{timestr}) :("
|
126
|
+
end
|
127
|
+
if(period <= 0)
|
128
|
+
return "that time is in the past! (#{timestr})"
|
129
|
+
end
|
130
|
+
if(period < 30 && repeat)
|
131
|
+
return "repeats of less than 30 seconds are forbidden"
|
132
|
+
end
|
133
|
+
if(!@reminders.has_key?(who))
|
134
|
+
@reminders[who] = Hash.new
|
135
|
+
elsif(@reminders[who].has_key?(subject))
|
136
|
+
del_reminder(who, subject)
|
137
|
+
end
|
138
|
+
|
139
|
+
if(repeat)
|
140
|
+
@reminders[who][subject] = @bot.timer.add(period) {
|
141
|
+
time = Time.now + period
|
142
|
+
tstr = time.strftime("%H:%M:%S")
|
143
|
+
@bot.say who, "repeat reminder (next at #{tstr}): #{subject}"
|
144
|
+
}
|
145
|
+
else
|
146
|
+
@reminders[who][subject] = @bot.timer.add_once(period) {
|
147
|
+
time = Time.now + period
|
148
|
+
tstr = time.strftime("%H:%M:%S")
|
149
|
+
@bot.say who, "reminder (#{tstr}): #{subject}"
|
150
|
+
}
|
151
|
+
end
|
152
|
+
return false
|
153
|
+
end
|
154
|
+
def del_reminder(who, subject=nil)
|
155
|
+
if(subject)
|
156
|
+
if(@reminders.has_key?(who) && @reminders[who].has_key?(subject))
|
157
|
+
@bot.timer.remove(@reminders[who][subject])
|
158
|
+
@reminders[who].delete(subject)
|
159
|
+
return true
|
160
|
+
else
|
161
|
+
return false
|
162
|
+
end
|
163
|
+
else
|
164
|
+
if(@reminders.has_key?(who))
|
165
|
+
@reminders[who].each_value {|v|
|
166
|
+
@bot.timer.remove(v)
|
167
|
+
}
|
168
|
+
@reminders.delete(who)
|
169
|
+
return true
|
170
|
+
else
|
171
|
+
return false
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
def remind(m, params)
|
176
|
+
who = params.has_key?(:who) ? params[:who] : m.sourcenick
|
177
|
+
string = params[:string].to_s
|
178
|
+
puts "in remind, string is: #{string}"
|
179
|
+
if(string =~ /^(.*)\s+in\s+(.*)$/)
|
180
|
+
subject = $1
|
181
|
+
period = $2
|
182
|
+
if(err = add_reminder(who, subject, period))
|
183
|
+
m.reply "incorrect usage: " + err
|
184
|
+
return
|
185
|
+
end
|
186
|
+
elsif(string =~ /^(.*)\s+every\s+(.*)$/)
|
187
|
+
subject = $1
|
188
|
+
period = $2
|
189
|
+
if(err = add_reminder(who, subject, period, true))
|
190
|
+
m.reply "incorrect usage: " + err
|
191
|
+
return
|
192
|
+
end
|
193
|
+
elsif(string =~ /^(.*)\s+at\s+(.*)$/)
|
194
|
+
subject = $1
|
195
|
+
time = $2
|
196
|
+
if(err = add_reminder(who, subject, time))
|
197
|
+
m.reply "incorrect usage: " + err
|
198
|
+
return
|
199
|
+
end
|
200
|
+
else
|
201
|
+
usage(m)
|
202
|
+
return
|
203
|
+
end
|
204
|
+
m.okay
|
205
|
+
end
|
206
|
+
def no_more(m, params)
|
207
|
+
who = params.has_key?(:who) ? params[:who] : m.sourcenick
|
208
|
+
deleted = params.has_key?(:string) ?
|
209
|
+
del_reminder(who, params[:string].to_s) : del_reminder(who)
|
210
|
+
if deleted
|
211
|
+
m.okay
|
212
|
+
else
|
213
|
+
m.reply "but I wasn't going to :/"
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
plugin = RemindPlugin.new
|
218
|
+
plugin.map 'remind me no more', :action => 'no_more'
|
219
|
+
plugin.map 'remind me no more about *string', :action => 'no_more'
|
220
|
+
plugin.map 'remind me no more *string', :action => 'no_more'
|
221
|
+
plugin.map 'remind me about *string'
|
222
|
+
plugin.map 'remind me *string'
|
223
|
+
plugin.map 'remind :who no more', :auth => 'remind_other', :action => 'no_more'
|
224
|
+
plugin.map 'remind :who no more about *string', :auth => 'remind_other', :action => 'no_more'
|
225
|
+
plugin.map 'remind :who no more *string', :auth => 'remind_other', :action => 'no_more'
|
226
|
+
plugin.map 'remind :who about *string', :auth => 'remind_other'
|
227
|
+
plugin.map 'remind :who *string', :auth => 'remind_other'
|
228
|
+
|