contacts 1.0.18 → 1.0.19
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/lib/contacts.rb +2 -1
- data/lib/contacts/aol.rb +148 -0
- data/lib/contacts/base.rb +1 -1
- data/lib/contacts/gmail.rb +1 -2
- data/lib/contacts/hotmail.rb +6 -7
- data/lib/contacts/yahoo.rb +53 -15
- metadata +2 -1
data/lib/contacts.rb
CHANGED
data/lib/contacts/aol.rb
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
class Hash
|
2
|
+
def to_query_string
|
3
|
+
u = ERB::Util.method(:u)
|
4
|
+
map { |k, v|
|
5
|
+
u.call(k) + "=" + u.call(v)
|
6
|
+
}.join("&")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Contacts
|
11
|
+
require 'hpricot'
|
12
|
+
class Aol < Base
|
13
|
+
URL = "http://www.aol.com/"
|
14
|
+
LOGIN_URL = "https://my.screenname.aol.com/_cqr/login/login.psp"
|
15
|
+
LOGIN_REFERER_URL = "http://webmail.aol.com/"
|
16
|
+
LOGIN_REFERER_PATH = "sitedomain=sns.webmail.aol.com&lang=en&locale=us&authLev=0&uitype=mini&loginId=&redirType=js&xchk=false"
|
17
|
+
AOL_NUM = "29970-343" # this seems to change each time they change the protocol
|
18
|
+
|
19
|
+
CONTACT_LIST_URL = "http://webmail.aol.com/#{AOL_NUM}/aim-2/en-us/Lite/ContactList.aspx?folder=Inbox&showUserFolders=False"
|
20
|
+
CONTACT_LIST_CSV_URL = "http://webmail.aol.com/#{AOL_NUM}/aim-2/en-us/Lite/ABExport.aspx?command=all"
|
21
|
+
PROTOCOL_ERROR = "AOL has changed its protocols, please upgrade this library first. If that does not work, dive into the code and submit a patch at http://github.com/cardmagic/contacts"
|
22
|
+
|
23
|
+
def real_connect
|
24
|
+
|
25
|
+
postdata = {
|
26
|
+
"loginId" => login,
|
27
|
+
"password" => password,
|
28
|
+
"rememberMe" => "on",
|
29
|
+
"_sns_fg_color_" => "",
|
30
|
+
"_sns_err_color_" => "",
|
31
|
+
"_sns_link_color_" => "",
|
32
|
+
"_sns_width_" => "",
|
33
|
+
"_sns_height_" => "",
|
34
|
+
"offerId" => "mail-second-en-us",
|
35
|
+
"_sns_bg_color_" => "",
|
36
|
+
"sitedomain" => "sns.webmail.aol.com",
|
37
|
+
"regPromoCode" => "",
|
38
|
+
"mcState" => "initialized",
|
39
|
+
"uitype" => "std",
|
40
|
+
"siteId" => "",
|
41
|
+
"lang" => "en",
|
42
|
+
"locale" => "us",
|
43
|
+
"authLev" => "0",
|
44
|
+
"siteState" => "",
|
45
|
+
"isSiteStateEncoded" => "false",
|
46
|
+
"use_aam" => "0",
|
47
|
+
"seamless" => "novl",
|
48
|
+
"aolsubmit" => CGI.escape("Sign In"),
|
49
|
+
"idType" => "SN",
|
50
|
+
"usrd" => "",
|
51
|
+
"doSSL" => "",
|
52
|
+
"redirType" => "",
|
53
|
+
"xchk" => "false"
|
54
|
+
}
|
55
|
+
|
56
|
+
# Get this cookie and stick it in the form to confirm to Aol that your cookies work
|
57
|
+
data, resp, cookies, forward = get(URL)
|
58
|
+
postdata["stips"] = cookie_hash_from_string(cookies)["stips"]
|
59
|
+
postdata["tst"] = cookie_hash_from_string(cookies)["tst"]
|
60
|
+
|
61
|
+
data, resp, cookies, forward, old_url = get(LOGIN_REFERER_URL, cookies) + [URL]
|
62
|
+
until forward.nil?
|
63
|
+
data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
|
64
|
+
end
|
65
|
+
|
66
|
+
data, resp, cookies, forward, old_url = get("#{LOGIN_URL}?#{LOGIN_REFERER_PATH}", cookies) + [LOGIN_REFERER_URL]
|
67
|
+
until forward.nil?
|
68
|
+
data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
|
69
|
+
end
|
70
|
+
|
71
|
+
doc = Hpricot(data)
|
72
|
+
(doc/:input).each do |input|
|
73
|
+
postdata["usrd"] = input.attributes["value"] if input.attributes["name"] == "usrd"
|
74
|
+
end
|
75
|
+
# parse data for <input name="usrd" value="2726212" type="hidden"> and add it to the postdata
|
76
|
+
|
77
|
+
postdata["SNS_SC"] = cookie_hash_from_string(cookies)["SNS_SC"]
|
78
|
+
postdata["SNS_LDC"] = cookie_hash_from_string(cookies)["SNS_LDC"]
|
79
|
+
postdata["LTState"] = cookie_hash_from_string(cookies)["LTState"]
|
80
|
+
# raise data.inspect
|
81
|
+
|
82
|
+
data, resp, cookies, forward, old_url = post(LOGIN_URL, postdata.to_query_string, cookies, LOGIN_REFERER_URL) + [LOGIN_REFERER_URL]
|
83
|
+
|
84
|
+
until forward.nil?
|
85
|
+
data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
|
86
|
+
end
|
87
|
+
|
88
|
+
if data.index("Invalid Screen Name or Password.")
|
89
|
+
raise AuthenticationError, "Username and password do not match"
|
90
|
+
elsif data.index("Required field must not be blank")
|
91
|
+
raise AuthenticationError, "Login and password must not be blank"
|
92
|
+
elsif data.index("errormsg_0_logincaptcha")
|
93
|
+
raise AuthenticationError, "Captcha error"
|
94
|
+
elsif data.index("Invalid request")
|
95
|
+
raise ConnectionError, PROTOCOL_ERROR
|
96
|
+
elsif cookies == ""
|
97
|
+
raise ConnectionError, PROTOCOL_ERROR
|
98
|
+
end
|
99
|
+
|
100
|
+
@cookies = cookies
|
101
|
+
end
|
102
|
+
|
103
|
+
def contacts
|
104
|
+
postdata = {
|
105
|
+
"file" => 'contacts',
|
106
|
+
"fileType" => 'csv'
|
107
|
+
}
|
108
|
+
|
109
|
+
return @contacts if @contacts
|
110
|
+
if connected?
|
111
|
+
data, resp, cookies, forward, old_url = get(CONTACT_LIST_URL, @cookies, CONTACT_LIST_URL) + [CONTACT_LIST_URL]
|
112
|
+
|
113
|
+
until forward.nil?
|
114
|
+
data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
|
115
|
+
end
|
116
|
+
|
117
|
+
if resp.code_type != Net::HTTPOK
|
118
|
+
raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
|
119
|
+
end
|
120
|
+
|
121
|
+
# parse data and grab <input name="user" value="8QzMPIAKs2" type="hidden">
|
122
|
+
doc = Hpricot(data)
|
123
|
+
(doc/:input).each do |input|
|
124
|
+
postdata["user"] = input.attributes["value"] if input.attributes["name"] == "user"
|
125
|
+
end
|
126
|
+
|
127
|
+
data, resp, cookies, forward, old_url = get(CONTACT_LIST_CSV_URL, @cookies, CONTACT_LIST_URL) + [CONTACT_LIST_URL]
|
128
|
+
|
129
|
+
if forward.nil?
|
130
|
+
parse data
|
131
|
+
else
|
132
|
+
raise AuthenticationError, "Account cancelled"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
private
|
137
|
+
|
138
|
+
def parse(data, options={})
|
139
|
+
data = CSV.parse(data)
|
140
|
+
col_names = data.shift
|
141
|
+
@contacts = data.map do |person|
|
142
|
+
["#{person[0]} #{person[1]}", person[4]] unless person[4].empty?
|
143
|
+
end.compact
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
TYPES[:aol] = Aol
|
148
|
+
end
|
data/lib/contacts/base.rb
CHANGED
data/lib/contacts/gmail.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# Use ActiveSupport's version of JSON if available
|
2
2
|
if Object.const_defined?('ActiveSupport') && ActiveSupport.const_defined?('JSON') && ActiveSupport::JSON.is_a?(Class)
|
3
|
-
puts JSON.class
|
4
3
|
class JSON
|
5
4
|
def self.parse(i)
|
6
5
|
ActiveSupport::JSON.decode(i)
|
@@ -81,7 +80,7 @@ class Contacts
|
|
81
80
|
# Default format.
|
82
81
|
# ['Name', 'Email1', 'Email2', ...]
|
83
82
|
if @contacts != nil
|
84
|
-
@contacts = @contacts.
|
83
|
+
@contacts = @contacts.select {|c| !c["Emails"].nil?}.map do |c|
|
85
84
|
name, emails = c.values_at "Name", "Emails"
|
86
85
|
# emails are returned in a form of
|
87
86
|
# [{"Address"=>"home.email@gmail.com"}, {"Type"=>{"Id"=>"WORK"}, "Address"=>"work.email@gmail.com"}]
|
data/lib/contacts/hotmail.rb
CHANGED
@@ -27,6 +27,11 @@ class Contacts
|
|
27
27
|
form_url = data.split("><").grep(/form/).first.split[5][8..-2]
|
28
28
|
data, resp, cookies, forward = post(form_url, postdata, cookies)
|
29
29
|
|
30
|
+
old_url = form_url
|
31
|
+
until cookies =~ /; PPAuth=/ || forward.nil?
|
32
|
+
data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
|
33
|
+
end
|
34
|
+
|
30
35
|
if data.index("The e-mail address or password is incorrect")
|
31
36
|
raise AuthenticationError, "Username and password do not match"
|
32
37
|
elsif data != ""
|
@@ -34,13 +39,7 @@ class Contacts
|
|
34
39
|
elsif cookies == ""
|
35
40
|
raise ConnectionError, PROTOCOL_ERROR
|
36
41
|
end
|
37
|
-
|
38
|
-
old_url = form_url
|
39
|
-
|
40
|
-
until forward.nil?
|
41
|
-
data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
|
42
|
-
end
|
43
|
-
|
42
|
+
|
44
43
|
data, resp, cookies, forward = get("http://mail.live.com/mail", cookies)
|
45
44
|
until forward.nil?
|
46
45
|
data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
|
data/lib/contacts/yahoo.rb
CHANGED
@@ -1,14 +1,23 @@
|
|
1
|
-
|
1
|
+
# Use ActiveSupport's version of JSON if available
|
2
|
+
if Object.const_defined?('ActiveSupport') && ActiveSupport.const_defined?('JSON') && ActiveSupport::JSON.is_a?(Class)
|
3
|
+
class JSON
|
4
|
+
def self.parse(i)
|
5
|
+
ActiveSupport::JSON.decode(i)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
else
|
9
|
+
require 'json/add/rails'
|
10
|
+
end
|
2
11
|
|
3
12
|
class Contacts
|
4
13
|
class Yahoo < Base
|
5
14
|
URL = "http://mail.yahoo.com/"
|
6
15
|
LOGIN_URL = "https://login.yahoo.com/config/login"
|
7
|
-
ADDRESS_BOOK_URL = "http://address.mail.yahoo.com
|
8
|
-
CONTACT_LIST_URL = "http://address.yahoo.com
|
16
|
+
ADDRESS_BOOK_URL = "http://address.mail.yahoo.com/?.rand=430244936"
|
17
|
+
CONTACT_LIST_URL = "http://address.mail.yahoo.com/?_src=&_crumb=crumb&sortfield=3&bucket=1&scroll=1&VPC=social_list&.r=time"
|
9
18
|
PROTOCOL_ERROR = "Yahoo has changed its protocols, please upgrade this library first. If that does not work, dive into the code and submit a patch at http://github.com/cardmagic/contacts"
|
10
19
|
|
11
|
-
def real_connect
|
20
|
+
def real_connect
|
12
21
|
postdata = ".tries=2&.src=ym&.md5=&.hash=&.js=&.last=&promo=&.intl=us&.bypass="
|
13
22
|
postdata += "&.partner=&.u=4eo6isd23l8r3&.v=0&.challenge=gsMsEcoZP7km3N3NeI4mX"
|
14
23
|
postdata += "kGB7zMV&.yplus=&.emailCode=&pkg=&stepid=&.ev=&hasMsgr=1&.chkP=Y&."
|
@@ -48,32 +57,61 @@ class Contacts
|
|
48
57
|
if resp.code_type != Net::HTTPOK
|
49
58
|
raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
|
50
59
|
end
|
51
|
-
|
52
|
-
crumb = data.to_s[/
|
60
|
+
|
61
|
+
crumb = data.to_s[/dotCrumb: '(.*?)'/][13...-1]
|
53
62
|
|
54
63
|
# now proceed with the new ".crumb" parameter to get the csv data
|
55
|
-
url = URI.parse("
|
64
|
+
url = URI.parse(contact_list_url.sub("_crumb=crumb","_crumb=#{crumb}").sub("time", Time.now.to_f.to_s.sub(".","")[0...-2]))
|
56
65
|
http = open_http(url)
|
57
|
-
resp,
|
58
|
-
"Cookie" => @cookies
|
66
|
+
resp, more_data = http.get("#{url.path}?#{url.query}",
|
67
|
+
"Cookie" => @cookies,
|
68
|
+
"X-Requested-With" => "XMLHttpRequest",
|
69
|
+
"Referer" => address_book_url
|
59
70
|
)
|
60
71
|
|
61
72
|
if resp.code_type != Net::HTTPOK
|
62
73
|
raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
|
63
74
|
end
|
64
|
-
|
75
|
+
|
65
76
|
parse data
|
77
|
+
|
78
|
+
parse more_data
|
79
|
+
|
80
|
+
if more_data =~ /"TotalABContacts":(\d+)/
|
81
|
+
total = $1.to_i
|
82
|
+
((total / 50)).times do |i|
|
83
|
+
# now proceed with the new ".crumb" parameter to get the csv data
|
84
|
+
url = URI.parse(contact_list_url.sub("bucket=1","bucket=#{i+2}").sub("_crumb=crumb","_crumb=#{crumb}").sub("time", Time.now.to_f.to_s.sub(".","")[0...-2]))
|
85
|
+
http = open_http(url)
|
86
|
+
resp, more_data = http.get("#{url.path}?#{url.query}",
|
87
|
+
"Cookie" => @cookies,
|
88
|
+
"X-Requested-With" => "XMLHttpRequest",
|
89
|
+
"Referer" => address_book_url
|
90
|
+
)
|
91
|
+
|
92
|
+
if resp.code_type != Net::HTTPOK
|
93
|
+
raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
|
94
|
+
end
|
95
|
+
|
96
|
+
parse more_data
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
@contacts
|
66
101
|
end
|
67
102
|
end
|
68
103
|
|
69
104
|
private
|
70
105
|
|
71
106
|
def parse(data, options={})
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
107
|
+
@contacts ||= []
|
108
|
+
if data =~ /var InitialContacts = (\[.*?\])/
|
109
|
+
@contacts += JSON.parse($1).select{|contact|!contact["email"].to_s.empty?}.map{|contact|[contact["contactName"], contact["email"]]}
|
110
|
+
elsif data =~ /^\{"response":/
|
111
|
+
@contacts += JSON.parse(data)["response"]["ResultSet"]["Contacts"].to_a.select{|contact|!contact["email"].to_s.empty?}.map{|contact|[contact["contactName"], contact["email"]]}
|
112
|
+
else
|
113
|
+
@contacts
|
114
|
+
end
|
77
115
|
end
|
78
116
|
|
79
117
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: contacts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.19
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lucas Carlson
|
@@ -38,6 +38,7 @@ files:
|
|
38
38
|
- lib/contacts.rb
|
39
39
|
- lib/contacts/base.rb
|
40
40
|
- lib/contacts/gmail.rb
|
41
|
+
- lib/contacts/aol.rb
|
41
42
|
- lib/contacts/hotmail.rb
|
42
43
|
- lib/contacts/plaxo.rb
|
43
44
|
- lib/contacts/yahoo.rb
|