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