atig 0.0.1

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.
Files changed (171) hide show
  1. data/.gitignore +24 -0
  2. data/Gemfile +3 -0
  3. data/README.mkdn +52 -0
  4. data/Rakefile +15 -0
  5. data/atig.gemspec +25 -0
  6. data/bin/atig +74 -0
  7. data/docs/OMakefile +32 -0
  8. data/docs/OMakeroot +45 -0
  9. data/docs/_static/allow.png +0 -0
  10. data/docs/_static/emacs.png +0 -0
  11. data/docs/_static/irc_setting.png +0 -0
  12. data/docs/_static/irssi.png +0 -0
  13. data/docs/_static/limechat.png +0 -0
  14. data/docs/_static/limechat_s.png +0 -0
  15. data/docs/_static/oauth_channel.png +0 -0
  16. data/docs/_static/screenshot.png +0 -0
  17. data/docs/_static/structure.png +0 -0
  18. data/docs/_static/verify.png +0 -0
  19. data/docs/changelog.rst +96 -0
  20. data/docs/commandline_options.rst +21 -0
  21. data/docs/commands.rst +84 -0
  22. data/docs/conf.py +194 -0
  23. data/docs/config.rst +159 -0
  24. data/docs/feature.rst +41 -0
  25. data/docs/graphics.graffle +1995 -0
  26. data/docs/hacking_guide.rst +43 -0
  27. data/docs/index.rst +109 -0
  28. data/docs/irc.rst +31 -0
  29. data/docs/options.rst +75 -0
  30. data/docs/quickstart.rst +89 -0
  31. data/docs/resize.sh +7 -0
  32. data/docs/tiarra.rst +2 -0
  33. data/docs/tig.rst +21 -0
  34. data/lib/atig.rb +19 -0
  35. data/lib/atig/agent.rb +8 -0
  36. data/lib/atig/agent/agent.rb +38 -0
  37. data/lib/atig/agent/clenup.rb +23 -0
  38. data/lib/atig/agent/dm.rb +35 -0
  39. data/lib/atig/agent/following.rb +45 -0
  40. data/lib/atig/agent/full_list.rb +20 -0
  41. data/lib/atig/agent/list.rb +55 -0
  42. data/lib/atig/agent/list_status.rb +46 -0
  43. data/lib/atig/agent/mention.rb +13 -0
  44. data/lib/atig/agent/other_list.rb +18 -0
  45. data/lib/atig/agent/own_list.rb +18 -0
  46. data/lib/atig/agent/stream_follow.rb +38 -0
  47. data/lib/atig/agent/timeline.rb +13 -0
  48. data/lib/atig/agent/user_stream.rb +31 -0
  49. data/lib/atig/basic_twitter.rb +116 -0
  50. data/lib/atig/bitly.rb +52 -0
  51. data/lib/atig/channel.rb +5 -0
  52. data/lib/atig/channel/channel.rb +17 -0
  53. data/lib/atig/channel/dm.rb +14 -0
  54. data/lib/atig/channel/list.rb +76 -0
  55. data/lib/atig/channel/mention.rb +20 -0
  56. data/lib/atig/channel/retweet.rb +28 -0
  57. data/lib/atig/channel/timeline.rb +74 -0
  58. data/lib/atig/command.rb +21 -0
  59. data/lib/atig/command/autofix.rb +58 -0
  60. data/lib/atig/command/command.rb +24 -0
  61. data/lib/atig/command/command_helper.rb +95 -0
  62. data/lib/atig/command/destroy.rb +44 -0
  63. data/lib/atig/command/dm.rb +31 -0
  64. data/lib/atig/command/favorite.rb +27 -0
  65. data/lib/atig/command/info.rb +50 -0
  66. data/lib/atig/command/limit.rb +15 -0
  67. data/lib/atig/command/location.rb +23 -0
  68. data/lib/atig/command/name.rb +18 -0
  69. data/lib/atig/command/option.rb +37 -0
  70. data/lib/atig/command/refresh.rb +18 -0
  71. data/lib/atig/command/reply.rb +37 -0
  72. data/lib/atig/command/retweet.rb +63 -0
  73. data/lib/atig/command/search.rb +51 -0
  74. data/lib/atig/command/spam.rb +26 -0
  75. data/lib/atig/command/status.rb +41 -0
  76. data/lib/atig/command/thread.rb +44 -0
  77. data/lib/atig/command/time.rb +32 -0
  78. data/lib/atig/command/uptime.rb +32 -0
  79. data/lib/atig/command/user.rb +42 -0
  80. data/lib/atig/command/user_info.rb +27 -0
  81. data/lib/atig/command/version.rb +49 -0
  82. data/lib/atig/command/whois.rb +39 -0
  83. data/lib/atig/db/db.rb +60 -0
  84. data/lib/atig/db/followings.rb +131 -0
  85. data/lib/atig/db/listenable.rb +22 -0
  86. data/lib/atig/db/lists.rb +76 -0
  87. data/lib/atig/db/roman.rb +30 -0
  88. data/lib/atig/db/sized_uniq_array.rb +62 -0
  89. data/lib/atig/db/sql.rb +35 -0
  90. data/lib/atig/db/statuses.rb +147 -0
  91. data/lib/atig/db/transaction.rb +47 -0
  92. data/lib/atig/exception_util.rb +26 -0
  93. data/lib/atig/gateway.rb +62 -0
  94. data/lib/atig/gateway/channel.rb +99 -0
  95. data/lib/atig/gateway/session.rb +326 -0
  96. data/lib/atig/http.rb +95 -0
  97. data/lib/atig/ifilter.rb +7 -0
  98. data/lib/atig/ifilter/expand_url.rb +74 -0
  99. data/lib/atig/ifilter/retweet.rb +14 -0
  100. data/lib/atig/ifilter/retweet_time.rb +16 -0
  101. data/lib/atig/ifilter/sanitize.rb +18 -0
  102. data/lib/atig/ifilter/strip.rb +15 -0
  103. data/lib/atig/ifilter/utf7.rb +26 -0
  104. data/lib/atig/ifilter/xid.rb +36 -0
  105. data/lib/atig/levenshtein.rb +49 -0
  106. data/lib/atig/monkey.rb +4 -0
  107. data/lib/atig/oauth-patch.rb +40 -0
  108. data/lib/atig/oauth.rb +55 -0
  109. data/lib/atig/ofilter.rb +4 -0
  110. data/lib/atig/ofilter/escape_url.rb +102 -0
  111. data/lib/atig/ofilter/footer.rb +20 -0
  112. data/lib/atig/ofilter/geo.rb +17 -0
  113. data/lib/atig/ofilter/short_url.rb +47 -0
  114. data/lib/atig/option.rb +90 -0
  115. data/lib/atig/scheduler.rb +79 -0
  116. data/lib/atig/search.rb +22 -0
  117. data/lib/atig/search_twitter.rb +21 -0
  118. data/lib/atig/sized_hash.rb +33 -0
  119. data/lib/atig/stream.rb +66 -0
  120. data/lib/atig/twitter.rb +79 -0
  121. data/lib/atig/twitter_struct.rb +63 -0
  122. data/lib/atig/unu.rb +27 -0
  123. data/lib/atig/update_checker.rb +53 -0
  124. data/lib/atig/url_escape.rb +62 -0
  125. data/lib/atig/util.rb +16 -0
  126. data/lib/atig/version.rb +3 -0
  127. data/lib/memory_profiler.rb +77 -0
  128. data/spec/command/autofix_spec.rb +35 -0
  129. data/spec/command/destroy_spec.rb +98 -0
  130. data/spec/command/dm_spec.rb +28 -0
  131. data/spec/command/favorite_spec.rb +55 -0
  132. data/spec/command/limit_spec.rb +27 -0
  133. data/spec/command/location_spec.rb +25 -0
  134. data/spec/command/name_spec.rb +19 -0
  135. data/spec/command/option_spec.rb +133 -0
  136. data/spec/command/refresh_spec.rb +22 -0
  137. data/spec/command/reply_spec.rb +79 -0
  138. data/spec/command/retweet_spec.rb +66 -0
  139. data/spec/command/spam_spec.rb +27 -0
  140. data/spec/command/status_spec.rb +44 -0
  141. data/spec/command/thread_spec.rb +91 -0
  142. data/spec/command/time_spec.rb +52 -0
  143. data/spec/command/uptime_spec.rb +55 -0
  144. data/spec/command/user_info_spec.rb +42 -0
  145. data/spec/command/user_spec.rb +50 -0
  146. data/spec/command/version_spec.rb +67 -0
  147. data/spec/command/whois_spec.rb +78 -0
  148. data/spec/db/followings_spec.rb +100 -0
  149. data/spec/db/listenable_spec.rb +32 -0
  150. data/spec/db/lists_spec.rb +104 -0
  151. data/spec/db/roman_spec.rb +17 -0
  152. data/spec/db/sized_uniq_array_spec.rb +63 -0
  153. data/spec/db/statuses_spec.rb +180 -0
  154. data/spec/ifilter/expand_url_spec.rb +44 -0
  155. data/spec/ifilter/retweet_spec.rb +28 -0
  156. data/spec/ifilter/retweet_time_spec.rb +25 -0
  157. data/spec/ifilter/sanitize_spec.rb +25 -0
  158. data/spec/ifilter/sid_spec.rb +29 -0
  159. data/spec/ifilter/strip_spec.rb +23 -0
  160. data/spec/ifilter/tid_spec.rb +29 -0
  161. data/spec/ifilter/utf7_spec.rb +30 -0
  162. data/spec/levenshtein_spec.rb +24 -0
  163. data/spec/ofilter/escape_url_spec.rb +50 -0
  164. data/spec/ofilter/footer_spec.rb +32 -0
  165. data/spec/ofilter/geo_spec.rb +33 -0
  166. data/spec/ofilter/short_url_spec.rb +127 -0
  167. data/spec/option_spec.rb +91 -0
  168. data/spec/sized_hash_spec.rb +45 -0
  169. data/spec/spec_helper.rb +35 -0
  170. data/spec/update_checker_spec.rb +55 -0
  171. metadata +326 -0
