Class Irc::Server
In: lib/rbot/irc.rb
Parent: Object
BasicUserMessage JoinMessage NamesMessage WhoisMessage ModeChangeMessage KickMessage MotdMessage QuitMessage BanlistMessage UserMessage NoSuchTargetMessage TopicMessage NickMessage WelcomeMessage UnknownMessage InviteMessage PartMessage NetmaskList UserList ArrayOf ChannelList Netmask User\n[lib/rbot/botuser.rb\nlib/rbot/irc.rb] Channel Singleton RfcCasemap StrictRfcCasemap AsciiCasemap Casemap PrivMessage NoticeMessage TokyoCabinet::BDB CIBDB Btree CIBtree Socket MessageQueue QueueRing Client DBHash\n[lib/rbot/registry/bdb.rb\nlib/rbot/registry/tc.rb] DBTree\n[lib/rbot/registry/bdb.rb\nlib/rbot/registry/tc.rb] Server NetmaskDb Bot\n[lib/rbot/botuser.rb\nlib/rbot/config.rb\nlib/rbot/ircbot.rb\nlib/rbot/language.rb\nlib/rbot/message.rb\nlib/rbot/messagemapper.rb\nlib/rbot/plugins.rb\nlib/rbot/rbotconfig.rb\nlib/rbot/registry/bdb.rb\nlib/rbot/registry/tc.rb] lib/rbot/ircsocket.rb lib/rbot/rfc2812.rb lib/rbot/registry/tc.rb lib/rbot/irc.rb lib/rbot/maskdb.rb lib/rbot/message.rb lib/rbot/messagemapper.rb lib/rbot/botuser.rb lib/rbot/registry/tc.rb (null) BotConfig PKGConfig ServerOrCasemap Irc dot/m_35_0.png

An IRC Server represents the Server the client is connected to.

Methods

External Aliases

hostname -> to_s

Attributes

capabilities  [R] 
chanmodes  [R] 
channels  [R] 
hostname  [R] 
supports  [R] 
usermodes  [R] 
users  [R] 
version  [R] 

Public Class methods

Create a new Server, with all instance variables reset to nil (for scalar variables), empty channel and user lists and @supports initialized to the default values for all known supported features.

[Source]

      # File lib/rbot/irc.rb, line 1563
1563:     def initialize
1564:       @hostname = @version = @usermodes = @chanmodes = nil
1565: 
1566:       @channels = ChannelList.new
1567: 
1568:       @users = UserList.new
1569: 
1570:       reset_capabilities
1571:     end

Public Instance methods

Returns the casemap of the server.

[Source]

      # File lib/rbot/irc.rb, line 1786
1786:     def casemap
1787:       @supports[:casemapping]
1788:     end

Returns the Channel with the given name on the server, creating it if necessary. This is a short form for new_channel(str, nil, [], false)

[Source]

      # File lib/rbot/irc.rb, line 1912
1912:     def channel(str)
1913:       new_channel(str,nil,[],false)
1914:     end

TODO Ho

[Source]

      # File lib/rbot/irc.rb, line 1534
1534:     def channel_names
1535:       @channels.map { |ch| ch.downcase }
1536:     end

Clears the server

[Source]

      # File lib/rbot/irc.rb, line 1637
1637:     def clear
1638:       reset_lists
1639:       reset_capabilities
1640:       @hostname = @version = @usermodes = @chanmodes = nil
1641:     end

Remove Channel name from the list of Channels

[Source]

      # File lib/rbot/irc.rb, line 1918
1918:     def delete_channel(name)
1919:       idx = has_channel?(name)
1920:       raise "Tried to remove unmanaged channel #{name}" unless idx
1921:       @channels.delete_at(idx)
1922:     end

Remove User someuser from the list of Users. someuser must be specified with the full Netmask.

[Source]

      # File lib/rbot/irc.rb, line 1993
1993:     def delete_user(someuser)
1994:       idx = has_user?(someuser)
1995:       raise "Tried to remove unmanaged user #{user}" unless idx
1996:       have = self.user(someuser)
1997:       @channels.each { |ch|
1998:         delete_user_from_channel(have, ch)
1999:       }
2000:       @users.delete_at(idx)
2001:     end

