<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,6 +1,6 @@
 Gem::Specification.new do |s|
   s.name = &quot;contacts&quot;
-  s.version = &quot;1.0.14&quot;
+  s.version = &quot;1.0.15&quot;
   s.date = &quot;2009-05-06&quot;
   s.summary = &quot;A universal interface to grab contact list information from various providers including Yahoo, Gmail, Hotmail, and Plaxo.&quot;
   s.email = &quot;lucas@rufy.com&quot;</diff>
      <filename>contacts.gemspec</filename>
    </modified>
    <modified>
      <diff>@@ -8,7 +8,7 @@ require &quot;thread&quot;
 
 class Contacts
   TYPES = {}
-  VERSION = &quot;1.0.13&quot;
+  VERSION = &quot;1.0.15&quot;
   
   class Base
     def initialize(login, password)</diff>
      <filename>lib/contacts/base.rb</filename>
    </modified>
    <modified>
      <diff>@@ -39,7 +39,7 @@ class Contacts
       
       cookies = remove_cookie(&quot;GMAIL_LOGIN&quot;, cookies)
 
-      if data.index(&quot;Username and password do not match&quot;)
+      if data.index(&quot;Username and password do not match&quot;) || data.index(&quot;New to Gmail? It's free and easy&quot;)
         raise AuthenticationError, &quot;Username and password do not match&quot;
       elsif data.index(&quot;The username or password you entered is incorrect&quot;)
         raise AuthenticationError, &quot;Username and password do not match&quot;
@@ -91,4 +91,4 @@ class Contacts
   end
 
   TYPES[:gmail] = Gmail
-end
+end
\ No newline at end of file</diff>
      <filename>lib/contacts/gmail.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,9 +1,9 @@
 class Contacts
   class Hotmail &lt; Base
-    URL                 = &quot;http://login.live.com/login.srf?id=2&quot;
+    URL                 = &quot;https://login.live.com/login.srf?id=2&quot;
     OLD_CONTACT_LIST_URL = &quot;http://%s/cgi-bin/addresses&quot;
     NEW_CONTACT_LIST_URL = &quot;http://%s/mail/GetContacts.aspx&quot;
-    NEWEST_CONTACT_LIST_URL = &quot;http://%s/mail/options.aspx?subsection=26&quot;
+    CONTACT_LIST_URL = &quot;http://mpeople.live.com/default.aspx?pg=0&quot; 
     COMPOSE_URL         = &quot;http://%s/cgi-bin/compose?&quot;
     PROTOCOL_ERROR      = &quot;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&quot;
     PWDPAD = &quot;IfYouAreReadingThisYouHaveTooMuchFreeTime&quot;
@@ -11,7 +11,6 @@ class Contacts
     
     def real_connect
       data, resp, cookies, forward = get(URL)
-      
       old_url = URL
       until forward.nil?
         data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
@@ -37,55 +36,16 @@ class Contacts
       end
       
       old_url = form_url
+      
       until forward.nil?
         data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
       end
-
-=begin      
-      if data =~ %r{action=&quot;(.*?)&quot;}
-        forward = $1
-        puts forward
-        napexp = CGI.escape(data.to_s[/id=&quot;NAPExp&quot; value=&quot;(.*?)&quot;/][19...-1])
-        nap = CGI.escape(data.to_s[/id=&quot;NAP&quot; value=&quot;(.*?)&quot;/][16...-1])
-        anon = CGI.escape(data.to_s[/id=&quot;ANON&quot; value=&quot;(.*?)&quot;/][17...-1])
-        anonexp = CGI.escape(data.to_s[/id=&quot;ANONExp&quot; value=&quot;(.*?)&quot;/][20...-1])
-        t = CGI.escape(data.to_s[/id=&quot;t&quot; value=&quot;(.*?)&quot;/][14...-1])
-        
-        postdata = &quot;NAPExp=%s&amp;NAP=%s&amp;ANON=%s&amp;ANONExp=%s&amp;t=%s&quot; % [ napexp, nap, anon, anonexp, t ]
-        puts postdata
-        data, resp, cookies, forward, old_url = post(forward, postdata, cookies, old_url) + [forward]
-      end
-
-      until forward.nil?
-        data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
-      end
-=end
       
       data, resp, cookies, forward = get(&quot;http://mail.live.com/mail&quot;, cookies)
       until forward.nil?
         data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
       end
-
-    # click on 'Contiune' if presented with the Hotmail Listened page
-    #  look for the Submit button with a &quot;TakeMeToInbox&quot; name (this should work for other languages)
-    if (not old_url.grep(/MessageAtLogin.aspx/).first.nil?)
-		
-      viewState = data.split(/&gt;\s*?&lt;/).grep(/__VIEWSTATE/).first[/value=\&quot;.+?\&quot;/][7..-2]
-      eventValidation = data.split(/&gt;\s*?&lt;/).grep(/__EVENTVALIDATION/).first[/value=\&quot;.+?\&quot;/][7..-2]
-      continueValue = data.split(/&gt;\s*?&lt;/).grep(/TakeMeToInbox/).first[/value=\&quot;.+?\&quot;/][7..-2]
-
-      # post back to the same url 
-      postdata = &quot;%s=%s&amp;%s=%s&amp;%s=%s&quot; % [
-            &quot;__VIEWSTATE&quot;, CGI.escape(viewState),
-            &quot;__EVENTVALIDATION&quot;, CGI.escape(eventValidation),
-            CGI.escape(&quot;TakeMeToInbox&quot;), CGI.escape(continueValue)
-        ]
-        data, resp, cookies, forward = post( old_url, postdata, cookies, old_url )
-        until forward.nil?
-          data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
-        end
-      end
-            
+      
       @domain = URI.parse(old_url).host
       @cookies = cookies
     rescue AuthenticationError =&gt; m
@@ -97,7 +57,6 @@ class Contacts
     end
     
     def contacts(options = {})
-      return @contacts if @contacts
       if connected?
         url = URI.parse(contact_list_url)
         data, resp, cookies, forward = get( contact_list_url, @cookies )
@@ -105,75 +64,62 @@ class Contacts
         if resp.code_type != Net::HTTPOK
           raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
         end
-
-        # we have to click on the Export Contacts button to get the csv:
-        # Search the content for __VIEWSTATE or __EVENTVALIDATION
-        viewState = data.split(/&gt;\s*?&lt;/).grep(/__VIEWSTATE/).first[/value=\&quot;.+?\&quot;/][7..-2]
-        eventValidation = data.split(/&gt;\s*?&lt;/).grep(/__EVENTVALIDATION/).first[/value=\&quot;.+?\&quot;/][7..-2]
-        exportValue = data.split(/&gt;\s*?&lt;/).grep(/ctl02\$ExportButton/).first[/value=\&quot;.+?\&quot;/][7..-2]
-        mt = cookies.split(&quot;; &quot;).grep(/mt=/).first[3..-1]
         
-        # post back to the same url 
-        postdata = &quot;%s=%s&amp;%s=%s&amp;%s=%s&amp;%s=%s&quot; % [
-          &quot;__VIEWSTATE&quot;, CGI.escape(viewState),
-          &quot;__EVENTVALIDATION&quot;, CGI.escape(eventValidation),
-          CGI.escape(&quot;ctl02$ExportButton&quot;), CGI.escape(exportValue),
-          &quot;mt&quot;, CGI.escape( mt )
-        ]
-	
-        url = URI.parse(contact_list_url)
-        http = open_http(url)
-        resp, data = http.post(&quot;#{url.path}?#{url.query}&quot;, postdata,
-          &quot;User-Agent&quot; =&gt; &quot;Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0&quot;,
-          &quot;Accept-Encoding&quot; =&gt; &quot;gzip&quot;,
-          &quot;Cookie&quot; =&gt; cookies,
-          &quot;Referer&quot; =&gt; contact_list_url,
-          &quot;Content-Type&quot; =&gt; 'application/x-www-form-urlencoded'
-        )
-
-        data = uncompress(resp, data)
-        parse(data, options)
+        @contacts = []
+        build_contacts = []
+        go = true
+        index = 0
+        
+        while(go) do
+          go = false
+          url = URI.parse(get_contact_list_url(index))
+          http = open_http(url)
+          resp, data = http.get(get_contact_list_url(index), &quot;Cookie&quot; =&gt; @cookies)
+          
+          email_match_text_beginning = Regexp.escape(&quot;http://m.mail.live.com/?rru=compose&amp;amp;to=&quot;)
+          email_match_text_end = Regexp.escape(&quot;&amp;amp;&quot;)
+          
+          raw_html = resp.body.grep(/(?:e|dn)lk[0-9]+/)
+          raw_html.delete_at 0
+          raw_html.inject do |memo, row|
+            c_info = row.match(/(e|dn)lk([0-9])+/)
+            
+            # Same contact, or different?
+            build_contacts &lt;&lt; [] if memo != c_info[2]
+            
+            # Grab info
+            case c_info[1]
+              when &quot;e&quot; # Email
+                build_contacts.last[1] = row.match(/#{email_match_text_beginning}(.*)#{email_match_text_end}/)[1]
+              when &quot;dn&quot; # Name
+                build_contacts.last[0] = row.match(/&lt;a[^&gt;]*&gt;(.+)&lt;\/a&gt;/)[1]
+            end
+            
+            # Set memo to contact id
+            c_info[2]
+          end
+          
+          go = resp.body.include?(&quot;Next page&quot;)
+          index += 1
+        end
+        
+        build_contacts.each do |contact|
+          unless contact[1].nil?
+            # Only return contacts with email addresses
+            contact[1] = CGI::unescape(contact[1])
+            @contacts &lt;&lt; contact
+          end
+        end
+        return @contacts
       end
     end
-
-
-  private
     
-    def contact_list_url
-      NEWEST_CONTACT_LIST_URL % @domain
+    def get_contact_list_url(index) 
+      &quot;http://mpeople.live.com/default.aspx?pg=#{index}&quot;
     end
     
-    def follow_email(data, id, contacts_slot)
-      compose_url = COMPOSE_URL % @domain
-      postdata = &quot;HrsTest=&amp;to=#{id}&amp;mailto=1&amp;ref=addresses&quot;
-      postdata += &quot;&amp;curmbox=00000000-0000-0000-0000-000000000001&quot;
-
-      a = data.split(/&gt;\s*&lt;input\s+/i).grep(/\s+name=&quot;a&quot;/i)
-      return nil if a.empty?
-
-      a = a[0].match(/\s+value=&quot;([a-f0-9]+)&quot;/i) or return nil
-      postdata += &quot;&amp;a=#{a[1]}&quot;
-
-      data, resp, @cookies, forward = post(compose_url, postdata, @cookies)
-      e = data.split(/&gt;\s*&lt;input\s+/i).grep(/\s+name=&quot;to&quot;/i)
-      return nil if e.empty?
-
-      e = e[0].match(/\s+value=&quot;([^&quot;]+)&quot;/i) or return nil
-      @contacts[contacts_slot][1] = e[1] if e[1].match(/@/)
-    end
-
-    def parse(data, options={})
-      data = data.split(&quot;\r\n&quot;)
-      data = CSV.parse(data.join(&quot;\r\n&quot;).gsub('&quot;', '').gsub(';', ','), ';')
-      col_names = data.shift
-
-      @contacts = data.delete_if{|person|person[0].nil?}.map do |person|
-        person = person[0].split(&quot;,&quot;)
-        next unless (idx = person.index('SMTP'))
-        [[person[1], person[2], person[3]].delete_if{|i|i.empty?}.join(&quot; &quot;), person[idx - 1]] unless person[idx - 1].nil?
-      end.compact 
-    end
+    private
+    
+    TYPES[:hotmail] = Hotmail
   end
-
-  TYPES[:hotmail] = Hotmail
 end
\ No newline at end of file</diff>
      <filename>lib/contacts/hotmail.rb</filename>
    </modified>
    <modified>
      <diff>@@ -53,7 +53,7 @@ end # Contacts
 
 
 # sample contacts responses
-'
+=begin
 Bad email
 =========
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
@@ -119,5 +119,4 @@ Success
   &lt;editCounter&gt;3&lt;/editCounter&gt;
   
 &lt;/ns1:GetContactsResponse&gt;
-
-'
+=end
\ No newline at end of file</diff>
      <filename>lib/contacts/plaxo.rb</filename>
    </modified>
    <modified>
      <diff>@@ -32,6 +32,8 @@ class GmailContactImporterTest &lt; ContactImporterTestCase
 
   def test_fetch_contacts
     contacts = Contacts.new(:gmail, @account.username, @account.password).contacts
-    assert_equal @account.contacts, contacts
+    @account.contacts.each do |contact|
+      assert contacts.include?(contact), &quot;Could not find: #{contact.inspect} in #{contacts.inspect}&quot;
+    end
   end
 end
\ No newline at end of file</diff>
      <filename>test/unit/gmail_contact_importer_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -20,6 +20,8 @@ class HotmailContactImporterTest &lt; ContactImporterTestCase
 
   def test_fetch_contacts
     contacts = Contacts.new(:hotmail, @account.username, @account.password).contacts
-    assert_equal @account.contacts, contacts
+    @account.contacts.each do |contact|
+      assert contacts.include?(contact), &quot;Could not find: #{contact.inspect} in #{contacts.inspect}&quot;
+    end
   end
 end</diff>
      <filename>test/unit/hotmail_contact_importer_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -25,6 +25,8 @@ class YahooContactImporterTest &lt; ContactImporterTestCase
 
   def test_fetch_contacts
     contacts = Contacts.new(:yahoo, @account.username, @account.password).contacts
-    assert_equal @account.contacts, contacts
+    @account.contacts.each do |contact|
+      assert contacts.include?(contact), &quot;Could not find: #{contact.inspect} in #{contacts.inspect}&quot;
+    end
   end
 end
\ No newline at end of file</diff>
      <filename>test/unit/yahoo_csv_contact_importer_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>cedf6f38c8fee32e119bae4005799ef073015b8d</id>
    </parent>
  </parents>
  <author>
    <name>Lucas Carlson</name>
    <email>lucas@rufy.com</email>
  </author>
  <url>http://github.com/cardmagic/contacts/commit/727fe48335b64f89576096af779b02cb5ecf2e61</url>
  <id>727fe48335b64f89576096af779b02cb5ecf2e61</id>
  <committed-date>2009-07-11T01:30:22-07:00</committed-date>
  <authored-date>2009-07-11T01:30:22-07:00</authored-date>
  <message>Various fixes from giannichiappetta as well as cleaning up the unit tests and fixing a gmail authentication check</message>
  <tree>77878b77bc585038c1db1f4597fd2cbc2a34b72a</tree>
  <committer>
    <name>Lucas Carlson</name>
    <email>lucas@rufy.com</email>
  </committer>
</commit>
