net-irc2 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,144 @@
1
+
2
+ module Net::IRC::Client::ChannelManager
3
+ # For managing channel
4
+ def on_rpl_namreply(m)
5
+ type = m[1]
6
+ channel = m[2]
7
+ init_channel(channel)
8
+
9
+ @channels.synchronize do
10
+ m[3].split(" ").each do |u|
11
+ _, mode, nick = *u.match(/\A([@+]?)(.+)/)
12
+
13
+ @channels[channel][:users] << nick
14
+ @channels[channel][:users].uniq!
15
+
16
+ op = @server_config.mode_parser.mark_to_op(mode)
17
+ if op
18
+ @channels[channel][:modes] << [op, nick]
19
+ end
20
+ end
21
+
22
+ case type
23
+ when "@" # secret
24
+ @channels[channel][:modes] << [:s, nil]
25
+ when "*" # private
26
+ @channels[channel][:modes] << [:p, nil]
27
+ when "=" # public
28
+ end
29
+
30
+ @channels[channel][:modes].uniq!
31
+ end
32
+ end
33
+
34
+ # For managing channel
35
+ def on_part(m)
36
+ nick = m.prefix.nick
37
+ channel = m[0]
38
+ init_channel(channel)
39
+
40
+ @channels.synchronize do
41
+ info = @channels[channel]
42
+ if info
43
+ info[:users].delete(nick)
44
+ info[:modes].delete_if {|u|
45
+ u[1] == nick
46
+ }
47
+ end
48
+ end
49
+ end
50
+
51
+ # For managing channel
52
+ def on_quit(m)
53
+ nick = m.prefix.nick
54
+
55
+ @channels.synchronize do
56
+ @channels.each do |channel, info|
57
+ info[:users].delete(nick)
58
+ info[:modes].delete_if {|u|
59
+ u[1] == nick
60
+ }
61
+ end
62
+ end
63
+ end
64
+
65
+ # For managing channel
66
+ def on_kick(m)
67
+ users = m[1].split(",")
68
+
69
+ @channels.synchronize do
70
+ m[0].split(",").each do |chan|
71
+ init_channel(chan)
72
+ info = @channels[chan]
73
+ if info
74
+ users.each do |nick|
75
+ info[:users].delete(nick)
76
+ info[:modes].delete_if {|u|
77
+ u[1] == nick
78
+ }
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ # For managing channel
86
+ def on_join(m)
87
+ nick = m.prefix.nick
88
+ channel = m[0]
89
+
90
+ @channels.synchronize do
91
+ init_channel(channel)
92
+
93
+ @channels[channel][:users] << nick
94
+ @channels[channel][:users].uniq!
95
+ end
96
+ end
97
+
98
+ # For managing channel
99
+ def on_nick(m)
100
+ oldnick = m.prefix.nick
101
+ newnick = m[0]
102
+
103
+ @channels.synchronize do
104
+ @channels.each do |channel, info|
105
+ info[:users].map! {|i|
106
+ (i == oldnick) ? newnick : i
107
+ }
108
+ info[:modes].map! {|mode, target|
109
+ (target == oldnick) ? [mode, newnick] : [mode, target]
110
+ }
111
+ end
112
+ end
113
+ end
114
+
115
+ # For managing channel
116
+ def on_mode(m)
117
+ channel = m[0]
118
+ @channels.synchronize do
119
+ init_channel(channel)
120
+
121
+ modes = @server_config.mode_parser.parse(m)
122
+ modes[:negative].each do |mode|
123
+ @channels[channel][:modes].delete(mode)
124
+ end
125
+
126
+ modes[:positive].each do |mode|
127
+ @channels[channel][:modes] << mode
128
+ end
129
+
130
+ @channels[channel][:modes].uniq!
131
+ [modes[:negative], modes[:positive]]
132
+ end
133
+ end
134
+
135
+ # For managing channel
136
+ def init_channel(channel)
137
+ @channels[channel] ||= {
138
+ :modes => [],
139
+ :users => [],
140
+ }
141
+ end
142
+
143
+ end
144
+
@@ -0,0 +1,117 @@
1
+ class Net::IRC::Client
2
+ include Net::IRC
3
+ include Constants
4
+
5
+ attr_reader :host, :port, :opts
6
+ attr_reader :prefix, :channels
7
+
8
+ def initialize(host, port, opts={})
9
+ @host = host
10
+ @port = port
11
+ @opts = OpenStruct.new(opts)
12
+ @log = @opts.logger || ::Logger.new($stdout)
13
+ @server_config = Message::ServerConfig.new
14
+ @channels = {
15
+ # "#channel" => {
16
+ # :modes => [],
17
+ # :users => [],
18
+ # }
19
+ }
20
+ @channels.extend(MonitorMixin)
21
+ end
22
+
23
+ # Connect to server and start loop.
24
+ def start
25
+ # reset config
26
+ @server_config = Message::ServerConfig.new
27
+ @socket = TCPSocket.new(@host, @port)
28
+ on_connected
29
+ post PASS, @opts.pass if @opts.pass
30
+ post NICK, @opts.nick
31
+ post USER, @opts.user, "0", "*", @opts.real
32
+
33
+ buffer = BufferedTokenizer.new("\r\n")
34
+
35
+ while data = @socket.readpartial(4096)
36
+ buffer.extract(data).each do |line|
37
+ l = "#{line}\r\n"
38
+ begin
39
+ @log.debug "RECEIVE: #{l.chomp}"
40
+ m = Message.parse(l)
41
+ next if on_message(m) === true
42
+ name = "on_#{(COMMANDS[m.command.upcase] || m.command).downcase}"
43
+ send(name, m) if respond_to?(name)
44
+ rescue Exception => e
45
+ warn e
46
+ warn e.backtrace.join("\r\t")
47
+ raise
48
+ rescue Message::InvalidMessage
49
+ @log.error "MessageParse: " + l.inspect
50
+ end
51
+ end
52
+ end
53
+ rescue IOError
54
+ ensure
55
+ finish
56
+ end
57
+
58
+ # Close connection to server.
59
+ def finish
60
+ begin
61
+ @socket.close
62
+ rescue
63
+ end
64
+ on_disconnected
65
+ end
66
+
67
+ # Catch all messages.
68
+ # If this method return true, aother callback will not be called.
69
+ def on_message(m)
70
+ end
71
+
72
+ # Default RPL_WELCOME callback.
73
+ # This sets @prefix from the message.
74
+ def on_rpl_welcome(m)
75
+ @prefix = Prefix.new(m[1][/\S+\z/])
76
+ end
77
+
78
+ # Default RPL_ISUPPORT callback.
79
+ # This detects server's configurations.
80
+ def on_rpl_isupport(m)
81
+ @server_config.set(m)
82
+ end
83
+
84
+ # Default PING callback. Response PONG.
85
+ def on_ping(m)
86
+ post PONG, @prefix ? @prefix.nick : ""
87
+ end
88
+
89
+ # Call when socket connected.
90
+ def on_connected
91
+ end
92
+
93
+ # Call when socket closed.
94
+ def on_disconnected
95
+ end
96
+
97
+ private
98
+
99
+ # Post message to server.
100
+ #
101
+ # include Net::IRC::Constants
102
+ # post PRIVMSG, "#channel", "foobar"
103
+ def post(command, *params)
104
+ m = Message.new(nil, command, params.map {|s|
105
+ if s
106
+ s.force_encoding("ASCII-8BIT") if s.respond_to? :force_encoding
107
+ #s.gsub(/\r\n|[\r\n]/, " ")
108
+ s.tr("\r\n", " ")
109
+ else
110
+ ""
111
+ end
112
+ })
113
+
114
+ @log.debug "SEND: #{m.to_s.chomp}"
115
+ @socket << m.to_s
116
+ end
117
+ end # Client
@@ -0,0 +1,214 @@
1
+ module Net::IRC::Constants # :nodoc:
2
+ RPL_WELCOME = '001'
3
+ RPL_YOURHOST = '002'
4
+ RPL_CREATED = '003'
5
+ RPL_MYINFO = '004'
6
+ RPL_ISUPPORT = '005'
7
+ RPL_USERHOST = '302'
8
+ RPL_ISON = '303'
9
+ RPL_AWAY = '301'
10
+ RPL_UNAWAY = '305'
11
+ RPL_NOWAWAY = '306'
12
+ RPL_WHOISUSER = '311'
13
+ RPL_WHOISSERVER = '312'
14
+ RPL_WHOISOPERATOR = '313'
15
+ RPL_WHOISIDLE = '317'
16
+ RPL_ENDOFWHOIS = '318'
17
+ RPL_WHOISCHANNELS = '319'
18
+ RPL_WHOWASUSER = '314'
19
+ RPL_ENDOFWHOWAS = '369'
20
+ RPL_LISTSTART = '321'
21
+ RPL_LIST = '322'
22
+ RPL_LISTEND = '323'
23
+ RPL_UNIQOPIS = '325'
24
+ RPL_CHANNELMODEIS = '324'
25
+ RPL_NOTOPIC = '331'
26
+ RPL_TOPIC = '332'
27
+ RPL_INVITING = '341'
28
+ RPL_SUMMONING = '342'
29
+ RPL_INVITELIST = '346'
30
+ RPL_ENDOFINVITELIST = '347'
31
+ RPL_EXCEPTLIST = '348'
32
+ RPL_ENDOFEXCEPTLIST = '349'
33
+ RPL_VERSION = '351'
34
+ RPL_WHOREPLY = '352'
35
+ RPL_ENDOFWHO = '315'
36
+ RPL_NAMREPLY = '353'
37
+ RPL_ENDOFNAMES = '366'
38
+ RPL_LINKS = '364'
39
+ RPL_ENDOFLINKS = '365'
40
+ RPL_BANLIST = '367'
41
+ RPL_ENDOFBANLIST = '368'
42
+ RPL_INFO = '371'
43
+ RPL_ENDOFINFO = '374'
44
+ RPL_MOTDSTART = '375'
45
+ RPL_MOTD = '372'
46
+ RPL_ENDOFMOTD = '376'
47
+ RPL_YOUREOPER = '381'
48
+ RPL_REHASHING = '382'
49
+ RPL_YOURESERVICE = '383'
50
+ RPL_TIME = '391'
51
+ RPL_USERSSTART = '392'
52
+ RPL_USERS = '393'
53
+ RPL_ENDOFUSERS = '394'
54
+ RPL_NOUSERS = '395'
55
+ RPL_TRACELINK = '200'
56
+ RPL_TRACECONNECTING = '201'
57
+ RPL_TRACEHANDSHAKE = '202'
58
+ RPL_TRACEUNKNOWN = '203'
59
+ RPL_TRACEOPERATOR = '204'
60
+ RPL_TRACEUSER = '205'
61
+ RPL_TRACESERVER = '206'
62
+ RPL_TRACESERVICE = '207'
63
+ RPL_TRACENEWTYPE = '208'
64
+ RPL_TRACECLASS = '209'
65
+ RPL_TRACERECONNECT = '210'
66
+ RPL_TRACELOG = '261'
67
+ RPL_TRACEEND = '262'
68
+ RPL_STATSLINKINFO = '211'
69
+ RPL_STATSCOMMANDS = '212'
70
+ RPL_ENDOFSTATS = '219'
71
+ RPL_STATSUPTIME = '242'
72
+ RPL_STATSOLINE = '243'
73
+ RPL_UMODEIS = '221'
74
+ RPL_SERVLIST = '234'
75
+ RPL_SERVLISTEND = '235'
76
+ RPL_LUSERCLIENT = '251'
77
+ RPL_LUSEROP = '252'
78
+ RPL_LUSERUNKNOWN = '253'
79
+ RPL_LUSERCHANNELS = '254'
80
+ RPL_LUSERME = '255'
81
+ RPL_ADMINME = '256'
82
+ RPL_ADMINLOC1 = '257'
83
+ RPL_ADMINLOC2 = '258'
84
+ RPL_ADMINEMAIL = '259'
85
+ RPL_TRYAGAIN = '263'
86
+ ERR_NOSUCHNICK = '401'
87
+ ERR_NOSUCHSERVER = '402'
88
+ ERR_NOSUCHCHANNEL = '403'
89
+ ERR_CANNOTSENDTOCHAN = '404'
90
+ ERR_TOOMANYCHANNELS = '405'
91
+ ERR_WASNOSUCHNICK = '406'
92
+ ERR_TOOMANYTARGETS = '407'
93
+ ERR_NOSUCHSERVICE = '408'
94
+ ERR_NOORIGIN = '409'
95
+ ERR_NORECIPIENT = '411'
96
+ ERR_NOTEXTTOSEND = '412'
97
+ ERR_NOTOPLEVEL = '413'
98
+ ERR_WILDTOPLEVEL = '414'
99
+ ERR_BADMASK = '415'
100
+ ERR_UNKNOWNCOMMAND = '421'
101
+ ERR_NOMOTD = '422'
102
+ ERR_NOADMININFO = '423'
103
+ ERR_FILEERROR = '424'
104
+ ERR_NONICKNAMEGIVEN = '431'
105
+ ERR_ERRONEUSNICKNAME = '432'
106
+ ERR_NICKNAMEINUSE = '433'
107
+ ERR_NICKCOLLISION = '436'
108
+ ERR_UNAVAILRESOURCE = '437'
109
+ ERR_USERNOTINCHANNEL = '441'
110
+ ERR_NOTONCHANNEL = '442'
111
+ ERR_USERONCHANNEL = '443'
112
+ ERR_NOLOGIN = '444'
113
+ ERR_SUMMONDISABLED = '445'
114
+ ERR_USERSDISABLED = '446'
115
+ ERR_NOTREGISTERED = '451'
116
+ ERR_NEEDMOREPARAMS = '461'
117
+ ERR_ALREADYREGISTRED = '462'
118
+ ERR_NOPERMFORHOST = '463'
119
+ ERR_PASSWDMISMATCH = '464'
120
+ ERR_YOUREBANNEDCREEP = '465'
121
+ ERR_YOUWILLBEBANNED = '466'
122
+ ERR_KEYSET = '467'
123
+ ERR_CHANNELISFULL = '471'
124
+ ERR_UNKNOWNMODE = '472'
125
+ ERR_INVITEONLYCHAN = '473'
126
+ ERR_BANNEDFROMCHAN = '474'
127
+ ERR_BADCHANNELKEY = '475'
128
+ ERR_BADCHANMASK = '476'
129
+ ERR_NOCHANMODES = '477'
130
+ ERR_BANLISTFULL = '478'
131
+ ERR_NOPRIVILEGES = '481'
132
+ ERR_CHANOPRIVSNEEDED = '482'
133
+ ERR_CANTKILLSERVER = '483'
134
+ ERR_RESTRICTED = '484'
135
+ ERR_UNIQOPPRIVSNEEDED = '485'
136
+ ERR_NOOPERHOST = '491'
137
+ ERR_UMODEUNKNOWNFLAG = '501'
138
+ ERR_USERSDONTMATCH = '502'
139
+ RPL_SERVICEINFO = '231'
140
+ RPL_ENDOFSERVICES = '232'
141
+ RPL_SERVICE = '233'
142
+ RPL_NONE = '300'
143
+ RPL_WHOISCHANOP = '316'
144
+ RPL_KILLDONE = '361'
145
+ RPL_CLOSING = '362'
146
+ RPL_CLOSEEND = '363'
147
+ RPL_INFOSTART = '373'
148
+ RPL_MYPORTIS = '384'
149
+ RPL_STATSCLINE = '213'
150
+ RPL_STATSNLINE = '214'
151
+ RPL_STATSILINE = '215'
152
+ RPL_STATSKLINE = '216'
153
+ RPL_STATSQLINE = '217'
154
+ RPL_STATSYLINE = '218'
155
+ RPL_STATSVLINE = '240'
156
+ RPL_STATSLLINE = '241'
157
+ RPL_STATSHLINE = '244'
158
+ RPL_STATSSLINE = '244'
159
+ RPL_STATSPING = '246'
160
+ RPL_STATSBLINE = '247'
161
+ RPL_STATSDLINE = '250'
162
+ ERR_NOSERVICEHOST = '492'
163
+
164
+ PASS = 'PASS'
165
+ NICK = 'NICK'
166
+ USER = 'USER'
167
+ OPER = 'OPER'
168
+ MODE = 'MODE'
169
+ SERVICE = 'SERVICE'
170
+ QUIT = 'QUIT'
171
+ SQUIT = 'SQUIT'
172
+ JOIN = 'JOIN'
173
+ PART = 'PART'
174
+ TOPIC = 'TOPIC'
175
+ NAMES = 'NAMES'
176
+ LIST = 'LIST'
177
+ INVITE = 'INVITE'
178
+ KICK = 'KICK'
179
+ PRIVMSG = 'PRIVMSG'
180
+ NOTICE = 'NOTICE'
181
+ MOTD = 'MOTD'
182
+ LUSERS = 'LUSERS'
183
+ VERSION = 'VERSION'
184
+ STATS = 'STATS'
185
+ LINKS = 'LINKS'
186
+ TIME = 'TIME'
187
+ CONNECT = 'CONNECT'
188
+ TRACE = 'TRACE'
189
+ ADMIN = 'ADMIN'
190
+ INFO = 'INFO'
191
+ SERVLIST = 'SERVLIST'
192
+ SQUERY = 'SQUERY'
193
+ WHO = 'WHO'
194
+ WHOIS = 'WHOIS'
195
+ WHOWAS = 'WHOWAS'
196
+ KILL = 'KILL'
197
+ PING = 'PING'
198
+ PONG = 'PONG'
199
+ ERROR = 'ERROR'
200
+ AWAY = 'AWAY'
201
+ REHASH = 'REHASH'
202
+ DIE = 'DIE'
203
+ RESTART = 'RESTART'
204
+ SUMMON = 'SUMMON'
205
+ USERS = 'USERS'
206
+ WALLOPS = 'WALLOPS'
207
+ USERHOST = 'USERHOST'
208
+ ISON = 'ISON'
209
+ end
210
+
211
+ Net::IRC::COMMANDS = Net::IRC::Constants.constants.inject({}) {|r, i| # :nodoc:
212
+ r.update(Net::IRC::Constants.const_get(i).to_s => i.to_s.freeze)
213
+ }
214
+
@@ -0,0 +1,85 @@
1
+ class Net::IRC::Message::ModeParser
2
+
3
+ ONE_PARAM_MASK = 0
4
+ ONE_PARAM = 1
5
+ ONE_PARAM_FOR_POSITIVE = 2
6
+ NO_PARAM = 3
7
+
8
+ def initialize
9
+ @modes = {}
10
+ @op_to_mark_map = {}
11
+ @mark_to_op_map = {}
12
+
13
+ # Initialize for ircd 2.11 (RFC2812+)
14
+ set(:CHANMODES, 'beIR,k,l,imnpstaqr')
15
+ set(:PREFIX, '(ov)@+')
16
+ end
17
+
18
+ def mark_to_op(mark)
19
+ mark.empty? ? nil : @mark_to_op_map[mark.to_sym]
20
+ end
21
+
22
+ def set(key, value)
23
+ case key
24
+ when :PREFIX
25
+ if value =~ /\A\(([a-zA-Z]+)\)(.+)\z/
26
+ @op_to_mark_map = {}
27
+ key, value = Regexp.last_match[1], Regexp.last_match[2]
28
+ key.scan(/./).zip(value.scan(/./)) {|pair|
29
+ @op_to_mark_map[pair[0].to_sym] = pair[1].to_sym
30
+ }
31
+ @mark_to_op_map = @op_to_mark_map.invert
32
+ end
33
+ when :CHANMODES
34
+ @modes = {}
35
+ value.split(",").each_with_index do |s, kind|
36
+ s.scan(/./).each {|c|
37
+ @modes[c.to_sym] = kind
38
+ }
39
+ end
40
+ end
41
+ end
42
+
43
+ def parse(arg)
44
+ params = arg.kind_of?(Net::IRC::Message) ? arg.to_a : arg.split(" ")
45
+ params.shift
46
+
47
+ ret = {
48
+ :positive => [],
49
+ :negative => [],
50
+ }
51
+
52
+ current = ret[:positive]
53
+ until params.empty?
54
+ s = params.shift
55
+ s.scan(/./).each do |c|
56
+ c = c.to_sym
57
+ case c
58
+ when :+
59
+ current = ret[:positive]
60
+ when :-
61
+ current = ret[:negative]
62
+ else
63
+ case @modes[c]
64
+ when ONE_PARAM_MASK,ONE_PARAM
65
+ current << [c, params.shift]
66
+ when ONE_PARAM_FOR_POSITIVE
67
+ if current.equal?(ret[:positive])
68
+ current << [c, params.shift]
69
+ else
70
+ current << [c, nil]
71
+ end
72
+ when NO_PARAM
73
+ current << [c, nil]
74
+ else
75
+ if @op_to_mark_map[c]
76
+ current << [c, params.shift]
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ ret
84
+ end
85
+ end
@@ -0,0 +1,30 @@
1
+ class Net::IRC::Message::ServerConfig
2
+ attr_reader :mode_parser
3
+
4
+ def initialize
5
+ @config = {}
6
+ @mode_parser = Net::IRC::Message::ModeParser.new
7
+ end
8
+
9
+ def set(arg)
10
+ params = arg.kind_of?(Net::IRC::Message) ? arg.to_a : arg.split(" ")
11
+
12
+ params[1..-1].each do |s|
13
+ case s
14
+ when /\A:?are supported by this server\z/
15
+ # Ignore
16
+ when /\A([^=]+)=(.*)\z/
17
+ key = Regexp.last_match[1].to_sym
18
+ value = Regexp.last_match[2]
19
+ @config[key] = value
20
+ @mode_parser.set(key, value) if key == :CHANMODES || key == :PREFIX
21
+ else
22
+ @config[s] = true
23
+ end
24
+ end
25
+ end
26
+
27
+ def [](key)
28
+ @config[key]
29
+ end
30
+ end
@@ -0,0 +1,109 @@
1
+ class Net::IRC::Message
2
+ include Net::IRC
3
+
4
+ class InvalidMessage < Net::IRC::IRCException; end
5
+
6
+ attr_reader :prefix, :command, :params
7
+
8
+ # Parse string and return new Message.
9
+ # If the string is invalid message, this method raises Net::IRC::Message::InvalidMessage.
10
+ def self.parse(str)
11
+ _, prefix, command, *rest = *PATTERN::MESSAGE_PATTERN.match(str)
12
+ raise InvalidMessage, "Invalid message: #{str.dump}" unless _
13
+
14
+ case
15
+ when rest[0] && !rest[0].empty?
16
+ middle, trailer, = *rest
17
+ when rest[2] && !rest[2].empty?
18
+ middle, trailer, = *rest[2, 2]
19
+ when rest[1]
20
+ params = []
21
+ trailer = rest[1]
22
+ when rest[3]
23
+ params = []
24
+ trailer = rest[3]
25
+ else
26
+ params = []
27
+ end
28
+
29
+ params ||= middle.split(/ /)[1..-1]
30
+ params << trailer if trailer
31
+
32
+ new(prefix, command, params)
33
+ end
34
+
35
+ def initialize(prefix, command, params)
36
+ @prefix = Prefix.new(prefix.to_s)
37
+ @command = command
38
+ @params = params
39
+ end
40
+
41
+ # Same as @params[n].
42
+ def [](n)
43
+ @params[n]
44
+ end
45
+
46
+ # Iterate params.
47
+ def each(&block)
48
+ @params.each(&block)
49
+ end
50
+
51
+ # Stringfy message to raw IRC message.
52
+ def to_s
53
+ str = ""
54
+
55
+ str << ":#{@prefix} " unless @prefix.empty?
56
+ str << @command
57
+
58
+ if @params
59
+ f = false
60
+ @params.each do |param|
61
+ f = !f && (param.empty? || param[0] == ?: || param.include?(" "))
62
+ str << " "
63
+ str << ":" if f
64
+ str << param
65
+ end
66
+ end
67
+
68
+ str << "\x0D\x0A"
69
+
70
+ str
71
+ end
72
+ alias to_str to_s
73
+
74
+ # Same as params.
75
+ def to_a
76
+ @params.dup
77
+ end
78
+
79
+ # If the message is CTCP, return true.
80
+ def ctcp?
81
+ #message = @params[1]
82
+ #message[0] == ?\01 && message[-1] == ?\01
83
+ /\x01(?>[^\x00\x01\r\n]*)\x01/ === @params[1]
84
+ end
85
+
86
+ def ctcps
87
+ messages = []
88
+ @params[1].gsub!(/\x01(?>[^\x00\x01\r\n]*)\x01/) do
89
+ messages << ctcp_decode($&)
90
+ ""
91
+ end
92
+ messages
93
+ end
94
+
95
+ def inspect
96
+ "#<%s:0x%x prefix:%s command:%s params:%s>" % [
97
+ self.class,
98
+ self.object_id,
99
+ @prefix,
100
+ @command,
101
+ @params.inspect
102
+ ]
103
+ end
104
+
105
+ autoload :ModeParser, "net/irc/message/modeparser"
106
+ autoload :ServerConfig, "net/irc/message/serverconfig"
107
+ #autoload :ISupportModeParser, "net/irc/message/isupportmodeparser"
108
+ end # Message
109
+