Commit 3b0b3ff3f5cd54656a984408266cb99d2180c6de

Authored by Antonio Terceiro
1 parent 6544bc0a

ActionItem1049: embedding contacts 1.0.14

Doing this sucks, but I won't package it for Debian just for Noosfero.
Showing 24 changed files with 1086 additions and 1 deletions   Show diff stats
doc/README_FOR_APP.en
... ... @@ -30,7 +30,7 @@ There are Debian packages available for all of them but contacts. Try:
30 30  
31 31 # aptitude install subversion ruby rake libgettext-ruby1.8 libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby libwill-paginate-ruby iso-codes libfeedparser-ruby libferret-ruby mongrel mongrel-cluster tango-icon-theme
32 32  
33   -To install contacts, you need to either use gem (gem install contacts), or you can just download the tarball from github or rubyforge and copy the contents of lib/ under noosfero's lib/ directory.
  33 +contacts is bundled together with noosfero for now, so you don't need to install it.
34 34  
35 35 If you have problems with the setup, use the development mailing list. In
36 36 special its possible that the requirements list above is not complete.
... ...
lib/contacts 0 → 120000
... ... @@ -0,0 +1 @@
  1 +../vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/lib/contacts
0 2 \ No newline at end of file
... ...
lib/contacts.rb 0 → 120000
... ... @@ -0,0 +1 @@
  1 +../vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/lib/contacts.rb
0 2 \ No newline at end of file
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/.gitignore 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +.DS_Store
  2 +test/accounts.yml
