contacts 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -137,7 +137,7 @@ Class <a href="Contacts/Yahoo.html" class="link">Contacts::Yahoo</a><br />
137
137
  <tr class="top-aligned-row context-row">
138
138
  <td class="context-item-name">VERSION</td>
139
139
  <td>=</td>
140
- <td class="context-item-value">&quot;1.0.1&quot;</td>
140
+ <td class="context-item-value">&quot;1.0.2&quot;</td>
141
141
  </tr>
142
142
  </table>
143
143
  </div>
@@ -10,7 +10,7 @@
10
10
  <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
11
11
  </head>
12
12
  <body class="standalone-code">
13
- <pre><span class="ruby-comment cmt"># File lib/contacts/base.rb, line 154</span>
13
+ <pre><span class="ruby-comment cmt"># File lib/contacts/base.rb, line 182</span>
14
14
  <span class="ruby-keyword kw">def</span> <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">type</span>, <span class="ruby-identifier">login</span>, <span class="ruby-identifier">password</span>)
15
15
  <span class="ruby-keyword kw">if</span> <span class="ruby-constant">TYPES</span>.<span class="ruby-identifier">include?</span>(<span class="ruby-identifier">type</span>.<span class="ruby-identifier">to_s</span>.<span class="ruby-identifier">intern</span>)
16
16
  <span class="ruby-constant">TYPES</span>[<span class="ruby-identifier">type</span>.<span class="ruby-identifier">to_s</span>.<span class="ruby-identifier">intern</span>].<span class="ruby-identifier">new</span>(<span class="ruby-identifier">login</span>, <span class="ruby-identifier">password</span>)
@@ -10,7 +10,7 @@
10
10
  <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
11
11
  </head>
12
12
  <body class="standalone-code">
13
- <pre><span class="ruby-comment cmt"># File lib/contacts/base.rb, line 162</span>
13
+ <pre><span class="ruby-comment cmt"># File lib/contacts/base.rb, line 190</span>
14
14
  <span class="ruby-keyword kw">def</span> <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">guess</span>(<span class="ruby-identifier">login</span>, <span class="ruby-identifier">password</span>)
15
15
  <span class="ruby-constant">TYPES</span>.<span class="ruby-identifier">inject</span>([]) <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">a</span>, <span class="ruby-identifier">t</span><span class="ruby-operator">|</span>
16
16
  <span class="ruby-keyword kw">begin</span>
@@ -10,10 +10,11 @@
10
10
  <link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
11
11
  </head>
12
12
  <body class="standalone-code">
13
- <pre><span class="ruby-comment cmt"># File lib/contacts/base.rb, line 11</span>
13
+ <pre><span class="ruby-comment cmt"># File lib/contacts/base.rb, line 14</span>
14
14
  <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">login</span>, <span class="ruby-identifier">password</span>)
15
15
  <span class="ruby-ivar">@login</span> = <span class="ruby-identifier">login</span>
16
16
  <span class="ruby-ivar">@password</span> = <span class="ruby-identifier">password</span>
17
+ <span class="ruby-ivar">@connections</span> = {}
17
18
  <span class="ruby-identifier">connect</span>
18
19
  <span class="ruby-keyword kw">end</span></pre>
19
20
  </body>
@@ -10,7 +10,7 @@
10
10
  <link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
11
11
  </head>
12
12
  <body class="standalone-code">
13
- <pre><span class="ruby-comment cmt"># File lib/contacts/base.rb, line 17</span>
13
+ <pre><span class="ruby-comment cmt"># File lib/contacts/base.rb, line 21</span>
14
14
  <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">connect</span>
15
15
  <span class="ruby-identifier">raise</span> <span class="ruby-constant">AuthenticationError</span>, <span class="ruby-node">&quot;Login and password must not be nil, login: #{@login.inspect}, password: #{@password.inspect}&quot;</span> <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@login</span>.<span class="ruby-identifier">nil?</span> <span class="ruby-operator">||</span> <span class="ruby-ivar">@password</span>.<span class="ruby-identifier">nil?</span>
16
16
  <span class="ruby-identifier">real_connect</span>
@@ -10,7 +10,7 @@
10
10
  <link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
11
11
  </head>
12
12
  <body class="standalone-code">
13
- <pre><span class="ruby-comment cmt"># File lib/contacts/base.rb, line 22</span>
13
+ <pre><span class="ruby-comment cmt"># File lib/contacts/base.rb, line 26</span>
14
14
  <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">connected?</span>
15
15
  <span class="ruby-ivar">@cookies</span> <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-operator">!</span><span class="ruby-ivar">@cookies</span>.<span class="ruby-identifier">empty?</span>