Deletes User user from Channel channel

[Source]

      # File lib/rbot/irc.rb, line 1986
1986:     def delete_user_from_channel(user, channel)
1987:       channel.delete_user(user)
1988:     end

Finds all Users on server whose Netmask matches mask

[Source]

      # File lib/rbot/irc.rb, line 2011
2011:     def find_users(mask)
2012:       nm = new_netmask(mask)
2013:       @users.inject(UserList.new) {
2014:         |list, user|
2015:         if user.user == "*" or user.host == "*"
2016:           list << user if user.nick.irc_downcase(casemap) =~ nm.nick.irc_downcase(casemap).to_irc_regexp
2017:         else
2018:           list << user if user.matches?(nm)
2019:         end
2020:         list
2021:       }
2022:     end
get_chan(name)

Alias for get_channel

Returns the channel with name name, if available

[Source]

      # File lib/rbot/irc.rb, line 1821
1821:     def get_channel(name)
1822:       return nil if name.nil_or_empty?
1823:       idx = has_channel?(name)
1824:       channels[idx] if idx
1825:     end

Returns the user with nick nick, if available

[Source]

      # File lib/rbot/irc.rb, line 1933
1933:     def get_user(nick)
1934:       idx = has_user?(nick)
1935:       @users[idx] if idx
1936:     end
has_chan?(name)

Alias for has_channel?

Checks if the receiver already has a channel with the given name

[Source]

      # File lib/rbot/irc.rb, line 1813
1813:     def has_channel?(name)
1814:       return false if name.nil_or_empty?
1815:       channel_names.index(name.irc_downcase(casemap))
1816:     end

Checks if the receiver already has a user with the given nick

[Source]

      # File lib/rbot/irc.rb, line 1926
1926:     def has_user?(nick)
1927:       return false if nick.nil_or_empty?
1928:       user_nicks.index(nick.irc_downcase(casemap))
1929:     end

[Source]

      # File lib/rbot/irc.rb, line 1543
1543:     def inspect
1544:       chans, users = [@channels, @users].map {|d|
1545:         d.sort { |a, b|
1546:           a.downcase <=> b.downcase
1547:         }.map { |x|
1548:           x.inspect
1549:         }
1550:       }
1551: 
1552:       str = self.__to_s__[0..-2]
1553:       str << " @hostname=#{hostname}"
1554:       str << " @channels=#{chans}"
1555:       str << " @users=#{users}"
1556:       str << ">"
1557:     end

Convert a prefix (@, +, %, …) to the corresponding mode (o, v, h, …). See also prefix_for_mode

[Source]

      # File lib/rbot/irc.rb, line 1618
1618:     def mode_for_prefix(pfx)
1619:       return @supports[:prefix][:modes][
1620:         @supports[:prefix][:prefixes].index(pfx.to_sym)
1621:       ]
1622:     end

Create a new Channel object bound to the receiver and add it to the list of Channels on the receiver, unless the channel was present already. In this case, the default action is to raise an exception, unless fails is set to false. An exception can also be raised if str is nil or empty, again only if fails is set to true; otherwise, the method just returns nil

[Source]

      # File lib/rbot/irc.rb, line 1835