0 3 \ No newline at end of file
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/LICENSE 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +Copyright (c) 2006, Lucas Carlson, MOG
  2 +All rights reserved.
  3 +
  4 +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
  5 +
  6 +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  7 +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  8 +Neither the name of the Lucas Carlson nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
  9 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  10 +
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/README 0 → 100644
... ... @@ -0,0 +1,43 @@
  1 +== Welcome to Contacts
  2 +
  3 +Contacts is a universal interface to grab contact list information from various providers including Hotmail, Gmail and Yahoo.
  4 +
  5 +== Download
  6 +
  7 +* gem install contacts
  8 +* http://rubyforge.org/projects/contacts
  9 +* svn co svn://rubyforge.org/var/svn/contacts
  10 +
  11 +== Background
  12 +
  13 +For a long time, the only way to get a list of contacts from your free online email accounts was with proprietary PHP scripts that would cost you $50. The act of grabbing that list is a simple matter of screen scrapping and this library gives you all the functionality you need. Thanks to the generosity of the highly popular Rails website MOG (http://mog.com) for allowing this library to be released open-source to the world. It is easy to extend this library to add new free email providers, so please contact the author if you would like to help.
  14 +
  15 +== Usage
  16 +
  17 + Contacts::Hotmail.new(login, password).contacts # => [["name", "foo@bar.com"], ["another name", "bow@wow.com"]]
  18 + Contacts::Yahoo.new(login, password).contacts
  19 + Contacts::Gmail.new(login, password).contacts
  20 +
  21 + Contacts.new(:gmail, login, password).contacts
  22 + Contacts.new(:hotmail, login, password).contacts
  23 + Contacts.new(:yahoo, login, password).contacts
  24 +
  25 + Contacts.guess(login, password).contacts
  26 +
  27 +Notice there are three ways to use this library so that you can limit the use as much as you would like in your particular application. The Contacts.guess method will automatically concatenate all the address book contacts from each of the successful logins in the case that a username password works across multiple services.
  28 +
  29 +== Examples
  30 +
  31 +See the examples/ directory.
  32 +
  33 +== Authors
  34 +
  35 +* Lucas Carlson from MOG (mailto:lucas@rufy.com) - http://mog.com
  36 +
  37 +== Contributors
  38 +
  39 +* Britt Selvitelle from Twitter (mailto:anotherbritt@gmail.com) - http://twitter.com
  40 +* Tony Targonski from GigPark (mailto:tony@gigpark.com) - http://gigpark.com
  41 +
  42 +This library is released under the terms of the BSD.
  43 +
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/Rakefile 0 → 100644
... ... @@ -0,0 +1,90 @@
  1 +require 'rubygems'
  2 +require 'rake'
  3 +require 'rake/testtask'
  4 +require 'rake/rdoctask'
  5 +require 'rake/gempackagetask'
  6 +require 'rake/contrib/rubyforgepublisher'
  7 +require 'lib/contacts'
  8 +
  9 +PKG_VERSION = Contacts::VERSION
  10 +
  11 +PKG_FILES = FileList[
  12 + "lib/**/*", "bin/*", "test/**/*", "[A-Z]*", "Rakefile", "doc/**/*", "examples/**/*"
  13 +]
  14 +
  15 +desc "Default Task"
  16 +task :default => [ :test ]
  17 +
  18 +# Run the unit tests
  19 +desc "Run all unit tests"
  20 +Rake::TestTask.new("test") { |t|
  21 + t.libs << "lib"
  22 + t.pattern = 'test/*/*_test.rb'
  23 + t.verbose = true
  24 +}
  25 +
  26 +# Make a console, useful when working on tests
  27 +desc "Generate a test console"
  28 +task :console do
  29 + verbose( false ) { sh "irb -I lib/ -r 'contacts'" }
  30 +end
  31 +
  32 +# Genereate the RDoc documentation
  33 +desc "Create documentation"
  34 +Rake::RDocTask.new("doc") { |rdoc|
  35 + rdoc.title = "Contact List - ridiculously easy contact list information from various providers including Yahoo, Gmail, and Hotmail"
  36 + rdoc.rdoc_dir = 'doc'
  37 + rdoc.rdoc_files.include('README')
  38 + rdoc.rdoc_files.include('lib/**/*.rb')
  39 +}
  40 +
  41 +# Genereate the package
  42 +spec = Gem::Specification.new do |s|
  43 +
  44 + #### Basic information.
  45 +
  46 + s.name = 'contacts'
  47 + s.version = PKG_VERSION
  48 + s.summary = <<-EOF
  49 + Ridiculously easy contact list information from various providers including Yahoo, Gmail, and Hotmail
  50 + EOF
  51 + s.description = <<-EOF
  52 + Ridiculously easy contact list information from various providers including Yahoo, Gmail, and Hotmail
  53 + EOF
  54 +
  55 + #### Which files are to be included in this gem? Everything! (Except CVS directories.)
  56 +
  57 + s.files = PKG_FILES
  58 +
  59 + #### Load-time details: library and application (you will need one or both).
  60 +
  61 + s.require_path = 'lib'
  62 + s.autorequire = 'contacts'
  63 +
  64 + s.add_dependency('json', '>= 0.4.1')
  65 + s.requirements << "A json parser"
  66 +
  67 + #### Documentation and testing.
  68 +
  69 + s.has_rdoc = true
  70 +
  71 + #### Author and project details.
  72 +
  73 + s.author = "Lucas Carlson"
  74 + s.email = "lucas@rufy.com"
  75 + s.homepage = "http://rubyforge.org/projects/contacts"
  76 +end
  77 +
  78 +Rake::GemPackageTask.new(spec) do |pkg|
  79 + pkg.need_zip = true
  80 + pkg.need_tar = true
  81 +end
  82 +
  83 +desc "Report code statistics (KLOCs, etc) from the application"
  84 +task :stats do
  85 + require 'code_statistics'
  86 + CodeStatistics.new(
  87 + ["Library", "lib"],
  88 + ["Units", "test"]
  89 + ).to_s
  90 +end
0 91 \ No newline at end of file
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/contacts.gemspec 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +Gem::Specification.new do |s|
  2 + s.name = "contacts"
  3 + s.version = "1.0.14"
  4 + s.date = "2009-05-06"
  5 + s.summary = "A universal interface to grab contact list information from various providers including Yahoo, Gmail, Hotmail, and Plaxo."
  6 + s.email = "lucas@rufy.com"
  7 + s.homepage = "http://github.com/cardmagic/contacts"
  8 + s.description = "A universal interface to grab contact list information from various providers including Yahoo, Gmail, Hotmail, and Plaxo."
  9 + s.has_rdoc = false
  10 + s.authors = ["Lucas Carlson"]
  11 + s.files = ["LICENSE", "Rakefile", "README", "examples/grab_contacts.rb", "lib/contacts.rb", "lib/contacts/base.rb", "lib/contacts/gmail.rb", "lib/contacts/hotmail.rb", "lib/contacts/plaxo.rb", "lib/contacts/yahoo.rb"]
  12 + s.add_dependency("json", [">= 1.1.1"])
  13 +end
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/cruise_config.rb 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +# Project-specific configuration for CruiseControl.rb
  2 +
  3 +Project.configure do |project|
  4 +
  5 + # Send email notifications about broken and fixed builds to email1@your.site, email2@your.site (default: send to nobody)
  6 + # if building this on your own CI box, please remove!
  7 + project.email_notifier.emails = ['opensource@pivotallabs.com']
  8 +
  9 + # Set email 'from' field to john@doe.com:
  10 + # project.email_notifier.from = 'john@doe.com'
  11 +
  12 + # Build the project by invoking rake task 'custom'
  13 + # project.rake_task = 'custom'
  14 +
  15 + # Build the project by invoking shell script "build_my_app.sh". Keep in mind that when the script is invoked, current working directory is
  16 + # [cruise]/projects/your_project/work, so if you do not keep build_my_app.sh in version control, it should be '../build_my_app.sh' instead
  17 + # project.build_command = 'build_my_app.sh'
  18 +
  19 + # Ping Subversion for new revisions every 5 minutes (default: 30 seconds)
  20 + # project.scheduler.polling_interval = 5.minutes
  21 +
  22 +end
0 23 \ No newline at end of file
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/examples/grab_contacts.rb 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +require File.dirname(__FILE__)+"/../lib/contacts"
  2 +
  3 +login = ARGV[0]
  4 +password = ARGV[1]
  5 +
  6 +Contacts::Gmail.new(login, password).contacts
  7 +
  8 +Contacts.new(:gmail, login, password).contacts
  9 +
  10 +Contacts.new("gmail", login, password).contacts
  11 +
  12 +Contacts.guess(login, password).contacts
0 13 \ No newline at end of file
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/geminstaller.yml 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +---
  2 +defaults:
  3 + install_options: --no-ri --no-rdoc
  4 +gems:
  5 + - name: json
  6 + version: >= 1.1.1
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/lib/contacts.rb 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +$:.unshift(File.dirname(__FILE__)+"/contacts/")
  2 +
  3 +require 'rubygems'
  4 +require 'base'
  5 +require 'gmail'
  6 +require 'hotmail'
  7 +require 'yahoo'
  8 +require 'plaxo'
0 9 \ No newline at end of file
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/lib/contacts/base.rb 0 → 100644
... ... @@ -0,0 +1,210 @@
  1 +require "cgi"
  2 +require "net/http"
  3 +require "net/https"
  4 +require "uri"
  5 +require "zlib"
  6 +require "stringio"
  7 +require "thread"
  8 +
  9 +class Contacts
  10 + TYPES = {}
  11 + VERSION = "1.0.13"
  12 +
  13 + class Base
  14 + def initialize(login, password)
  15 + @login = login
  16 + @password = password
  17 + @connections = {}
  18 + connect
  19 + end
  20 +
  21 + def connect
  22 + raise AuthenticationError, "Login and password must not be nil, login: #{@login.inspect}, password: #{@password.inspect}" if @login.nil? || @password.nil?
  23 + real_connect
  24 + end
  25 +
  26 + def connected?
  27 + @cookies && !@cookies.empty?
  28 + end
  29 +
  30 + def contacts(options = {})
  31 + return @contacts if @contacts
  32 + if connected?
  33 + url = URI.parse(contact_list_url)
  34 + http = open_http(url)
  35 + resp, data = http.get("#{url.path}?#{url.query}",
  36 + "Cookie" => @cookies
  37 + )
  38 +
  39 + if resp.code_type != Net::HTTPOK
  40 + raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
  41 + end
  42 +
  43 + parse(data, options)
  44 + end
  45 + end
  46 +
  47 + def login
  48 + @attempt ||= 0
  49 + @attempt += 1
  50 +
  51 + if @attempt == 1
  52 + @login
  53 + else
  54 + if @login.include?("@#{domain}")
  55 + @login.sub("@#{domain}","")
  56 + else
  57 + "#{@login}@#{domain}"
  58 + end
  59 + end
  60 + end
  61 +
  62 + def password
  63 + @password
  64 + end
  65 +
  66 + private
  67 +
  68 + def domain
  69 + @d ||= URI.parse(self.class.const_get(:URL)).host.sub(/^www\./,'')
  70 + end
  71 +
  72 + def contact_list_url
  73 + self.class.const_get(:CONTACT_LIST_URL)
  74 + end
  75 +
  76 + def address_book_url
  77 + self.class.const_get(:ADDRESS_BOOK_URL)
  78 + end
  79 +
  80 + def open_http(url)
  81 + c = @connections[Thread.current.object_id] ||= {}
  82 + http = c["#{url.host}:#{url.port}"]
  83 + unless http
  84 + http = Net::HTTP.new(url.host, url.port)
  85 + if url.port == 443
  86 + http.use_ssl = true
  87 + http.verify_mode = OpenSSL::SSL::VERIFY_NONE
  88 + end
  89 + c["#{url.host}:#{url.port}"] = http
  90 + end
  91 + http.start unless http.started?
  92 + http
  93 + end
  94 +
  95 + def parse_cookies(data, existing="")
  96 + return existing if data.nil?
  97 +
  98 + cookies = existing.split(";").map{|i|i.split("=", 2).map{|j|j.strip}}.inject({}){|h,i|h[i[0]]=i[1];h}
  99 +
  100 + data.gsub!(/ ?[\w]+=EXPIRED;/,'')
  101 + data.gsub!(/ ?expires=(.*?, .*?)[;,$]/i, ';')
  102 + data.gsub!(/ ?(domain|path)=[\S]*?[;,$]/i,';')
  103 + data.gsub!(/[,;]?\s*(secure|httponly)/i,'')
  104 + data.gsub!(/(;\s*){2,}/,', ')
  105 + data.gsub!(/(,\s*){2,}/,', ')
  106 + data.sub!(/^,\s*/,'')
  107 + data.sub!(/\s*,$/,'')
  108 +
  109 + data.split(", ").map{|t|t.to_s.split(";").first}.each do |data|
  110 + k, v = data.split("=", 2).map{|j|j.strip}
  111 + if cookies[k] && v.empty?
  112 + cookies.delete(k)
  113 + elsif v && !v.empty?
  114 + cookies[k] = v
  115 + end
  116 + end
  117 +
  118 + cookies.map{|k,v| "#{k}=#{v}"}.join("; ")
  119 + end
  120 +
  121 + def remove_cookie(cookie, cookies)
  122 + parse_cookies("#{cookie}=", cookies)
  123 + end
  124 +
  125 + def post(url, postdata, cookies="", referer="")
  126 + url = URI.parse(url)
  127 + http = open_http(url)
  128 + resp, data = http.post(url.path, postdata,
  129 + "User-Agent" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0",
  130 + "Accept-Encoding" => "gzip",
  131 + "Cookie" => cookies,
  132 + "Referer" => referer,
  133 + "Content-Type" => 'application/x-www-form-urlencoded'
  134 + )
  135 + data = uncompress(resp, data)
  136 + cookies = parse_cookies(resp.response['set-cookie'], cookies)
  137 + forward = resp.response['Location']
  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
  142 + return data, resp, cookies, forward
  143 + end
  144 +
  145 + def get(url, cookies="", referer="")
  146 + url = URI.parse(url)
  147 + http = open_http(url)
  148 + resp, data = http.get("#{url.path}?#{url.query}",
  149 + "User-Agent" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0",
  150 + "Accept-Encoding" => "gzip",
  151 + "Cookie" => cookies,
  152 + "Referer" => referer
  153 + )
  154 + data = uncompress(resp, data)
  155 + cookies = parse_cookies(resp.response['set-cookie'], cookies)
  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
  160 + return data, resp, cookies, forward
  161 + end
  162 +
  163 + def uncompress(resp, data)
  164 + case resp.response['content-encoding']
  165 + when 'gzip':
  166 + gz = Zlib::GzipReader.new(StringIO.new(data))
  167 + data = gz.read
  168 + gz.close
  169 + resp.response['content-encoding'] = nil
  170 + # FIXME: Not sure what Hotmail was feeding me with their 'deflate',
  171 + # but the headers definitely were not right
  172 + when 'deflate':
  173 + data = Zlib::Inflate.inflate(data)
  174 + resp.response['content-encoding'] = nil
  175 + end
  176 +
  177 + data
  178 + end
  179 + end
  180 +
  181 + class ContactsError < StandardError
  182 + end
  183 +
  184 + class AuthenticationError < ContactsError
  185 + end
  186 +
  187 + class ConnectionError < ContactsError
  188 + end
  189 +
  190 + class TypeNotFound < ContactsError
  191 + end
  192 +
  193 + def self.new(type, login, password)
  194 + if TYPES.include?(type.to_s.intern)
  195 + TYPES[type.to_s.intern].new(login, password)
  196 + else
  197 + raise TypeNotFound, "#{type.inspect} is not a valid type, please choose one of the following: #{TYPES.keys.inspect}"
  198 + end
  199 + end
  200 +
  201 + def self.guess(login, password)
  202 + TYPES.inject([]) do |a, t|
  203 + begin
  204 + a + t[1].new(login, password).contacts
  205 + rescue AuthenticationError
  206 + a
  207 + end
  208 + end.uniq
  209 + end
  210 +end
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/lib/contacts/gmail.rb 0 → 100644
... ... @@ -0,0 +1,94 @@
  1 +begin
  2 + # If the json gem is available, use it
  3 + require "json/add/rails"
  4 +rescue MissingSourceFile
  5 + # Otherwise wrap the ActiveSupport JSON implementation for our simple use case
  6 + class JSON
  7 + def self.parse(i)
  8 + ActiveSupport::JSON.decode(i)
  9 + end
  10 + end
  11 +end
  12 +
  13 +class Contacts
  14 + class Gmail < Base
  15 + URL = "https://mail.google.com/mail/"
  16 + LOGIN_URL = "https://www.google.com/accounts/ServiceLoginAuth"
  17 + LOGIN_REFERER_URL = "https://www.google.com/accounts/ServiceLogin?service=mail&passive=true&rm=false&continue=http%3A%2F%2Fmail.google.com%2Fmail%3Fui%3Dhtml%26zy%3Dl&ltmpl=yj_blanco&ltmplcache=2&hl=en"
  18 + CONTACT_LIST_URL = "https://mail.google.com/mail/contacts/data/contacts?thumb=true&show=ALL&enums=true&psort=Name&max=10000&out=js&rf=&jsx=true"
  19 + PROTOCOL_ERROR = "Gmail 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"
  20 +
  21 + def real_connect
  22 + postdata = "ltmpl=yj_blanco"
  23 + postdata += "&continue=%s" % CGI.escape(URL)
  24 + postdata += "&ltmplcache=2"
  25 + postdata += "&service=mail"
  26 + postdata += "&rm=false"
  27 + postdata += "&ltmpl=yj_blanco"
  28 + postdata += "&hl=en"
  29 + postdata += "&Email=%s" % CGI.escape(login)
  30 + postdata += "&Passwd=%s" % CGI.escape(password)
  31 + postdata += "&rmShown=1"
  32 + postdata += "&null=Sign+in"
  33 +
  34 + time = Time.now.to_i
  35 + time_past = Time.now.to_i - 8 - rand(12)
  36 + cookie = "GMAIL_LOGIN=T#{time_past}/#{time_past}/#{time}"
  37 +
  38 + data, resp, cookies, forward, old_url = post(LOGIN_URL, postdata, cookie, LOGIN_REFERER_URL) + [LOGIN_URL]
  39 +
  40 + cookies = remove_cookie("GMAIL_LOGIN", cookies)
  41 +
  42 + if data.index("Username and password do not match")
  43 + raise AuthenticationError, "Username and password do not match"
  44 + elsif data.index("The username or password you entered is incorrect")
  45 + raise AuthenticationError, "Username and password do not match"
  46 + elsif data.index("Required field must not be blank")
  47 + raise AuthenticationError, "Login and password must not be blank"
  48 + elsif data.index("errormsg_0_logincaptcha")
  49 + raise AuthenticationError, "Captcha error"
  50 + elsif data.index("Invalid request")
  51 + raise ConnectionError, PROTOCOL_ERROR
  52 + elsif cookies == ""
  53 + raise ConnectionError, PROTOCOL_ERROR
  54 + end
  55 +
  56 + cookies = remove_cookie("LSID", cookies)
  57 + cookies = remove_cookie("GV", cookies)
  58 +
  59 + @cookies = cookies
  60 + end
  61 +
  62 + private
  63 +
  64 + def parse(data, options)
  65 + data.gsub!(/^while \(true\); &&&START&&&/, '')
  66 + data.gsub!(/ &&&END&&&$/, '')
  67 + data.gsub!(/\t/, ' ') # tabs in the note field cause errors with JSON.parse
  68 + data.gsub!(/[\t\x00-\x1F]/, " ") # strip control characters
  69 +
  70 + @contacts = JSON.parse(data)['Body']['Contacts'] || {}
  71 +
  72 + # Determine in which format to return the data.
  73 +
  74 + # Return the full JSON Hash.
  75 + return @contacts if(options[:details])
  76 +
  77 + # Default format.
  78 + # ['Name', 'Email1', 'Email2', ...]
  79 + if @contacts != nil
  80 + @contacts = @contacts.delete_if {|c| c["Emails"].nil?}.map do |c|
  81 + name, emails = c.values_at "Name", "Emails"
  82 + # emails are returned in a form of
  83 + # [{"Address"=>"home.email@gmail.com"}, {"Type"=>{"Id"=>"WORK"}, "Address"=>"work.email@gmail.com"}]
  84 + emails = emails.collect{|a| a.values_at("Address")}
  85 + [name, emails].flatten
  86 + end
  87 + else
  88 + []
  89 + end
  90 + end
  91 + end
  92 +
  93 + TYPES[:gmail] = Gmail
  94 +end
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/lib/contacts/hotmail.rb 0 → 100644
... ... @@ -0,0 +1,179 @@
  1 +class Contacts
  2 + class Hotmail < Base
  3 + URL = "http://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 + NEWEST_CONTACT_LIST_URL = "http://%s/mail/options.aspx?subsection=26"
  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 +
  15 + old_url = URL
  16 + until forward.nil?
  17 + data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
  18 + end
  19 +
  20 + postdata = "PPSX=%s&PwdPad=%s&login=%s&passwd=%s&LoginOptions=2&PPFT=%s" % [
  21 + CGI.escape(data.split("><").grep(/PPSX/).first[/=\S+$/][2..-3]),
  22 + PWDPAD[0...(PWDPAD.length-@password.length)],
  23 + CGI.escape(login),
  24 + CGI.escape(password),
  25 + CGI.escape(data.split("><").grep(/PPFT/).first[/=\S+$/][2..-3])
  26 + ]
  27 +
  28 + form_url = data.split("><").grep(/form/).first.split[5][8..-2]
  29 + data, resp, cookies, forward = post(form_url, postdata, cookies)
  30 +
  31 + if data.index("The e-mail address or password is incorrect")
  32 + raise AuthenticationError, "Username and password do not match"
  33 + elsif data != ""
  34 + raise AuthenticationError, "Required field must not be blank"
  35 + elsif cookies == ""
  36 + raise ConnectionError, PROTOCOL_ERROR
  37 + end
  38 +
  39 + old_url = form_url
  40 + until forward.nil?
  41 + data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
  42 + end
  43 +
  44 +=begin
  45 + if data =~ %r{action="(.*?)"}
  46 + forward = $1
  47 + puts forward
  48 + napexp = CGI.escape(data.to_s[/id="NAPExp" value="(.*?)"/][19...-1])
  49 + nap = CGI.escape(data.to_s[/id="NAP" value="(.*?)"/][16...-1])
  50 + anon = CGI.escape(data.to_s[/id="ANON" value="(.*?)"/][17...-1])
  51 + anonexp = CGI.escape(data.to_s[/id="ANONExp" value="(.*?)"/][20...-1])
  52 + t = CGI.escape(data.to_s[/id="t" value="(.*?)"/][14...-1])
  53 +
  54 + postdata = "NAPExp=%s&NAP=%s&ANON=%s&ANONExp=%s&t=%s" % [ napexp, nap, anon, anonexp, t ]
  55 + puts postdata
  56 + data, resp, cookies, forward, old_url = post(forward, postdata, cookies, old_url) + [forward]
  57 + end
  58 +
  59 + until forward.nil?
  60 + data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
  61 + end
  62 +=end
  63 +
  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
  90 + @cookies = cookies
  91 + rescue AuthenticationError => m
  92 + if @attempt == 1
  93 + retry
  94 + else
  95 + raise m
  96 + end
  97 + end
  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 +
  140 + private
  141 +
  142 + def contact_list_url
  143 + NEWEST_CONTACT_LIST_URL % @domain
  144 + end
  145 +
  146 + def follow_email(data, id, contacts_slot)
  147 + compose_url = COMPOSE_URL % @domain
  148 + postdata = "HrsTest=&to=#{id}&mailto=1&ref=addresses"
  149 + postdata += "&curmbox=00000000-0000-0000-0000-000000000001"
  150 +
  151 + a = data.split(/>\s*<input\s+/i).grep(/\s+name="a"/i)
  152 + return nil if a.empty?
  153 +
  154 + a = a[0].match(/\s+value="([a-f0-9]+)"/i) or return nil
  155 + postdata += "&a=#{a[1]}"
  156 +
  157 + data, resp, @cookies, forward = post(compose_url, postdata, @cookies)
  158 + e = data.split(/>\s*<input\s+/i).grep(/\s+name="to"/i)
  159 + return nil if e.empty?
  160 +
  161 + e = e[0].match(/\s+value="([^"]+)"/i) or return nil
  162 + @contacts[contacts_slot][1] = e[1] if e[1].match(/@/)
  163 + end
  164 +
  165 + def parse(data, options={})
  166 + data = data.split("\r\n")
  167 + data = CSV.parse(data.join("\r\n").gsub('"', '').gsub(';', ','), ';')
  168 + col_names = data.shift
  169 +
  170 + @contacts = data.delete_if{|person|person[0].nil?}.map do |person|
  171 + person = person[0].split(",")
  172 + next unless (idx = person.index('SMTP'))
  173 + [[person[1], person[2], person[3]].delete_if{|i|i.empty?}.join(" "), person[idx - 1]] unless person[idx - 1].nil?
  174 + end.compact
  175 + end
  176 + end
  177 +
  178 + TYPES[:hotmail] = Hotmail
  179 +end
