contacts 1.0.12 → 1.0.13

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.
@@ -8,7 +8,7 @@ require "thread"
8
8
 
9
9
  class Contacts
10
10
  TYPES = {}
11
- VERSION = "1.0.12"
11
+ VERSION = "1.0.13"
12
12
 
13
13
  class Base
14
14
  def initialize(login, password)
@@ -136,6 +136,9 @@ class Contacts
136
136
  cookies = parse_cookies(resp.response['set-cookie'], cookies)
137
137
  forward = resp.response['Location']
138
138
  forward ||= (data =~ /<meta.*?url='([^']+)'/ ? CGI.unescapeHTML($1) : nil)
139
+ if (not forward.nil?) && URI.parse(forward).host.nil?
140
+ forward = url.scheme.to_s + "://" + url.host.to_s + forward
141
+ end
139
142
  return data, resp, cookies, forward
140
143
  end
141
144
 
@@ -151,6 +154,9 @@ class Contacts
151
154
  data = uncompress(resp, data)
152
155
  cookies = parse_cookies(resp.response['set-cookie'], cookies)
153
156
  forward = resp.response['Location']
157
+ if (not forward.nil?) && URI.parse(forward).host.nil?
158
+ forward = url.scheme.to_s + "://" + url.host.to_s + forward
159
+ end
154
160
  return data, resp, cookies, forward
155
161
  end
156
162
 
@@ -67,7 +67,9 @@ class Contacts
67
67
  if @contacts != nil
68
68
  @contacts = @contacts.delete_if {|c| c["Emails"].nil?}.map do |c|
69
69
  name, emails = c.values_at "Name", "Emails"
70
- emails = emails.first.values
70
+ # emails are returned in a form of
71
+ # [{"Address"=>"home.email@gmail.com"}, {"Type"=>{"Id"=>"WORK"}, "Address"=>"work.email@gmail.com"}]
72
+ emails = emails.collect{|a| a.values_at("Address")}
71
73
  [name, emails].flatten
72
74
  end
73
75
  else
@@ -3,6 +3,7 @@ class Contacts
3
3
  URL = "http://login.live.com/login.srf?id=2"
4
4
  OLD_CONTACT_LIST_URL = "http://%s/cgi-bin/addresses"
5
5
  NEW_CONTACT_LIST_URL = "http://%s/mail/GetContacts.aspx"
6
+ NEWEST_CONTACT_LIST_URL = "http://%s/mail/options.aspx?subsection=26"
6
7
  COMPOSE_URL = "http://%s/cgi-bin/compose?"
7
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"
8
9
  PWDPAD = "IfYouAreReadingThisYouHaveTooMuchFreeTime"
@@ -60,10 +61,32 @@ class Contacts
60
61
  end
61
62
  =end
62
63
 
