alexjp-blackbook_csv 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/CHANGES.markdown +44 -0
  2. data/Manifest.txt +59 -0
  3. data/README.markdown +72 -0
  4. data/Rakefile +39 -0
  5. data/debug_blackbook.rb +10 -0
  6. data/init.rb +1 -0
  7. data/lib/blackbook/exporter/base.rb +16 -0
  8. data/lib/blackbook/exporter/vcf.rb +45 -0
  9. data/lib/blackbook/exporter/xml.rb +28 -0
  10. data/lib/blackbook/importer/aol.rb +83 -0
  11. data/lib/blackbook/importer/base.rb +39 -0
  12. data/lib/blackbook/importer/csv.rb +87 -0
  13. data/lib/blackbook/importer/gmail.rb +66 -0
  14. data/lib/blackbook/importer/hotmail.rb +124 -0
  15. data/lib/blackbook/importer/page_scraper.rb +86 -0
  16. data/lib/blackbook/importer/yahoo.rb +61 -0
  17. data/lib/blackbook.rb +76 -0
  18. data/test/fixtures/aol_application_page.html +566 -0
  19. data/test/fixtures/aol_bad_login_response_stage_3.html +565 -0
  20. data/test/fixtures/aol_contacts.html +90 -0
  21. data/test/fixtures/aol_login_response_stage_1.html +158 -0
  22. data/test/fixtures/aol_login_response_stage_2.html +559 -0
  23. data/test/fixtures/aol_login_response_stage_3.html +61 -0
  24. data/test/fixtures/aol_login_response_stage_4.html +48 -0
  25. data/test/fixtures/aol_login_response_stage_5.html +404 -0
  26. data/test/fixtures/aol_new_contacts.html +431 -0
  27. data/test/fixtures/gmail.csv +3 -0
  28. data/test/fixtures/gmail_bad_login_response_stage_2.html +560 -0
  29. data/test/fixtures/gmail_contacts.html +228 -0
  30. data/test/fixtures/gmail_login_response_stage_1.html +556 -0
  31. data/test/fixtures/gmail_login_response_stage_2.html +1 -0
  32. data/test/fixtures/gmail_login_response_stage_2a.html +1 -0
  33. data/test/fixtures/gmail_login_response_stage_3.html +249 -0
  34. data/test/fixtures/hotmail_bad_login_response_stage_2.html +31 -0
  35. data/test/fixtures/hotmail_contacts.html +191 -0
  36. data/test/fixtures/hotmail_login_response_stage_1.html +31 -0
  37. data/test/fixtures/hotmail_login_response_stage_2.html +1 -0
  38. data/test/fixtures/hotmail_login_response_stage_3.html +380 -0
  39. data/test/fixtures/yahoo_bad_login_response_stage_2.html +443 -0
  40. data/test/fixtures/yahoo_contacts.csv +3 -0
  41. data/test/fixtures/yahoo_contacts_not_logged_in.html +432 -0
  42. data/test/fixtures/yahoo_contacts_stage_1.html +399 -0
  43. data/test/fixtures/yahoo_login_response_stage_1.html +433 -0
  44. data/test/fixtures/yahoo_login_response_stage_2.html +16 -0
  45. data/test/scripts/live_test.rb +25 -0
  46. data/test/test_blackbook.rb +60 -0
  47. data/test/test_blackbook_exporter_base.rb +16 -0
  48. data/test/test_blackbook_exporter_vcf.rb +52 -0
  49. data/test/test_blackbook_exporter_xml.rb +16 -0
  50. data/test/test_blackbook_importer_aol.rb +113 -0
  51. data/test/test_blackbook_importer_base.rb +24 -0
  52. data/test/test_blackbook_importer_csv.rb +60 -0
  53. data/test/test_blackbook_importer_gmail.rb +117 -0
  54. data/test/test_blackbook_importer_hotmail.rb +147 -0
  55. data/test/test_blackbook_importer_page_scraper.rb +51 -0
  56. data/test/test_blackbook_importer_yahoo.rb +97 -0
  57. data/test/test_helper.rb +69 -0
  58. data/vendor/plugins/blackbook/lib/autotest/blackbook.rb +27 -0
  59. data/vendor/plugins/blackbook/lib/autotest/discover.rb +3 -0
  60. metadata +176 -0