0 180 \ No newline at end of file
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/lib/contacts/plaxo.rb 0 → 100644
... ... @@ -0,0 +1,123 @@
  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 = cont.elements['fullName'].nil? ? cont.elements['displayName'].text : cont.elements['fullName'].text
  38 + email = cont.elements['email1'].text
  39 + @contacts << [name, email]
  40 + end.compact
  41 + @contacts
  42 + else
  43 + raise ConnectionError, PROTOCOL_ERROR
  44 + end
  45 +
  46 + end # parse
  47 +
  48 + end # Plaxo
  49 +
  50 + TYPES[:plaxo] = Plaxo
  51 +
  52 +end # Contacts
  53 +
  54 +
  55 +# sample contacts responses
  56 +'
  57 +Bad email
  58 +=========
  59 +<?xml version="1.0" encoding="utf-8" ?>
  60 +<ns1:GetContactsResponse xmlns:ns1="Plaxo">
  61 + <response>
  62 + <code>401</code>
  63 + <subCode>1</subCode>
  64 + <message>User not found.</message>
  65 + </response>
  66 +</ns1:GetContactsResponse>
  67 +
  68 +
  69 +Bad password
  70 +============
  71 +<?xml version="1.0" encoding="utf-8" ?>
  72 +<ns1:GetContactsResponse xmlns:ns1="Plaxo">
  73 + <response>
  74 + <code>401</code>
  75 + <subCode>4</subCode>
  76 + <message>Bad password or security token.</message>
  77 + </response>
  78 +</ns1:GetContactsResponse>
  79 +
  80 +
  81 +Success
  82 +=======
  83 +<?xml version="1.0" encoding="utf-8" ?>
  84 +<ns1:GetContactsResponse xmlns:ns1="Plaxo">
  85 +
  86 + <response>
  87 + <code>200</code>
  88 + <message>OK</message>
  89 + <userId>77311236242</userId>
  90 + </response>
  91 +
  92 + <contacts>
  93 +
  94 + <contact>
  95 + <itemId>61312569</itemId>
  96 + <displayName>Joe Blow1</displayName>
  97 + <fullName>Joe Blow1</fullName>
  98 + <firstName>Joe</firstName>
  99 + <lastName>Blow1</lastName>
  100 + <homeEmail1>joeblow1@mailinator.com</homeEmail1>
  101 + <email1>joeblow1@mailinator.com</email1>
  102 + <folderId>5291351</folderId>
  103 + </contact>
  104 +
  105 + <contact>
  106 + <itemId>61313159</itemId>
  107 + <displayName>Joe Blow2</displayName>
  108 + <fullName>Joe Blow2</fullName>
  109 + <firstName>Joe</firstName>
  110 + <lastName>Blow2</lastName>
  111 + <homeEmail1>joeblow2@mailinator.com</homeEmail1>
  112 + <email1>joeblow2@mailinator.com</email1>
  113 + <folderId>5291351</folderId>
  114 + </contact>
  115 +
  116 + </contacts>
  117 +
  118 + <totalCount>2</totalCount>
  119 + <editCounter>3</editCounter>
  120 +
  121 +</ns1:GetContactsResponse>
  122 +
  123 +'
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/lib/contacts/yahoo.rb 0 → 100644
... ... @@ -0,0 +1,82 @@
  1 +require 'csv'
  2 +
  3 +class Contacts
  4 + class Yahoo < Base
  5 + URL = "http://mail.yahoo.com/"
  6 + LOGIN_URL = "https://login.yahoo.com/config/login"
  7 + ADDRESS_BOOK_URL = "http://address.mail.yahoo.com/?1&VPC=import_export"
  8 + CONTACT_LIST_URL = "http://address.yahoo.com/index.php?VPC=import_export&A=B&submit[action_export_yahoo]=Export%20Now"
  9 + 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"
  10 +
  11 + def real_connect
  12 + postdata = ".tries=2&.src=ym&.md5=&.hash=&.js=&.last=&promo=&.intl=us&.bypass="
  13 + postdata += "&.partner=&.u=4eo6isd23l8r3&.v=0&.challenge=gsMsEcoZP7km3N3NeI4mX"
  14 + postdata += "kGB7zMV&.yplus=&.emailCode=&pkg=&stepid=&.ev=&hasMsgr=1&.chkP=Y&."
  15 + postdata += "done=#{CGI.escape(URL)}&login=#{CGI.escape(login)}&passwd=#{CGI.escape(password)}"
  16 +
  17 + data, resp, cookies, forward = post(LOGIN_URL, postdata)
  18 +
  19 + if data.index("Invalid ID or password") || data.index("This ID is not yet taken")
  20 + raise AuthenticationError, "Username and password do not match"
  21 + elsif data.index("Sign in") && data.index("to Yahoo!")
  22 + raise AuthenticationError, "Required field must not be blank"
  23 + elsif !data.match(/uncompressed\/chunked/)
  24 + raise ConnectionError, PROTOCOL_ERROR
  25 + elsif cookies == ""
  26 + raise ConnectionError, PROTOCOL_ERROR
  27 + end
  28 +
  29 + data, resp, cookies, forward = get(forward, cookies, LOGIN_URL)
  30 +
  31 + if resp.code_type != Net::HTTPOK
  32 + raise ConnectionError, PROTOCOL_ERROR
  33 + end
  34 +
  35 + @cookies = cookies
  36 + end
  37 +
  38 + def contacts
  39 + return @contacts if @contacts
  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[/id="crumb2" value="(.*?)"/][19...-1]
  53 +
  54 + # now proceed with the new ".crumb" parameter to get the csv data
  55 + url = URI.parse("#{contact_list_url}&.crumb=#{crumb}")
  56 + http = open_http(url)
  57 + resp, data = http.get("#{url.path}?#{url.query}",
  58 + "Cookie" => @cookies
  59 + )
  60 +
  61 + if resp.code_type != Net::HTTPOK
  62 + raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
  63 + end
  64 +
  65 + parse data
  66 + end
  67 + end
  68 +
  69 + private
  70 +
  71 + def parse(data, options={})
  72 + data = CSV.parse(data)
  73 + col_names = data.shift
  74 + @contacts = data.map do |person|
  75 + [[person[0], person[1], person[2]].delete_if{|i|i.empty?}.join(" "), person[4]] unless person[4].empty?
  76 + end.compact
  77 + end
  78 +
  79 + end
  80 +
  81 + TYPES[:yahoo] = Yahoo
  82 +end
