harleytt-gvoice-ruby 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
data/.bundle/config ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_DISABLE_SHARED_GEMS: "1"
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ .DS_Store
2
+ *.log
3
+ gvoice-ruby-config.yml
4
+ *.gem
5
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,19 @@
1
+ # A sample Gemfile
2
+ source "http://rubygems.org"
3
+ #
4
+ gem 'curb'
5
+ gem 'nokogiri'
6
+ gem 'json'
7
+
8
+ # Make sure the correct version of xmpp4r-simple is loaded when
9
+ # require is called in bin/gv-notifier
10
+ if RUBY_VERSION < '1.9'
11
+ gem 'xmpp4r-simple', "= 0.8.8"
12
+ else
13
+ gem 'scashin133-xmpp4r-simple', '= 0.8.9'
14
+ end
15
+
16
+ group :test do
17
+ gem 'shoulda'
18
+ gem 'mocha'
19
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,24 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ curb (0.7.8)
5
+ json (1.4.6)
6
+ mocha (0.9.8)
7
+ rake
8
+ nokogiri (1.4.3.1)
9
+ rake (0.8.7)
10
+ scashin133-xmpp4r-simple (0.8.9)
11
+ xmpp4r (>= 0.3.2)
12
+ shoulda (2.11.3)
13
+ xmpp4r (0.5)
14
+
15
+ PLATFORMS
16
+ ruby
17
+
18
+ DEPENDENCIES
19
+ curb
20
+ json
21
+ mocha
22
+ nokogiri
23
+ scashin133-xmpp4r-simple (= 0.8.9)
24
+ shoulda
data/README.rdoc ADDED
@@ -0,0 +1,90 @@
1
+ = gvoice-ruby
2
+
3
+ == Introduction
4
+
5
+ gvoice-ruby is a library for interacting with Google's Voice service (previously GrandCentral) using ruby. As Google does not yet publish an official API for Google Voice gvoice-ruby uses the ruby libcurl library (Curb) to interact with the web service itself by using the HTTP verbs POST and GET to send and retrieve information to the Google Voice service.
6
+
7
+ gvoice-ruby is currently a very preliminary project with limited functionality basically confined to returning arrays of voicemail or sms objects and sending sms messages, or connecting calls. It cannot cancel calls already in progress. It currently works under ruby 1.8.7-p302 and 1.9.2-p0 on my computer running Mac OS X 10.6 (Snow Leopard). It is not guaranteed to work anywhere else and has very few tests.
8
+
9
+ However, you should be able to run bundle install after running git clone as outlined below and it should function.
10
+
11
+ == Prerequisites
12
+
13
+ 1.) Ruby 1.8.7 or 1.9.2
14
+
15
+ 2.) Bundler 1.0 (gem install bundler)
16
+
17
+ == Installing
18
+
19
+ Install the gem:
20
+
21
+ $ gem install gvoice-ruby
22
+
23
+ or
24
+
25
+ Clone the git repository:
26
+
27
+ $ git clone git://github.com/kgautreaux/gvoice-ruby.git
28
+
29
+ then:
30
+
31
+ $ cd gvoice-ruby
32
+
33
+ and:
34
+
35
+ $ bundle install
36
+
37
+ This should install all the required gems provided you have the right permissions.
38
+
39
+ To run the test suite:
40
+
41
+ $ bundle exec rake
42
+
43
+ == Examples
44
+
45
+ Please see the bin/ directory for examples of using the library to accomplish some tasks. You must run bundle exec 'command' in order for the program to work, i.e.
46
+
47
+ $ cd gvoice-ruby
48
+ $ bundle exec bin/gv-notifier
49
+
50
+ == Known Issues
51
+
52
+ 1.) You have to run 'bundle exec bin/"command"' and it must be run in the context of the gvoice-ruby directory.
53
+
54
+ 2.) It does some wicked monkeypatching to run on both 1.9.2 and 1.8.7 mostly due to the new Date class in Ruby 1.9.2.
55
+
56
+ 3.) It is technically a library but it doesn't document any sort of API thus far.
57
+
58
+ == BUGS
59
+
60
+ 1.) It has few tests.
61
+
62
+ 2.) If the Google Voice service changes in any way it will break.
63
+
64
+ 3.) If the libraries used change it will break.
65
+
66
+ 4.) It is somewhat tightly coupled to the private post and fetch_page methods (sms and voicemail arrays depend upon these methods).
67
+
68
+ 5.) It is not RESTful in any way.
69
+
70
+ 6.) It cannot yet cancel calls very well, but it can initiate them.
71
+
72
+ 7.) It is my first attempt at writing a library and is not idiomatic ruby.
73
+
74
+ 8.) It requires rubygems but doesn't set RUBYOPT environment variable.
75
+
76
+ 9.) It requires the file compatibility.rb which monkeypatches the Array and Symbol classes on Ruby < 1.9 to enable sorting.
77
+
78
+ 10.) You cannot change any of the Google Voice settings using this library.
79
+
80
+ 11.) The library loads a specific YAML file that must be in place for anything to work as the script has no logical defaults.
81
+
82
+ 12.) Minimal to no error handling present. Fail silent...Fail deep.
83
+
84
+ 13.) The library doesn't post the id of sms messages it sends so they don't get associated with any conversation in Google Voice.
85
+
86
+ 14.) On Ruby 1.9 and above the library monkeypatches it's own call method to reformat dates.
87
+
88
+ == Thanks
89
+
90
+ Thanks to Chad Smith for posting the URL for accessing the Google Voice service as listed on http://posttopic.com/topic/google-voice-add-on-development#post-27
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+
5
+ desc "Run all tests for this project."
6
+ Rake::TestTask.new(:test) do |test|
7
+ test.libs << 'lib' << 'test'
8
+ test.pattern = 'test/**/*_test.rb'
9
+ test.verbose = true
10
+ end
11
+
12
+ task :default => :test
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.3
data/bin/gv-notifier ADDED
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env ruby -W1
2
+ # -*- encoding: utf-8 -*-
3
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ begin
5
+ require 'gvoice-ruby'
6
+ require 'xmpp4r-simple'
7
+ rescue LoadError
8
+ warn "\n\nYou must run 'bundle exec #{$0}' to allow loading of correct gems!\n\n"
9
+ raise
10
+ end
11
+
12
+ config = GvoiceRuby::Configurator.load_config
13
+
14
+ # Main
15
+ jabber_bot = Jabber::Simple.new(config[:bot_name], config[:bot_password])
16
+
17
+ voicebox = GvoiceRuby::Client.new
18
+
19
+ voicebox.check
20
+
21
+ voicebox.missed.each do |call|
22
+ if DateTime.parse(call.display_start_date_time).yday >= (Time.now.yday - 3)
23
+ puts "You missed a call from #{call.from} on #{call.display_start_date_time}."
24
+ end
25
+ end
26
+ puts "\n"
27
+
28
+ voicebox.received.each do |call|
29
+ if DateTime.parse(call.display_start_date_time).yday >= (Time.now.yday - 1)
30
+ puts "You received a call from #{call.from} on #{call.display_start_date_time}."
31
+ end
32
+ end
33
+ puts "\n"
34
+
35
+ voicebox.placed.each do |call|
36
+ if DateTime.parse(call.display_start_date_time).yday >= (Time.now.yday - 3)
37
+ puts "You placed a call to #{call.from} on #{call.display_start_date_time}."
38
+ end
39
+ end
40
+ puts "\n"
41
+
42
+ if voicebox.any_unread?
43
+ sms_messages = []
44
+ voicemail_messages = []
45
+
46
+ voicebox.smss.each do |t|
47
+ if t.labels.include?('unread')
48
+ sms_messages << "#{t.from} says: '#{t.text}' at #{t.display_start_date_time}\n"
49
+ voicebox.mark_as_read({:id => t.id})
50
+ voicebox.add_note({:id => t.id, :note => "You were notified via gv-notifier at #{Time.now}."})
51
+ # voicebox.star({:id => t.id})
52
+ else
53
+ next
54
+ end
55
+ end
56
+
57
+ voicebox.voicemails.each do |v|
58
+ if v.labels.include?('unread')
59
+ voicemail_messages << "Voicemail from #{v.from} at #{v.display_start_date_time}:\n#{v.transcript}\n"
60
+ voicebox.mark_as_read({:id => v.id})
61
+ else
62
+ next
63
+ end
64
+ end
65
+
66
+ begin
67
+ [sms_messages, voicemail_messages].each do |thing|
68
+ thing.each { |m| jabber_bot.deliver(voicebox.user.email, m, :normal);print m }
69
+ end
70
+ rescue
71
+ raise
72
+ end
73
+ config[:last_message_start_time] = voicebox.all_messages.last.start_time
74
+ else
75
+ print "No unread messages in your Google Voice inbox.\n"
76
+ end
77
+
78
+ GvoiceRuby::Configurator.write_config(config)
data/bin/gv-place-call ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby -W1
2
+ # -*- encoding: utf-8 -*-
3
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ begin
5
+ require 'gvoice-ruby'
6
+ rescue LoadError
7
+ warn "\n\nYou must run 'bundle exec #{$0}' to allow loading of correct gems!\n\n"
8
+ raise
9
+ end
10
+
11
+ voicebox = GvoiceRuby::Client.new
12
+
13
+ # Phone types:
14
+ # 1) Home
15
+ # 2) Mobile
16
+ # 3) Work
17
+ # 7) Gizmo
18
+ this_phone = { :outgoing_number => "3088720071", :forwarding_number => "3088721257", :phone_type => 2 }
19
+
20
+ puts "Call connected!" if voicebox.call(this_phone)
21
+
22
+ puts "Call cancelled!" if voicebox.cancel_call
data/bin/gv-send-sms ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby -W1
2
+ # -*- encoding: utf-8 -*-
3
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ begin
5
+ require 'gvoice-ruby'
6
+ rescue LoadError
7
+ warn "\n\nYou must run 'bundle exec #{$0}' to allow loading of correct gems!\n\n"
8
+ raise
9
+ end
10
+
11
+ voicebox = GvoiceRuby::Client.new
12
+
13
+ txt = {:phone_number => "3088721257", :text => "Testing sms from gvoice-ruby!" }
14
+
15
+ puts "Message sent!" if voicebox.send_sms(txt)
16
+
@@ -0,0 +1,11 @@
1
+ ---
2
+ :google_auth_url: https://www.google.com/accounts/ServiceLoginAuth
3
+ :google_account_password: your_google_account_password
4
+ :continue_url: https://www.google.com/voice
5
+ :last_message_start_time: 0
6
+ :bot_name: your_gtalk_or_jabber_bot_name
7
+ :google_service: grandcentral
8
+ :bot_password: your_gtalk_bot_password
9
+ :google_voice_feed_url: https://www.google.com/voice/inbox/recent
10
+ :google_account_email: your_google_email_address@gmail.com
11
+ :logfile: path/to/log/file
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
3
+ require 'gvoice-ruby/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "harleytt-gvoice-ruby"
7
+ s.version = GvoiceRuby::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Keith Gautreaux", "Roy Kolak", "Jeremy Stephens"]
10
+ s.email = ["keith.gautreaux@gmail.com"]
11
+ s.homepage = "http://github.com/kgautreaux/gvoice-ruby"
12
+ s.summary = "gvoice-ruby is a library for interacting with Google’s Voice service (previously GrandCentral) using ruby."
13
+ s.description = <<-EOS
14
+ gvoice-ruby is currently a very preliminary project with limited functionality basically confined to returning arrays of voicemail or sms objects and sending sms messages, or connecting calls. It cannot cancel calls already in progress. It currently works under ruby 1.8.7-p302 and 1.9.2-p0 on my computer running Mac OS X 10.6 (Snow Leopard). It is not guaranteed to work anywhere else and has very few tests.
15
+ EOS
16
+
17
+ s.required_rubygems_version = "~> 1.3.6"
18
+ # s.rubyforge_project = "gvoice-ruby"
19
+
20
+ s.add_dependency "curb", "~> 0.7.8"
21
+ s.add_dependency "nokogiri", "~> 1.4.3.1"
22
+ s.add_dependency "json", "~> 1.4.6"
23
+
24
+ s.add_development_dependency "bundler", "~> 1.0.0.rc.6"
25
+ s.add_development_dependency "mocha", "~> 0.9.7"
26
+ s.add_development_dependency "shoulda", "~> 2.11.3"
27
+ s.add_development_dependency "rake", "~> 0.8.7"
28
+
29
+ s.files = `git ls-files`.split("\n")
30
+ # s.executables = ["bin/gv-notifier", "bin/gv-place-call", "bin/gv-send-sms"]#`git ls-files`.split("\n").select { |f| f =~ /^bin/ }
31
+ s.require_paths = ['lib']
32
+
33
+ s.post_install_message = "\n\nPlease run 'cd gvoice-ruby;bundle install;bundle exec rake' to run the tests.\n\n"
34
+ end
@@ -0,0 +1,9 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module GvoiceRuby
3
+ class Call < Struct.new(:id, :start_time, :display_number, :display_start_date_time, :display_start_time, :relative_start_time, :is_read, :starred, :labels, :from, :to)
4
+ #attr_accessor :id, :start_time, :display_number, :display_start_date_time, :display_start_time, :relative_start_time, :is_read, :labels, :from, :to, :text
5
+ #
6
+ #def initialize
7
+ #end
8
+ end
9
+ end
@@ -0,0 +1,277 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.unshift(File.dirname(__FILE__))
3
+ %w[curb nokogiri json sms voicemail call user logger compatibility inbox_parser open-uri errors].each { |lib| require lib }
4
+
5
+ module GvoiceRuby
6
+ class Client
7
+ include Curl
8
+
9
+ attr_accessor :unread_counts, :smss, :voicemails, :user, :all_messages, :calls
10
+ attr_reader :logger
11
+
12
+ def initialize(config = GvoiceRuby::Configurator.load_config)
13
+ if config[:google_account_email].nil? || config[:google_account_password].nil?
14
+ raise ArgumentError, "Invalid Google Account username or password provided."
15
+ else
16
+ @logger = Logger.new(config.has_key?(:logfile) ? config[:logfile] :
17
+ File.join(File.dirname(__FILE__), '..', '..', 'log', 'gvoice-ruby.log'))
18
+ @user = User.new(config[:google_account_email], config[:google_account_password])
19
+ @any_unread = []
20
+ @unread_counts = {}
21
+ @all_messages = []
22
+ initialize_curb
23
+ end
24
+
25
+ login(config)
26
+ set_rnr_se_token
27
+ end
28
+
29
+ def any_unread?
30
+ @any_unread
31
+ end
32
+
33
+ def logged_in?
34
+ !@curb_instance.nil?
35
+ end
36
+
37
+ def check(parser = GvoiceRuby::InboxParser.new)
38
+ inbox = parser.parse_page(fetch_page)
39
+
40
+ get_unread_counts(inbox)
41
+ @smss = parser.parse_sms_messages(inbox['messages'])
42
+ @voicemails = parser.parse_voicemail_messages(inbox['messages'])
43
+ @all_messages = smss | voicemails
44
+ @all_messages.sort_by!(&:start_time)
45
+ end
46
+
47
+ def missed(parser = GvoiceRuby::InboxParser.new)
48
+ inbox = parser.parse_page(fetch_page('https://www.google.com/voice/inbox/recent/missed/'))
49
+ parser.parse_calls(inbox['messages'])
50
+ end
51
+
52
+ def received(parser = GvoiceRuby::InboxParser.new)
53
+ inbox = parser.parse_page(fetch_page('https://www.google.com/voice/inbox/recent/received/'))
54
+ parser.parse_calls(inbox['messages'])
55
+ end
56
+
57
+ def placed(parser = GvoiceRuby::InboxParser.new)
58
+ inbox = parser.parse_page(fetch_page('https://www.google.com/voice/inbox/recent/placed/'))
59
+ parser.parse_calls(inbox['messages'])
60
+ end
61
+
62
+ def send_sms(options, show_details = true)
63
+ fields = [ PostField.content('phoneNumber', options[:phone_number]),
64
+ PostField.content('text', options[:text]),
65
+ PostField.content('_rnr_se', @_rnr_se) ]
66
+
67
+ options.merge!({ :post_url => "https://www.google.com/voice/sms/send" })
68
+
69
+ if show_details
70
+ logger.info "Sending sms..."
71
+ logger.info "\tTo: #{options[:phone_number]}"
72
+ logger.info "\tBody: #{options[:text]}"
73
+ logger.info "\tSent at: #{Time.now}\n"
74
+ end
75
+
76
+ post(options, fields)
77
+ end
78
+
79
+ def call(options)
80
+ fields = [ PostField.content('outgoingNumber', options[:outgoing_number]),
81
+ PostField.content('forwardingNumber', options[:forwarding_number]),
82
+ PostField.content('phoneType', options[:phone_type] || 2),
83
+ PostField.content('subscriberNumber', 'undefined'),
84
+ PostField.content('remember', 0),
85
+ PostField.content('_rnr_se', @_rnr_se) ]
86
+
87
+ options.merge!({ :post_url => "https://www.google.com/voice/call/connect" })
88
+
89
+ post(options, fields)
90
+ end
91
+
92
+ def cancel_call(options = {})
93
+ fields = [ PostField.content('outgoingNumber', options[:outgoing_number] || 'undefined'),
94
+ PostField.content('forwardingNumber', options[:forwarding_number] || 'undefined'),
95
+ PostField.content('cancelType', 'C2C'),
96
+ PostField.content('_rnr_se', @_rnr_se) ]
97
+
98
+ options.merge!({ :post_url => "https://www.google.com/voice/call/cancel" })
99
+
100
+ post(options, fields)
101
+ end
102
+
103
+ def archive(options)
104
+ fields = [ PostField.content('messages', options[:id]),
105
+ PostField.content('archive', 1),
106
+ PostField.content('_rnr_se', @_rnr_se) ]
107
+
108
+ options.merge!({ :post_url => 'https://www.google.com/voice/inbox/mark'})
109
+
110
+ post(options, fields)
111
+ end
112
+
113
+ def mark_as_read(options)
114
+ fields = [ PostField.content('messages', options[:id]),
115
+ PostField.content('read', 1),
116
+ PostField.content('_rnr_se', @_rnr_se) ]
117
+
118
+ options.merge!({ :post_url => 'https://www.google.com/voice/inbox/mark'})
119
+
120
+ post(options, fields)
121
+ end
122
+
123
+ def mark_as_unread(options)
124
+ fields = [ PostField.content('messages', options[:id]),
125
+ PostField.content('read', 0),
126
+ PostField.content('_rnr_se', @_rnr_se) ]
127
+
128
+ options.merge!({ :post_url => 'https://www.google.com/voice/inbox/mark'})
129
+
130
+ post(options, fields)
131
+ end
132
+
133
+ def star(options)
134
+ fields = [ PostField.content('messages', options[:id]),
135
+ PostField.content('star', 1),
136
+ PostField.content('_rnr_se', @_rnr_se) ]
137
+
138
+ options.merge!({ :post_url => 'https://www.google.com/voice/inbox/star'})
139
+
140
+ post(options, fields)
141
+ end
142
+
143
+ def unstar(options)
144
+ fields = [ PostField.content('messages', options[:id]),
145
+ PostField.content('star', 0),
146
+ PostField.content('_rnr_se', @_rnr_se) ]
147
+
148
+ options.merge!({ :post_url => 'https://www.google.com/voice/inbox/star'})
149
+
150
+ post(options, fields)
151
+ end
152
+
153
+ def add_note(options)
154
+ fields = [ PostField.content('id', options[:id]),
155
+ PostField.content('note', options[:note]),
156
+ PostField.content('_rnr_se', @_rnr_se) ]
157
+
158
+ options.merge!({ :post_url => 'https://www.google.com/voice/inbox/savenote'})
159
+
160
+ post(options, fields)
161
+ end
162
+
163
+ def delete_note(options)
164
+ fields = [ PostField.content('id', options[:id]),
165
+ PostField.content('_rnr_se', @_rnr_se) ]
166
+
167
+ options.merge!({ :post_url => 'https://www.google.com/voice/inbox/deletenote'})
168
+
169
+ post(options, fields)
170
+ end
171
+
172
+ def logout
173
+ if logged_in?
174
+ @curb_instance.url = "https://www.google.com/voice/account/signout"
175
+ @curb_instance.perform
176
+ logger.info "FINISHED LOGOUT #{@curb_instance.url}: HTTP #{@curb_instance.response_code}"
177
+ @curb_instance = nil
178
+ end
179
+ self
180
+ end
181
+
182
+ private
183
+ def login(options = {})
184
+ @curb_instance.url = 'https://www.google.com/accounts/ServiceLoginAuth'
185
+ @curb_instance.perform
186
+ # If String#force_encoding doesn't exist we are on Ruby 1.8 and we shouldn't encode anything
187
+ @curb_instance.body_str.force_encoding("UTF-8") if @curb_instance.body_str.respond_to?(:force_encoding)
188
+
189
+ defeat_google_xsrf(@curb_instance.body_str)
190
+
191
+ begin
192
+ fields = [ PostField.content('continue', (options[:continue_url] || 'https://www.google.com/voice')),
193
+ PostField.content('GALX', @galx),
194
+ PostField.content('service', (options[:google_service] || 'grandcentral')),
195
+ PostField.content('Email', options[:google_account_email]),
196
+ PostField.content('Passwd', options[:google_account_password]) ]
197
+ rescue ArgumentError
198
+ warn "Unable to log in."
199
+ raise GvoiceRuby::LoginFailed
200
+ end
201
+ options.merge!({ :post_url => 'https://www.google.com/accounts/ServiceLoginAuth' })
202
+
203
+ post(options, fields)
204
+ end
205
+
206
+ def post(options, fields)
207
+ @curb_instance.url = options[:post_url] #"https://www.google.com/voice/call/connect || https://www.google.com/voice/sms/send"
208
+ @curb_instance.http_post(fields)
209
+
210
+ logger.info "FINISHED POST TO #{options[:post_url]}: HTTP #{@curb_instance.response_code}"
211
+ return @curb_instance
212
+ end
213
+
214
+ def fetch_page(url = 'https://www.google.com/voice/inbox/recent')
215
+
216
+ @curb_instance.url = url #"https://www.google.com/voice/inbox/recent"
217
+
218
+ @curb_instance.http_get
219
+
220
+ logger.info "FINISHED FETCHING #{url}: HTTP #{@curb_instance.response_code}"
221
+ return @curb_instance
222
+ end
223
+
224
+ def get_unread_counts(inbox)
225
+ @unread_counts = inbox['unreadCounts']
226
+ @any_unread = inbox['unreadCounts']['unread'].to_i != 0
227
+ logger.info "No unread messages in your Google Voice inbox." unless @any_unread
228
+ end
229
+
230
+ def defeat_google_xsrf(body_string)
231
+ # defeat Google's XSRF protection
232
+ doc = Nokogiri::HTML::DocumentFragment.parse(body_string)
233
+ doc.css('div.loginBox table#gaia_table input').each do |input|
234
+ if input.to_s =~ /GALX/u
235
+ @galx = input.to_s.scan(/value\="(.+?)"/u).flatten!.pop
236
+ else
237
+ next
238
+ # raise IOError, 'Cannot fetch galx attribute from Google.'
239
+ end
240
+ end
241
+ end
242
+
243
+ def set_rnr_se_token
244
+ if @curb_instance.response_code == 200 #&& @curb_instance.respond_to?(:perform) # Vestigial?
245
+ @curb_instance.url = "http://www.google.com/voice"
246
+ @curb_instance.perform
247
+ @_rnr_se = extract_rnr_se(@curb_instance.body_str)
248
+ else
249
+ raise IOError, "Curb instance was not properly initialized."
250
+ end
251
+ end
252
+
253
+ def extract_rnr_se(body_string)
254
+ begin
255
+ /value="(.+)"/.match(Nokogiri::HTML::Document.parse(body_string).css('form#gc-search-form').inner_html)
256
+ return $1
257
+ rescue IOError
258
+ raise IOError, "Problem extracting _rnr_se code from page."
259
+ end
260
+ end
261
+
262
+ def initialize_curb
263
+ @curb_instance = Easy.new do |curl|
264
+ # Google gets mad if you don't fake this...
265
+ curl.headers["User-Agent"] = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2"
266
+ # Let's see what happens under the hood
267
+ # curl.verbose = true
268
+
269
+ # Google will redirect us a bit
270
+ curl.follow_location = true
271
+
272
+ # Google will make sure we retain cookies
273
+ curl.enable_cookies = true
274
+ end
275
+ end
276
+ end
277
+ end