muck-contacts 2.6.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,68 @@
1
+ require 'csv'
2
+
3
+ class Contacts
4
+ class Mailru < Base
5
+ LOGIN_URL = "https://auth.mail.ru/cgi-bin/auth"
6
+ ADDRESS_BOOK_URL = "http://win.mail.ru/cgi-bin/abexport/addressbook.csv"
7
+
8
+ attr_accessor :cookies
9
+
10
+ def real_connect
11
+ username = login
12
+
13
+ postdata = "Login=%s&Domain=%s&Password=%s" % [
14
+ CGI.escape(username),
15
+ CGI.escape(domain_param(username)),
16
+ CGI.escape(password)
17
+ ]
18
+
19
+ data, resp, self.cookies, forward = post(LOGIN_URL, postdata, "")
20
+
21
+ if data.index("fail=1")
22
+ raise AuthenticationError, "Username and password do not match"
23
+ elsif cookies == "" or data == ""
24
+ raise ConnectionError, PROTOCOL_ERROR
25
+ end
26
+
27
+ data, resp, cookies, forward = get(login_token_link(data), login_cookies.join(';'))
28
+ end
29
+
30
+ def contacts
31
+ postdata = "confirm=1&abtype=6"
32
+ data, resp, cookies, forward = post(ADDRESS_BOOK_URL, postdata, login_cookies.join(';'))
33
+
34
+ @contacts = []
35
+ CSV.parse(data) do |row|
36
+ @contacts << [row[0], row[4]] unless header_row?(row)
37
+ end
38
+
39
+ @contacts
40
+ end
41
+
42
+ def skip_gzip?
43
+ true
44
+ end
45
+
46
+ private
47
+ def login_token_link(data)
48
+ data.match(/url=(.+)\">/)[1]
49
+ end
50
+
51
+ def login_cookies
52
+ self.cookies.split(';').collect{|c| c if (c.include?('t=') or c.include?('Mpop='))}.compact.collect{|c| c.strip}
53
+ end
54
+
55
+ def header_row?(row)
56
+ row[0] == 'AB-Name'
57
+ end
58
+
59
+ def domain_param(login)
60
+ login.include?('@') ?
61
+ login.match(/.+@(.+)/)[1] :
62
+ 'mail.ru'
63
+ end
64
+
65
+ end
66
+
67
+ TYPES[:mailru] = Mailru
68
+ end
@@ -0,0 +1,59 @@
1
+ require 'csv'
2
+
3
+ class Contacts
4
+ class Outlook < Base
5
+
6
+ def initialize(file)
7
+ @contact_file = Array.new
8
+ file = file.respond_to?(:read) ? file.read : file
9
+ file.each_line do |line|
10
+ @contact_file << CSV.parse(line)[0]
11
+ end
12
+ @full_name = false
13
+ @header_indexes = Hash.new
14
+ @header_indexes[:email_address] = Array.new
15
+
16
+ headers = @contact_file[0]
17
+
18
+ @contact_file = @contact_file[1, @contact_file.length]
19
+
20
+ headers.each_with_index do |header, i|
21
+ if header.match(/^Name$/)
22
+ @full_name = true
23
+ @header_indexes[:full_name] = i
24
+ elsif header.match(/^First Name/)
25
+ @header_indexes[:first_name] = i
26
+ elsif header.match(/^Last Name/)
27
+ @header_indexes[:last_name] = i
28
+ elsif header.match(/E-mail/)
29
+ @header_indexes[:email_address] << i
30
+ end
31
+ end
32
+ end
33
+
34
+ def contacts
35
+
36
+ contacts = Array.new
37
+
38
+ @contact_file.each_with_index do |line, i|
39
+ contacts[i] = Array.new unless contacts[i]
40
+ if(@full_name)
41
+ contacts[i][0] = line[@header_indexes[:full_name]]
42
+ else
43
+ contacts[i][0] = "#{line[@header_indexes[:first_name]]} #{line[@header_indexes[:last_name]]}"
44
+ end
45
+ @header_indexes[:email_address].each do |index|
46
+ if line[index] && !contacts[i][1]
47
+ contacts[i][1] = line[index]
48
+ end
49
+ end
50
+ end
51
+
52
+ contacts
53
+ end
54
+
55
+ end
56
+
57
+ private
58
+ FILETYPES[:outlook] = Outlook
59
+ end
@@ -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,25 @@
1
+ class Contacts
2
+ class Vcf < Base
3
+
4
+ def initialize(file)
5
+ @contact_file = file
6
+ end
7
+
8
+ def contacts
9
+ contacts = Array.new
10
+ i = 0
11
+ @contact_file.each do |line|
12
+ contacts[i] = Array.new unless contacts[i]
13
+ if line.match(/FN:/)
14
+ contacts[i] << line.gsub(/FN:/, '').strip
15
+ elsif line.match(/EMAIL;/)
16
+ contacts[i] << line.gsub(/^.*:/, '').strip
17
+ elsif line.match(/END:VCARD/)
18
+ i += 1
19
+ end
20
+ end
21
+ contacts
22
+ end
23
+ end
24
+ FILETYPES[:vcf] = Vcf
25
+ end
@@ -0,0 +1,104 @@
1
+ class Contacts
2
+ class Yahoo < Base
3
+ URL = "http://mail.yahoo.com/"
4
+ LOGIN_URL = "https://login.yahoo.com/config/login"
5
+ ADDRESS_BOOK_URL = "http://address.mail.yahoo.com/?.rand=430244936"
6
+ CONTACT_LIST_URL = "http://address.mail.yahoo.com/?_src=&_crumb=crumb&sortfield=3&bucket=1&scroll=1&VPC=social_list&.r=time"
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
10
+ postdata = ".tries=2&.src=ym&.md5=&.hash=&.js=&.last=&promo=&.intl=us&.bypass="
11
+ postdata += "&.partner=&.u=4eo6isd23l8r3&.v=0&.challenge=gsMsEcoZP7km3N3NeI4mX"
12
+ postdata += "kGB7zMV&.yplus=&.emailCode=&pkg=&stepid=&.ev=&hasMsgr=1&.chkP=Y&."
13
+ postdata += "done=#{CGI.escape(URL)}&login=#{CGI.escape(login)}&passwd=#{CGI.escape(password)}"
14
+
15
+ data, resp, cookies, forward = post(LOGIN_URL, postdata)
16
+
17
+ if data.index("Invalid ID or password") || data.index("This ID is not yet taken")
18
+ raise AuthenticationError, "Username and password do not match"
19
+ elsif data.index("Sign in") && data.index("to Yahoo!")
20
+ raise AuthenticationError, "Required field must not be blank"
21
+ elsif !data.match(/uncompressed\/chunked/)
22
+ raise ConnectionError, PROTOCOL_ERROR
23
+ elsif cookies == ""
24
+ raise ConnectionError, PROTOCOL_ERROR
25
+ end
26
+
27
+ data, resp, cookies, forward = get(forward, cookies, LOGIN_URL)
28
+
29
+ if resp.code_type != Net::HTTPOK
30
+ raise ConnectionError, PROTOCOL_ERROR
31
+ end
32
+
33
+ @cookies = cookies
34
+ end
35
+
36
+ def contacts
37
+ return @contacts if @contacts
38
+ @contacts = []
39
+
40
+ if connected?
41
+ # first, get the addressbook site with the new crumb parameter
42
+ url = URI.parse(address_book_url)
43
+ http = open_http(url)
44
+ resp, data = http.get("#{url.path}?#{url.query}",
45
+ "Cookie" => @cookies
46
+ )
47
+
48
+ if resp.code_type != Net::HTTPOK
49
+ raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
50
+ end
51
+
52
+ crumb = data.to_s[/dotCrumb: '(.*?)'/][13...-1]
53
+
54
+ # now proceed with the new ".crumb" parameter to get the csv data
55
+ url = URI.parse(contact_list_url.sub("_crumb=crumb","_crumb=#{crumb}").sub("time", Time.now.to_f.to_s.sub(".","")[0...-2]))
56
+ http = open_http(url)
57
+ resp, more_data = http.get("#{url.path}?#{url.query}",
58
+ "Cookie" => @cookies,
59
+ "X-Requested-With" => "XMLHttpRequest",
60
+ "Referer" => address_book_url
61
+ )
62
+
63
+ if resp.code_type != Net::HTTPOK
64
+ raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
65
+ end
66
+
67
+ if more_data =~ /"TotalABContacts":(\d+)/
68
+ total = $1.to_i
69
+ ((total / 50.0).ceil).times do |i|
70
+ # now proceed with the new ".crumb" parameter to get the csv data
71
+ 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]))
72
+ http = open_http(url)
73
+ resp, more_data = http.get("#{url.path}?#{url.query}",
74
+ "Cookie" => @cookies,
75
+ "X-Requested-With" => "XMLHttpRequest",
76
+ "Referer" => address_book_url
77
+ )
78
+
79
+ if resp.code_type != Net::HTTPOK
80
+ raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
81
+ end
82
+
83
+ parse more_data
84
+ end
85
+ end
86
+
87
+ @contacts
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def parse(data, options={})
94
+ @contacts ||= []
95
+ @contacts += Contacts.parse_json(data)["response"]["ResultSet"]["Contacts"].to_a.select{|contact|!contact["email"].to_s.empty?}.map do |contact|
96
+ name = contact["contactName"].split(",")
97
+ [[name.pop, name.join(",")].join(" ").strip, contact["email"]]
98
+ end if data =~ /^\{"response":/
99
+ @contacts
100
+ end
101
+ end
102
+
103
+ TYPES[:yahoo] = Yahoo
104
+ end
@@ -0,0 +1,73 @@
1
+ gmail:
2
+ username: <changeme>
3
+ password: <changeme>
4
+ contacts:
5
+ -
6
+ name: "FirstName1 LastName1"
7
+ email_address: "firstname1@example.com"
8
+ -
9
+ name: "FirstName2 LastName2"
10
+ email_address: "firstname2@example.com"
11
+ yahoo:
12
+ username: <changeme>
13
+ password: <changeme>
14
+ contacts:
15
+ -
16
+ name: "FirstName1 LastName1"
17
+ email_address: "firstname1@example.com"
18
+ -
19
+ name: "FirstName2 LastName2"
20
+ email_address: "firstname2@example.com"
21
+ hotmail:
22
+ username: <changeme>
23
+ password: <changeme>
24
+ contacts:
25
+ -
26
+ name: "FirstName1 LastName1"
27
+ email_address: "firstname1@example.com"
28
+ -
29
+ name: "FirstName2 LastName2"
30
+ email_address: "firstname2@example.com"
31
+ aol:
32
+ username: <changeme>
33
+ password: <changeme>
34
+ contacts:
35
+ -
36
+ name: "FirstName1 LastName1"
37
+ email_address: "firstname1@example.com"
38
+ -
39
+ name: "FirstName2 LastName2"
40
+ email_address: "firstname2@example.com"
41
+ mailru:
42
+ username: <changeme>
43
+ password: <changeme>
44
+ contacts:
45
+ -
46
+ name: "FirstName1 LastName1"
47
+ email_address: "firstname1@example.com"
48
+ -
49
+ name: "FirstName2 LastName2"
50
+ email_address: "firstname2@example.com"
51
+ facebook:
52
+ username: <facebook uid>
53
+ password: <access token from facebook app oauth2>
54
+ contacts:
55
+ -
56
+ name: "FirstName1 LastName1"
57
+ account_id: "facebook_uid"
58
+ -
59
+ name: "FirstName2 LastName2"
60
+ account_id: "facebook_uid"
61
+ linked_in:
62
+ username: <oauth token for user>
63
+ password: <oauth secret for user>
64
+ app_id: <consumer token from linked_in app>
65
+ app_secret: <consumer secret from linked_in app>
66
+ contacts:
67
+ -
68
+ name: "FirstName1 LastName1"
69
+ account_id: "linked_in_uid"
70
+ -
71
+ name: "FirstName2 LastName2"
72
+ account_id: "linked_in_uid"
73
+