0 83 \ No newline at end of file
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/test/example_accounts.yml 0 → 100644
... ... @@ -0,0 +1,40 @@
  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"
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/test/test_helper.rb 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +dir = File.dirname(__FILE__)
  2 +$LOAD_PATH.unshift(dir + "/../lib/")
  3 +require 'test/unit'
  4 +require 'contacts'
  5 +
  6 +class ContactImporterTestCase < Test::Unit::TestCase
  7 + # Add more helper methods to be used by all tests here...
  8 + def default_test
  9 + assert true
  10 + end
  11 +end
  12 +
  13 +class TestAccounts
  14 + def self.[](type)
  15 + load[type]
  16 + end
  17 +
  18 + def self.load(file = File.dirname(__FILE__) + "/accounts.yml")
  19 + raise "/test/accounts.yml file not found, please create, see /test/example_accounts.yml for information" unless File.exist?(file)
  20 +
  21 + accounts = {}
  22 + YAML::load(File.open(file)).each do |type, contents|
  23 + contacts = contents["contacts"].collect {|contact| [contact["name"], contact["email_address"]]}
  24 + accounts[type.to_sym] = Account.new(type.to_sym, contents["username"], contents["password"], contacts)
  25 + end
  26 + accounts
  27 + end
  28 +
  29 + Account = Struct.new :type, :username, :password, :contacts
  30 +end
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/test/test_suite.rb 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +dir = File.dirname(__FILE__)
  2 +Dir["#{dir}/**/*_test.rb"].each do |file|
  3 + require file
  4 +end
