Two plugins had the executable property set. Reset it
[rbot] / data / rbot / plugins / topic.rb
1 # Author: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>
2 # Add a bunch of topic manipulation features
3
4 class TopicPlugin < Plugin
5   def initialize
6     super
7     @separator = "|" # default separator
8   end
9
10   def help(plugin, topic="")
11     case plugin
12     when "topic"
13       case topic
14       when "add"
15         return "topic add <text> => add <text> at the end the topic"
16       when "prepend"
17         return "topic prepend <text> => add <text> at the beginning of the topic"
18       when "addat"
19         return "topic addat <num> <text> => add <text> at position <num> of the topic"
20       when "del", "delete"
21         return "topic del <num> => remove section <num> from the topic"
22       when "replace"
23         return "topic replace <num> <text> => Replaces section <num> with <text>"
24       when "sep", "separator"
25         return "topic sep(arator) [<text>] => get or set the topic section separator"
26       when "learn"
27         return "topic learn => remembers the topic for later"
28       when "restore"
29         return "topic restore => resets the topic to the latest remembered one"
30       when "clear"
31         return "topic clear => clears the topic"
32       when "set"
33         return "topic set <text> => sets the topic to <text>"
34       when "undo"
35         return "topic undo => undoes the latest change to the topic"
36       else
37         return "topic add(at)|prepend|del(ete)|replace|sep(arator)|learn|restore|clear|set|undo: " + \
38                "manipulate the topic of the current channel; use topic <#channel> <command> " + \
39                "for private addressing"
40       end
41     end
42   end
43
44   def handletopic(m, param)
45     return unless m.kind_of?(PrivMessage)
46     if m.public?
47       ch = m.channel
48     else
49       ch = m.server.get_channel(param[:channel])
50       unless ch
51         m.reply("I am not in channel #{param[:channel]}")
52         return
53       end
54     end
55     cmd = param[:command]
56     txt = param[:text].to_s
57
58     case cmd
59     when /^a(dd|ppend)$/
60       topicappend(m, ch, txt)
61     when 'prepend'
62       topicprepend(m, ch, txt)
63     when 'addat'
64       if txt =~ /\s*(-?\d+)\s+(.*)\s*/
65         num = $1.to_i - 1
66         num += 1 if num < 0
67         txt = $2
68         topicaddat(m, ch, num, txt)
69       end
70     when /^del(ete)?$/
71       if txt =~ /\s*(-?\d+)\s*/
72         num=$1.to_i - 1
73         num += 1 if num < 0
74         topicdel(m, ch, num)
75       end
76     when 'set'
77       topicset(m, ch, txt)
78     when 'clear'
79       topicset(m, ch, '')
80     when /^sep(arator)?$/
81       topicsep(m, ch, txt)
82     when 'learn'
83       learntopic(m, ch)
84     when 'replace'
85       if txt =~ /\s*(-?\d+)\s+(.*)\s*/
86         num = $1.to_i - 1
87         num += 1 if num < 0
88         txt = $2
89         replacetopic(m, ch, num, txt)
90       end
91     when 'restore'
92       restoretopic(m, ch)
93     when 'undo'
94       undotopic(m, ch)
95     else
96       m.reply 'unknown command'
97     end
98   end
99
100   def topicsep(m, ch, txt)
101     return if !@bot.auth.allow?("topic::edit::separator", m.source, m.replyto)
102     if txt
103       sep = txt.strip
104       if sep != ""
105         setsep(ch, sep)
106       end
107     end
108     m.reply "Topic separator set to #{getsep(ch)}"
109   end
110
111   def setsep(ch, sep)
112     raise unless ch.class <= Irc::Channel
113     # TODO multiserver
114     k = ch.downcase
115
116     if @registry.has_key?(k)
117       data = @registry[k]
118     else
119       data = Hash.new
120     end
121
122     oldsep = getsep(ch)
123     topic = ch.topic.text
124     topicarray = topic.split(/\s+#{Regexp.escape(oldsep)}\s*/)
125
126     if sep != oldsep and topicarray.length > 0
127       newtopic = topicarray.join(" #{sep} ")
128       @bot.topic ch, newtopic if newtopic != topic
129     end
130
131     data[:separator] = sep
132     @registry[k] = data
133   end
134
135   def getsep(ch)
136     raise unless ch.class <= Irc::Channel
137     # TODO multiserver
138     k = ch.downcase
139
140     if @registry.has_key?(k)
141       if @registry[k].has_key?(:separator)
142         return @registry[k][:separator]
143       end
144     end
145     return @separator
146   end
147
148   def topicaddat(m, ch, num, txt)
149     return if !@bot.auth.allow?("topic::edit::add", m.source, m.replyto)
150     sep = getsep(ch)
151     topic = ch.topic.text
152     topicarray = topic.split(/\s+#{Regexp.escape(sep)}\s*/)
153     topicarray.insert(num, txt)
154     newtopic = topicarray.join(" #{sep} ")
155     changetopic(m, ch, newtopic)
156   end
157
158   def topicappend(m, ch, txt)
159     topicaddat(m, ch, -1, txt)
160   end
161
162   def topicprepend(m, ch, txt)
163     topicaddat(m, ch, 0, txt)
164   end
165
166   def topicdel(m, ch, num)
167     return if !@bot.auth.allow?("topic::edit::del", m.source, m.replyto)
168     sep = getsep(ch)
169     topic = ch.topic.text
170     topicarray = topic.split(/\s+#{Regexp.escape(sep)}\s*/)
171     topicarray.delete_at(num)
172     newtopic = topicarray.join(" #{sep} ")
173     changetopic(m, ch, newtopic)
174   end
175
176   def learntopic(m, ch)
177     return if !@bot.auth.allow?("topic::store::store", m.source, m.replyto)
178     topic = ch.topic.text
179     k = ch.downcase
180     if @registry.has_key?(k)
181       data = @registry[k]
182     else
183       data = Hash.new
184     end
185     data[:topic] = topic
186     @registry[k] = data
187     m.okay
188   end
189
190   def replacetopic(m, ch, num, txt)
191     return if !@bot.auth.allow?("topic::edit::replace", m.source, m.replyto)
192     sep = getsep(ch)
193     topic = ch.topic.text
194     topicarray = topic.split(/\s+#{Regexp.escape(sep)}\s*/)
195     topicarray[num] = txt
196     newtopic = topicarray.join(" #{sep} ")
197     changetopic(m, ch, newtopic)
198   end
199
200   def restoretopic(m, ch)
201     return if !@bot.auth.allow?("topic::store::restore", m.source, m.replyto)
202     k = ch.downcase
203     if @registry.has_key?(k) && @registry[k].has_key?(:topic)
204       topic = @registry[k][:topic]
205       topicset(m, ch, topic)
206     else
207       m.reply "I don't remember any topic for #{ch}"
208     end
209   end
210
211   def topicset(m, ch, text)
212     return if !@bot.auth.allow?("topic::edit::replace", m.source, m.replyto)
213     changetopic(m, ch, text)
214   end
215
216   # This method changes the topic on channel +ch+ to +text+, storing
217   # the previous topic for undo
218   def changetopic(m, ch, text)
219     k = ch.downcase
220     if @registry.has_key?(k)
221       data = @registry[k]
222     else
223       data = Hash.new
224     end
225
226     data[:oldtopic] = ch.topic.text
227     @registry[k] = data
228
229     @bot.topic ch, text
230   end
231
232   def undotopic(m, ch)
233     k = ch.downcase
234     if @registry.has_key?(k)
235       data = @registry[k]
236       if data.has_key?(:oldtopic)
237         changetopic(m, ch, data[:oldtopic].dup)
238         return
239       end
240     end
241
242     m.reply "No recent changes were recorded for #{ch}"
243   end
244
245 end
246 plugin = TopicPlugin.new
247
248 plugin.map 'topic :command [*text]', :action => 'handletopic', :public => true, :private => false
249 plugin.map 'topic :channel :command [*text]', :action => 'handletopic', :public => false, :private => true
250
251 plugin.default_auth('*', false)
252
253