16
16
  <span class="ruby-keyword kw">end</span></pre>
@@ -10,16 +10,12 @@
10
10
  <link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
11
11
  </head>
12
12
  <body class="standalone-code">
13
- <pre><span class="ruby-comment cmt"># File lib/contacts/base.rb, line 26</span>
13
+ <pre><span class="ruby-comment cmt"># File lib/contacts/base.rb, line 30</span>
14
14
  <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">contacts</span>
15
15
  <span class="ruby-keyword kw">return</span> <span class="ruby-ivar">@contacts</span> <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@contacts</span>
16
16
  <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">connected?</span>
17
17
  <span class="ruby-identifier">url</span> = <span class="ruby-constant">URI</span>.<span class="ruby-identifier">parse</span>(<span class="ruby-identifier">contact_list_url</span>)
18
- <span class="ruby-identifier">http</span> = <span class="ruby-constant">Net</span><span class="ruby-operator">::</span><span class="ruby-constant">HTTP</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">url</span>.<span class="ruby-identifier">host</span>, <span class="ruby-identifier">url</span>.<span class="ruby-identifier">port</span>)
19
- <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">url</span>.<span class="ruby-identifier">port</span> <span class="ruby-operator">==</span> <span class="ruby-value">443</span>
20
- <span class="ruby-identifier">http</span>.<span class="ruby-identifier">use_ssl</span> = <span class="ruby-keyword kw">true</span>
21
- <span class="ruby-identifier">http</span>.<span class="ruby-identifier">verify_mode</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">SSL</span><span class="ruby-operator">::</span><span class="ruby-constant">VERIFY_NONE</span>
22
- <span class="ruby-keyword kw">end</span>
18
+ <span class="ruby-identifier">http</span> = <span class="ruby-identifier">open_http</span>(<span class="ruby-identifier">url</span>)
23
19
  <span class="ruby-identifier">resp</span>, <span class="ruby-identifier">data</span> = <span class="ruby-identifier">http</span>.<span class="ruby-identifier">get</span>(<span class="ruby-node">&quot;#{url.path}?#{url.query}&quot;</span>,
24
20
  <span class="ruby-value str">&quot;Cookie&quot;</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-ivar">@cookies</span>
25
21
  )
@@ -115,6 +115,11 @@
115
115
  <td>=</td>
116
116
  <td class="context-item-value">&quot;http://%s/cgi-bin/addresses&quot;</td>
117
117
  </tr>
118
+ <tr class="top-aligned-row context-row">
119
+ <td class="context-item-name">COMPOSE_URL</td>
120
+ <td>=</td>
121
+ <td class="context-item-value">&quot;http://%s/cgi-bin/compose?&quot;</td>
122
+ </tr>
118
123
  <tr class="top-aligned-row context-row">
119
124
  <td class="context-item-name">PROTOCOL_ERROR</td>
120
125
  <td>=</td>
@@ -125,6 +130,11 @@
125
130
  <td>=</td>
126
131
  <td class="context-item-value">&quot;IfYouAreReadingThisYouHaveTooMuchFreeTime&quot;</td>
127
132
  </tr>
133
+ <tr class="top-aligned-row context-row">
134
+ <td class="context-item-name">MAX_HTTP_THREADS</td>
135
+ <td>=</td>
136
+ <td class="context-item-value">8</td>
137
+ </tr>
128
138
  </table>
129
139
  </div>
130
140
  </div>
@@ -10,7 +10,7 @@
10
10
  <link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
11
11
  </head>
12
12
  <body class="standalone-code">
13
- <pre><span class="ruby-comment cmt"># File lib/contacts/hotmail.rb, line 8</span>
13
+ <pre><span class="ruby-comment cmt"># File lib/contacts/hotmail.rb, line 10</span>
14
14
  <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">real_connect</span>
15
15
  <span class="ruby-identifier">data</span>, <span class="ruby-identifier">resp</span>, <span class="ruby-identifier">cookies</span>, <span class="ruby-identifier">forward</span> = <span class="ruby-identifier">get</span>(<span class="ruby-constant">URL</span>)
16
16
  <span class="ruby-identifier">data</span>, <span class="ruby-identifier">resp</span>, <span class="ruby-identifier">cookies</span>, <span class="ruby-identifier">forward</span> = <span class="ruby-identifier">get</span>(<span class="ruby-identifier">forward</span>, <span class="ruby-identifier">cookies</span>, <span class="ruby-constant">URL</span>)