0 5 \ No newline at end of file
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/test/unit/gmail_contact_importer_test.rb 0 → 100644
... ... @@ -0,0 +1,37 @@
  1 +dir = File.dirname(__FILE__)
  2 +require "#{dir}/../test_helper"
  3 +require 'contacts'
  4 +
  5 +class GmailContactImporterTest < ContactImporterTestCase
  6 + def setup
  7 + super
  8 + @account = TestAccounts[:gmail]
  9 + end
  10 +
  11 + def test_successful_login
  12 + Contacts.new(:gmail, @account.username, @account.password)
  13 + end
  14 +
  15 + def test_importer_fails_with_invalid_password
  16 + assert_raise(Contacts::AuthenticationError) do
  17 + Contacts.new(:gmail, @account.username, "wrong_password")
  18 + end
  19 + end
  20 +
  21 + def test_importer_fails_with_blank_password
  22 + assert_raise(Contacts::AuthenticationError) do
  23 + Contacts.new(:gmail, @account.username, "")
  24 + end
  25 + end
  26 +
  27 + def test_importer_fails_with_blank_username
  28 + assert_raise(Contacts::AuthenticationError) do
  29 + Contacts.new(:gmail, "", @account.password)
  30 + end
  31 + end
  32 +
  33 + def test_fetch_contacts
  34 + contacts = Contacts.new(:gmail, @account.username, @account.password).contacts
  35 + assert_equal @account.contacts, contacts
  36 + end
  37 +end
