net-irc 0.0.1 → 0.0.2
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 +27 -0
- data/Rakefile +2 -1
- data/examples/client.rb +23 -0
- data/examples/lig.rb +306 -108
- data/examples/lingr.rb +333 -0
- data/examples/nig.rb +144 -0
- data/examples/tig.rb +153 -48
- data/examples/wig.rb +40 -15
- data/lib/net/irc.rb +95 -77
- data/spec/net-irc_spec.rb +385 -0
- data/spec/spec.opts +1 -0
- metadata +8 -3
data/lib/net/irc.rb
CHANGED
@@ -4,11 +4,12 @@ require "ostruct"
|
|
4
4
|
require "socket"
|
5
5
|
require "thread"
|
6
6
|
require "logger"
|
7
|
+
require "monitor"
|
7
8
|
|
8
9
|
module Net; end
|
9
10
|
|
10
11
|
module Net::IRC
|
11
|
-
VERSION = "0.0.
|
12
|
+
VERSION = "0.0.2"
|
12
13
|
class IRCException < StandardError; end
|
13
14
|
|
14
15
|
module PATTERN # :nodoc:
|
@@ -309,7 +310,7 @@ module Net::IRC
|
|
309
310
|
|
310
311
|
# Extract prefix string to [nick, user, host] Array.
|
311
312
|
def extract
|
312
|
-
_, *ret = *self.match(/^([^\s!]+)
|
313
|
+
_, *ret = *self.match(/^([^\s!]+)(?:!([^\s@]+)@(\S+))?$/)
|
313
314
|
ret
|
314
315
|
end
|
315
316
|
end
|
@@ -449,6 +450,7 @@ class Net::IRC::Client
|
|
449
450
|
# :users => [],
|
450
451
|
# }
|
451
452
|
}
|
453
|
+
@channels.extend(MonitorMixin)
|
452
454
|
end
|
453
455
|
|
454
456
|
# Connect to server and start loop.
|
@@ -495,12 +497,12 @@ class Net::IRC::Client
|
|
495
497
|
# Default RPL_WELCOME callback.
|
496
498
|
# This sets @prefix from the message.
|
497
499
|
def on_rpl_welcome(m)
|
498
|
-
@prefix = Prefix.new(m[1][/\S
|
500
|
+
@prefix = Prefix.new(m[1][/\S+$/])
|
499
501
|
end
|
500
502
|
|
501
503
|
# Default PING callback. Response PONG.
|
502
504
|
def on_ping(m)
|
503
|
-
post PONG, @nick
|
505
|
+
post PONG, @prefix ? @prefix.nick : ""
|
504
506
|
end
|
505
507
|
|
506
508
|
# For managing channel
|
@@ -509,29 +511,31 @@ class Net::IRC::Client
|
|
509
511
|
channel = m[2]
|
510
512
|
init_channel(channel)
|
511
513
|
|
512
|
-
|
513
|
-
|
514
|
+
@channels.synchronize do
|
515
|
+
m[3].split(/\s+/).each do |u|
|
516
|
+
_, mode, nick = *u.match(/^([@+]?)(.+)/)
|
514
517
|
|
515
|
-
|
516
|
-
|
518
|
+
@channels[channel][:users] << nick
|
519
|
+
@channels[channel][:users].uniq!
|
517
520
|
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
521
|
+
case mode
|
522
|
+
when "@" # channel operator
|
523
|
+
@channels[channel][:modes] << ["o", nick]
|
524
|
+
when "+" # voiced (under moderating mode)
|
525
|
+
@channels[channel][:modes] << ["v", nick]
|
526
|
+
end
|
523
527
|
end
|
524
|
-
end
|
525
528
|
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
529
|
+
case type
|
530
|
+
when "@" # secret
|
531
|
+
@channels[channel][:modes] << ["s", nil]
|
532
|
+
when "*" # private
|
533
|
+
@channels[channel][:modes] << ["p", nil]
|
534
|
+
when "=" # public
|
535
|
+
end
|
533
536
|
|
534
|
-
|
537
|
+
@channels[channel][:modes].uniq!
|
538
|
+
end
|
535
539
|
end
|
536
540
|
|
537
541
|
# For managing channel
|
@@ -540,12 +544,14 @@ class Net::IRC::Client
|
|
540
544
|
channel = m[0]
|
541
545
|
init_channel(channel)
|
542
546
|
|
543
|
-
|
544
|
-
|
545
|
-
info
|
546
|
-
|
547
|
-
|
548
|
-
|
547
|
+
@channels.synchronize do
|
548
|
+
info = @channels[channel]
|
549
|
+
if info
|
550
|
+
info[:users].delete(nick)
|
551
|
+
info[:modes].delete_if {|u|
|
552
|
+
u[1] == nick
|
553
|
+
}
|
554
|
+
end
|
549
555
|
end
|
550
556
|
end
|
551
557
|
|
@@ -553,26 +559,31 @@ class Net::IRC::Client
|
|
553
559
|
def on_quit(m)
|
554
560
|
nick = m.prefix.nick
|
555
561
|
|
556
|
-
@channels.
|
557
|
-
info
|
558
|
-
|
559
|
-
|
560
|
-
|
562
|
+
@channels.synchronize do
|
563
|
+
@channels.each do |channel, info|
|
564
|
+
info[:users].delete(nick)
|
565
|
+
info[:modes].delete_if {|u|
|
566
|
+
u[1] == nick
|
567
|
+
}
|
568
|
+
end
|
561
569
|
end
|
562
570
|
end
|
563
571
|
|
564
572
|
# For managing channel
|
565
573
|
def on_kick(m)
|
566
574
|
users = m[1].split(/,/)
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
575
|
+
|
576
|
+
@channels.synchronize do
|
577
|
+
m[0].split(/,/).each do |chan|
|
578
|
+
init_channel(chan)
|
579
|
+
info = @channels[chan]
|
580
|
+
if info
|
581
|
+
users.each do |nick|
|
582
|
+
info[:users].delete(nick)
|
583
|
+
info[:modes].delete_if {|u|
|
584
|
+
u[1] == nick
|
585
|
+
}
|
586
|
+
end
|
576
587
|
end
|
577
588
|
end
|
578
589
|
end
|
@@ -582,47 +593,52 @@ class Net::IRC::Client
|
|
582
593
|
def on_join(m)
|
583
594
|
nick = m.prefix.nick
|
584
595
|
channel = m[0]
|
585
|
-
init_channel(channel)
|
586
596
|
|
587
|
-
@channels
|
588
|
-
|
597
|
+
@channels.synchronize do
|
598
|
+
init_channel(channel)
|
599
|
+
|
600
|
+
@channels[channel][:users] << nick
|
601
|
+
@channels[channel][:users].uniq!
|
602
|
+
end
|
589
603
|
end
|
590
604
|
|
591
605
|
# For managing channel
|
592
606
|
def on_mode(m)
|
593
607
|
channel = m[0]
|
594
|
-
|
608
|
+
@channels.synchronize do
|
609
|
+
init_channel(channel)
|
610
|
+
|
611
|
+
positive_mode = []
|
612
|
+
negative_mode = []
|
613
|
+
|
614
|
+
mode = positive_mode
|
615
|
+
arg_pos = 0
|
616
|
+
m[1].each_byte do |c|
|
617
|
+
case c
|
618
|
+
when ?+
|
619
|
+
mode = positive_mode
|
620
|
+
when ?-
|
621
|
+
mode = negative_mode
|
622
|
+
when ?o, ?v, ?k, ?l, ?b, ?e, ?I
|
623
|
+
mode << [c.chr, m[arg_pos + 2]]
|
624
|
+
arg_pos += 1
|
625
|
+
else
|
626
|
+
mode << [c.chr, nil]
|
627
|
+
end
|
628
|
+
end
|
629
|
+
mode = nil
|
595
630
|
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
mode = positive_mode
|
600
|
-
arg_pos = 0
|
601
|
-
m[1].each_byte do |c|
|
602
|
-
case c
|
603
|
-
when ?+
|
604
|
-
mode = positive_mode
|
605
|
-
when ?-
|
606
|
-
mode = negative_mode
|
607
|
-
when ?o, ?v, ?k, ?l, ?b, ?e, ?I
|
608
|
-
mode << [c.chr, m[arg_pos + 2]]
|
609
|
-
arg_pos += 1
|
610
|
-
else
|
611
|
-
mode << [c.chr, nil]
|
631
|
+
negative_mode.each do |m|
|
632
|
+
@channels[channel][:modes].delete(m)
|
612
633
|
end
|
613
|
-
end
|
614
|
-
mode = nil
|
615
634
|
|
616
|
-
|
617
|
-
|
618
|
-
|
635
|
+
positive_mode.each do |m|
|
636
|
+
@channels[channel][:modes] << m
|
637
|
+
end
|
619
638
|
|
620
|
-
|
621
|
-
|
639
|
+
@channels[channel][:modes].uniq!
|
640
|
+
[negative_mode, positive_mode]
|
622
641
|
end
|
623
|
-
|
624
|
-
@channels[channel][:modes].uniq!
|
625
|
-
[negative_mode, positive_mode]
|
626
642
|
end
|
627
643
|
|
628
644
|
# For managing channel
|
@@ -719,7 +735,7 @@ class Net::IRC::Server
|
|
719
735
|
|
720
736
|
# Override subclass.
|
721
737
|
def server_name
|
722
|
-
"
|
738
|
+
"net-irc"
|
723
739
|
end
|
724
740
|
|
725
741
|
# Override subclass.
|
@@ -830,15 +846,17 @@ class Net::IRC::Server
|
|
830
846
|
})
|
831
847
|
@log.debug "SEND: #{m.to_s.chomp}"
|
832
848
|
@socket << m
|
849
|
+
rescue IOError
|
850
|
+
finish
|
833
851
|
end
|
834
852
|
|
835
853
|
# Call when client connected.
|
836
854
|
# Send RPL_WELCOME sequence. If you want to customize, override this method at subclass.
|
837
855
|
def inital_message
|
838
|
-
post
|
839
|
-
post
|
840
|
-
post
|
841
|
-
post
|
856
|
+
post server_name, RPL_WELCOME, @nick, "Welcome to the Internet Relay Network #{@prefix}"
|
857
|
+
post server_name, RPL_YOURHOST, @nick, "Your host is #{server_name}, running version #{server_version}"
|
858
|
+
post server_name, RPL_CREATED, @nick, "This server was created #{Time.now}"
|
859
|
+
post server_name, RPL_MYINFO, @nick, "#{server_name} #{server_version} #{avaiable_user_modes} #{avaiable_channel_modes}"
|
842
860
|
end
|
843
861
|
end
|
844
862
|
end # Server
|
@@ -0,0 +1,385 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH << "lib"
|
4
|
+
$LOAD_PATH << "../lib"
|
5
|
+
|
6
|
+
require "net/irc"
|
7
|
+
include Net::IRC
|
8
|
+
include Constants
|
9
|
+
|
10
|
+
describe Net::IRC::Message, "construct" do
|
11
|
+
|
12
|
+
it "should generate message correctly" do
|
13
|
+
m = Message.new("foo", "PRIVMSG", ["#channel", "message"])
|
14
|
+
m.to_s.should == ":foo PRIVMSG #channel message\r\n"
|
15
|
+
|
16
|
+
m = Message.new("foo", "PRIVMSG", ["#channel", "message with space"])
|
17
|
+
m.to_s.should == ":foo PRIVMSG #channel :message with space\r\n"
|
18
|
+
|
19
|
+
m = Message.new(nil, "PRIVMSG", ["#channel", "message"])
|
20
|
+
m.to_s.should == "PRIVMSG #channel message\r\n"
|
21
|
+
|
22
|
+
m = Message.new(nil, "PRIVMSG", ["#channel", "message with space"])
|
23
|
+
m.to_s.should == "PRIVMSG #channel :message with space\r\n"
|
24
|
+
|
25
|
+
m = Message.new(nil, "MODE", [
|
26
|
+
"#channel",
|
27
|
+
"+ooo",
|
28
|
+
"nick1",
|
29
|
+
"nick2",
|
30
|
+
"nick3"
|
31
|
+
])
|
32
|
+
m.to_s.should == "MODE #channel +ooo nick1 nick2 nick3\r\n"
|
33
|
+
|
34
|
+
m = Message.new(nil, "KICK", [
|
35
|
+
"#channel,#channel1",
|
36
|
+
"nick1,nick2",
|
37
|
+
])
|
38
|
+
m.to_s.should == "KICK #channel,#channel1 nick1,nick2\r\n"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should have ctcp? method" do
|
42
|
+
m = Message.new("foo", "PRIVMSG", ["#channel", "\x01ACTION foo\x01"])
|
43
|
+
m.ctcp?.should be_true
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should behave as Array contains params" do
|
47
|
+
m = Message.new("foo", "PRIVMSG", ["#channel", "message"])
|
48
|
+
m[0].should == m.params[0]
|
49
|
+
m[1].should == m.params[1]
|
50
|
+
m.to_a.should == ["#channel", "message"]
|
51
|
+
|
52
|
+
channel, message = *m
|
53
|
+
channel.should == "#channel"
|
54
|
+
message.should == "message"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe Net::IRC::Message, "parse" do
|
59
|
+
it "should parse correctly following RFC." do
|
60
|
+
m = Message.parse("PRIVMSG #channel message\r\n")
|
61
|
+
m.prefix.should == ""
|
62
|
+
m.command.should == "PRIVMSG"
|
63
|
+
m.params.should == ["#channel", "message"]
|
64
|
+
|
65
|
+
m = Message.parse("PRIVMSG #channel :message leading :\r\n")
|
66
|
+
m.prefix.should == ""
|
67
|
+
m.command.should == "PRIVMSG"
|
68
|
+
m.params.should == ["#channel", "message leading :"]
|
69
|
+
|
70
|
+
m = Message.parse("PRIVMSG #channel middle :message leading :\r\n")
|
71
|
+
m.prefix.should == ""
|
72
|
+
m.command.should == "PRIVMSG"
|
73
|
+
m.params.should == ["#channel", "middle", "message leading :"]
|
74
|
+
|
75
|
+
m = Message.parse("PRIVMSG #channel middle message with middle\r\n")
|
76
|
+
m.prefix.should == ""
|
77
|
+
m.command.should == "PRIVMSG"
|
78
|
+
m.params.should == ["#channel", "middle", "message", "with", "middle"]
|
79
|
+
|
80
|
+
m = Message.parse(":prefix PRIVMSG #channel message\r\n")
|
81
|
+
m.prefix.should == "prefix"
|
82
|
+
m.command.should == "PRIVMSG"
|
83
|
+
m.params.should == ["#channel", "message"]
|
84
|
+
|
85
|
+
m = Message.parse(":prefix PRIVMSG #channel :message leading :\r\n")
|
86
|
+
m.prefix.should == "prefix"
|
87
|
+
m.command.should == "PRIVMSG"
|
88
|
+
m.params.should == ["#channel", "message leading :"]
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should allow multibyte " do
|
92
|
+
m = Message.parse(":てすと PRIVMSG #channel :message leading :\r\n")
|
93
|
+
m.prefix.should == "てすと"
|
94
|
+
m.command.should == "PRIVMSG"
|
95
|
+
m.params.should == ["#channel", "message leading :"]
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should allow space at end" do
|
99
|
+
m = Message.parse("JOIN #foobar \r\n")
|
100
|
+
m.prefix.should == ""
|
101
|
+
m.command.should == "JOIN"
|
102
|
+
m.params.should == ["#foobar"]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe Net::IRC::Constants, "lookup" do
|
107
|
+
it "should lookup numeric replies from Net::IRC::COMMANDS" do
|
108
|
+
welcome = Net::IRC::Constants.const_get("RPL_WELCOME")
|
109
|
+
welcome.should == "001"
|
110
|
+
Net::IRC::COMMANDS[welcome].should == "RPL_WELCOME"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe Net::IRC::Prefix, "" do
|
115
|
+
it "should be kind of String" do
|
116
|
+
Prefix.new("").should be_kind_of(String)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should parse prefix correctly." do
|
120
|
+
prefix = Prefix.new("foo!bar@localhost")
|
121
|
+
prefix.extract.should == ["foo", "bar", "localhost"]
|
122
|
+
|
123
|
+
prefix = Prefix.new("foo!-bar@localhost")
|
124
|
+
prefix.extract.should == ["foo", "-bar", "localhost"]
|
125
|
+
|
126
|
+
prefix = Prefix.new("foo!+bar@localhost")
|
127
|
+
prefix.extract.should == ["foo", "+bar", "localhost"]
|
128
|
+
|
129
|
+
prefix = Prefix.new("foo!~bar@localhost")
|
130
|
+
prefix.extract.should == ["foo", "~bar", "localhost"]
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should allow multibyte in nick." do
|
134
|
+
prefix = Prefix.new("あああ!~bar@localhost")
|
135
|
+
prefix.extract.should == ["あああ", "~bar", "localhost"]
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should allow lame prefix." do
|
139
|
+
prefix = Prefix.new("nick")
|
140
|
+
prefix.extract.should == ["nick", nil, nil]
|
141
|
+
end
|
142
|
+
|
143
|
+
it "has nick method" do
|
144
|
+
prefix = Prefix.new("foo!bar@localhost")
|
145
|
+
prefix.nick.should == "foo"
|
146
|
+
end
|
147
|
+
|
148
|
+
it "has user method" do
|
149
|
+
prefix = Prefix.new("foo!bar@localhost")
|
150
|
+
prefix.user.should == "bar"
|
151
|
+
end
|
152
|
+
|
153
|
+
it "has host method" do
|
154
|
+
prefix = Prefix.new("foo!bar@localhost")
|
155
|
+
prefix.host.should == "localhost"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe Net::IRC, "utilities" do
|
160
|
+
it "has ctcp_encoding method" do
|
161
|
+
message = ctcp_encoding "ACTION hehe"
|
162
|
+
message.should == "\x01ACTION hehe\x01"
|
163
|
+
|
164
|
+
message = ctcp_encoding "ACTION \x01 \x5c "
|
165
|
+
message.should == "\x01ACTION \x5c\x61 \x5c\x5c \x01"
|
166
|
+
|
167
|
+
message = ctcp_encoding "ACTION \x00 \x0a \x0d \x10 "
|
168
|
+
message.should == "\x01ACTION \x100 \x10n \x10r \x10\x10 \x01"
|
169
|
+
end
|
170
|
+
|
171
|
+
it "has ctcp_decoding method" do
|
172
|
+
message = ctcp_decoding "\x01ACTION hehe\x01"
|
173
|
+
message.should == "ACTION hehe"
|
174
|
+
|
175
|
+
message = ctcp_decoding "\x01ACTION \x5c\x61 \x5c\x5c \x01"
|
176
|
+
message.should == "ACTION \x01 \x5c "
|
177
|
+
|
178
|
+
message = ctcp_decoding "\x01ACTION \x100 \x10n \x10r \x10\x10 \x01"
|
179
|
+
message.should == "ACTION \x00 \x0a \x0d \x10 "
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
class TestServerSession < Net::IRC::Server::Session
|
184
|
+
@@testq = SizedQueue.new(1)
|
185
|
+
@@instance = nil
|
186
|
+
|
187
|
+
def self.testq
|
188
|
+
@@testq
|
189
|
+
end
|
190
|
+
|
191
|
+
def self.instance
|
192
|
+
@@instance
|
193
|
+
end
|
194
|
+
|
195
|
+
def initialize(*args)
|
196
|
+
super
|
197
|
+
@@instance = self
|
198
|
+
end
|
199
|
+
|
200
|
+
def on_message(m)
|
201
|
+
@@testq << m
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
class TestClient < Net::IRC::Client
|
206
|
+
@@testq = SizedQueue.new(1)
|
207
|
+
|
208
|
+
def self.testq
|
209
|
+
@@testq
|
210
|
+
end
|
211
|
+
|
212
|
+
def on_message(m)
|
213
|
+
@@testq << m
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe Net::IRC, "server and client" do
|
218
|
+
before :all do
|
219
|
+
@port = nil
|
220
|
+
@server, @client = nil, nil
|
221
|
+
|
222
|
+
Thread.abort_on_exception = true
|
223
|
+
Thread.start do
|
224
|
+
@server = Net::IRC::Server.new("localhost", @port, TestServerSession, {
|
225
|
+
:logger => Logger.new(nil),
|
226
|
+
})
|
227
|
+
@server.start
|
228
|
+
end
|
229
|
+
|
230
|
+
true until @server.instance_variable_get(:@serv)
|
231
|
+
|
232
|
+
@port = @server.instance_variable_get(:@serv).addr[1]
|
233
|
+
|
234
|
+
Thread.start do
|
235
|
+
@client = TestClient.new("localhost", @port, {
|
236
|
+
:nick => "foonick",
|
237
|
+
:user => "foouser",
|
238
|
+
:real => "foo real name",
|
239
|
+
:pass => "foopass",
|
240
|
+
:logger => Logger.new(nil),
|
241
|
+
})
|
242
|
+
@client.start
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
server_q = TestServerSession.testq
|
247
|
+
client_q = TestClient.testq
|
248
|
+
|
249
|
+
it "client should send pass/nick/user sequence." do
|
250
|
+
server_q.pop.to_s.should == "PASS foopass\r\n"
|
251
|
+
server_q.pop.to_s.should == "NICK foonick\r\n"
|
252
|
+
server_q.pop.to_s.should == "USER foouser 0 * :foo real name\r\n"
|
253
|
+
end
|
254
|
+
|
255
|
+
it "server should send 001,002,003 numeric replies." do
|
256
|
+
client_q.pop.to_s.should match(/^:net-irc 001 foonick :Welcome to the Internet Relay Network \S+!\S+@\S+/)
|
257
|
+
client_q.pop.to_s.should match(/^:net-irc 002 foonick :Your host is .+?, running version /)
|
258
|
+
client_q.pop.to_s.should match(/^:net-irc 003 foonick :This server was created /)
|
259
|
+
end
|
260
|
+
|
261
|
+
it "client posts PRIVMSG and server receives it." do
|
262
|
+
@client.instance_eval do
|
263
|
+
post PRIVMSG, "#channel", "message a b c"
|
264
|
+
end
|
265
|
+
|
266
|
+
message = server_q.pop
|
267
|
+
message.should be_a_kind_of(Net::IRC::Message)
|
268
|
+
message.to_s.should == "PRIVMSG #channel :message a b c\r\n"
|
269
|
+
end
|
270
|
+
|
271
|
+
it "client should manage channel mode/users correctly" do
|
272
|
+
client = @client
|
273
|
+
c = @client.instance_variable_get(:@channels)
|
274
|
+
TestServerSession.instance.instance_eval do
|
275
|
+
Thread.exclusive do
|
276
|
+
post client.prefix, JOIN, "#test"
|
277
|
+
post nil, NOTICE, "#test", "sep1"
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
true until client_q.pop.to_s == "NOTICE #test sep1\r\n"
|
282
|
+
c.synchronize do
|
283
|
+
c.should be_a_kind_of(Hash)
|
284
|
+
c["#test"].should be_a_kind_of(Hash)
|
285
|
+
c["#test"][:modes].should be_a_kind_of(Array)
|
286
|
+
c["#test"][:users].should be_a_kind_of(Array)
|
287
|
+
c["#test"][:users].should == ["foonick"]
|
288
|
+
end
|
289
|
+
|
290
|
+
TestServerSession.instance.instance_eval do
|
291
|
+
Thread.exclusive do
|
292
|
+
post "test1!test@localhost", JOIN, "#test"
|
293
|
+
post "test2!test@localhost", JOIN, "#test"
|
294
|
+
post nil, NOTICE, "#test", "sep2"
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
true until client_q.pop.to_s == "NOTICE #test sep2\r\n"
|
299
|
+
c.synchronize do
|
300
|
+
c["#test"][:users].should == ["foonick", "test1", "test2"]
|
301
|
+
end
|
302
|
+
|
303
|
+
TestServerSession.instance.instance_eval do
|
304
|
+
Thread.exclusive do
|
305
|
+
post nil, RPL_NAMREPLY, client.prefix.nick, "@", "#test", "foo1 foo2 foo3 @foo4 +foo5"
|
306
|
+
post nil, NOTICE, "#test", "sep3"
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
true until client_q.pop.to_s == "NOTICE #test sep3\r\n"
|
311
|
+
c.synchronize do
|
312
|
+
c["#test"][:users].should == ["foonick", "test1", "test2", "foo1", "foo2", "foo3", "foo4", "foo5"]
|
313
|
+
c["#test"][:modes].should include(["s", nil])
|
314
|
+
c["#test"][:modes].should include(["o", "foo4"])
|
315
|
+
c["#test"][:modes].should include(["v", "foo5"])
|
316
|
+
end
|
317
|
+
|
318
|
+
TestServerSession.instance.instance_eval do
|
319
|
+
Thread.exclusive do
|
320
|
+
post nil, RPL_NAMREPLY, client.prefix.nick, "@", "#test1", "foo1 foo2 foo3 @foo4 +foo5"
|
321
|
+
post "foo4!foo@localhost", QUIT, "message"
|
322
|
+
post "foo5!foo@localhost", PART, "#test1", "message"
|
323
|
+
post client.prefix, KICK, "#test", "foo1", "message"
|
324
|
+
post client.prefix, MODE, "#test", "+o", "foo2"
|
325
|
+
post nil, NOTICE, "#test", "sep4"
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
true until client_q.pop.to_s == "NOTICE #test sep4\r\n"
|
330
|
+
c.synchronize do
|
331
|
+
c["#test"][:users].should == ["foonick", "test1", "test2", "foo2", "foo3", "foo5"]
|
332
|
+
c["#test1"][:users].should == ["foo1", "foo2", "foo3"]
|
333
|
+
c["#test"][:modes].should_not include(["o", "foo4"])
|
334
|
+
c["#test"][:modes].should include(["v", "foo5"])
|
335
|
+
c["#test1"][:modes].should_not include(["v", "foo5"])
|
336
|
+
c["#test"][:modes].should include(["o", "foo2"])
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
it "should allow lame RPL_WELCOME (not prefix but nick)" do
|
341
|
+
client = @client
|
342
|
+
TestServerSession.instance.instance_eval do
|
343
|
+
Thread.exclusive do
|
344
|
+
post "server", RPL_WELCOME, client.prefix.nick, "Welcome to the Internet Relay Network #{client.prefix.nick}"
|
345
|
+
post nil, NOTICE, "#test", "sep1"
|
346
|
+
end
|
347
|
+
end
|
348
|
+
true until client_q.pop.to_s == "NOTICE #test sep1\r\n"
|
349
|
+
client.prefix.should == "foonick"
|
350
|
+
end
|
351
|
+
|
352
|
+
it "should destroy closed session" do
|
353
|
+
oldclient = @client
|
354
|
+
@client.finish
|
355
|
+
|
356
|
+
Thread.start do
|
357
|
+
@client = TestClient.new("localhost", @port, {
|
358
|
+
:nick => "foonick",
|
359
|
+
:user => "foouser",
|
360
|
+
:real => "foo real name",
|
361
|
+
:pass => "foopass",
|
362
|
+
:logger => Logger.new(nil),
|
363
|
+
})
|
364
|
+
@client.start
|
365
|
+
end
|
366
|
+
|
367
|
+
Thread.pass
|
368
|
+
true while @client == oldclient
|
369
|
+
|
370
|
+
c = @client.instance_variable_get(:@channels)
|
371
|
+
TestServerSession.instance.instance_eval do
|
372
|
+
Thread.exclusive do
|
373
|
+
post nil, NOTICE, "#test", "sep1"
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
true until client_q.pop.to_s == "NOTICE #test sep1\r\n"
|
378
|
+
end
|
379
|
+
|
380
|
+
after :all do
|
381
|
+
@server.finish
|
382
|
+
@client.finish
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|