1835:     def new_channel(name, topic=nil, users=[], fails=true)
1836:       if name.nil_or_empty?
1837:         raise "Tried to look for empty or nil channel name #{name.inspect}" if fails
1838:         return nil
1839:       end
1840:       ex = get_chan(name)
1841:       if ex
1842:         raise "Channel #{name} already exists on server #{self}" if fails
1843:         return ex
1844:       else
1845: 
1846:         prefix = name[0,1]
1847: 
1848:         # Give a warning if the new Channel goes over some server limits.
1849:         #
1850:         # FIXME might need to raise an exception
1851:         #
1852:         warn "#{self} doesn't support channel prefix #{prefix}" unless @supports[:chantypes].include?(prefix)
1853:         warn "#{self} doesn't support channel names this long (#{name.length} > #{@supports[:channellen]})" unless name.length <= @supports[:channellen]
1854: 
1855:         # Next, we check if we hit the limit for channels of type +prefix+
1856:         # if the server supports +chanlimit+
1857:         #
1858:         @supports[:chanlimit].keys.each { |k|
1859:           next unless k.include?(prefix)
1860:           count = 0
1861:           channel_names.each { |n|
1862:             count += 1 if k.include?(n[0])
1863:           }
1864:           # raise IndexError, "Already joined #{count} channels with prefix #{k}" if count == @supports[:chanlimit][k]
1865:           warn "Already joined #{count}/#{@supports[:chanlimit][k]} channels with prefix #{k}, we may be going over server limits" if count >= @supports[:chanlimit][k]
1866:         }
1867: 
1868:         # So far, everything is fine. Now create the actual Channel
1869:         #
1870:         chan = Channel.new(name, topic, users, :server => self)
1871: 
1872:         # We wade through +prefix+ and +chanmodes+ to create appropriate
1873:         # lists and flags for this channel
1874: 
1875:         @supports[:prefix][:modes].each { |mode|
1876:           chan.create_mode(mode, Channel::UserMode)
1877:         } if @supports[:prefix][:modes]
1878: 
1879:         @supports[:chanmodes].each { |k, val|
1880:           if val
1881:             case k
1882:             when :typea
1883:               val.each { |mode|
1884:                 chan.create_mode(mode, Channel::ModeTypeA)
1885:               }
1886:             when :typeb
1887:               val.each { |mode|
1888:                 chan.create_mode(mode, Channel::ModeTypeB)
1889:               }
1890:             when :typec
1891:               val.each { |mode|
1892:                 chan.create_mode(mode, Channel::ModeTypeC)
1893:               }
1894:             when :typed
1895:               val.each { |mode|
1896:                 chan.create_mode(mode, Channel::ModeTypeD)
1897:               }
1898:             end
1899:           end
1900:         }
1901: 
1902:         @channels << chan
1903:         # debug "Created channel #{chan.inspect}"
1904:         return chan
1905:       end
1906:     end

Create a new Netmask object with the appropriate casemap

[Source]

      # File lib/rbot/irc.rb, line 2005
2005:     def new_netmask(str)
2006:       str.to_irc_netmask(:server => self)
2007:     end

Create a new User object bound to the receiver and add it to the list of Users on the receiver, unless the User was present already. In this case, the default action is to raise an exception, unless fails is set to false. An exception can also be raised if str is nil or empty, again only if fails is set to true; otherwise, the method just returns nil

[Source]

      # File lib/rbot/irc.rb, line 1945
1945:     def new_user(str, fails=true)
1946:       if str.nil_or_empty?
1947:         raise "Tried to look for empty or nil user name #{str.inspect}" if fails
1948:         return nil
1949:       end
1950:       tmp = str.to_irc_user(:server => self)
1951:       old = get_user(tmp.nick)
1952:       # debug "Tmp: #{tmp.inspect}"
1953:       # debug "Old: #{old.inspect}"
1954:       if old
1955:         # debug "User already existed as #{old.inspect}"
1956:         if tmp.known?
1957:           if old.known?
1958:             # debug "Both were known"
1959:             # Do not raise an error: things like Freenode change the hostname after identification
1960:             warning "User #{tmp.nick} has inconsistent Netmasks! #{self} knows #{old.inspect} but access was tried with #{tmp.inspect}" if old != tmp
1961:             raise "User #{tmp} already exists on server #{self}" if fails
1962:           end
1963:           if old.fullform.downcase != tmp.fullform.downcase
1964:             old.replace(tmp)
1965:             # debug "Known user now #{old.inspect}"
1966:           end
1967:         end
1968:         return old
1969:       else
1970:         warn "#{self} doesn't support nicknames this long (#{tmp.nick.length} > #{@supports[:nicklen]})" unless tmp.nick.length <= @supports[:nicklen]
1971:         @users << tmp
1972:         return @users.last
1973:       end
1974:     end

This method is used to parse a 005 RPL_ISUPPORT line

See the RPL_ISUPPORT draft

[Source]

      # File lib/rbot/irc.rb, line 1674