0 38 \ No newline at end of file
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/test/unit/hotmail_contact_importer_test.rb 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +dir = File.dirname(__FILE__)
  2 +require "#{dir}/../test_helper"
  3 +require 'contacts'
  4 +
  5 +class HotmailContactImporterTest < ContactImporterTestCase
  6 + def setup
  7 + super
  8 + @account = TestAccounts[:hotmail]
  9 + end
  10 +
  11 + def test_successful_login
  12 + Contacts.new(:hotmail, @account.username, @account.password)
  13 + end
  14 +
  15 + def test_importer_fails_with_invalid_password
  16 + assert_raise(Contacts::AuthenticationError) do
  17 + Contacts.new(:hotmail, @account.username,"wrong_password")
  18 + end
  19 + end
  20 +
  21 + def test_fetch_contacts
  22 + contacts = Contacts.new(:hotmail, @account.username, @account.password).contacts
  23 + assert_equal @account.contacts, contacts
  24 + end
  25 +end
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/test/unit/test_accounts_test.rb 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +dir = File.dirname(__FILE__)
  2 +require "#{dir}/../test_helper"
  3 +
  4 +class TestAccountsTest < ContactImporterTestCase
  5 + def test_test_accounts_loads_data_from_example_accounts_file
  6 + account = TestAccounts.load(File.dirname(__FILE__) + "/../example_accounts.yml")[:gmail]
  7 +
  8 + assert_equal :gmail, account.type
  9 + assert_equal "<changeme>", account.username
  10 + assert_equal "<changeme>", account.password
  11 + assert_equal [["FirstName1 LastName1", "firstname1@example.com"], ["FirstName2 LastName2", "firstname2@example.com"]], account.contacts
  12 + end
  13 +
  14 + def test_test_accounts_blows_up_if_file_doesnt_exist
  15 + assert_raise(RuntimeError) do
  16 + TestAccounts.load("file_that_does_not_exist.yml")
  17 + end
  18 + end
  19 +
  20 + def test_we_can_load_from_account_file
  21 + assert_not_nil TestAccounts[:gmail].username
  22 + end
  23 +end
