contacts 1.0.1 → 1.0.2
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/doc/classes/Contacts.html +1 -1
- data/doc/classes/Contacts.src/M000001.html +1 -1
- data/doc/classes/Contacts.src/M000002.html +1 -1
- data/doc/classes/Contacts/Base.src/M000005.html +2 -1
- data/doc/classes/Contacts/Base.src/M000006.html +1 -1
- data/doc/classes/Contacts/Base.src/M000007.html +1 -1
- data/doc/classes/Contacts/Base.src/M000008.html +2 -6
- data/doc/classes/Contacts/Hotmail.html +10 -0
- data/doc/classes/Contacts/Hotmail.src/M000011.html +1 -1
- data/doc/created.rid +1 -1
- data/doc/files/lib/contacts/base_rb.html +4 -1
- data/doc/files/lib/contacts/hotmail_rb.html +1 -1
- data/lib/contacts/base.rb +44 -16
- data/lib/contacts/hotmail.rb +50 -4
- metadata +2 -2
data/doc/classes/Contacts.html
CHANGED
@@ -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">"1.0.
|
140
|
+
<td class="context-item-value">"1.0.2"</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
|
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
|
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
|
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
|
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">"Login and password must not be nil, login: #{@login.inspect}, password: #{@password.inspect}"</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
|
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">&&</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
|
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-
|
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">"#{url.path}?#{url.query}"</span>,
|
24
20
|
<span class="ruby-value str">"Cookie"</span> =<span class="ruby-operator">></span> <span class="ruby-ivar">@cookies</span>
|
25
21
|
)
|
@@ -115,6 +115,11 @@
|
|
115
115
|
<td>=</td>
|
116
116
|
<td class="context-item-value">"http://%s/cgi-bin/addresses"</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">"http://%s/cgi-bin/compose?"</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">"IfYouAreReadingThisYouHaveTooMuchFreeTime"</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
|
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
|
-
|
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>
|
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
|
78
78
|
net/https
|
79
79
|
uri
|
80
|
+
zlib
|
81
|
+
stringio
|
82
|
+
thread
|
80
83
|
</div>
|
81
84
|
</div>
|
82
85
|
|
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.
|
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 =
|
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 =
|
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 =
|
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
|
data/lib/contacts/hotmail.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
71
|
-
|
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.
|
7
|
-
date:
|
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
|