1674:     def parse_isupport(line)
1675:       debug "Parsing ISUPPORT #{line.inspect}"
1676:       ar = line.split(' ')
1677:       reparse = []
1678:       ar.each { |en|
1679:         prekey, val = en.split('=', 2)
1680:         if prekey =~ /^-(.*)/
1681:           key = $1.downcase.to_sym
1682:           val = false
1683:         else
1684:           key = prekey.downcase.to_sym
1685:         end
1686:         case key
1687:         when :casemapping
1688:           noval_warn(key, val) {
1689:             if val == 'charset'
1690:               reparse << "CASEMAPPING=(charset)"
1691:             else
1692:               # TODO some servers offer non-standard CASEMAPPINGs in the form
1693:               # locale.charset[-options], which indicate an extended set of
1694:               # allowed characters (mostly for nicks). This might be supported
1695:               # with hooks for the unicode core module
1696:               @supports[key] = val.to_irc_casemap
1697:             end
1698:           }
1699:         when :chanlimit, :idchan, :maxlist, :targmax
1700:           noval_warn(key, val) {
1701:             groups = val.split(',')
1702:             groups.each { |g|
1703:               k, v = g.split(':')
1704:               @supports[key][k] = v.to_i || 0
1705:               if @supports[key][k] == 0
1706:                 warn "Deleting #{key} limit of 0 for #{k}"
1707:                 @supports[key].delete(k)
1708:               end
1709:             }
1710:           }
1711:         when :chanmodes
1712:           noval_warn(key, val) {
1713:             groups = val.split(',')
1714:             @supports[key][:typea] = groups[0].scan(/./).map { |x| x.to_sym}
1715:             @supports[key][:typeb] = groups[1].scan(/./).map { |x| x.to_sym}
1716:             @supports[key][:typec] = groups[2].scan(/./).map { |x| x.to_sym}
1717:             @supports[key][:typed] = groups[3].scan(/./).map { |x| x.to_sym}
1718:           }
1719:         when :channellen, :kicklen, :modes, :topiclen
1720:           if val
1721:             @supports[key] = val.to_i
1722:           else
1723:             @supports[key] = nil
1724:           end
1725:         when :chantypes
1726:           @supports[key] = val # can also be nil
1727:         when :excepts
1728:           val ||= 'e'
1729:           @supports[key] = val
1730:         when :invex
1731:           val ||= 'I'
1732:           @supports[key] = val
1733:         when :maxchannels
1734:           noval_warn(key, val) {
1735:             reparse << "CHANLIMIT=(chantypes):#{val} "
1736:           }
1737:         when :maxtargets
1738:           noval_warn(key, val) {
1739:             @supports[:targmax]['PRIVMSG'] = val.to_i
1740:             @supports[:targmax]['NOTICE'] = val.to_i
1741:           }
1742:         when :network
1743:           noval_warn(key, val) {
1744:             @supports[key] = val
1745:           }
1746:         when :nicklen
1747:           noval_warn(key, val) {
1748:             @supports[key] = val.to_i
1749:           }
1750:         when :prefix
1751:           if val
1752:             val.scan(/\((.*)\)(.*)/) { |m, p|
1753:               @supports[key][:modes] = m.scan(/./).map { |x| x.to_sym}
1754:               @supports[key][:prefixes] = p.scan(/./).map { |x| x.to_sym}
1755:             }
1756:           else
1757:             @supports[key][:modes] = nil
1758:             @supports[key][:prefixes] = nil
1759:           end
1760:         when :safelist
1761:           val_warn(key, val) {
1762:             @supports[key] = val.nil? ? true : val
1763:           }
1764:         when :statusmsg
1765:           noval_warn(key, val) {
1766:             @supports[key] = val.scan(/./)
1767:           }
1768:         when :std
1769:           noval_warn(key, val) {
1770:             @supports[key] = val.split(',')
1771:           }
1772:         else
1773:           @supports[key] =  val.nil? ? true : val
1774:         end
1775:       }
1776:       unless reparse.empty?
1777:         reparse_str = reparse.join(" ")
1778:         reparse_str.gsub!("(chantypes)",@supports[:chantypes])
1779:         reparse_str.gsub!("(charset)",@supports[:charset] || 'rfc1459')
1780:         parse_isupport(reparse_str)
1781:       end
1782:     end