0 24 \ No newline at end of file
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/test/unit/yahoo_csv_contact_importer_test.rb 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +dir = File.dirname(__FILE__)
  2 +require "#{dir}/../test_helper"
  3 +require 'contacts'
  4 +
  5 +class YahooContactImporterTest < ContactImporterTestCase
  6 + def setup
  7 + super
  8 + @account = TestAccounts[:yahoo]
  9 + end
  10 +
  11 + def test_successful_login
  12 + Contacts.new(:yahoo, @account.username, @account.password)
  13 + end
  14 +
  15 + def test_importer_fails_with_invalid_password
  16 + assert_raise(Contacts::AuthenticationError) do
  17 + Contacts.new(:yahoo, @account.username,"wrong_password")
  18 + end
  19 + # run the "successful" login test to ensure we reset yahoo's failed login lockout counter
  20 + # See http://www.pivotaltracker.com/story/show/138210
  21 + assert_nothing_raised do
  22 + Contacts.new(:yahoo, @account.username, @account.password)
  23 + end
  24 + end
  25 +
  26 + def test_fetch_contacts
  27 + contacts = Contacts.new(:yahoo, @account.username, @account.password).contacts
  28 + assert_equal @account.contacts, contacts
  29 + end
  30 +end
0 31 \ No newline at end of file
... ...