]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - data/rbot/plugins/quotes.rb
multiple plugins: Changes to remove parenthesize warnings.
[user/henk/code/ruby/rbot.git] / data / rbot / plugins / quotes.rb
1 #-- vim:sw=2:et
2 #++
3 #
4 # :title: Quotes plugin
5 #
6 # TODO:: switch to db
7
8 define_structure :Quote, :num, :date, :source, :quote
9
10 class QuotePlugin < Plugin
11   def dirname
12     'quotes'
13   end
14
15   def initialize
16     super
17     @lists = Hash.new
18     @changed = Hash.new
19     Dir[datafile('*')].each {|f|
20       next if File.directory?(f)
21       channel = File.basename(f)
22       @lists[channel] = Array.new if(!@lists.has_key?(channel))
23       IO.foreach(f) {|line|
24         if(line =~ /^(\d+) \| ([^|]+) \| (\S+) \| (.*)$/)
25           num = $1.to_i
26           @lists[channel][num] = Quote.new(num, $2, $3, $4)
27         end
28       }
29       @changed[channel] = false
30     }
31   end
32
33   def save
34     Dir.mkdir(datafile) unless FileTest.directory? datafile
35     @lists.each {|channel, quotes|
36       begin
37         if @changed[channel]
38           debug "Writing new quotefile for channel #{channel} ..."
39           Utils.safe_save(datafile(channel)) {|file|
40             quotes.compact.each {|q|
41               file.puts "#{q.num} | #{q.date} | #{q.source} | #{q.quote}"
42             }
43           }
44           @changed[channel] = false
45         else
46           debug "Not writing quotefile for channel #{channel} (unchanged)"
47         end
48       rescue => e
49         error "failed to write quotefile for channel #{channel}!\n#{$!}"
50         error "#{e.class}: #{e}"
51         error e.backtrace.join("\n")
52       end
53     }
54   end
55
56   def cleanup
57     @lists.clear
58     @changed.clear
59     super
60   end
61
62   def lastquote(channel)
63     @lists[channel].length-1
64   end
65
66   def addquote(source, channel, quote)
67     @lists[channel] = Array.new if(!@lists.has_key?(channel))
68     num = @lists[channel].length
69     @lists[channel][num] = Quote.new(num, Time.new, source.fullform, quote)
70     @changed[channel] = true
71     return num
72   end
73
74   def getquote(source, channel, num=nil)
75     return nil unless(@lists.has_key?(channel))
76     return nil unless(@lists[channel].length > 0)
77     if(num)
78       if(@lists[channel][num])
79         return @lists[channel][num], @lists[channel].length - 1
80       end
81     else
82       # random quote
83       return @lists[channel].compact[rand(@lists[channel].nitems)],
84       @lists[channel].length - 1
85     end
86   end
87
88   def delquote(channel, num)
89     return false unless(@lists.has_key?(channel))
90     return false unless(@lists[channel].length > 0)
91     if(@lists[channel][num])
92       @lists[channel][num] = nil
93       @lists[channel].pop if num == @lists[channel].length - 1
94       @changed[channel] = true
95       return true
96     end
97     return false
98   end
99
100   def countquote(source, channel=nil, regexp=nil)
101     unless(channel)
102       total=0
103       @lists.each_value {|l|
104         total += l.compact.length
105       }
106       return total
107     end
108     return 0 unless(@lists.has_key?(channel))
109     return 0 unless(@lists[channel].length > 0)
110     if(regexp)
111       matches = @lists[channel].compact.find_all {|a| a.quote =~ /#{regexp}/i }
112     else
113       matches = @lists[channel].compact
114     end
115     return matches.length
116   end
117
118   def searchquote(source, channel, regexp)
119     return nil unless(@lists.has_key?(channel))
120     return nil unless(@lists[channel].length > 0)
121     matches = @lists[channel].compact.find_all {|a| a.quote =~ /#{regexp}/i }
122     if(matches.length > 0)
123       return matches[rand(matches.length)], @lists[channel].length - 1
124     else
125       return nil
126     end
127   end
128
129   def listquotes(source, channel, regexp)
130     return nil unless(@lists.has_key?(channel))
131     return nil unless(@lists[channel].length > 0)
132     matches = @lists[channel].compact.find_all {|a| a.quote =~ /#{regexp}/i }
133     if matches.length > 0
134       return matches
135     else
136       return nil
137     end
138   end
139
140   def help(plugin, topic="")
141     case plugin
142     when "addquote"
143       _("addquote [<channel>] <quote> => Add quote <quote> for channel <channel>. You only need to supply <channel> if you are addressing %{nick} privately.") % { :nick => @bot.nick }
144     when "delquote"
145       _("delquote [<channel>] <num> => delete quote from <channel> with number <num>. You only need to supply <channel> if you are addressing %{nick} privately.") % { :nick => @bot.nick }
146     when "getquote"
147       _("getquote [<channel>] [<num>] => get quote from <channel> with number <num>. You only need to supply <channel> if you are addressing %{nick} privately. Without <num>, a random quote will be returned.") % { :nick => @bot.nick }
148     when "searchquote"
149       _("searchquote [<channel>] <regexp> => search for quote from <channel> that matches <regexp>. You only need to supply <channel> if you are addressing %{nick} privately.") % { :nick => @bot.nick }
150     when "listquotes"
151       _("listquotes [<channel>] <regexp> => list the quotes from <channel> that match <regexp>. You only need to supply <channel> if you are addressing %{nick} privately.") % { :nick => @bot.nick }
152     when "topicquote"
153       _("topicquote [<channel>] [<num>] => set topic to quote from <channel> with number <num>. You only need to supply <channel> if you are addressing %{nick} privately. Without <num>, a random quote will be set.") % { :nick => @bot.nick }
154     when "countquote"
155       _("countquote [<channel>] <regexp> => count quotes from <channel> that match <regexp>. You only need to supply <channel> if you are addressing %{nick} privately.") % { :nick => @bot.nick }
156     when "whoquote"
157       _("whoquote [<channel>] <num> => show who added quote <num>. You only need to supply <channel> if you are addressing %{nick} privately") % { :nick => @bot.nick }
158     when "whenquote"
159       _("whenquote [<channel>] <num> => show when quote <num> was added. You only need to supply <channel> if you are addressing %{nick} privately") % { :nick => @bot.nick }
160     when "lastquote"
161       _("lastquote [<channel>] => show the last quote in a given channel. You only need to supply <channel> if you are addressing %{nick} privately") % { :nick => @bot.nick }
162     else
163       _("Quote module (Quote storage and retrieval) topics: addquote, delquote, getquote, searchquote, listquotes, topicquote, countquote, whoquote, whenquote, lastquote") % { :nick => @bot.nick }
164     end
165   end
166
167   def cmd_addquote(m, p)
168     channel = p[:channel] || m.channel.to_s
169     quote = p[:quote].to_s
170     num = addquote(m.source, channel, quote)
171     m.reply _("added the quote (#%{num})") % { :num => num }
172   end
173
174   def cmd_delquote(m, p)
175     channel = p[:channel] || m.channel.to_s
176     num = p[:num].to_i
177     if delquote(channel, num)
178       m.okay
179     else
180       m.reply _("quote not found!")
181     end
182   end
183
184   def cmd_getquote(m, p)
185     channel = p[:channel] || m.channel.to_s
186     num = p[:num] ? p[:num].to_i : nil
187     quote, total = getquote(m.source, channel, num)
188     if quote
189       m.reply _("[%{num}] %{quote}") % {
190         :num => quote.num,
191         :quote => quote.quote
192       }
193     else
194       m.reply _("quote not found!")
195     end
196   end
197
198   def cmd_whoquote(m, p)
199     channel = p[:channel] || m.channel.to_s
200     num = p[:num] ? p[:num].to_i : nil
201     quote, total = getquote(m.source, channel, num)
202     if quote
203       m.reply _("quote %{num} added by %{source}") % {
204         :num => quote.num,
205         :source => quote.source
206       }
207     else
208       m.reply _("quote not found!")
209     end
210   end
211
212   def cmd_whenquote(m, p)
213     channel = p[:channel] || m.channel.to_s
214     num = p[:num] ? p[:num].to_i : nil
215     quote, total = getquote(m.source, channel, num)
216     if quote
217       m.reply _("quote %{num} added on %{date}") % {
218         :num => quote.num,
219         :date => quote.date
220       }
221     else
222       m.reply _("quote not found!")
223     end
224   end
225
226   def cmd_searchquote(m, p)
227     channel = p[:channel] || m.channel.to_s
228     reg = p[:reg].to_s
229     quote, total = searchquote(m.source, channel, reg)
230     if quote
231       m.reply _("[%{num}] %{quote}") % {
232         :num => quote.num,
233         :quote => quote.quote
234       }
235     else
236       m.reply _("quote not found!")
237     end
238   end
239
240   def cmd_listquotes(m, p)
241     channel = p[:channel] || m.channel.to_s
242     reg = p[:reg].to_s
243     if quotes = listquotes(m.source, channel, reg)
244       m.reply _("%{total} quotes matching %{reg} found: %{list}") % {
245         :total => quotes.size,
246         :reg => reg,
247         :list => quotes.map {|q| q.num }.join(', ')
248       }
249     else
250       m.reply _("quote not found!")
251     end
252   end
253
254   def cmd_countquote(m, p)
255     channel = p[:channel] || m.channel.to_s
256     reg = p[:reg] ? p[:reg].to_s : nil
257     total = countquote(m.source, channel, reg)
258     if reg.length > 0
259       m.reply _("%{total} quotes matching %{reg}") % {
260         :total => total,
261         :reg => reg
262       }
263     else
264       m.reply _("%{total} quotes") % { :total => total }
265     end
266   end
267
268   def cmd_topicquote(m, p)
269     channel = p[:channel] || m.channel.to_s
270     num = p[:num] ? p[:num].to_i : nil
271     quote, total = getquote(m.source, channel, num)
272     if quote
273       @bot.topic channel, _("[%{num}] %{quote}") % {
274         :num => quote.num,
275         :quote => quote.quote
276       }
277     else
278       m.reply _("quote not found!")
279     end
280   end
281
282   def cmd_lastquote(m, p)
283     channel = p[:channel] || m.channel.to_s
284     quote, total = getquote(m.source, channel, lastquote(channel))
285     if quote
286       m.reply _("[%{num}] %{quote}") % {
287         :num => quote.num,
288         :quote => quote.quote
289       }
290     else
291       m.reply _("quote not found!")
292     end
293   end
294 end
295
296 plugin = QuotePlugin.new
297 plugin.register("quotes")
298
299 plugin.default_auth('other::edit', false) # Prevent random people from editing other channels quote lists by default
300 plugin.default_auth('other::view', true) # But allow them to view them
301
302 plugin.map "addquote :channel *quote", :action => :cmd_addquote, :requirements => { :channel => Regexp::Irc::GEN_CHAN }, :auth_path => '!quote::other::edit::add!'
303 plugin.map "delquote :channel :num", :action => :cmd_delquote, :requirements => { :channel => Regexp::Irc::GEN_CHAN, :num => /^\d+$/ }, :auth_path => '!quote::other::edit::del!'
304 plugin.map "getquote :channel [:num]", :action => :cmd_getquote, :requirements => { :channel => Regexp::Irc::GEN_CHAN, :num => /^\d+$/ }, :auth_path => '!quote::other::view::get!'
305 plugin.map "whoquote :channel :num", :action => :cmd_whoquote, :requirements => { :channel => Regexp::Irc::GEN_CHAN, :num => /^\d+$/ }, :auth_path => '!quote::other::view::who!'
306 plugin.map "whenquote :channel :num", :action => :cmd_whenquote, :requirements => { :channel => Regexp::Irc::GEN_CHAN, :num => /^\d+$/ }, :auth_path => '!quote::other::view::when!'
307 plugin.map "searchquote :channel *reg", :action => :cmd_searchquote, :requirements => { :channel => Regexp::Irc::GEN_CHAN }, :auth_path => '!quote::other::view::search!'
308 plugin.map "listquotes :channel *reg", :action => :cmd_listquotes, :requirements => { :channel => Regexp::Irc::GEN_CHAN }, :auth_path => '!quote::other::view::list!'
309 plugin.map "countquote :channel [*reg]", :action => :cmd_countquote, :requirements => { :channel => Regexp::Irc::GEN_CHAN }, :auth_path => '!quote::other::view::count!'
310 plugin.map "topicquote :channel [:num]", :action => :cmd_topicquote, :requirements => { :channel => Regexp::Irc::GEN_CHAN, :num => /^\d+$/ }, :auth_path => '!quote::other::topic!'
311 plugin.map "lastquote :channel", :action => :cmd_lastquote, :requirements => { :channel => Regexp::Irc::GEN_CHAN }, :auth_path => '!quote::other::view::last!'
312
313 plugin.default_auth('edit', false) # Prevent random people from removing quotes
314 plugin.default_auth('edit::add', true) # But allow them to add them
315
316 plugin.map "addquote *quote", :action => :cmd_addquote, :private => false, :auth_path => '!quote::edit::add!'
317 plugin.map "delquote :num", :action => :cmd_delquote, :private => false, :requirements => { :num => /^\d+$/ }, :auth_path => '!quote::edit::del!'
318 plugin.map "getquote [:num]", :action => :cmd_getquote, :private => false, :requirements => { :num => /^\d+$/ }, :auth_path => '!quote::view::get!'
319 plugin.map "whoquote :num", :action => :cmd_whoquote, :private => false, :requirements => { :num => /^\d+$/ }, :auth_path => '!quote::view::who!'
320 plugin.map "whenquote :num", :action => :cmd_whenquote, :private => false, :requirements => { :num => /^\d+$/ }, :auth_path => '!quote::view::when!'
321 plugin.map "searchquote *reg", :action => :cmd_searchquote, :private => false, :auth_path => '!quote::view::search!'
322 plugin.map "listquotes *reg", :action => :cmd_listquotes, :private => false, :auth_path => '!quote::view::list!'
323 plugin.map "countquote [*reg]", :action => :cmd_countquote, :private => false, :auth_path => '!quote::view::count!'
324 plugin.map "topicquote [:num]", :action => :cmd_topicquote, :private => false, :requirements => { :num => /^\d+$/ }, :auth_path => '!quote::topic!'
325 plugin.map "lastquote", :action => :cmd_lastquote, :private => false, :auth_path => '!quote::view::last!'
326