Commit a868a78ff3c73f7f7f7e199155a607446642d6f8

Authored by Rodrigo Souto
Committed by Antonio Terceiro
1 parent 5fa16d48

Adding new version of contacts library

   * Added gdata as well since contacts need it. It uses the Apache
     License 2.0, so we are ok.
   * Used the current style of vendor libraries because we lack a better
     way to do it currently.

(ActionItem1348)
Showing 91 changed files with 3543 additions and 1085 deletions   Show diff stats
lib/contacts
1   -../vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/lib/contacts
2 1 \ No newline at end of file
  2 +../vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/lib/contacts
3 3 \ No newline at end of file
... ...
lib/contacts.rb
1   -../vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/lib/contacts.rb
2 1 \ No newline at end of file
  2 +../vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/lib/contacts.rb
3 3 \ No newline at end of file
... ...
lib/gdata 0 → 120000
... ... @@ -0,0 +1 @@
  1 +../vendor/gdata-1.1.1/lib/gdata
0 2 \ No newline at end of file
... ...
lib/gdata.rb 0 → 120000
... ... @@ -0,0 +1 @@
  1 +../vendor/gdata-1.1.1/lib/gdata.rb
0 2 \ No newline at end of file
... ...
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/.gitignore
... ... @@ -1,2 +0,0 @@
1   -.DS_Store
2   -test/accounts.yml
3 0 \ No newline at end of file
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/LICENSE
... ... @@ -1,10 +0,0 @@
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
... ... @@ -1,43 +0,0 @@
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
... ... @@ -1,90 +0,0 @@
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
91 0 \ No newline at end of file
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/contacts.gemspec
... ... @@ -1,13 +0,0 @@
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
... ... @@ -1,22 +0,0 @@
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
23 0 \ No newline at end of file
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/examples/grab_contacts.rb
... ... @@ -1,12 +0,0 @@
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
13 0 \ No newline at end of file
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/geminstaller.yml
... ... @@ -1,6 +0,0 @@
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
... ... @@ -1,8 +0,0 @@
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'
9 0 \ No newline at end of file
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/lib/contacts/base.rb
... ... @@ -1,210 +0,0 @@
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
... ... @@ -1,94 +0,0 @@
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
... ... @@ -1,179 +0,0 @@
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
180 0 \ No newline at end of file
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/lib/contacts/plaxo.rb
... ... @@ -1,123 +0,0 @@
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
... ... @@ -1,82 +0,0 @@
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
83 0 \ No newline at end of file
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/test/example_accounts.yml
... ... @@ -1,40 +0,0 @@
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
... ... @@ -1,30 +0,0 @@
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
... ... @@ -1,4 +0,0 @@
1   -dir = File.dirname(__FILE__)
2   -Dir["#{dir}/**/*_test.rb"].each do |file|
3   - require file
4   -end
5 0 \ No newline at end of file
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/test/unit/gmail_contact_importer_test.rb
... ... @@ -1,37 +0,0 @@
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
38 0 \ No newline at end of file
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/test/unit/hotmail_contact_importer_test.rb
... ... @@ -1,25 +0,0 @@
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
... ... @@ -1,23 +0,0 @@
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
24 0 \ No newline at end of file
vendor/cardmagic-contacts-cedf6f38c8fee32e119bae4005799ef073015b8d/test/unit/yahoo_csv_contact_importer_test.rb
... ... @@ -1,30 +0,0 @@
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
31 0 \ No newline at end of file
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/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-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/README 0 → 100644
... ... @@ -0,0 +1,47 @@
  1 +== Welcome to Contacts
  2 +
  3 +Contacts is a universal interface to grab contact list information from various providers including Hotmail, AOL, Gmail 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 +== 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 +* Waheed Barghouthi from Watwet (mailto:waheed.barghouthi@gmail.com) - http://watwet.com
  42 +* Glenn Sidney from Glenn Fu (mailto:glenn@glennfu.com) - http://glennfu.com
  43 +* Brian McQuay from Onomojo (mailto:brian@onomojo.com) - http://onomojo.com
  44 +* Adam Hunter (mailto:adamhunter@me.com) - http://adamhunter.me/
  45 +
  46 +This library is released under the terms of the BSD.
  47 +
... ...
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/Rakefile 0 → 100644
... ... @@ -0,0 +1,91 @@
  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 +] - ["test/accounts.yml"]
  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 = 'adamhunter-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.add_dependency('gdata', '= 1.1.1')
  66 + s.requirements << "A json parser, the gdata ruby gem"
  67 +
  68 + #### Documentation and testing.
  69 +
  70 + s.has_rdoc = true
  71 +
  72 + #### Author and project details.
  73 +
  74 + s.author = "Lucas Carlson"
  75 + s.email = "lucas@rufy.com"
  76 + s.homepage = "http://rubyforge.org/projects/contacts"
  77 +end
  78 +
  79 +Rake::GemPackageTask.new(spec) do |pkg|
  80 + pkg.need_zip = true
  81 + pkg.need_tar = true
  82 +end
  83 +
  84 +desc "Report code statistics (KLOCs, etc) from the application"
  85 +task :stats do
  86 + require 'code_statistics'
  87 + CodeStatistics.new(
  88 + ["Library", "lib"],
  89 + ["Units", "test"]
  90 + ).to_s
  91 +end
0 92 \ No newline at end of file
... ...
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/contacts.gemspec 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +Gem::Specification.new do |s|
  2 + s.name = "contacts"
  3 + s.version = "1.2.0"
  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/json_picker.rb", "lib/contacts/gmail.rb", "lib/contacts/aol.rb", "lib/contacts/hotmail.rb", "lib/contacts/plaxo.rb", "lib/contacts/yahoo.rb"]
  12 + s.add_dependency("json", ">= 1.1.1")
  13 + s.add_dependency('gdata', '>= 1.1.1')
  14 +end
... ...
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/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-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/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-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/geminstaller.yml 0 → 100644
... ... @@ -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
... ...
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/lib/contacts.rb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +$:.unshift(File.dirname(__FILE__)+"/contacts/")
  2 +
  3 +require 'rubygems'
  4 +
  5 +require 'base'
  6 +require 'gmail'
  7 +require 'hotmail'
  8 +require 'yahoo'
  9 +require 'plaxo'
  10 +require 'aol'
  11 +require 'json_picker'
0 12 \ No newline at end of file
... ...
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/lib/contacts/aol.rb 0 → 100644
... ... @@ -0,0 +1,148 @@
  1 +class Hash
  2 + def to_query_string
  3 + u = ERB::Util.method(:u)
  4 + map { |k, v|
  5 + u.call(k) + "=" + u.call(v)
  6 + }.join("&")
  7 + end
  8 +end
  9 +
  10 +class Contacts
  11 + require 'hpricot'
  12 + class Aol < Base
  13 + URL = "http://www.aol.com/"
  14 + LOGIN_URL = "https://my.screenname.aol.com/_cqr/login/login.psp"
  15 + LOGIN_REFERER_URL = "http://webmail.aol.com/"
  16 + LOGIN_REFERER_PATH = "sitedomain=sns.webmail.aol.com&lang=en&locale=us&authLev=0&uitype=mini&loginId=&redirType=js&xchk=false"
  17 + AOL_NUM = "29970-343" # this seems to change each time they change the protocol
  18 +
  19 + CONTACT_LIST_URL = "http://webmail.aol.com/#{AOL_NUM}/aim-2/en-us/Lite/ContactList.aspx?folder=Inbox&showUserFolders=False"
  20 + CONTACT_LIST_CSV_URL = "http://webmail.aol.com/#{AOL_NUM}/aim-2/en-us/Lite/ABExport.aspx?command=all"
  21 + 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"
  22 +
  23 + def real_connect
  24 +
  25 + postdata = {
  26 + "loginId" => login,
  27 + "password" => password,
  28 + "rememberMe" => "on",
  29 + "_sns_fg_color_" => "",
  30 + "_sns_err_color_" => "",
  31 + "_sns_link_color_" => "",
  32 + "_sns_width_" => "",
  33 + "_sns_height_" => "",
  34 + "offerId" => "mail-second-en-us",
  35 + "_sns_bg_color_" => "",
  36 + "sitedomain" => "sns.webmail.aol.com",
  37 + "regPromoCode" => "",
  38 + "mcState" => "initialized",
  39 + "uitype" => "std",
  40 + "siteId" => "",
  41 + "lang" => "en",
  42 + "locale" => "us",
  43 + "authLev" => "0",
  44 + "siteState" => "",
  45 + "isSiteStateEncoded" => "false",
  46 + "use_aam" => "0",
  47 + "seamless" => "novl",
  48 + "aolsubmit" => CGI.escape("Sign In"),
  49 + "idType" => "SN",
  50 + "usrd" => "",
  51 + "doSSL" => "",
  52 + "redirType" => "",
  53 + "xchk" => "false"
  54 + }
  55 +
  56 + # Get this cookie and stick it in the form to confirm to Aol that your cookies work
  57 + data, resp, cookies, forward = get(URL)
  58 + postdata["stips"] = cookie_hash_from_string(cookies)["stips"]
  59 + postdata["tst"] = cookie_hash_from_string(cookies)["tst"]
  60 +
  61 + data, resp, cookies, forward, old_url = get(LOGIN_REFERER_URL, cookies) + [URL]
  62 + until forward.nil?
  63 + data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
  64 + end
  65 +
  66 + data, resp, cookies, forward, old_url = get("#{LOGIN_URL}?#{LOGIN_REFERER_PATH}", cookies) + [LOGIN_REFERER_URL]
  67 + until forward.nil?
  68 + data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
  69 + end
  70 +
  71 + doc = Hpricot(data)
  72 + (doc/:input).each do |input|
  73 + postdata["usrd"] = input.attributes["value"] if input.attributes["name"] == "usrd"
  74 + end
  75 + # parse data for <input name="usrd" value="2726212" type="hidden"> and add it to the postdata
  76 +
  77 + postdata["SNS_SC"] = cookie_hash_from_string(cookies)["SNS_SC"]
  78 + postdata["SNS_LDC"] = cookie_hash_from_string(cookies)["SNS_LDC"]
  79 + postdata["LTState"] = cookie_hash_from_string(cookies)["LTState"]
  80 + # raise data.inspect
  81 +
  82 + data, resp, cookies, forward, old_url = post(LOGIN_URL, postdata.to_query_string, cookies, LOGIN_REFERER_URL) + [LOGIN_REFERER_URL]
  83 +
  84 + until forward.nil?
  85 + data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
  86 + end
  87 +
  88 + if data.index("Invalid Screen Name or Password.")
  89 + raise AuthenticationError, "Username and password do not match"
  90 + elsif data.index("Required field must not be blank")
  91 + raise AuthenticationError, "Login and password must not be blank"
  92 + elsif data.index("errormsg_0_logincaptcha")
  93 + raise AuthenticationError, "Captcha error"
  94 + elsif data.index("Invalid request")
  95 + raise ConnectionError, PROTOCOL_ERROR
  96 + elsif cookies == ""
  97 + raise ConnectionError, PROTOCOL_ERROR
  98 + end
  99 +
  100 + @cookies = cookies
  101 + end
  102 +
  103 + def contacts
  104 + postdata = {
  105 + "file" => 'contacts',
  106 + "fileType" => 'csv'
  107 + }
  108 +
  109 + return @contacts if @contacts
  110 + if connected?
  111 + data, resp, cookies, forward, old_url = get(CONTACT_LIST_URL, @cookies, CONTACT_LIST_URL) + [CONTACT_LIST_URL]
  112 +
  113 + until forward.nil?
  114 + data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
  115 + end
  116 +
  117 + if resp.code_type != Net::HTTPOK
  118 + raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
  119 + end
  120 +
  121 + # parse data and grab <input name="user" value="8QzMPIAKs2" type="hidden">
  122 + doc = Hpricot(data)
  123 + (doc/:input).each do |input|
  124 + postdata["user"] = input.attributes["value"] if input.attributes["name"] == "user"
  125 + end
  126 +
  127 + data, resp, cookies, forward, old_url = get(CONTACT_LIST_CSV_URL, @cookies, CONTACT_LIST_URL) + [CONTACT_LIST_URL]
  128 +
  129 + if forward.nil?
  130 + parse data
  131 + else
  132 + raise AuthenticationError, "Account cancelled"
  133 + end
  134 + end
  135 + end
  136 + private
  137 +
  138 + def parse(data, options={})
  139 + data = CSV.parse(data)
  140 + col_names = data.shift
  141 + @contacts = data.map do |person|
  142 + ["#{person[0]} #{person[1]}", person[4]] unless person[4].empty?
  143 + end.compact
  144 + end
  145 + end
  146 +
  147 + TYPES[:aol] = Aol
  148 +end