data/lib/atig/http.rb ADDED
@@ -0,0 +1,95 @@
1
+ require "net/https"
2
+ require 'atig/util'
3
+
4
+ module Atig
5
+ class Http
6
+ include Util
7
+
8
+ @@proxy = nil
9
+ def self.proxy=(proxy)
10
+ if proxy =~ /\A(?:([^:@]+)(?::([^@]+))?@)?([^:]+)(?::(\d+))?\z/ then
11
+ @@proxy = OpenStruct.new({
12
+ :user => $1,
13
+ :password => $2,
14
+ :address => $3,
15
+ :port => $4.to_i,
16
+ })
17
+ end
18
+ end
19
+
20
+ def initialize(logger=nil)
21
+ @log = logger
22
+ @cert_store = OpenSSL::X509::Store.new
23
+ @cert_store.set_default_paths
24
+ end
25
+
26
+ def server_name
27
+ "twittergw"
28
+ end
29
+
30
+ def server_version
31
+ @server_version ||= instance_eval {
32
+ head = `git rev-parse HEAD 2>/dev/null`.chomp
33
+ head.empty?? "unknown" : head
34
+ }
35
+ end
36
+
37
+ def http(uri, open_timeout = nil, read_timeout = 60)
38
+ http = case
39
+ when @@proxy
40
+ Net::HTTP.new(uri.host, uri.port, @@proxy.address, @@proxy.port,
41
+ @@proxy.user, @@proxy.password)
42
+ when ENV["HTTP_PROXY"], ENV["http_proxy"]
43
+ proxy = URI(ENV["HTTP_PROXY"] || ENV["http_proxy"])
44
+ Net::HTTP.new(uri.host, uri.port, proxy.host, proxy.port,
45
+ proxy.user, proxy.password)
46
+ else
47
+ Net::HTTP.new(uri.host, uri.port)
48
+ end
49
+ http.open_timeout = open_timeout if open_timeout # nil by default
50
+ http.read_timeout = read_timeout if read_timeout # 60 by default
51
+ if uri.is_a? URI::HTTPS
52
+ http.use_ssl = true
53
+ http.cert_store = @cert_store
54
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
55
+ end
56
+ http
57
+ rescue => e
58
+ log(:error, e) if @log
59
+ end
60
+
61
+ def req(method, uri, header = {}, credentials = nil)
62
+ accepts = ["*/*"]
63
+ types = { "json" => "application/json", "txt" => "text/plain" }
64
+ ext = uri.path[/[^.]+\z/]
65
+ accepts.unshift types[ext] if types.key?(ext)
66
+ user_agent = "#{self.class}/#{server_version} (#{File.basename(__FILE__)}; net-irc) Ruby/#{RUBY_VERSION} (#{RUBY_PLATFORM})"
67
+
68
+ header["User-Agent"] ||= user_agent
69
+ header["Accept"] ||= accepts.join(",")
70
+ header["Accept-Charset"] ||= "UTF-8,*;q=0.0" if ext != "json"
71
+
72
+ req = case method.to_s.downcase.to_sym
73
+ when :get
74
+ Net::HTTP::Get.new uri.request_uri, header
75
+ when :head
76
+ Net::HTTP::Head.new uri.request_uri, header
77
+ when :post
78
+ Net::HTTP::Post.new uri.path, header
79
+ when :put
80
+ Net::HTTP::Put.new uri.path, header
81
+ when :delete
82
+ Net::HTTP::Delete.new uri.request_uri, header
83
+ else # raise ""
84
+ end
85
+ if req.request_body_permitted?
86
+ req["Content-Type"] ||= "application/x-www-form-urlencoded"
87
+ req.body = uri.query
88
+ end
89
+ req.basic_auth(*credentials) if credentials
90
+ req
91
+ rescue => e
92
+ log(:error, e) if @log
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,7 @@
1
+ require 'atig/ifilter/retweet'
2
+ require 'atig/ifilter/retweet_time'
3
+ require 'atig/ifilter/utf7'
4
+ require 'atig/ifilter/sanitize'
5
+ require 'atig/ifilter/expand_url'
6
+ require 'atig/ifilter/strip'
7
+ require 'atig/ifilter/xid'
@@ -0,0 +1,74 @@
1
+ # -*- mode:ruby; coding:utf-8 -*-
2
+
3
+ require 'atig/util'
4
+ require 'atig/http'
5
+ require 'atig/sized_hash'
6
+
7
+ module Atig
8
+ module IFilter
9
+ class ExpandUrl
10
+ include Util
11
+ def initialize(context)
12
+ @log = context.log
13
+ @opts = context.opts
14
+ @http = Atig::Http.new @log
15
+ @cache = Atig::SizedHash.new 100
16
+ end
17
+
18
+ def call(status)
19
+ target = if @opts.untiny_whole_urls then
20
+ URI.regexp(%w[http https])
21
+ else
22
+ %r{
23
+ http:// (?:
24
+ (?: bit\.ly | (?: tin | rub) yurl\.com | j\.mp | t\.co
25
+ | htn.to
26
+ | is\.gd | cli\.gs | tr\.im | u\.nu | airme\.us
27
+ | ff\.im | twurl.nl | bkite\.com | tumblr\.com
28
+ | pic\.gd | sn\.im | digg\.com | goo\.gl)
29
+ / [0-9a-z=-]+ |
30
+ blip\.fm/~ (?> [0-9a-z]+) (?! /) |
31
+ flic\.kr/[a-z0-9/]+
32
+ )
33
+ }ix
34
+ end
35
+
36
+ status.merge :text => status.text.gsub(target) {|url|
37
+ x = @cache[url]
38
+ if x then
39
+ x
40
+ else
41
+ @cache[url] = resolve_http_redirect(URI(url)).to_s || url
42
+ end
43
+ }
44
+ end
45
+
46
+ def resolve_http_redirect(uri, limit = 3)
47
+ return uri if limit.zero? or uri.nil?
48
+ log :debug, uri.inspect
49
+ req = @http.req :head, uri
50
+ @http.http(uri, 3, 2).request(req) do |res|
51
+ break if not res.is_a?(Net::HTTPRedirection) or
52
+ not res.key?("Location")
53
+ begin
54
+ location = URI(res["Location"])
55
+ rescue URI::InvalidURIError
56
+ end
57
+ unless location.is_a? URI::HTTP
58
+ begin
59
+ location = URI.join(uri.to_s, res["Location"])
60
+ rescue URI::InvalidURIError, URI::BadURIError
61
+ # FIXME
62
+ end
63
+ end
64
+ uri = resolve_http_redirect(location, limit - 1)
65
+ end
66
+
67
+ uri
68
+ rescue Errno::ETIMEDOUT, IOError, Timeout::Error, Errno::ECONNRESET => e
69
+ log :error, e.inspect
70
+ uri
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,14 @@
1
+ # -*- mode:ruby; coding:utf-8 -*-
2
+
3
+ module Atig
4
+ module IFilter
5
+ module Retweet
6
+ Prefix = "\00310♺ \017"
7
+ def self.call(status)
8
+ return status unless status.retweeted_status
9
+ rt = status.retweeted_status
10
+ status.merge :text => "#{Prefix}RT @#{rt.user.screen_name}: #{rt.text}"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ # -*- mode:ruby; coding:utf-8 -*-
2
+
3
+ module Atig
4
+ module IFilter
5
+ module RetweetTime
6
+ def self.call(status)
7
+ unless status.retweeted_status then
8
+ status
9
+ else
10
+ t = Time.gm(*Time.parse(status.retweeted_status.created_at).to_a)
11
+ status.merge :text => "#{status.text} \x0310[#{t.strftime "%Y-%m-%d %H:%M"}]\x0F"
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ # -*- mode:ruby; coding:utf-8 -*-
2
+
3
+ module Atig
4
+ module IFilter
5
+ WSP_REGEX = Regexp.new("\\r\\n|[\\r\\n\\t#{"\\u00A0\\u1680\\u180E\\u2002-\\u200D\\u202F\\u205F\\u2060\\uFEFF" if "\u0000" == "\000"}]")
6
+
7
+ Sanitize = lambda{|status|
8
+ text = status.text.
9
+ delete("\000\001").
10
+ gsub(">", ">").
11
+ gsub(""", '"').
12
+ gsub("&lt;", "<").
13
+ gsub(WSP_REGEX, " ")
14
+ status.merge :text => text
15
+ }
16
+ end
17
+ end
18
+
@@ -0,0 +1,15 @@
1
+ # -*- mode:ruby; coding:utf-8 -*-
2
+
3
+ module Atig
4
+ module IFilter
5
+ class Strip
6
+ def initialize(suffix=[])
7
+ @rsuffix = /#{Regexp.union(*suffix)}\z/
8
+ end
9
+
10
+ def call(status)
11
+ status.merge :text => status.text.sub(@rsuffix, "").strip
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ # -*- mode:ruby; coding:utf-8 -*-
2
+
3
+ require 'atig/util'
4
+ require "iconv"
5
+
6
+ module Atig
7
+ module IFilter
8
+ class Utf7
9
+ include Util
10
+ def initialize(context)
11
+ @log = context.log
12
+ end
13
+
14
+ def call(status)
15
+ return status unless defined? ::Iconv and status.text.include?("+")
16
+
17
+ status.merge :text => status.text.sub(/\A(?:.+ > |.+\z)/) { Iconv.iconv("UTF-8", "UTF-7", $&).join }
18
+ rescue Iconv::IllegalSequence
19
+ status
20
+ rescue => e
21
+ log :error,e
22
+ status
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,36 @@
1
+
2
+ module Atig
3
+ module IFilter
4
+ class Xid
5
+ def initialize(context)
6
+ @opts = context.opts
7
+ c = @opts.send name # expect: 0..15, true, "0,1"
8
+ b = nil
9
+ c, b = c.split(",", 2).map {|i| i.to_i } if c.respond_to? :split
10
+ c = 10 unless (0 .. 15).include? c # 10: teal
11
+ if (0 .. 15).include?(b)
12
+ @format = "\003%.2d,%.2d[%%s]\017" % [c, b]
13
+ else
14
+ @format = "\003%.2d[%%s]\017" % c
15
+ end
16
+ end
17
+
18
+ def call(status)
19
+ xid = status.send name
20
+ unless xid and @opts.send(name)
21
+ status
22
+ else
23
+ status.merge :text => "#{status.text} #{@format % xid}"
24
+ end
25
+ end
26
+ end
27
+
28
+ class Sid < Xid
29
+ def name; :sid end
30
+ end
31
+
32
+ class Tid < Xid
33
+ def name; :tid end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,49 @@
1
+ # -*- mode:ruby; coding:utf-8 -*-
2
+ # http://subtech.g.hatena.ne.jp/cho45/20091008/1254934083
3
+
4
+ module Atig
5
+ module Levenshtein
6
+ def levenshtein(a, b)
7
+ PureRuby.levenshtein(a, b)
8
+ end
9
+ module_function :levenshtein
10
+
11
+ module PureRuby
12
+ def levenshtein(a, b)
13
+ case
14
+ when a.empty?
15
+ b.length
16
+ when b.empty?
17
+ a.length
18
+ else
19
+ d = Array.new(a.length + 1) { |s|
20
+ Array.new(b.length + 1, 0)
21
+ }
22
+
23
+ (0..a.length).each do |i|
24
+ d[i][0] = i
25
+ end
26
+
27
+ (0..b.length).each do |j|
28
+ d[0][j] = j
29
+ end
30
+
31
+ (1..a.length).each do |i|
32
+ (1..b.length).each do |j|
33
+ cost = (a[i - 1] == b[j - 1]) ? 0 : 1
34
+ d[i][j] = [
35
+ d[i-1][j ] + 1,
36
+ d[i ][j-1] + 1,
37
+ d[i-1][j-1] + cost
38
+ ].min
39
+ end
40
+ end
41
+
42
+ d[a.length][b.length]
43
+ end
44
+ end
45
+
46
+ module_function :levenshtein
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,4 @@
1
+ # monkey hack
2
+ module Net::IRC
3
+ module_function :low_quote, :low_dequote
4
+ end
@@ -0,0 +1,40 @@
1
+ # -*- coding: utf-8 -*-
2
+ if defined? ::Encoding
3
+ # エンコーディングの違いのせいで、
4
+ # 日本語の文字列をpostパラメータに含めようとするとエラーが出ます。
5
+ # 無理矢理エンコーディングをUTF-8に変えて再試行することで回避。
6
+ module OAuth
7
+ module Helper
8
+ def escape(value)
9
+ begin
10
+ URI::escape(value.to_s, OAuth::RESERVED_CHARACTERS)
11
+ rescue ArgumentError
12
+ URI::escape(
13
+ value.to_s.force_encoding(Encoding::UTF_8),
14
+ OAuth::RESERVED_CHARACTERS
15
+ )
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ # 1.9から文字列がEnumerableでなくなりましたので、
22
+ # その対応をしています。
23
+ module HMAC
24
+ class Base
25
+ def set_key(key)
26
+ key = @algorithm.digest(key) if key.size > @block_size
27
+ key_xor_ipad = Array.new(@block_size, 0x36)
28
+ key_xor_opad = Array.new(@block_size, 0x5c)
29
+ key.bytes.each_with_index do |value, index|
30
+ key_xor_ipad[index] ^= value
31
+ key_xor_opad[index] ^= value
32
+ end
33
+ @key_xor_ipad = key_xor_ipad.pack('c*')
34
+ @key_xor_opad = key_xor_opad.pack('c*')
35
+ @md = @algorithm.new
36
+ @initialized = true
37
+ end
38
+ end
39
+ end
40
+ end
data/lib/atig/oauth.rb ADDED
@@ -0,0 +1,55 @@
1
+ # -*- mode:ruby; coding:utf-8 -*-
2
+ require 'atig/oauth-patch'
3
+
4
+ module Atig
5
+ class OAuth
6
+ CONSUMER_KEY = 'TO9wbD379qmFSJp6pFs5w'
7
+ CONSUMER_SECRET = 'Gap8ishP3J3JrjH4JEspcii4poiZgMowHRazWGM1cYg'
8
+
9
+ @@profiles = {}
10
+ class << self
11
+ def dump
12
+ @@profiles
13
+ end
14
+
15
+ def load(profiles)
16
+ @@profiles = profiles
17
+ end
18
+ end
19
+
20
+ attr_reader :access
21
+ def initialize(context, nick)
22
+ uri = URI(context.opts.api_base)
23
+ site = "http://#{uri.host}"
24
+
25
+ @nick = nick
26
+ @oauth = ::OAuth::Consumer.new(CONSUMER_KEY, CONSUMER_SECRET, {
27
+ :site => site,
28
+ :proxy => ENV["HTTP_PROXY"] || ENV["http_proxy"]
29
+ })
30
+
31
+ if @@profiles.key? @nick
32
+ token,secret = @@profiles[@nick]
33
+ @access = ::OAuth::AccessToken.new(@oauth, token, secret)
34
+ end
35
+ end
36
+
37
+ def verified?
38
+ @access != nil
39
+ end
40
+
41
+ def url
42
+ @request = @oauth.get_request_token
43
+ @request.authorize_url
44
+ end
45
+
46
+ def verify(code)
47
+ @access = @request.get_access_token(:oauth_verifier => code)
48
+ if @access then
49
+ @@profiles[@nick] = [ @access.token , @access.secret ]
50
+ end
51
+ rescue
52
+ false
53
+ end
54
+ end
55
+ end