net-irc 0.0.4 → 0.0.5
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.
- data/ChangeLog +16 -0
- data/Rakefile +1 -1
- data/examples/nig.rb +4 -0
- data/examples/tig.rb +159 -72
- data/examples/wig.rb +638 -32
- data/lib/net/irc.rb +1 -1
- data/lib/net/irc/client.rb +13 -129
- data/lib/net/irc/client/channel_manager.rb +144 -0
- data/lib/net/irc/constants.rb +1 -1
- data/lib/net/irc/message.rb +3 -1
- data/lib/net/irc/message/modeparser.rb +66 -25
- data/lib/net/irc/message/serverconfig.rb +30 -0
- data/spec/channel_manager_spec.rb +176 -0
- data/spec/modeparser_spec.rb +141 -19
- data/spec/net-irc_spec.rb +9 -69
- metadata +8 -6
- data/lib/net/irc/message/modeparser/hyperion.rb +0 -88
- data/lib/net/irc/message/modeparser/rfc1459.rb +0 -21
data/lib/net/irc.rb
CHANGED
data/lib/net/irc/client.rb
CHANGED
@@ -6,10 +6,11 @@ class Net::IRC::Client
|
|
6
6
|
attr_reader :prefix, :channels
|
7
7
|
|
8
8
|
def initialize(host, port, opts={})
|
9
|
-
@host
|
10
|
-
@port
|
11
|
-
@opts
|
12
|
-
@log
|
9
|
+
@host = host
|
10
|
+
@port = port
|
11
|
+
@opts = OpenStruct.new(opts)
|
12
|
+
@log = @opts.logger || Logger.new($stdout)
|
13
|
+
@server_config = Message::ServerConfig.new
|
13
14
|
@channels = {
|
14
15
|
# "#channel" => {
|
15
16
|
# :modes => [],
|
@@ -21,6 +22,8 @@ class Net::IRC::Client
|
|
21
22
|
|
22
23
|
# Connect to server and start loop.
|
23
24
|
def start
|
25
|
+
# reset config
|
26
|
+
@server_config = Message::ServerConfig.new
|
24
27
|
@socket = TCPSocket.open(@host, @port)
|
25
28
|
on_connected
|
26
29
|
post PASS, @opts.pass if @opts.pass
|
@@ -66,136 +69,17 @@ class Net::IRC::Client
|
|
66
69
|
@prefix = Prefix.new(m[1][/\S+$/])
|
67
70
|
end
|
68
71
|
|
72
|
+
# Default RPL_ISUPPORT callback.
|
73
|
+
# This detects server's configurations.
|
74
|
+
def on_rpl_isupport(m)
|
75
|
+
@server_config.set(m)
|
76
|
+
end
|
77
|
+
|
69
78
|
# Default PING callback. Response PONG.
|
70
79
|
def on_ping(m)
|
71
80
|
post PONG, @prefix ? @prefix.nick : ""
|
72
81
|
end
|
73
82
|
|
74
|
-
# For managing channel
|
75
|
-
def on_rpl_namreply(m)
|
76
|
-
type = m[1]
|
77
|
-
channel = m[2]
|
78
|
-
init_channel(channel)
|
79
|
-
|
80
|
-
@channels.synchronize do
|
81
|
-
m[3].split(/\s+/).each do |u|
|
82
|
-
_, mode, nick = *u.match(/^([@+]?)(.+)/)
|
83
|
-
|
84
|
-
@channels[channel][:users] << nick
|
85
|
-
@channels[channel][:users].uniq!
|
86
|
-
|
87
|
-
case mode
|
88
|
-
when "@" # channel operator
|
89
|
-
@channels[channel][:modes] << [:o, nick]
|
90
|
-
when "+" # voiced (under moderating mode)
|
91
|
-
@channels[channel][:modes] << [:v, nick]
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
case type
|
96
|
-
when "@" # secret
|
97
|
-
@channels[channel][:modes] << [:s, nil]
|
98
|
-
when "*" # private
|
99
|
-
@channels[channel][:modes] << [:p, nil]
|
100
|
-
when "=" # public
|
101
|
-
end
|
102
|
-
|
103
|
-
@channels[channel][:modes].uniq!
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
# For managing channel
|
108
|
-
def on_part(m)
|
109
|
-
nick = m.prefix.nick
|
110
|
-
channel = m[0]
|
111
|
-
init_channel(channel)
|
112
|
-
|
113
|
-
@channels.synchronize do
|
114
|
-
info = @channels[channel]
|
115
|
-
if info
|
116
|
-
info[:users].delete(nick)
|
117
|
-
info[:modes].delete_if {|u|
|
118
|
-
u[1] == nick
|
119
|
-
}
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
# For managing channel
|
125
|
-
def on_quit(m)
|
126
|
-
nick = m.prefix.nick
|
127
|
-
|
128
|
-
@channels.synchronize do
|
129
|
-
@channels.each do |channel, info|
|
130
|
-
info[:users].delete(nick)
|
131
|
-
info[:modes].delete_if {|u|
|
132
|
-
u[1] == nick
|
133
|
-
}
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
# For managing channel
|
139
|
-
def on_kick(m)
|
140
|
-
users = m[1].split(/,/)
|
141
|
-
|
142
|
-
@channels.synchronize do
|
143
|
-
m[0].split(/,/).each do |chan|
|
144
|
-
init_channel(chan)
|
145
|
-
info = @channels[chan]
|
146
|
-
if info
|
147
|
-
users.each do |nick|
|
148
|
-
info[:users].delete(nick)
|
149
|
-
info[:modes].delete_if {|u|
|
150
|
-
u[1] == nick
|
151
|
-
}
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
# For managing channel
|
159
|
-
def on_join(m)
|
160
|
-
nick = m.prefix.nick
|
161
|
-
channel = m[0]
|
162
|
-
|
163
|
-
@channels.synchronize do
|
164
|
-
init_channel(channel)
|
165
|
-
|
166
|
-
@channels[channel][:users] << nick
|
167
|
-
@channels[channel][:users].uniq!
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
# For managing channel
|
172
|
-
def on_mode(m)
|
173
|
-
channel = m[0]
|
174
|
-
@channels.synchronize do
|
175
|
-
init_channel(channel)
|
176
|
-
|
177
|
-
mode = Message::ModeParser::RFC1459::Channel.parse(m)
|
178
|
-
mode[:negative].each do |m|
|
179
|
-
@channels[channel][:modes].delete(m)
|
180
|
-
end
|
181
|
-
|
182
|
-
mode[:positive].each do |m|
|
183
|
-
@channels[channel][:modes] << m
|
184
|
-
end
|
185
|
-
|
186
|
-
@channels[channel][:modes].uniq!
|
187
|
-
[mode[:negative], mode[:positive]]
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
# For managing channel
|
192
|
-
def init_channel(channel)
|
193
|
-
@channels[channel] ||= {
|
194
|
-
:modes => [],
|
195
|
-
:users => [],
|
196
|
-
}
|
197
|
-
end
|
198
|
-
|
199
83
|
# Do nothing.
|
200
84
|
# This is for avoiding error on calling super.
|
201
85
|
# So you can always call super at subclass.
|
@@ -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(/\s+/).each do |u|
|
11
|
+
_, mode, nick = *u.match(/^([@+]?)(.+)/)
|
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! {|m, target|
|
109
|
+
(target == oldnick) ? [m, newnick] : [m, 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
|
+
mode = @server_config.mode_parser.parse(m)
|
122
|
+
mode[:negative].each do |m|
|
123
|
+
@channels[channel][:modes].delete(m)
|
124
|
+
end
|
125
|
+
|
126
|
+
mode[:positive].each do |m|
|
127
|
+
@channels[channel][:modes] << m
|
128
|
+
end
|
129
|
+
|
130
|
+
@channels[channel][:modes].uniq!
|
131
|
+
[mode[:negative], mode[: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
|
+
|
data/lib/net/irc/constants.rb
CHANGED
data/lib/net/irc/message.rb
CHANGED
@@ -76,7 +76,7 @@ class Net::IRC::Message
|
|
76
76
|
|
77
77
|
# Same as params.
|
78
78
|
def to_a
|
79
|
-
@params
|
79
|
+
@params.dup
|
80
80
|
end
|
81
81
|
|
82
82
|
# If the message is CTCP, return true.
|
@@ -96,5 +96,7 @@ class Net::IRC::Message
|
|
96
96
|
end
|
97
97
|
|
98
98
|
autoload :ModeParser, "net/irc/message/modeparser"
|
99
|
+
autoload :ServerConfig, "net/irc/message/serverconfig"
|
100
|
+
autoload :ISupportModeParser, "net/irc/message/isupportmodeparser"
|
99
101
|
end # Message
|
100
102
|
|
@@ -1,44 +1,85 @@
|
|
1
1
|
class Net::IRC::Message::ModeParser
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
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-zA-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
|
6
41
|
end
|
7
42
|
|
8
43
|
def parse(arg)
|
9
44
|
params = arg.kind_of?(Net::IRC::Message) ? arg.to_a : arg.split(/\s+/)
|
45
|
+
params.shift
|
10
46
|
|
11
|
-
ret =
|
47
|
+
ret = {
|
12
48
|
:positive => [],
|
13
49
|
:negative => [],
|
14
50
|
}
|
15
51
|
|
16
|
-
current =
|
17
|
-
params
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
when @require_arg.include?(sym)
|
27
|
-
current << [sym, params[arg_pos + 2]]
|
28
|
-
arg_pos += 1
|
29
|
-
when @definition.key?(sym)
|
30
|
-
current << [sym, nil]
|
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]
|
31
62
|
else
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
35
79
|
end
|
36
80
|
end
|
37
81
|
end
|
38
82
|
|
39
83
|
ret
|
40
84
|
end
|
41
|
-
|
42
|
-
autoload :RFC1459, "net/irc/message/modeparser/rfc1459"
|
43
|
-
autoload :Hyperion, "net/irc/message/modeparser/hyperion"
|
44
85
|
end
|