muck-contacts 2.6.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,24 @@
1
+ source :rubygems
2
+
3
+ gem 'json', ">= 1.1.1"
4
+ gem 'gdata', :platform => [:ruby_18]
5
+ gem 'gdata19', :platform => [:ruby_19]
6
+ gem 'hpricot', '= 0.8.2'
7
+ gem 'encryptor'
8
+ gem 'oauth', '>= 0.4.0'
9
+
10
+ gem 'mini_fb', :group => :facebook
11
+
12
+ # Need this from git so we don't end up in dependency hell with oauth
13
+ gem "linkedin", :group => :linkedin, :git => "https://github.com/pengwynn/linkedin.git"
14
+
15
+
16
+ group :development do
17
+ gem 'jeweler'
18
+ end
19
+
20
+ group :test do
21
+ gem "ruby-debug", :platform => [:ruby_18]
22
+ gem "ruby-debug19", :platform => [:ruby_19]
23
+ gem "shoulda"
24
+ end
data/LICENSE ADDED
@@ -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
+
data/README ADDED
@@ -0,0 +1,58 @@
1
+ == Welcome to Contacts
2
+
3
+ Contacts is a universal interface to grab contact list information from various providers including Outlook, Address Book, Hotmail, AOL, Gmail, Plaxo and Yahoo.
4
+
5
+ == Download
6
+
7
+ * gem install contacts
8
+ * http://github.com/cardmagic/contacts
9
+ * git clone git://github.com/cardmagic/contacts.git
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
+ == Captcha error
30
+
31
+ If there are too many failed attempts with the gmail login info, Google will raise a captcha response. To integrate the captcha handling, pass in the token and response via:
32
+
33
+ Contacts::Gmail.new(login, password, :captcha_token => params[:captcha_token], :captcha_response => params[:captcha_response]).contacts
34
+
35
+ == Examples
36
+
37
+ See the examples/ directory.
38
+
39
+ == Authors
40
+
41
+ * Lucas Carlson from MOG (mailto:lucas@rufy.com) - http://mog.com
42
+ * Paperless Post
43
+
44
+ == Contributors
45
+
46
+ * Britt Selvitelle from Twitter (mailto:anotherbritt@gmail.com) - http://twitter.com
47
+ * Tony Targonski from GigPark (mailto:tony@gigpark.com) - http://gigpark.com
48
+ * Waheed Barghouthi from Watwet (mailto:waheed.barghouthi@gmail.com) - http://watwet.com
49
+ * Glenn Sidney from Glenn Fu (mailto:glenn@glennfu.com) - http://glennfu.com
50
+ * Brian McQuay from Onomojo (mailto:brian@onomojo.com) - http://onomojo.com
51
+ * Adam Hunter (mailto:adamhunter@me.com) - http://adamhunter.me/
52
+ * Glenn Ford (mailto:glenn@glennfu.com) - http://www.glennfu.com/
53
+ * Leonardo Wong (mailto:mac@boy.name)
54
+ * Rusty Burchfield
55
+ * justintv
56
+
57
+ This library is released under the terms of the BSD.
58
+
@@ -0,0 +1,43 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "muck-contacts"
16
+ gem.homepage = "http://github.com/tatemae/contacts"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{A universal interface to grab contact list information from various providers including Outlook, Address Book, Yahoo, AOL, Gmail, Hotmail, and Plaxo.}
19
+ gem.description = %Q{A universal interface to grab contact list information from various providers including Outlook, Address Book, Yahoo, AOL, Gmail, Hotmail, and Plaxo.}
20
+ gem.email = "rob@notch8.com"
21
+ gem.authors = ["Rob Kaufman"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rake/testtask'
30
+ Rake::TestTask.new(:test) do |test|
31
+ test.libs << 'lib' << 'test'
32
+ test.pattern = 'test/**/*_test.rb'
33
+ test.verbose = true
34
+ end
35
+
36
+ #require 'rcov/rcovtask'
37
+ #Rcov::RcovTask.new do |test|
38
+ #test.libs << 'test'
39
+ #test.pattern = 'test/**/test_*.rb'
40
+ #test.verbose = true
41
+ #end
42
+
43
+ task :default => :test
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 2.6.1
@@ -0,0 +1,106 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{contacts}
8
+ s.version = "2.6.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Rob Kaufman"]
12
+ s.date = %q{2011-02-10}
13
+ s.description = %q{A universal interface to grab contact list information from various providers including Outlook, Address Book, Yahoo, AOL, Gmail, Hotmail, and Plaxo.}
14
+ s.email = %q{rob@notch8.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README"
18
+ ]
19
+ s.files = [
20
+ "Gemfile",
21
+ "LICENSE",
22
+ "README",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "contacts.gemspec",
26
+ "cruise_config.rb",
27
+ "examples/grab_contacts.rb",
28
+ "geminstaller.yml",
29
+ "lib/contacts.rb",
30
+ "lib/contacts/aol_importer.rb",
31
+ "lib/contacts/base.rb",
32
+ "lib/contacts/facebook.rb",
33
+ "lib/contacts/gmail.rb",
34
+ "lib/contacts/hotmail.rb",
35
+ "lib/contacts/json_picker.rb",
36
+ "lib/contacts/linked_in.rb",
37
+ "lib/contacts/mailru.rb",
38
+ "lib/contacts/outlook.rb",
39
+ "lib/contacts/plaxo.rb",
40
+ "lib/contacts/vcf.rb",
41
+ "lib/contacts/yahoo.rb",
42
+ "test/example_accounts.yml",
43
+ "test/test_helper.rb",
44
+ "test/unit/aol_contact_importer_test.rb",
45
+ "test/unit/facebook_contact_importer_test.rb",
46
+ "test/unit/gmail_contact_importer_test.rb",
47
+ "test/unit/hotmail_contact_importer_test.rb",
48
+ "test/unit/linked_in_contact_importer_test.rb",
49
+ "test/unit/mailru_contact_importer_test.rb",
50
+ "test/unit/outlook_test.rb",
51
+ "test/unit/test_accounts_test.rb",
52
+ "test/unit/vcf_test.rb",
53
+ "test/unit/yahoo_csv_contact_importer_test.rb"
54
+ ]
55
+ s.homepage = %q{http://github.com/notch8/contacts}
56
+ s.licenses = ["MIT"]
57
+ s.require_paths = ["lib"]
58
+ s.rubygems_version = %q{1.3.7}
59
+ s.summary = %q{A universal interface to grab contact list information from various providers including Outlook, Address Book, Yahoo, AOL, Gmail, Hotmail, and Plaxo.}
60
+ s.test_files = [
61
+ "examples/grab_contacts.rb",
62
+ "test/test_helper.rb",
63
+ "test/unit/aol_contact_importer_test.rb",
64
+ "test/unit/facebook_contact_importer_test.rb",
65
+ "test/unit/gmail_contact_importer_test.rb",
66
+ "test/unit/hotmail_contact_importer_test.rb",
67
+ "test/unit/linked_in_contact_importer_test.rb",
68
+ "test/unit/mailru_contact_importer_test.rb",
69
+ "test/unit/outlook_test.rb",
70
+ "test/unit/test_accounts_test.rb",
71
+ "test/unit/vcf_test.rb",
72
+ "test/unit/yahoo_csv_contact_importer_test.rb"
73
+ ]
74
+
75
+ if s.respond_to? :specification_version then
76
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
77
+ s.specification_version = 3
78
+
79
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
80
+ s.add_runtime_dependency(%q<json>, [">= 1.1.1"])
81
+ s.add_runtime_dependency(%q<gdata>, [">= 0"])
82
+ s.add_runtime_dependency(%q<gdata19>, [">= 0"])
83
+ s.add_runtime_dependency(%q<hpricot>, ["= 0.8.2"])
84
+ s.add_runtime_dependency(%q<encryptor>, [">= 0"])
85
+ s.add_runtime_dependency(%q<oauth>, [">= 0.4.0"])
86
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
87
+ else
88
+ s.add_dependency(%q<json>, [">= 1.1.1"])
89
+ s.add_dependency(%q<gdata>, [">= 0"])
90
+ s.add_dependency(%q<gdata19>, [">= 0"])
91
+ s.add_dependency(%q<hpricot>, ["= 0.8.2"])
92
+ s.add_dependency(%q<encryptor>, [">= 0"])
93
+ s.add_dependency(%q<oauth>, [">= 0.4.0"])
94
+ s.add_dependency(%q<jeweler>, [">= 0"])
95
+ end
96
+ else
97
+ s.add_dependency(%q<json>, [">= 1.1.1"])
98
+ s.add_dependency(%q<gdata>, [">= 0"])
99
+ s.add_dependency(%q<gdata19>, [">= 0"])
100
+ s.add_dependency(%q<hpricot>, ["= 0.8.2"])
101
+ s.add_dependency(%q<encryptor>, [">= 0"])
102
+ s.add_dependency(%q<oauth>, [">= 0.4.0"])
103
+ s.add_dependency(%q<jeweler>, [">= 0"])
104
+ end
105
+ end
106
+
@@ -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,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,0 +1,8 @@
1
+ ---
2
+ defaults:
3
+ install_options: --no-ri --no-rdoc
4
+ gems:
5
+ - name: json
6
+ version: >= 1.1.1
7
+ - name: gdata
8
+ version: >= 1.1.1
@@ -0,0 +1,37 @@
1
+ $:.unshift(File.dirname(__FILE__)+"/contacts/")
2
+
3
+ ## Use ActiveSupport's version of JSON if available
4
+ #if Object.const_defined?('ActiveSupport') && ActiveSupport.const_defined?('JSON')
5
+ # module ActiveSupportJsonParseFunction
6
+ # def parse(i)
7
+ # ActiveSupport::JSON.decode(i)
8
+ # end
9
+ # end
10
+ # # newer versions of ActiveSupport define a root JSON module to extend...
11
+ # if Object.const_defined?('JSON')
12
+ # JSON.send(:extend, ActiveSupportJsonParseFunction)
13
+ # else
14
+ # # ... older need it defined from scratch
15
+ # class JSON
16
+ # extend ActiveSupportJsonParseFunction
17
+ # end
18
+ # end
19
+ #else
20
+ # require 'json/add/rails'
21
+ #end
22
+
23
+ require 'rubygems'
24
+
25
+ require 'json_picker'
26
+ require 'base'
27
+ require 'json_picker'
28
+ require 'gmail'
29
+ require 'hotmail'
30
+ require 'yahoo'
31
+ require 'plaxo'
32
+ require 'mailru'
33
+ require 'vcf'
34
+ require 'outlook'
35
+ require 'aol_importer'
36
+ require 'facebook'
37
+ require 'linked_in'
@@ -0,0 +1,149 @@
1
+ require 'hpricot'
2
+ require 'csv'
3
+
4
+ class Contacts
5
+ class AolImporter < Base
6
+ URL = "http://www.aol.com/"
7
+ LOGIN_URL = "https://my.screenname.aol.com/_cqr/login/login.psp"
8
+ LOGIN_REFERER_URL = "http://webmail.aol.com/"
9
+ LOGIN_REFERER_PATH = "sitedomain=sns.webmail.aol.com&lang=en&locale=us&authLev=0&uitype=mini&loginId=&redirType=js&xchk=false"
10
+ AOL_NUM = "32319-211" # this seems to change each time they change the protocol
11
+
12
+ CONTACT_LIST_URL = "http://mail.aol.com/#{AOL_NUM}/aol-6/en-us/Lite/ContactList.aspx?folder=Inbox&showUserFolders=False"
13
+ CONTACT_LIST_CSV_URL = "http://mail.aol.com/#{AOL_NUM}/aol-6/en-us/Lite/ABExport.aspx?command=all"
14
+ PROTOCOL_ERROR = "AOL 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"
15
+
16
+ def contacts
17
+ postdata = {
18
+ "file" => 'contacts',
19
+ "fileType" => 'csv'
20
+ }
21
+
22
+ return @contacts if @contacts
23
+ if connected?
24
+ data, resp, cookies, forward, old_url = get(CONTACT_LIST_URL, @cookies, CONTACT_LIST_URL) + [CONTACT_LIST_URL]
25
+
26
+ until forward.nil?
27
+ data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
28
+ end
29
+
30
+ if resp.code_type != Net::HTTPOK
31
+ raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
32
+ end
33
+
34
+ # parse data and grab <input name="user" value="8QzMPIAKs2" type="hidden">
35
+ doc = Hpricot(data)
36
+ (doc/:input).each do |input|
37
+ postdata["user"] = input.attributes["value"] if input.attributes["name"] == "user"
38
+ end
39
+
40
+ data, resp, cookies, forward, old_url = get(CONTACT_LIST_CSV_URL, @cookies, CONTACT_LIST_URL) + [CONTACT_LIST_URL]
41
+
42
+ until forward.nil?
43
+ data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
44
+ end
45
+
46
+ if data.include?("error.gif")
47
+ raise AuthenticationError, "Account invalid"
48
+ end
49
+
50
+ parse data
51
+ end
52
+ end
53
+
54
+
55
+ def real_connect
56
+
57
+ postdata = {
58
+ "loginId" => login,
59
+ "password" => password,
60
+ "rememberMe" => "on",
61
+ "_sns_fg_color_" => "",
62
+ "_sns_err_color_" => "",
63
+ "_sns_link_color_" => "",
64
+ "_sns_width_" => "",
65
+ "_sns_height_" => "",
66
+ "offerId" => "mail-second-en-us",
67
+ "_sns_bg_color_" => "",
68
+ "sitedomain" => "sns.webmail.aol.com",
69
+ "regPromoCode" => "",
70
+ "mcState" => "initialized",
71
+ "uitype" => "std",
72
+ "siteId" => "",
73
+ "lang" => "en",
74
+ "locale" => "us",
75
+ "authLev" => "0",
76
+ "siteState" => "",
77
+ "isSiteStateEncoded" => "false",
78
+ "use_aam" => "0",
79
+ "seamless" => "novl",
80
+ "aolsubmit" => CGI.escape("Sign In"),
81
+ "idType" => "SN",
82
+ "usrd" => "",
83
+ "doSSL" => "",
84
+ "redirType" => "",
85
+ "xchk" => "false"
86
+ }
87
+
88
+ # Get this cookie and stick it in the form to confirm to Aol that your cookies work
89
+ data, resp, cookies, forward = get(URL)
90
+ postdata["stips"] = cookie_hash_from_string(cookies)["stips"]
91
+ postdata["tst"] = cookie_hash_from_string(cookies)["tst"]
92
+
93
+ data, resp, cookies, forward, old_url = get(LOGIN_REFERER_URL, cookies) + [URL]
94
+ until forward.nil?
95
+ data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
96
+ end
97
+
98
+ data, resp, cookies, forward, old_url = get("#{LOGIN_URL}?#{LOGIN_REFERER_PATH}", cookies) + [LOGIN_REFERER_URL]
99
+ until forward.nil?
100
+ data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
101
+ end
102
+
103
+ doc = Hpricot(data)
104
+ (doc/:input).each do |input|
105
+ postdata["usrd"] = input.attributes["value"] if input.attributes["name"] == "usrd"
106
+ end
107
+ # parse data for <input name="usrd" value="2726212" type="hidden"> and add it to the postdata
108
+
109
+ postdata["SNS_SC"] = cookie_hash_from_string(cookies)["SNS_SC"]
110
+ postdata["SNS_LDC"] = cookie_hash_from_string(cookies)["SNS_LDC"]
111
+ postdata["LTState"] = cookie_hash_from_string(cookies)["LTState"]
112
+ # raise data.inspect
113
+
114
+ data, resp, cookies, forward, old_url = post(LOGIN_URL, h_to_query_string(postdata), cookies, LOGIN_REFERER_URL) + [LOGIN_REFERER_URL]
115
+
116
+ until forward.nil?
117
+ data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
118
+ end
119
+ if data.index("Invalid Password, Username or Email")
120
+ raise AuthenticationError, "Username and password do not match"
121
+ elsif data.index("Required field must not be blank")
122
+ raise AuthenticationError, "Login and password must not be blank"
123
+ elsif data.index("errormsg_0_logincaptcha")
124
+ raise AuthenticationError, "Captcha error"
125
+ elsif data.index("Invalid request")
126
+ raise ConnectionError, PROTOCOL_ERROR
127
+ elsif cookies == ""
128
+ raise ConnectionError, PROTOCOL_ERROR
129
+ end
130
+
131
+ @cookies = cookies
132
+ end
133
+
134
+
135
+ def parse(data, options={})
136
+ data = CSV.parse(data)
137
+ col_names = data.shift
138
+ @contacts = data.map do |person|
139
+ ["#{person[0]} #{person[1]}", person[4]] if person[4] && !person[4].empty?
140
+ end.compact
141
+ end
142
+
143
+ def h_to_query_string(hash)
144
+ u = ERB::Util.method(:u)
145
+ hash.map{ |k, v| u.call(k) + "=" + u.call(v) }.join("&")
146
+ end
147
+ end
148
+ TYPES[:aolImporter] = AolImporter
149
+ end