class Cinch::Message

This class serves two purposes. For one, it simply represents incoming messages and allows for querying various details (who sent the message, what kind of message it is, etc).

At the same time, it allows responding to messages, which means sending messages to either users or channels.

Attributes

action_message[R]

@return [String, nil] The action message @since 2.0.0

bot[R]

@return [Bot] @since 1.1.0

channel[R]

@return [Channel] The channel in which this message was sent

command[R]

@return [String]

ctcp_args[R]

@return [Array<String>, nil]

ctcp_command[R]

@return [String, nil] the command part of an CTCP message

ctcp_message[R]

@return [String, nil] the CTCP message, without 001 control characters

error[R]

@return [Integer, nil] the numeric error code, if any

events[RW]

@return [Array<Symbol>]

message[R]

@return [String, nil]

params[R]

@return [Array<String>]

prefix[R]

@return [String]

raw[R]

@return [String]

server[R]

@return [String, nil]

statusmsg_mode[R]

The STATUSMSG mode a channel message was sent to.

Some IRC servers allow sending messages limited to people in a channel who have a certain mode. For example, by sending a message to `+#channel`, only people who are voiced, or have a higher mode (op) will receive the message.

This attribute contains the mode character the message was sent to, or nil if it was a normal message. For the previous example, this attribute would be set to `ā€œvā€`, for voiced.

@return [String, nil] @since 2.3.0

tags[R]

@return [Hash]

target[R]

@return [Target]

time[R]

@return [Time] @since 2.0.0

user[R]

@return [User] The user who sent this message

Public Class Methods

new(msg, bot) click to toggle source
# File lib/cinch/message.rb, line 88
def initialize(msg, bot)
  @raw     = msg
  @bot     = bot
  @matches = { ctcp: {}, action: {}, other: {} }
  @events  = []
  @time    = Time.now
  @statusmsg_mode = nil
  parse if msg
end

Public Instance Methods

action?() click to toggle source

@return [Boolean] true if the message is an action (/me) @since 2.0.0

# File lib/cinch/message.rb, line 150
def action?
  @ctcp_command == "ACTION"
end
action_reply(text) click to toggle source

Reply to a message with an action.

