]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - lib/rbot/message.rb
Fix a warning introduced with [245]
[user/henk/code/ruby/rbot.git] / lib / rbot / message.rb
1 module Irc
2   BotConfig.register BotConfigArrayValue.new('core.address_prefix',
3     :default => [], :wizard => true,
4     :desc => "what non nick-matching prefixes should the bot respond to as if addressed (e.g !, so that '!foo' is treated like 'rbot: foo')"
5   )
6
7   # base user message class, all user messages derive from this
8   # (a user message is defined as having a source hostmask, a target
9   # nick/channel and a message part)
10   class BasicUserMessage
11
12     # associated bot
13     attr_reader :bot
14
15     # when the message was received
16     attr_reader :time
17
18     # hostmask of message source
19     attr_reader :source
20
21     # nick of message source
22     attr_reader :sourcenick
23
24     # url part of message source
25     attr_reader :sourceaddress
26
27     # nick/channel message was sent to
28     attr_reader :target
29
30     # contents of the message
31     attr_accessor :message
32
33     # has the message been replied to/handled by a plugin?
34     attr_accessor :replied
35
36     # instantiate a new Message
37     # bot::      associated bot class
38     # source::   hostmask of the message source
39     # target::   nick/channel message is destined for
40     # message::  message part
41     def initialize(bot, source, target, message)
42       @msg_wants_id = false unless defined? @msg_wants_id
43
44       @time = Time.now
45       @bot = bot
46       @source = source
47       @address = false
48       @target = target
49       @message = BasicUserMessage.stripcolour message
50       @replied = false
51
52       @identified = false
53       if @msg_wants_id && @bot.capabilities["identify-msg".to_sym]
54         if @message =~ /([-+])(.*)/
55           @identified = ($1=="+")
56           @message = $2
57         else
58           warning "Message does not have identification"
59         end
60       end
61
62       # split source into consituent parts
63       if source =~ /^((\S+)!(\S+))$/
64         @sourcenick = $2
65         @sourceaddress = $3
66       end
67
68       if target && target.downcase == @bot.nick.downcase
69         @address = true
70       end
71
72     end
73
74     def identified?
75       return @identified
76     end
77
78     # returns true if the message was addressed to the bot.
79     # This includes any private message to the bot, or any public message
80     # which looks like it's addressed to the bot, e.g. "bot: foo", "bot, foo",
81     # a kick message when bot was kicked etc.
82     def address?
83       return @address
84     end
85
86     # has this message been replied to by a plugin?
87     def replied?
88       return @replied
89     end
90
91     # strip mIRC colour escapes from a string
92     def BasicUserMessage.stripcolour(string)
93       return "" unless string
94       ret = string.gsub(/\cC\d\d?(?:,\d\d?)?/, "")
95       #ret.tr!("\x00-\x1f", "")
96       ret
97     end
98
99   end
100
101   # class for handling IRC user messages. Includes some utilities for handling
102   # the message, for example in plugins.
103   # The +message+ member will have any bot addressing "^bot: " removed
104   # (address? will return true in this case)
105   class UserMessage < BasicUserMessage
106
107     # for plugin messages, the name of the plugin invoked by the message
108     attr_reader :plugin
109
110     # for plugin messages, the rest of the message, with the plugin name
111     # removed
112     attr_reader :params
113
114     # convenience member. Who to reply to (i.e. would be sourcenick for a
115     # privately addressed message, or target (the channel) for a publicly
116     # addressed message
117     attr_reader :replyto
118
119     # channel the message was in, nil for privately addressed messages
120     attr_reader :channel
121
122     # for PRIVMSGs, true if the message was a CTCP ACTION (CTCP stuff
123     # will be stripped from the message)
124     attr_reader :action
125
126     # instantiate a new UserMessage
127     # bot::      associated bot class
128     # source::   hostmask of the message source
129     # target::   nick/channel message is destined for
130     # message::  message part
131     def initialize(bot, source, target, message)
132       super(bot, source, target, message)
133       @target = target
134       @private = false
135       @plugin = nil
136       @action = false
137
138       if target.downcase == @bot.nick.downcase
139         @private = true
140         @address = true
141         @channel = nil
142         @replyto = @sourcenick
143       else
144         @replyto = @target
145         @channel = @target
146       end
147
148       # check for option extra addressing prefixes, e.g "|search foo", or
149       # "!version" - first match wins
150       bot.config['core.address_prefix'].each {|mprefix|
151         if @message.gsub!(/^#{Regexp.escape(mprefix)}\s*/, "")
152           @address = true
153           break
154         end
155       }
156
157       # even if they used above prefixes, we allow for silly people who
158       # combine all possible types, e.g. "|rbot: hello", or
159       # "/msg rbot rbot: hello", etc
160       if @message.gsub!(/^\s*#{Regexp.escape(bot.nick)}\s*([:;,>]|\s)\s*/i, "")
161         @address = true
162       end
163
164       if(@message =~ /^\001ACTION\s(.+)\001/)
165         @message = $1
166         @action = true
167       end
168
169       # free splitting for plugins
170       @params = @message.dup
171       if @params.gsub!(/^\s*(\S+)[\s$]*/, "")
172         @plugin = $1.downcase
173         @params = nil unless @params.length > 0
174       end
175     end
176
177     # returns true for private messages, e.g. "/msg bot hello"
178     def private?
179       return @private
180     end
181
182     # returns true if the message was in a channel
183     def public?
184       return !@private
185     end
186
187     def action?
188       return @action
189     end
190
191     # convenience method to reply to a message, useful in plugins. It's the
192     # same as doing:
193     # <tt>@bot.say m.replyto, string</tt>
194     # So if the message is private, it will reply to the user. If it was
195     # in a channel, it will reply in the channel.
196     def reply(string)
197       @bot.say @replyto, string
198       @replied = true
199     end
200
201     # convenience method to reply "okay" in the current language to the
202     # message
203     def okay
204       @bot.say @replyto, @bot.lang.get("okay")
205     end
206
207   end
208
209   # class to manage IRC PRIVMSGs
210   class PrivMessage < UserMessage
211     def initialize(bot, source, target, message)
212       @msg_wants_id = true
213       super
214     end
215   end
216
217   # class to manage IRC NOTICEs
218   class NoticeMessage < UserMessage
219     def initialize(bot, source, target, message)
220       @msg_wants_id = true
221       super
222     end
223   end
224
225   # class to manage IRC KICKs
226   # +address?+ can be used as a shortcut to see if the bot was kicked,
227   # basically, +target+ was kicked from +channel+ by +source+ with +message+
228   class KickMessage < BasicUserMessage
229     # channel user was kicked from
230     attr_reader :channel
231
232     def initialize(bot, source, target, channel, message="")
233       super(bot, source, target, message)
234       @channel = channel
235     end
236   end
237
238   # class to pass IRC Nick changes in. @message contains the old nickame,
239   # @sourcenick contains the new one.
240   class NickMessage < BasicUserMessage
241     def initialize(bot, source, oldnick, newnick)
242       super(bot, source, oldnick, newnick)
243     end
244   end
245
246   class QuitMessage < BasicUserMessage
247     def initialize(bot, source, target, message="")
248       super(bot, source, target, message)
249     end
250   end
251
252   class TopicMessage < BasicUserMessage
253     # channel topic
254     attr_reader :topic
255     # topic set at (unixtime)
256     attr_reader :timestamp
257     # topic set on channel
258     attr_reader :channel
259
260     def initialize(bot, source, channel, timestamp, topic="")
261       super(bot, source, channel, topic)
262       @topic = topic
263       @timestamp = timestamp
264       @channel = channel
265     end
266   end
267
268   # class to manage channel joins
269   class JoinMessage < BasicUserMessage
270     # channel joined
271     attr_reader :channel
272     def initialize(bot, source, channel, message="")
273       super(bot, source, channel, message)
274       @channel = channel
275       # in this case sourcenick is the nick that could be the bot
276       @address = (sourcenick.downcase == @bot.nick.downcase)
277     end
278   end
279
280   # class to manage channel parts
281   # same as a join, but can have a message too
282   class PartMessage < JoinMessage
283   end
284 end