0 149 \ No newline at end of file
... ...
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/lib/contacts/base.rb 0 → 100644
... ... @@ -0,0 +1,215 @@
  1 +require "cgi"
  2 +require "net/http"
  3 +require "net/https"
  4 +require "uri"
  5 +require "zlib"
  6 +require "stringio"
  7 +require "thread"
  8 +require "erb"
  9 +
  10 +class Contacts
  11 + TYPES = {}
  12 + VERSION = "1.2.0"
  13 +
  14 + class Base
  15 + def initialize(login, password)
  16 + @login = login
  17 + @password = password
  18 + @connections = {}
  19 + connect
  20 + end
  21 +
  22 + def connect
  23 + raise AuthenticationError, "Login and password must not be nil, login: #{@login.inspect}, password: #{@password.inspect}" if @login.nil? || @login.empty? || @password.nil? || @password.empty?
  24 + real_connect
  25 + end
  26 +
  27 + def connected?
  28 + @cookies && !@cookies.empty?
  29 + end
  30 +
  31 + def contacts(options = {})
  32 + return @contacts if @contacts
  33 + if connected?
  34 + url = URI.parse(contact_list_url)
  35 + http = open_http(url)
  36 + resp, data = http.get("#{url.path}?#{url.query}",
  37 + "Cookie" => @cookies
  38 + )
  39 +
  40 + if resp.code_type != Net::HTTPOK
  41 + raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
  42 + end
  43 +
  44 + parse(data, options)
  45 + end
  46 + end
  47 +
  48 + def login
  49 + @attempt ||= 0
  50 + @attempt += 1
  51 +
  52 + if @attempt == 1
  53 + @login
  54 + else
  55 + if @login.include?("@#{domain}")
  56 + @login.sub("@#{domain}","")
  57 + else
  58 + "#{@login}@#{domain}"
  59 + end
  60 + end
  61 + end
  62 +
  63 + def password
  64 + @password
  65 + end
  66 +
  67 + private
  68 +
  69 + def domain
  70 + @d ||= URI.parse(self.class.const_get(:URL)).host.sub(/^www\./,'')
  71 + end
  72 +
  73 + def contact_list_url
  74 + self.class.const_get(:CONTACT_LIST_URL)
  75 + end
  76 +
  77 + def address_book_url
  78 + self.class.const_get(:ADDRESS_BOOK_URL)
  79 + end
  80 +
  81 + def open_http(url)
  82 + c = @connections[Thread.current.object_id] ||= {}
  83 + http = c["#{url.host}:#{url.port}"]
  84 + unless http
  85 + http = Net::HTTP.new(url.host, url.port)
  86 + if url.port == 443
  87 + http.use_ssl = true
  88 + http.verify_mode = OpenSSL::SSL::VERIFY_NONE
  89 + end
  90 + c["#{url.host}:#{url.port}"] = http
  91 + end
  92 + http.start unless http.started?
  93 + http
  94 + end
  95 +
  96 + def cookie_hash_from_string(cookie_string)
  97 + cookie_string.split(";").map{|i|i.split("=", 2).map{|j|j.strip}}.inject({}){|h,i|h[i[0]]=i[1];h}
  98 + end
  99 +
  100 + def parse_cookies(data, existing="")
  101 + return existing if data.nil?
  102 +
  103 + cookies = cookie_hash_from_string(existing)
  104 +
  105 + data.gsub!(/ ?[\w]+=EXPIRED;/,'')
  106 + data.gsub!(/ ?expires=(.*?, .*?)[;,$]/i, ';')
  107 + data.gsub!(/ ?(domain|path)=[\S]*?[;,$]/i,';')
  108 + data.gsub!(/[,;]?\s*(secure|httponly)/i,'')
  109 + data.gsub!(/(;\s*){2,}/,', ')
  110 + data.gsub!(/(,\s*){2,}/,', ')
  111 + data.sub!(/^,\s*/,'')
  112 + data.sub!(/\s*,$/,'')
  113 +
  114 + data.split(", ").map{|t|t.to_s.split(";").first}.each do |data|
  115 + k, v = data.split("=", 2).map{|j|j.strip}
  116 + if cookies[k] && v.empty?
  117 + cookies.delete(k)
  118 + elsif v && !v.empty?
  119 + cookies[k] = v
  120 + end
  121 + end
  122 +
  123 + cookies.map{|k,v| "#{k}=#{v}"}.join("; ")
  124 + end
  125 +
  126 + def remove_cookie(cookie, cookies)
  127 + parse_cookies("#{cookie}=", cookies)
  128 + end
  129 +
  130 + def post(url, postdata, cookies="", referer="")
  131 + url = URI.parse(url)
  132 + http = open_http(url)
  133 + resp, data = http.post(url.path, postdata,
  134 + "User-Agent" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0",
  135 + "Accept-Encoding" => "gzip",
  136 + "Cookie" => cookies,
  137 + "Referer" => referer,
  138 + "Content-Type" => 'application/x-www-form-urlencoded'
  139 + )
  140 + data = uncompress(resp, data)
  141 + cookies = parse_cookies(resp.response['set-cookie'], cookies)
  142 + forward = resp.response['Location']
  143 + forward ||= (data =~ /<meta.*?url='([^']+)'/ ? CGI.unescapeHTML($1) : nil)
  144 + if (not forward.nil?) && URI.parse(forward).host.nil?
  145 + forward = url.scheme.to_s + "://" + url.host.to_s + forward
  146 + end
  147 + return data, resp, cookies, forward
  148 + end
  149 +
  150 + def get(url, cookies="", referer="")
  151 + url = URI.parse(url)
  152 + http = open_http(url)
  153 + resp, data = http.get("#{url.path}?#{url.query}",
  154 + "User-Agent" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0",
  155 + "Accept-Encoding" => "gzip",
  156 + "Cookie" => cookies,
  157 + "Referer" => referer
  158 + )
  159 + data = uncompress(resp, data)
  160 + cookies = parse_cookies(resp.response['set-cookie'], cookies)
  161 + forward = resp.response['Location']
  162 + if (not forward.nil?) && URI.parse(forward).host.nil?
  163 + forward = url.scheme.to_s + "://" + url.host.to_s + forward
  164 + end
  165 + return data, resp, cookies, forward
  166 + end
  167 +
  168 + def uncompress(resp, data)
  169 + case resp.response['content-encoding']
  170 + when 'gzip':
  171 + gz = Zlib::GzipReader.new(StringIO.new(data))
  172 + data = gz.read
  173 + gz.close
  174 + resp.response['content-encoding'] = nil
  175 + # FIXME: Not sure what Hotmail was feeding me with their 'deflate',
  176 + # but the headers definitely were not right
  177 + when 'deflate':
  178 + data = Zlib::Inflate.inflate(data)
  179 + resp.response['content-encoding'] = nil
  180 + end
  181 +
  182 + data
  183 + end
  184 + end
  185 +
  186 + class ContactsError < StandardError
  187 + end
  188 +
  189 + class AuthenticationError < ContactsError
  190 + end
  191 +
  192 + class ConnectionError < ContactsError
  193 + end
  194 +
  195 + class TypeNotFound < ContactsError
  196 + end
  197 +
  198 + def self.new(type, login, password)
  199 + if TYPES.include?(type.to_s.intern)
  200 + TYPES[type.to_s.intern].new(login, password)
  201 + else
  202 + raise TypeNotFound, "#{type.inspect} is not a valid type, please choose one of the following: #{TYPES.keys.inspect}"
  203 + end
  204 + end
  205 +
  206 + def self.guess(login, password)
  207 + TYPES.inject([]) do |a, t|
  208 + begin
  209 + a + t[1].new(login, password).contacts
  210 + rescue AuthenticationError
  211 + a
  212 + end
  213 + end.uniq
  214 + end
  215 +end
... ...
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/lib/contacts/gmail.rb 0 → 100644
... ... @@ -0,0 +1,35 @@
  1 +require 'gdata'
  2 +
  3 +class Contacts
  4 + class Gmail < Base
  5 +
  6 + CONTACTS_SCOPE = 'http://www.google.com/m8/feeds/'
  7 + CONTACTS_FEED = CONTACTS_SCOPE + 'contacts/default/full/?max-results=1000'
  8 +
  9 + def contacts
  10 + return @contacts if @contacts
  11 + end
  12 +
  13 + def real_connect
  14 + @client = GData::Client::Contacts.new
  15 + @client.clientlogin(@login, @password)
  16 +
  17 + feed = @client.get(CONTACTS_FEED).to_xml
  18 +
  19 + @contacts = feed.elements.to_a('entry').collect do |entry|
  20 + title, email = entry.elements['title'].text, nil
  21 + entry.elements.each('gd:email') do |e|
  22 + email = e.attribute('address').value if e.attribute('primary')
  23 + end
  24 + [title, email] unless email.nil?
  25 + end
  26 + @contacts.compact!
  27 + rescue GData::Client::AuthorizationError => e
  28 + raise AuthenticationError, "Username or password are incorrect"
  29 + end
  30 +
  31 + private
  32 +
  33 + TYPES[:gmail] = Gmail
  34 + end
  35 +end
