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.
- checksums.yaml +7 -0
- data/AUTHORS.txt +33 -0
- data/ChangeLog +95 -0
- data/README +91 -0
- data/Rakefile +69 -0
- data/examples/2ch.rb +225 -0
- data/examples/2ig.rb +267 -0
- data/examples/client.rb +23 -0
- data/examples/echo_bot.rb +31 -0
- data/examples/echo_bot_celluloid.rb +33 -0
- data/examples/gig.rb +192 -0
- data/examples/gmail.rb +202 -0
- data/examples/gtig.rb +420 -0
- data/examples/hatena-star-stream.rb +270 -0
- data/examples/hcig.rb +285 -0
- data/examples/hig.rb +771 -0
- data/examples/iig.rb +819 -0
- data/examples/ircd.rb +358 -0
- data/examples/lig.rb +551 -0
- data/examples/lingr.rb +327 -0
- data/examples/mixi.rb +252 -0
- data/examples/sig.rb +188 -0
- data/examples/tig.rb +2712 -0
- data/lib/net/irc/client/channel_manager.rb +144 -0
- data/lib/net/irc/client.rb +117 -0
- data/lib/net/irc/constants.rb +214 -0
- data/lib/net/irc/message/modeparser.rb +85 -0
- data/lib/net/irc/message/serverconfig.rb +30 -0
- data/lib/net/irc/message.rb +109 -0
- data/lib/net/irc/pattern.rb +68 -0
- data/lib/net/irc/server.rb +186 -0
- data/lib/net/irc.rb +77 -0
- data/spec/channel_manager_spec.rb +184 -0
- data/spec/modeparser_spec.rb +165 -0
- data/spec/net-irc_spec.rb +337 -0
- data/spec/spec.opts +1 -0
- metadata +91 -0
data/examples/ircd.rb
ADDED
@@ -0,0 +1,358 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# vim:encoding=UTF-8:
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'net/irc'
|
6
|
+
|
7
|
+
class NetIrcServer < Net::IRC::Server::Session
|
8
|
+
def server_name
|
9
|
+
"net-irc"
|
10
|
+
end
|
11
|
+
|
12
|
+
def server_version
|
13
|
+
"0.0.0"
|
14
|
+
end
|
15
|
+
|
16
|
+
def available_user_modes
|
17
|
+
"iosw"
|
18
|
+
end
|
19
|
+
|
20
|
+
def default_user_modes
|
21
|
+
""
|
22
|
+
end
|
23
|
+
|
24
|
+
def available_channel_modes
|
25
|
+
"om"
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_channel_modes
|
29
|
+
""
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(*args)
|
33
|
+
super
|
34
|
+
@@channels ||= {}
|
35
|
+
@@users ||= {}
|
36
|
+
@ping = false
|
37
|
+
end
|
38
|
+
|
39
|
+
def on_pass(m)
|
40
|
+
end
|
41
|
+
|
42
|
+
def on_user(m)
|
43
|
+
@user, @real = m.params[0], m.params[3]
|
44
|
+
@host = @socket.peeraddr[2]
|
45
|
+
@prefix = Prefix.new("#{@nick}!#{@user}@#{@host}")
|
46
|
+
@joined_on = @updated_on = Time.now.to_i
|
47
|
+
|
48
|
+
post @socket, @prefix, NICK, nick
|
49
|
+
@nick = nick
|
50
|
+
@prefix = "#{@nick}!#{@user}@#{@host}"
|
51
|
+
|
52
|
+
time = Time.now.to_i
|
53
|
+
@@users[@nick.downcase] = {
|
54
|
+
:nick => @nick,
|
55
|
+
:user => @user,
|
56
|
+
:host => @host,
|
57
|
+
:real => @real,
|
58
|
+
:prefix => @prefix,
|
59
|
+
:socket => @socket,
|
60
|
+
:joined_on => time,
|
61
|
+
:updated_on => time
|
62
|
+
}
|
63
|
+
|
64
|
+
initial_message
|
65
|
+
|
66
|
+
start_ping
|
67
|
+
end
|
68
|
+
|
69
|
+
def on_join(m)
|
70
|
+
channels = m.params[0].split(/\s*,\s*/)
|
71
|
+
password = m.params[1]
|
72
|
+
|
73
|
+
channels.each do |channel|
|
74
|
+
unless channel.downcase =~ /^#/
|
75
|
+
post @socket, server_name, ERR_NOSUCHCHANNEL, @nick, channel, "No such channel"
|
76
|
+
next
|
77
|
+
end
|
78
|
+
|
79
|
+
unless @@channels.key?(channel.downcase)
|
80
|
+
channel_create(channel)
|
81
|
+
else
|
82
|
+
return if @@channels[channel.downcase][:users].key?(@nick.downcase)
|
83
|
+
|
84
|
+
@@channels[channel.downcase][:users][@nick.downcase] = []
|
85
|
+
end
|
86
|
+
|
87
|
+
mode = @@channels[channel.downcase][:mode].empty? ? "" : "+" + @@channels[channel.downcase][:mode]
|
88
|
+
post @socket, server_name, RPL_CHANNELMODEIS, @nick, @@channels[channel.downcase][:alias], mode
|
89
|
+
|
90
|
+
channel_users = ""
|
91
|
+
@@channels[channel.downcase][:users].each do |nick, m|
|
92
|
+
post @@users[nick][:socket], @prefix, JOIN, @@channels[channel.downcase][:alias]
|
93
|
+
|
94
|
+
case
|
95
|
+
when m.index("@")
|
96
|
+
f = "@"
|
97
|
+
when m.index("+")
|
98
|
+
f = "+"
|
99
|
+
else
|
100
|
+
f = ""
|
101
|
+
end
|
102
|
+
channel_users += "#{f}#{@@users[nick.downcase][:nick]} "
|
103
|
+
end
|
104
|
+
post @socket, server_name, RPL_NAMREPLY, @@users[nick][:nick], "=", @@channels[channel.downcase][:alias], "#{channel_users.strip}"
|
105
|
+
post @socket, server_name, RPL_ENDOFNAMES, @@users[nick][:nick], @@channels[channel.downcase][:alias], "End of /NAMES list"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def on_part(m)
|
110
|
+
channel, message = *m.params
|
111
|
+
|
112
|
+
@@channels[channel.downcase][:users].each do |nick, f|
|
113
|
+
post @@users[nick][:socket], @prefix, PART, @@channels[channel.downcase][:alias], message
|
114
|
+
end
|
115
|
+
channel_part(channel)
|
116
|
+
end
|
117
|
+
|
118
|
+
def on_quit(m)
|
119
|
+
message = m.params[0]
|
120
|
+
@@channels.each do |channel, f|
|
121
|
+
if f[:users].key?(@nick.downcase)
|
122
|
+
channel_part(channel)
|
123
|
+
f[:users].each do |nick, m|
|
124
|
+
post @@users[nick][:socket], @prefix, QUIT, message
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
finish
|
129
|
+
end
|
130
|
+
|
131
|
+
def on_disconnected
|
132
|
+
super
|
133
|
+
@@channels.each do |channel, f|
|
134
|
+
if f[:users].key?(@nick.downcase)
|
135
|
+
channel_part(channel)
|
136
|
+
f[:users].each do |nick, m|
|
137
|
+
post @@users[nick][:socket], @prefix, QUIT, "disconnect"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
channel_part_all
|
142
|
+
@@users.delete(@nick.downcase)
|
143
|
+
end
|
144
|
+
|
145
|
+
def on_who(m)
|
146
|
+
channel = m.params[0]
|
147
|
+
return unless channel
|
148
|
+
|
149
|
+
c = channel.downcase
|
150
|
+
case
|
151
|
+
when @@channels.key?(c)
|
152
|
+
@@channels[c][:users].each do |nickname, m|
|
153
|
+
nick = @@users[nickname][:nick]
|
154
|
+
user = @@users[nickname][:user]
|
155
|
+
host = @@users[nickname][:host]
|
156
|
+
real = @@users[nickname][:real]
|
157
|
+
case
|
158
|
+
when m.index("@")
|
159
|
+
f = "@"
|
160
|
+
when m.index("+")
|
161
|
+
f = "+"
|
162
|
+
else
|
163
|
+
f = ""
|
164
|
+
end
|
165
|
+
post @socket, server_name, RPL_WHOREPLY, @nick, @@channels[c][:alias], user, host, server_name, nick, "H#{f}", "0 #{real}"
|
166
|
+
end
|
167
|
+
post @socket, server_name, RPL_ENDOFWHO, @nick, @@channels[c][:alias], "End of /WHO list"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def on_mode(m)
|
172
|
+
end
|
173
|
+
|
174
|
+
def on_privmsg(m)
|
175
|
+
while (Time.now.to_i - @updated_on < 2)
|
176
|
+
sleep 2
|
177
|
+
end
|
178
|
+
idle_update
|
179
|
+
|
180
|
+
return on_ctcp(m[0], ctcp_decoding(m[1])) if m.ctcp?
|
181
|
+
|
182
|
+
target, message = *m.params
|
183
|
+
t = target.downcase
|
184
|
+
|
185
|
+
case
|
186
|
+
when @@channels.key?(t)
|
187
|
+
if @@channels[t][:users].key?(@nick.downcase)
|
188
|
+
@@channels[t][:users].each do |nick, m|
|
189
|
+
post @@users[nick][:socket], @prefix, PRIVMSG, @@channels[t][:alias], message unless nick == @nick.downcase
|
190
|
+
end
|
191
|
+
else
|
192
|
+
post @socket, nil, ERR_CANNOTSENDTOCHAN, @nick, target, "Cannot send to channel"
|
193
|
+
end
|
194
|
+
when @@users.key?(t)
|
195
|
+
post @@users[nick][:socket], @prefix, PRIVMSG, @@users[t][:nick], message
|
196
|
+
else
|
197
|
+
post @socket, nil, ERR_NOSUCHNICK, @nick, target, "No such nick/channel"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def on_ping(m)
|
202
|
+
post @socket, server_name, PONG, m.params[0]
|
203
|
+
end
|
204
|
+
|
205
|
+
def on_pong(m)
|
206
|
+
@ping = true
|
207
|
+
end
|
208
|
+
|
209
|
+
def idle_update
|
210
|
+
@updated_on = Time.now.to_i
|
211
|
+
if logged_in?
|
212
|
+
@@users[@nick.downcase][:updated_on] = @updated_on
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def channel_create(channel)
|
217
|
+
@@channels[channel.downcase] = {
|
218
|
+
:alias => channel,
|
219
|
+
:topic => "",
|
220
|
+
:mode => default_channel_modes,
|
221
|
+
:users => {@nick.downcase => ["@"]},
|
222
|
+
}
|
223
|
+
end
|
224
|
+
|
225
|
+
def channel_part(channel)
|
226
|
+
@@channels[channel.downcase][:users].delete(@nick.downcase)
|
227
|
+
channel_delete(channel.downcase) if @@channels[channel.downcase][:users].size == 0
|
228
|
+
end
|
229
|
+
|
230
|
+
def channel_part_all
|
231
|
+
@@channels.each do |c|
|
232
|
+
channel_part(c)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def channel_delete(channel)
|
237
|
+
@@channels.delete(channel.downcase)
|
238
|
+
end
|
239
|
+
|
240
|
+
def post(socket, prefix, command, *params)
|
241
|
+
m = Message.new(prefix, command, params.map{|s|
|
242
|
+
s.gsub(/[\r\n]/, "")
|
243
|
+
})
|
244
|
+
socket << m
|
245
|
+
rescue
|
246
|
+
finish
|
247
|
+
end
|
248
|
+
|
249
|
+
def start_ping
|
250
|
+
Thread.start do
|
251
|
+
loop do
|
252
|
+
@ping = false
|
253
|
+
time = Time.now.to_i
|
254
|
+
if @ping == false && (time - @updated_on > 60)
|
255
|
+
post @socket, server_name, PING, @prefix
|
256
|
+
loop do
|
257
|
+
sleep 1
|
258
|
+
if @ping
|
259
|
+
break
|
260
|
+
end
|
261
|
+
if 60 < Time.now.to_i - time
|
262
|
+
Thread.stop
|
263
|
+
finish
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
sleep 60
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
# Call when client connected.
|
273
|
+
# Send RPL_WELCOME sequence. If you want to customize, override this method at subclass.
|
274
|
+
def initial_message
|
275
|
+
post @socket, server_name, RPL_WELCOME, @nick, "Welcome to the Internet Relay Network #{@prefix}"
|
276
|
+
post @socket, server_name, RPL_YOURHOST, @nick, "Your host is #{server_name}, running version #{server_version}"
|
277
|
+
post @socket, server_name, RPL_CREATED, @nick, "This server was created #{Time.now}"
|
278
|
+
post @socket, server_name, RPL_MYINFO, @nick, "#{server_name} #{server_version} #{available_user_modes} #{available_channel_modes}"
|
279
|
+
end
|
280
|
+
|
281
|
+
end
|
282
|
+
|
283
|
+
|
284
|
+
if __FILE__ == $0
|
285
|
+
require "optparse"
|
286
|
+
|
287
|
+
opts = {
|
288
|
+
:port => 6969,
|
289
|
+
:host => "localhost",
|
290
|
+
:log => nil,
|
291
|
+
:debug => false,
|
292
|
+
:foreground => false,
|
293
|
+
}
|
294
|
+
|
295
|
+
OptionParser.new do |parser|
|
296
|
+
parser.instance_eval do
|
297
|
+
self.banner = <<-EOB.gsub(/^\t+/, "")
|
298
|
+
Usage: #{$0} [opts]
|
299
|
+
|
300
|
+
EOB
|
301
|
+
|
302
|
+
separator ""
|
303
|
+
|
304
|
+
separator "Options:"
|
305
|
+
on("-p", "--port [PORT=#{opts[:port]}]", "port number to listen") do |port|
|
306
|
+
opts[:port] = port
|
307
|
+
end
|
308
|
+
|
309
|
+
on("-h", "--host [HOST=#{opts[:host]}]", "host name or IP address to listen") do |host|
|
310
|
+
opts[:host] = host
|
311
|
+
end
|
312
|
+
|
313
|
+
on("-l", "--log LOG", "log file") do |log|
|
314
|
+
opts[:log] = log
|
315
|
+
end
|
316
|
+
|
317
|
+
on("--debug", "Enable debug mode") do |debug|
|
318
|
+
opts[:log] = $stdout
|
319
|
+
opts[:debug] = true
|
320
|
+
end
|
321
|
+
|
322
|
+
on("-f", "--foreground", "run foreground") do |foreground|
|
323
|
+
opts[:log] = $stdout
|
324
|
+
opts[:foreground] = true
|
325
|
+
end
|
326
|
+
|
327
|
+
on("-n", "--name [user name or email address]") do |name|
|
328
|
+
opts[:name] = name
|
329
|
+
end
|
330
|
+
|
331
|
+
parse!(ARGV)
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
opts[:logger] = Logger.new(opts[:log], "daily")
|
336
|
+
opts[:logger].level = opts[:debug] ? Logger::DEBUG : Logger::INFO
|
337
|
+
|
338
|
+
#def daemonize(foreground = false)
|
339
|
+
# [:INT, :TERM, :HUP].each do |sig|
|
340
|
+
# Signal.trap sig, "EXIT"
|
341
|
+
# end
|
342
|
+
# return yield if $DEBUG or foreground
|
343
|
+
# Process.fork do
|
344
|
+
# Process.setsid
|
345
|
+
# Dir.chdir "/"
|
346
|
+
# STDIN.reopen "/dev/null"
|
347
|
+
# STDOUT.reopen "/dev/null", "a"
|
348
|
+
# STDERR.reopen STDOUT
|
349
|
+
# yield
|
350
|
+
# end
|
351
|
+
# exit! 0
|
352
|
+
#end
|
353
|
+
|
354
|
+
#daemonize(opts[:debug] || opts[:foreground]) do
|
355
|
+
Net::IRC::Server.new(opts[:host], opts[:port], NetIrcServer, opts).start
|
356
|
+
#end
|
357
|
+
end
|
358
|
+
|