This method is used to parse a 004 RPL_MY_INFO line

[Source]

      # File lib/rbot/irc.rb, line 1645
1645:     def parse_my_info(line)
1646:       ar = line.split(' ')
1647:       @hostname = ar[0]
1648:       @version = ar[1]
1649:       @usermodes = ar[2]
1650:       @chanmodes = ar[3]
1651:     end

Convert a mode (o, v, h, …) to the corresponding prefix (@, +, %, …). See also mode_for_prefix

[Source]

      # File lib/rbot/irc.rb, line 1610
1610:     def prefix_for_mode(mode)
1611:       return @supports[:prefix][:prefixes][
1612:         @supports[:prefix][:modes].index(mode.to_sym)
1613:       ]
1614:     end

Resets the server capabilities

[Source]

      # File lib/rbot/irc.rb, line 1575
1575:     def reset_capabilities
1576:       @supports = {
1577:         :casemapping => 'rfc1459'.to_irc_casemap,
1578:         :chanlimit => {},
1579:         :chanmodes => {
1580:           :typea => nil, # Type A: address lists
1581:           :typeb => nil, # Type B: needs a parameter
1582:           :typec => nil, # Type C: needs a parameter when set
1583:           :typed => nil  # Type D: must not have a parameter
1584:         },
1585:         :channellen => 50,
1586:         :chantypes => "#&!+",
1587:         :excepts => nil,
1588:         :idchan => {},
1589:         :invex => nil,
1590:         :kicklen => nil,
1591:         :maxlist => {},
1592:         :modes => 3,
1593:         :network => nil,
1594:         :nicklen => 9,
1595:         :prefix => {
1596:           :modes => [:o, :v],
1597:           :prefixes => ["@""@", :+]
1598:         },
1599:         :safelist => nil,
1600:         :statusmsg => nil,
1601:         :std => nil,
1602:         :targmax => {},
1603:         :topiclen => nil
1604:       }
1605:       @capabilities = {}
1606:     end

Resets the Channel and User list

[Source]

      # File lib/rbot/irc.rb, line 1626
1626:     def reset_lists
1627:       @users.reverse_each { |u|
1628:         delete_user(u)
1629:       }
1630:       @channels.reverse_each { |u|
1631:         delete_channel(u)
1632:       }
1633:     end

Returns the User with the given Netmask on the server, creating it if necessary. This is a short form for new_user(str, false)

[Source]

      # File lib/rbot/irc.rb, line 1980
1980:     def user(str)
1981:       new_user(str, false)
1982:     end

TODO Ho

[Source]

      # File lib/rbot/irc.rb, line 1539
1539:     def user_nicks
1540:       @users.map { |u| u.downcase }
1541:     end

Returns the actual User or Channel object matching name

[Source]

      # File lib/rbot/irc.rb, line 1803
1803:     def user_or_channel(name)
1804:       if supports[:chantypes].include?(name[0])
1805:         return channel(name)
1806:       else
1807:         return user(name)
1808:       end
1809:     end

Returns User or Channel depending on what name can be a name of

[Source]

      # File lib/rbot/irc.rb, line 1793
1793:     def user_or_channel?(name)
1794:       if supports[:chantypes].include?(name[0])
1795:         return Channel
1796:       else
1797:         return User
1798:       end
1799:     end

Private Instance methods

[Source]

      # File lib/rbot/irc.rb, line 1653
1653:     def noval_warn(key, val, &block)
1654:       if val
1655:         yield if block_given?
1656:       else
1657:         warn "No #{key.to_s.upcase} value"
1658:       end
1659:     end

[Source]

      # File lib/rbot/irc.rb, line 1661
1661:     def val_warn(key, val, &block)
1662:       if val == true or val == false or val.nil?
1663:         yield if block_given?
1664:       else
1665:         warn "No #{key.to_s.upcase} value must be specified, got #{val}"
1666:       end
1667:     end

[Validate]