0 36 \ No newline at end of file
... ...
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/lib/contacts/hotmail.rb 0 → 100644
... ... @@ -0,0 +1,124 @@
  1 +class Contacts
  2 + class Hotmail < Base
  3 + URL = "https://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 + CONTACT_LIST_URL = "http://mpeople.live.com/default.aspx?pg=0"
  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 + old_url = URL
  15 + until forward.nil?
  16 + data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
  17 + end
  18 +
  19 + postdata = "PPSX=%s&PwdPad=%s&login=%s&passwd=%s&LoginOptions=2&PPFT=%s" % [
  20 + CGI.escape(data.split("><").grep(/PPSX/).first[/=\S+$/][2..-3]),
  21 + PWDPAD[0...(PWDPAD.length-@password.length)],
  22 + CGI.escape(login),
  23 + CGI.escape(password),
  24 + CGI.escape(data.split("><").grep(/PPFT/).first[/=\S+$/][2..-3])
  25 + ]
  26 +
  27 + form_url = data.split("><").grep(/form/).first.split[5][8..-2]
  28 + data, resp, cookies, forward = post(form_url, postdata, cookies)
  29 +
  30 + old_url = form_url
  31 + until cookies =~ /; PPAuth=/ || forward.nil?
  32 + data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
  33 + end
  34 +
  35 + if data.index("The e-mail address or password is incorrect")
  36 + raise AuthenticationError, "Username and password do not match"
  37 + elsif data != ""
  38 + raise AuthenticationError, "Required field must not be blank"
  39 + elsif cookies == ""
  40 + raise ConnectionError, PROTOCOL_ERROR
  41 + end
  42 +
  43 + data, resp, cookies, forward = get("http://mail.live.com/mail", cookies)
  44 + until forward.nil?
  45 + data, resp, cookies, forward, old_url = get(forward, cookies, old_url) + [forward]
  46 + end
  47 +
  48 + @domain = URI.parse(old_url).host
  49 + @cookies = cookies
  50 + rescue AuthenticationError => m
  51 + if @attempt == 1
  52 + retry
  53 + else
  54 + raise m
  55 + end
  56 + end
  57 +
  58 + def contacts(options = {})
  59 + if connected?
  60 + url = URI.parse(contact_list_url)
  61 + data, resp, cookies, forward = get( contact_list_url, @cookies )
  62 +
  63 + if resp.code_type != Net::HTTPOK
  64 + raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
  65 + end
  66 +
  67 + @contacts = []
  68 + build_contacts = []
  69 + go = true
  70 + index = 0
  71 +
  72 + while(go) do
  73 + go = false
  74 + url = URI.parse(get_contact_list_url(index))
  75 + http = open_http(url)
  76 + resp, data = http.get(get_contact_list_url(index), "Cookie" => @cookies)
  77 +
  78 + email_match_text_beginning = Regexp.escape("http://m.mail.live.com/?rru=compose&amp;to=")
  79 + email_match_text_end = Regexp.escape("&amp;")
  80 +
  81 + raw_html = resp.body.grep(/(?:e|dn)lk[0-9]+/)
  82 + raw_html.delete_at 0
  83 + raw_html.inject do |memo, row|
  84 + c_info = row.match(/(e|dn)lk([0-9])+/)
  85 +
  86 + # Same contact, or different?
  87 + build_contacts << [] if memo != c_info[2]
  88 +
  89 + # Grab info
  90 + case c_info[1]
  91 + when "e" # Email
  92 + build_contacts.last[1] = row.match(/#{email_match_text_beginning}(.*)#{email_match_text_end}/)[1]
  93 + when "dn" # Name
  94 + build_contacts.last[0] = row.match(/<a[^>]*>(.+)<\/a>/)[1]
  95 + end
  96 +
  97 + # Set memo to contact id
  98 + c_info[2]
  99 + end
  100 +
  101 + go = resp.body.include?("Next page")
  102 + index += 1
  103 + end
  104 +
  105 + build_contacts.each do |contact|
  106 + unless contact[1].nil?
  107 + # Only return contacts with email addresses
  108 + contact[1] = CGI::unescape(contact[1])
  109 + @contacts << contact
  110 + end
  111 + end
  112 + return @contacts
  113 + end
  114 + end
  115 +
  116 + def get_contact_list_url(index)
  117 + "http://mpeople.live.com/default.aspx?pg=#{index}"
  118 + end
  119 +
  120 + private
  121 +
  122 + TYPES[:hotmail] = Hotmail
  123 + end
  124 +end
0 125 \ No newline at end of file
... ...
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/lib/contacts/json_picker.rb 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +if !Object.const_defined?('ActiveSupport')
  2 + require 'json'
  3 +end
  4 +
  5 +class Contacts
  6 + def self.parse_json( string )
  7 + if Object.const_defined?('ActiveSupport') and
  8 + ActiveSupport.const_defined?('JSON')
  9 + ActiveSupport::JSON.decode( string )
  10 + elsif Object.const_defined?('JSON')
  11 + JSON.parse( string )
  12 + else
  13 + raise 'Contacts requires JSON or Rails (with ActiveSupport::JSON)'
  14 + end
  15 + end
  16 +end
0 17 \ No newline at end of file
... ...
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/lib/contacts/plaxo.rb 0 → 100644
... ... @@ -0,0 +1,130 @@
  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 = if cont.elements['fullName']
  38 + cont.elements['fullName'].text
  39 + elsif cont.elements['displayName']
  40 + cont.elements['displayName'].text
  41 + end
  42 + email = if cont.elements['email1']
  43 + cont.elements['email1'].text
  44 + end
  45 + if name || email
  46 + @contacts << [name, email]
  47 + end
  48 + end
  49 + @contacts
  50 + else
  51 + raise ConnectionError, PROTOCOL_ERROR
  52 + end
  53 +
  54 + end # parse
  55 +
  56 + end # Plaxo
  57 +
  58 + TYPES[:plaxo] = Plaxo
  59 +
  60 +end # Contacts
  61 +
  62 +
  63 +# sample contacts responses
  64 +=begin
  65 +Bad email
  66 +=========
  67 +<?xml version="1.0" encoding="utf-8" ?>
  68 +<ns1:GetContactsResponse xmlns:ns1="Plaxo">
  69 + <response>
  70 + <code>401</code>
  71 + <subCode>1</subCode>
  72 + <message>User not found.</message>
  73 + </response>
  74 +</ns1:GetContactsResponse>
  75 +
  76 +
  77 +Bad password
  78 +============
  79 +<?xml version="1.0" encoding="utf-8" ?>
  80 +<ns1:GetContactsResponse xmlns:ns1="Plaxo">
  81 + <response>
  82 + <code>401</code>
  83 + <subCode>4</subCode>
  84 + <message>Bad password or security token.</message>
  85 + </response>
  86 +</ns1:GetContactsResponse>
  87 +
  88 +
  89 +Success
  90 +=======
  91 +<?xml version="1.0" encoding="utf-8" ?>
  92 +<ns1:GetContactsResponse xmlns:ns1="Plaxo">
  93 +
  94 + <response>
  95 + <code>200</code>
  96 + <message>OK</message>
  97 + <userId>77311236242</userId>
  98 + </response>
  99 +
  100 + <contacts>
  101 +
  102 + <contact>
  103 + <itemId>61312569</itemId>
  104 + <displayName>Joe Blow1</displayName>
  105 + <fullName>Joe Blow1</fullName>
  106 + <firstName>Joe</firstName>
  107 + <lastName>Blow1</lastName>
  108 + <homeEmail1>joeblow1@mailinator.com</homeEmail1>
  109 + <email1>joeblow1@mailinator.com</email1>
  110 + <folderId>5291351</folderId>
  111 + </contact>
  112 +
  113 + <contact>
  114 + <itemId>61313159</itemId>
  115 + <displayName>Joe Blow2</displayName>
  116 + <fullName>Joe Blow2</fullName>
  117 + <firstName>Joe</firstName>
  118 + <lastName>Blow2</lastName>
  119 + <homeEmail1>joeblow2@mailinator.com</homeEmail1>
  120 + <email1>joeblow2@mailinator.com</email1>
  121 + <folderId>5291351</folderId>
  122 + </contact>
  123 +
  124 + </contacts>
  125 +
  126 + <totalCount>2</totalCount>
  127 + <editCounter>3</editCounter>
  128 +
  129 +</ns1:GetContactsResponse>
  130 +=end
0 131 \ No newline at end of file
... ...
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/lib/contacts/yahoo.rb 0 → 100644
... ... @@ -0,0 +1,109 @@
  1 +class Contacts
  2 + class Yahoo < Base
  3 + URL = "http://mail.yahoo.com/"
  4 + LOGIN_URL = "https://login.yahoo.com/config/login"
  5 + ADDRESS_BOOK_URL = "http://address.mail.yahoo.com/?.rand=430244936"
  6 + CONTACT_LIST_URL = "http://address.mail.yahoo.com/?_src=&_crumb=crumb&sortfield=3&bucket=1&scroll=1&VPC=social_list&.r=time"
  7 + 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"
  8 +
  9 + def real_connect
  10 + postdata = ".tries=2&.src=ym&.md5=&.hash=&.js=&.last=&promo=&.intl=us&.bypass="
  11 + postdata += "&.partner=&.u=4eo6isd23l8r3&.v=0&.challenge=gsMsEcoZP7km3N3NeI4mX"
  12 + postdata += "kGB7zMV&.yplus=&.emailCode=&pkg=&stepid=&.ev=&hasMsgr=1&.chkP=Y&."
  13 + postdata += "done=#{CGI.escape(URL)}&login=#{CGI.escape(login)}&passwd=#{CGI.escape(password)}"
  14 +
  15 + data, resp, cookies, forward = post(LOGIN_URL, postdata)
  16 +
  17 + if data.index("Invalid ID or password") || data.index("This ID is not yet taken")
  18 + raise AuthenticationError, "Username and password do not match"
  19 + elsif data.index("Sign in") && data.index("to Yahoo!")
  20 + raise AuthenticationError, "Required field must not be blank"
  21 + elsif !data.match(/uncompressed\/chunked/)
  22 + raise ConnectionError, PROTOCOL_ERROR
  23 + elsif cookies == ""
  24 + raise ConnectionError, PROTOCOL_ERROR
  25 + end
  26 +
  27 + data, resp, cookies, forward = get(forward, cookies, LOGIN_URL)
  28 +
  29 + if resp.code_type != Net::HTTPOK
  30 + raise ConnectionError, PROTOCOL_ERROR
  31 + end
  32 +
  33 + @cookies = cookies
  34 + end
  35 +
  36 + def contacts
  37 + return @contacts if @contacts
  38 + if connected?
  39 + # first, get the addressbook site with the new crumb parameter
  40 + url = URI.parse(address_book_url)
  41 + http = open_http(url)
  42 + resp, data = http.get("#{url.path}?#{url.query}",
  43 + "Cookie" => @cookies
  44 + )
  45 +
  46 + if resp.code_type != Net::HTTPOK
  47 + raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
  48 + end
  49 +
  50 + crumb = data.to_s[/dotCrumb: '(.*?)'/][13...-1]
  51 +
  52 + # now proceed with the new ".crumb" parameter to get the csv data
  53 + url = URI.parse(contact_list_url.sub("_crumb=crumb","_crumb=#{crumb}").sub("time", Time.now.to_f.to_s.sub(".","")[0...-2]))
  54 + http = open_http(url)
  55 + resp, more_data = http.get("#{url.path}?#{url.query}",
  56 + "Cookie" => @cookies,
  57 + "X-Requested-With" => "XMLHttpRequest",
  58 + "Referer" => address_book_url
  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 +
  67 + parse more_data
  68 +
  69 + if more_data =~ /"TotalABContacts":(\d+)/
  70 + total = $1.to_i
  71 + ((total / 50)).times do |i|
  72 + # now proceed with the new ".crumb" parameter to get the csv data
  73 + url = URI.parse(contact_list_url.sub("bucket=1","bucket=#{i+2}").sub("_crumb=crumb","_crumb=#{crumb}").sub("time", Time.now.to_f.to_s.sub(".","")[0...-2]))
  74 + http = open_http(url)
  75 + resp, more_data = http.get("#{url.path}?#{url.query}",
  76 + "Cookie" => @cookies,
  77 + "X-Requested-With" => "XMLHttpRequest",
  78 + "Referer" => address_book_url
  79 + )
  80 +
  81 + if resp.code_type != Net::HTTPOK
  82 + raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
  83 + end
  84 +
  85 + parse more_data
  86 + end
  87 + end
  88 +
  89 + @contacts
  90 + end
  91 + end
  92 +
  93 + private
  94 +
  95 + def parse(data, options={})
  96 + @contacts ||= []
  97 + if data =~ /var InitialContacts = (\[.*?\])/
  98 + @contacts += Contacts.parse_json($1).select{|contact|!contact["email"].to_s.empty?}.map{|contact|[contact["contactName"], contact["email"]]}
  99 + elsif data =~ /^\{"response":/
  100 + @contacts += Contacts.parse_json(data)["response"]["ResultSet"]["Contacts"].to_a.select{|contact|!contact["email"].to_s.empty?}.map{|contact|[contact["contactName"], contact["email"]]}
  101 + else
  102 + @contacts
  103 + end
  104 + end
  105 +
  106 + end
  107 +
  108 + TYPES[:yahoo] = Yahoo
  109 +end
0 110 \ No newline at end of file
... ...
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/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-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/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-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/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-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/test/unit/aol_contact_importer_test.rb 0 → 100644
... ... @@ -0,0 +1,39 @@
  1 +dir = File.dirname(__FILE__)
  2 +require "#{dir}/../test_helper"
  3 +require 'contacts'
  4 +
  5 +class AolContactImporterTest < ContactImporterTestCase
  6 + def setup
  7 + super
  8 + @account = TestAccounts[:aol]
  9 + end
  10 +
  11 + def test_successful_login
  12 + Contacts.new(:aol, @account.username, @account.password)
  13 + end
  14 +
  15 + def test_importer_fails_with_invalid_password
  16 + assert_raise(Contacts::AuthenticationError) do
  17 + Contacts.new(:aol, @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(:aol, @account.username, "")
  24 + end
  25 + end
  26 +
  27 + def test_importer_fails_with_blank_username
  28 + assert_raise(Contacts::AuthenticationError) do
  29 + Contacts.new(:aol, "", @account.password)
  30 + end
  31 + end
  32 +
  33 + def test_fetch_contacts
  34 + contacts = Contacts.new(:aol, @account.username, @account.password).contacts
  35 + @account.contacts.each do |contact|
  36 + assert contacts.include?(contact), "Could not find: #{contact.inspect} in #{contacts.inspect}"
  37 + end
  38 + end
  39 +end
0 40 \ No newline at end of file
... ...
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/test/unit/gmail_contact_importer_test.rb 0 → 100644
... ... @@ -0,0 +1,39 @@
  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 + @account.contacts.each do |contact|
  36 + assert contacts.include?(contact), "Could not find: #{contact.inspect} in #{contacts.inspect}"
  37 + end
  38 + end
  39 +end
0 40 \ No newline at end of file
... ...
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/test/unit/hotmail_contact_importer_test.rb 0 → 100644
... ... @@ -0,0 +1,41 @@
  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 + @account.contacts.each do |contact|
  24 + assert contacts.include?(contact), "Could not find: #{contact.inspect} in #{contacts.inspect}"
  25 + end
  26 + end
  27 +
  28 + def test_importer_fails_with_invalid_msn_password
  29 + assert_raise(Contacts::AuthenticationError) do
  30 + Contacts.new(:hotmail, "test@msn.com","wrong_password")
  31 + end
  32 + end
  33 +
  34 + # Since the hotmail scraper doesn't read names, test email
  35 + def test_fetch_email
  36 + contacts = Contacts.new(:hotmail, @account.username, @account.password).contacts
  37 + @account.contacts.each do |contact|
  38 + assert contacts.any?{|book_contact| book_contact.last == contact.last }, "Could not find: #{contact.inspect} in #{contacts.inspect}"
  39 + end
  40 + end
  41 +end
... ...
vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/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-f66219e6589ccaf3ab9e3574fdd41225d0dd5073/test/unit/yahoo_csv_contact_importer_test.rb 0 → 100644
... ... @@ -0,0 +1,32 @@
  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_a_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_a_fetch_contacts
  27 + contacts = Contacts.new(:yahoo, @account.username, @account.password).contacts
  28 + @account.contacts.each do |contact|
  29 + assert contacts.include?(contact), "Could not find: #{contact.inspect} in #{contacts.inspect}"
  30 + end
  31 + end
  32 +end
0 33 \ No newline at end of file
... ...
vendor/gdata-1.1.1/LICENSE 0 → 100644
... ... @@ -0,0 +1,202 @@
  1 +
  2 + Apache License
  3 + Version 2.0, January 2004
  4 + http://www.apache.org/licenses/
  5 +
  6 +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
  7 +
  8 +1. Definitions.
  9 +
  10 + "License" shall mean the terms and conditions for use, reproduction,
  11 + and distribution as defined by Sections 1 through 9 of this document.
  12 +
  13 + "Licensor" shall mean the copyright owner or entity authorized by
  14 + the copyright owner that is granting the License.
  15 +
  16 + "Legal Entity" shall mean the union of the acting entity and all
  17 + other entities that control, are controlled by, or are under common
  18 + control with that entity. For the purposes of this definition,
  19 + "control" means (i) the power, direct or indirect, to cause the
  20 + direction or management of such entity, whether by contract or
  21 + otherwise, or (ii) ownership of fifty percent (50%) or more of the
  22 + outstanding shares, or (iii) beneficial ownership of such entity.
  23 +
  24 + "You" (or "Your") shall mean an individual or Legal Entity
  25 + exercising permissions granted by this License.
  26 +
  27 + "Source" form shall mean the preferred form for making modifications,
  28 + including but not limited to software source code, documentation
  29 + source, and configuration files.
  30 +
  31 + "Object" form shall mean any form resulting from mechanical
  32 + transformation or translation of a Source form, including but
  33 + not limited to compiled object code, generated documentation,
  34 + and conversions to other media types.
  35 +
  36 + "Work" shall mean the work of authorship, whether in Source or
  37 + Object form, made available under the License, as indicated by a
  38 + copyright notice that is included in or attached to the work
  39 + (an example is provided in the Appendix below).
  40 +
  41 + "Derivative Works" shall mean any work, whether in Source or Object
  42 + form, that is based on (or derived from) the Work and for which the
  43 + editorial revisions, annotations, elaborations, or other modifications
  44 + represent, as a whole, an original work of authorship. For the purposes
  45 + of this License, Derivative Works shall not include works that remain
  46 + separable from, or merely link (or bind by name) to the interfaces of,
  47 + the Work and Derivative Works thereof.
  48 +
  49 + "Contribution" shall mean any work of authorship, including
  50 + the original version of the Work and any modifications or additions
  51 + to that Work or Derivative Works thereof, that is intentionally
  52 + submitted to Licensor for inclusion in the Work by the copyright owner
  53 + or by an individual or Legal Entity authorized to submit on behalf of
  54 + the copyright owner. For the purposes of this definition, "submitted"
  55 + means any form of electronic, verbal, or written communication sent
  56 + to the Licensor or its representatives, including but not limited to
  57 + communication on electronic mailing lists, source code control systems,
  58 + and issue tracking systems that are managed by, or on behalf of, the
  59 + Licensor for the purpose of discussing and improving the Work, but
  60 + excluding communication that is conspicuously marked or otherwise
  61 + designated in writing by the copyright owner as "Not a Contribution."
  62 +
  63 + "Contributor" shall mean Licensor and any individual or Legal Entity
  64 + on behalf of whom a Contribution has been received by Licensor and
  65 + subsequently incorporated within the Work.
  66 +
  67 +2. Grant of Copyright License. Subject to the terms and conditions of
  68 + this License, each Contributor hereby grants to You a perpetual,
  69 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable
  70 + copyright license to reproduce, prepare Derivative Works of,
  71 + publicly display, publicly perform, sublicense, and distribute the
  72 + Work and such Derivative Works in Source or Object form.
  73 +
  74 +3. Grant of Patent License. Subject to the terms and conditions of
  75 + this License, each Contributor hereby grants to You a perpetual,
  76 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable
  77 + (except as stated in this section) patent license to make, have made,
  78 + use, offer to sell, sell, import, and otherwise transfer the Work,
  79 + where such license applies only to those patent claims licensable
  80 + by such Contributor that are necessarily infringed by their
  81 + Contribution(s) alone or by combination of their Contribution(s)
  82 + with the Work to which such Contribution(s) was submitted. If You
  83 + institute patent litigation against any entity (including a
  84 + cross-claim or counterclaim in a lawsuit) alleging that the Work
  85 + or a Contribution incorporated within the Work constitutes direct
  86 + or contributory patent infringement, then any patent licenses
  87 + granted to You under this License for that Work shall terminate
  88 + as of the date such litigation is filed.
  89 +
  90 +4. Redistribution. You may reproduce and distribute copies of the
  91 + Work or Derivative Works thereof in any medium, with or without
  92 + modifications, and in Source or Object form, provided that You
  93 + meet the following conditions:
  94 +
  95 + (a) You must give any other recipients of the Work or
  96 + Derivative Works a copy of this License; and
  97 +
  98 + (b) You must cause any modified files to carry prominent notices
  99 + stating that You changed the files; and
  100 +
  101 + (c) You must retain, in the Source form of any Derivative Works
  102 + that You distribute, all copyright, patent, trademark, and
  103 + attribution notices from the Source form of the Work,
  104 + excluding those notices that do not pertain to any part of
  105 + the Derivative Works; and
  106 +
  107 + (d) If the Work includes a "NOTICE" text file as part of its
  108 + distribution, then any Derivative Works that You distribute must
  109 + include a readable copy of the attribution notices contained
  110 + within such NOTICE file, excluding those notices that do not
  111 + pertain to any part of the Derivative Works, in at least one
  112 + of the following places: within a NOTICE text file distributed
  113 + as part of the Derivative Works; within the Source form or
  114 + documentation, if provided along with the Derivative Works; or,
  115 + within a display generated by the Derivative Works, if and
  116 + wherever such third-party notices normally appear. The contents
  117 + of the NOTICE file are for informational purposes only and
  118 + do not modify the License. You may add Your own attribution
  119 + notices within Derivative Works that You distribute, alongside
  120 + or as an addendum to the NOTICE text from the Work, provided
  121 + that such additional attribution notices cannot be construed
  122 + as modifying the License.
  123 +
  124 + You may add Your own copyright statement to Your modifications and
  125 + may provide additional or different license terms and conditions
  126 + for use, reproduction, or distribution of Your modifications, or
  127 + for any such Derivative Works as a whole, provided Your use,
  128 + reproduction, and distribution of the Work otherwise complies with
  129 + the conditions stated in this License.
  130 +
  131 +5. Submission of Contributions. Unless You explicitly state otherwise,
  132 + any Contribution intentionally submitted for inclusion in the Work
  133 + by You to the Licensor shall be under the terms and conditions of
  134 + this License, without any additional terms or conditions.
  135 + Notwithstanding the above, nothing herein shall supersede or modify
  136 + the terms of any separate license agreement you may have executed
  137 + with Licensor regarding such Contributions.
  138 +
  139 +6. Trademarks. This License does not grant permission to use the trade
  140 + names, trademarks, service marks, or product names of the Licensor,
  141 + except as required for reasonable and customary use in describing the
  142 + origin of the Work and reproducing the content of the NOTICE file.
  143 +
  144 +7. Disclaimer of Warranty. Unless required by applicable law or
  145 + agreed to in writing, Licensor provides the Work (and each
  146 + Contributor provides its Contributions) on an "AS IS" BASIS,
  147 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  148 + implied, including, without limitation, any warranties or conditions
  149 + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
  150 + PARTICULAR PURPOSE. You are solely responsible for determining the
  151 + appropriateness of using or redistributing the Work and assume any
  152 + risks associated with Your exercise of permissions under this License.
  153 +
  154 +8. Limitation of Liability. In no event and under no legal theory,
  155 + whether in tort (including negligence), contract, or otherwise,
  156 + unless required by applicable law (such as deliberate and grossly
  157 + negligent acts) or agreed to in writing, shall any Contributor be
  158 + liable to You for damages, including any direct, indirect, special,
  159 + incidental, or consequential damages of any character arising as a
  160 + result of this License or out of the use or inability to use the
  161 + Work (including but not limited to damages for loss of goodwill,
  162 + work stoppage, computer failure or malfunction, or any and all
  163 + other commercial damages or losses), even if such Contributor
  164 + has been advised of the possibility of such damages.
  165 +
  166 +9. Accepting Warranty or Additional Liability. While redistributing
  167 + the Work or Derivative Works thereof, You may choose to offer,
  168 + and charge a fee for, acceptance of support, warranty, indemnity,
  169 + or other liability obligations and/or rights consistent with this
  170 + License. However, in accepting such obligations, You may act only
  171 + on Your own behalf and on Your sole responsibility, not on behalf
  172 + of any other Contributor, and only if You agree to indemnify,
  173 + defend, and hold each Contributor harmless for any liability
  174 + incurred by, or claims asserted against, such Contributor by reason
  175 + of your accepting any such warranty or additional liability.
  176 +
  177 +END OF TERMS AND CONDITIONS
  178 +
  179 +APPENDIX: How to apply the Apache License to your work.
  180 +
  181 + To apply the Apache License to your work, attach the following
  182 + boilerplate notice, with the fields enclosed by brackets "[]"
  183 + replaced with your own identifying information. (Don't include
  184 + the brackets!) The text should be enclosed in the appropriate
  185 + comment syntax for the file format. We also recommend that a
  186 + file or class name and description of purpose be included on the
  187 + same "printed page" as the copyright notice for easier
  188 + identification within third-party archives.
  189 +
  190 +Copyright [yyyy] [name of copyright owner]
  191 +
  192 +Licensed under the Apache License, Version 2.0 (the "License");
  193 +you may not use this file except in compliance with the License.
  194 +You may obtain a copy of the License at
  195 +
  196 + http://www.apache.org/licenses/LICENSE-2.0
  197 +
  198 +Unless required by applicable law or agreed to in writing, software
  199 +distributed under the License is distributed on an "AS IS" BASIS,
  200 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  201 +See the License for the specific language governing permissions and
  202 +limitations under the License.
0 203 \ No newline at end of file
... ...
vendor/gdata-1.1.1/README 0 → 100644
... ... @@ -0,0 +1,97 @@
  1 += GData
  2 +
  3 +* http://code.google.com/p/gdata
  4 +
  5 +== DESCRIPTION:
  6 +
  7 +Ruby wrapper for working with Google Data APIs
  8 +
  9 +== SYNOPSIS:
  10 +
  11 + yt = GData::Client::YouTube.new
  12 + yt.source = 'my_cool_application'
  13 + yt.clientlogin('username', 'password')
  14 + yt.client_id = 'CLIENT_ID'
  15 + yt.developer_key = 'DEVELOPER_KEY'
  16 + feed = yt.get('http://gdata.youtube.com/feeds/api/users/default/uploads').to_xml
  17 +
  18 + # creating, updating, and deleting a playlist
  19 +
  20 + entry = <<-EOF
  21 + <entry xmlns="http://www.w3.org/2005/Atom"
  22 + xmlns:yt="http://gdata.youtube.com/schemas/2007">
  23 + <title type="text">Ruby Utility Unit Test</title>
  24 + <summary>This is a test playlist.</summary>
  25 + </entry>
  26 + EOF
  27 +
  28 + response = yt.post('http://gdata.youtube.com/feeds/api/users/default/playlists', entry).to_xml
  29 +
  30 + edit_uri = response.elements["link[@rel='edit']"].attributes['href']
  31 +
  32 + response.elements["summary"].text = "Updated description"
  33 +
  34 + response = yt.put(edit_uri, response.to_s).to_xml
  35 +
  36 + yt.delete(edit_uri).to_xml
  37 +
  38 + # uploading a video
  39 +
  40 + test_movie = '/path/to/a/movie.mov'
  41 + mime_type = 'video/quicktime'
  42 + feed = 'http://uploads.gdata.youtube.com/feeds/api/users/default/uploads'
  43 +
  44 + entry = <<EOF
  45 + <entry xmlns="http://www.w3.org/2005/Atom"
  46 + xmlns:media="http://search.yahoo.com/mrss/"
  47 + xmlns:yt="http://gdata.youtube.com/schemas/2007">
  48 + <media:group>
  49 + <media:title type="plain">Test Movie</media:title>
  50 + <media:description type="plain">
  51 + This is a test with the Ruby library
  52 + </media:description>
  53 + <media:category
  54 + scheme="http://gdata.youtube.com/schemas/2007/categories.cat">People
  55 + </media:category>
  56 + <media:keywords>test,lame</media:keywords>
  57 + </media:group>
  58 + </entry>
  59 + EOF
  60 +
  61 + response = @yt.post_file(feed, test_movie, mime_type, entry).to_xml
  62 +
  63 +== REQUIREMENTS:
  64 +
  65 +* A sunny disposition
  66 +
  67 +Tested against Ruby 1.8.6 patch level 114
  68 +
  69 +== INSTALL:
  70 +
  71 + sudo gem install gdata
  72 +
  73 +To generate documentation:
  74 +
  75 + rake doc
  76 +
  77 +To run unit tests:
  78 +
  79 + cp test/test_config.yml.example test/test_config.yml
  80 + # edit test/test_config.yml
  81 + rake test
  82 +
  83 +== LICENSE:
  84 +
  85 +Copyright (C) 2008 Google Inc.
  86 +
  87 +Licensed under the Apache License, Version 2.0 (the "License");
  88 +you may not use this file except in compliance with the License.
  89 +You may obtain a copy of the License at
  90 +
  91 + http://www.apache.org/licenses/LICENSE-2.0
  92 +
  93 +Unless required by applicable law or agreed to in writing, software
  94 +distributed under the License is distributed on an "AS IS" BASIS,
  95 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  96 +See the License for the specific language governing permissions and
  97 +limitations under the License.
0 98 \ No newline at end of file
... ...
vendor/gdata-1.1.1/Rakefile 0 → 100644
... ... @@ -0,0 +1,64 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +require 'rubygems'
  16 +require 'rake/gempackagetask'
  17 +require 'rake/rdoctask'
  18 +require 'rake/testtask'
  19 +
  20 +task :default => [:test]
  21 +
  22 +task :test do
  23 + ruby "test/ts_gdata.rb"
  24 +end
  25 +
  26 +task :prepdoc do
  27 + all_doc_files = FileList.new('doc/**/*')
  28 + all_doc_files.each do |file|
  29 + system "hg add #{file}"
  30 + end
  31 +end
  32 +
  33 +task :doc do
  34 + system "rdoc -U --title 'gdata module documentation' -m README README lib/"
  35 +end
  36 +
  37 +spec = Gem::Specification.new do |s|
  38 + s.platform = Gem::Platform::RUBY
  39 + s.author = 'Jeff Fisher'
  40 + s.email = 'jfisher@youtube.com'
  41 + s.homepage = 'http://code.google.com/p/gdata-ruby-util'
  42 + s.summary = "Google Data APIs Ruby Utility Library"
  43 + s.rubyforge_project = 'gdata'
  44 + s.name = 'gdata'
  45 + s.version = '1.1.1'
  46 + s.requirements << 'none'
  47 + s.require_path = 'lib'
  48 + s.test_files = FileList['test/ts_gdata.rb']
  49 + s.has_rdoc = true
  50 + s.extra_rdoc_files = ['README', 'LICENSE']
  51 + s.rdoc_options << '--main' << 'README'
  52 + s.files = FileList.new('[A-Z]*', 'lib/**/*.rb', 'test/**/*') do |fl|
  53 + fl.exclude(/test_config\.yml$/)
  54 + end
  55 + s.description = <<EOF
  56 +This gem provides a set of wrappers designed to make it easy to work with
  57 +the Google Data APIs.
  58 +EOF
  59 +end
  60 +
  61 +Rake::GemPackageTask.new(spec) do |pkg|
  62 + pkg.need_zip = true
  63 + pkg.need_tar = true
  64 +end
... ...
vendor/gdata-1.1.1/lib/gdata.rb 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +$:.unshift(File.dirname(__FILE__))
  16 +
  17 +require 'gdata/http'
  18 +require 'gdata/client'
  19 +require 'gdata/auth'
  20 +# This is for Unicode "support"
  21 +require 'jcode'
  22 +$KCODE = 'UTF8'
0 23 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/auth.rb 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +require 'gdata/auth/clientlogin'
  16 +require 'gdata/auth/authsub'
  17 +
  18 +module GData
  19 + module Auth
  20 + SOURCE_LIB_STRING = 'GoogleDataRubyUtil-'
  21 + end
  22 +end
0 23 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/auth/authsub.rb 0 → 100644
... ... @@ -0,0 +1,161 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +require 'cgi'
  16 +require 'openssl'
  17 +require 'base64'
  18 +
  19 +module GData
  20 + module Auth
  21 +
  22 + # This class implements AuthSub signatures for Data API requests.
  23 + # It can be used with a GData::Client::GData object.
  24 + class AuthSub
  25 +
  26 + # The URL of AuthSubRequest.
  27 + REQUEST_HANDLER = 'https://www.google.com/accounts/AuthSubRequest'
  28 + # The URL of AuthSubSessionToken.
  29 + SESSION_HANDLER = 'https://www.google.com/accounts/AuthSubSessionToken'
  30 + # The URL of AuthSubRevokeToken.
  31 + REVOKE_HANDLER = 'https://www.google.com/accounts/AuthSubRevokeToken'
  32 + # The URL of AuthSubInfo.
  33 + INFO_HANDLER = 'https://www.google.com/accounts/AuthSubTokenInfo'
  34 + # 2 ** 64, the largest 64 bit unsigned integer
  35 + BIG_INT_MAX = 18446744073709551616
  36 +
  37 + # AuthSub access token.
  38 + attr_accessor :token
  39 + # Private RSA key used to sign secure requests.
  40 + attr_reader :private_key
  41 +
  42 + # Initialize the class with a new token. Optionally pass a private
  43 + # key or custom URLs.
  44 + def initialize(token, options = {})
  45 + if token.nil?
  46 + raise ArgumentError, "Token cannot be nil."
  47 + elsif token.class != String
  48 + raise ArgumentError, "Token must be a String."
  49 + end
  50 +
  51 + @token = token
  52 +
  53 + options.each do |key, value|
  54 + self.send("#{key}=", value)
  55 + end
  56 + end
  57 +
  58 + # Set the private key to use with this AuthSub token.
  59 + # The key can be an OpenSSL::PKey::RSA object, a string containing a
  60 + # private key in PEM format, or a string specifying a path to a PEM
  61 + # file that contains the private key.
  62 + def private_key=(key)
  63 + begin
  64 + if key.nil? or key.class == OpenSSL::PKey::RSA
  65 + @private_key = key
  66 + elsif File.exists?(key)
  67 + key_from_file = File.read(key)
  68 + @private_key = OpenSSL::PKey::RSA.new(key_from_file)
  69 + else
  70 + @private_key = OpenSSL::PKey::RSA.new(key)
  71 + end
  72 + rescue
  73 + raise ArgumentError, "Not a valid private key."
  74 + end
  75 + end
  76 +
  77 + # Sign a GData::Http::Request object with a valid AuthSub Authorization
  78 + # header.
  79 + def sign_request!(request)
  80 + header = "AuthSub token=\"#{@token}\""
  81 +
  82 + if @private_key
  83 + time = Time.now.to_i
  84 + nonce = OpenSSL::BN.rand_range(BIG_INT_MAX)
  85 + method = request.method.to_s.upcase
  86 + data = "#{method} #{request.url} #{time} #{nonce}"
  87 + sig = @private_key.sign(OpenSSL::Digest::SHA1.new, data)
  88 + sig = Base64.encode64(sig).gsub(/\n/, '')
  89 + header = "#{header} sigalg=\"rsa-sha1\" data=\"#{data}\""
  90 + header = "#{header} sig=\"#{sig}\""
  91 + end
  92 +
  93 + request.headers['Authorization'] = header
  94 + end
  95 +
  96 + # Upgrade the current token into a session token.
  97 + def upgrade
  98 + request = GData::HTTP::Request.new(SESSION_HANDLER)
  99 + sign_request!(request)
  100 + service = GData::HTTP::DefaultService.new
  101 + response = service.make_request(request)
  102 + if response.status_code != 200
  103 + raise GData::Client::AuthorizationError.new(response)
  104 + end
  105 +
  106 + @token = response.body[/Token=(.*)/,1]
  107 + return @token
  108 +
  109 + end
  110 +
  111 + # Return some information about the current token. If the current token
  112 + # is a one-time use token, this operation will use it up!
  113 + def info
  114 + request = GData::HTTP::Request.new(INFO_HANDLER)
  115 + sign_request!(request)
  116 + service = GData::HTTP::DefaultService.new
  117 + response = service.make_request(request)
  118 + if response.status_code != 200
  119 + raise GData::Client::AuthorizationError.new(response)
  120 + end
  121 +
  122 + result = {}
  123 + result[:target] = response.body[/Target=(.*)/,1]
  124 + result[:scope] = response.body[/Scope=(.*)/,1]
  125 + result[:secure] = response.body[/Secure=(.*)/,1]
  126 + return result
  127 +
  128 + end
  129 +
  130 + # Revoke the token.
  131 + def revoke
  132 + request = GData::HTTP::Request.new(REVOKE_HANDLER)
  133 + sign_request!(request)
  134 + service = GData::HTTP::DefaultService.new
  135 + response = service.make_request(request)
  136 + if response.status_code != 200
  137 + raise GData::Client::AuthorizationError.new(response)
  138 + end
  139 +
  140 + end
  141 +
  142 + # Return the proper URL for an AuthSub approval page with the requested
  143 + # scope. next_url should be a URL that points back to your code that
  144 + # will receive the token. domain is optionally a Google Apps domain.
  145 + def self.get_url(next_url, scope, secure = false, session = true,
  146 + domain = nil)
  147 + next_url = CGI.escape(next_url)
  148 + scope = CGI.escape(scope)
  149 + secure = secure ? 1 : 0
  150 + session = session ? 1 : 0
  151 + body = "next=#{next_url}&scope=#{scope}&session=#{session}" +
  152 + "&secure=#{secure}"
  153 + if domain
  154 + domain = CGI.escape(domain)
  155 + body = "#{body}&hd=#{domain}"
  156 + end
  157 + return "#{REQUEST_HANDLER}?#{body}"
  158 + end
  159 + end
  160 + end
  161 +end
0 162 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/auth/clientlogin.rb 0 → 100644
... ... @@ -0,0 +1,102 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +require 'cgi'
  16 +
  17 +module GData
  18 + module Auth
  19 +
  20 + # This class implements ClientLogin signatures for Data API requests.
  21 + # It can be used with a GData::Client::GData object.
  22 + class ClientLogin
  23 +
  24 + # The ClientLogin authentication handler
  25 + attr_accessor :auth_url
  26 + # One of 'HOSTED_OR_GOOGLE', 'GOOGLE', or 'HOSTED'.
  27 + # See documentation here:
  28 + # http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html
  29 + attr_accessor :account_type
  30 + # The access token
  31 + attr_accessor :token
  32 + # The service name for the API you are working with
  33 + attr_accessor :service
  34 +
  35 + # Initialize the class with the service name of an API that you wish
  36 + # to request a token for.
  37 + def initialize(service, options = {})
  38 + if service.nil?
  39 + raise ArgumentError, "Service name cannot be nil"
  40 + end
  41 +
  42 + @service = service
  43 +
  44 + options.each do |key, value|
  45 + self.send("#{key}=", value)
  46 + end
  47 +
  48 + @auth_url ||= 'https://www.google.com/accounts/ClientLogin'
  49 + @account_type ||= 'HOSTED_OR_GOOGLE'
  50 + end
  51 +
  52 + # Retrieves a token for the given username and password.
  53 + # source identifies your application.
  54 + # login_token and login_captcha are used only if you are responding
  55 + # to a previously issued CAPTCHA challenge.
  56 + def get_token(username, password, source, login_token = nil,
  57 + login_captcha = nil)
  58 + body = Hash.new
  59 + body['accountType'] = @account_type
  60 + body['Email'] = username
  61 + body['Passwd'] = password
  62 + body['service'] = @service
  63 + body['source'] = source
  64 + if login_token and login_captcha
  65 + body['logintoken'] = login_token
  66 + body['logincaptcha'] = login_captcha
  67 + end
  68 +
  69 + request = GData::HTTP::Request.new(@auth_url, :body => body,
  70 + :method => :post)
  71 + service = GData::HTTP::DefaultService.new
  72 + response = service.make_request(request)
  73 + if response.status_code != 200
  74 + url = response.body[/Url=(.*)/,1]
  75 + error = response.body[/Error=(.*)/,1]
  76 +
  77 + if error == "CaptchaRequired"
  78 + captcha_token = response.body[/CaptchaToken=(.*)/,1]
  79 + captcha_url = response.body[/CaptchaUrl=(.*)/,1]
  80 + raise GData::Client::CaptchaError.new(captcha_token, captcha_url),
  81 + "#{error} : #{url}"
  82 + end
  83 +
  84 + raise GData::Client::AuthorizationError.new(response)
  85 + end
  86 +
  87 + @token = response.body[/Auth=(.*)/,1]
  88 + return @token
  89 + end
  90 +
  91 + # Creates an appropriate Authorization header on a GData::HTTP::Request
  92 + # object.
  93 + def sign_request!(request)
  94 + if @token == nil
  95 + raise GData::Client::Error, "Cannot sign request without credentials"
  96 + end
  97 +
  98 + request.headers['Authorization'] = "GoogleLogin auth=#{@token}"
  99 + end
  100 + end
  101 + end
  102 +end
0 103 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/client.rb 0 → 100644
... ... @@ -0,0 +1,84 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +require 'gdata/client/base'
  16 +require 'gdata/client/apps'
  17 +require 'gdata/client/blogger'
  18 +require 'gdata/client/booksearch'
  19 +require 'gdata/client/calendar'
  20 +require 'gdata/client/contacts'
  21 +require 'gdata/client/doclist'
  22 +require 'gdata/client/finance'
  23 +require 'gdata/client/gbase'
  24 +require 'gdata/client/gmail'
  25 +require 'gdata/client/health'
  26 +require 'gdata/client/notebook'
  27 +require 'gdata/client/photos'
  28 +require 'gdata/client/spreadsheets'
  29 +require 'gdata/client/webmaster_tools'
  30 +require 'gdata/client/youtube'
  31 +
  32 +module GData
  33 + module Client
  34 +
  35 + # Base class for GData::Client errors
  36 + class Error < RuntimeError
  37 + end
  38 +
  39 + # Base class for errors raised due to requests
  40 + class RequestError < Error
  41 +
  42 + # The Net::HTTPResponse that caused this error.
  43 + attr_accessor :response
  44 +
  45 + # Creates a new RequestError from Net::HTTPResponse +response+ with a
  46 + # message containing the error code and response body.
  47 + def initialize(response)
  48 + @response = response
  49 +
  50 + super "request error #{response.status_code}: #{response.body}"
  51 + end
  52 +
  53 + end
  54 +
  55 + class AuthorizationError < RequestError
  56 + end
  57 +
  58 + class BadRequestError < RequestError
  59 + end
  60 +
  61 + # An error caused by ClientLogin issuing a CAPTCHA error.
  62 + class CaptchaError < RuntimeError
  63 + # The token identifying the CAPTCHA
  64 + attr_reader :token
  65 + # The URL to the CAPTCHA image
  66 + attr_reader :url
  67 +
  68 + def initialize(token, url)
  69 + @token = token
  70 + @url = url
  71 + end
  72 + end
  73 +
  74 + class ServerError < RequestError
  75 + end
  76 +
  77 + class UnknownError < RequestError
  78 + end
  79 +
  80 + class VersionConflictError < RequestError
  81 + end
  82 +
  83 + end
  84 +end
0 85 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/client/apps.rb 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +module GData
  16 + module Client
  17 +
  18 + # Client class to wrap working with the Apps Provisioning API.
  19 + class Apps < Base
  20 +
  21 + def initialize(options = {})
  22 + options[:clientlogin_service] ||= 'apps'
  23 + super(options)
  24 + end
  25 + end
  26 + end
  27 +end
0 28 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/client/base.rb 0 → 100644
... ... @@ -0,0 +1,182 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +module GData
  16 + module Client
  17 +
  18 + # A client object used to interact with different Google Data APIs.
  19 + class Base
  20 +
  21 + # A subclass of GData::Auth that handles authentication signing.
  22 + attr_accessor :auth_handler
  23 + # A subclass of GData::HTTP that handles making HTTP requests.
  24 + attr_accessor :http_service
  25 + # Headers to include in every request.
  26 + attr_accessor :headers
  27 + # The API version being used.
  28 + attr_accessor :version
  29 + # The default URL for ClientLogin.
  30 + attr_accessor :clientlogin_url
  31 + # A default service name for ClientLogin (overriden by subclasses).
  32 + attr_accessor :clientlogin_service
  33 + # The broadest AuthSub scope for working with an API.
  34 + # This is overriden by the service-specific subclasses.
  35 + attr_accessor :authsub_scope
  36 + # A short string identifying the current application.
  37 + attr_accessor :source
  38 +
  39 + def initialize(options = {})
  40 + options.each do |key, value|
  41 + self.send("#{key}=", value)
  42 + end
  43 +
  44 + @headers ||= {}
  45 + @http_service ||= GData::HTTP::DefaultService
  46 + @version ||= '2'
  47 + @source ||= 'AnonymousApp'
  48 + end
  49 +
  50 + # Sends an HTTP request with the given file as a stream
  51 + def make_file_request(method, url, file_path, mime_type, entry = nil)
  52 + if not File.readable?(file_path)
  53 + raise ArgumentError, "File #{file_path} is not readable."
  54 + end
  55 + file = File.open(file_path, 'rb')
  56 + @headers['Slug'] = File.basename(file_path)
  57 + if entry
  58 + @headers['MIME-Version'] = '1.0'
  59 + body = GData::HTTP::MimeBody.new(entry, file, mime_type)
  60 + @headers['Content-Type'] = body.content_type
  61 + response = self.make_request(method, url, body)
  62 + else
  63 + @headers['Content-Type'] = mime_type
  64 + response = self.make_request(method, url, file)
  65 + end
  66 + file.close
  67 + return response
  68 + end
  69 +
  70 + # Sends an HTTP request and return the response.
  71 + def make_request(method, url, body = '')
  72 + headers = self.prepare_headers
  73 + request = GData::HTTP::Request.new(url, :headers => headers,
  74 + :method => method, :body => body)
  75 +
  76 + if @auth_handler and @auth_handler.respond_to?(:sign_request!)
  77 + @auth_handler.sign_request!(request)
  78 + end
  79 +
  80 + service = http_service.new
  81 + response = service.make_request(request)
  82 +
  83 + case response.status_code
  84 + when 200, 201, 302
  85 + #Do nothing, it's a success.
  86 + when 401, 403
  87 + raise AuthorizationError.new(response)
  88 + when 400
  89 + raise BadRequestError.new(response)
  90 + when 409
  91 + raise VersionConflictError.new(response)
  92 + when 500
  93 + raise ServerError.new(response)
  94 + else
  95 + raise UnknownError.new(response)
  96 + end
  97 +
  98 + return response
  99 + end
  100 +
  101 + # Performs an HTTP GET against the API.
  102 + def get(url)
  103 + return self.make_request(:get, url)
  104 + end
  105 +
  106 + # Performs an HTTP PUT against the API.
  107 + def put(url, body)
  108 + return self.make_request(:put, url, body)
  109 + end
  110 +
  111 + # Performs an HTTP PUT with the given file
  112 + def put_file(url, file_path, mime_type, entry = nil)
  113 + return self.make_file_request(:put, url, file_path, mime_type, entry)
  114 + end
  115 +
  116 + # Performs an HTTP POST against the API.
  117 + def post(url, body)
  118 + return self.make_request(:post, url, body)
  119 + end
  120 +
  121 + # Performs an HTTP POST with the given file
  122 + def post_file(url, file_path, mime_type, entry = nil)
  123 + return self.make_file_request(:post, url, file_path, mime_type, entry)
  124 + end
  125 +
  126 + # Performs an HTTP DELETE against the API.
  127 + def delete(url)
  128 + return self.make_request(:delete, url)
  129 + end
  130 +
  131 + # Constructs some necessary headers for every request.
  132 + def prepare_headers
  133 + headers = @headers
  134 + headers['GData-Version'] = @version
  135 + headers['User-Agent'] = GData::Auth::SOURCE_LIB_STRING + @source
  136 + # by default we assume we are sending Atom entries
  137 + if not headers.has_key?('Content-Type')
  138 + headers['Content-Type'] = 'application/atom+xml'
  139 + end
  140 + return headers
  141 + end
  142 +
  143 + # Performs ClientLogin for the service. See GData::Auth::ClientLogin
  144 + # for details.
  145 + def clientlogin(username, password, captcha_token = nil,
  146 + captcha_answer = nil, service = nil, account_type = nil)
  147 + if service.nil?
  148 + service = @clientlogin_service
  149 + end
  150 + options = { :account_type => account_type }
  151 + self.auth_handler = GData::Auth::ClientLogin.new(service, options)
  152 + if @clientlogin_url
  153 + @auth_handler.auth_url = @clientlogin_url
  154 + end
  155 + source = GData::Auth::SOURCE_LIB_STRING + @source
  156 + @auth_handler.get_token(username, password, source, captcha_token, captcha_answer)
  157 + end
  158 +
  159 + def authsub_url(next_url, secure = false, session = true, domain = nil,
  160 + scope = nil)
  161 + if scope.nil?
  162 + scope = @authsub_scope
  163 + end
  164 + GData::Auth::AuthSub.get_url(next_url, scope, secure, session, domain)
  165 + end
  166 +
  167 + # Sets an AuthSub token for the service.
  168 + def authsub_token=(token)
  169 + self.auth_handler = GData::Auth::AuthSub.new(token)
  170 + end
  171 +
  172 + # Sets a private key to use with AuthSub requests.
  173 + def authsub_private_key=(key)
  174 + if @auth_handler.class == GData::Auth::AuthSub
  175 + @auth_handler.private_key = key
  176 + else
  177 + raise Error, "An AuthSub token must be set first."
  178 + end
  179 + end
  180 + end
  181 + end
  182 +end
... ...
vendor/gdata-1.1.1/lib/gdata/client/blogger.rb 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +module GData
  16 + module Client
  17 +
  18 + # Client class to wrap working with the Blogger API.
  19 + class Blogger < Base
  20 +
  21 + def initialize(options = {})
  22 + options[:clientlogin_service] ||= 'blogger'
  23 + options[:authsub_scope] ||= 'http://www.blogger.com/feeds/'
  24 + super(options)
  25 + end
  26 + end
  27 + end
  28 +end
0 29 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/client/booksearch.rb 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +module GData
  16 + module Client
  17 +
  18 + # Client class to wrap working with the Book Search Data API.
  19 + class BookSearch < Base
  20 +
  21 + def initialize(options = {})
  22 + options[:clientlogin_service] ||= 'print'
  23 + options[:authsub_scope] ||= 'http://www.google.com/books/feeds/'
  24 + super(options)
  25 + end
  26 + end
  27 + end
  28 +end
0 29 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/client/calendar.rb 0 → 100644
... ... @@ -0,0 +1,58 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +module GData
  16 + module Client
  17 +
  18 + # Client class to wrap working with the Calendar Data API.
  19 + class Calendar < Base
  20 +
  21 + # Holds on to a session cookie
  22 + attr_accessor :session_cookie
  23 +
  24 + def initialize(options = {})
  25 + options[:clientlogin_service] ||= 'cl'
  26 + options[:authsub_scope] ||= 'http://www.google.com/calendar/feeds/'
  27 + super(options)
  28 + end
  29 +
  30 + # Overrides auth_handler= so if the authentication changes,
  31 + # the session cookie is cleared.
  32 + def auth_handler=(handler)
  33 + @session_cookie = nil
  34 + return super(handler)
  35 + end
  36 +
  37 + # Overrides make_request to handle 302 redirects with a session cookie.
  38 + def make_request(method, url, body = '', retries = 4)
  39 + response = super(method, url, body)
  40 + if response.status_code == 302 and retries > 0
  41 + @session_cookie = response.headers['set-cookie']
  42 + return self.make_request(method, url, body,
  43 + retries - 1)
  44 + else
  45 + return response
  46 + end
  47 + end
  48 +
  49 + # Custom prepare_headers to include the session cookie if it exists
  50 + def prepare_headers
  51 + if @session_cookie
  52 + @headers['cookie'] = @session_cookie
  53 + end
  54 + super
  55 + end
  56 + end
  57 + end
  58 +end
0 59 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/client/contacts.rb 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +module GData
  16 + module Client
  17 +
  18 + # Client class to wrap working with the Contacts API.
  19 + class Contacts < Base
  20 +
  21 + def initialize(options = {})
  22 + options[:clientlogin_service] ||= 'cp'
  23 + options[:authsub_scope] ||= 'http://www.google.com/m8/feeds/'
  24 + super(options)
  25 + end
  26 + end
  27 + end
  28 +end
0 29 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/client/doclist.rb 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +module GData
  16 + module Client
  17 +
  18 + # Client class to wrap working with the Documents List Data API.
  19 + class DocList < Base
  20 +
  21 + def initialize(options = {})
  22 + options[:clientlogin_service] ||= 'writely'
  23 + options[:authsub_scope] ||= 'http://docs.google.com/feeds/'
  24 + super(options)
  25 + end
  26 + end
  27 + end
  28 +end
0 29 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/client/finance.rb 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +module GData
  16 + module Client
  17 +
  18 + # Client class to wrap working with the Finance API.
  19 + class Finance < Base
  20 +
  21 + def initialize(options = {})
  22 + options[:clientlogin_service] ||= 'finance'
  23 + options[:authsub_scope] ||= 'http://finance.google.com/finance/feeds/'
  24 + super(options)
  25 + end
  26 + end
  27 + end
  28 +end
0 29 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/client/gbase.rb 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +module GData
  16 + module Client
  17 +
  18 + # Client class to wrap working with the Google Base API.
  19 + class GBase < Base
  20 +
  21 + def initialize(options = {})
  22 + options[:clientlogin_service] ||= 'gbase'
  23 + options[:authsub_scope] ||= 'http://www.google.com/base/feeds/'
  24 + super(options)
  25 + end
  26 + end
  27 + end
  28 +end
0 29 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/client/gmail.rb 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +module GData
  16 + module Client
  17 +
  18 + # Client class to wrap working with the GMail Atom Feed.
  19 + class GMail < Base
  20 +
  21 + def initialize(options = {})
  22 + options[:clientlogin_service] ||= 'mail'
  23 + options[:authsub_scope] ||= 'https://mail.google.com/mail/feed/atom/'
  24 + super(options)
  25 + end
  26 + end
  27 + end
  28 +end
0 29 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/client/health.rb 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +module GData
  16 + module Client
  17 +
  18 + # Client class to wrap working with the Health API.
  19 + class Health < Base
  20 +
  21 + def initialize(options = {})
  22 + options[:clientlogin_service] ||= 'health'
  23 + options[:authsub_scope] ||= 'https://www.google.com/health/feeds/'
  24 + super(options)
  25 + end
  26 + end
  27 + end
  28 +end
0 29 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/client/notebook.rb 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +module GData
  16 + module Client
  17 +
  18 + # Client class to wrap working with the Notebook Data API.
  19 + class Notebook < Base
  20 +
  21 + def initialize(options = {})
  22 + options[:clientlogin_service] ||= 'notebook'
  23 + options[:authsub_scope] ||= 'http://www.google.com/notebook/feeds/'
  24 + super(options)
  25 + end
  26 + end
  27 + end
  28 +end
0 29 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/client/photos.rb 0 → 100644
... ... @@ -0,0 +1,29 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +module GData
  16 + module Client
  17 +
  18 + # Client class to wrap working with the Picasa Web Albums API.
  19 + class Photos < Base
  20 +
  21 + def initialize(options = {})
  22 + options[:clientlogin_service] ||= 'lh2'
  23 + options[:authsub_scope] ||= 'http://picasaweb.google.com/data/'
  24 + options[:version] ||= '1'
  25 + super(options)
  26 + end
  27 + end
  28 + end
  29 +end
0 30 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/client/spreadsheets.rb 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +module GData
  16 + module Client
  17 +
  18 + # Client class to wrap working with the Spreadsheets API.
  19 + class Spreadsheets < Base
  20 +
  21 + def initialize(options = {})
  22 + options[:clientlogin_service] ||= 'wise'
  23 + options[:authsub_scope] ||= 'http://spreadsheets.google.com/feeds/'
  24 + super(options)
  25 + end
  26 + end
  27 + end
  28 +end
0 29 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/client/webmaster_tools.rb 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +module GData
  16 + module Client
  17 +
  18 + # Client class to wrap working with the Webmaster Tools API.
  19 + class WebmasterTools < Base
  20 +
  21 + def initialize(options = {})
  22 + options[:clientlogin_service] ||= 'sitemaps'
  23 + options[:authsub_scope] ||= 'http://www.google.com/webmasters/tools/feeds/'
  24 + super(options)
  25 + end
  26 + end
  27 + end
  28 +end
0 29 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/client/youtube.rb 0 → 100644
... ... @@ -0,0 +1,47 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +module GData
  16 + module Client
  17 +
  18 + # Client class to wrap working with the YouTube API. Sets some
  19 + # YouTube-specific options.
  20 + class YouTube < Base
  21 +
  22 + # The YouTube developer key being used.
  23 + attr_accessor :developer_key
  24 + # The YouTube ClientID being used.
  25 + attr_accessor :client_id
  26 +
  27 + def initialize(options = {})
  28 + options[:clientlogin_service] ||= 'youtube'
  29 + options[:clientlogin_url] ||= 'https://www.google.com/youtube/accounts/ClientLogin'
  30 + options[:authsub_scope] ||= 'http://gdata.youtube.com'
  31 + options[:version] ||= '2'
  32 + super(options)
  33 + end
  34 +
  35 + # Custom prepare_headers to include the developer key and clientID
  36 + def prepare_headers
  37 + if @client_id
  38 + @headers['X-GData-Client'] = @client_id
  39 + end
  40 + if @developer_key
  41 + @headers['X-GData-Key'] = "key=#{@developer_key}"
  42 + end
  43 + super
  44 + end
  45 + end
  46 + end
  47 +end
0 48 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/http.rb 0 → 100644
... ... @@ -0,0 +1,18 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +require 'gdata/http/default_service'
  16 +require 'gdata/http/mime_body'
  17 +require 'gdata/http/request'
  18 +require 'gdata/http/response'
... ...
vendor/gdata-1.1.1/lib/gdata/http/default_service.rb 0 → 100644
... ... @@ -0,0 +1,82 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +require 'net/http'
  16 +require 'net/https'
  17 +require 'uri'
  18 +
  19 +module GData
  20 + module HTTP
  21 +
  22 + # This is the default implementation of the HTTP layer that uses
  23 + # Net::HTTP. You could roll your own if you have different requirements
  24 + # or cannot use Net::HTTP for some reason.
  25 + class DefaultService
  26 +
  27 + # Take a GData::HTTP::Request, execute the request, and return a
  28 + # GData::HTTP::Response object.
  29 + def make_request(request)
  30 + url = URI.parse(request.url)
  31 + http = Net::HTTP.new(url.host, url.port)
  32 + http.use_ssl = (url.scheme == 'https')
  33 + http.verify_mode = OpenSSL::SSL::VERIFY_NONE
  34 +
  35 + case request.method
  36 + when :get
  37 + req = Net::HTTP::Get.new(url.request_uri)
  38 + when :put
  39 + req = Net::HTTP::Put.new(url.request_uri)
  40 + when :post
  41 + req = Net::HTTP::Post.new(url.request_uri)
  42 + when :delete
  43 + req = Net::HTTP::Delete.new(url.request_uri)
  44 + else
  45 + raise ArgumentError, "Unsupported HTTP method specified."
  46 + end
  47 +
  48 + case request.body
  49 + when String
  50 + req.body = request.body
  51 + when Hash
  52 + req.set_form_data(request.body)
  53 + when File
  54 + req.body_stream = request.body
  55 + request.chunked = true
  56 + when GData::HTTP::MimeBody
  57 + req.body_stream = request.body
  58 + request.chunked = true
  59 + else
  60 + req.body = request.body.to_s
  61 + end
  62 +
  63 + request.headers.each do |key, value|
  64 + req[key] = value
  65 + end
  66 +
  67 + request.calculate_length!
  68 +
  69 + res = http.request(req)
  70 +
  71 + response = Response.new
  72 + response.body = res.body
  73 + response.headers = Hash.new
  74 + res.each do |key, value|
  75 + response.headers[key] = value
  76 + end
  77 + response.status_code = res.code.to_i
  78 + return response
  79 + end
  80 + end
  81 + end
  82 +end
0 83 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/http/mime_body.rb 0 → 100644
... ... @@ -0,0 +1,95 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +
  16 +module GData
  17 + module HTTP
  18 +
  19 + # Class acts as a virtual file handle to a MIME multipart message body
  20 + class MimeBody
  21 +
  22 + # The MIME boundary being used.
  23 + attr_reader :boundary
  24 +
  25 + # All fields are required, the entry should be a string and is assumed
  26 + # to be XML.
  27 + def initialize(entry, file, file_mime_type)
  28 + @boundary = "END_OF_PART_#{rand(64000)}"
  29 + entry = wrap_entry(entry, file_mime_type)
  30 + closing_boundary = MimeBodyString.new("\r\n--#{@boundary}--")
  31 + @parts = [entry, file, closing_boundary]
  32 + @current_part = 0
  33 + end
  34 +
  35 + # Implement read so that this class can be treated as a stream.
  36 + def read(bytes_requested)
  37 + if @current_part >= @parts.length
  38 + return false
  39 + end
  40 +
  41 + buffer = @parts[@current_part].read(bytes_requested)
  42 +
  43 + until buffer.length == bytes_requested
  44 + @current_part += 1
  45 + next_buffer = self.read(bytes_requested - buffer.length)
  46 + break if not next_buffer
  47 + buffer += next_buffer
  48 + end
  49 +
  50 + return buffer
  51 + end
  52 +
  53 + # Returns the content type of the message including boundary.
  54 + def content_type
  55 + return "multipart/related; boundary=\"#{@boundary}\""
  56 + end
  57 +
  58 + private
  59 +
  60 + # Sandwiches the entry body into a MIME message
  61 + def wrap_entry(entry, file_mime_type)
  62 + wrapped_entry = "--#{@boundary}\r\n"
  63 + wrapped_entry += "Content-Type: application/atom+xml\r\n\r\n"
  64 + wrapped_entry += entry
  65 + wrapped_entry += "\r\n--#{@boundary}\r\n"
  66 + wrapped_entry += "Content-Type: #{file_mime_type}\r\n\r\n"
  67 + return MimeBodyString.new(wrapped_entry)
  68 + end
  69 +
  70 + end
  71 +
  72 + # Class makes a string into a stream-like object
  73 + class MimeBodyString
  74 +
  75 + def initialize(source_string)
  76 + @string = source_string
  77 + @bytes_read = 0
  78 + end
  79 +
  80 + # Implement read so that this class can be treated as a stream.
  81 + def read(bytes_requested)
  82 + if @bytes_read == @string.length
  83 + return false
  84 + elsif bytes_requested > @string.length - @bytes_read
  85 + bytes_requested = @string.length - @bytes_read
  86 + end
  87 +
  88 + buffer = @string[@bytes_read, bytes_requested]
  89 + @bytes_read += bytes_requested
  90 +
  91 + return buffer
  92 + end
  93 + end
  94 + end
  95 +end
... ...
vendor/gdata-1.1.1/lib/gdata/http/request.rb 0 → 100644
... ... @@ -0,0 +1,74 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +require "rexml/document"
  16 +
  17 +module GData
  18 + module HTTP
  19 +
  20 + # Very simple class to hold everything about an HTTP request.
  21 + class Request
  22 +
  23 + # The URL of the request.
  24 + attr_accessor :url
  25 + # The body of the request.
  26 + attr_accessor :body
  27 + # The HTTP method being used in the request.
  28 + attr_accessor :method
  29 + # The HTTP headers of the request.
  30 + attr_accessor :headers
  31 +
  32 + # Only the URL itself is required, everything else is optional.
  33 + def initialize(url, options = {})
  34 + @url = url
  35 + options.each do |key, value|
  36 + self.send("#{key}=", value)
  37 + end
  38 +
  39 + @method ||= :get
  40 + @headers ||= {}
  41 + end
  42 +
  43 + # Returns whether or not a request is chunked.
  44 + def chunked?
  45 + if @headers['Transfer-Encoding'] == 'chunked'
  46 + return true
  47 + else
  48 + return false
  49 + end
  50 + end
  51 +
  52 + # Sets if the request is using chunked transfer-encoding.
  53 + def chunked=(enabled)
  54 + if enabled
  55 + @headers['Transfer-Encoding'] = 'chunked'
  56 + else
  57 + @headers.delete('Transfer-Encoding')
  58 + end
  59 + end
  60 +
  61 + # Calculates and sets the length of the body.
  62 + def calculate_length!
  63 + if not @headers['Content-Length'] and not chunked? \
  64 + and method != :get and method != :delete
  65 + if @body
  66 + @headers['Content-Length'] = @body.length
  67 + else
  68 + @headers['Content-Length'] = 0
  69 + end
  70 + end
  71 + end
  72 + end
  73 + end
  74 +end
0 75 \ No newline at end of file
... ...
vendor/gdata-1.1.1/lib/gdata/http/response.rb 0 → 100644
... ... @@ -0,0 +1,44 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +require 'gdata/client'
  16 +
  17 +module GData
  18 + module HTTP
  19 +
  20 + # An extremely simple class to hold the values of an HTTP response.
  21 + class Response
  22 +
  23 + # The HTTP response code.
  24 + attr_accessor :status_code
  25 + # The body of the HTTP response.
  26 + attr_accessor :body
  27 + # The headers of the HTTP response.
  28 + attr_accessor :headers
  29 +
  30 + # Converts the response body into a REXML::Document
  31 + def to_xml
  32 + if @body
  33 + begin
  34 + return REXML::Document.new(@body).root
  35 + rescue
  36 + raise GData::Client::Error, "Response body not XML."
  37 + end
  38 + else
  39 + return nil
  40 + end
  41 + end
  42 + end
  43 + end
  44 +end
0 45 \ No newline at end of file
... ...
vendor/gdata-1.1.1/test/tc_gdata_auth_authsub.rb 0 → 100644
... ... @@ -0,0 +1,53 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +$:.unshift(File.dirname(__FILE__))
  16 +require 'test_helper'
  17 +
  18 +class TC_GData_Auth_AuthSub < Test::Unit::TestCase
  19 +
  20 + include TestHelper
  21 +
  22 + def test_make_authenticated_request
  23 + token = self.get_authsub_token()
  24 + key = self.get_authsub_private_key()
  25 + service = GData::Client::YouTube.new
  26 + if token
  27 +
  28 + service.authsub_token = token
  29 + if key
  30 + service.authsub_private_key = key
  31 + end
  32 +
  33 + feed = service.get('http://gdata.youtube.com/feeds/api/users/default/uploads?max-results=1')
  34 + self.assert_not_nil(feed, 'Feed should not be nil')
  35 + end
  36 + end
  37 +
  38 + def test_generate_url
  39 + scope = 'http://gdata.youtube.com'
  40 + next_url = 'http://example.com'
  41 + secure = true
  42 + session = false
  43 + url = GData::Auth::AuthSub.get_url(next_url, scope, secure, session)
  44 + self.assert_equal('https://www.google.com/accounts/AuthSubRequest?next=http%3A%2F%2Fexample.com&scope=http%3A%2F%2Fgdata.youtube.com&session=0&secure=1', url)
  45 +
  46 + # test generating with a pre-populated scope
  47 + yt = GData::Client::YouTube.new
  48 + client_url = yt.authsub_url(next_url, secure, session)
  49 + self.assert_equal(url, client_url)
  50 +
  51 + end
  52 +
  53 +end
0 54 \ No newline at end of file
... ...
vendor/gdata-1.1.1/test/tc_gdata_auth_clientlogin.rb 0 → 100644
... ... @@ -0,0 +1,59 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +$:.unshift(File.dirname(__FILE__))
  16 +require 'test_helper'
  17 +
  18 +class TC_GData_Auth_ClientLogin < Test::Unit::TestCase
  19 +
  20 + include TestHelper
  21 +
  22 + def test_has_config
  23 + self.assert_not_nil(self.get_username(),
  24 + 'Must have a username in test_config.yml')
  25 + self.assert_not_nil(self.get_password(),
  26 + 'Must have a password in test_config.yml')
  27 + end
  28 +
  29 + def test_get_token
  30 + client_login = GData::Auth::ClientLogin.new('cl')
  31 + source = 'GDataUnitTest'
  32 + assert_nothing_raised do
  33 + token = client_login.get_token(self.get_username(), self.get_password(), source)
  34 + end
  35 + end
  36 +
  37 + def test_all_clients
  38 + source = 'GDataUnitTest'
  39 + GData::Client.constants.each do |const_name|
  40 + const = GData::Client.const_get(const_name)
  41 + if const.superclass == GData::Client::Base
  42 + instance = const.new
  43 + assert_nothing_raised do
  44 + instance.clientlogin(self.get_username(), self.get_password(), source)
  45 + end
  46 + end
  47 + end
  48 + end
  49 +
  50 + def test_specify_account_type
  51 + gp = GData::Client::Photos.new
  52 + gp.source = 'GDataUnitTest'
  53 + assert_nothing_raised do
  54 + token = gp.clientlogin(self.get_username(), self.get_password(), nil, nil, nil, 'GOOGLE')
  55 + end
  56 + end
  57 +
  58 +
  59 +end
0 60 \ No newline at end of file
... ...
vendor/gdata-1.1.1/test/tc_gdata_client_base.rb 0 → 100644
... ... @@ -0,0 +1,37 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +$:.unshift(File.dirname(__FILE__))
  16 +require 'test_helper'
  17 +
  18 +class TC_GData_Client_Base < Test::Unit::TestCase
  19 +
  20 + include TestHelper
  21 +
  22 + def test_simple_gdata_get
  23 + service = GData::Client::Base.new
  24 + feed = service.get('http://gdata.youtube.com/feeds/base/videos?max-results=1').to_xml
  25 + assert_not_nil(feed, 'feed can not be nil')
  26 + end
  27 +
  28 + def test_clientlogin_with_service
  29 + service = GData::Client::Base.new
  30 + service.clientlogin(self.get_username(), self.get_password(), nil, nil,
  31 + 'youtube')
  32 + feed = service.get('http://gdata.youtube.com/feeds/api/users/default/uploads?max-results=1').to_xml
  33 + assert_not_nil(feed, 'feed can not be nil')
  34 + end
  35 +
  36 +end
  37 +
0 38 \ No newline at end of file
... ...
vendor/gdata-1.1.1/test/tc_gdata_client_calendar.rb 0 → 100644
... ... @@ -0,0 +1,40 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +$:.unshift(File.dirname(__FILE__))
  16 +require 'test_helper'
  17 +
  18 +class TC_GData_Client_Calendar < Test::Unit::TestCase
  19 +
  20 + include TestHelper
  21 +
  22 + def setup
  23 + @cl = GData::Client::Calendar.new
  24 + @cl.clientlogin(self.get_username, self.get_password)
  25 + end
  26 +
  27 + def test_get_all_calendars
  28 + response = @cl.get('http://www.google.com/calendar/feeds/default/allcalendars/full')
  29 + self.assert_equal(200, response.status_code, 'Must not be a redirect.')
  30 + self.assert_not_nil(@cl.session_cookie, 'Must have a session cookie.')
  31 + feed = response.to_xml
  32 + self.assert_not_nil(feed, 'feed can not be nil')
  33 +
  34 + #login again to make sure the session cookie gets cleared
  35 + @cl.clientlogin(self.get_username, self.get_password)
  36 + self.assert_nil(@cl.session_cookie, 'Should clear session cookie.')
  37 + end
  38 +
  39 +
  40 +end
0 41 \ No newline at end of file
... ...
vendor/gdata-1.1.1/test/tc_gdata_client_photos.rb 0 → 100644
... ... @@ -0,0 +1,65 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +$:.unshift(File.dirname(__FILE__))
  16 +require 'test_helper'
  17 +
  18 +class TC_GData_Client_Photos < Test::Unit::TestCase
  19 +
  20 + include TestHelper
  21 +
  22 + def setup
  23 + @gp = GData::Client::Photos.new
  24 + @gp.source = 'Ruby Client Unit Tests'
  25 + @gp.clientlogin(self.get_username(), self.get_password())
  26 + end
  27 +
  28 + def test_authenticated_dropbox_feed
  29 + feed = @gp.get('http://picasaweb.google.com/data/feed/api/user/default/albumid/default?max-results=1').to_xml
  30 + self.assert_not_nil(feed, 'feed can not be nil')
  31 + end
  32 +
  33 + def test_photo_upload
  34 + test_image = File.join(File.dirname(__FILE__), 'testimage.jpg')
  35 + mime_type = 'image/jpeg'
  36 +
  37 + response = @gp.post_file('http://picasaweb.google.com/data/feed/api/user/default/albumid/default',
  38 + test_image, mime_type).to_xml
  39 +
  40 + edit_uri = response.elements["link[@rel='edit']"].attributes['href']
  41 +
  42 + @gp.delete(edit_uri)
  43 + end
  44 +
  45 + def test_photo_upload_with_metadata
  46 + test_image = File.join(File.dirname(__FILE__), 'testimage.jpg')
  47 + mime_type = 'image/jpeg'
  48 +
  49 + entry = <<-EOF
  50 + <entry xmlns='http://www.w3.org/2005/Atom'>
  51 + <title>ruby-client-testing.jpg</title>
  52 + <summary>Test case for Ruby Client Library.</summary>
  53 + <category scheme="http://schemas.google.com/g/2005#kind"
  54 + term="http://schemas.google.com/photos/2007#photo"/>
  55 + </entry>
  56 + EOF
  57 +
  58 + response = @gp.post_file('http://picasaweb.google.com/data/feed/api/user/default/albumid/default',
  59 + test_image, mime_type, entry).to_xml
  60 +
  61 + edit_uri = response.elements["link[@rel='edit']"].attributes['href']
  62 +
  63 + @gp.delete(edit_uri)
  64 + end
  65 +end
0 66 \ No newline at end of file
... ...
vendor/gdata-1.1.1/test/tc_gdata_client_youtube.rb 0 → 100644
... ... @@ -0,0 +1,77 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +$:.unshift(File.dirname(__FILE__))
  16 +require 'test_helper'
  17 +
  18 +class TC_GData_Client_YouTube < Test::Unit::TestCase
  19 +
  20 + include TestHelper
  21 +
  22 + def setup
  23 + @yt = GData::Client::YouTube.new
  24 + self.assert(@yt.headers.empty?, 'headers should be empty.')
  25 + @yt.clientlogin(self.get_username(), self.get_password())
  26 + @yt.client_id = 'ytapi-Google-GDataUnitTests-lcqr3u89-1'
  27 + @yt.developer_key = 'AI39si4vwXwDLR5MrtsdR1ULUD8__EnEccla-0bnqV40KpeFDIyCwEv0VJqZKHUsO3MvVM_bXHp3cAr55HmMYMhqfxzLMUgDXA'
  28 + end
  29 +
  30 + def test_authenticated_uploads_feed
  31 +
  32 +
  33 + feed = @yt.get('http://gdata.youtube.com/feeds/api/users/default/uploads?max-results=1').to_xml
  34 + self.assert_not_nil(feed, 'feed can not be nil')
  35 + end
  36 +
  37 + def test_favorites
  38 +
  39 + video_id = 'zlfKdbWwruY'
  40 +
  41 + entry = <<-EOF
  42 + <entry xmlns="http://www.w3.org/2005/Atom">
  43 + <id>#{video_id}</id>
  44 + </entry>
  45 + EOF
  46 +
  47 + response = @yt.post('http://gdata.youtube.com/feeds/api/users/default/favorites', entry).to_xml
  48 +
  49 + edit_uri = response.elements["link[@rel='edit']"].attributes['href']
  50 +
  51 + @yt.delete(edit_uri)
  52 +
  53 + end
  54 +
  55 + def test_playlist
  56 + entry = <<-EOF
  57 + <entry xmlns="http://www.w3.org/2005/Atom"
  58 + xmlns:yt="http://gdata.youtube.com/schemas/2007">
  59 + <title type="text">Ruby Utility Unit Test</title>
  60 + <summary>This is a test playlist.</summary>
  61 + </entry>
  62 + EOF
  63 +
  64 + response = @yt.post('http://gdata.youtube.com/feeds/api/users/default/playlists', entry).to_xml
  65 +
  66 + edit_uri = response.elements["link[@rel='edit']"].attributes['href']
  67 +
  68 + response.elements["summary"].text = "Updated description"
  69 +
  70 + response = @yt.put(edit_uri, response.to_s).to_xml
  71 +
  72 + self.assert_equal("Updated description", response.elements["summary"].text)
  73 +
  74 + @yt.delete(edit_uri)
  75 + end
  76 +
  77 +end
0 78 \ No newline at end of file
... ...
vendor/gdata-1.1.1/test/tc_gdata_http_mime_body.rb 0 → 100644
... ... @@ -0,0 +1,46 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +$:.unshift(File.dirname(__FILE__))
  16 +require 'test_helper'
  17 +
  18 +class TC_GData_HTTP_MimeBody < Test::Unit::TestCase
  19 +
  20 + include TestHelper
  21 +
  22 + def test_mime_body_string
  23 + stream = GData::HTTP::MimeBodyString.new('testing 1 2 3')
  24 +
  25 + self.assert_equal('t', stream.read(1))
  26 + self.assert_equal('esting', stream.read(6))
  27 + self.assert_equal(' 1 2 ', stream.read(5))
  28 + self.assert_equal('3', stream.read(50))
  29 + self.assert_equal(false, stream.read(10))
  30 + end
  31 +
  32 + def test_mime_body_string_large_read
  33 + stream = GData::HTTP::MimeBodyString.new('test string')
  34 +
  35 + self.assert_equal('test string', stream.read(1024))
  36 + self.assert_equal(false, stream.read(1024))
  37 + end
  38 +
  39 + def test_mime_body_string_unicode
  40 + stream = GData::HTTP::MimeBodyString.new('λ')
  41 + self.assert(stream.read(1), 'Greek character should be two bytes')
  42 + self.assert(stream.read(1), 'Greek character should be two full bytes')
  43 + self.assert_equal(false, stream.read(1))
  44 + end
  45 +
  46 +end
0 47 \ No newline at end of file
... ...
vendor/gdata-1.1.1/test/tc_gdata_http_request.rb 0 → 100644
... ... @@ -0,0 +1,36 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +$:.unshift(File.dirname(__FILE__))
  16 +require 'test_helper'
  17 +
  18 +class TC_GData_HTTP_Request < Test::Unit::TestCase
  19 +
  20 + include TestHelper
  21 +
  22 + def test_world_is_sane
  23 + assert(true, 'World is not sane.')
  24 + end
  25 +
  26 + def test_google_is_live
  27 + request = GData::HTTP::Request.new('http://www.google.com')
  28 +
  29 + service = GData::HTTP::DefaultService.new
  30 +
  31 + response = service.make_request(request)
  32 +
  33 + assert_equal(200, response.status_code)
  34 + end
  35 +
  36 +end
0 37 \ No newline at end of file
... ...
vendor/gdata-1.1.1/test/test_helper.rb 0 → 100644
... ... @@ -0,0 +1,47 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +require 'yaml'
  16 +require 'test/unit'
  17 +require 'test/unit/ui/console/testrunner'
  18 +
  19 +$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
  20 +require 'gdata'
  21 +
  22 +module TestHelper
  23 +
  24 + def get_config()
  25 + if not defined?(@config_file)
  26 + @config_file = YAML::load_file(File.join(File.dirname(__FILE__), 'test_config.yml'))
  27 + end
  28 + return @config_file
  29 + end
  30 +
  31 + def get_username()
  32 + return self.get_config()['username']
  33 + end
  34 +
  35 + def get_password()
  36 + return self.get_config()['password']
  37 + end
  38 +
  39 + def get_authsub_token()
  40 + return self.get_config()['authsub_token']
  41 + end
  42 +
  43 + def get_authsub_private_key()
  44 + return self.get_config()['authsub_private_key']
  45 + end
  46 +
  47 +end
0 48 \ No newline at end of file
... ...
vendor/gdata-1.1.1/test/testimage.jpg 0 → 100644

689 Bytes

vendor/gdata-1.1.1/test/ts_gdata.rb 0 → 100644
... ... @@ -0,0 +1,42 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +$:.unshift(File.dirname(__FILE__))
  16 +require 'test_helper'
  17 +require 'ts_gdata_http'
  18 +require 'ts_gdata_client'
  19 +require 'ts_gdata_auth'
  20 +
  21 +class TS_GData
  22 + def self.suite
  23 + suite = Test::Unit::TestSuite.new("GData Test Suite")
  24 + suite << UnicodeStringTest.suite
  25 + suite << TS_GData_HTTP.suite
  26 + suite << TS_GData_Client.suite
  27 + suite << TS_GData_Auth.suite
  28 + return suite
  29 + end
  30 +end
  31 +
  32 +class UnicodeStringTest < Test::Unit::TestCase
  33 + def test_jlength
  34 + s = "Καλημέρα κόσμε!"
  35 + assert_equal(15, s.jlength) # Note the 'j'
  36 + assert_not_equal(15, s.length) # Normal, non unicode length
  37 + assert_equal(28, s.length) # Greek letters happen to take two-bytes
  38 + end
  39 +end
  40 +
  41 +
  42 +Test::Unit::UI::Console::TestRunner.run(TS_GData)
0 43 \ No newline at end of file
... ...
vendor/gdata-1.1.1/test/ts_gdata_auth.rb 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +require 'tc_gdata_auth_clientlogin'
  16 +require 'tc_gdata_auth_authsub'
  17 +
  18 +class TS_GData_Auth
  19 + def self.suite
  20 + suite = Test::Unit::TestSuite.new
  21 + suite << TC_GData_Auth_ClientLogin.suite
  22 + suite << TC_GData_Auth_AuthSub.suite
  23 + return suite
  24 + end
  25 +end
0 26 \ No newline at end of file
... ...
vendor/gdata-1.1.1/test/ts_gdata_client.rb 0 → 100644
... ... @@ -0,0 +1,29 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +require 'tc_gdata_client_base'
  16 +require 'tc_gdata_client_calendar'
  17 +require 'tc_gdata_client_photos'
  18 +require 'tc_gdata_client_youtube'
  19 +
  20 +class TS_GData_Client
  21 + def self.suite
  22 + suite = Test::Unit::TestSuite.new
  23 + suite << TC_GData_Client_Base.suite
  24 + suite << TC_GData_Client_Calendar.suite
  25 + suite << TC_GData_Client_Photos.suite
  26 + suite << TC_GData_Client_YouTube.suite
  27 + return suite
  28 + end
  29 +end
0 30 \ No newline at end of file
... ...
vendor/gdata-1.1.1/test/ts_gdata_http.rb 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +# Copyright (C) 2008 Google Inc.
  2 +#
  3 +# Licensed under the Apache License, Version 2.0 (the "License");
  4 +# you may not use this file except in compliance with the License.
  5 +# You may obtain a copy of the License at
  6 +#
  7 +# http://www.apache.org/licenses/LICENSE-2.0
  8 +#
  9 +# Unless required by applicable law or agreed to in writing, software
  10 +# distributed under the License is distributed on an "AS IS" BASIS,
  11 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 +# See the License for the specific language governing permissions and
  13 +# limitations under the License.
  14 +
  15 +require 'tc_gdata_http_request'
  16 +require 'tc_gdata_http_mime_body'
  17 +
  18 +class TS_GData_HTTP
  19 + def self.suite
  20 + suite = Test::Unit::TestSuite.new
  21 + suite << TC_GData_HTTP_Request.suite
  22 + suite << TC_GData_HTTP_MimeBody.suite
  23 + return suite
  24 + end
  25 +end
0 26 \ No newline at end of file
... ...