63
- data, resp, cookies, forward, old_url = get("http://mail.live.com/mail", cookies)
64
- data, resp, cookies, forward, old_url = get(forward, cookies)
65
-
66
- @domain = URI.parse(forward).host
64
+ data, resp, cookies, forward = get("http://mail.live.com/mail", cookies)
65
+ until forward.nil?
66
+ data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
67
+ end
68
+
69
+ # click on 'Contiune' if presented with the Hotmail Listened page
70
+ # look for the Submit button with a "TakeMeToInbox" name (this should work for other languages)
71
+ if (not old_url.grep(/MessageAtLogin.aspx/).first.nil?)
72
+
73
+ viewState = data.split(/>\s*?</).grep(/__VIEWSTATE/).first[/value=\".+?\"/][7..-2]
74
+ eventValidation = data.split(/>\s*?</).grep(/__EVENTVALIDATION/).first[/value=\".+?\"/][7..-2]
75
+ continueValue = data.split(/>\s*?</).grep(/TakeMeToInbox/).first[/value=\".+?\"/][7..-2]
76
+
77
+ # post back to the same url
78
+ postdata = "%s=%s&%s=%s&%s=%s" % [
79
+ "__VIEWSTATE", CGI.escape(viewState),
80
+ "__EVENTVALIDATION", CGI.escape(eventValidation),
81
+ CGI.escape("TakeMeToInbox"), CGI.escape(continueValue)
82
+ ]
83
+ data, resp, cookies, forward = post( old_url, postdata, cookies, old_url )
84
+ until forward.nil?
85
+ data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
86
+ end
87
+ end
88
+
89
+ @domain = URI.parse(old_url).host
67
90
  @cookies = cookies
68
91
  rescue AuthenticationError => m
69
92
  if @attempt == 1
@@ -73,10 +96,51 @@ class Contacts
73
96
  end
74
97
  end
75
98
 
99
+ def contacts(options = {})
100
+ return @contacts if @contacts
101
+ if connected?
102
+ url = URI.parse(contact_list_url)
103
+ data, resp, cookies, forward = get( contact_list_url, @cookies )
104
+
105
+ if resp.code_type != Net::HTTPOK
106
+ raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
107
+ end
108
+
109
+ # we have to click on the Export Contacts button to get the csv:
110
+ # Search the content for __VIEWSTATE or __EVENTVALIDATION
111
+ viewState = data.split(/>\s*?</).grep(/__VIEWSTATE/).first[/value=\".+?\"/][7..-2]
112
+ eventValidation = data.split(/>\s*?</).grep(/__EVENTVALIDATION/).first[/value=\".+?\"/][7..-2]
113
+ exportValue = data.split(/>\s*?</).grep(/ctl02\$ExportButton/).first[/value=\".+?\"/][7..-2]
114
+ mt = cookies.split("; ").grep(/mt=/).first[3..-1]
115
+
116
+ # post back to the same url
117
+ postdata = "%s=%s&%s=%s&%s=%s&%s=%s" % [
118
+ "__VIEWSTATE", CGI.escape(viewState),
119
+ "__EVENTVALIDATION", CGI.escape(eventValidation),
120
+ CGI.escape("ctl02$ExportButton"), CGI.escape(exportValue),
121
+ "mt", CGI.escape( mt )
122
+ ]
123
+
124
+ url = URI.parse(contact_list_url)
125
+ http = open_http(url)
126
+ resp, data = http.post("#{url.path}?#{url.query}", postdata,
127
+ "User-Agent" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0",
128
+ "Accept-Encoding" => "gzip",
129
+ "Cookie" => cookies,
130
+ "Referer" => contact_list_url,
131
+ "Content-Type" => 'application/x-www-form-urlencoded'
132
+ )
133
+
134
+ data = uncompress(resp, data)
135
+ parse(data, options)
136
+ end
137
+ end
138
+
139
+
76
140
  private
77
141
 
78
142
  def contact_list_url
79
- NEW_CONTACT_LIST_URL % @domain
143
+ NEWEST_CONTACT_LIST_URL % @domain
80
144
  end
81
145
 
82
146
  def follow_email(data, id, contacts_slot)
@@ -100,7 +164,7 @@ class Contacts
100
164
 
101
165
  def parse(data, options={})
102
166
  data = data.split("\r\n")
103
- data = CSV.parse(data.join("\r\n").gsub('"', ''), ';')
167
+ data = CSV.parse(data.join("\r\n").gsub('"', '').gsub(';', ','), ';')
104
168
  col_names = data.shift
105
169
 
106
170
  @contacts = data.delete_if{|person|person[0].nil?}.map do |person|
@@ -109,7 +173,6 @@ class Contacts
109
173
  [[person[1], person[2], person[3]].delete_if{|i|i.empty?}.join(" "), person[idx - 1]] unless person[idx - 1].nil?
110
174
  end.compact
111
175
  end
112
-
113
176
  end
114
177
 
115
178
  TYPES[:hotmail] = Hotmail
@@ -16,7 +16,7 @@ class Contacts
16
16
 
17
17
  data, resp, cookies, forward = post(LOGIN_URL, postdata)
18
18
 
19
- if data.index("Invalid ID or password")
19
+ if data.index("Invalid ID or password") || data.index("This ID is not yet taken")
20
20
  raise AuthenticationError, "Username and password do not match"
21
21
  elsif data.index("Sign in") && data.index("to Yahoo!")
22
22
  raise AuthenticationError, "Required field must not be blank"
metadata CHANGED
@@ -1,19 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contacts
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.12
5
- platform: ""
4
+ version: 1.0.13
5
+ platform: ruby
6
6
  authors:
7
7
  - Lucas Carlson
8
8
  autorequire: contacts
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-07-11 00:00:00 -07:00
12
+ date: 2009-01-08 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: json
17
+ type: :runtime
17
18
  version_requirement:
18
19
  version_requirements: !ruby/object:Gem::Requirement
19
20
  requirements:
@@ -63,7 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
64
  requirements:
64
65
  - A json parser
65
66
  rubyforge_project:
66
- rubygems_version: 0.9.5
67
+ rubygems_version: 1.3.1
67
68
  signing_key:
68
69
  specification_version: 2
69
70
  summary: Ridiculously easy contact list information from various providers including Yahoo, Gmail, and Hotmail