# Channels is the User on (of those the client is on too)?
# We may want this so that when a User leaves all Channels and he hasn't
# sent us privmsgs, we know we can remove him from the Server @users list
+# FIXME for the time being, we do it with a method that scans the server
+# (if defined), so the method is slow and should not be used frequently.
# * Maybe ChannelList and UserList should be HashesOf instead of ArrayOf?
# See items marked as TODO Ho.
# The framework to do this is now in place, thanks to the new [] method
# We alias the to_s method to __to_s__ to make
# it accessible in all classes
- alias :__to_s__ :to_s
+ alias :__to_s__ :to_s
end
# The Irc module is used to keep all IRC-related classes
include Singleton
def initialize
- super('rfc1459', "\x41-\x5e", "\x61-\x7e")
+ super('rfc1459', "\x41-\x5a\x7b-\x7e", "\x61-\x7a\x5b-\x5e")
end
end
include Singleton
def initialize
- super('strict-rfc1459', "\x41-\x5d", "\x61-\x7d")
+ super('strict-rfc1459', "\x41-\x5a\x7b-\x7d", "\x61-\x7a\x5b-\x5d")
end
end
h = {}
h[:server] = @server if defined?(@server) and @server
h[:casemap] = @casemap if defined?(@casemap) and @casemap
- h[:casemap] ||= @server.casemap if defined?(@server) and @server
return h
end
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}/
+ 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}/
# IPv6, from Resolv::IPv6, without the \A..\z anchors
GEN_HOST = /#{HOSTNAME}|#{HOSTADDR}/
# # FreeNode network replaces the host of affiliated users with
- # # 'virtual hosts'
+ # # 'virtual hosts'
# # FIXME we need the true syntax to match it properly ...
# PDPC_HOST_PART = /[0-9A-Za-z.-]+/
# PDPC_HOST = /#{PDPC_HOST_PART}(?:\/#{PDPC_HOST_PART})+/
# # NOTE: the final optional and non-greedy dot is needed because some
# # servers (e.g. FreeNode) send the hostname of the services as "services."
# # which is not RFC compliant, but sadly done.
- # GEN_HOST_EXT = /#{PDPC_HOST}|#{GEN_HOST}\.??/
+ # GEN_HOST_EXT = /#{PDPC_HOST}|#{GEN_HOST}\.??/
# Sadly, different networks have different, RFC-breaking ways of cloaking
# the actualy host address: see above for an example to handle FreeNode.
# Subclasses of Netmask will return a new Netmask, using full_downcase
#
def to_irc_netmask(opts={})
- if self.class == Netmask and not opts[:force]
+ if self.class == Netmask
return self if fits_with_server_and_casemap?(opts)
end
return self.full_downcase.to_irc_netmask(server_and_casemap.merge(opts))
class User < Netmask
alias :to_s :nick
- attr_accessor :real_name
+ attr_accessor :real_name, :idle_since, :signon
# Create a new IRC User from a given Netmask (or anything that can be converted
# into a Netmask) provided that the given Netmask does not have globs.
raise ArgumentError, "#{str.inspect} must not have globs (unescaped * or ?)" if host.has_irc_glob? && host != "*"
@away = false
@real_name = String.new
+ @idle_since = nil
+ @signon = nil
end
# The nick of a User may be changed freely, but it must not contain glob patterns.
raise "Can't resolve channel #{channel}"
end
end
+
+ def channels
+ if @server
+ @server.channels.select { |ch| ch.has_user?(self) }
+ else
+ Array.new
+ end
+ end
end
end
+ # Hash of modes. Subclass of Hash that defines any? and all?
+ # to check if boolean modes (Type D) are set
+ class ModeHash < Hash
+ def any?(*ar)
+ !!ar.find { |m| s = m.to_sym ; self[s] && self[s].set? }
+ end
+ def all?(*ar)
+ !ar.find { |m| s = m.to_sym ; !(self[s] && self[s].set?) }
+ end
+ end
# Channel modes of type A manipulate lists
#
include ServerOrCasemap
attr_reader :name, :topic, :mode, :users
alias :to_s :name
+ attr_accessor :creation_time, :url
def inspect
str = self.__to_s__[0..-2]
str << " on server #{server}" if server
str << " @name=#{@name.inspect} @topic=#{@topic.text.inspect}"
str << " @users=[#{user_nicks.sort.join(', ')}]"
+ str << " (created on #{creation_time})" if creation_time
+ str << " (URL #{url})" if url
str << ">"
end
# Adds a user to the channel
#
def add_user(user, opts={})
- silent = opts.fetch(:silent, false)
+ silent = opts.fetch(:silent, false)
if has_user?(user)
warn "Trying to add user #{user} to channel #{self} again" unless silent
else
}
# Flags
- @mode = {}
- class << @mode
- def any?(*ar)
- !!ar.find { |m| s = m.to_sym ; self[s] && self[s].set? }
- end
- def all?(*ar)
- !ar.find { |m| s = m.to_sym ; !(self[s] && self[s].set?) }
- end
- end
+ @mode = ModeHash.new
+
+ # creation time, only on some networks
+ @creation_time = nil
+
+ # URL, only on some networks
+ @url = nil
end
# Removes a user from the channel