net-irc 0.0.3 → 0.0.4
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 +7 -0
- data/examples/hatena-star-stream.rb +265 -0
- data/examples/lig.rb +3 -0
- data/examples/mixi.rb +236 -0
- data/examples/tig.rb +68 -21
- data/lib/net/irc.rb +6 -811
- data/lib/net/irc/client.rb +227 -0
- data/lib/net/irc/constants.rb +214 -0
- data/lib/net/irc/message.rb +100 -0
- data/lib/net/irc/message/modeparser.rb +44 -0
- data/lib/net/irc/message/modeparser/hyperion.rb +88 -0
- data/lib/net/irc/message/modeparser/rfc1459.rb +21 -0
- data/lib/net/irc/pattern.rb +68 -0
- data/lib/net/irc/server.rb +188 -0
- data/spec/modeparser_spec.rb +43 -0
- data/spec/net-irc_spec.rb +7 -7
- metadata +17 -3
data/examples/tig.rb
CHANGED
@@ -23,7 +23,7 @@ Configuration example for Tiarra ( http://coderepos.org/share/wiki/Tiarra ).
|
|
23
23
|
twitter {
|
24
24
|
host: localhost
|
25
25
|
port: 16668
|
26
|
-
name: username@example.com athack jabber=username@example.com:jabberpasswd
|
26
|
+
name: username@example.com athack jabber=username@example.com:jabberpasswd tid=10
|
27
27
|
password: password on Twitter
|
28
28
|
in-encoding: utf8
|
29
29
|
out-encoding: utf8
|
@@ -40,6 +40,32 @@ it's good for Twitter like reply command (@nick).
|
|
40
40
|
In this case, you will see torrent of join messages after connected,
|
41
41
|
because NAMES list can't send @ leading nick (it interpreted op.)
|
42
42
|
|
43
|
+
### tid=<color>
|
44
|
+
|
45
|
+
Apply id to each message for make favorites by CTCP ACTION.
|
46
|
+
|
47
|
+
/me fav id
|
48
|
+
|
49
|
+
<color> can be
|
50
|
+
|
51
|
+
0 => white
|
52
|
+
1 => black
|
53
|
+
2 => blue navy
|
54
|
+
3 => green
|
55
|
+
4 => red
|
56
|
+
5 => brown maroon
|
57
|
+
6 => purple
|
58
|
+
7 => orange olive
|
59
|
+
8 => yellow
|
60
|
+
9 => lightgreen lime
|
61
|
+
10 => teal
|
62
|
+
11 => lightcyan cyan aqua
|
63
|
+
12 => lightblue royal
|
64
|
+
13 => pink lightpurple fuchsia
|
65
|
+
14 => grey
|
66
|
+
15 => lightgrey silver
|
67
|
+
|
68
|
+
|
43
69
|
### jabber=<jid>:<pass>
|
44
70
|
|
45
71
|
If `jabber=<jid>:<pass>` option specified,
|
@@ -52,6 +78,10 @@ install 'xmpp4r-simple' gem.
|
|
52
78
|
|
53
79
|
Be careful for managing password.
|
54
80
|
|
81
|
+
### alwaysim
|
82
|
+
|
83
|
+
Use IM instead of any APIs (ex. post)
|
84
|
+
|
55
85
|
|
56
86
|
## Licence
|
57
87
|
|
@@ -122,13 +152,15 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
122
152
|
post server_name, MODE, main_channel, "+o", @prefix.nick
|
123
153
|
|
124
154
|
@real, *@opts = @opts.name || @real.split(/\s+/)
|
125
|
-
@opts
|
155
|
+
@opts = @opts.inject({}) {|r,i|
|
156
|
+
key, value = i.split(/=/)
|
157
|
+
r.update(key => value)
|
158
|
+
}
|
126
159
|
@tmap = TypableMap.new
|
127
160
|
|
128
|
-
|
129
|
-
|
130
|
-
jid
|
131
|
-
jabber.replace("jabber=#{jid}:********")
|
161
|
+
if @opts["jabber"]
|
162
|
+
jid, pass = @opts["jabber"].split(/:/, 2)
|
163
|
+
@opts["jabber"].replace("jabber=#{jid}:********")
|
132
164
|
if jabber_bot_id
|
133
165
|
begin
|
134
166
|
require "xmpp4r-simple"
|
@@ -139,11 +171,12 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
139
171
|
finish
|
140
172
|
end
|
141
173
|
else
|
142
|
-
jabber
|
174
|
+
@opts.delete("jabber")
|
143
175
|
log "This gateway does not support Jabber bot."
|
144
176
|
end
|
145
177
|
end
|
146
178
|
|
179
|
+
log "Client Options: #{@opts.inspect}"
|
147
180
|
@log.info "Client Options: #{@opts.inspect}"
|
148
181
|
|
149
182
|
@timeline = []
|
@@ -164,7 +197,7 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
164
197
|
end
|
165
198
|
sleep 3
|
166
199
|
|
167
|
-
return if jabber
|
200
|
+
return if @opts["jabber"]
|
168
201
|
|
169
202
|
@check_timeline_thread = Thread.start do
|
170
203
|
loop do
|
@@ -198,7 +231,7 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
198
231
|
target, message = *m.params
|
199
232
|
begin
|
200
233
|
if target =~ /^#/
|
201
|
-
if @im && @im.connected? # in jabber mode, using jabber post
|
234
|
+
if @opts.key?("alwaysim") && @im && @im.connected? # in jabber mode, using jabber post
|
202
235
|
ret = @im.deliver(jabber_bot_id, message)
|
203
236
|
post "#{nick}!#{nick}@#{api_base.host}", TOPIC, main_channel, untinyurl(message)
|
204
237
|
else
|
@@ -234,17 +267,27 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
234
267
|
end
|
235
268
|
|
236
269
|
unless res
|
237
|
-
post nil, ERR_NOSUCHNICK, nick, "No such nick/channel"
|
270
|
+
post nil, ERR_NOSUCHNICK, nick, "No such nick/channel"
|
238
271
|
end
|
239
272
|
when "fav"
|
240
273
|
tid = args[0]
|
241
|
-
|
242
|
-
if
|
274
|
+
st = @tmap[tid]
|
275
|
+
if st
|
276
|
+
id = st["id"] || st["rid"]
|
243
277
|
res = api("favorites/create/#{id}", {})
|
244
278
|
post nil, NOTICE, main_channel, "Fav: #{res["screen_name"]}: #{res["text"]}"
|
245
279
|
else
|
246
280
|
post nil, NOTICE, main_channel, "No such id #{tid}"
|
247
281
|
end
|
282
|
+
when "link"
|
283
|
+
tid = args[0]
|
284
|
+
st = @tmap[tid]
|
285
|
+
if st
|
286
|
+
st["link"] = (api_base + "/#{st["user"]["screen_name"]}/statuses/#{st["id"]}").to_s unless st["link"]
|
287
|
+
post nil, NOTICE, main_channel, st["link"]
|
288
|
+
else
|
289
|
+
post nil, NOTICE, main_channel, "No such id #{tid}"
|
290
|
+
end
|
248
291
|
end
|
249
292
|
rescue ApiFailed => e
|
250
293
|
log e.inspect
|
@@ -349,13 +392,17 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
349
392
|
nick = s["user_login_id"] || s["user"]["screen_name"] # it may be better to use user_login_id in Wassr
|
350
393
|
mesg = generate_status_message(s)
|
351
394
|
|
352
|
-
tid = @tmap.push(
|
395
|
+
tid = @tmap.push(s)
|
353
396
|
|
354
397
|
@log.debug [id, nick, mesg]
|
355
398
|
if nick == @nick # 自分のときは topic に
|
356
399
|
post "#{nick}!#{nick}@#{api_base.host}", TOPIC, main_channel, untinyurl(mesg)
|
357
400
|
else
|
358
|
-
|
401
|
+
if @opts["tid"]
|
402
|
+
message(nick, main_channel, "%s \x03%s [%s]" % [mesg, @opts["tid"], tid])
|
403
|
+
else
|
404
|
+
message(nick, main_channel, "%s" % [mesg, tid])
|
405
|
+
end
|
359
406
|
end
|
360
407
|
@groups.each do |channel, members|
|
361
408
|
if members.include?(nick)
|
@@ -409,7 +456,7 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
409
456
|
first = true unless @friends
|
410
457
|
@friends ||= []
|
411
458
|
friends = api("statuses/friends")
|
412
|
-
if first && !@opts.
|
459
|
+
if first && !@opts.key?("athack")
|
413
460
|
@friends = friends
|
414
461
|
post nil, RPL_NAMREPLY, @nick, "=", main_channel, @friends.map{|i| "@#{i["screen_name"]}" }.join(" ")
|
415
462
|
post nil, RPL_ENDOFNAMES, @nick, main_channel, "End of NAMES list"
|
@@ -421,11 +468,11 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
421
468
|
return if !first && (now_friends.length - prv_friends.length).abs > 10
|
422
469
|
|
423
470
|
(now_friends - prv_friends).each do |join|
|
424
|
-
join = "@#{join}" if @opts.
|
471
|
+
join = "@#{join}" if @opts.key?("athack")
|
425
472
|
post "#{join}!#{join}@#{api_base.host}", JOIN, main_channel
|
426
473
|
end
|
427
474
|
(prv_friends - now_friends).each do |part|
|
428
|
-
part = "@#{part}" if @opts.
|
475
|
+
part = "@#{part}" if @opts.key?("athack")
|
429
476
|
post "#{part}!#{part}@#{api_base.host}", PART, main_channel, ""
|
430
477
|
end
|
431
478
|
@friends = friends
|
@@ -487,9 +534,9 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
487
534
|
header = {
|
488
535
|
"User-Agent" => @user_agent,
|
489
536
|
"Authorization" => "Basic " + ["#{@real}:#{@pass}"].pack("m"),
|
490
|
-
"X-Twitter-Client" => api_source,
|
491
|
-
"X-Twitter-Client-Version" => server_version,
|
492
|
-
"X-Twitter-Client-URL" => "http://coderepos.org/share/browser/lang/ruby/misc/tig.rb",
|
537
|
+
# "X-Twitter-Client" => api_source,
|
538
|
+
# "X-Twitter-Client-Version" => server_version,
|
539
|
+
# "X-Twitter-Client-URL" => "http://coderepos.org/share/browser/lang/ruby/misc/tig.rb",
|
493
540
|
}
|
494
541
|
header["If-Modified-Since"] = q["since"] if q.key?("since")
|
495
542
|
|
@@ -566,7 +613,7 @@ class TwitterIrcGateway < Net::IRC::Server::Session
|
|
566
613
|
%w|a i u e o|.map {|v| "#{k}#{v}" }
|
567
614
|
}.flatten
|
568
615
|
|
569
|
-
def initialize(size=
|
616
|
+
def initialize(size=1)
|
570
617
|
@seq = Roma
|
571
618
|
@map = {}
|
572
619
|
@n = 0
|
data/lib/net/irc.rb
CHANGED
@@ -9,290 +9,15 @@ require "monitor"
|
|
9
9
|
module Net; end
|
10
10
|
|
11
11
|
module Net::IRC
|
12
|
-
VERSION = "0.0.
|
12
|
+
VERSION = "0.0.4"
|
13
13
|
class IRCException < StandardError; end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
# digit = %x30-39 ; 0-9
|
18
|
-
# hexdigit = digit / "A" / "B" / "C" / "D" / "E" / "F"
|
19
|
-
# special = %x5B-60 / %x7B-7D
|
20
|
-
# ; "[", "]", "\", "`", "_", "^", "{", "|", "}"
|
21
|
-
LETTER = 'A-Za-z'
|
22
|
-
DIGIT = '\d'
|
23
|
-
HEXDIGIT = "#{DIGIT}A-Fa-f"
|
24
|
-
SPECIAL = '\x5B-\x60\x7B-\x7D'
|
15
|
+
require "net/irc/constants"
|
16
|
+
require "net/irc/pattern"
|
25
17
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
# hostname = shortname *( "." shortname )
|
30
|
-
SHORTNAME = "[#{LETTER}#{DIGIT}](?:[-#{LETTER}#{DIGIT}]*[#{LETTER}#{DIGIT}])?"
|
31
|
-
HOSTNAME = "#{SHORTNAME}(?:\\.#{SHORTNAME})*"
|
32
|
-
|
33
|
-
# servername = hostname
|
34
|
-
SERVERNAME = HOSTNAME
|
35
|
-
|
36
|
-
# nickname = ( letter / special ) *8( letter / digit / special / "-" )
|
37
|
-
#NICKNAME = "[#{LETTER}#{SPECIAL}\\w][-#{LETTER}#{DIGIT}#{SPECIAL}]*"
|
38
|
-
NICKNAME = "\\S+" # for multibytes
|
39
|
-
|
40
|
-
# user = 1*( %x01-09 / %x0B-0C / %x0E-1F / %x21-3F / %x41-FF )
|
41
|
-
# ; any octet except NUL, CR, LF, " " and "@"
|
42
|
-
USER = '[\x01-\x09\x0B-\x0C\x0E-\x1F\x21-\x3F\x41-\xFF]+'
|
43
|
-
|
44
|
-
# ip4addr = 1*3digit "." 1*3digit "." 1*3digit "." 1*3digit
|
45
|
-
IP4ADDR = "[#{DIGIT}]{1,3}(?:\\.[#{DIGIT}]{1,3}){3}"
|
46
|
-
# ip6addr = 1*hexdigit 7( ":" 1*hexdigit )
|
47
|
-
# ip6addr =/ "0:0:0:0:0:" ( "0" / "FFFF" ) ":" ip4addr
|
48
|
-
IP6ADDR = "(?:[#{HEXDIGIT}]+(?::[#{HEXDIGIT}]+){7}|0:0:0:0:0:(?:0|FFFF):#{IP4ADDR})"
|
49
|
-
# hostaddr = ip4addr / ip6addr
|
50
|
-
HOSTADDR = "(?:#{IP4ADDR}|#{IP6ADDR})"
|
51
|
-
|
52
|
-
# host = hostname / hostaddr
|
53
|
-
HOST = "(?:#{HOSTNAME}|#{HOSTADDR})"
|
54
|
-
|
55
|
-
# prefix = servername / ( nickname [ [ "!" user ] "@" host ] )
|
56
|
-
PREFIX = "(?:#{NICKNAME}(?:(?:!#{USER})?@#{HOST})?|#{SERVERNAME})"
|
57
|
-
|
58
|
-
# nospcrlfcl = %x01-09 / %x0B-0C / %x0E-1F / %x21-39 / %x3B-FF
|
59
|
-
# ; any octet except NUL, CR, LF, " " and ":"
|
60
|
-
NOSPCRLFCL = '\x01-\x09\x0B-\x0C\x0E-\x1F\x21-\x39\x3B-\xFF'
|
61
|
-
|
62
|
-
# command = 1*letter / 3digit
|
63
|
-
COMMAND = "(?:[#{LETTER}]+|[#{DIGIT}]{3})"
|
64
|
-
|
65
|
-
# SPACE = %x20 ; space character
|
66
|
-
# middle = nospcrlfcl *( ":" / nospcrlfcl )
|
67
|
-
# trailing = *( ":" / " " / nospcrlfcl )
|
68
|
-
# params = *14( SPACE middle ) [ SPACE ":" trailing ]
|
69
|
-
# =/ 14( SPACE middle ) [ SPACE [ ":" ] trailing ]
|
70
|
-
MIDDLE = "[#{NOSPCRLFCL}][:#{NOSPCRLFCL}]*"
|
71
|
-
TRAILING = "[: #{NOSPCRLFCL}]*"
|
72
|
-
PARAMS = "(?:((?: #{MIDDLE}){0,14})(?: :(#{TRAILING}))?|((?: #{MIDDLE}){14})(?::?)?(#{TRAILING}))"
|
73
|
-
|
74
|
-
# crlf = %x0D %x0A ; "carriage return" "linefeed"
|
75
|
-
# message = [ ":" prefix SPACE ] command [ params ] crlf
|
76
|
-
CRLF = '\x0D\x0A'
|
77
|
-
MESSAGE = "(?::(#{PREFIX}) )?(#{COMMAND})#{PARAMS}\s*#{CRLF}"
|
78
|
-
|
79
|
-
CLIENT_PATTERN = /\A#{NICKNAME}(?:(?:!#{USER})?@#{HOST})\z/on
|
80
|
-
MESSAGE_PATTERN = /\A#{MESSAGE}\z/on
|
81
|
-
end # PATTERN
|
82
|
-
|
83
|
-
module Constants # :nodoc:
|
84
|
-
RPL_WELCOME = '001'
|
85
|
-
RPL_YOURHOST = '002'
|
86
|
-
RPL_CREATED = '003'
|
87
|
-
RPL_MYINFO = '004'
|
88
|
-
RPL_BOUNCE = '005'
|
89
|
-
RPL_USERHOST = '302'
|
90
|
-
RPL_ISON = '303'
|
91
|
-
RPL_AWAY = '301'
|
92
|
-
RPL_UNAWAY = '305'
|
93
|
-
RPL_NOWAWAY = '306'
|
94
|
-
RPL_WHOISUSER = '311'
|
95
|
-
RPL_WHOISSERVER = '312'
|
96
|
-
RPL_WHOISOPERATOR = '313'
|
97
|
-
RPL_WHOISIDLE = '317'
|
98
|
-
RPL_ENDOFWHOIS = '318'
|
99
|
-
RPL_WHOISCHANNELS = '319'
|
100
|
-
RPL_WHOWASUSER = '314'
|
101
|
-
RPL_ENDOFWHOWAS = '369'
|
102
|
-
RPL_LISTSTART = '321'
|
103
|
-
RPL_LIST = '322'
|
104
|
-
RPL_LISTEND = '323'
|
105
|
-
RPL_UNIQOPIS = '325'
|
106
|
-
RPL_CHANNELMODEIS = '324'
|
107
|
-
RPL_NOTOPIC = '331'
|
108
|
-
RPL_TOPIC = '332'
|
109
|
-
RPL_INVITING = '341'
|
110
|
-
RPL_SUMMONING = '342'
|
111
|
-
RPL_INVITELIST = '346'
|
112
|
-
RPL_ENDOFINVITELIST = '347'
|
113
|
-
RPL_EXCEPTLIST = '348'
|
114
|
-
RPL_ENDOFEXCEPTLIST = '349'
|
115
|
-
RPL_VERSION = '351'
|
116
|
-
RPL_WHOREPLY = '352'
|
117
|
-
RPL_ENDOFWHO = '315'
|
118
|
-
RPL_NAMREPLY = '353'
|
119
|
-
RPL_ENDOFNAMES = '366'
|
120
|
-
RPL_LINKS = '364'
|
121
|
-
RPL_ENDOFLINKS = '365'
|
122
|
-
RPL_BANLIST = '367'
|
123
|
-
RPL_ENDOFBANLIST = '368'
|
124
|
-
RPL_INFO = '371'
|
125
|
-
RPL_ENDOFINFO = '374'
|
126
|
-
RPL_MOTDSTART = '375'
|
127
|
-
RPL_MOTD = '372'
|
128
|
-
RPL_ENDOFMOTD = '376'
|
129
|
-
RPL_YOUREOPER = '381'
|
130
|
-
RPL_REHASHING = '382'
|
131
|
-
RPL_YOURESERVICE = '383'
|
132
|
-
RPL_TIME = '391'
|
133
|
-
RPL_USERSSTART = '392'
|
134
|
-
RPL_USERS = '393'
|
135
|
-
RPL_ENDOFUSERS = '394'
|
136
|
-
RPL_NOUSERS = '395'
|
137
|
-
RPL_TRACELINK = '200'
|
138
|
-
RPL_TRACECONNECTING = '201'
|
139
|
-
RPL_TRACEHANDSHAKE = '202'
|
140
|
-
RPL_TRACEUNKNOWN = '203'
|
141
|
-
RPL_TRACEOPERATOR = '204'
|
142
|
-
RPL_TRACEUSER = '205'
|
143
|
-
RPL_TRACESERVER = '206'
|
144
|
-
RPL_TRACESERVICE = '207'
|
145
|
-
RPL_TRACENEWTYPE = '208'
|
146
|
-
RPL_TRACECLASS = '209'
|
147
|
-
RPL_TRACERECONNECT = '210'
|
148
|
-
RPL_TRACELOG = '261'
|
149
|
-
RPL_TRACEEND = '262'
|
150
|
-
RPL_STATSLINKINFO = '211'
|
151
|
-
RPL_STATSCOMMANDS = '212'
|
152
|
-
RPL_ENDOFSTATS = '219'
|
153
|
-
RPL_STATSUPTIME = '242'
|
154
|
-
RPL_STATSOLINE = '243'
|
155
|
-
RPL_UMODEIS = '221'
|
156
|
-
RPL_SERVLIST = '234'
|
157
|
-
RPL_SERVLISTEND = '235'
|
158
|
-
RPL_LUSERCLIENT = '251'
|
159
|
-
RPL_LUSEROP = '252'
|
160
|
-
RPL_LUSERUNKNOWN = '253'
|
161
|
-
RPL_LUSERCHANNELS = '254'
|
162
|
-
RPL_LUSERME = '255'
|
163
|
-
RPL_ADMINME = '256'
|
164
|
-
RPL_ADMINLOC1 = '257'
|
165
|
-
RPL_ADMINLOC2 = '258'
|
166
|
-
RPL_ADMINEMAIL = '259'
|
167
|
-
RPL_TRYAGAIN = '263'
|
168
|
-
ERR_NOSUCHNICK = '401'
|
169
|
-
ERR_NOSUCHSERVER = '402'
|
170
|
-
ERR_NOSUCHCHANNEL = '403'
|
171
|
-
ERR_CANNOTSENDTOCHAN = '404'
|
172
|
-
ERR_TOOMANYCHANNELS = '405'
|
173
|
-
ERR_WASNOSUCHNICK = '406'
|
174
|
-
ERR_TOOMANYTARGETS = '407'
|
175
|
-
ERR_NOSUCHSERVICE = '408'
|
176
|
-
ERR_NOORIGIN = '409'
|
177
|
-
ERR_NORECIPIENT = '411'
|
178
|
-
ERR_NOTEXTTOSEND = '412'
|
179
|
-
ERR_NOTOPLEVEL = '413'
|
180
|
-
ERR_WILDTOPLEVEL = '414'
|
181
|
-
ERR_BADMASK = '415'
|
182
|
-
ERR_UNKNOWNCOMMAND = '421'
|
183
|
-
ERR_NOMOTD = '422'
|
184
|
-
ERR_NOADMININFO = '423'
|
185
|
-
ERR_FILEERROR = '424'
|
186
|
-
ERR_NONICKNAMEGIVEN = '431'
|
187
|
-
ERR_ERRONEUSNICKNAME = '432'
|
188
|
-
ERR_NICKNAMEINUSE = '433'
|
189
|
-
ERR_NICKCOLLISION = '436'
|
190
|
-
ERR_UNAVAILRESOURCE = '437'
|
191
|
-
ERR_USERNOTINCHANNEL = '441'
|
192
|
-
ERR_NOTONCHANNEL = '442'
|
193
|
-
ERR_USERONCHANNEL = '443'
|
194
|
-
ERR_NOLOGIN = '444'
|
195
|
-
ERR_SUMMONDISABLED = '445'
|
196
|
-
ERR_USERSDISABLED = '446'
|
197
|
-
ERR_NOTREGISTERED = '451'
|
198
|
-
ERR_NEEDMOREPARAMS = '461'
|
199
|
-
ERR_ALREADYREGISTRED = '462'
|
200
|
-
ERR_NOPERMFORHOST = '463'
|
201
|
-
ERR_PASSWDMISMATCH = '464'
|
202
|
-
ERR_YOUREBANNEDCREEP = '465'
|
203
|
-
ERR_YOUWILLBEBANNED = '466'
|
204
|
-
ERR_KEYSET = '467'
|
205
|
-
ERR_CHANNELISFULL = '471'
|
206
|
-
ERR_UNKNOWNMODE = '472'
|
207
|
-
ERR_INVITEONLYCHAN = '473'
|
208
|
-
ERR_BANNEDFROMCHAN = '474'
|
209
|
-
ERR_BADCHANNELKEY = '475'
|
210
|
-
ERR_BADCHANMASK = '476'
|
211
|
-
ERR_NOCHANMODES = '477'
|
212
|
-
ERR_BANLISTFULL = '478'
|
213
|
-
ERR_NOPRIVILEGES = '481'
|
214
|
-
ERR_CHANOPRIVSNEEDED = '482'
|
215
|
-
ERR_CANTKILLSERVER = '483'
|
216
|
-
ERR_RESTRICTED = '484'
|
217
|
-
ERR_UNIQOPPRIVSNEEDED = '485'
|
218
|
-
ERR_NOOPERHOST = '491'
|
219
|
-
ERR_UMODEUNKNOWNFLAG = '501'
|
220
|
-
ERR_USERSDONTMATCH = '502'
|
221
|
-
RPL_SERVICEINFO = '231'
|
222
|
-
RPL_ENDOFSERVICES = '232'
|
223
|
-
RPL_SERVICE = '233'
|
224
|
-
RPL_NONE = '300'
|
225
|
-
RPL_WHOISCHANOP = '316'
|
226
|
-
RPL_KILLDONE = '361'
|
227
|
-
RPL_CLOSING = '362'
|
228
|
-
RPL_CLOSEEND = '363'
|
229
|
-
RPL_INFOSTART = '373'
|
230
|
-
RPL_MYPORTIS = '384'
|
231
|
-
RPL_STATSCLINE = '213'
|
232
|
-
RPL_STATSNLINE = '214'
|
233
|
-
RPL_STATSILINE = '215'
|
234
|
-
RPL_STATSKLINE = '216'
|
235
|
-
RPL_STATSQLINE = '217'
|
236
|
-
RPL_STATSYLINE = '218'
|
237
|
-
RPL_STATSVLINE = '240'
|
238
|
-
RPL_STATSLLINE = '241'
|
239
|
-
RPL_STATSHLINE = '244'
|
240
|
-
RPL_STATSSLINE = '244'
|
241
|
-
RPL_STATSPING = '246'
|
242
|
-
RPL_STATSBLINE = '247'
|
243
|
-
RPL_STATSDLINE = '250'
|
244
|
-
ERR_NOSERVICEHOST = '492'
|
245
|
-
|
246
|
-
PASS = 'PASS'
|
247
|
-
NICK = 'NICK'
|
248
|
-
USER = 'USER'
|
249
|
-
OPER = 'OPER'
|
250
|
-
MODE = 'MODE'
|
251
|
-
SERVICE = 'SERVICE'
|
252
|
-
QUIT = 'QUIT'
|
253
|
-
SQUIT = 'SQUIT'
|
254
|
-
JOIN = 'JOIN'
|
255
|
-
PART = 'PART'
|
256
|
-
TOPIC = 'TOPIC'
|
257
|
-
NAMES = 'NAMES'
|
258
|
-
LIST = 'LIST'
|
259
|
-
INVITE = 'INVITE'
|
260
|
-
KICK = 'KICK'
|
261
|
-
PRIVMSG = 'PRIVMSG'
|
262
|
-
NOTICE = 'NOTICE'
|
263
|
-
MOTD = 'MOTD'
|
264
|
-
LUSERS = 'LUSERS'
|
265
|
-
VERSION = 'VERSION'
|
266
|
-
STATS = 'STATS'
|
267
|
-
LINKS = 'LINKS'
|
268
|
-
TIME = 'TIME'
|
269
|
-
CONNECT = 'CONNECT'
|
270
|
-
TRACE = 'TRACE'
|
271
|
-
ADMIN = 'ADMIN'
|
272
|
-
INFO = 'INFO'
|
273
|
-
SERVLIST = 'SERVLIST'
|
274
|
-
SQUERY = 'SQUERY'
|
275
|
-
WHO = 'WHO'
|
276
|
-
WHOIS = 'WHOIS'
|
277
|
-
WHOWAS = 'WHOWAS'
|
278
|
-
KILL = 'KILL'
|
279
|
-
PING = 'PING'
|
280
|
-
PONG = 'PONG'
|
281
|
-
ERROR = 'ERROR'
|
282
|
-
AWAY = 'AWAY'
|
283
|
-
REHASH = 'REHASH'
|
284
|
-
DIE = 'DIE'
|
285
|
-
RESTART = 'RESTART'
|
286
|
-
SUMMON = 'SUMMON'
|
287
|
-
USERS = 'USERS'
|
288
|
-
WALLOPS = 'WALLOPS'
|
289
|
-
USERHOST = 'USERHOST'
|
290
|
-
ISON = 'ISON'
|
291
|
-
end
|
292
|
-
|
293
|
-
COMMANDS = Constants.constants.inject({}) {|r,i| # :nodoc:
|
294
|
-
r.update(Constants.const_get(i) => i)
|
295
|
-
}
|
18
|
+
autoload :Message, "net/irc/message"
|
19
|
+
autoload :Client, "net/irc/client"
|
20
|
+
autoload :Server, "net/irc/server"
|
296
21
|
|
297
22
|
class Prefix < String
|
298
23
|
def nick
|
@@ -332,533 +57,3 @@ module Net::IRC
|
|
332
57
|
module_function :ctcp_decoding
|
333
58
|
end
|
334
59
|
|
335
|
-
class Net::IRC::Message
|
336
|
-
include Net::IRC
|
337
|
-
|
338
|
-
class InvalidMessage < Net::IRC::IRCException; end
|
339
|
-
|
340
|
-
attr_reader :prefix, :command, :params
|
341
|
-
|
342
|
-
# Parse string and return new Message.
|
343
|
-
# If the string is invalid message, this method raises Net::IRC::Message::InvalidMessage.
|
344
|
-
def self.parse(str)
|
345
|
-
_, prefix, command, *rest = *PATTERN::MESSAGE_PATTERN.match(str)
|
346
|
-
raise InvalidMessage, "Invalid message: #{str.dump}" unless _
|
347
|
-
|
348
|
-
case
|
349
|
-
when rest[0] && !rest[0].empty?
|
350
|
-
middle, trailer, = *rest
|
351
|
-
when rest[2] && !rest[2].empty?
|
352
|
-
middle, trailer, = *rest[2, 2]
|
353
|
-
when rest[1]
|
354
|
-
params = []
|
355
|
-
trailer = rest[1]
|
356
|
-
when rest[3]
|
357
|
-
params = []
|
358
|
-
trailer = rest[3]
|
359
|
-
else
|
360
|
-
params = []
|
361
|
-
end
|
362
|
-
|
363
|
-
params ||= middle.split(/ /)[1..-1]
|
364
|
-
params << trailer if trailer
|
365
|
-
|
366
|
-
new(prefix, command, params)
|
367
|
-
end
|
368
|
-
|
369
|
-
def initialize(prefix, command, params)
|
370
|
-
@prefix = Prefix.new(prefix.to_s)
|
371
|
-
@command = command
|
372
|
-
@params = params
|
373
|
-
end
|
374
|
-
|
375
|
-
# Same as @params[n].
|
376
|
-
def [](n)
|
377
|
-
@params[n]
|
378
|
-
end
|
379
|
-
|
380
|
-
# Iterate params.
|
381
|
-
def each(&block)
|
382
|
-
@params.each(&block)
|
383
|
-
end
|
384
|
-
|
385
|
-
# Stringfy message to raw IRC message.
|
386
|
-
def to_s
|
387
|
-
str = ""
|
388
|
-
|
389
|
-
str << ":#{@prefix} " unless @prefix.empty?
|
390
|
-
str << @command
|
391
|
-
|
392
|
-
if @params
|
393
|
-
f = false
|
394
|
-
@params.each do |param|
|
395
|
-
str << " "
|
396
|
-
if !f && (param.size == 0 || / / =~ param || /^:/ =~ param)
|
397
|
-
str << ":#{param}"
|
398
|
-
f = true
|
399
|
-
else
|
400
|
-
str << param
|
401
|
-
end
|
402
|
-
end
|
403
|
-
end
|
404
|
-
|
405
|
-
str << "\x0D\x0A"
|
406
|
-
|
407
|
-
str
|
408
|
-
end
|
409
|
-
alias to_str to_s
|
410
|
-
|
411
|
-
# Same as params.
|
412
|
-
def to_a
|
413
|
-
@params
|
414
|
-
end
|
415
|
-
|
416
|
-
# If the message is CTCP, return true.
|
417
|
-
def ctcp?
|
418
|
-
message = @params[1]
|
419
|
-
message[0] == 1 && message[message.length-1] == 1
|
420
|
-
end
|
421
|
-
|
422
|
-
def inspect
|
423
|
-
'#<%s:0x%x prefix:%s command:%s params:%s>' % [
|
424
|
-
self.class,
|
425
|
-
self.object_id,
|
426
|
-
@prefix,
|
427
|
-
@command,
|
428
|
-
@params.inspect
|
429
|
-
]
|
430
|
-
end
|
431
|
-
|
432
|
-
end # Message
|
433
|
-
|
434
|
-
class Net::IRC::Client
|
435
|
-
include Net::IRC
|
436
|
-
include Constants
|
437
|
-
|
438
|
-
attr_reader :host, :port, :opts
|
439
|
-
attr_reader :prefix, :channels
|
440
|
-
|
441
|
-
def initialize(host, port, opts={})
|
442
|
-
@host = host
|
443
|
-
@port = port
|
444
|
-
@opts = OpenStruct.new(opts)
|
445
|
-
@log = @opts.logger || Logger.new($stdout)
|
446
|
-
@channels = {
|
447
|
-
# "#channel" => {
|
448
|
-
# :modes => [],
|
449
|
-
# :users => [],
|
450
|
-
# }
|
451
|
-
}
|
452
|
-
@channels.extend(MonitorMixin)
|
453
|
-
end
|
454
|
-
|
455
|
-
# Connect to server and start loop.
|
456
|
-
def start
|
457
|
-
@socket = TCPSocket.open(@host, @port)
|
458
|
-
on_connected
|
459
|
-
post PASS, @opts.pass if @opts.pass
|
460
|
-
post NICK, @opts.nick
|
461
|
-
post USER, @opts.user, "0", "*", @opts.real
|
462
|
-
while l = @socket.gets
|
463
|
-
begin
|
464
|
-
@log.debug "RECEIVE: #{l.chomp}"
|
465
|
-
m = Message.parse(l)
|
466
|
-
next if on_message(m) === true
|
467
|
-
name = "on_#{(COMMANDS[m.command.upcase] || m.command).downcase}"
|
468
|
-
send(name, m) if respond_to?(name)
|
469
|
-
rescue Exception => e
|
470
|
-
warn e
|
471
|
-
warn e.backtrace.join("\r\t")
|
472
|
-
raise
|
473
|
-
rescue Message::InvalidMessage
|
474
|
-
@log.error "MessageParse: " + l.inspect
|
475
|
-
end
|
476
|
-
end
|
477
|
-
rescue IOError
|
478
|
-
ensure
|
479
|
-
finish
|
480
|
-
end
|
481
|
-
|
482
|
-
# Close connection to server.
|
483
|
-
def finish
|
484
|
-
begin
|
485
|
-
@socket.close
|
486
|
-
rescue
|
487
|
-
end
|
488
|
-
on_disconnected
|
489
|
-
end
|
490
|
-
|
491
|
-
# Catch all messages.
|
492
|
-
# If this method return true, aother callback will not be called.
|
493
|
-
def on_message(m)
|
494
|
-
end
|
495
|
-
|
496
|
-
# Default RPL_WELCOME callback.
|
497
|
-
# This sets @prefix from the message.
|
498
|
-
def on_rpl_welcome(m)
|
499
|
-
@prefix = Prefix.new(m[1][/\S+$/])
|
500
|
-
end
|
501
|
-
|
502
|
-
# Default PING callback. Response PONG.
|
503
|
-
def on_ping(m)
|
504
|
-
post PONG, @prefix ? @prefix.nick : ""
|
505
|
-
end
|
506
|
-
|
507
|
-
# For managing channel
|
508
|
-
def on_rpl_namreply(m)
|
509
|
-
type = m[1]
|
510
|
-
channel = m[2]
|
511
|
-
init_channel(channel)
|
512
|
-
|
513
|
-
@channels.synchronize do
|
514
|
-
m[3].split(/\s+/).each do |u|
|
515
|
-
_, mode, nick = *u.match(/^([@+]?)(.+)/)
|
516
|
-
|
517
|
-
@channels[channel][:users] << nick
|
518
|
-
@channels[channel][:users].uniq!
|
519
|
-
|
520
|
-
case mode
|
521
|
-
when "@" # channel operator
|
522
|
-
@channels[channel][:modes] << ["o", nick]
|
523
|
-
when "+" # voiced (under moderating mode)
|
524
|
-
@channels[channel][:modes] << ["v", nick]
|
525
|
-
end
|
526
|
-
end
|
527
|
-
|
528
|
-
case type
|
529
|
-
when "@" # secret
|
530
|
-
@channels[channel][:modes] << ["s", nil]
|
531
|
-
when "*" # private
|
532
|
-
@channels[channel][:modes] << ["p", nil]
|
533
|
-
when "=" # public
|
534
|
-
end
|
535
|
-
|
536
|
-
@channels[channel][:modes].uniq!
|
537
|
-
end
|
538
|
-
end
|
539
|
-
|
540
|
-
# For managing channel
|
541
|
-
def on_part(m)
|
542
|
-
nick = m.prefix.nick
|
543
|
-
channel = m[0]
|
544
|
-
init_channel(channel)
|
545
|
-
|
546
|
-
@channels.synchronize do
|
547
|
-
info = @channels[channel]
|
548
|
-
if info
|
549
|
-
info[:users].delete(nick)
|
550
|
-
info[:modes].delete_if {|u|
|
551
|
-
u[1] == nick
|
552
|
-
}
|
553
|
-
end
|
554
|
-
end
|
555
|
-
end
|
556
|
-
|
557
|
-
# For managing channel
|
558
|
-
def on_quit(m)
|
559
|
-
nick = m.prefix.nick
|
560
|
-
|
561
|
-
@channels.synchronize do
|
562
|
-
@channels.each do |channel, info|
|
563
|
-
info[:users].delete(nick)
|
564
|
-
info[:modes].delete_if {|u|
|
565
|
-
u[1] == nick
|
566
|
-
}
|
567
|
-
end
|
568
|
-
end
|
569
|
-
end
|
570
|
-
|
571
|
-
# For managing channel
|
572
|
-
def on_kick(m)
|
573
|
-
users = m[1].split(/,/)
|
574
|
-
|
575
|
-
@channels.synchronize do
|
576
|
-
m[0].split(/,/).each do |chan|
|
577
|
-
init_channel(chan)
|
578
|
-
info = @channels[chan]
|
579
|
-
if info
|
580
|
-
users.each do |nick|
|
581
|
-
info[:users].delete(nick)
|
582
|
-
info[:modes].delete_if {|u|
|
583
|
-
u[1] == nick
|
584
|
-
}
|
585
|
-
end
|
586
|
-
end
|
587
|
-
end
|
588
|
-
end
|
589
|
-
end
|
590
|
-
|
591
|
-
# For managing channel
|
592
|
-
def on_join(m)
|
593
|
-
nick = m.prefix.nick
|
594
|
-
channel = m[0]
|
595
|
-
|
596
|
-
@channels.synchronize do
|
597
|
-
init_channel(channel)
|
598
|
-
|
599
|
-
@channels[channel][:users] << nick
|
600
|
-
@channels[channel][:users].uniq!
|
601
|
-
end
|
602
|
-
end
|
603
|
-
|
604
|
-
# For managing channel
|
605
|
-
def on_mode(m)
|
606
|
-
channel = m[0]
|
607
|
-
@channels.synchronize do
|
608
|
-
init_channel(channel)
|
609
|
-
|
610
|
-
positive_mode = []
|
611
|
-
negative_mode = []
|
612
|
-
|
613
|
-
mode = positive_mode
|
614
|
-
arg_pos = 0
|
615
|
-
m[1].each_byte do |c|
|
616
|
-
case c
|
617
|
-
when ?+
|
618
|
-
mode = positive_mode
|
619
|
-
when ?-
|
620
|
-
mode = negative_mode
|
621
|
-
when ?o, ?v, ?k, ?l, ?b, ?e, ?I
|
622
|
-
mode << [c.chr, m[arg_pos + 2]]
|
623
|
-
arg_pos += 1
|
624
|
-
else
|
625
|
-
mode << [c.chr, nil]
|
626
|
-
end
|
627
|
-
end
|
628
|
-
mode = nil
|
629
|
-
|
630
|
-
negative_mode.each do |m|
|
631
|
-
@channels[channel][:modes].delete(m)
|
632
|
-
end
|
633
|
-
|
634
|
-
positive_mode.each do |m|
|
635
|
-
@channels[channel][:modes] << m
|
636
|
-
end
|
637
|
-
|
638
|
-
@channels[channel][:modes].uniq!
|
639
|
-
[negative_mode, positive_mode]
|
640
|
-
end
|
641
|
-
end
|
642
|
-
|
643
|
-
# For managing channel
|
644
|
-
def init_channel(channel)
|
645
|
-
@channels[channel] ||= {
|
646
|
-
:modes => [],
|
647
|
-
:users => [],
|
648
|
-
}
|
649
|
-
end
|
650
|
-
|
651
|
-
# Do nothing.
|
652
|
-
# This is for avoiding error on calling super.
|
653
|
-
# So you can always call super at subclass.
|
654
|
-
def method_missing(name, *args)
|
655
|
-
end
|
656
|
-
|
657
|
-
# Call when socket connected.
|
658
|
-
def on_connected
|
659
|
-
end
|
660
|
-
|
661
|
-
# Call when socket closed.
|
662
|
-
def on_disconnected
|
663
|
-
end
|
664
|
-
|
665
|
-
private
|
666
|
-
|
667
|
-
# Post message to server.
|
668
|
-
#
|
669
|
-
# include Net::IRC::Constans
|
670
|
-
# post PRIVMSG, "#channel", "foobar"
|
671
|
-
def post(command, *params)
|
672
|
-
m = Message.new(nil, command, params.map {|s|
|
673
|
-
s ? s.gsub(/[\r\n]/, " ") : ""
|
674
|
-
})
|
675
|
-
|
676
|
-
@log.debug "SEND: #{m.to_s.chomp}"
|
677
|
-
@socket << m
|
678
|
-
end
|
679
|
-
end # Client
|
680
|
-
|
681
|
-
class Net::IRC::Server
|
682
|
-
def initialize(host, port, session_class, opts={})
|
683
|
-
@host = host
|
684
|
-
@port = port
|
685
|
-
@session_class = session_class
|
686
|
-
@opts = OpenStruct.new(opts)
|
687
|
-
@sessions = []
|
688
|
-
end
|
689
|
-
|
690
|
-
# Start server loop.
|
691
|
-
def start
|
692
|
-
@serv = TCPServer.new(@host, @port)
|
693
|
-
@log = @opts.logger || Logger.new($stdout)
|
694
|
-
@log.info "Host: #{@host} Port:#{@port}"
|
695
|
-
@accept = Thread.start do
|
696
|
-
loop do
|
697
|
-
Thread.start(@serv.accept) do |s|
|
698
|
-
begin
|
699
|
-
@log.info "Client connected, new session starting..."
|
700
|
-
s = @session_class.new(self, s, @log, @opts)
|
701
|
-
@sessions << s
|
702
|
-
s.start
|
703
|
-
rescue Exception => e
|
704
|
-
puts e
|
705
|
-
puts e.backtrace
|
706
|
-
ensure
|
707
|
-
@sessions.delete(s)
|
708
|
-
end
|
709
|
-
end
|
710
|
-
end
|
711
|
-
end
|
712
|
-
@accept.join
|
713
|
-
end
|
714
|
-
|
715
|
-
# Close all sessions.
|
716
|
-
def finish
|
717
|
-
Thread.exclusive do
|
718
|
-
@accept.kill
|
719
|
-
begin
|
720
|
-
@serv.close
|
721
|
-
rescue
|
722
|
-
end
|
723
|
-
@sessions.each do |s|
|
724
|
-
s.finish
|
725
|
-
end
|
726
|
-
end
|
727
|
-
end
|
728
|
-
|
729
|
-
|
730
|
-
class Session
|
731
|
-
include Net::IRC
|
732
|
-
include Constants
|
733
|
-
|
734
|
-
attr_reader :prefix, :nick, :real, :host
|
735
|
-
|
736
|
-
# Override subclass.
|
737
|
-
def server_name
|
738
|
-
"net-irc"
|
739
|
-
end
|
740
|
-
|
741
|
-
# Override subclass.
|
742
|
-
def server_version
|
743
|
-
"0.0.0"
|
744
|
-
end
|
745
|
-
|
746
|
-
# Override subclass.
|
747
|
-
def avaiable_user_modes
|
748
|
-
"eixwy"
|
749
|
-
end
|
750
|
-
|
751
|
-
# Override subclass.
|
752
|
-
def avaiable_channel_modes
|
753
|
-
"spknm"
|
754
|
-
end
|
755
|
-
|
756
|
-
def initialize(server, socket, logger, opts={})
|
757
|
-
@server, @socket, @log, @opts = server, socket, logger, opts
|
758
|
-
end
|
759
|
-
|
760
|
-
def self.start(*args)
|
761
|
-
new(*args).start
|
762
|
-
end
|
763
|
-
|
764
|
-
# Start session loop.
|
765
|
-
def start
|
766
|
-
on_connected
|
767
|
-
while l = @socket.gets
|
768
|
-
begin
|
769
|
-
@log.debug "RECEIVE: #{l.chomp}"
|
770
|
-
m = Message.parse(l)
|
771
|
-
next if on_message(m) === true
|
772
|
-
|
773
|
-
name = "on_#{(COMMANDS[m.command.upcase] || m.command).downcase}"
|
774
|
-
send(name, m) if respond_to?(name)
|
775
|
-
|
776
|
-
break if m.command == QUIT
|
777
|
-
rescue Message::InvalidMessage
|
778
|
-
@log.error "MessageParse: " + l.inspect
|
779
|
-
end
|
780
|
-
end
|
781
|
-
rescue IOError
|
782
|
-
ensure
|
783
|
-
finish
|
784
|
-
end
|
785
|
-
|
786
|
-
# Close this session.
|
787
|
-
def finish
|
788
|
-
begin
|
789
|
-
@socket.close
|
790
|
-
rescue
|
791
|
-
end
|
792
|
-
on_disconnected
|
793
|
-
end
|
794
|
-
|
795
|
-
# Default PASS callback.
|
796
|
-
# Set @pass.
|
797
|
-
def on_pass(m)
|
798
|
-
@pass = m.params[0]
|
799
|
-
end
|
800
|
-
|
801
|
-
# Default NICK callback.
|
802
|
-
# Set @nick.
|
803
|
-
def on_nick(m)
|
804
|
-
@nick = m.params[0]
|
805
|
-
end
|
806
|
-
|
807
|
-
# Default USER callback.
|
808
|
-
# Set @user, @real, @host and call initial_message.
|
809
|
-
def on_user(m)
|
810
|
-
@user, @real = m.params[0], m.params[3]
|
811
|
-
@host = @socket.peeraddr[2]
|
812
|
-
@prefix = Prefix.new("#{@nick}!#{@user}@#{@host}")
|
813
|
-
initial_message
|
814
|
-
end
|
815
|
-
|
816
|
-
# Call when socket connected.
|
817
|
-
def on_connected
|
818
|
-
end
|
819
|
-
|
820
|
-
# Call when socket closed.
|
821
|
-
def on_disconnected
|
822
|
-
end
|
823
|
-
|
824
|
-
# Catch all messages.
|
825
|
-
# If this method return true, aother callback will not be called.
|
826
|
-
def on_message(m)
|
827
|
-
end
|
828
|
-
|
829
|
-
# Default PING callback. Response PONG.
|
830
|
-
def on_ping(m)
|
831
|
-
post server_name, PONG, m.params[0]
|
832
|
-
end
|
833
|
-
|
834
|
-
# Do nothing.
|
835
|
-
# This is for avoiding error on calling super.
|
836
|
-
# So you can always call super at subclass.
|
837
|
-
def method_missing(name, *args)
|
838
|
-
end
|
839
|
-
|
840
|
-
private
|
841
|
-
# Post message to server.
|
842
|
-
#
|
843
|
-
# include Net::IRC::Constans
|
844
|
-
# post prefix, PRIVMSG, "#channel", "foobar"
|
845
|
-
def post(prefix, command, *params)
|
846
|
-
m = Message.new(prefix, command, params.map {|s|
|
847
|
-
s.gsub(/[\r\n]/, " ")
|
848
|
-
})
|
849
|
-
@log.debug "SEND: #{m.to_s.chomp}"
|
850
|
-
@socket << m
|
851
|
-
rescue IOError
|
852
|
-
finish
|
853
|
-
end
|
854
|
-
|
855
|
-
# Call when client connected.
|
856
|
-
# Send RPL_WELCOME sequence. If you want to customize, override this method at subclass.
|
857
|
-
def initial_message
|
858
|
-
post server_name, RPL_WELCOME, @nick, "Welcome to the Internet Relay Network #{@prefix}"
|
859
|
-
post server_name, RPL_YOURHOST, @nick, "Your host is #{server_name}, running version #{server_version}"
|
860
|
-
post server_name, RPL_CREATED, @nick, "This server was created #{Time.now}"
|
861
|
-
post server_name, RPL_MYINFO, @nick, "#{server_name} #{server_version} #{avaiable_user_modes} #{avaiable_channel_modes}"
|
862
|
-
end
|
863
|
-
end
|
864
|
-
end # Server
|