contacts_cn 1.2.6 → 1.2.7
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/aol.rb +26 -26
- data/lib/contacts/base.rb +20 -20
- data/lib/contacts/gmail.rb +8 -8
- data/lib/contacts/hotmail.rb +5 -5
- data/lib/contacts/json_picker.rb +1 -1
- data/lib/contacts/net_ease.rb +72 -72
- data/lib/contacts/plaxo.rb +17 -17
- data/lib/contacts/sina.rb +55 -54
- data/lib/contacts/sohu.rb +32 -32
- data/lib/contacts/yahoo.rb +24 -24
- data/lib/contacts_cn.rb +1 -1
- data/test/unit/net_ease_contact_importer_test.rb +2 -2
- data/test/unit/sina_contact_importer_test.rb +2 -2
- data/test/unit/test_accounts_test.rb +4 -4
- metadata +20 -20
data/lib/contacts/aol.rb
CHANGED
@@ -7,11 +7,11 @@ class Contacts
|
|
7
7
|
LOGIN_REFERER_URL = "http://webmail.aol.com/"
|
8
8
|
LOGIN_REFERER_PATH = "sitedomain=sns.webmail.aol.com&lang=en&locale=us&authLev=0&uitype=mini&loginId=&redirType=js&xchk=false"
|
9
9
|
AOL_NUM = "29970-343" # this seems to change each time they change the protocol
|
10
|
-
|
10
|
+
|
11
11
|
CONTACT_LIST_URL = "http://webmail.aol.com/#{AOL_NUM}/aim-2/en-us/Lite/ContactList.aspx?folder=Inbox&showUserFolders=False"
|
12
12
|
CONTACT_LIST_CSV_URL = "http://webmail.aol.com/#{AOL_NUM}/aim-2/en-us/Lite/ABExport.aspx?command=all"
|
13
13
|
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"
|
14
|
-
|
14
|
+
|
15
15
|
def real_connect
|
16
16
|
if login.strip =~ /^(.+)@aol\.com$/ # strip off the @aol.com for AOL logins
|
17
17
|
login = $1
|
@@ -47,39 +47,39 @@ class Contacts
|
|
47
47
|
"redirType" => "",
|
48
48
|
"xchk" => "false"
|
49
49
|
}
|
50
|
-
|
50
|
+
|
51
51
|
# Get this cookie and stick it in the form to confirm to Aol that your cookies work
|
52
52
|
data, resp, cookies, forward = get(URL)
|
53
53
|
postdata["stips"] = cookie_hash_from_string(cookies)["stips"]
|
54
54
|
postdata["tst"] = cookie_hash_from_string(cookies)["tst"]
|
55
|
-
|
55
|
+
|
56
56
|
data, resp, cookies, forward, old_url = get(LOGIN_REFERER_URL, cookies) + [URL]
|
57
57
|
until forward.nil?
|
58
58
|
data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
data, resp, cookies, forward, old_url = get("#{LOGIN_URL}?#{LOGIN_REFERER_PATH}", cookies) + [LOGIN_REFERER_URL]
|
62
62
|
until forward.nil?
|
63
63
|
data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
doc = Hpricot(data)
|
67
67
|
(doc/:input).each do |input|
|
68
68
|
postdata["usrd"] = input.attributes["value"] if input.attributes["name"] == "usrd"
|
69
69
|
end
|
70
70
|
# parse data for <input name="usrd" value="2726212" type="hidden"> and add it to the postdata
|
71
|
-
|
71
|
+
|
72
72
|
postdata["SNS_SC"] = cookie_hash_from_string(cookies)["SNS_SC"]
|
73
73
|
postdata["SNS_LDC"] = cookie_hash_from_string(cookies)["SNS_LDC"]
|
74
74
|
postdata["LTState"] = cookie_hash_from_string(cookies)["LTState"]
|
75
75
|
# raise data.inspect
|
76
|
-
|
76
|
+
|
77
77
|
data, resp, cookies, forward, old_url = post(LOGIN_URL, h_to_query_string(postdata), cookies, LOGIN_REFERER_URL) + [LOGIN_REFERER_URL]
|
78
|
-
|
78
|
+
|
79
79
|
until forward.nil?
|
80
80
|
data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
if data.index("Invalid Username or Password. Please try again.")
|
84
84
|
raise AuthenticationError, "Username and password do not match"
|
85
85
|
elsif data.index("Required field must not be blank")
|
@@ -91,57 +91,57 @@ class Contacts
|
|
91
91
|
elsif cookies == ""
|
92
92
|
raise ConnectionError, PROTOCOL_ERROR
|
93
93
|
end
|
94
|
-
|
94
|
+
|
95
95
|
@cookies = cookies
|
96
96
|
end
|
97
|
-
|
97
|
+
|
98
98
|
def contacts
|
99
99
|
postdata = {
|
100
100
|
"file" => 'contacts',
|
101
101
|
"fileType" => 'csv'
|
102
102
|
}
|
103
|
-
|
103
|
+
|
104
104
|
return @contacts if @contacts
|
105
105
|
if connected?
|
106
106
|
data, resp, cookies, forward, old_url = get(CONTACT_LIST_URL, @cookies, CONTACT_LIST_URL) + [CONTACT_LIST_URL]
|
107
|
-
|
107
|
+
|
108
108
|
until forward.nil?
|
109
109
|
data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
|
110
110
|
end
|
111
|
-
|
111
|
+
|
112
112
|
if resp.code_type != Net::HTTPOK
|
113
113
|
raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
|
114
114
|
end
|
115
|
-
|
115
|
+
|
116
116
|
# parse data and grab <input name="user" value="8QzMPIAKs2" type="hidden">
|
117
117
|
doc = Hpricot(data)
|
118
118
|
(doc/:input).each do |input|
|
119
119
|
postdata["user"] = input.attributes["value"] if input.attributes["name"] == "user"
|
120
120
|
end
|
121
|
-
|
121
|
+
|
122
122
|
data, resp, cookies, forward, old_url = get(CONTACT_LIST_CSV_URL, @cookies, CONTACT_LIST_URL) + [CONTACT_LIST_URL]
|
123
|
-
|
123
|
+
|
124
124
|
until forward.nil?
|
125
125
|
data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
|
126
126
|
end
|
127
|
-
|
127
|
+
|
128
128
|
if data.include?("error.gif")
|
129
129
|
raise AuthenticationError, "Account invalid"
|
130
130
|
end
|
131
|
-
|
131
|
+
|
132
132
|
parse data
|
133
133
|
end
|
134
134
|
end
|
135
|
-
|
136
|
-
|
135
|
+
private
|
136
|
+
|
137
137
|
def parse(data, options={})
|
138
138
|
data = CSV::Reader.parse(data)
|
139
139
|
col_names = data.shift
|
140
140
|
@contacts = data.map do |person|
|
141
141
|
["#{person[0]} #{person[1]}", person[4]] if person[4] && !person[4].empty?
|
142
142
|
end.compact
|
143
|
-
end
|
144
|
-
|
143
|
+
end
|
144
|
+
|
145
145
|
def h_to_query_string(hash)
|
146
146
|
u = ERB::Util.method(:u)
|
147
147
|
hash.map { |k, v|
|
@@ -149,6 +149,6 @@ class Contacts
|
|
149
149
|
}.join("&")
|
150
150
|
end
|
151
151
|
end
|
152
|
-
|
152
|
+
|
153
153
|
TYPES[:aol] = Aol
|
154
|
-
end
|
154
|
+
end
|
data/lib/contacts/base.rb
CHANGED
@@ -9,7 +9,7 @@ require "erb"
|
|
9
9
|
|
10
10
|
class Contacts
|
11
11
|
TYPES = {}
|
12
|
-
VERSION = "1.2.
|
12
|
+
VERSION = "1.2.7"
|
13
13
|
|
14
14
|
class Base
|
15
15
|
def initialize(login, password, options={})
|
@@ -36,7 +36,7 @@ class Contacts
|
|
36
36
|
url = URI.parse(contact_list_url)
|
37
37
|
http = open_http(url)
|
38
38
|
resp, data = http.get("#{url.path}?#{url.query}",
|
39
|
-
|
39
|
+
"Cookie" => @cookies
|
40
40
|
)
|
41
41
|
|
42
42
|
if resp.code_type != Net::HTTPOK
|
@@ -74,7 +74,7 @@ class Contacts
|
|
74
74
|
@password
|
75
75
|
end
|
76
76
|
|
77
|
-
|
77
|
+
private
|
78
78
|
|
79
79
|
def domain
|
80
80
|
@d ||= self.class.const_get(:DOMAIN) rescue nil
|
@@ -142,19 +142,19 @@ class Contacts
|
|
142
142
|
url = URI.parse(url)
|
143
143
|
http = open_http(url)
|
144
144
|
resp, data = http.post(url.path, postdata,
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
145
|
+
"User-Agent" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0",
|
146
|
+
"Accept-Encoding" => "gzip",
|
147
|
+
"Cookie" => cookies,
|
148
|
+
"Referer" => referer,
|
149
|
+
"Content-Type" => 'application/x-www-form-urlencoded'
|
150
150
|
)
|
151
151
|
data = uncompress(resp, data)
|
152
152
|
cookies = parse_cookies(resp.response['set-cookie'], cookies)
|
153
153
|
forward = resp.response['Location']
|
154
154
|
forward ||= (data =~ /<meta.*?url='([^']+)'/ ? CGI.unescapeHTML($1) : nil)
|
155
|
-
|
156
|
-
|
157
|
-
|
155
|
+
if (not forward.nil?) && URI.parse(forward).host.nil?
|
156
|
+
forward = url.scheme.to_s + "://" + url.host.to_s + forward
|
157
|
+
end
|
158
158
|
return data, resp, cookies, forward
|
159
159
|
end
|
160
160
|
|
@@ -162,17 +162,17 @@ class Contacts
|
|
162
162
|
url = URI.parse(url)
|
163
163
|
http = open_http(url)
|
164
164
|
resp, data = http.get("#{url.path}?#{url.query}",
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
165
|
+
"User-Agent" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0",
|
166
|
+
"Accept-Encoding" => "gzip",
|
167
|
+
"Cookie" => cookies,
|
168
|
+
"Referer" => referer
|
169
169
|
)
|
170
170
|
data = uncompress(resp, data)
|
171
171
|
cookies = parse_cookies(resp.response['set-cookie'], cookies)
|
172
172
|
forward = resp.response['Location']
|
173
|
-
|
174
|
-
|
175
|
-
|
173
|
+
if (not forward.nil?) && URI.parse(forward).host.nil?
|
174
|
+
forward = url.scheme.to_s + "://" + url.host.to_s + forward
|
175
|
+
end
|
176
176
|
return data, resp, cookies, forward
|
177
177
|
end
|
178
178
|
|
@@ -183,8 +183,8 @@ class Contacts
|
|
183
183
|
data = gz.read
|
184
184
|
gz.close
|
185
185
|
resp.response['content-encoding'] = nil
|
186
|
-
|
187
|
-
|
186
|
+
# FIXME: Not sure what Hotmail was feeding me with their 'deflate',
|
187
|
+
# but the headers definitely were not right
|
188
188
|
when 'deflate'
|
189
189
|
data = Zlib::Inflate.inflate(data)
|
190
190
|
resp.response['content-encoding'] = nil
|
data/lib/contacts/gmail.rb
CHANGED
@@ -2,20 +2,20 @@ require 'gdata'
|
|
2
2
|
|
3
3
|
class Contacts
|
4
4
|
class Gmail < Base
|
5
|
-
|
5
|
+
|
6
6
|
CONTACTS_SCOPE = 'http://www.google.com/m8/feeds/'
|
7
7
|
CONTACTS_FEED = CONTACTS_SCOPE + 'contacts/default/full/?max-results=1000'
|
8
|
-
|
8
|
+
|
9
9
|
def contacts
|
10
10
|
return @contacts if @contacts
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def real_connect
|
14
14
|
@client = GData::Client::Contacts.new
|
15
15
|
@client.clientlogin(@login, @password, @captcha_token, @captcha_response)
|
16
|
-
|
16
|
+
|
17
17
|
feed = @client.get(CONTACTS_FEED).to_xml
|
18
|
-
|
18
|
+
|
19
19
|
@contacts = feed.elements.to_a('entry').collect do |entry|
|
20
20
|
title, email = entry.elements['title'].text, nil
|
21
21
|
entry.elements.each('gd:email') do |e|
|
@@ -27,9 +27,9 @@ class Contacts
|
|
27
27
|
rescue GData::Client::AuthorizationError => e
|
28
28
|
raise AuthenticationError, "Username or password are incorrect"
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
private
|
32
|
-
|
32
|
+
|
33
33
|
TYPES[:gmail] = Gmail
|
34
34
|
end
|
35
|
-
end
|
35
|
+
end
|
data/lib/contacts/hotmail.rb
CHANGED
@@ -79,7 +79,7 @@ class Contacts
|
|
79
79
|
email_match_text_end = Regexp.escape("&")
|
80
80
|
|
81
81
|
raw_html = resp.body.split("
|
82
|
-
").grep(/(?:e|dn)lk[0-9]+/)
|
82
|
+
").grep(/(?:e|dn)lk[0-9]+/)
|
83
83
|
raw_html.inject(-1) do |memo, row|
|
84
84
|
c_info = row.match(/(e|dn)lk([0-9])+/)
|
85
85
|
|
@@ -88,10 +88,10 @@ class Contacts
|
|
88
88
|
|
89
89
|
# Grab info
|
90
90
|
case c_info[1]
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
91
|
+
when "e" # Email
|
92
|
+
build_contacts.last[1] = row.match(/#{email_match_text_beginning}(.*)#{email_match_text_end}/)[1]
|
93
|
+
when "dn" # Name
|
94
|
+
build_contacts.last[0] = row.match(/<a[^>]*>(.+)<\/a>/)[1]
|
95
95
|
end
|
96
96
|
|
97
97
|
# Set memo to contact id
|
data/lib/contacts/json_picker.rb
CHANGED
@@ -5,7 +5,7 @@ end
|
|
5
5
|
class Contacts
|
6
6
|
def self.parse_json( string )
|
7
7
|
if Object.const_defined?('ActiveSupport') and
|
8
|
-
|
8
|
+
ActiveSupport.const_defined?('JSON')
|
9
9
|
ActiveSupport::JSON.decode( string )
|
10
10
|
elsif Object.const_defined?('JSON')
|
11
11
|
JSON.parse( string )
|
data/lib/contacts/net_ease.rb
CHANGED
@@ -1,116 +1,116 @@
|
|
1
1
|
class Contacts
|
2
2
|
class NetEase < Base
|
3
|
-
|
3
|
+
URL = "http://www.163.com"
|
4
4
|
LOGIN_URL = "https://reg.163.com/logins.jsp"
|
5
5
|
LoginData = {
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
6
|
+
:url2 => {
|
7
|
+
:wy163 => 'http://mail.163.com/errorpage/err_163.htm',
|
8
|
+
:wy126 => 'http://mail.126.com/errorpage/err_126.htm',
|
9
|
+
:yeah => 'http://mail.yeah.net/errorpage/err_yeah.htm'
|
10
|
+
},
|
11
|
+
:url => {
|
12
|
+
:wy163 => 'http://entry.mail.163.com/coremail/fcg/ntesdoor2?lightweight=1&verifycookie=1&language=-1&style=-1&username=%s',
|
13
|
+
:wy126 => 'http://entry.mail.126.com/cgi/ntesdoor?hid=10010102&lightweight=1&verifycookie=1&language=0&style=-1&username=%s',
|
14
|
+
:yeah => 'http://entry.mail.yeah.net/cgi/ntesdoor?lightweight=1&verifycookie=1&style=-1&username=%s'
|
15
|
+
},
|
16
|
+
:product => {
|
17
|
+
:wy163 => 'mail163',
|
18
|
+
:wy126 => 'mail126',
|
19
|
+
:yeah => 'mailyeah'
|
20
|
+
}
|
21
21
|
}
|
22
22
|
ENTER_MAIL_URL = {
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
:wy163 => "http://entry.mail.163.com/coremail/fcg/ntesdoor2?lightweight=1&verifycookie=1&language=-1&style=-1&username=%s",
|
24
|
+
:wy126 => "http://entry.mail.126.com/cgi/ntesdoor?hid=10010102&lightweight=1&verifycookie=1&language=0&style=-1&username=%s",
|
25
|
+
:yeah => "http://entry.mail.yeah.net/cgi/ntesdoor?lightweight=1&verifycookie=1&style=-1&username=%s"
|
26
26
|
}
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
CONTACT_LIST_URL = "%ss?sid=%s&func=global:sequential"
|
29
|
+
PROTOCOL_ERROR = "netease has changed its protocols, please upgrade this library first. you can also contact kamechb@gmail.com"
|
30
30
|
|
31
31
|
def initialize(login, password, options={})
|
32
|
-
|
33
|
-
|
32
|
+
@mail_type = get_mail_type(login)
|
33
|
+
super(login,password,options)
|
34
34
|
end
|
35
35
|
|
36
36
|
def real_connect
|
37
|
-
|
38
|
-
|
37
|
+
login_for_cookies
|
38
|
+
enter_mail_server
|
39
39
|
end
|
40
40
|
|
41
41
|
def contacts
|
42
|
-
|
42
|
+
return @contacts if @contacts
|
43
43
|
if connected?
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
44
|
+
url = URI.parse(CONTACT_LIST_URL % [@mail_server,@sid])
|
45
|
+
http = open_http(url)
|
46
|
+
postdata = '<?xml version="1.0"?><object><array name="items"><object><string name="func">pab:searchContacts</string><object name="var"><array name="order"><object><string name="field">FN</string><boolean name="ignoreCase">true</boolean></object></array></object></object><object><string name="func">user:getSignatures</string></object><object><string name="func">pab:getAllGroups</string></object></array></object>'
|
47
|
+
set_header = {"Cookie" => @cookies,'Accept' => 'text/javascript','Content-Type' => 'application/xml; charset=UTF-8'}
|
48
|
+
resp, data = http.post("#{url.path}?#{url.query}",postdata,set_header)
|
49
|
+
if resp.code_type != Net::HTTPOK
|
50
50
|
raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
|
51
51
|
end
|
52
|
-
|
52
|
+
parse(data)
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
56
|
private
|
57
57
|
|
58
58
|
def get_mail_type(username)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
59
|
+
if username.include?("@126.com")
|
60
|
+
:wy126
|
61
|
+
elsif username.include?("@163.com")
|
62
|
+
:wy163
|
63
|
+
elsif username.include?("@yeah.net")
|
64
|
+
:yeah
|
65
|
+
else
|
66
|
+
raise MailServerError, "there are only three mail servers that 126.com, 163.com and yeah.net. please add domain after username"
|
67
|
+
end
|
68
68
|
end
|
69
69
|
|
70
70
|
def parse(data)
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
71
|
+
json_data = Contacts.parse_json(data)
|
72
|
+
json_data['var'][0]['var'].map{|contactor|
|
73
|
+
[contactor['FN'],contactor['EMAIL;PREF']]
|
74
|
+
}
|
75
75
|
end
|
76
76
|
|
77
77
|
def login_for_cookies
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
78
|
+
data = {
|
79
|
+
:type => '1',
|
80
|
+
:url => LoginData[:url][@mail_type],
|
81
|
+
:username => @login,
|
82
|
+
:password => @password,
|
83
|
+
:selType => '-1',
|
84
|
+
:remUser => '1',
|
85
|
+
:secure => 'on',
|
86
|
+
:verifycookie => '1',
|
87
|
+
:style => '-1',
|
88
|
+
:product => LoginData[:product][@mail_type],
|
89
|
+
:savelogin => '',
|
90
|
+
:url2 => LoginData[:url2][@mail_type]
|
91
91
|
}
|
92
92
|
postdata = data.to_query_string
|
93
93
|
#login and get cookie
|
94
94
|
data, resp, cookies, forward = post(LOGIN_URL,postdata)
|
95
95
|
@cookies = cookies
|
96
96
|
if data.index(LoginData[:url2][@mail_type])
|
97
|
-
|
97
|
+
raise AuthenticationError, "Username or password error"
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
101
|
def enter_mail_server
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
102
|
+
#get mail server and sid
|
103
|
+
enter_mail_url = ENTER_MAIL_URL[@mail_type] % @login
|
104
|
+
data, resp, cookies, forward = get(enter_mail_url,@cookies)
|
105
|
+
location = resp['Location']
|
106
|
+
data_reg = /<a.*?(http.*?)main.jsp\?sid=(.*?)\">/
|
107
|
+
location_reg = /(http.*?)main.jsp\?sid=(.*)/
|
108
|
+
unless data.match(data_reg) || location.match(location_reg)
|
109
|
+
raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
|
110
|
+
end
|
111
|
+
@cookies = cookies
|
112
|
+
@mail_server = $1
|
113
|
+
@sid = $2
|
114
114
|
end
|
115
115
|
TYPES[:net_ease] = NetEase
|
116
116
|
end
|
data/lib/contacts/plaxo.rb
CHANGED
@@ -7,28 +7,28 @@ class Contacts
|
|
7
7
|
ADDRESS_BOOK_URL = "http://www.plaxo.com/po3/?module=ab&operation=viewFull&mode=normal"
|
8
8
|
CONTACT_LIST_URL = "http://www.plaxo.com/axis/soap/contact?_action=getContacts&_format=xml"
|
9
9
|
PROTOCOL_ERROR = "Plaxo 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
|
-
|
10
|
+
|
11
11
|
def real_connect
|
12
|
-
|
12
|
+
|
13
13
|
end # real_connect
|
14
|
-
|
14
|
+
|
15
15
|
def contacts
|
16
16
|
getdata = "&authInfo.authByEmail.email=%s" % CGI.escape(login)
|
17
17
|
getdata += "&authInfo.authByEmail.password=%s" % CGI.escape(password)
|
18
18
|
data, resp, cookies, forward = get(CONTACT_LIST_URL + getdata)
|
19
|
-
|
19
|
+
|
20
20
|
if resp.code_type != Net::HTTPOK
|
21
21
|
raise ConnectionError, PROTOCOL_ERROR
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
parse data
|
25
25
|
end # contacts
|
26
|
-
|
27
|
-
|
26
|
+
|
27
|
+
private
|
28
28
|
def parse(data, options={})
|
29
29
|
doc = REXML::Document.new(data)
|
30
30
|
code = doc.elements['//response/code'].text
|
31
|
-
|
31
|
+
|
32
32
|
if code == '401'
|
33
33
|
raise AuthenticationError, "Username and password do not match"
|
34
34
|
elsif code == '200'
|
@@ -50,13 +50,13 @@ class Contacts
|
|
50
50
|
else
|
51
51
|
raise ConnectionError, PROTOCOL_ERROR
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
end # parse
|
55
55
|
|
56
56
|
end # Plaxo
|
57
|
-
|
57
|
+
|
58
58
|
TYPES[:plaxo] = Plaxo
|
59
|
-
|
59
|
+
|
60
60
|
end # Contacts
|
61
61
|
|
62
62
|
|
@@ -96,7 +96,7 @@ Success
|
|
96
96
|
<message>OK</message>
|
97
97
|
<userId>77311236242</userId>
|
98
98
|
</response>
|
99
|
-
|
99
|
+
|
100
100
|
<contacts>
|
101
101
|
|
102
102
|
<contact>
|
@@ -109,7 +109,7 @@ Success
|
|
109
109
|
<email1>joeblow1@mailinator.com</email1>
|
110
110
|
<folderId>5291351</folderId>
|
111
111
|
</contact>
|
112
|
-
|
112
|
+
|
113
113
|
<contact>
|
114
114
|
<itemId>61313159</itemId>
|
115
115
|
<displayName>Joe Blow2</displayName>
|
@@ -120,11 +120,11 @@ Success
|
|
120
120
|
<email1>joeblow2@mailinator.com</email1>
|
121
121
|
<folderId>5291351</folderId>
|
122
122
|
</contact>
|
123
|
-
|
123
|
+
|
124
124
|
</contacts>
|
125
|
-
|
125
|
+
|
126
126
|
<totalCount>2</totalCount>
|
127
127
|
<editCounter>3</editCounter>
|
128
|
-
|
128
|
+
|
129
129
|
</ns1:GetContactsResponse>
|
130
|
-
=end
|
130
|
+
=end
|
data/lib/contacts/sina.rb
CHANGED
@@ -1,35 +1,35 @@
|
|
1
1
|
class Contacts
|
2
2
|
class Sina < Base
|
3
|
-
|
3
|
+
URL = "http://mail.sina.com.cn"
|
4
4
|
LOGIN_URL = {
|
5
|
-
|
6
|
-
|
5
|
+
:sina_cn => "https://mail.sina.com.cn/cgi-bin/cnlogin.php",
|
6
|
+
:sina_com => "https://mail.sina.com.cn/cgi-bin/login.php"
|
7
7
|
}
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
8
|
+
LOGIN_COOKIE = {
|
9
|
+
:sina_cn => "sina_cn_mail_id=nonobo_t; sina_cn_mail_recid=true",
|
10
|
+
:sina_com => "sina_free_mail_id=fangs2; sina_free_mail_recid=true; sina_free_mail_ltype=uid; sina_vip_mail_recid=false"
|
11
|
+
}
|
12
|
+
DOMAIN = {
|
13
|
+
:sina_cn => 'sina.cn',
|
14
|
+
:sina_com => 'sina.com'
|
15
|
+
}
|
16
|
+
PROTOCOL_ERROR = "sina has changed its protocols, please upgrade this library first. you can also contact kamechb@gmail.com"
|
17
17
|
|
18
18
|
def initialize(login, password, options={})
|
19
|
-
|
20
|
-
|
19
|
+
@mail_type = get_mail_type(login)
|
20
|
+
super(login,password,options)
|
21
21
|
end
|
22
22
|
|
23
23
|
def real_connect
|
24
|
-
|
25
|
-
|
24
|
+
login_for_cookies
|
25
|
+
redirect_for_location
|
26
26
|
end
|
27
27
|
|
28
28
|
def contacts
|
29
|
-
|
29
|
+
return @contacts if @contacts
|
30
30
|
if connected?
|
31
|
-
|
32
|
-
|
31
|
+
data, resp, cookies, forward = get(@mail_url,@cookies)
|
32
|
+
if resp.code_type != Net::HTTPOK
|
33
33
|
raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
|
34
34
|
end
|
35
35
|
parse(data)
|
@@ -39,50 +39,51 @@ class Contacts
|
|
39
39
|
private
|
40
40
|
|
41
41
|
def get_mail_type(username)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
42
|
+
if username.include?("@sina.com")
|
43
|
+
:sina_com
|
44
|
+
elsif username.include?("@sina.cn")
|
45
|
+
:sina_cn
|
46
|
+
else
|
47
|
+
raise MailServerError, "there are only two mail servers that sina.com and sina.cn. please add domain after username"
|
48
|
+
end
|
49
49
|
end
|
50
50
|
|
51
51
|
def parse(data)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
52
|
+
#data =~ /conf.*?contacts:.*?(\{.*?\}),\s*groups:/m
|
53
|
+
data =~ /conf.*?contacts.*?(\{.*\}).*?groups/m
|
54
|
+
contacts = $1.gsub(""",'')
|
55
|
+
contacts = ActiveSupport::JSON.decode(contacts)
|
56
|
+
contacts['contact'].map{|contactor|
|
57
|
+
[contactor['name'],contactor['email']]
|
58
|
+
}
|
58
59
|
end
|
59
60
|
|
60
61
|
def login_for_cookies
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
62
|
+
data = {
|
63
|
+
:domain => DOMAIN[@mail_type],
|
64
|
+
:logintype => 'uid',
|
65
|
+
:u => @login,
|
66
|
+
:psw => @password,
|
67
|
+
:savelogin => 'on',
|
68
|
+
:sshchk => 'on',
|
69
|
+
:ssl => 'on'
|
70
|
+
}
|
71
|
+
data, resp, cookies, forward = post(LOGIN_URL[@mail_type],data.to_query_string,LOGIN_COOKIE[@mail_type])
|
72
|
+
login_faile_flag = %r{form.*?action.*?http.*?mail.sina.com.cn/cgi-bin/.*?login.php}m
|
73
|
+
if data.match(login_faile_flag)
|
74
|
+
raise AuthenticationError, "Username or password error"
|
75
|
+
end
|
76
|
+
data.match(/URL=(http:\/\/.*?)'>/)
|
77
|
+
@redirect_url = $1
|
78
|
+
@mail_server = @redirect_url.match(/(http:\/\/.*\..*?)\//)
|
79
|
+
@cookies = cookies
|
79
80
|
end
|
80
81
|
|
81
82
|
def redirect_for_location
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
83
|
+
data, resp, cookies, forward = get(@redirect_url,@cookies)
|
84
|
+
location = resp['Location']
|
85
|
+
@mail_url = location.index("http://") ? location : "#{@mail_server}#{location}"
|
86
|
+
@cookies = cookies
|
86
87
|
end
|
87
88
|
|
88
89
|
TYPES[:sina] = Sina
|
data/lib/contacts/sohu.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
class Contacts
|
2
2
|
class Sohu < Base
|
3
|
-
|
4
|
-
|
3
|
+
URL = "http://mail.sohu.com"
|
4
|
+
DOMAIN = "sohu.com"
|
5
5
|
LOGIN_URL = "https://passport.sohu.com/sso/login.jsp"
|
6
6
|
LOGIN_COOKIE = "IPLOC=CN3301; SUV=1008301317090277"
|
7
|
-
|
8
|
-
|
7
|
+
MAIL_URL = "http://mail.sohu.com/bapp/81/main"
|
8
|
+
PROTOCOL_ERROR = "sohu has changed its protocols, please upgrade this library first. you can also contact kamechb@gmail.com"
|
9
9
|
|
10
10
|
def real_connect
|
11
|
-
|
11
|
+
login_for_cookies
|
12
12
|
end
|
13
13
|
|
14
14
|
def contacts
|
15
|
-
|
15
|
+
return @contacts if @contacts
|
16
16
|
if connected?
|
17
|
-
|
18
|
-
|
17
|
+
data, resp, cookies, forward = get(MAIL_URL,@cookies)
|
18
|
+
if resp.code_type != Net::HTTPOK
|
19
19
|
raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
|
20
20
|
end
|
21
21
|
parse(data)
|
@@ -26,32 +26,32 @@ class Contacts
|
|
26
26
|
|
27
27
|
|
28
28
|
def parse(data)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
data.match(/ADDRESSES.*?'(\{.*?\})';/m)
|
30
|
+
contacts = ActiveSupport::JSON.decode($1)
|
31
|
+
contacts['contact'].map{|contactor|
|
32
|
+
[contactor['nickname'],contactor['email']]
|
33
|
+
}
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
36
|
+
def login_for_cookies
|
37
|
+
data = {
|
38
|
+
:userid => @login,
|
39
|
+
:password => @password,
|
40
|
+
:appid => '1000',
|
41
|
+
:persistentcookie => '0',
|
42
|
+
:s => '1283173792650',
|
43
|
+
:b => '2',
|
44
|
+
:w => '1280',
|
45
|
+
:pwdtype => '0',
|
46
|
+
:v => '26'
|
47
|
+
}
|
48
|
+
data, resp, cookies, forward = get("#{LOGIN_URL}?#{data.to_query_string}",LOGIN_COOKIE)
|
49
|
+
login_faile_flag = %r{login_status.*?error}
|
50
|
+
if data.match(login_faile_flag)
|
51
|
+
raise AuthenticationError, "Username or password error"
|
52
|
+
end
|
53
|
+
@cookies = cookies
|
54
|
+
end
|
55
55
|
|
56
56
|
TYPES[:sohu] = Sohu
|
57
57
|
end
|
data/lib/contacts/yahoo.rb
CHANGED
@@ -5,15 +5,15 @@ class Contacts
|
|
5
5
|
ADDRESS_BOOK_URL = "http://address.mail.yahoo.com/?.rand=430244936"
|
6
6
|
CONTACT_LIST_URL = "http://address.mail.yahoo.com/?_src=&_crumb=crumb&sortfield=3&bucket=1&scroll=1&VPC=social_list&.r=time"
|
7
7
|
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"
|
8
|
-
|
9
|
-
def real_connect
|
8
|
+
|
9
|
+
def real_connect
|
10
10
|
postdata = ".tries=2&.src=ym&.md5=&.hash=&.js=&.last=&promo=&.intl=us&.bypass="
|
11
11
|
postdata += "&.partner=&.u=4eo6isd23l8r3&.v=0&.challenge=gsMsEcoZP7km3N3NeI4mX"
|
12
12
|
postdata += "kGB7zMV&.yplus=&.emailCode=&pkg=&stepid=&.ev=&hasMsgr=1&.chkP=Y&."
|
13
13
|
postdata += "done=#{CGI.escape(URL)}&login=#{CGI.escape(login)}&passwd=#{CGI.escape(password)}"
|
14
|
-
|
14
|
+
|
15
15
|
data, resp, cookies, forward = post(LOGIN_URL, postdata)
|
16
|
-
|
16
|
+
|
17
17
|
if data.index("Invalid ID or password") || data.index("This ID is not yet taken")
|
18
18
|
raise AuthenticationError, "Username and password do not match"
|
19
19
|
elsif data.index("Sign in") && data.index("to Yahoo!")
|
@@ -23,24 +23,24 @@ class Contacts
|
|
23
23
|
elsif cookies == ""
|
24
24
|
raise ConnectionError, PROTOCOL_ERROR
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
data, resp, cookies, forward = get(forward, cookies, LOGIN_URL)
|
28
|
-
|
28
|
+
|
29
29
|
if resp.code_type != Net::HTTPOK
|
30
30
|
raise ConnectionError, PROTOCOL_ERROR
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
@cookies = cookies
|
34
34
|
end
|
35
|
-
|
36
|
-
def contacts
|
35
|
+
|
36
|
+
def contacts
|
37
37
|
return @contacts if @contacts
|
38
38
|
if connected?
|
39
39
|
# first, get the addressbook site with the new crumb parameter
|
40
40
|
url = URI.parse(address_book_url)
|
41
41
|
http = open_http(url)
|
42
42
|
resp, data = http.get("#{url.path}?#{url.query}",
|
43
|
-
|
43
|
+
"Cookie" => @cookies
|
44
44
|
)
|
45
45
|
|
46
46
|
if resp.code_type != Net::HTTPOK
|
@@ -53,15 +53,15 @@ class Contacts
|
|
53
53
|
url = URI.parse(contact_list_url.sub("_crumb=crumb","_crumb=#{crumb}").sub("time", Time.now.to_f.to_s.sub(".","")[0...-2]))
|
54
54
|
http = open_http(url)
|
55
55
|
resp, more_data = http.get("#{url.path}?#{url.query}",
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
"Cookie" => @cookies,
|
57
|
+
"X-Requested-With" => "XMLHttpRequest",
|
58
|
+
"Referer" => address_book_url
|
59
59
|
)
|
60
60
|
|
61
61
|
if resp.code_type != Net::HTTPOK
|
62
|
-
|
62
|
+
raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
if more_data =~ /"TotalABContacts":(\d+)/
|
66
66
|
total = $1.to_i
|
67
67
|
((total / 50.0).ceil).times do |i|
|
@@ -69,25 +69,25 @@ class Contacts
|
|
69
69
|
url = URI.parse(contact_list_url.sub("bucket=1","bucket=#{i}").sub("_crumb=crumb","_crumb=#{crumb}").sub("time", Time.now.to_f.to_s.sub(".","")[0...-2]))
|
70
70
|
http = open_http(url)
|
71
71
|
resp, more_data = http.get("#{url.path}?#{url.query}",
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
"Cookie" => @cookies,
|
73
|
+
"X-Requested-With" => "XMLHttpRequest",
|
74
|
+
"Referer" => address_book_url
|
75
75
|
)
|
76
76
|
|
77
77
|
if resp.code_type != Net::HTTPOK
|
78
|
-
|
78
|
+
raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
|
79
79
|
end
|
80
80
|
|
81
81
|
parse more_data
|
82
82
|
end
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
@contacts
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
|
-
|
90
|
-
|
89
|
+
private
|
90
|
+
|
91
91
|
def parse(data, options={})
|
92
92
|
@contacts ||= []
|
93
93
|
@contacts += Contacts.parse_json(data)["response"]["ResultSet"]["Contacts"].to_a.select{|contact|!contact["email"].to_s.empty?}.map do |contact|
|
@@ -96,8 +96,8 @@ class Contacts
|
|
96
96
|
end if data =~ /^\{"response":/
|
97
97
|
@contacts
|
98
98
|
end
|
99
|
-
|
99
|
+
|
100
100
|
end
|
101
101
|
|
102
102
|
TYPES[:yahoo] = Yahoo
|
103
|
-
end
|
103
|
+
end
|
data/lib/contacts_cn.rb
CHANGED
@@ -4,20 +4,20 @@ require "#{dir}/../test_helper"
|
|
4
4
|
class TestAccountsTest < ContactImporterTestCase
|
5
5
|
def test_test_accounts_loads_data_from_example_accounts_file
|
6
6
|
account = TestAccounts.load(File.dirname(__FILE__) + "/../example_accounts.yml")[:gmail]
|
7
|
-
|
7
|
+
|
8
8
|
assert_equal :gmail, account.type
|
9
9
|
assert_equal "<changeme>", account.username
|
10
10
|
assert_equal "<changeme>", account.password
|
11
11
|
assert_equal [["FirstName1 LastName1", "firstname1@example.com"], ["FirstName2 LastName2", "firstname2@example.com"]], account.contacts
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def test_test_accounts_blows_up_if_file_doesnt_exist
|
15
15
|
assert_raise(RuntimeError) do
|
16
16
|
TestAccounts.load("file_that_does_not_exist.yml")
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def test_we_can_load_from_account_file
|
21
21
|
assert_not_nil TestAccounts[:gmail].username
|
22
22
|
end
|
23
|
-
end
|
23
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: contacts_cn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 17
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 1.2.
|
9
|
+
- 7
|
10
|
+
version: 1.2.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Lucas Carlson
|
@@ -16,7 +16,7 @@ autorequire: contacts
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2011-
|
19
|
+
date: 2011-12-19 00:00:00 +08:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -62,32 +62,32 @@ extensions: []
|
|
62
62
|
extra_rdoc_files: []
|
63
63
|
|
64
64
|
files:
|
65
|
-
- lib/
|
66
|
-
- lib/contacts/
|
65
|
+
- lib/contacts_cn.rb
|
66
|
+
- lib/contacts/base.rb
|
67
|
+
- lib/contacts/json_picker.rb
|
68
|
+
- lib/contacts/gmail.rb
|
67
69
|
- lib/contacts/sina.rb
|
68
70
|
- lib/contacts/plaxo.rb
|
69
|
-
- lib/contacts/aol.rb
|
70
|
-
- lib/contacts/gmail.rb
|
71
|
-
- lib/contacts/base.rb
|
72
71
|
- lib/contacts/net_ease.rb
|
72
|
+
- lib/contacts/aol.rb
|
73
|
+
- lib/contacts/hash_ext.rb
|
73
74
|
- lib/contacts/hotmail.rb
|
74
|
-
- lib/contacts/
|
75
|
+
- lib/contacts/yahoo.rb
|
75
76
|
- lib/contacts/sohu.rb
|
76
|
-
- lib/contacts_cn.rb
|
77
|
-
- test/example_accounts.yml
|
78
77
|
- test/test_helper.rb
|
79
|
-
- test/
|
80
|
-
- test/unit/hotmail_contact_importer_test.rb
|
78
|
+
- test/unit/gmail_contact_importer_test.rb
|
81
79
|
- test/unit/aol_contact_importer_test.rb
|
82
|
-
- test/unit/sina_contact_importer_test.rb
|
83
|
-
- test/unit/test_accounts_test.rb
|
84
80
|
- test/unit/sohu_contact_importer_test.rb
|
85
81
|
- test/unit/net_ease_contact_importer_test.rb
|
82
|
+
- test/unit/sina_contact_importer_test.rb
|
86
83
|
- test/unit/yahoo_csv_contact_importer_test.rb
|
87
|
-
- test/unit/
|
84
|
+
- test/unit/hotmail_contact_importer_test.rb
|
85
|
+
- test/unit/test_accounts_test.rb
|
86
|
+
- test/example_accounts.yml
|
87
|
+
- test/test_suite.rb
|
88
|
+
- README
|
88
89
|
- Rakefile
|
89
90
|
- LICENSE
|
90
|
-
- README
|
91
91
|
- examples/grab_contacts.rb
|
92
92
|
has_rdoc: true
|
93
93
|
homepage: http://rubyforge.org/projects/contacts
|
@@ -119,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
119
|
requirements:
|
120
120
|
- A json parser, the gdata ruby gem
|
121
121
|
rubyforge_project:
|
122
|
-
rubygems_version: 1.
|
122
|
+
rubygems_version: 1.6.2
|
123
123
|
signing_key:
|
124
124
|
specification_version: 3
|
125
125
|
summary: A universal interface to grab contact list information from various providers including Yahoo, AOL, Gmail, Hotmail, 126, 163, Yeah, Sohu, Sina and Plaxo.It is extended from contacts gem.
|