net-irc 0.0.5 → 0.0.6

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.
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # -*- coding: UTF-8 -*-
2
3
  =begin
3
4
 
4
5
  # wig.rb
@@ -21,7 +22,7 @@ Configuration example for Tiarra ( http://coderepos.org/share/wiki/Tiarra ).
21
22
 
22
23
  wassr {
23
24
  host: localhost
24
- port: 16668
25
+ port: 16670
25
26
  name: username@example.com athack jabber=username@example.com:jabberpasswd tid=10 ratio=10:3:5
26
27
  password: password on Wassr
27
28
  in-encoding: utf8
@@ -181,8 +182,8 @@ class WassrIrcGateway < Net::IRC::Server::Session
181
182
  log "Client Options: #{@opts.inspect}"
182
183
  @log.info "Client Options: #{@opts.inspect}"
183
184
 
184
- timeline_ratio, friends_ratio, channel_ratio = (@opts["ratio"] || "10:3:5").split(":").map {|ratio| ratio.to_i }
185
- footing = (timeline_ratio + friends_ratio + channel_ratio).to_f
185
+ @ratio = Struct.new(:timeline, :friends, :channel).new(*(@opts["ratio"] || "10:3:5").split(":").map {|ratio| ratio.to_f })
186
+ @footing = @ratio.inject {|r,i| r + i }
186
187
 
187
188
  @timeline = []
188
189
  @check_friends_thread = Thread.start do
@@ -197,7 +198,7 @@ class WassrIrcGateway < Net::IRC::Server::Session
197
198
  @log.error "\t#{l}"
198
199
  end
199
200
  end
200
- sleep freq(friends_ratio / footing)
201
+ sleep freq(@ratio[:friends] / @footing)
201
202
  end
202
203
  end
203
204
 
@@ -217,7 +218,7 @@ class WassrIrcGateway < Net::IRC::Server::Session
217
218
  @log.error "\t#{l}"
218
219
  end
219
220
  end
220
- sleep freq(timeline_ratio / footing)
221
+ sleep freq(@ratio[:timeline] / @footing)
221
222
  end
222
223
  end
223
224
 
@@ -236,7 +237,7 @@ class WassrIrcGateway < Net::IRC::Server::Session
236
237
  @log.error "\t#{l}"
237
238
  end
238
239
  end
239
- sleep freq(channel_ratio / footing)
240
+ sleep freq(@ratio[:channel] / @footing)
240
241
  end
241
242
  end
242
243
  end
@@ -257,23 +258,26 @@ class WassrIrcGateway < Net::IRC::Server::Session
257
258
  begin
258
259
  if target =~ /^#(.+)/
259
260
  channel = Regexp.last_match[1]
260
- if @opts.key?("alwaysim") && @im && @im.connected? # in jabber mode, using jabber post
261
+ reply = message[/\s+>(.+)$/, 1]
262
+ message = Iconv.iconv("UTF-7", "UTF-8", message).join if @utf7
263
+ if !reply && @opts.key?("alwaysim") && @im && @im.connected? # in jabber mode, using jabber post
261
264
  message = "##{channel} #{message}" unless "##{channel}" == main_channel
262
265
  ret = @im.deliver(jabber_bot_id, message)
263
266
  post "#{nick}!#{nick}@#{api_base.host}", TOPIC, channel, untinyurl(message)
264
267
  else
265
268
  if "##{channel}" == main_channel
266
- ret = api("statuses/update", {"status" => message})
269
+ rid = rid_for(reply) if reply
270
+ ret = api("statuses/update", {"status" => message, "reply_status_rid" => rid})
267
271
  else
268
272
  ret = api("channel_message/update", {"name_en" => channel, "body" => message})
269
273
  end
274
+ log "Status Updated via API"
270
275
  end
271
276
  else
272
277
  # direct message
273
278
  ret = api("direct_messages/new", {"user" => target, "text" => message})
274
279
  end
275
280
  raise ApiFailed, "API failed" unless ret
276
- log "Status Updated" unless @im && @im.connected?
277
281
  rescue => e
278
282
  @log.error [retry_count, e.inspect].inspect
279
283
  if retry_count > 0
@@ -289,6 +293,14 @@ class WassrIrcGateway < Net::IRC::Server::Session
289
293
  def on_ctcp(target, message)
290
294
  _, command, *args = message.split(/\s+/)
291
295
  case command
296
+ when "utf7"
297
+ begin
298
+ require "iconv"
299
+ @utf7 = !@utf7
300
+ log "utf7 mode: #{@utf7 ? 'on' : 'off'}"
301
+ rescue LoadError => e
302
+ log "Can't load iconv."
303
+ end
292
304
  when "list"
293
305
  nick = args[0]
294
306
  @log.debug([ nick, message ])
@@ -298,41 +310,49 @@ class WassrIrcGateway < Net::IRC::Server::Session
298
310
  end
299
311
 
300
312
  unless res
301
- post nil, ERR_NOSUCHNICK, nick, "No such nick/channel"
313
+ post server_name, ERR_NOSUCHNICK, nick, "No such nick/channel"
302
314
  end
303
315
  when "fav"
304
- tid = args[0]
305
- st = @tmap[tid]
306
- if st
307
- if @im && @im.connected?
308
- # IM のときはいろいろめんどうなことする
309
- nick, count = *st
310
- pos = @counters[nick] - count
311
- @log.debug "%p %s %d/%d => %d" % [
312
- st,
313
- nick,
314
- count,
315
- @counters[nick],
316
- pos
317
- ]
318
- res = api("statuses/user_timeline", { "id" => nick })[pos]
319
- id = res["rid"]
320
- else
321
- id = st["id"] || st["rid"]
316
+ target = args[0]
317
+ st = @tmap[target]
318
+ id = rid_for(target)
319
+ if st || id
320
+ unless id
321
+ if @im && @im.connected?
322
+ # IM のときはいろいろめんどうなことする
323
+ nick, count = *st
324
+ pos = @counters[nick] - count
325
+ @log.debug "%p %s %d/%d => %d" % [
326
+ st,
327
+ nick,
328
+ count,
329
+ @counters[nick],
330
+ pos
331
+ ]
332
+ res = api("statuses/user_timeline", { "id" => nick })
333
+ raise ApiFailed, "#{nick} may be private mode" if res.empty?
334
+ if res[pos]
335
+ id = res[pos]["rid"]
336
+ else
337
+ raise ApiFailed, "#{pos} of #{nick} is not found."
338
+ end
339
+ else
340
+ id = st["id"] || st["rid"]
341
+ end
322
342
  end
323
343
  res = api("favorites/create/#{id}", {})
324
- post nil, NOTICE, main_channel, "Fav: #{res["screen_name"]}: #{res["text"]}"
344
+ post server_name, NOTICE, main_channel, "Fav: #{res["screen_name"]}: #{res["text"]}"
325
345
  else
326
- post nil, NOTICE, main_channel, "No such id #{tid}"
346
+ post server_name, NOTICE, main_channel, "No such id or status #{target}"
327
347
  end
328
348
  when "link"
329
349
  tid = args[0]
330
350
  st = @tmap[tid]
331
351
  if st
332
352
  st["link"] = (api_base + "/#{st["user"]["screen_name"]}/statuses/#{st["id"]}").to_s unless st["link"]
333
- post nil, NOTICE, main_channel, st["link"]
353
+ post server_name, NOTICE, main_channel, st["link"]
334
354
  else
335
- post nil, NOTICE, main_channel, "No such id #{tid}"
355
+ post server_name, NOTICE, main_channel, "No such id #{tid}"
336
356
  end
337
357
  end
338
358
  rescue ApiFailed => e
@@ -343,12 +363,12 @@ class WassrIrcGateway < Net::IRC::Server::Session
343
363
  nick = m.params[0]
344
364
  f = (@friends || []).find {|i| i["screen_name"] == nick }
345
365
  if f
346
- post nil, RPL_WHOISUSER, @nick, nick, nick, api_base.host, "*", "#{f["name"]} / #{f["description"]}"
347
- post nil, RPL_WHOISSERVER, @nick, nick, api_base.host, api_base.to_s
348
- post nil, RPL_WHOISIDLE, @nick, nick, "0", "seconds idle"
349
- post nil, RPL_ENDOFWHOIS, @nick, nick, "End of WHOIS list"
366
+ post server_name, RPL_WHOISUSER, @nick, nick, nick, api_base.host, "*", "#{f["name"]} / #{f["description"]}"
367
+ post server_name, RPL_WHOISSERVER, @nick, nick, api_base.host, api_base.to_s
368
+ post server_name, RPL_WHOISIDLE, @nick, nick, "0", "seconds idle"
369
+ post server_name, RPL_ENDOFWHOIS, @nick, nick, "End of WHOIS list"
350
370
  else
351
- post nil, ERR_NOSUCHNICK, nick, "No such nick/channel"
371
+ post server_name, ERR_NOSUCHNICK, nick, "No such nick/channel"
352
372
  end
353
373
  end
354
374
 
@@ -356,10 +376,15 @@ class WassrIrcGateway < Net::IRC::Server::Session
356
376
  channels = m.params[0].split(/\s*,\s*/)
357
377
  channels.each do |channel|
358
378
  next if channel == main_channel
359
- @channels[channel] = {
360
- :read => []
361
- }
362
- post "#{@nick}!#{@nick}@#{api_base.host}", JOIN, channel
379
+ res = api("channel/exists", { "name_en" => channel.sub(/^#/, "") })
380
+ if res["exists"]
381
+ @channels[channel] = {
382
+ :read => []
383
+ }
384
+ post "#{@nick}!#{@nick}@#{api_base.host}", JOIN, channel
385
+ else
386
+ post server_name, ERR_NOSUCHNICK, channel, "No such nick/channel"
387
+ end
363
388
  end
364
389
  end
365
390
 
@@ -381,20 +406,20 @@ class WassrIrcGateway < Net::IRC::Server::Session
381
406
  user = nick = f["screen_name"]
382
407
  host = serv = api_base.host
383
408
  real = f["name"]
384
- post nil, RPL_WHOREPLY, @nick, channel, user, host, serv, nick, "H*@", "0 #{real}"
409
+ post server_name, RPL_WHOREPLY, @nick, channel, user, host, serv, nick, "H*@", "0 #{real}"
385
410
  end
386
- post nil, RPL_ENDOFWHO, @nick, channel
411
+ post server_name, RPL_ENDOFWHO, @nick, channel
387
412
  when @groups.key?(channel)
388
413
  @groups[channel].each do |name|
389
414
  f = @friends.find {|i| i["screen_name"] == name }
390
415
  user = nick = f["screen_name"]
391
416
  host = serv = api_base.host
392
417
  real = f["name"]
393
- post nil, RPL_WHOREPLY, @nick, channel, user, host, serv, nick, "H*@", "0 #{real}"
418
+ post server_name, RPL_WHOREPLY, @nick, channel, user, host, serv, nick, "H*@", "0 #{real}"
394
419
  end
395
- post nil, RPL_ENDOFWHO, @nick, channel
420
+ post server_name, RPL_ENDOFWHO, @nick, channel
396
421
  else
397
- post nil, ERR_NOSUCHNICK, @nick, nick, "No such nick/channel"
422
+ post server_name, ERR_NOSUCHNICK, @nick, nick, "No such nick/channel"
398
423
  end
399
424
  end
400
425
 
@@ -455,6 +480,14 @@ class WassrIrcGateway < Net::IRC::Server::Session
455
480
  mesg = s["text"]
456
481
  @log.debug(mesg)
457
482
 
483
+ begin
484
+ require 'iconv'
485
+ mesg = mesg.sub(/^.+ > |^.+/) {|str| Iconv.iconv("UTF-8", "UTF-7", str).join }
486
+ mesg = "[utf7]: #{mesg}" if body =~ /[^a-z0-9\s]/i
487
+ rescue LoadError
488
+ rescue Iconv::IllegalSequence
489
+ end
490
+
458
491
  # added @user in no use @user reply message (Wassr only)
459
492
  if s.has_key?("reply_status_url") and s["reply_status_url"] and s["text"] !~ /^@.*/ and %r{([^/]+)/statuses/[^/]+}.match(s["reply_status_url"])
460
493
  reply_user_id = $1
@@ -490,11 +523,16 @@ class WassrIrcGateway < Net::IRC::Server::Session
490
523
  def check_friends
491
524
  first = true unless @friends
492
525
  @friends ||= []
493
- friends = api("statuses/friends")
526
+ friends = []
527
+ 1.upto(5) do |i|
528
+ f = api("statuses/friends", {"page" => i.to_s})
529
+ friends += f
530
+ break if f.length < 100
531
+ end
494
532
  if first && !@opts.key?("athack")
495
533
  @friends = friends
496
- post nil, RPL_NAMREPLY, @nick, "=", main_channel, @friends.map{|i| "@#{i["screen_name"]}" }.join(" ")
497
- post nil, RPL_ENDOFNAMES, @nick, main_channel, "End of NAMES list"
534
+ post server_name, RPL_NAMREPLY, @nick, "=", main_channel, @friends.map{|i| "@#{i["screen_name"]}" }.join(" ")
535
+ post server_name, RPL_ENDOFNAMES, @nick, main_channel, "End of NAMES list"
498
536
  else
499
537
  prv_friends = @friends.map {|i| i["screen_name"] }
500
538
  now_friends = friends.map {|i| i["screen_name"] }
@@ -535,6 +573,13 @@ class WassrIrcGateway < Net::IRC::Server::Session
535
573
  if Regexp.last_match
536
574
  nick, id = Regexp.last_match.captures
537
575
  body = CGI.unescapeHTML(body)
576
+ begin
577
+ require 'iconv'
578
+ body = body.sub(/^.+ > |^.+/) {|str| Iconv.iconv("UTF-8", "UTF-7", str).join }
579
+ body = "[utf7]: #{body}" if body =~ /[^a-z0-9\s]/i
580
+ rescue LoadError
581
+ rescue Iconv::IllegalSequence
582
+ end
538
583
 
539
584
  case
540
585
  when nick == "投稿完了"
@@ -582,7 +627,7 @@ class WassrIrcGateway < Net::IRC::Server::Session
582
627
 
583
628
  uri = api_base.dup
584
629
  uri.path = "/#{path}.json"
585
- uri.query = q.inject([]) {|r,(k,v)| v.inject(r) {|r,i| r << "#{k}=#{URI.escape(i, /[^-.!~*'()\w]/n)}" } }.join("&")
630
+ uri.query = q.inject([]) {|r,(k,v)| v ? r << "#{k}=#{URI.escape(v, /[^-.!~*'()\w]/n)}" : r }.join("&")
586
631
 
587
632
 
588
633
  req = nil
@@ -642,6 +687,18 @@ class WassrIrcGateway < Net::IRC::Server::Session
642
687
  }
643
688
  end
644
689
 
690
+ # return rid of most recent matched status with text
691
+ def rid_for(text)
692
+ target = Regexp.new(Regexp.quote(text.strip), "i")
693
+ status = api("statuses/friends_timeline").find {|i|
694
+ next false if i["user_login_id"] == @nick # 自分は除外
695
+ i["text"] =~ target
696
+ }
697
+
698
+ @log.debug "Looking up status contains #{text.inspect} -> #{status.inspect}"
699
+ status ? status["rid"] : nil
700
+ end
701
+
645
702
  class TypableMap < Hash
646
703
  Roma = %w|k g ky gy s z sh j t d ch n ny h b p hy by py m my y r ry w v q|.unshift("").map {|consonant|
647
704
  case
@@ -9,7 +9,7 @@ require "monitor"
9
9
  module Net; end
10
10
 
11
11
  module Net::IRC
12
- VERSION = "0.0.5"
12
+ VERSION = "0.0.6"
13
13
  class IRCException < StandardError; end
14
14
 
15
15
  require "net/irc/constants"
@@ -209,6 +209,6 @@ module Net::IRC::Constants # :nodoc:
209
209
  end
210
210
 
211
211
  Net::IRC::COMMANDS = Net::IRC::Constants.constants.inject({}) {|r,i| # :nodoc:
212
- r.update(Net::IRC::Constants.const_get(i) => i)
212
+ r.update(Net::IRC::Constants.const_get(i).to_s => i.to_s)
213
213
  }
214
214
 
@@ -82,7 +82,7 @@ class Net::IRC::Message
82
82
  # If the message is CTCP, return true.
83
83
  def ctcp?
84
84
  message = @params[1]
85
- message[0] == 1 && message[message.length-1] == 1
85
+ message[0] == "\01"[0] && message[message.length-1] == "\01"[0]
86
86
  end
87
87
 
88
88
  def inspect
@@ -1,4 +1,4 @@
1
-
1
+ # coding: ASCII-8BIT
2
2
  module Net::IRC::PATTERN # :nodoc:
3
3
  # letter = %x41-5A / %x61-7A ; A-Z / a-z
4
4
  # digit = %x30-39 ; 0-9
@@ -56,7 +56,7 @@ module Net::IRC::PATTERN # :nodoc:
56
56
  # =/ 14( SPACE middle ) [ SPACE [ ":" ] trailing ]
57
57
  MIDDLE = "[#{NOSPCRLFCL}][:#{NOSPCRLFCL}]*"
58
58
  TRAILING = "[: #{NOSPCRLFCL}]*"
59
- PARAMS = "(?:((?: #{MIDDLE}){0,14})(?: :(#{TRAILING}))?|((?: #{MIDDLE}){14})(?::?)?(#{TRAILING}))"
59
+ PARAMS = "(?:((?: #{MIDDLE}){0,14})(?: :(#{TRAILING}))?|((?: #{MIDDLE}){14}):?(#{TRAILING}))"
60
60
 
61
61
  # crlf = %x0D %x0A ; "carriage return" "linefeed"
62
62
  # message = [ ":" prefix SPACE ] command [ params ] crlf
@@ -56,6 +56,7 @@ describe Net::IRC, "server and client" do
56
56
  @server.start
57
57
  end
58
58
 
59
+ Thread.pass
59
60
  true until @server.instance_variable_get(:@serv)
60
61
 
61
62
  @port = @server.instance_variable_get(:@serv).addr[1]
@@ -70,6 +71,9 @@ describe Net::IRC, "server and client" do
70
71
  })
71
72
  @client.start
72
73
  end
74
+
75
+ Thread.pass
76
+ true until @client
73
77
  end
74
78
 
75
79
  server_q = ChannelManagerTestServerSession.testq
@@ -79,6 +83,7 @@ describe Net::IRC, "server and client" do
79
83
  client = @client
80
84
  client.instance_variable_set(:@prefix, Prefix.new("foonick!foouser@localhost"))
81
85
 
86
+ true until ChannelManagerTestServerSession.instance
82
87
  ChannelManagerTestServerSession.instance.instance_eval do
83
88
  Thread.exclusive do
84
89
  post client.prefix, JOIN, "#test"
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+ # ENCODING=ASCII-8BIT
3
+ # :vim:encoding=utf-8:
4
+ # ↑ どうするのが正解?
2
5
 
3
6
  $LOAD_PATH << "lib"
4
7
  $LOAD_PATH << "../lib"
@@ -229,18 +232,19 @@ describe Net::IRC, "server and client" do
229
232
  @server, @client = nil, nil
230
233
 
231
234
  Thread.abort_on_exception = true
232
- Thread.start do
235
+ @tserver = Thread.start do
233
236
  @server = Net::IRC::Server.new("localhost", @port, TestServerSession, {
234
237
  :logger => Logger.new(nil),
235
238
  })
236
239
  @server.start
237
240
  end
238
241
 
242
+ Thread.pass
239
243
  true until @server.instance_variable_get(:@serv)
240
244
 
241
245
  @port = @server.instance_variable_get(:@serv).addr[1]
242
246
 
243
- Thread.start do
247
+ @tclient = Thread.start do
244
248
  @client = TestClient.new("localhost", @port, {
245
249
  :nick => "foonick",
246
250
  :user => "foouser",
@@ -250,6 +254,9 @@ describe Net::IRC, "server and client" do
250
254
  })
251
255
  @client.start
252
256
  end
257
+
258
+ Thread.pass
259
+ true until @client
253
260
  end
254
261
 
255
262
  server_q = TestServerSession.testq
@@ -285,41 +292,20 @@ describe Net::IRC, "server and client" do
285
292
  post nil, NOTICE, "#test", "sep1"
286
293
  end
287
294
  end
295
+ Thread.pass
288
296
  true until client_q.pop.to_s == "NOTICE #test sep1\r\n"
289
297
  client.prefix.should == "foonick"
290
298
  end
291
299
 
292
- it "should destroy closed session" do
293
- oldclient = @client
294
- @client.finish
295
-
296
- Thread.start do
297
- @client = TestClient.new("localhost", @port, {
298
- :nick => "foonick",
299
- :user => "foouser",
300
- :real => "foo real name",
301
- :pass => "foopass",
302
- :logger => Logger.new(nil),
303
- })
304
- @client.start
305
- end
306
-
307
- Thread.pass
308
- true while @client == oldclient
309
-
310
- c = @client.instance_variable_get(:@channels)
311
- TestServerSession.instance.instance_eval do
312
- Thread.exclusive do
313
- post nil, NOTICE, "#test", "sep1"
314
- end
315
- end
316
-
317
- true until client_q.pop.to_s == "NOTICE #test sep1\r\n"
318
- end
300
+ # it "should destroy closed session" do
301
+ # end
319
302
 
320
303
  after :all do
321
304
  @server.finish
322
305
  @client.finish
306
+ @tserver.kill
307
+ @tclient.kill
308
+ @server = @client = @tserver = @tclient = nil
323
309
  end
324
310
  end
325
311