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