im_contacts 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.
@@ -0,0 +1,125 @@
1
+ class Contacts
2
+ class Hotmail < Base
3
+ URL = "https://login.live.com/login.srf?id=2"
4
+ OLD_CONTACT_LIST_URL = "http://%s/cgi-bin/addresses"
5
+ NEW_CONTACT_LIST_URL = "http://%s/mail/GetContacts.aspx"
6
+ CONTACT_LIST_URL = "http://mpeople.live.com/default.aspx?pg=0"
7
+ COMPOSE_URL = "http://%s/cgi-bin/compose?"
8
+ PROTOCOL_ERROR = "Hotmail has changed its protocols, please upgrade this library first. If that does not work, report this error at http://rubyforge.org/forum/?group_id=2693"
9
+ PWDPAD = "IfYouAreReadingThisYouHaveTooMuchFreeTime"
10
+ MAX_HTTP_THREADS = 8
11
+
12
+ def real_connect
13
+ data, resp, cookies, forward = get(URL)
14
+ old_url = URL
15
+ until forward.nil?
16
+ data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
17
+ end
18
+
19
+ postdata = "PPSX=%s&PwdPad=%s&login=%s&passwd=%s&LoginOptions=2&PPFT=%s" % [
20
+ CGI.escape(data.split("><").grep(/PPSX/).first[/=\S+$/][2..-3]),
21
+ PWDPAD[0...(PWDPAD.length-@password.length)],
22
+ CGI.escape(login),
23
+ CGI.escape(password),
24
+ CGI.escape(data.split("><").grep(/PPFT/).first[/=\S+$/][2..-3])
25
+ ]
26
+
27
+ form_url = data.split("><").grep(/form/).first.split[5][8..-2]
28
+ data, resp, cookies, forward = post(form_url, postdata, cookies)
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
+
35
+ if data.index("The e-mail address or password is incorrect")
36
+ raise AuthenticationError, "Username and password do not match"
37
+ elsif data != ""
38
+ raise AuthenticationError, "Required field must not be blank"
39
+ elsif cookies == ""
40
+ raise ConnectionError, PROTOCOL_ERROR
41
+ end
42
+
43
+ data, resp, cookies, forward = get("http://mail.live.com/mail", cookies)
44
+ until forward.nil?
45
+ data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
46
+ end
47
+
48
+ @domain = URI.parse(old_url).host
49
+ @cookies = cookies
50
+ rescue AuthenticationError => m
51
+ if @attempt == 1
52
+ retry
53
+ else
54
+ raise m
55
+ end
56
+ end
57
+
58
+ def contacts(options = {})
59
+ if connected?
60
+ url = URI.parse(contact_list_url)
61
+ data, resp, cookies, forward = get( contact_list_url, @cookies )
62
+
63
+ if resp.code_type != Net::HTTPOK
64
+ raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
65
+ end
66
+
67
+ @contacts = []
68
+ build_contacts = []
69
+ go = true
70
+ index = 0
71
+
72
+ while(go) do
73
+ go = false
74
+ url = URI.parse(get_contact_list_url(index))
75
+ http = open_http(url)
76
+ resp, data = http.get(get_contact_list_url(index), "Cookie" => @cookies)
77
+
78
+ email_match_text_beginning = Regexp.escape("http://m.mail.live.com/?rru=compose&amp;to=")
79
+ email_match_text_end = Regexp.escape("&amp;")
80
+
81
+ raw_html = resp.body.split("
82
+ ").grep(/(?:e|dn)lk[0-9]+/)
83
+ raw_html.inject(-1) do |memo, row|
84
+ c_info = row.match(/(e|dn)lk([0-9])+/)
85
+
86
+ # Same contact, or different?
87
+ build_contacts << [] if memo != c_info[2]
88
+
89
+ # Grab info
90
+ case c_info[1]
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
+ end
96
+
97
+ # Set memo to contact id
98
+ c_info[2]
99
+ end
100
+
101
+ go = resp.body.include?("ContactList_next")
102
+ index += 1
103
+ end
104
+
105
+ build_contacts.each do |contact|
106
+ unless contact[1].nil?
107
+ # Only return contacts with email addresses
108
+ contact[1] = CGI::unescape(contact[1])
109
+ @contacts << contact
110
+ end
111
+ end
112
+
113
+ return @contacts
114
+ end
115
+ end
116
+
117
+ def get_contact_list_url(index)
118
+ "http://mpeople.live.com/default.aspx?pg=#{index}"
119
+ end
120
+
121
+ private
122
+
123
+ TYPES[:hotmail] = Hotmail
124
+ end
125
+ end
@@ -0,0 +1,16 @@
1
+ if !Object.const_defined?('ActiveSupport')
2
+ require 'json'
3
+ end
4
+
5
+ class Contacts
6
+ def self.parse_json( string )
7
+ if Object.const_defined?('ActiveSupport') and
8
+ ActiveSupport.const_defined?('JSON')
9
+ ActiveSupport::JSON.decode( string )
10
+ elsif Object.const_defined?('JSON')
11
+ JSON.parse( string )
12
+ else
13
+ raise 'Contacts requires JSON or Rails (with ActiveSupport::JSON)'
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,117 @@
1
+ class Contacts
2
+ class NetEase < Base
3
+ URL = "http://www.163.com"
4
+ LOGIN_URL = "https://reg.163.com/logins.jsp"
5
+ LoginData = {
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
+ }
22
+ ENTER_MAIL_URL = {
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
+ }
27
+
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
+
31
+ def initialize(login, password, options={})
32
+ @mail_type = get_mail_type(login)
33
+ super(login,password,options)
34
+ end
35
+
36
+ def real_connect
37
+ login_for_cookies
38
+ enter_mail_server
39
+ end
40
+
41
+ def contacts
42
+ return @contacts if @contacts
43
+ if connected?
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
+ raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
51
+ end
52
+ parse(data)
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def get_mail_type(username)
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
+ end
69
+
70
+ def parse(data)
71
+ json_data = Contacts.parse_json(data)
72
+ json_data['var'][0]['var'].map{|contactor|
73
+ [contactor['FN'],contactor['EMAIL;PREF']]
74
+ }
75
+ end
76
+
77
+ def login_for_cookies
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
+ }
92
+ postdata = data.to_query_string
93
+ #login and get cookie
94
+ data, resp, cookies, forward = post(LOGIN_URL,postdata)
95
+ @cookies = cookies
96
+ if data.index(LoginData[:url2][@mail_type])
97
+ raise AuthenticationError, "Username or password error"
98
+ end
99
+ end
100
+
101
+ def enter_mail_server
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
+ end
115
+ TYPES[:net_ease] = NetEase
116
+ end
117
+ 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,91 @@
1
+ class Contacts
2
+ class Sina < Base
3
+ URL = "http://mail.sina.com.cn"
4
+ LOGIN_URL = {
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
+ }
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
+
18
+ def initialize(login, password, options={})
19
+ @mail_type = get_mail_type(login)
20
+ super(login,password,options)
21
+ end
22
+
23
+ def real_connect
24
+ login_for_cookies
25
+ redirect_for_location
26
+ end
27
+
28
+ def contacts
29
+ return @contacts if @contacts
30
+ if connected?
31
+ data, resp, cookies, forward = get(@mail_url,@cookies)
32
+ if resp.code_type != Net::HTTPOK
33
+ raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
34
+ end
35
+ parse(data)
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def get_mail_type(username)
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
+ end
50
+
51
+ def parse(data)
52
+ data =~ /conf.*?contacts:.*?(\{.*?\}),\s*groups:/m
53
+ contacts = $1.gsub("&quot;",'')
54
+ contacts = ActiveSupport::JSON.decode(contacts)
55
+ contacts['contact'].map{|contactor|
56
+ [contactor['name'],contactor['email']]
57
+ }
58
+ end
59
+
60
+ def login_for_cookies
61
+ data = {
62
+ :domain => DOMAIN[@mail_type],
63
+ :logintype => 'uid',
64
+ :u => @login,
65
+ :psw => @password,
66
+ :savelogin => 'on',
67
+ :sshchk => 'on',
68
+ :ssl => 'on'
69
+ }
70
+ data, resp, cookies, forward = post(LOGIN_URL[@mail_type],data.to_query_string,LOGIN_COOKIE[@mail_type])
71
+ login_faile_flag = %r{form.*?action.*?http.*?mail.sina.com.cn/cgi-bin/.*?login.php}m
72
+ if data.match(login_faile_flag)
73
+ raise AuthenticationError, "Username or password error"
74
+ end
75
+ data.match(/URL=(http:\/\/.*?)'>/)
76
+ @redirect_url = $1
77
+ @mail_server = @redirect_url.match(/(http:\/\/.*\..*?)\//)
78
+ @cookies = cookies
79
+ end
80
+
81
+ def redirect_for_location
82
+ data, resp, cookies, forward = get(@redirect_url,@cookies)
83
+ location = resp['Location']
84
+ @mail_url = location.index("http://") ? location : "#{@mail_server}#{location}"
85
+ @cookies = cookies
86
+ end
87
+
88
+ TYPES[:sina] = Sina
89
+ end
90
+
91
+ end
@@ -0,0 +1,59 @@
1
+ class Contacts
2
+ class Sohu < Base
3
+ URL = "http://mail.sohu.com"
4
+ DOMAIN = "sohu.com"
5
+ LOGIN_URL = "https://passport.sohu.com/sso/login.jsp"
6
+ LOGIN_COOKIE = "IPLOC=CN3301; SUV=1008301317090277"
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
+
10
+ def real_connect
11
+ login_for_cookies
12
+ end
13
+
14
+ def contacts
15
+ return @contacts if @contacts
16
+ if connected?
17
+ data, resp, cookies, forward = get(MAIL_URL,@cookies)
18
+ if resp.code_type != Net::HTTPOK
19
+ raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
20
+ end
21
+ parse(data)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+
28
+ def parse(data)
29
+ data.match(/ADDRESSES.*?'(\{.*?\})';/m)
30
+ contacts = ActiveSupport::JSON.decode($1)
31
+ contacts['contact'].map{|contactor|
32
+ [contactor['nickname'],contactor['email']]
33
+ }
34
+ end
35
+
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
+
56
+ TYPES[:sohu] = Sohu
57
+ end
58
+
59
+ end
@@ -0,0 +1,103 @@
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
+ if connected?
39
+ # first, get the addressbook site with the new crumb parameter
40
+ url = URI.parse(address_book_url)
41
+ http = open_http(url)
42
+ resp, data = http.get("#{url.path}?#{url.query}",
43
+ "Cookie" => @cookies
44
+ )
45
+
46
+ if resp.code_type != Net::HTTPOK
47
+ raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
48
+ end
49
+
50
+ crumb = data.to_s[/dotCrumb: '(.*?)'/][13...-1]
51
+
52
+ # now proceed with the new ".crumb" parameter to get the csv data
53
+ url = URI.parse(contact_list_url.sub("_crumb=crumb","_crumb=#{crumb}").sub("time", Time.now.to_f.to_s.sub(".","")[0...-2]))
54
+ http = open_http(url)
55
+ resp, more_data = http.get("#{url.path}?#{url.query}",
56
+ "Cookie" => @cookies,
57
+ "X-Requested-With" => "XMLHttpRequest",
58
+ "Referer" => address_book_url
59
+ )
60
+
61
+ if resp.code_type != Net::HTTPOK
62
+ raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
63
+ end
64
+
65
+ if more_data =~ /"TotalABContacts":(\d+)/
66
+ total = $1.to_i
67
+ ((total / 50.0).ceil).times do |i|
68
+ # now proceed with the new ".crumb" parameter to get the csv data
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
+ http = open_http(url)
71
+ resp, more_data = http.get("#{url.path}?#{url.query}",
72
+ "Cookie" => @cookies,
73
+ "X-Requested-With" => "XMLHttpRequest",
74
+ "Referer" => address_book_url
75
+ )
76
+
77
+ if resp.code_type != Net::HTTPOK
78
+ raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
79
+ end
80
+
81
+ parse more_data
82
+ end
83
+ end
84
+
85
+ @contacts
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def parse(data, options={})
92
+ @contacts ||= []
93
+ @contacts += Contacts.parse_json(data)["response"]["ResultSet"]["Contacts"].to_a.select{|contact|!contact["email"].to_s.empty?}.map do |contact|
94
+ name = contact["contactName"].split(",")
95
+ [[name.pop, name.join(",")].join(" ").strip, contact["email"]]
96
+ end if data =~ /^\{"response":/
97
+ @contacts
98
+ end
99
+
100
+ end
101
+
102
+ TYPES[:yahoo] = Yahoo
103
+ end
@@ -0,0 +1,17 @@
1
+ $:.unshift(File.dirname(__FILE__)+"/contacts/")
2
+
3
+ require 'rubygems'
4
+ unless Object.const_defined?('ActiveSupport')
5
+ require 'active_support'
6
+ end
7
+ require 'base'
8
+ require 'gmail'
9
+ require 'hotmail'
10
+ require 'yahoo'
11
+ require 'plaxo'
12
+ require 'aol'
13
+ require 'net_ease'
14
+ require 'sina'
15
+ require 'sohu'
16
+ require 'json_picker'
17
+ require 'hash_ext'