data/doc/created.rid CHANGED
@@ -1 +1 @@
1
- Thu Dec 07 13:33:56 PST 2006
1
+ Fri Mar 30 10:28:09 PDT 2007
@@ -56,7 +56,7 @@
56
56
  </tr>
57
57
  <tr class="top-aligned-row">
58
58
  <td><strong>Last Update:</strong></td>
59
- <td>Thu Dec 07 10:27:59 PST 2006</td>
59
+ <td>Fri Mar 30 10:27:18 PDT 2007</td>
60
60
  </tr>
61
61
  </table>
62
62
  </div>
@@ -77,6 +77,9 @@
77
77
  net/http&nbsp;&nbsp;
78
78
  net/https&nbsp;&nbsp;
79
79
  uri&nbsp;&nbsp;
80
+ zlib&nbsp;&nbsp;
81
+ stringio&nbsp;&nbsp;
82
+ thread&nbsp;&nbsp;
80
83
  </div>
81
84
  </div>
82
85
 
@@ -56,7 +56,7 @@
56
56
  </tr>
57
57
  <tr class="top-aligned-row">
58
58
  <td><strong>Last Update:</strong></td>
59
- <td>Thu Dec 07 10:57:58 PST 2006</td>
59
+ <td>Fri Mar 30 10:23:35 PDT 2007</td>
60
60
  </tr>
61
61
  </table>
62
62
  </div>
data/lib/contacts/base.rb CHANGED
@@ -2,15 +2,19 @@ require "cgi"
2
2
  require "net/http"
3
3
  require "net/https"
4
4
  require "uri"
5
+ require "zlib"
6
+ require "stringio"
7
+ require "thread"
5
8
 
6
9
  class Contacts
7
10
  TYPES = {}
8
- VERSION = "1.0.1"
11
+ VERSION = "1.0.2"
9
12
 
10
13
  class Base
11
14
  def initialize(login, password)
12
15
  @login = login
13
16
  @password = password
17
+ @connections = {}
14
18
  connect
15
19
  end
16
20
 
@@ -27,11 +31,7 @@ class Contacts
27
31
  return @contacts if @contacts
28
32
  if connected?
29
33
  url = URI.parse(contact_list_url)
30
- http = Net::HTTP.new(url.host, url.port)
31
- if url.port == 443
32
- http.use_ssl = true
33
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
34
- end
34
+ http = open_http(url)
35
35
  resp, data = http.get("#{url.path}?#{url.query}",
36
36
  "Cookie" => @cookies
37
37
  )
@@ -72,6 +72,21 @@ class Contacts
72
72
  def contact_list_url
73
73
  self.class.const_get(:CONTACT_LIST_URL)
74
74
  end
75
+
76
+ def open_http(url)
77
+ c = @connections[Thread.current.object_id] ||= {}
78
+ http = c["#{url.host}:#{url.port}"]
79
+ unless http
80
+ http = Net::HTTP.new(url.host, url.port)
81
+ if url.port == 443
82
+ http.use_ssl = true
83
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
84
+ end
85
+ c["#{url.host}:#{url.port}"] = http
86
+ end
87
+ http.start unless http.started?
88
+ http
89
+ end
75
90
 
76
91
  def parse_cookies(data, existing="")
77
92
  return existing if data.nil?
@@ -105,17 +120,15 @@ class Contacts
105
120
 
106
121
  def post(url, postdata, cookies="", referer="")
107
122
  url = URI.parse(url)
108
- http = Net::HTTP.new(url.host, url.port)
109
- if url.port == 443
110
- http.use_ssl = true
111
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
112
- end
123
+ http = open_http(url)
113
124
  resp, data = http.post(url.path, postdata,
114
125
  "User-Agent" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0",
126
+ "Accept-Encoding" => "gzip",
115
127
  "Cookie" => cookies,
116
128
  "Referer" => referer,
117
129
  "Content-Type" => 'application/x-www-form-urlencoded'
118
130
  )
131
+ data = uncompress(resp, data)
119
132
  cookies = parse_cookies(resp.response['set-cookie'], cookies)
120
133
  forward = resp.response['Location']
121
134
  return data, resp, cookies, forward
@@ -123,20 +136,35 @@ class Contacts
123
136
 
124
137
  def get(url, cookies="", referer="")
125
138
  url = URI.parse(url)
126
- http = Net::HTTP.new(url.host, url.port)
127
- if url.port == 443
128
- http.use_ssl = true
129
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
130
- end
139
+ http = open_http(url)
131
140
  resp, data = http.get("#{url.path}?#{url.query}",
132
141
  "User-Agent" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0",
142
+ "Accept-Encoding" => "gzip",
133
143
  "Cookie" => cookies,
134
144
  "Referer" => referer
135
145
  )
