IN_ON = /in|on/
- # We start with some IRC related regular expressions, used to match
- # Irc::User nicks and Irc::Channel names
- #
- # For each of them we define three versions of the regular expression:
- # * a generic one, which should match for any server but may turn out to
- # match more than a specific server would accept
- # * an RFC-compliant matcher
- # * TODO a server-specific one that uses the Irc::Server#supports method to build
- # a matcher valid for a particular server.
- #
module Irc
- CHAN_FIRST = /[#&+]/
- CHAN_SAFE = /![A-Z0-9]{5}/
- CHAN_ANY = /[^\x00\x07\x0A\x0D ,:]/
- GEN_CHAN = /(?:#{CHAN_FIRST}|#{CHAN_SAFE})#{CHAN_ANY}+/
- RFC_CHAN = /#{CHAN_FIRST}#{CHAN_ANY}{1,49}|#{CHAN_SAFE}#{CHAN_ANY}{1,44}/
-
+ # Match a list of channel anmes separated by optional commas, whitespace
+ # and optionally the word "and"
CHAN_LIST = Regexp.new_list(GEN_CHAN)
# Match "in #channel" or "on #channel" and/or "in private" (optionally
IN_CHAN_LIST_PVT_SFX = Regexp.new_list(/#{GEN_CHAN}|here|private|pvt/, IN_ON)
IN_CHAN_LIST_PVT = /#{IN_ON}\s+#{IN_CHAN_LIST_PVT_SFX}|anywhere|everywhere/
- SPECIAL_CHAR = /[\x5b-\x60\x7b-\x7d]/
- NICK_FIRST = /#{SPECIAL_CHAR}|[[:alpha:]]/
- NICK_ANY = /#{SPECIAL_CHAR}|[[:alnum:]]|-/
- GEN_NICK = /#{NICK_FIRST}#{NICK_ANY}+/
- RFC_NICK = /#{NICK_FIRST}#{NICK_ANY}{0,8}/
-
# Match a list of nicknames separated by optional commas, whitespace and
# optionally the word "and"
- NICK_LIST = Regexp.new_list(GEN_CHAN)
+ NICK_LIST = Regexp.new_list(GEN_NICK)
end
- # Next, some general purpose ones
- DIGITS = /\d+/
- HEX_DIGIT = /[0-9A-Fa-f]/
- HEX_DIGITS = /#{HEX_DIGIT}+/
- HEX_OCTET = /#{HEX_DIGIT}#{HEX_DIGIT}?/
- DEC_OCTET = /[01]?\d?\d|2[0-4]\d|25[0-5]/
- DEC_IP_ADDR = /#{DEC_OCTET}.#{DEC_OCTET}.#{DEC_OCTET}.#{DEC_OCTET}/
- HEX_IP_ADDR = /#{HEX_OCTET}.#{HEX_OCTET}.#{HEX_OCTET}.#{HEX_OCTET}/
- IP_ADDR = /#{DEC_IP_ADDR}|#{HEX_IP_ADDR}/
-
end
end\r
\r
\r
+# We extend the Regexp class with an Irc module which will contain some\r
+# Irc-specific regexps\r
+#\r
+class Regexp\r
+\r
+ # We start with some general-purpose ones which will be used in the\r
+ # Irc module too, but are useful regardless\r
+ DIGITS = /\d+/\r
+ HEX_DIGIT = /[0-9A-Fa-f]/\r
+ HEX_DIGITS = /#{HEX_DIGIT}+/\r
+ HEX_OCTET = /#{HEX_DIGIT}#{HEX_DIGIT}?/\r
+ DEC_OCTET = /[01]?\d?\d|2[0-4]\d|25[0-5]/\r
+ DEC_IP_ADDR = /#{DEC_OCTET}.#{DEC_OCTET}.#{DEC_OCTET}.#{DEC_OCTET}/\r
+ HEX_IP_ADDR = /#{HEX_OCTET}.#{HEX_OCTET}.#{HEX_OCTET}.#{HEX_OCTET}/\r
+ IP_ADDR = /#{DEC_IP_ADDR}|#{HEX_IP_ADDR}/\r
+\r
+ # IPv6, from Resolv::IPv6, without the \A..\z anchors\r
+ HEX_16BIT = /#{HEX_DIGIT}{1,4}/\r
+ IP6_8Hex = /(?:#{HEX_16BIT}:){7}#{HEX_16BIT}/\r
+ IP6_CompressedHex = /((?:#{HEX_16BIT}(?::#{HEX_16BIT})*)?)::((?:#{HEX_16BIT}(?::#{HEX_16BIT})*)?)/\r
+ IP6_6Hex4Dec = /((?:#{HEX_16BIT}:){6,6})#{DEC_IP_ADDR}/\r
+ IP6_CompressedHex4Dec = /((?:#{HEX_16BIT}(?::#{HEX_16BIT})*)?)::((?:#{HEX_16BIT}:)*)#{DEC_IP_ADDR}/\r
+ IP6_ADDR = /(?:#{IP6_8Hex})|(?:#{IP6_CompressedHex})|(?:#{IP6_6Hex4Dec})|(?:#{IP6_CompressedHex4Dec})/\r
+\r
+ # We start with some IRC related regular expressions, used to match\r
+ # Irc::User nicks and users and Irc::Channel names\r
+ #\r
+ # For each of them we define two versions of the regular expression:\r
+ # * a generic one, which should match for any server but may turn out to\r
+ # match more than a specific server would accept\r
+ # * an RFC-compliant matcher\r
+ #\r
+ module Irc\r
+\r
+ # Channel-name-matching regexps\r
+ CHAN_FIRST = /[#&+]/\r
+ CHAN_SAFE = /![A-Z0-9]{5}/\r
+ CHAN_ANY = /[^\x00\x07\x0A\x0D ,:]/\r
+ GEN_CHAN = /(?:#{CHAN_FIRST}|#{CHAN_SAFE})#{CHAN_ANY}+/\r
+ RFC_CHAN = /#{CHAN_FIRST}#{CHAN_ANY}{1,49}|#{CHAN_SAFE}#{CHAN_ANY}{1,44}/\r
+\r
+ # Nick-matching regexps\r
+ SPECIAL_CHAR = /[\x5b-\x60\x7b-\x7d]/\r
+ NICK_FIRST = /#{SPECIAL_CHAR}|[[:alpha:]]/\r
+ NICK_ANY = /#{SPECIAL_CHAR}|[[:alnum:]]|-/\r
+ GEN_NICK = /#{NICK_FIRST}#{NICK_ANY}+/\r
+ RFC_NICK = /#{NICK_FIRST}#{NICK_ANY}{0,8}/\r
+\r
+ USER_CHAR = /[^\x00\x0a\x0d @]/\r
+ GEN_USER = /#{USER_CHAR}+/\r
+\r
+ # Host-matching regexps\r
+ HOSTNAME_COMPONENT = /[[:alnum:]](?:[[:alnum:]]|-)*[[:alnum:]]*/\r
+ HOSTNAME = /#{HOSTNAME_COMPONENT}(?:\.#{HOSTNAME_COMPONENT})*/\r
+ HOSTADDR = /#{IP_ADDR}|#{IP6_ADDR}/\r
+\r
+ GEN_HOST = /#{HOSTNAME}|#{HOSTADDR}/\r
+\r
+ # FreeNode network replaces the host of affiliated users with\r
+ # 'virtual hosts' \r
+ # FIXME we need the true syntax to match it properly ...\r
+ PDPC_HOST_PART = /[0-9A-Za-z.-]+/\r
+ PDPC_HOST = /#{PDPC_HOST_PART}(?:\/#{PDPC_HOST_PART})+/\r
+\r
+ # NOTE: the final optional and non-greedy dot is needed because some\r
+ # servers (e.g. FreeNode) send the hostname of the services as "services."\r
+ # which is not RFC compliant, but sadly done.\r
+ GEN_MASK_HOST = /#{PDPC_HOST}|#{GEN_HOST}\.??/ \r
+\r
+ # Netmask-matching Regexp\r
+ GEN_MASK = /(#{GEN_NICK})(?:(?:!(#{GEN_USER}))?@(#{GEN_MASK_HOST}))?/\r
+ end\r
+\r
+end\r
+\r
+\r
module Irc\r
\r
\r
# Now we can see if the given string _str_ is an actual Netmask\r
if str.respond_to?(:to_str)\r
case str.to_str\r
- when /^(?:(\S+?)(?:!(\S+)@(?:(\S+))?)?)?$/\r
+ when /^(?:#{Regexp::Irc::GEN_MASK})?$/\r
# We do assignment using our internal methods\r
self.nick = $1\r
self.user = $2\r
# This is not always true, though, since some servers do not send a
# full hostmask for user messages.
#
- if prefix =~ /^(?:\S+)(?:!\S+)?@(?:\S+)$/
+ if prefix =~ /^#{Regexp::Irc::GEN_MASK}$/
data[:source] = @server.user(prefix)
else
if @server.hostname
if @server.hostname != prefix
- debug "Origin #{prefix} for message\n\t#{serverstring.inspect}\nis neither a user hostmask nor the server hostname, assuming it's a nick"
- data[:source] = @server.user(prefix)
+ # TODO do we want to be able to differentiated messages that are passed on to us from /other/ servers?
+ debug "Origin #{prefix} for message\n\t#{serverstring.inspect}\nis neither a user hostmask nor the server hostname\nI'll pretend that it's from the server anyway"
+ data[:source] = @server
else
data[:source] = @server
end