For its behaviour with regard to STATUSMSG, see {#reply}.

@param [String] text the action message @return [void]

# File lib/cinch/message.rb, line 213
def action_reply(text)
  text = text.to_s
  reply_target.action(text)
end
channel?() click to toggle source

@return [Boolean] true if this message was sent in a channel

# File lib/cinch/message.rb, line 139
def channel?
  !@channel.nil?
end
ctcp?() click to toggle source

@return [Boolean] true if the message is an CTCP message

# File lib/cinch/message.rb, line 144
def ctcp?
  !!(@params.last =~ /\001.+\001/)
end
ctcp_reply(answer) click to toggle source

Reply to a CTCP message

@return [void]

# File lib/cinch/message.rb, line 230
def ctcp_reply(answer)
  return unless ctcp?

  @user.notice "\001#{@ctcp_command} #{answer}\001"
end
error?() click to toggle source

@return [Boolean] true if the message describes an error

# File lib/cinch/message.rb, line 134
def error?
  !@error.nil?
end
match(regexp, type, strip_colors) click to toggle source

@api private @return [MatchData]

# File lib/cinch/message.rb, line 158
def match(regexp, type, strip_colors)
  text = ""
  case type
  when :ctcp
    text = ctcp_message
  when :action
    text = action_message
  else
    text = message.to_s
    type = :other
  end

  text = Cinch::Formatting.unformat(text) if strip_colors

  @matches[type][regexp] ||= text.match(regexp)
end
numeric_reply?() click to toggle source

@return [Boolean] true if the message is an numeric reply (as

opposed to a command)
# File lib/cinch/message.rb, line 129
def numeric_reply?
  !!@command.match(/^\d{3}$/)
end
parse() click to toggle source

@api private @return [void]

# File lib/cinch/message.rb, line 100
def parse
  match = @raw.match(/\A(?:@([^ ]+) )?(?::(\S+) )?(\S+)(.*)/)
  tags, @prefix, @command, raw_params = match.captures

  if @bot.irc.network.ngametv?
    @prefix = "%s!%s@%s" % [@prefix, @prefix, @prefix] if @prefix != "ngame"
  end

  @params  = parse_params(raw_params)
  @tags    = parse_tags(tags)

  @user    = parse_user
  @channel, @statusmsg_mode = parse_channel
  @target  = @channel || @user
  @server  = parse_server
  @error   = parse_error
  @message = parse_message

  @ctcp_message = parse_ctcp_message
  @ctcp_command = parse_ctcp_command
  @ctcp_args    = parse_ctcp_args

  @action_message = parse_action_message
end
reply(text, prefix = false) click to toggle source

Replies to a message, automatically determining if it was a channel or a private message.

If the message is a STATUSMSG, i.e. it was send to `+#channel` or `@#channel` instead of `#channel`, the reply will be sent as the same kind of STATUSMSG. See {#statusmsg_mode} for more information on STATUSMSG.

@param [String] text the message @param [Boolean] prefix if prefix is true and the message was in

a channel, the reply will be prefixed by the nickname of whoever
send the mesage

@return [void]

# File lib/cinch/message.rb, line 190
def reply(text, prefix = false)
  text = text.to_s
  text = text.split("\n").map { |l| "#{user.nick}: #{l}" }.join("\n") if @channel && prefix

  reply_target.send(text)
end
safe_action_reply(text) click to toggle source

Like {#action_reply}, but using {Target#safe_action} instead

@param (see action_reply) @return (see action_reply)

# File lib/cinch/message.rb, line 222
def safe_action_reply(text)
  text = text.to_s
  reply_target.safe_action(text)
end
safe_reply(text, prefix = false) click to toggle source

Like {#reply}, but using {Target#safe_send} instead

@param (see reply) @return (see reply)

# File lib/cinch/message.rb, line 201
def safe_reply(text, prefix = false)
  text = text.to_s
  text = "#{@user.nick}: #{text}" if channel && prefix
  reply_target.safe_send(text)
end
to_s() click to toggle source

@return [String] @since 1.1.0

# File lib/cinch/message.rb, line 240
def to_s
  "#<Cinch::Message @raw=#{@raw.chomp.inspect} @params=#{@params.inspect} channel=#{@channel.inspect} user=#{@user.inspect}>"
end

Private Instance Methods

parse_action_message() click to toggle source
# File lib/cinch/message.rb, line 384
def parse_action_message
  # has to be called after parse_ctcp_message
  return nil unless action?

  @ctcp_message.split(" ", 2).last
end
parse_channel() click to toggle source
# File lib/cinch/message.rb, line 308
def parse_channel
  # has to be called after parse_params
  return nil if @params.empty?

  case @command
  when "INVITE", Constants::RPL_CHANNELMODEIS.to_s, Constants::RPL_BANLIST.to_s
    @bot.channel_list.find_ensured(@params[1])
  when Constants::RPL_NAMEREPLY.to_s
    @bot.channel_list.find_ensured(@params[2])
  else
    # Note that this will also find channels for messages that
    # don't actually include a channel parameter. For example
    # `QUIT :#sometext` will be interpreted as a channel. The
    # alternative to the currently used heuristic would be to
    # hardcode a list of commands that provide a channel argument.
    ch, status = privmsg_channel_name(@params.first)
    if ch.nil? && numeric_reply? && @params.size > 1
      ch, status = privmsg_channel_name(@params[1])
    end
    return @bot.channel_list.find_ensured(ch), status if ch
  end
end
parse_ctcp_args() click to toggle source
# File lib/cinch/message.rb, line 377
def parse_ctcp_args
  # has to be called after parse_ctcp_message
  return unless ctcp?

  @ctcp_message.split(" ")[1..-1]
end
parse_ctcp_command() click to toggle source
# File lib/cinch/message.rb, line 370
def parse_ctcp_command
  # has to be called after parse_ctcp_message
  return unless ctcp?

  @ctcp_message.split(" ").first
end
parse_ctcp_message() click to toggle source
# File lib/cinch/message.rb, line 362
def parse_ctcp_message
  # has to be called after parse_params
  return unless ctcp?

  @params.last =~ /\001(.+)\001/
  Regexp.last_match(1)
end
parse_error() click to toggle source
# File lib/cinch/message.rb, line 349
def parse_error
  return @command.to_i if numeric_reply? && @command[/[45]\d\d/]
end
parse_message() click to toggle source
# File lib/cinch/message.rb, line 353
def parse_message
  # has to be called after parse_params
  if error?
    @error.to_s
  elsif regular_command?
    @params.last
  end
end
parse_params(raw_params) click to toggle source
# File lib/cinch/message.rb, line 257
def parse_params(raw_params)
  params = []
  if match = raw_params.match(/(?:^:| :)(.*)$/)
    params = match.pre_match.split(" ")
    params << match[1]
  else
    params = raw_params.split(" ")
  end

  params
end
parse_server() click to toggle source
# File lib/cinch/message.rb, line 342
def parse_server
  return unless @prefix
  return if @prefix =~ /[@!]/

  @prefix[/^(\S+)/, 1]
end
parse_tags(raw_tags) click to toggle source
# File lib/cinch/message.rb, line 269
def parse_tags(raw_tags)
  return {} if raw_tags.nil?

  def to_symbol(string)
    string.tr("-", "_").downcase.to_sym
  end

  tags = {}
  raw_tags.split(";").each do |tag|
    tag_name, tag_value = tag.split("=")
    if /,/.match?(tag_value)
      tag_value = tag_value.split(",")
    elsif tag_value.nil?
      tag_value = tag_name
    end
    if %r{/}.match?(tag_name)
      vendor, tag_name = tag_name.split("/")
      tags[to_symbol(vendor)] = {
        to_symbol(tag_name) => tag_value,
      }
    else
      tags[to_symbol(tag_name)] = tag_value
    end
  end
  tags
end
parse_user() click to toggle source
# File lib/cinch/message.rb, line 296
def parse_user
  return unless @prefix

  nick = @prefix[/^(\S+)!/, 1]
  user = @prefix[/^\S+!(\S+)@/, 1]
  host = @prefix[/@(\S+)$/, 1]

  return nil if nick.nil?

  @bot.user_list.find_ensured(user, nick, host)
end
privmsg_channel_name(s) click to toggle source
# File lib/cinch/message.rb, line 331
def privmsg_channel_name(s)
  chantypes = @bot.irc.isupport["CHANTYPES"]
  statusmsg = @bot.irc.isupport["STATUSMSG"]
  if statusmsg.include?(s[0]) && chantypes.include?(s[1])
    status = @bot.irc.isupport["PREFIX"].invert[s[0]]
    return s[1..-1], status
  elsif chantypes.include?(s[0])
    return s, nil
  end
end
regular_command?() click to toggle source
# File lib/cinch/message.rb, line 253
def regular_command?
  !numeric_reply? # a command can only be numeric or "regular"…
end
reply_target() click to toggle source
# File lib/cinch/message.rb, line 246
def reply_target
  return @target if @channel.nil? || @statusmsg_mode.nil?

  prefix = @bot.irc.isupport["PREFIX"][@statusmsg_mode]
  Target.new(prefix + @channel.name, @bot)
end
to_symbol(string) click to toggle source
# File lib/cinch/message.rb, line 272
def to_symbol(string)
  string.tr("-", "_").downcase.to_sym
end