kinokero 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +44 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +49 -0
- data/Gemfile_mock +8 -0
- data/LICENSE +20 -0
- data/README.md +955 -0
- data/Rakefile +1 -0
- data/console/.ruby-gemset +1 -0
- data/console/.ruby-version +1 -0
- data/console/Gemfile +6 -0
- data/console/Gemfile.lock +63 -0
- data/console/README.md +34 -0
- data/console/config/application_configuration.rb +39 -0
- data/console/config/gcp_seed.yml +73 -0
- data/console/config/kinokero_initializer_template.rb +108 -0
- data/console/console +2 -0
- data/console/irb_console +2 -0
- data/console/lib/appliance_common.rb +73 -0
- data/console/twiga.rb +579 -0
- data/hp-check.log +244 -0
- data/kinokero.gemspec +35 -0
- data/lib/kinokero.rb +183 -0
- data/lib/kinokero/blank.rb +105 -0
- data/lib/kinokero/cloudprint.rb +1159 -0
- data/lib/kinokero/device.rb +6 -0
- data/lib/kinokero/jingle.rb +176 -0
- data/lib/kinokero/log.rb +157 -0
- data/lib/kinokero/printer.rb +313 -0
- data/lib/kinokero/proxy.rb +341 -0
- data/lib/kinokero/ruby_extensions.rb +21 -0
- data/lib/kinokero/sasl_xoauth2.rb +164 -0
- data/lib/kinokero/version.rb +3 -0
- data/lib/proto/cloud_device_description.proto +18 -0
- data/lib/proto/cloud_device_state.proto +30 -0
- data/lib/proto/cloud_device_state_type.proto +20 -0
- data/lib/proto/cloud_device_ui_state.proto +42 -0
- data/lib/proto/cloud_device_ui_state_severity.proto +12 -0
- data/lib/proto/cloud_job_ticket.proto +18 -0
- data/lib/proto/collate.proto +4 -0
- data/lib/proto/collate_ticket_item.proto +5 -0
- data/lib/proto/color.proto +42 -0
- data/lib/proto/color_ticket_item.proto +12 -0
- data/lib/proto/copies.proto +6 -0
- data/lib/proto/copies_ticket_item.proto +5 -0
- data/lib/proto/cover.proto +31 -0
- data/lib/proto/cover_state.proto +25 -0
- data/lib/proto/device_action_cause.proto +19 -0
- data/lib/proto/dpi.proto +27 -0
- data/lib/proto/dpi_ticket_item.proto +13 -0
- data/lib/proto/duplex.proto +15 -0
- data/lib/proto/duplex_ticket_item.proto +8 -0
- data/lib/proto/fit_to_page.proto +20 -0
- data/lib/proto/fit_to_page_ticket_item.proto +8 -0
- data/lib/proto/input_tray_state.proto +31 -0
- data/lib/proto/input_tray_unit.proto +35 -0
- data/lib/proto/job_state.proto +143 -0
- data/lib/proto/local_settings.proto +36 -0
- data/lib/proto/localized_string.proto +119 -0
- data/lib/proto/margins.proto +33 -0
- data/lib/proto/margins_ticket_item.proto +14 -0
- data/lib/proto/marker.proto +62 -0
- data/lib/proto/marker_state.proto +31 -0
- data/lib/proto/media_path.proto +6 -0
- data/lib/proto/media_path_state.proto +25 -0
- data/lib/proto/media_size.proto +216 -0
- data/lib/proto/media_size_ticket_item.proto +17 -0
- data/lib/proto/output_bin_state.proto +31 -0
- data/lib/proto/output_bin_unit.proto +32 -0
- data/lib/proto/page_orientation.proto +16 -0
- data/lib/proto/page_orientation_ticket_item.proto +9 -0
- data/lib/proto/page_range.proto +15 -0
- data/lib/proto/page_range_ticket_item.proto +7 -0
- data/lib/proto/print_job_state.proto +18 -0
- data/lib/proto/print_job_state_diff.proto +13 -0
- data/lib/proto/print_job_ui_state.proto +24 -0
- data/lib/proto/print_ticket_section.proto +30 -0
- data/lib/proto/printer_description_section.proto +107 -0
- data/lib/proto/printer_state_section.proto +49 -0
- data/lib/proto/printer_ui_state_section.proto +39 -0
- data/lib/proto/printing_speed.proto +35 -0
- data/lib/proto/pwg_raster_config.proto +176 -0
- data/lib/proto/range_capability.proto +14 -0
- data/lib/proto/reverse_order.proto +5 -0
- data/lib/proto/reverse_order_ticket_item.proto +5 -0
- data/lib/proto/scanner_description_section.proto +5 -0
- data/lib/proto/scanner_state_section.proto +25 -0
- data/lib/proto/select_capability.proto +31 -0
- data/lib/proto/supported_content_type.proto +12 -0
- data/lib/proto/typed_value_capability.proto +15 -0
- data/lib/proto/vendor_capability.proto +40 -0
- data/lib/proto/vendor_state.proto +26 -0
- data/lib/proto/vendor_ticket_item.proto +9 -0
- data/lib/proto_lib/cloud_device_state.pb.rb +21 -0
- data/lib/proto_lib/cloud_device_state_type.pb.rb +16 -0
- data/lib/proto_lib/cloud_device_ui_state.pb.rb +22 -0
- data/lib/proto_lib/cloud_device_ui_state_severity.pb.rb +17 -0
- data/lib/proto_lib/collate.pb.rb +11 -0
- data/lib/proto_lib/color.pb.rb +31 -0
- data/lib/proto_lib/copies.pb.rb +12 -0
- data/lib/proto_lib/cover.pb.rb +21 -0
- data/lib/proto_lib/cover_state.pb.rb +27 -0
- data/lib/proto_lib/device_action_cause.pb.rb +18 -0
- data/lib/proto_lib/dpi.pb.rb +27 -0
- data/lib/proto_lib/duplex.pb.rb +26 -0
- data/lib/proto_lib/fit_to_page.pb.rb +28 -0
- data/lib/proto_lib/input_tray_state.pb.rb +30 -0
- data/lib/proto_lib/input_tray_unit.pb.rb +25 -0
- data/lib/proto_lib/job_state.pb.rb +99 -0
- data/lib/proto_lib/localized_string.pb.rb +118 -0
- data/lib/proto_lib/margins.pb.rb +30 -0
- data/lib/proto_lib/marker.pb.rb +45 -0
- data/lib/proto_lib/marker_state.pb.rb +30 -0
- data/lib/proto_lib/media_path.pb.rb +11 -0
- data/lib/proto_lib/media_path_state.pb.rb +27 -0
- data/lib/proto_lib/media_size.pb.rb +198 -0
- data/lib/proto_lib/output_bin_state.pb.rb +30 -0
- data/lib/proto_lib/output_bin_unit.pb.rb +22 -0
- data/lib/proto_lib/page_orientation.pb.rb +26 -0
- data/lib/proto_lib/page_range.pb.rb +20 -0
- data/lib/proto_lib/print_job_state_diff.pb.rb +12 -0
- data/lib/proto_lib/printer_description_section.pb.rb +30 -0
- data/lib/proto_lib/printer_state_section.pb.rb +23 -0
- data/lib/proto_lib/printer_ui_state_section.pb.rb +28 -0
- data/lib/proto_lib/printing_speed.pb.rb +21 -0
- data/lib/proto_lib/pwg_raster_config.pb.rb +103 -0
- data/lib/proto_lib/range_capability.pb.rb +19 -0
- data/lib/proto_lib/reverse_order.pb.rb +11 -0
- data/lib/proto_lib/scanner_description_section.pb.rb +10 -0
- data/lib/proto_lib/scanner_state_section.pb.rb +17 -0
- data/lib/proto_lib/select_capability.pb.rb +22 -0
- data/lib/proto_lib/supported_content_type.pb.rb +13 -0
- data/lib/proto_lib/typed_value_capability.pb.rb +19 -0
- data/lib/proto_lib/vendor_capability.pb.rb +23 -0
- data/lib/proto_lib/vendor_state.pb.rb +27 -0
- data/test/.ruby-gemset +1 -0
- data/test/.ruby-version +1 -0
- data/test/Gemfile +68 -0
- data/test/Gemfile.lock +269 -0
- data/test/README.md +2 -0
- data/test/Rakefile +6 -0
- data/test/app/assets/javascripts/application.js +16 -0
- data/test/app/assets/stylesheets/application.css +13 -0
- data/test/app/controllers/application_controller.rb +13 -0
- data/test/app/controllers/home_controller.rb +10 -0
- data/test/app/helpers/application_helper.rb +2 -0
- data/test/app/views/home/index.html.erb +2 -0
- data/test/app/views/home/show.html.erb +2 -0
- data/test/app/views/layouts/application.html.erb +14 -0
- data/test/bin/bundle +3 -0
- data/test/bin/rails +4 -0
- data/test/bin/rake +4 -0
- data/test/config/application.rb +29 -0
- data/test/config/boot.rb +4 -0
- data/test/config/database.yml +25 -0
- data/test/config/environment.rb +5 -0
- data/test/config/environments/development.rb +48 -0
- data/test/config/environments/production.rb +95 -0
- data/test/config/environments/test.rb +42 -0
- data/test/config/initializers/backtrace_silencers.rb +7 -0
- data/test/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/config/initializers/inflections.rb +16 -0
- data/test/config/initializers/mime_types.rb +5 -0
- data/test/config/initializers/secret_token.rb +12 -0
- data/test/config/initializers/session_store.rb +3 -0
- data/test/config/initializers/wrap_parameters.rb +14 -0
- data/test/config/locales/en.yml +23 -0
- data/test/config/routes.rb +65 -0
- data/test/db/development.sqlite3 +0 -0
- data/test/db/migrate/20111012050200_add_sessions_table.rb +12 -0
- data/test/db/schema.rb +26 -0
- data/test/db/seeds.rb +7 -0
- data/test/db/test.sqlite3 +0 -0
- data/test/log/development.log +0 -0
- data/test/log/test.log +0 -0
- data/test/test/controllers/home_controller_test.rb +133 -0
- data/test/test/ctlr_test_helper.rb +7 -0
- data/test/test/fixtures/gcp_seed.yml +51 -0
- data/test/test/models/cloudprint_test.rb +186 -0
- data/test/test/models/jingle_test.rb +44 -0
- data/test/test/models/printer_test.rb +99 -0
- data/test/test/models/proxy_test.rb +102 -0
- data/test/test/test_helper.rb +31 -0
- data/test/test/test_kinokero.rb +234 -0
- metadata +462 -0
@@ -0,0 +1,341 @@
|
|
1
|
+
# #########################################################################
|
2
|
+
# #########################################################################
|
3
|
+
|
4
|
+
module Kinokero
|
5
|
+
|
6
|
+
# #########################################################################
|
7
|
+
|
8
|
+
class Proxy
|
9
|
+
|
10
|
+
extend Forwardable
|
11
|
+
# require 'singleton'
|
12
|
+
# include Singleton
|
13
|
+
|
14
|
+
# #########################################################################
|
15
|
+
|
16
|
+
attr_reader :my_devices, :options
|
17
|
+
|
18
|
+
# #########################################################################
|
19
|
+
|
20
|
+
# -----------------------------------------------------------------------------
|
21
|
+
def initialize( gcp_hash, options = { verbose: true, auto_connect: true } )
|
22
|
+
|
23
|
+
@proxy_id = Kinokero.my_proxy_id
|
24
|
+
@options = options
|
25
|
+
@my_devices = {} # will hold the device objects from seed
|
26
|
+
|
27
|
+
Kinokero::Log.verbose_debug( options.inspect, options[:verbose] )
|
28
|
+
|
29
|
+
cups_list = Cups.show_destinations # current printer list
|
30
|
+
|
31
|
+
# convert seed data into device objects
|
32
|
+
gcp_hash.each_key do |item|
|
33
|
+
|
34
|
+
# make sure that the persistent printer is still in CUPS list
|
35
|
+
if cups_list.include?( gcp_hash[item][:cups_alias] )
|
36
|
+
|
37
|
+
# instantiate object and remember
|
38
|
+
@my_devices[ item ] =
|
39
|
+
Kinokero::Printer.new( gcp_hash[item] )
|
40
|
+
|
41
|
+
@my_devices[ item ].cloudprint = Kinokero::Cloudprint.new(
|
42
|
+
@my_devices[item].gcp_printer_control,
|
43
|
+
options
|
44
|
+
)
|
45
|
+
|
46
|
+
else # previously registered device no longer active
|
47
|
+
# TODO:
|
48
|
+
end # convert each seed to a device object
|
49
|
+
|
50
|
+
end # setting up each device
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
# -----------------------------------------------------------------------------
|
55
|
+
# do_connect --
|
56
|
+
# -----------------------------------------------------------------------------
|
57
|
+
def do_connect(item)
|
58
|
+
# establish a jingle connection
|
59
|
+
@my_devices[item].cloudprint.gtalk_start_connection do |printerid|
|
60
|
+
# NOTE: this execution takes place asynchronously
|
61
|
+
# upon callback from jingle notification
|
62
|
+
|
63
|
+
if printerid =~ /delete/
|
64
|
+
# jingle notified us of delete
|
65
|
+
# potentially reentreant; but delete anyway
|
66
|
+
# TODO: verify printerid for us?
|
67
|
+
do_delete( item, true )
|
68
|
+
else # print notification
|
69
|
+
do_print_jobs( printerid )
|
70
|
+
end # if..then..else notification type
|
71
|
+
|
72
|
+
end # block
|
73
|
+
|
74
|
+
# execution continues here BEFORE above block executes
|
75
|
+
|
76
|
+
# upon first connect, fetch & print any pending jobs in queue
|
77
|
+
fetch_and_print_queue_if_ready(
|
78
|
+
item,
|
79
|
+
@my_devices[item].gcp_printer_control[:gcp_printerid]
|
80
|
+
)
|
81
|
+
|
82
|
+
# begin polling the printer device status
|
83
|
+
@my_devices[item].start_poll_thread
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
# -----------------------------------------------------------------------------
|
88
|
+
|
89
|
+
def do_fetch_jobs( item )
|
90
|
+
|
91
|
+
@my_devices[item].cloudprint.gcp_get_printer_fetch(
|
92
|
+
@my_devices[item].gcp_printer_control[:gcp_printerid]
|
93
|
+
)
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
# -----------------------------------------------------------------------------
|
98
|
+
# do_delete --
|
99
|
+
# this is potentially reentreant:
|
100
|
+
# an initial do_delete spawns a jingle delete notification which
|
101
|
+
# then calls do delete again at an indeterminate point
|
102
|
+
# -----------------------------------------------------------------------------
|
103
|
+
def do_delete(item, skip_gcp=nil )
|
104
|
+
|
105
|
+
# forestall reentreant issues by checking our validity
|
106
|
+
unless (my_device = @my_devices[item]).nil?
|
107
|
+
|
108
|
+
# stop polling the printer device status
|
109
|
+
my_device.stop_poll_thread
|
110
|
+
|
111
|
+
# forestall reentreant issues by checking our validity
|
112
|
+
unless my_device.cloudprint.nil?
|
113
|
+
# do delete housekeeping & maybe issue GCP command
|
114
|
+
my_device.cloudprint.gcp_delete_printer( skip_gcp )
|
115
|
+
my_device.cloudprint = nil # release the reference to our object
|
116
|
+
end # unless cloudprint's been removed
|
117
|
+
|
118
|
+
end # unless device already removed
|
119
|
+
|
120
|
+
@my_devices.delete( item ) # remove device struct from our list
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
# -----------------------------------------------------------------------------
|
125
|
+
# do_register -- registers our default printer, prints claim info
|
126
|
+
# -----------------------------------------------------------------------------
|
127
|
+
def do_register( gcp_request, &block )
|
128
|
+
|
129
|
+
response = Kinokero::Cloudprint.register_anonymous_printer( gcp_request ) do |gcp_ctl|
|
130
|
+
|
131
|
+
# this block is called only if/when asynch polling completes
|
132
|
+
# in a separate process
|
133
|
+
puts Kinokero::Log.say_info("\n***** Printer successfully registered to GCP *****")
|
134
|
+
puts Kinokero::Log.say_warn "register gcp_control: #{@gcp_ctl.object_id}"
|
135
|
+
puts gcp_ctl.inspect
|
136
|
+
|
137
|
+
# wrap the newly registered printer in a device object
|
138
|
+
new_device = Kinokero::Printer.new( gcp_ctl, gcp_request)
|
139
|
+
|
140
|
+
# add it to our list of managed devices
|
141
|
+
@my_devices[ gcp_ctl[:item] ] = new_device
|
142
|
+
|
143
|
+
# create a cloudprint object to manage the protocols
|
144
|
+
new_device.cloudprint =
|
145
|
+
Kinokero::Cloudprint.new( gcp_ctl, @options )
|
146
|
+
|
147
|
+
Kinokero::Log.verbose_debug "my_devices has #{ @my_devices.size } devices [#{ @my_devices.object_id }]"
|
148
|
+
|
149
|
+
# this is the place to save anything we need to about the printers
|
150
|
+
# under swalapala control; info is in gcp_ctl
|
151
|
+
yield( gcp_ctl ) # persistence
|
152
|
+
|
153
|
+
end # block for register
|
154
|
+
|
155
|
+
# execution continues here AFTER registering but BEFORE polling completes
|
156
|
+
# this is our opportunity to tell the user to claim the printer via
|
157
|
+
# registration token at Google Cloud Print server
|
158
|
+
|
159
|
+
print_gcp_registration_info( response ) # output registration instructions
|
160
|
+
|
161
|
+
return response
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
# -----------------------------------------------------------------------------
|
166
|
+
# -----------------------------------------------------------------------------
|
167
|
+
def do_refresh(item)
|
168
|
+
@my_devices[item].cloudprint.gcp_refresh_tokens
|
169
|
+
# new token should be set up in the gcp_control area
|
170
|
+
end
|
171
|
+
|
172
|
+
# -----------------------------------------------------------------------------
|
173
|
+
# -----------------------------------------------------------------------------
|
174
|
+
def do_list(item)
|
175
|
+
@my_devices[item].cloudprint.gcp_get_printer_list
|
176
|
+
end
|
177
|
+
|
178
|
+
# -----------------------------------------------------------------------------
|
179
|
+
# -----------------------------------------------------------------------------
|
180
|
+
def do_ready_state(item)
|
181
|
+
@my_devices[item].cloudprint.gcp_ready_state_changed(
|
182
|
+
true, # shows ready for jobs
|
183
|
+
0, # waiting for work
|
184
|
+
'' # no reason description needed
|
185
|
+
)
|
186
|
+
end
|
187
|
+
|
188
|
+
|
189
|
+
# -----------------------------------------------------------------------------
|
190
|
+
# -----------------------------------------------------------------------------
|
191
|
+
|
192
|
+
def item_from_printerid( printerid )
|
193
|
+
|
194
|
+
found = @my_devices.detect do |item, device|
|
195
|
+
break item if device.gcp_printer_control[:gcp_printerid] == printerid
|
196
|
+
false
|
197
|
+
end # each item
|
198
|
+
|
199
|
+
raise PrinteridNotFound, printerid if found.nil? # oops, not found!
|
200
|
+
|
201
|
+
return found
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
# -----------------------------------------------------------------------------
|
206
|
+
|
207
|
+
def fetch_and_print_queue_if_ready( item, printerid )
|
208
|
+
|
209
|
+
if @my_devices[item].is_printer_ready?
|
210
|
+
|
211
|
+
print_fetch_queue(
|
212
|
+
item, # find corresponding device item
|
213
|
+
printerid,
|
214
|
+
@my_devices[item].cloudprint.gcp_get_printer_fetch( printerid )
|
215
|
+
)
|
216
|
+
|
217
|
+
else # oops, printer is NOT ready
|
218
|
+
# TODO: shouldn't we tell GCP about this situation?
|
219
|
+
|
220
|
+
end # continue if printer ready
|
221
|
+
|
222
|
+
end
|
223
|
+
|
224
|
+
# -----------------------------------------------------------------------------
|
225
|
+
|
226
|
+
# do_print_jobs blends across the perfect protocol boundaries I'm trying to
|
227
|
+
# maintain with Cloudprint, mainly because there's a higher level process
|
228
|
+
# handling which it has to handle, thus involving multiple cloudprint
|
229
|
+
# interactions and Printer class interaction.
|
230
|
+
# -----------------------------------------------------------------------------
|
231
|
+
def do_print_jobs( printerid )
|
232
|
+
|
233
|
+
fetch_and_print_queue_if_ready(
|
234
|
+
item_from_printerid( printerid ),
|
235
|
+
printerid
|
236
|
+
)
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
# -----------------------------------------------------------------------------
|
241
|
+
|
242
|
+
# DRY work of printing a fetch queue of jobs
|
243
|
+
def print_fetch_queue(item, printerid, fetch_result)
|
244
|
+
if fetch_result['success']
|
245
|
+
Kinokero::Log.verbose_debug "#{ printerid } queue has #{ fetch_result['jobs'].size } jobs"
|
246
|
+
|
247
|
+
my_cloudprint = @my_devices[item].cloudprint # DRY access
|
248
|
+
|
249
|
+
# deal with each job fetched
|
250
|
+
fetch_result['jobs'].each do |job|
|
251
|
+
|
252
|
+
unless printerid == job['printerid'] # ? hmmm, different printer ref'd
|
253
|
+
|
254
|
+
item = item_from_printerid( printerid ) # find corresponding device item
|
255
|
+
printerid = job['printerid']
|
256
|
+
my_cloudprint = @my_devices[item].cloudprint # DRY access
|
257
|
+
print "\e[1;31m\n***** WARNING ***** differ printerid in fetch queue #{printerid}\n\e[0m"
|
258
|
+
end
|
259
|
+
|
260
|
+
# able to download the job file for printing?
|
261
|
+
if ( job_file = my_cloudprint.gcp_get_job_file( job["fileUrl"] ) )
|
262
|
+
|
263
|
+
# update printer status to IN PROGRESS
|
264
|
+
my_cloudprint.gcp_job_status(
|
265
|
+
job["id"],
|
266
|
+
::Kinokero::Cloudprint::GCP_JOBSTATE_IN_PROGRESS,
|
267
|
+
0
|
268
|
+
)
|
269
|
+
|
270
|
+
# write the file locally
|
271
|
+
File.open( job["id"], 'wb') { |fp| fp.write(job_file) }
|
272
|
+
|
273
|
+
status = @my_devices[item].print_file( job['id'] )
|
274
|
+
|
275
|
+
# TODO: do something intelligent with the status
|
276
|
+
# like report back to GCP
|
277
|
+
|
278
|
+
# poll printer job status & report back to GCP
|
279
|
+
my_cloudprint.gcp_job_status(
|
280
|
+
job["id"],
|
281
|
+
::Kinokero::Cloudprint::GCP_JOBSTATE_DONE,
|
282
|
+
job["numberOfPages"]
|
283
|
+
)
|
284
|
+
|
285
|
+
# delete the file
|
286
|
+
File.delete( job["id"] )
|
287
|
+
|
288
|
+
else # failure to get file; tell GCP about the status
|
289
|
+
my_cloudprint.gcp_job_status_abort(
|
290
|
+
job["id"],
|
291
|
+
::Kinokero::Cloudprint::GCP_USER_ACTION_OTHER,
|
292
|
+
0
|
293
|
+
)
|
294
|
+
|
295
|
+
end # if..then..else get job file
|
296
|
+
|
297
|
+
end # do each job
|
298
|
+
end # pending job queue from fetch
|
299
|
+
|
300
|
+
end
|
301
|
+
|
302
|
+
# -----------------------------------------------------------------------------
|
303
|
+
# -----------------------------------------------------------------------------
|
304
|
+
def print_gcp_registration_info( response )
|
305
|
+
if response[:success]
|
306
|
+
Kinokero::Printer.print_gcp_registration_info(
|
307
|
+
response[:cups_alias], # actual printer to use
|
308
|
+
snippet_registration_info( response ) # crafted message to print
|
309
|
+
)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# -----------------------------------------------------------------------------
|
314
|
+
# -----------------------------------------------------------------------------
|
315
|
+
def snippet_registration_info( response )
|
316
|
+
<<RUBY10
|
317
|
+
|
318
|
+
******************************************************************
|
319
|
+
*** Important instructions to complete CloudPrint registration ***
|
320
|
+
******************************************************************
|
321
|
+
*** Go to the following url and claim printer with the given ***
|
322
|
+
*** registration token, or click the easy-claim url below. You ***
|
323
|
+
*** must do this within the next fifteen (15) minutes. Thanks! ***
|
324
|
+
******************************************************************
|
325
|
+
|
326
|
+
Registration token: #{response[:gcp_printer_reg_token]}
|
327
|
+
Claim printer URL: #{response[:gcp_claim_token_url]}
|
328
|
+
Easy-claim URL: #{response[:gcp_easy_reg_url]}
|
329
|
+
Record id: #{response[:swalapala_printer_id]}
|
330
|
+
Printer name: #{response[:gcp_printer_name]}
|
331
|
+
GCP printer id: #{response[:gcp_printer_id]}
|
332
|
+
|
333
|
+
RUBY10
|
334
|
+
end
|
335
|
+
|
336
|
+
# -----------------------------------------------------------------------------
|
337
|
+
# -----------------------------------------------------------------------------
|
338
|
+
|
339
|
+
end # class Proxy
|
340
|
+
|
341
|
+
end # module
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# commonly used extensions from Rails for Ruby
|
2
|
+
#
|
3
|
+
require 'kinokero/blank'
|
4
|
+
|
5
|
+
# ****************************************************************************
|
6
|
+
class Hash
|
7
|
+
|
8
|
+
# -----------------------------------------------------------------------------
|
9
|
+
# File activesupport/lib/active_support/core_ext/hash/keys.rb, line 48
|
10
|
+
# -----------------------------------------------------------------------------
|
11
|
+
def assert_valid_keys(*valid_keys)
|
12
|
+
valid_keys.flatten!
|
13
|
+
each_key do |k|
|
14
|
+
raise(ArgumentError, "Unknown key: #{k}") unless valid_keys.include?(k)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
# -----------------------------------------------------------------------------
|
18
|
+
# -----------------------------------------------------------------------------
|
19
|
+
|
20
|
+
end # class Hash
|
21
|
+
# ****************************************************************************
|
@@ -0,0 +1,164 @@
|
|
1
|
+
# ****************************************************************************
|
2
|
+
# ***** addtions to XMPP4R to handle Google Talk X-OAUTH2 ********************
|
3
|
+
# ****************************************************************************
|
4
|
+
# ****************************************************************************
|
5
|
+
# ****************************************************************************
|
6
|
+
|
7
|
+
module Jabber
|
8
|
+
|
9
|
+
# ****************************************************************************
|
10
|
+
|
11
|
+
MECHANISM_XOAUTH2 = 'X-OAUTH2'
|
12
|
+
NS_GOOGLE_AUTH_PROTOCOL = "http://www.google.com/talk/protocol/auth"
|
13
|
+
NS_GOOGLE_AUTH_SERVICE = "chromiumsync"
|
14
|
+
|
15
|
+
# ****************************************************************************
|
16
|
+
|
17
|
+
class Client
|
18
|
+
|
19
|
+
# -----------------------------------------------------------------------------
|
20
|
+
# Authenticate with the server
|
21
|
+
#
|
22
|
+
# Throws ClientAuthenticationFailure
|
23
|
+
#
|
24
|
+
# Authentication mechanisms are used in the following preference:
|
25
|
+
# * SASL X-OAUTH2
|
26
|
+
# * SASL DIGEST-MD5
|
27
|
+
# * SASL PLAIN
|
28
|
+
# * Non-SASL digest
|
29
|
+
# password:: [String]
|
30
|
+
#
|
31
|
+
# THIS OVERRIDES XMPP4R method of the same
|
32
|
+
#
|
33
|
+
# -----------------------------------------------------------------------------
|
34
|
+
def auth(password)
|
35
|
+
|
36
|
+
begin
|
37
|
+
if @stream_mechanisms.include? MECHANISM_XOAUTH2
|
38
|
+
auth_sasl SASL.new(self, MECHANISM_XOAUTH2), password
|
39
|
+
elsif @stream_mechanisms.include? 'DIGEST-MD5'
|
40
|
+
auth_sasl SASL.new(self, 'DIGEST-MD5'), password
|
41
|
+
elsif @stream_mechanisms.include? 'PLAIN'
|
42
|
+
auth_sasl SASL.new(self, 'PLAIN'), password
|
43
|
+
else
|
44
|
+
auth_nonsasl(password)
|
45
|
+
end
|
46
|
+
|
47
|
+
rescue
|
48
|
+
Jabber::debuglog("#{$!.class}: #{$!}\n#{$!.backtrace.join("\n")}")
|
49
|
+
raise ClientAuthenticationFailure.new, $!.to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end # class Client
|
55
|
+
|
56
|
+
# ****************************************************************************
|
57
|
+
# Helpers for SASL authentication (RFC2222)
|
58
|
+
#
|
59
|
+
# You might not need to use them directly, they are
|
60
|
+
# invoked by Jabber::Client#auth
|
61
|
+
# ****************************************************************************
|
62
|
+
|
63
|
+
module SASL
|
64
|
+
|
65
|
+
# -----------------------------------------------------------------------------
|
66
|
+
# Factory function to obtain a SASL helper for the specified mechanism
|
67
|
+
# -----------------------------------------------------------------------------
|
68
|
+
def SASL.new(stream, mechanism)
|
69
|
+
|
70
|
+
case mechanism
|
71
|
+
|
72
|
+
when MECHANISM_XOAUTH2 # added for the override
|
73
|
+
Xoauth2.new(stream)
|
74
|
+
|
75
|
+
when 'DIGEST-MD5'
|
76
|
+
DigestMD5.new(stream)
|
77
|
+
|
78
|
+
when 'PLAIN'
|
79
|
+
Plain.new(stream)
|
80
|
+
|
81
|
+
when 'ANONYMOUS'
|
82
|
+
Anonymous.new(stream)
|
83
|
+
|
84
|
+
else
|
85
|
+
raise "Unknown SASL mechanism: #{mechanism}"
|
86
|
+
|
87
|
+
end # case
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
# -----------------------------------------------------------------------------
|
92
|
+
# cookie is an OAuth2 access token which you obtained from the anonymous registration flow.
|
93
|
+
# this is passed as the "password" to auth
|
94
|
+
# -----------------------------------------------------------------------------
|
95
|
+
class Xoauth2 < Base
|
96
|
+
|
97
|
+
def auth(password)
|
98
|
+
|
99
|
+
auth_text = "\x00#{@stream.jid.node}\x00#{password}"
|
100
|
+
error = nil
|
101
|
+
|
102
|
+
# ::Twiga.say_warn 'XOAUTH2: ' + auth_text.inspect + "\n"
|
103
|
+
# ::Twiga.say_warn 'ENCODED: ' + Base64::strict_encode64(auth_text).inspect + "\n"
|
104
|
+
|
105
|
+
@stream.send(
|
106
|
+
generate_auth(
|
107
|
+
MECHANISM_XOAUTH2,
|
108
|
+
Base64::strict_encode64(auth_text)
|
109
|
+
)
|
110
|
+
) do |reply|
|
111
|
+
unless reply.name == 'success'
|
112
|
+
error = reply.first_element(nil).name
|
113
|
+
end
|
114
|
+
true
|
115
|
+
end # do reply handling
|
116
|
+
|
117
|
+
raise error unless error.nil?
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
# ****************************************************************************
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
# ****************************************************************************
|
126
|
+
# from the Jingle documentation for CloudPrint
|
127
|
+
#
|
128
|
+
# h) Outgoing stanza from Google Cloud Print proxy or printer
|
129
|
+
# ****************************************************************************
|
130
|
+
# <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl"
|
131
|
+
# mechanism="X-OAUTH2" auth:service="chromiumsync"
|
132
|
+
# auth:allow-generated-jid="true"
|
133
|
+
# auth:client-uses-full-bind-result="true"
|
134
|
+
# xmlns:auth="http://www.google.com/talk/protocol/auth">
|
135
|
+
# {Base-64 encoded authentication data}
|
136
|
+
# </auth>
|
137
|
+
# ****************************************************************************
|
138
|
+
def generate_auth(mechanism, text=nil)
|
139
|
+
|
140
|
+
auth = REXML::Element.new 'auth'
|
141
|
+
auth.add_namespace NS_SASL
|
142
|
+
auth.attributes['mechanism'] = mechanism
|
143
|
+
auth.attributes['auth:service'] = NS_GOOGLE_AUTH_SERVICE
|
144
|
+
auth.attributes['auth:allow-generated-jid'] = "true"
|
145
|
+
auth.attributes['auth:client-uses-full-bind-result'] = "true"
|
146
|
+
auth.attributes['xmlns:auth'] = NS_GOOGLE_AUTH_PROTOCOL
|
147
|
+
auth.text = text
|
148
|
+
auth
|
149
|
+
end
|
150
|
+
|
151
|
+
# -----------------------------------------------------------------------------
|
152
|
+
# -----------------------------------------------------------------------------
|
153
|
+
|
154
|
+
# ****************************************************************************
|
155
|
+
|
156
|
+
end # class Xoauth2
|
157
|
+
|
158
|
+
# ****************************************************************************
|
159
|
+
|
160
|
+
end # module Sasl
|
161
|
+
|
162
|
+
# ****************************************************************************
|
163
|
+
end # module Jabber
|
164
|
+
|