foco-contacts 1.2.18

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.
@@ -0,0 +1,130 @@
1
+ require 'rexml/document'
2
+
3
+ class Contacts
4
+ class Plaxo < Base
5
+ URL = "http://www.plaxo.com/"
6
+ LOGIN_URL = "https://www.plaxo.com/signin"
7
+ ADDRESS_BOOK_URL = "http://www.plaxo.com/po3/?module=ab&operation=viewFull&mode=normal"
8
+ CONTACT_LIST_URL = "http://www.plaxo.com/axis/soap/contact?_action=getContacts&_format=xml"
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
+
11
+ def real_connect
12
+
13
+ end # real_connect
14
+
15
+ def contacts
16
+ getdata = "&authInfo.authByEmail.email=%s" % CGI.escape(login)
17
+ getdata += "&authInfo.authByEmail.password=%s" % CGI.escape(password)
18
+ data, resp, cookies, forward = get(CONTACT_LIST_URL + getdata)
19
+
20
+ if resp.code_type != Net::HTTPOK
21
+ raise ConnectionError, PROTOCOL_ERROR
22
+ end
23
+
24
+ parse data
25
+ end # contacts
26
+
27
+ private
28
+ def parse(data, options={})
29
+ doc = REXML::Document.new(data)
30
+ code = doc.elements['//response/code'].text
31
+
32
+ if code == '401'
33
+ raise AuthenticationError, "Username and password do not match"
34
+ elsif code == '200'
35
+ @contacts = []
36
+ doc.elements.each('//contact') do |cont|
37
+ name = if cont.elements['fullName']
38
+ cont.elements['fullName'].text
39
+ elsif cont.elements['displayName']
40
+ cont.elements['displayName'].text
41
+ end
42
+ email = if cont.elements['email1']
43
+ cont.elements['email1'].text
44
+ end
45
+ if name || email
46
+ @contacts << [name, email]
47
+ end
48
+ end
49
+ @contacts
50
+ else
51
+ raise ConnectionError, PROTOCOL_ERROR
52
+ end
53
+
54
+ end # parse
55
+
56
+ end # Plaxo
57
+
58
+ TYPES[:plaxo] = Plaxo
59
+
60
+ end # Contacts
61
+
62
+
63
+ # sample contacts responses
64
+ =begin
65
+ Bad email
66
+ =========
67
+ <?xml version="1.0" encoding="utf-8" ?>
68
+ <ns1:GetContactsResponse xmlns:ns1="Plaxo">
69
+ <response>
70
+ <code>401</code>
71
+ <subCode>1</subCode>
72
+ <message>User not found.</message>
73
+ </response>
74
+ </ns1:GetContactsResponse>
75
+
76
+
77
+ Bad password
78
+ ============
79
+ <?xml version="1.0" encoding="utf-8" ?>
80
+ <ns1:GetContactsResponse xmlns:ns1="Plaxo">
81
+ <response>
82
+ <code>401</code>
83
+ <subCode>4</subCode>
84
+ <message>Bad password or security token.</message>
85
+ </response>
86
+ </ns1:GetContactsResponse>
87
+
88
+
89
+ Success
90
+ =======
91
+ <?xml version="1.0" encoding="utf-8" ?>
92
+ <ns1:GetContactsResponse xmlns:ns1="Plaxo">
93
+
94
+ <response>
95
+ <code>200</code>
96
+ <message>OK</message>
97
+ <userId>77311236242</userId>
98
+ </response>
99
+
100
+ <contacts>
101
+
102
+ <contact>
103
+ <itemId>61312569</itemId>
104
+ <displayName>Joe Blow1</displayName>
105
+ <fullName>Joe Blow1</fullName>
106
+ <firstName>Joe</firstName>
107
+ <lastName>Blow1</lastName>
108
+ <homeEmail1>joeblow1@mailinator.com</homeEmail1>
109
+ <email1>joeblow1@mailinator.com</email1>
110
+ <folderId>5291351</folderId>
111
+ </contact>
112
+
113
+ <contact>
114
+ <itemId>61313159</itemId>
115
+ <displayName>Joe Blow2</displayName>
116
+ <fullName>Joe Blow2</fullName>
117
+ <firstName>Joe</firstName>
118
+ <lastName>Blow2</lastName>
119
+ <homeEmail1>joeblow2@mailinator.com</homeEmail1>
120
+ <email1>joeblow2@mailinator.com</email1>
121
+ <folderId>5291351</folderId>
122
+ </contact>
123
+
124
+ </contacts>
125
+
126
+ <totalCount>2</totalCount>
127
+ <editCounter>3</editCounter>
128
+
129
+ </ns1:GetContactsResponse>
130
+ =end
@@ -0,0 +1,78 @@
1
+ class Contacts
2
+ class Seznam < Base
3
+ DETECTED_DOMAINS = [ /seznam\.cz/i, /email\.cz/i, /post\.cz/i, /spoluzaci\.cz/i, /stream\.cz/i, /firmy\.cz/i, ]
4
+ LOGIN_URL = "https://login.szn.cz/loginProcess"
5
+ ADDRESS_BOOK_URL = "http://email.seznam.cz/abookCsvExport?sessionId=&charset=utf-8&eof=windows&export=nameLast&export=nameFirst&export=nick&export=email"
6
+
7
+ attr_accessor :cookies
8
+
9
+ def real_connect
10
+ postdata = "disableSSL=0&domain=%s&forceRelogin=0&forceSSL=0&lang=cz&loginType=seznam&returnURL=%s&serviceId=email&username=%s&password=%s" % [
11
+ CGI.escape(domain),
12
+ CGI.escape('http://email.seznam.cz/ticket'),
13
+ CGI.escape(username),
14
+ CGI.escape(password)
15
+ ]
16
+
17
+ data, resp, self.cookies, forward = post(LOGIN_URL, postdata, "")
18
+
19
+ if !forward.nil? && forward.match("badLogin")
20
+ raise AuthenticationError, "Username and password do not match"
21
+ end
22
+
23
+ doc = Nokogiri(data)
24
+
25
+ a = doc.at('body>a')
26
+ forward = a['href'].to_s
27
+
28
+ data, resp, self.cookies, forward = get(forward, self.cookies)
29
+
30
+ doc = Nokogiri(data)
31
+
32
+ a = doc.at('body>a')
33
+ forward = a['href'].to_s
34
+
35
+ data, resp, self.cookies, forward = get(forward, self.cookies)
36
+
37
+ doc = Nokogiri(data)
38
+
39
+ a = doc.at('body>a')
40
+ forward = a['href'].to_s
41
+
42
+ data, resp, self.cookies, forward = get(forward, self.cookies)
43
+ end
44
+
45
+ def contacts
46
+ @contacts = []
47
+
48
+ data, resp, self.cookies, forward = get(ADDRESS_BOOK_URL, self.cookies)
49
+
50
+ CSV.parse(data, { :col_sep => ';' }) do |row|
51
+ last_name, first_name, unknown, email = row
52
+
53
+ name = "#{first_name} #{last_name}".strip
54
+ email.strip!
55
+
56
+ @contacts << [name, email] unless email.empty?
57
+ end
58
+
59
+ @contacts
60
+ end
61
+
62
+ def skip_gzip?
63
+ false
64
+ end
65
+
66
+ private
67
+
68
+ def username
69
+ @login.split('@').first
70
+ end
71
+
72
+ def domain
73
+ @login.split('@').last
74
+ end
75
+ end
76
+
77
+ TYPES[:seznam] = Seznam
78
+ end
@@ -0,0 +1,79 @@
1
+ class Contacts
2
+ class TonlineDe < Base
3
+ DETECTED_DOMAINS = [ /t-mobile\.de/i, /t-online\.de/i ]
4
+ URL = "https://email.t-online.de/V4-0-4-0/srv-bin/aaa?method=deliverLoginBox"
5
+ ADDRESS_BOOK_URL = "https://email.t-online.de/V4-0-4-0/srv-bin/addressbook?method=exportAdressbook&p%5Bformat%5D=CSV&p%5Bliid%5D="
6
+ PROTOCOL_ERROR = "t-online.de has changed its protocols"
7
+
8
+ attr_accessor :cookies, :tid
9
+
10
+ def real_connect
11
+ data, resp, self.cookies, forward = get(URL, "")
12
+
13
+ doc = Nokogiri(data)
14
+ meta = doc.at('meta[http-equiv=refresh]')
15
+
16
+ if meta.nil?
17
+ raise ConnectionError, PROTOCOL_ERROR
18
+ end
19
+
20
+ forward = meta['content'].split('URL=').last
21
+
22
+ data, resp, self.cookies, forward = get(forward, self.cookies)
23
+
24
+ doc = Nokogiri(data)
25
+
26
+ self.tid = doc.at('input[name=tid]')['value']
27
+ url = doc.at('form[name=login]')['action']
28
+
29
+ postdata = "appid=0158&lang=de&login=Login&pwd=%s&skinid=30&tid=%s&usr=%s" % [
30
+ CGI.escape(password),
31
+ CGI.escape(self.tid),
32
+ CGI.escape(username)
33
+ ]
34
+
35
+ data, resp, self.cookies, forward = post(url, postdata, self.cookies)
36
+
37
+ if forward.nil? || !forward.match("loadUser")
38
+ raise AuthenticationError, "Username and password do not match"
39
+ end
40
+
41
+ data, resp, self.cookies, forward = get(forward, self.cookies)
42
+ end
43
+
44
+ def contacts
45
+ @contacts = []
46
+
47
+ data, resp, self.cookies, forward = get(ADDRESS_BOOK_URL, self.cookies)
48
+
49
+ CSV.parse(data) do |row|
50
+ other, first_name, last_name, email = row
51
+
52
+ name = "#{first_name} #{last_name}".strip
53
+ email.strip!
54
+
55
+ next unless email.include?('@')
56
+
57
+ @contacts << [name, email]
58
+ end
59
+
60
+ @contacts
61
+ end
62
+
63
+ def skip_gzip?
64
+ false
65
+ end
66
+
67
+ private
68
+
69
+ def username
70
+ @login.split('@').first
71
+ end
72
+
73
+ def domain
74
+ @login.split('@').last
75
+ end
76
+ end
77
+
78
+ TYPES[:tonline_de] = TonlineDe
79
+ end
@@ -0,0 +1,79 @@
1
+ class Contacts
2
+ class WebDe < Base
3
+ DETECTED_DOMAINS = [ /web\.de/i ]
4
+ LOGIN_URL = "https://uas2.uilogin.de/centrallogin-3.1/login"
5
+ ADDRESS_BOOK_URL = "https://mm.web.de/contacts"
6
+
7
+
8
+ attr_accessor :cookies
9
+
10
+ def real_connect
11
+ postdata = "serviceID=%s&username=%s&password=%s" % [
12
+ CGI.escape('mobile.web.mail.webde.live'),
13
+ CGI.escape(login),
14
+ CGI.escape(password)
15
+ ]
16
+
17
+ data, resp, self.cookies, forward = post(LOGIN_URL, postdata, "")
18
+
19
+ if !forward.index("/success")
20
+ raise AuthenticationError, "Username and password do not match"
21
+ end
22
+
23
+ data, resp, self.cookies, forward = get(forward, self.cookies)
24
+
25
+ end
26
+
27
+ def contacts
28
+ url = ADDRESS_BOOK_URL
29
+ @contacts = []
30
+
31
+ begin
32
+ data, resp, self.cookies, forward = get(url, self.cookies)
33
+ data, resp, cookies, forward = get(forward, self.cookies)
34
+
35
+ doc = Nokogiri(data)
36
+
37
+ (doc/'ul[id=addressLines]/li').each do |li|
38
+ links = (li/'a')
39
+
40
+ name = links[0].text.strip
41
+ name = name.split(', ').reverse.join(' ')
42
+
43
+ next if links[1].nil?
44
+
45
+ match = links[1]['href'].match('to=([^&]+)')
46
+
47
+ next if !match
48
+
49
+ email = match[1].strip
50
+
51
+ @contacts << [ name, email ]
52
+ end
53
+
54
+ a_next = doc.at('a[id=go-next]')
55
+
56
+ unless a_next.nil?
57
+ url = ADDRESS_BOOK_URL + '?' + a_next[:href].split('?')[1]
58
+ else
59
+ url = nil
60
+ end
61
+
62
+ end while !url.nil?
63
+
64
+ @contacts
65
+ end
66
+
67
+ def skip_gzip?
68
+ false
69
+ end
70
+
71
+ private
72
+
73
+ def header_row?(row)
74
+ row[0] == 'Last Name'
75
+ end
76
+ end
77
+
78
+ TYPES[:web_de] = WebDe
79
+ end
@@ -0,0 +1,106 @@
1
+ class Contacts
2
+ class Yahoo < Base
3
+ DETECTED_DOMAINS = [ /yahoo/i, /ymail/i, /rocketmail/i ]
4
+ URL = "http://mail.yahoo.com/"
5
+ LOGIN_URL = "https://login.yahoo.com/config/login"
6
+ ADDRESS_BOOK_URL = "http://address.mail.yahoo.com/?.rand=430244936"
7
+ CONTACT_LIST_URL = "http://address.mail.yahoo.com/?_src=&_crumb=crumb&sortfield=3&bucket=1&scroll=1&VPC=social_list&.r=time"
8
+ 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"
9
+
10
+ def real_connect
11
+ postdata = ".tries=2&.src=ym&.md5=&.hash=&.js=&.last=&promo=&.intl=us&.bypass="
12
+ postdata += "&.partner=&.u=4eo6isd23l8r3&.v=0&.challenge=gsMsEcoZP7km3N3NeI4mX"
13
+ postdata += "kGB7zMV&.yplus=&.emailCode=&pkg=&stepid=&.ev=&hasMsgr=1&.chkP=Y&."
14
+ postdata += "done=#{CGI.escape(URL)}&login=#{CGI.escape(login)}&passwd=#{CGI.escape(password)}"
15
+
16
+ data, resp, cookies, forward = post(LOGIN_URL, postdata)
17
+
18
+ if data.index("Invalid ID or password") || data.index("This ID is not yet taken")
19
+ # raise AuthenticationError, "Username and password do not match"
20
+ elsif data.index("Sign in") && data.index("to Yahoo!")
21
+ # raise AuthenticationError, "Required field must not be blank"
22
+ elsif !data.match(/uncompressed\/chunked/)
23
+ # raise ConnectionError, PROTOCOL_ERROR
24
+ elsif cookies == ""
25
+ # raise ConnectionError, PROTOCOL_ERROR
26
+ end
27
+
28
+ data, resp, cookies, forward = get(forward, cookies, LOGIN_URL)
29
+
30
+ if resp.code_type != Net::HTTPOK
31
+ # raise ConnectionError, PROTOCOL_ERROR
32
+ end
33
+
34
+ @cookies = cookies
35
+ end
36
+
37
+ def contacts
38
+ return @contacts if @contacts
39
+ @contacts = []
40
+
41
+ if connected?
42
+ # first, get the addressbook site with the new crumb parameter
43
+ url = URI.parse(address_book_url)
44
+ http = open_http(url)
45
+ resp = http.get("#{url.path}?#{url.query}",
46
+ "Cookie" => @cookies
47
+ )
48
+
49
+ if resp.code_type != Net::HTTPOK
50
+ # raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
51
+ end
52
+
53
+ crumb = resp.body.to_s[/dotCrumb: '(.*?)'/][13...-1]
54
+
55
+ # now proceed with the new ".crumb" parameter to get the csv data
56
+ url = URI.parse(contact_list_url.sub("_crumb=crumb","_crumb=#{crumb}").sub("time", Time.now.to_f.to_s.sub(".","")[0...-2]))
57
+ http = open_http(url)
58
+ resp = http.get("#{url.path}?#{url.query}",
59
+ "Cookie" => @cookies,
60
+ "X-Requested-With" => "XMLHttpRequest",
61
+ "Referer" => address_book_url
62
+ )
63
+
64
+ if resp.code_type != Net::HTTPOK
65
+ # raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
66
+ end
67
+
68
+ if resp.body =~ /"TotalABContacts":(\d+)/
69
+ total = $1.to_i
70
+ ((total / 50.0).ceil).times do |i|
71
+ # now proceed with the new ".crumb" parameter to get the csv data
72
+ 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]))
73
+ http = open_http(url)
74
+ resp = http.get("#{url.path}?#{url.query}",
75
+ "Cookie" => @cookies,
76
+ "X-Requested-With" => "XMLHttpRequest",
77
+ "Referer" => address_book_url
78
+ )
79
+
80
+ if resp.code_type != Net::HTTPOK
81
+ # raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
82
+ end
83
+
84
+ parse resp.body
85
+ end
86
+ end
87
+
88
+ @contacts
89
+ end
90
+ end
91
+
92
+ private
93
+
94
+ def parse(data, options={})
95
+ @contacts ||= []
96
+ @contacts += Contacts.parse_json(data)["response"]["ResultSet"]["Contacts"].to_a.select{|contact|!contact["email"].to_s.empty?}.map do |contact|
97
+ name = contact["contactName"].split(",")
98
+ [[name.pop, name.join(",")].join(" ").strip, contact["email"]]
99
+ end if data =~ /^\{"response":/
100
+ @contacts
101
+ end
102
+
103
+ end
104
+
105
+ TYPES[:yahoo] = Yahoo
106
+ end