146
+ data = uncompress(resp, data)
136
147
  cookies = parse_cookies(resp.response['set-cookie'], cookies)
137
148
  forward = resp.response['Location']
138
149
  return data, resp, cookies, forward
139
150
  end
151
+
152
+ def uncompress(resp, data)
153
+ case resp.response['content-encoding']
154
+ when 'gzip':
155
+ gz = Zlib::GzipReader.new(StringIO.new(data))
156
+ data = gz.read
157
+ gz.close
158
+ resp.response['content-encoding'] = nil
159
+ # FIXME: Not sure what Hotmail was feeding me with their 'deflate',
160
+ # but the headers definitely were not right
161
+ when 'deflate':
162
+ data = Zlib::Inflate.inflate(data)
163
+ resp.response['content-encoding'] = nil
164
+ end
165
+
166
+ data
167
+ end
140
168
  end
141
169
 
142
170
  class ContactsError < StandardError
@@ -2,8 +2,10 @@ class Contacts
2
2
  class Hotmail < Base
3
3
  URL = "http://www.hotmail.com/"
4
4
  CONTACT_LIST_URL = "http://%s/cgi-bin/addresses"
5
+ COMPOSE_URL = "http://%s/cgi-bin/compose?"
5
6
  PROTOCOL_ERROR = "Hotmail has changed its protocols, please upgrade this library first. If that does not work, contact lucas@rufy.com with this error"
6
7
  PWDPAD = "IfYouAreReadingThisYouHaveTooMuchFreeTime"
8
+ MAX_HTTP_THREADS = 8
7
9
 
8
10
  def real_connect
9
11
  data, resp, cookies, forward = get(URL)
@@ -60,15 +62,59 @@ class Contacts
60
62
  CONTACT_LIST_URL % @domain
61
63
  end
62
64
 
65
+ def follow_email(data, id, contacts_slot)
66
+ compose_url = COMPOSE_URL % @domain
67
+ postdata = "HrsTest=&to=#{id}&mailto=1&ref=addresses"
68
+ postdata += "&curmbox=00000000-0000-0000-0000-000000000001"
69
+
70
+ a = data.split(/>\s*<input\s+/i).grep(/\s+name="a"/i)
71
+ return nil if a.empty?
72
+
73
+ a = a[0].match(/\s+value="([a-f0-9]+)"/i) or return nil
74
+ postdata += "&a=#{a[1]}"
75
+
76
+ data, resp, @cookies, forward = post(compose_url, postdata, @cookies)
77
+ e = data.split(/>\s*<input\s+/i).grep(/\s+name="to"/i)
78
+ return nil if e.empty?
79
+
80
+ e = e[0].match(/\s+value="([^"]+)"/i) or return nil
81
+ @contacts[contacts_slot][1] = e[1] if e[1].match(/@/)
82
+ end
83
+
63
84
  def parse(data)
64
85
  chunks = data.split('id="hotmail"')
65
- chunks.delete_at(0)
86
+ prev = chunks.delete_at(0)
66
87
 
67
- @contacts = chunks.map do |chunk|
88
+ queue = Queue.new
89
+ threads = []
90
+ @contacts = []
91
+ chunks.each do |chunk|
68
92
  name = chunk.split('return false;">')[1].split('</a>')[0] rescue nil
69
93
  email = chunk.split('return false;">')[2].split('</a>')[0] rescue nil
70
- [name, email] if email && email != "more"
71
- end.compact
94
+ unless email && email != "more"
95
+ prev = chunk
96
+ next
97
+ end
98
+ next_slot = @contacts.size
99
+ @contacts[next_slot] = [name, email]
100
+ if email.match(/\.\.\.$/)
101
+ if m = prev.match(/\s+id="([A-Za-z0-9\-]+)"/)
102
+ queue.push([m[1], next_slot])
103
+ if threads.size < MAX_HTTP_THREADS
104
+ threads.push(Thread.new {
105
+ while x = queue.pop
106
+ follow_email(data, *x)
107
+ end
108
+ })
109
+ end
110
+ end
111
+ end
112
+ prev = chunk
113
+ end
114
+
115
+ threads.each { queue.push(nil) }
116
+ threads.each { |t| t.join }
117
+ @contacts
72
118
  end
73
119
 
74
120
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: contacts
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.0.1
7
- date: 2006-12-07 00:00:00 -08:00
6
+ version: 1.0.2
7
+ date: 2007-03-30 00:00:00 -07:00
8
8
  summary: Ridiculously easy contact list information from various providers including Yahoo, Gmail, and Hotmail
9
9
  require_paths:
10
10
  - lib