]*>(.+)<\/a>/)[1]
end
@@ -105,7 +159,7 @@ def contacts(options = {})
build_contacts.each do |contact|
unless contact[1].nil?
# Only return contacts with email addresses
- contact[1] = CGI::unescape(contact[1])
+ contact[1] = CGI::unescape CGI::unescape(contact[1])
@contacts << contact
end
end
@@ -122,4 +176,4 @@ def get_contact_list_url(index)
TYPES[:hotmail] = Hotmail
end
-end
\ No newline at end of file
+end
diff --git a/lib/contacts/json_picker.rb b/lib/contacts/json_picker.rb
index 6149b62..c935f61 100644
--- a/lib/contacts/json_picker.rb
+++ b/lib/contacts/json_picker.rb
@@ -4,8 +4,7 @@
class Contacts
def self.parse_json( string )
- if Object.const_defined?('ActiveSupport') and
- ActiveSupport.const_defined?('JSON')
+ if Object.const_defined?('ActiveSupport') and ActiveSupport.const_defined?('JSON')
ActiveSupport::JSON.decode( string )
elsif Object.const_defined?('JSON')
JSON.parse( string )
@@ -13,4 +12,4 @@ def self.parse_json( string )
raise 'Contacts requires JSON or Rails (with ActiveSupport::JSON)'
end
end
-end
\ No newline at end of file
+end
diff --git a/lib/contacts/plaxo.rb b/lib/contacts/plaxo.rb
index e86e51a..8fa6df5 100644
--- a/lib/contacts/plaxo.rb
+++ b/lib/contacts/plaxo.rb
@@ -24,6 +24,18 @@ def contacts
parse data
end # contacts
+ def contacts_data
+ getdata = "&authInfo.authByEmail.email=%s" % CGI.escape(login)
+ getdata += "&authInfo.authByEmail.password=%s" % CGI.escape(password)
+ data, resp, cookies, forward = get(CONTACT_LIST_URL + getdata)
+
+ if resp.code_type != Net::HTTPOK
+ raise ConnectionError, PROTOCOL_ERROR
+ end
+
+ data
+ end
+
private
def parse(data, options={})
doc = REXML::Document.new(data)
@@ -39,14 +51,16 @@ def parse(data, options={})
elsif cont.elements['displayName']
cont.elements['displayName'].text
end
- email = if cont.elements['email1']
- cont.elements['email1'].text
- end
- if name || email
- @contacts << [name, email]
+ i = 1
+ emails = []
+ while (cont.elements["email#{i}"] || cont.elements["workEmail#{i}"])
+ emails << cont.elements["email#{i}"].text if cont.elements["email#{i}"]
+ emails << cont.elements["workEmail#{i}"].text if cont.elements["workEmail#{i}"]
+ i += 1
end
+ emails.each {|email| @contacts << [name, email] }
end
- @contacts
+ @contacts.uniq {|a,b| b}
else
raise ConnectionError, PROTOCOL_ERROR
end
@@ -127,4 +141,4 @@ def parse(data, options={})
3
-=end
\ No newline at end of file
+=end
diff --git a/lib/contacts/yahoo.rb b/lib/contacts/yahoo.rb
index 5b27d36..22cac0b 100644
--- a/lib/contacts/yahoo.rb
+++ b/lib/contacts/yahoo.rb
@@ -5,17 +5,24 @@ class Yahoo < Base
ADDRESS_BOOK_URL = "http://address.mail.yahoo.com/?.rand=430244936"
CONTACT_LIST_URL = "http://address.mail.yahoo.com/?_src=&_crumb=crumb&sortfield=3&bucket=1&scroll=1&VPC=social_list&.r=time"
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"
-
- def real_connect
+ INVALID_PASS = 'Invalid ID or password.
Please try again using your full Yahoo! ID.
'
+ NOT_YET_TAKEN = 'This ID is not yet taken.
Are you trying to '
+
+ def real_connect(attempt_count=0)
postdata = ".tries=2&.src=ym&.md5=&.hash=&.js=&.last=&promo=&.intl=us&.bypass="
postdata += "&.partner=&.u=4eo6isd23l8r3&.v=0&.challenge=gsMsEcoZP7km3N3NeI4mX"
postdata += "kGB7zMV&.yplus=&.emailCode=&pkg=&stepid=&.ev=&hasMsgr=1&.chkP=Y&."
postdata += "done=#{CGI.escape(URL)}&login=#{CGI.escape(login)}&passwd=#{CGI.escape(password)}"
-
+
data, resp, cookies, forward = post(LOGIN_URL, postdata)
-
- if data.index("Invalid ID or password") || data.index("This ID is not yet taken")
- raise AuthenticationError, "Username and password do not match"
+
+ if data.index(INVALID_PASS) || data.index(NOT_YET_TAKEN)
+ if attempt_count < 1
+ sleep(5)
+ return real_connect(attempt_count + 1)
+ else
+ raise AuthenticationError, "Username and password do not match"
+ end
elsif data.index("Sign in") && data.index("to Yahoo!")
raise AuthenticationError, "Required field must not be blank"
elsif !data.match(/uncompressed\/chunked/)
@@ -23,20 +30,50 @@ def real_connect
elsif cookies == ""
raise ConnectionError, PROTOCOL_ERROR
end
-
+
data, resp, cookies, forward = get(forward, cookies, LOGIN_URL)
-
+
if resp.code_type != Net::HTTPOK
raise ConnectionError, PROTOCOL_ERROR
end
-
+
@cookies = cookies
end
+
+ def contacts_data
+ if connected?
+ # first, get the addressbook site with the new crumb parameter
+ url = URI.parse(address_book_url)
+ http = open_http(url)
+ resp, data = http.get("#{url.path}?#{url.query}",
+ "Cookie" => @cookies
+ )
- def contacts
+ if resp.code_type != Net::HTTPOK
+ raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
+ end
+
+ crumb = data.to_s[/dotCrumb: '(.*?)'/][13...-1]
+
+ # now proceed with the new ".crumb" parameter to get the csv data
+ url = URI.parse(contact_list_url.sub("_crumb=crumb","_crumb=#{crumb}").sub("time", Time.now.to_f.to_s.sub(".","")[0...-2]))
+ http = open_http(url)
+ resp, more_data = http.get("#{url.path}?#{url.query}",
+ "Cookie" => @cookies,
+ "X-Requested-With" => "XMLHttpRequest",
+ "Referer" => address_book_url
+ )
+
+ if resp.code_type != Net::HTTPOK
+ raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
+ end
+
+ [data, more_data]
+ end
+ end
+
+ def contacts
return @contacts if @contacts
- @contacts = []
-
if connected?
# first, get the addressbook site with the new crumb parameter
url = URI.parse(address_book_url)
@@ -63,12 +100,16 @@ def contacts
if resp.code_type != Net::HTTPOK
raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
end
-
+
+ parse data
+
+ parse more_data
+
if more_data =~ /"TotalABContacts":(\d+)/
total = $1.to_i
- ((total / 50.0).ceil).times do |i|
+ ((total / 50)).times do |i|
# now proceed with the new ".crumb" parameter to get the csv data
- 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]))
+ url = URI.parse(contact_list_url.sub("bucket=1","bucket=#{i+1}").sub("_crumb=crumb","_crumb=#{crumb}").sub("time", Time.now.to_f.to_s.sub(".","")[0...-2]))
http = open_http(url)
resp, more_data = http.get("#{url.path}?#{url.query}",
"Cookie" => @cookies,
@@ -79,26 +120,28 @@ def contacts
if resp.code_type != Net::HTTPOK
raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
end
-
+
parse more_data
end
end
-
- @contacts
+ # eliminate dupe emails
+ @contacts = @contacts.uniq {|a,b| b}
end
end
private
-
+
def parse(data, options={})
@contacts ||= []
- @contacts += Contacts.parse_json(data)["response"]["ResultSet"]["Contacts"].to_a.select{|contact|!contact["email"].to_s.empty?}.map do |contact|
- name = contact["contactName"].split(",")
- [[name.pop, name.join(",")].join(" ").strip, contact["email"]]
- end if data =~ /^\{"response":/
- @contacts
+ if data =~ /var InitialContacts = (\[.*?\]);/
+ @contacts += Contacts.parse_json($1).select{|contact|!contact["email"].to_s.empty?}.map{|contact|[contact["contactName"], contact["email"]]}
+ elsif data =~ /^\{"response":/
+ @contacts += Contacts.parse_json(data)["response"]["ResultSet"]["Contacts"].to_a.select{|contact|!contact["email"].to_s.empty?}.map{|contact|[contact["contactName"], contact["email"]]}
+ else
+ @contacts
+ end
end
-
+
end
TYPES[:yahoo] = Yahoo