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')"
7 BotConfig.register BotConfigBooleanValue.new('core.reply_with_nick',
8 :default => false, :wizard => true,
9 :desc => "if true, the bot will prepend the nick to what he has to say when replying (e.g. 'markey: you can't do that!')"
12 BotConfig.register BotConfigStringValue.new('core.nick_postfix',
13 :default => ':', :wizard => true,
14 :desc => "when replying with nick put this character after the nick of the user the bot is replying to"
22 ColorRx = /#{Color}\d?\d?(?:,\d\d?)?/
24 # base user message class, all user messages derive from this
25 # (a user message is defined as having a source hostmask, a target
26 # nick/channel and a message part)
27 class BasicUserMessage
35 # when the message was received
38 # User that originated the message
41 # User/Channel message was sent to
44 # contents of the message
45 attr_accessor :message
47 # has the message been replied to/handled by a plugin?
48 attr_accessor :replied
50 # instantiate a new Message
51 # bot:: associated bot class
52 # server:: Server where the message took place
53 # source:: User that sent the message
54 # target:: User/Channel is destined for
55 # message:: actual message
56 def initialize(bot, server, source, target, message)
57 @msg_wants_id = false unless defined? @msg_wants_id
64 @message = BasicUserMessage.stripcolour message
69 if @msg_wants_id && @server.capabilities[:"identify-msg"]
70 if @message =~ /^([-+])(.*)/
71 @identified = ($1=="+")
74 warning "Message does not have identification"
78 if target && target == @bot.myself
84 # Access the nick of the source
90 # Access the user@host of the source
93 "#{@source.user}@#{@source.host}"
96 # Was the message from an identified user?
101 # returns true if the message was addressed to the bot.
102 # This includes any private message to the bot, or any public message
103 # which looks like it's addressed to the bot, e.g. "bot: foo", "bot, foo",
104 # a kick message when bot was kicked etc.
109 # has this message been replied to by a plugin?
114 # strip mIRC colour escapes from a string
115 def BasicUserMessage.stripcolour(string)
116 return "" unless string
117 ret = string.gsub(ColorRx, "")
118 #ret.tr!("\x00-\x1f", "")
124 # class for handling IRC user messages. Includes some utilities for handling
125 # the message, for example in plugins.
126 # The +message+ member will have any bot addressing "^bot: " removed
127 # (address? will return true in this case)
128 class UserMessage < BasicUserMessage
130 # for plugin messages, the name of the plugin invoked by the message
133 # for plugin messages, the rest of the message, with the plugin name
137 # convenience member. Who to reply to (i.e. would be sourcenick for a
138 # privately addressed message, or target (the channel) for a publicly
142 # channel the message was in, nil for privately addressed messages
145 # for PRIVMSGs, true if the message was a CTCP ACTION (CTCP stuff
146 # will be stripped from the message)
149 # instantiate a new UserMessage
150 # bot:: associated bot class
151 # source:: hostmask of the message source
152 # target:: nick/channel message is destined for
153 # message:: message part
154 def initialize(bot, server, source, target, message)
155 super(bot, server, source, target, message)
161 if target == @bot.myself
171 # check for option extra addressing prefixes, e.g "|search foo", or
172 # "!version" - first match wins
173 bot.config['core.address_prefix'].each {|mprefix|
174 if @message.gsub!(/^#{Regexp.escape(mprefix)}\s*/, "")
180 # even if they used above prefixes, we allow for silly people who
181 # combine all possible types, e.g. "|rbot: hello", or
182 # "/msg rbot rbot: hello", etc
183 if @message.gsub!(/^\s*#{Regexp.escape(bot.nick)}\s*([:;,>]|\s)\s*/i, "")
187 if(@message =~ /^\001ACTION\s(.+)\001/)
192 # free splitting for plugins
193 @params = @message.dup
194 if @params.gsub!(/^\s*(\S+)[\s$]*/, "")
195 @plugin = $1.downcase
196 @params = nil unless @params.length > 0
200 # returns true for private messages, e.g. "/msg bot hello"
205 # returns true if the message was in a channel
214 # convenience method to reply to a message, useful in plugins. It's the
216 # <tt>@bot.say m.replyto, string</tt>
217 # So if the message is private, it will reply to the user. If it was
218 # in a channel, it will reply in the channel.
219 def plainreply(string, options={})
220 @bot.say @replyto, string, options
224 # Same as reply, but when replying in public it adds the nick of the user
225 # the bot is replying to
226 def nickreply(string, options={})
227 extra = self.public? ? "#{@source}#{@bot.config['core.nick_postfix']} " : ""
228 @bot.say @replyto, extra + string, options
232 # the default reply style is to nickreply unless the reply already contains
233 # the nick or core.reply_with_nick is set to false
235 def reply(string, options={})
236 if @bot.config['core.reply_with_nick'] and not string =~ /\b#{@source}\b/
237 return nickreply(string, options)
239 plainreply(string, options)
242 # convenience method to reply to a message with an action. It's the
244 # <tt>@bot.action m.replyto, string</tt>
245 # So if the message is private, it will reply to the user. If it was
246 # in a channel, it will reply in the channel.
247 def act(string, options={})
248 @bot.action @replyto, string, options
252 # convenience method to reply "okay" in the current language to the
255 self.plainreply @bot.lang.get("okay")
258 # Like the above, but append the username
260 str = @bot.lang.get("okay").dup
262 # remove final punctuation
263 str.gsub!(/[!,.]$/,"")
264 str += ", #{@source}"
269 # the default okay style is the same as the default reply style
272 if @bot.config['core.reply_with_nick']
280 # class to manage IRC PRIVMSGs
281 class PrivMessage < UserMessage
282 def initialize(bot, server, source, target, message)
288 # class to manage IRC NOTICEs
289 class NoticeMessage < UserMessage
290 def initialize(bot, server, source, target, message)
296 # class to manage IRC KICKs
297 # +address?+ can be used as a shortcut to see if the bot was kicked,
298 # basically, +target+ was kicked from +channel+ by +source+ with +message+
299 class KickMessage < BasicUserMessage
300 # channel user was kicked from
303 def initialize(bot, server, source, target, channel, message="")
304 super(bot, server, source, target, message)
309 # class to pass IRC Nick changes in. @message contains the old nickame,
310 # @sourcenick contains the new one.
311 class NickMessage < BasicUserMessage
312 def initialize(bot, server, source, oldnick, newnick)
313 super(bot, server, source, oldnick, newnick)
325 class QuitMessage < BasicUserMessage
326 def initialize(bot, server, source, target, message="")
327 super(bot, server, source, target, message)
331 class TopicMessage < BasicUserMessage
334 # topic set at (unixtime)
335 attr_reader :timestamp
336 # topic set on channel
339 def initialize(bot, server, source, channel, topic=ChannelTopic.new)
340 super(bot, server, source, channel, topic.text)
342 @timestamp = topic.set_on
347 # class to manage channel joins
348 class JoinMessage < BasicUserMessage
351 def initialize(bot, server, source, channel, message="")
352 super(bot, server, source, channel, message)
354 # in this case sourcenick is the nick that could be the bot
355 @address = (source == @bot.myself)
359 # class to manage channel parts
360 # same as a join, but can have a message too
361 class PartMessage < JoinMessage