data/CHANGES.markdown ADDED
@@ -0,0 +1,44 @@
1
+ == 1.0.5 / 2008-11-26
2
+
3
+ * moved to github
4
+ * added patch for gmail. emails were coming in with notes.
5
+ * added german stuff to blackbook gem
6
+
7
+ == 1.0.4 / 2008-02-27
8
+
9
+ * 1 minor enhancement
10
+ * fix 1.0.3 dud with AOL issues - Thank you Howard Wong!
11
+
12
+ == 1.0.3 / 2008-02-27
13
+
14
+ * 1 minor enhancement
15
+ * address the change in where AOL contacts are listed
16
+
17
+ == 1.0.2 / 2008-02-20
18
+
19
+ * 1 minor enhancement
20
+ * fixed sign on issue with GMail
21
+
22
+ == 1.0.1 / 2008-02-08
23
+
24
+ * 2 minor enhancement
25
+ * fix edge case sign on issue with GMail
26
+
27
+ == 1.0.0 / 2008-01-30
28
+
29
+ * 2 major enhancements
30
+ * Birthday!
31
+ * Mechanize patch for AOL sign-on! Thanks Mortee!
32
+
33
+ * Importers
34
+ * AOL
35
+ * GMail
36
+ * Hotmail
37
+ * Yahoo!
38
+ * CSV
39
+
40
+ * Exporters
41
+ * Hash
42
+ * XML
43
+ * VCard
44
+
data/Manifest.txt ADDED
@@ -0,0 +1,59 @@
1
+ CHANGES.markdown
2
+ Manifest.txt
3
+ README.markdown
4
+ Rakefile
5
+ debug_blackbook.rb
6
+ init.rb
7
+ lib/blackbook.rb
8
+ lib/blackbook/exporter/base.rb
9
+ lib/blackbook/exporter/vcf.rb
10
+ lib/blackbook/exporter/xml.rb
11
+ lib/blackbook/importer/aol.rb
12
+ lib/blackbook/importer/base.rb
13
+ lib/blackbook/importer/csv.rb
14
+ lib/blackbook/importer/gmail.rb
15
+ lib/blackbook/importer/hotmail.rb
16
+ lib/blackbook/importer/page_scraper.rb
17
+ lib/blackbook/importer/yahoo.rb
18
+ test/fixtures/aol_application_page.html
19
+ test/fixtures/aol_bad_login_response_stage_3.html
20
+ test/fixtures/aol_contacts.html
21
+ test/fixtures/aol_login_response_stage_1.html
22
+ test/fixtures/aol_login_response_stage_2.html
23
+ test/fixtures/aol_login_response_stage_3.html
24
+ test/fixtures/aol_login_response_stage_4.html
25
+ test/fixtures/aol_login_response_stage_5.html
26
+ test/fixtures/aol_new_contacts.html
27
+ test/fixtures/gmail.csv
28
+ test/fixtures/gmail_bad_login_response_stage_2.html
29
+ test/fixtures/gmail_contacts.html
30
+ test/fixtures/gmail_login_response_stage_1.html
31
+ test/fixtures/gmail_login_response_stage_2.html
32
+ test/fixtures/gmail_login_response_stage_2a.html
33
+ test/fixtures/gmail_login_response_stage_3.html
34
+ test/fixtures/hotmail_bad_login_response_stage_2.html
35
+ test/fixtures/hotmail_contacts.html
36
+ test/fixtures/hotmail_login_response_stage_1.html
37
+ test/fixtures/hotmail_login_response_stage_2.html
38
+ test/fixtures/hotmail_login_response_stage_3.html
39
+ test/fixtures/yahoo_bad_login_response_stage_2.html
40
+ test/fixtures/yahoo_contacts.csv
41
+ test/fixtures/yahoo_contacts_not_logged_in.html
42
+ test/fixtures/yahoo_contacts_stage_1.html
43
+ test/fixtures/yahoo_login_response_stage_1.html
44
+ test/fixtures/yahoo_login_response_stage_2.html
45
+ test/scripts/live_test.rb
46
+ test/test_blackbook.rb
47
+ test/test_blackbook_exporter_base.rb
48
+ test/test_blackbook_exporter_vcf.rb
49
+ test/test_blackbook_exporter_xml.rb
50
+ test/test_blackbook_importer_aol.rb
51
+ test/test_blackbook_importer_base.rb
52
+ test/test_blackbook_importer_csv.rb
53
+ test/test_blackbook_importer_gmail.rb
54
+ test/test_blackbook_importer_hotmail.rb
55
+ test/test_blackbook_importer_page_scraper.rb
56
+ test/test_blackbook_importer_yahoo.rb
57
+ test/test_helper.rb
58
+ vendor/plugins/blackbook/lib/autotest/blackbook.rb
59
+ vendor/plugins/blackbook/lib/autotest/discover.rb
data/README.markdown ADDED
@@ -0,0 +1,72 @@
1
+ Blackbook
2
+ http://github.com/purzelrakete/blackbook/tree/master
3
+
4
+ == DESCRIPTION:
5
+
6
+ Blackbook automates the nitty-gritty of importing contacts from various services and files and exporting them as VCard, XML, or simple Hash. Utilize those contacts from services like AOL, GMail, Yahoo Mail, Hotmail or CSV to help your social networking site become GIGANTIC overnight! You'll be able to get big and sell for millions before anyone figures out it's just like every other social network.
7
+
8
+ == FEATURES/PROBLEMS:
9
+
10
+ The current list of supported services and file types:
11
+
12
+ Import:
13
+ * AOL
14
+ * CSV files
15
+ * Gmail
16
+ * Hotmail
17
+ * Yahoo! Mail
18
+
19
+ Export:
20
+ * Simple hash (default)
21
+ * Vcard
22
+ * XML
23
+
24
+ If you create an additional importer or exporter - or simply find a bug - please consider submitting it as a patch to the project so the community can all benefit from your hard work and ingenuity.
25
+
26
+ == SYNOPSIS:
27
+
28
+ # An example of fetching Gmail contacts - by default, returns an array of hashes with :name and :email
29
+ contacts = Blackbook.get :username => 'me@gmail.com', :password => 'whatever'
30
+
31
+ # or returning XML
32
+ contacts = Blackbook.get :username => 'me@gmail.com', :password => 'whatever', :as => :xml
33
+
34
+ # or importing from a CSV file
35
+ contacts = Blackbook.get :csv, :file => #<File:/path/to/file.csv>
36
+
37
+ == REQUIREMENTS:
38
+
39
+ * Mechanize and its dependencies, for interacting with online providers
40
+ * Fastercsv for reading CSV, Mechanize >= 0.7.0 for page scraping
41
+
42
+ == INSTALL:
43
+
44
+ 1. gem sources -a http://gems.github.com
45
+ 2. sudo gem install purzelrakete-blackbook
46
+
47
+ == THANKS:
48
+
49
+ Big thanks to Marton Fabo for figuring out why Mechanize couldn't log in to AOL.
50
+
51
+ == LICENSE:
52
+
53
+ Copyright (c) 2007, Contentfree
54
+
55
+ Permission is hereby granted, free of charge, to any person obtaining
56
+ a copy of this software and associated documentation files (the
57
+ 'Software'), to deal in the Software without restriction, including
58
+ without limitation the rights to use, copy, modify, merge, publish,
59
+ distribute, sublicense, and/or sell copies of the Software, and to
60
+ permit persons to whom the Software is furnished to do so, subject to
61
+ the following conditions:
62
+
63
+ The above copyright notice and this permission notice shall be
64
+ included in all copies or substantial portions of the Software.
65
+
66
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
67
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
68
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
69
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
70
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
71
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
72
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,39 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ $LOAD_PATH.unshift 'lib'
6
+ require 'blackbook'
7
+
8
+ begin
9
+ require 'rcov/rcovtask'
10
+ rescue LoadError
11
+ end
12
+
13
+ Hoe.new('blackbook', Blackbook::VERSION) do |p|
14
+ p.rubyforge_name = 'contentfree'
15
+ p.author = 'Contentfree'
16
+ p.email = 'dave.myron@contentfree.com'
17
+ p.summary = 'Blackbook handles the nitty-gritty of importing contacts from various service providers and contact lists and exporting them in a useful format.'
18
+ # FIX these were broken with the switch from README.txt to README.markdown
19
+ # p.description = p.paragraphs_of('README.txt', 1).join("\n\n")
20
+ # p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
21
+ # p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
22
+ p.extra_deps << [ "mechanize", ">= 0.7.0" ]
23
+ p.extra_deps << [ "fastercsv", ">= 1.2.0" ]
24
+ p.clean_globs << 'coverage'
25
+ p.clean_globs << 'pkg'
26
+ p.clean_globs << 'doc'
27
+ p.clean_globs << 'ri'
28
+ end
29
+
30
+ task :release_and_publish => [:release, :publish_docs]
31
+
32
+ begin
33
+ Rcov::RcovTask.new do |t|
34
+ t.test_files = FileList['test/test*.rb']
35
+ t.verbose = true
36
+ #t.rcov_opts << "--exclude rcov.rb,hpricot.rb,hpricot/.*\.rb"
37
+ end
38
+ rescue NameError
39
+ end
@@ -0,0 +1,10 @@
1
+ require 'blackbook'
2
+
3
+ aol = Blackbook.get :username => 'mondragonmichael@aol.com', :password => '123aol0'
4
+ puts "===== aol #{aol.inspect}"
5
+
6
+ unless aol.detect{|c| c[:name].downcase == 'Dave Myron'.downcase && c[:email] == 'dave.myron@contentfree.com'}
7
+ puts "AOL not working"
8
+ exit 1
9
+ end
10
+
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'blackbook'
@@ -0,0 +1,16 @@
1
+ ##
2
+ # base class for exporters of contact information
3
+
4
+ module Blackbook::Exporter
5
+
6
+ class Base
7
+ ##
8
+ # Override this to convert +contacts+ (an array of hashes) to something more useful. Here, it
9
+ # just returns Blackbook's internal format
10
+ def export( contacts )
11
+ contacts
12
+ end
13
+
14
+ Blackbook.register :basic, self
15
+ end
16
+ end
@@ -0,0 +1,45 @@
1
+ ##
2
+ # exports contacts in Vcard format
3
+ class Blackbook::Exporter::Vcf < Blackbook::Exporter::Base
4
+
5
+ ##
6
+ # representation of a vcard
7
+
8
+ class Vcard
9
+
10
+ attr_accessor :first, :last, :email
11
+
12
+ ##
13
+ # initialize dynamically sets the attributes passed in as accessible
14
+ # attribute on its object
15
+
16
+ def initialize( attributes = {} )
17
+ attributes.each{ |name,value| self.send("#{name}=", value) rescue next }
18
+ end
19
+
20
+ ##
21
+ # text representation of this vcard
22
+ def to_s
23
+ <<-EOVC
24
+ BEGIN:VCARD
25
+ N:#{last};#{first}
26
+ EMAIL:#{email}
27
+ END:VCARD
28
+ EOVC
29
+ end
30
+ end
31
+
32
+ ##
33
+ # exports contacts as Vcards
34
+
35
+ def export( contacts = [] )
36
+ return if contacts.empty?
37
+
38
+ contacts.uniq.compact.collect do |contact|
39
+ first_name, last_name = contact[:name].split(' ', 2)
40
+ Vcard.new( :first => first_name.to_s, :last => last_name.to_s, :email => contact[:email])
41
+ end
42
+ end
43
+
44
+ Blackbook.register(:vcf, self)
45
+ end
@@ -0,0 +1,28 @@
1
+ require 'rexml/document'
2
+
3
+ ##
4
+ # exports contacts in xml format
5
+
6
+ class Blackbook::Exporter::Xml < Blackbook::Exporter::Base
7
+
8
+ ##
9
+ # contacts are an array of hashes that are contacts and returns xml
10
+
11
+ def export( contacts )
12
+ doc = REXML::Document.new
13
+ doc << REXML::XMLDecl.new
14
+
15
+ root = doc.add_element 'contacts'
16
+ contacts.each do |contact|
17
+ el = root.add_element 'contact'
18
+ name = el.add_element 'name'
19
+ name.text = contact[:name]
20
+
21
+ el.add_element('email').text = contact[:email]
22
+ end
23
+
24
+ doc.to_s
25
+ end
26
+
27
+ Blackbook.register(:xml, self)
28
+ end
@@ -0,0 +1,83 @@
1
+ require 'blackbook/importer/page_scraper'
2
+
3
+ ##
4
+ # Imports contacts from AOL
5
+
6
+ class Blackbook::Importer::Aol < Blackbook::Importer::PageScraper
7
+
8
+ ##
9
+ # Matches this importer to an user's name/address
10
+
11
+ def =~( options )
12
+ options && options[:username] =~ /@(aol|aim)\.com$/i ? true : false
13
+ end
14
+
15
+ ##
16
+ # Login process:
17
+ # - Get mail.aol.com which redirects to a page containing a javascript redirect
18
+ # - Get the URL that the javascript is supposed to redirect you to
19
+ # - Fill out and submit the login form
20
+ # - Get the URL from *another* javascript redirect
21
+
22
+ def login
23
+ page = agent.get( 'http://webmail.aol.com/' )
24
+
25
+ form = page.forms.name('AOLLoginForm').first
26
+ form.loginId = options[:username].split('@').first # Drop the domain
27
+ form.password = options[:password]
28
+ page = agent.submit(form, form.buttons.first)
29
+
30
+ raise( Blackbook::BadCredentialsError, "That username and password was not accepted. Please check them and try again." ) if page.body =~ /Invalid Screen Name or Password. Please try again./
31
+
32
+ # aol bumps to a wait page while logging in. if we can't scrape out the js then its a bad login
33
+ wait_url = page.body.scan(/onLoad="checkError[^\)]+/).first.scan(/'([^']+)'/).last.first
34
+ page = agent.get wait_url
35
+
36
+ base_uri = page.body.scan(/^var gSuccessPath = \"(.+)\";/).first.first
37
+ raise( Blackbook::BadCredentialsError, "You do not appear to be signed in." ) unless base_uri
38
+ page = agent.get base_uri
39
+ end
40
+
41
+ ##
42
+ # must login to prepare
43
+
44
+ def prepare
45
+ login
46
+ end
47
+
48
+ ##
49
+ # The url to scrape contacts from has to be put together from the Auth cookie
50
+ # and a known uri that hosts their contact service. An array of hashes with
51
+ # :name and :email keys is returned.
52
+
53
+ def scrape_contacts
54
+ unless auth_cookie = agent.cookies.find{|c| c.name =~ /^Auth/}
55
+ raise( Blackbook::BadCredentialsError, "Must be authenticated to access contacts." )
56
+ end
57
+
58
+ # jump through the hoops of formulating a request to get printable contacts
59
+ uri = agent.current_page.uri.dup
60
+ inputs = agent.current_page.search("//input")
61
+ user = inputs.detect{|i| i['type'] == 'hidden' && i['name'] == 'user'}
62
+ utoken = user['value']
63
+
64
+ path = uri.path.split('/')
65
+ path.pop
66
+ path << 'addresslist-print.aspx'
67
+ uri.path = path.join('/')
68
+ uri.query = "command=all&sort=FirstLastNick&sortDir=Ascending&nameFormat=FirstLastNick&user=#{utoken}"
69
+ page = agent.get uri.to_s
70
+
71
+ # Grab all the contacts
72
+ names = page.body.scan( /<span class="fullName">([^<]+)<\/span>/ ).flatten
73
+ emails = page.body.scan( /<span>Email 1:<\/span> <span>([^<]+)<\/span>/ ).flatten
74
+ (0...[names.size,emails.size].max).collect do |i|
75
+ {
76
+ :name => names[i],
77
+ :email => emails[i]
78
+ }
79
+ end
80
+ end
81
+
82
+ Blackbook.register :aol, self
83
+ end
@@ -0,0 +1,39 @@
1
+ #
2
+ # Provides a base template for interface and behavior of contact importers
3
+
4
+ module Blackbook::Importer
5
+ class Base
6
+ attr_accessor :options
7
+
8
+ ##
9
+ # Should return true or false/nil depending on whether the +options+ given
10
+ # can be handled by this importer
11
+
12
+ def =~( options ); end # stub
13
+
14
+ ##
15
+ # Does the work of extracting contacts. Returns an Array of Arrays
16
+ # containing the name and email as the first and second elements. Of
17
+ # course, you can override this behavior to meet the needs of a
18
+ # particular service.
19
+
20
+ def fetch_contacts!; end # stub
21
+
22
+ ##
23
+ # Imports the contacts using the given +options+. Returns an array of
24
+ # hashes in the internal format (a hash with at least :name and :email
25
+ # values).
26
+
27
+ def import(options = {})
28
+ self.options = options
29
+ fetch_contacts!
30
+ end
31
+
32
+ ##
33
+ # Name of the importer service.
34
+
35
+ def service_name
36
+ self.class.name.split("::").last
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,87 @@
1
+ require 'fastercsv'
2
+
3
+ ##
4
+ # Imports contacts from a CSV file
5
+
6
+ class Blackbook::Importer::Csv < Blackbook::Importer::Base
7
+
8
+ DEFAULT_COLUMNS = [:name,:email,:misc]
9
+
10
+ ##
11
+ # Matches this importer to a file that contains CSV values
12
+
13
+ def =~(options)
14
+ options && options[:file].respond_to?(:open) ? true : false
15
+ end
16
+
17
+ ##
18
+ # fetch_contacts! implementation for this importer
19
+
20
+ def fetch_contacts!
21
+ a = open(options[:file].base_uri.to_s)
22
+ lines_ = Array.new
23
+ lines = a.readlines
24
+ first_line = lines.first
25
+ if first_line.is_binary_data?
26
+ lines.each { |e|
27
+ s = ''
28
+ unless e == lines.first
29
+ u = "\377\376N" << e.strip
30
+ e = u
31
+ s << e.toutf8
32
+ s.slice!(0)
33
+ else s << e.toutf8
34
+ end
35
+ lines_ << s
36
+ }
37
+ lines = lines_
38
+ end
39
+
40
+ # lines.each { |e|
41
+ # if e.is_binary_data?
42
+ # e = e.toutf8
43
+ # end
44
+ # }
45
+
46
+ columns = to_columns(lines.first)
47
+ lines.shift if columns.first == :name
48
+ columns = DEFAULT_COLUMNS.dup unless columns.first == :name
49
+
50
+ contacts = Array.new
51
+ lines.each do |l|
52
+ vals = l.split(',')
53
+ next if vals.empty?
54
+ contacts << to_hash(columns, vals)
55
+ end
56
+
57
+ contacts
58
+ end
59
+
60
+ def to_hash(cols, vals) # :nodoc:
61
+ h = Hash.new
62
+ cols.each do |c|
63
+ h[c] = (c == cols.last) ? vals.join(',') : vals.shift
64
+ end
65
+ h
66
+ end
67
+
68
+ def to_columns(line) # :nodoc:
69
+ if line
70
+ columns = Array.new
71
+ tags = line.split(',')
72
+ # deal with "Name,E-mail..." oddity up front
73
+ if tags.first =~ /^name$/i
74
+ tags.shift
75
+ columns << :name
76
+ if tags.first =~ /^e.?mail/i # E-mail or Email
77
+ tags.shift
78
+ columns << :email
79
+ end
80
+ end
81
+ tags.each{|v| columns << v.strip.to_sym}
82
+ columns
83
+ end
84
+ end
85
+
86
+ Blackbook.register(:csv, self)
87
+ end
@@ -0,0 +1,66 @@
1
+ require 'blackbook/importer/page_scraper'
2
+
3
+ ##
4
+ # Imports contacts from GMail
5
+
6
+ class Blackbook::Importer::Gmail < Blackbook::Importer::PageScraper
7
+
8
+ ##
9
+ # Matches this importer to an user's name/address
10
+
11
+ def =~(options = {})
12
+ options && options[:username] =~ /@gmail.com$/i ? true : false
13
+ end
14
+
15
+ ##
16
+ # login to gmail
17
+
18
+ def login
19
+ page = agent.get('http://mail.google.com/mail/')
20
+ form = page.forms.first
21
+ form.Email = options[:username]
22
+ form.Passwd = options[:password]
23
+ page = agent.submit(form,form.buttons.first)
24
+
25
+ raise( Blackbook::BadCredentialsError, "That username and password was not accepted. Please check them and try again." ) if page.body =~ /Username and password do not match/
26
+
27
+ if page.search('//meta').first.attributes['content'] =~ /url='?(http.+?)'?$/i
28
+ page = agent.get $1
29
+ end
30
+ end
31
+
32
+ ##
33
+ # prepare this importer
34
+
35
+ def prepare
36
+ login
37
+ end
38
+
39
+ ##
40
+ # scrape gmail contacts for this importer
41
+
42
+ def scrape_contacts
43
+ unless agent.cookies.find{|c| c.name == 'GAUSR' &&
44
+ c.value == "mail:#{options[:username]}"}
45
+ raise( Blackbook::BadCredentialsError, "Must be authenticated to access contacts." )
46
+ end
47
+
48
+ page = agent.get('http://mail.google.com/mail/h/?v=cl&pnl=a')
49
+ contact_rows = page.search("input[@name='c']/../..")
50
+ contact_rows.collect do |row|
51
+ columns = row/"td"
52
+ email = columns[2].inner_html.gsub( /(\n|&nbsp;)/, '' ) # email
53
+ clean_email = email[/[a-zA-Z0-9._%+-]+@(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,4}/]
54
+
55
+ unless clean_email.empty?
56
+ columns = row/"td"
57
+ {
58
+ :name => ( columns[1] / "b" ).inner_html, # name
59
+ :email => clean_email
60
+ }
61
+ end
62
+ end.compact
63
+ end
64
+
65
+ Blackbook.register(:gmail, self)
66
+ end