OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/service/cloud_print/cloud_print_proxy_backend.h" | 5 #include "chrome/service/cloud_print/cloud_print_proxy_backend.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
11 #include "base/md5.h" | |
12 #include "base/rand_util.h" | 11 #include "base/rand_util.h" |
13 #include "base/string_number_conversions.h" | |
14 #include "base/string_split.h" | |
15 #include "base/stringprintf.h" | |
16 #include "base/utf_string_conversions.h" | |
17 #include "base/values.h" | 12 #include "base/values.h" |
18 #include "chrome/common/net/gaia/gaia_oauth_client.h" | 13 #include "chrome/common/net/gaia/gaia_oauth_client.h" |
19 #include "chrome/common/net/gaia/gaia_urls.h" | 14 #include "chrome/common/net/gaia/gaia_urls.h" |
| 15 #include "chrome/service/cloud_print/cloud_print_auth.h" |
| 16 #include "chrome/service/cloud_print/cloud_print_connector.h" |
20 #include "chrome/service/cloud_print/cloud_print_consts.h" | 17 #include "chrome/service/cloud_print/cloud_print_consts.h" |
21 #include "chrome/service/cloud_print/cloud_print_helpers.h" | 18 #include "chrome/service/cloud_print/cloud_print_helpers.h" |
22 #include "chrome/service/cloud_print/cloud_print_token_store.h" | 19 #include "chrome/service/cloud_print/cloud_print_token_store.h" |
23 #include "chrome/service/cloud_print/cloud_print_url_fetcher.h" | |
24 #include "chrome/service/cloud_print/printer_job_handler.h" | |
25 #include "chrome/service/gaia/service_gaia_authenticator.h" | 20 #include "chrome/service/gaia/service_gaia_authenticator.h" |
26 #include "chrome/service/net/service_url_request_context.h" | 21 #include "chrome/service/net/service_url_request_context.h" |
27 #include "chrome/service/service_process.h" | 22 #include "chrome/service/service_process.h" |
28 #include "googleurl/src/gurl.h" | 23 #include "googleurl/src/gurl.h" |
29 #include "grit/generated_resources.h" | 24 #include "grit/generated_resources.h" |
30 #include "jingle/notifier/base/notifier_options.h" | 25 #include "jingle/notifier/base/notifier_options.h" |
31 #include "jingle/notifier/listener/mediator_thread_impl.h" | 26 #include "jingle/notifier/listener/mediator_thread_impl.h" |
32 #include "jingle/notifier/listener/talk_mediator_impl.h" | 27 #include "jingle/notifier/listener/talk_mediator_impl.h" |
33 #include "net/url_request/url_request_status.h" | |
34 #include "ui/base/l10n/l10n_util.h" | 28 #include "ui/base/l10n/l10n_util.h" |
35 | 29 |
36 // The real guts of CloudPrintProxyBackend, to keep the public client API clean. | 30 // The real guts of CloudPrintProxyBackend, to keep the public client API clean. |
37 class CloudPrintProxyBackend::Core | 31 class CloudPrintProxyBackend::Core |
38 : public base::RefCountedThreadSafe<CloudPrintProxyBackend::Core>, | 32 : public base::RefCountedThreadSafe<CloudPrintProxyBackend::Core>, |
39 public CloudPrintURLFetcherDelegate, | 33 public CloudPrintAuth::Client, |
40 public cloud_print::PrintServerWatcherDelegate, | 34 public CloudPrintConnector::Client, |
41 public PrinterJobHandlerDelegate, | 35 public notifier::TalkMediator::Delegate { |
42 public notifier::TalkMediator::Delegate, | |
43 public gaia::GaiaOAuthClient::Delegate { | |
44 public: | 36 public: |
45 // It is OK for print_server_url to be empty. In this case system should | 37 // It is OK for print_server_url to be empty. In this case system should |
46 // use system default (local) print server. | 38 // use system default (local) print server. |
47 Core(CloudPrintProxyBackend* backend, | 39 Core(CloudPrintProxyBackend* backend, |
| 40 const std::string& proxy_id, |
48 const GURL& cloud_print_server_url, | 41 const GURL& cloud_print_server_url, |
49 const DictionaryValue* print_system_settings, | 42 const DictionaryValue* print_system_settings, |
50 const gaia::OAuthClientInfo& oauth_client_info, | 43 const gaia::OAuthClientInfo& oauth_client_info, |
51 bool enable_job_poll); | 44 bool enable_job_poll); |
52 | 45 |
53 // Note: | 46 // Note: |
54 // | 47 // |
55 // The Do* methods are the various entry points from CloudPrintProxyBackend | 48 // The Do* methods are the various entry points from CloudPrintProxyBackend |
56 // It calls us on a dedicated thread to actually perform synchronous | 49 // It calls us on a dedicated thread to actually perform synchronous |
57 // (and potentially blocking) operations. | 50 // (and potentially blocking) operations. |
(...skipping 15 matching lines...) Expand all Loading... |
73 void DoInitializeWithRobotAuthCode(const std::string& robot_oauth_auth_code, | 66 void DoInitializeWithRobotAuthCode(const std::string& robot_oauth_auth_code, |
74 const std::string& robot_email, | 67 const std::string& robot_email, |
75 const std::string& proxy_id); | 68 const std::string& proxy_id); |
76 | 69 |
77 // Called on the CloudPrintProxyBackend core_thread_ to perform | 70 // Called on the CloudPrintProxyBackend core_thread_ to perform |
78 // shutdown. | 71 // shutdown. |
79 void DoShutdown(); | 72 void DoShutdown(); |
80 void DoRegisterSelectedPrinters( | 73 void DoRegisterSelectedPrinters( |
81 const printing::PrinterList& printer_list); | 74 const printing::PrinterList& printer_list); |
82 | 75 |
83 // CloudPrintURLFetcher::Delegate implementation. | 76 // CloudPrintAuth::Client implementation. |
84 virtual CloudPrintURLFetcher::ResponseAction HandleJSONData( | 77 virtual void OnAuthenticationComplete( |
85 const content::URLFetcher* source, | 78 const std::string& access_token, |
86 const GURL& url, | 79 const std::string& robot_oauth_refresh_token, |
87 DictionaryValue* json_data, | 80 const std::string& robot_email, |
88 bool succeeded); | 81 const std::string& user_email); |
| 82 virtual void OnInvalidCredentials(); |
89 | 83 |
90 virtual void OnRequestAuthError(); | 84 // CloudPrintConnector::Client implementation. |
91 | 85 virtual void OnPrintersAvailable(const printing::PrinterList& printers); |
92 // cloud_print::PrintServerWatcherDelegate implementation | 86 virtual void OnAuthFailed(); |
93 virtual void OnPrinterAdded(); | |
94 // PrinterJobHandler::Delegate implementation | |
95 virtual void OnPrinterJobHandlerShutdown(PrinterJobHandler* job_handler, | |
96 const std::string& printer_id); | |
97 virtual void OnAuthError(); | |
98 virtual void OnPrinterNotFound(const std::string& printer_name, | |
99 bool* delete_from_server); | |
100 | 87 |
101 // notifier::TalkMediator::Delegate implementation. | 88 // notifier::TalkMediator::Delegate implementation. |
102 virtual void OnNotificationStateChange( | 89 virtual void OnNotificationStateChange( |
103 bool notifications_enabled); | 90 bool notifications_enabled); |
104 virtual void OnIncomingNotification( | 91 virtual void OnIncomingNotification( |
105 const notifier::Notification& notification); | 92 const notifier::Notification& notification); |
106 virtual void OnOutgoingNotification(); | 93 virtual void OnOutgoingNotification(); |
107 | 94 |
108 // gaia::GaiaOAuthClient::Delegate implementation. | |
109 virtual void OnGetTokensResponse(const std::string& refresh_token, | |
110 const std::string& access_token, | |
111 int expires_in_seconds); | |
112 virtual void OnRefreshTokenResponse(const std::string& access_token, | |
113 int expires_in_seconds); | |
114 virtual void OnOAuthError(); | |
115 virtual void OnNetworkError(int response_code); | |
116 | |
117 private: | 95 private: |
118 // Prototype for a response handler. | |
119 typedef CloudPrintURLFetcher::ResponseAction | |
120 (CloudPrintProxyBackend::Core::*ResponseHandler)( | |
121 const content::URLFetcher* source, | |
122 const GURL& url, | |
123 DictionaryValue* json_data, | |
124 bool succeeded); | |
125 // Begin response handlers | |
126 CloudPrintURLFetcher::ResponseAction HandlePrinterListResponse( | |
127 const content::URLFetcher* source, | |
128 const GURL& url, | |
129 DictionaryValue* json_data, | |
130 bool succeeded); | |
131 | |
132 CloudPrintURLFetcher::ResponseAction HandleRegisterPrinterResponse( | |
133 const content::URLFetcher* source, | |
134 const GURL& url, | |
135 DictionaryValue* json_data, | |
136 bool succeeded); | |
137 | |
138 CloudPrintURLFetcher::ResponseAction HandleRegisterFailedStatusResponse( | |
139 const content::URLFetcher* source, | |
140 const GURL& url, | |
141 DictionaryValue* json_data, | |
142 bool succeeded); | |
143 | |
144 CloudPrintURLFetcher::ResponseAction HandlePrintSystemUnavailableResponse( | |
145 const content::URLFetcher* source, | |
146 const GURL& url, | |
147 DictionaryValue* json_data, | |
148 bool succeeded); | |
149 | |
150 CloudPrintURLFetcher::ResponseAction HandleEnumPrintersFailedResponse( | |
151 const content::URLFetcher* source, | |
152 const GURL& url, | |
153 DictionaryValue* json_data, | |
154 bool succeeded); | |
155 | |
156 CloudPrintURLFetcher::ResponseAction HandleGetAuthCodeResponse( | |
157 const content::URLFetcher* source, | |
158 const GURL& url, | |
159 DictionaryValue* json_data, | |
160 bool succeeded); | |
161 | |
162 // End response handlers | |
163 | |
164 // NotifyXXX is how the Core communicates with the frontend across | 96 // NotifyXXX is how the Core communicates with the frontend across |
165 // threads. | 97 // threads. |
166 void NotifyPrinterListAvailable( | 98 void NotifyPrinterListAvailable( |
167 const printing::PrinterList& printer_list); | 99 const printing::PrinterList& printer_list); |
168 void NotifyAuthenticated( | 100 void NotifyAuthenticated( |
169 const std::string& robot_oauth_refresh_token, | 101 const std::string& robot_oauth_refresh_token, |
170 const std::string& robot_email, | 102 const std::string& robot_email, |
171 const std::string& user_email); | 103 const std::string& user_email); |
172 void NotifyAuthenticationFailed(); | 104 void NotifyAuthenticationFailed(); |
173 void NotifyPrintSystemUnavailable(); | 105 void NotifyPrintSystemUnavailable(); |
174 | 106 |
175 // Once we have robot credentials, this method gets the ball rolling. | 107 // Init XMPP channel |
176 void PostAuthInitialization(); | 108 void InitNotifications(const std::string& robot_email, |
177 // Starts a new printer registration process. | 109 const std::string& access_token); |
178 void StartRegistration(); | |
179 // Ends the printer registration process. | |
180 void EndRegistration(); | |
181 // Registers printer capabilities and defaults for the next printer in the | |
182 // list with the cloud print server. | |
183 void RegisterNextPrinter(); | |
184 // Retrieves the list of registered printers for this user/proxy combination | |
185 // from the cloud print server. | |
186 void GetRegisteredPrinters(); | |
187 // Removes the given printer from the list. Returns false if the printer | |
188 // did not exist in the list. | |
189 bool RemovePrinterFromList(const std::string& printer_name); | |
190 // Initializes a job handler object for the specified printer. The job | |
191 // handler is responsible for checking for pending print jobs for this | |
192 // printer and print them. | |
193 void InitJobHandlerForPrinter(DictionaryValue* printer_data); | |
194 // Reports a diagnostic message to the server. | |
195 void ReportUserMessage(const std::string& message_id, | |
196 const std::string& failure_message, | |
197 ResponseHandler handler); | |
198 // Make a GAIA request to refresh the access token. | |
199 void RefreshAccessToken(); | |
200 | |
201 // Callback method for GetPrinterCapsAndDefaults. | |
202 void OnReceivePrinterCaps( | |
203 bool succeeded, | |
204 const std::string& printer_name, | |
205 const printing::PrinterCapsAndDefaults& caps_and_defaults); | |
206 | 110 |
207 void HandlePrinterNotification(const std::string& printer_id); | 111 void HandlePrinterNotification(const std::string& printer_id); |
208 void PollForJobs(); | 112 void PollForJobs(); |
209 // Schedules a task to poll for jobs. Does nothing if a task is already | 113 // Schedules a task to poll for jobs. Does nothing if a task is already |
210 // scheduled. | 114 // scheduled. |
211 void ScheduleJobPoll(); | 115 void ScheduleJobPoll(); |
212 CloudPrintTokenStore* GetTokenStore(); | 116 CloudPrintTokenStore* GetTokenStore(); |
213 | 117 |
214 // Our parent CloudPrintProxyBackend | 118 // Our parent CloudPrintProxyBackend |
215 CloudPrintProxyBackend* backend_; | 119 CloudPrintProxyBackend* backend_; |
216 | 120 |
| 121 // Cloud Print authenticator. |
| 122 scoped_refptr<CloudPrintAuth> auth_; |
| 123 |
| 124 // Cloud Print connector. |
| 125 scoped_refptr<CloudPrintConnector> connector_; |
| 126 |
| 127 // Server URL. |
217 GURL cloud_print_server_url_; | 128 GURL cloud_print_server_url_; |
218 gaia::OAuthClientInfo oauth_client_info_; | 129 // Proxy Id. |
219 scoped_ptr<DictionaryValue> print_system_settings_; | |
220 // Pointer to current print system. | |
221 scoped_refptr<cloud_print::PrintSystem> print_system_; | |
222 // The list of printers to be registered with the cloud print server. | |
223 // To begin with,this list is initialized with the list of local and network | |
224 // printers available. Then we query the server for the list of printers | |
225 // already registered. We trim this list to remove the printers already | |
226 // registered. We then pass a copy of this list to the frontend to give the | |
227 // user a chance to further trim the list. When the frontend gives us the | |
228 // final list we make a copy into this so that we can start registering. | |
229 printing::PrinterList printer_list_; | |
230 // Indicates whether the printers in printer_list_ is the complete set of | |
231 // printers to be registered for this proxy. | |
232 bool complete_list_available_; | |
233 // The CloudPrintURLFetcher instance for the current request. | |
234 scoped_refptr<CloudPrintURLFetcher> request_; | |
235 // The index of the nex printer to be uploaded. | |
236 size_t next_upload_index_; | |
237 // The unique id for this proxy | |
238 std::string proxy_id_; | 130 std::string proxy_id_; |
239 // The OAuth2 refresh token for the robot. | |
240 std::string refresh_token_; | |
241 // The email address of the user. This is only used during initial | |
242 // authentication with an LSID. This is only used for storing in prefs for | |
243 // display purposes. | |
244 std::string user_email_; | |
245 // The email address of the robot account. | |
246 std::string robot_email_; | |
247 // Cached info about the last printer that we tried to upload. We cache this | |
248 // so we won't have to requery the printer if the upload fails and we need | |
249 // to retry. | |
250 std::string last_uploaded_printer_name_; | |
251 printing::PrinterCapsAndDefaults last_uploaded_printer_info_; | |
252 // A map of printer id to job handler. | |
253 typedef std::map<std::string, scoped_refptr<PrinterJobHandler> > | |
254 JobHandlerMap; | |
255 JobHandlerMap job_handler_map_; | |
256 ResponseHandler next_response_handler_; | |
257 scoped_refptr<cloud_print::PrintSystem::PrintServerWatcher> | |
258 print_server_watcher_; | |
259 bool new_printers_available_; | |
260 bool registration_in_progress_; | |
261 // Notification (xmpp) handler. | 131 // Notification (xmpp) handler. |
262 scoped_ptr<notifier::TalkMediator> talk_mediator_; | 132 scoped_ptr<notifier::TalkMediator> talk_mediator_; |
263 // Indicates whether XMPP notifications are currently enabled. | 133 // Indicates whether XMPP notifications are currently enabled. |
264 bool notifications_enabled_; | 134 bool notifications_enabled_; |
265 // The time when notifications were enabled. Valid only when | 135 // The time when notifications were enabled. Valid only when |
266 // notifications_enabled_ is true. | 136 // notifications_enabled_ is true. |
267 base::TimeTicks notifications_enabled_since_; | 137 base::TimeTicks notifications_enabled_since_; |
268 // Indicates whether a task to poll for jobs has been scheduled. | 138 // Indicates whether a task to poll for jobs has been scheduled. |
269 bool job_poll_scheduled_; | 139 bool job_poll_scheduled_; |
270 // Indicates whether we should poll for jobs when we lose XMPP connection. | 140 // Indicates whether we should poll for jobs when we lose XMPP connection. |
271 bool enable_job_poll_; | 141 bool enable_job_poll_; |
272 scoped_ptr<gaia::GaiaOAuthClient> oauth_client_; | |
273 scoped_ptr<CloudPrintTokenStore> token_store_; | 142 scoped_ptr<CloudPrintTokenStore> token_store_; |
274 | 143 |
275 DISALLOW_COPY_AND_ASSIGN(Core); | 144 DISALLOW_COPY_AND_ASSIGN(Core); |
276 }; | 145 }; |
277 | 146 |
278 CloudPrintProxyBackend::CloudPrintProxyBackend( | 147 CloudPrintProxyBackend::CloudPrintProxyBackend( |
279 CloudPrintProxyFrontend* frontend, | 148 CloudPrintProxyFrontend* frontend, |
| 149 const std::string& proxy_id, |
280 const GURL& cloud_print_server_url, | 150 const GURL& cloud_print_server_url, |
281 const DictionaryValue* print_system_settings, | 151 const DictionaryValue* print_system_settings, |
282 const gaia::OAuthClientInfo& oauth_client_info, | 152 const gaia::OAuthClientInfo& oauth_client_info, |
283 bool enable_job_poll) | 153 bool enable_job_poll) |
284 : core_thread_("Chrome_CloudPrintProxyCoreThread"), | 154 : core_thread_("Chrome_CloudPrintProxyCoreThread"), |
285 frontend_loop_(MessageLoop::current()), | 155 frontend_loop_(MessageLoop::current()), |
286 frontend_(frontend) { | 156 frontend_(frontend) { |
287 DCHECK(frontend_); | 157 DCHECK(frontend_); |
288 core_ = new Core(this, | 158 core_ = new Core(this, |
| 159 proxy_id, |
289 cloud_print_server_url, | 160 cloud_print_server_url, |
290 print_system_settings, | 161 print_system_settings, |
291 oauth_client_info, | 162 oauth_client_info, |
292 enable_job_poll); | 163 enable_job_poll); |
293 } | 164 } |
294 | 165 |
295 CloudPrintProxyBackend::~CloudPrintProxyBackend() { | 166 CloudPrintProxyBackend::~CloudPrintProxyBackend() { |
296 DCHECK(!core_); | 167 DCHECK(!core_); |
297 } | 168 } |
298 | 169 |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
372 const printing::PrinterList& printer_list) { | 243 const printing::PrinterList& printer_list) { |
373 core_thread_.message_loop()->PostTask(FROM_HERE, | 244 core_thread_.message_loop()->PostTask(FROM_HERE, |
374 NewRunnableMethod( | 245 NewRunnableMethod( |
375 core_.get(), | 246 core_.get(), |
376 &CloudPrintProxyBackend::Core::DoRegisterSelectedPrinters, | 247 &CloudPrintProxyBackend::Core::DoRegisterSelectedPrinters, |
377 printer_list)); | 248 printer_list)); |
378 } | 249 } |
379 | 250 |
380 CloudPrintProxyBackend::Core::Core( | 251 CloudPrintProxyBackend::Core::Core( |
381 CloudPrintProxyBackend* backend, | 252 CloudPrintProxyBackend* backend, |
| 253 const std::string& proxy_id, |
382 const GURL& cloud_print_server_url, | 254 const GURL& cloud_print_server_url, |
383 const DictionaryValue* print_system_settings, | 255 const DictionaryValue* print_system_settings, |
384 const gaia::OAuthClientInfo& oauth_client_info, | 256 const gaia::OAuthClientInfo& oauth_client_info, |
385 bool enable_job_poll) | 257 bool enable_job_poll) |
386 : backend_(backend), | 258 : backend_(backend), |
387 cloud_print_server_url_(cloud_print_server_url), | 259 cloud_print_server_url_(cloud_print_server_url), |
388 oauth_client_info_(oauth_client_info), | 260 proxy_id_(proxy_id), |
389 complete_list_available_(false), | |
390 next_upload_index_(0), | |
391 next_response_handler_(NULL), | |
392 new_printers_available_(false), | |
393 registration_in_progress_(false), | |
394 notifications_enabled_(false), | |
395 job_poll_scheduled_(false), | 261 job_poll_scheduled_(false), |
396 enable_job_poll_(enable_job_poll) { | 262 enable_job_poll_(enable_job_poll) { |
397 if (print_system_settings) { | 263 auth_ = new CloudPrintAuth(this, |
398 // It is possible to have no print settings specified. | 264 cloud_print_server_url, |
399 print_system_settings_.reset(print_system_settings->DeepCopy()); | 265 print_system_settings, |
400 } | 266 oauth_client_info, |
| 267 proxy_id); |
| 268 connector_ = new CloudPrintConnector(this, |
| 269 proxy_id, |
| 270 cloud_print_server_url, |
| 271 print_system_settings); |
401 } | 272 } |
402 | 273 |
403 void CloudPrintProxyBackend::Core::DoInitializeWithLsid( | 274 void CloudPrintProxyBackend::Core::DoInitializeWithLsid( |
404 const std::string& lsid, | 275 const std::string& lsid, |
405 const std::string& proxy_id, | 276 const std::string& proxy_id, |
406 const std::string& last_robot_refresh_token, | 277 const std::string& last_robot_refresh_token, |
407 const std::string& last_robot_email, | 278 const std::string& last_robot_email, |
408 const std::string& last_user_email) { | 279 const std::string& last_user_email) { |
409 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | 280 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); |
410 // Note: The GAIA login is synchronous but that should be OK because we are in | 281 // Note: The GAIA login is synchronous but that should be OK because we are in |
411 // the CloudPrintProxyCoreThread and we cannot really do anything else until | 282 // the CloudPrintProxyCoreThread and we cannot really do anything else until |
412 // the GAIA signin is successful. | 283 // the GAIA signin is successful. |
413 std::string user_agent = "ChromiumBrowser"; | 284 auth_->AuthenticateWithLsid(lsid, last_robot_refresh_token, |
414 scoped_refptr<ServiceGaiaAuthenticator> gaia_auth_for_print( | 285 last_robot_email, last_user_email); |
415 new ServiceGaiaAuthenticator( | |
416 user_agent, kCloudPrintGaiaServiceId, | |
417 GaiaUrls::GetInstance()->client_login_url(), | |
418 g_service_process->io_thread()->message_loop_proxy())); | |
419 gaia_auth_for_print->set_message_loop(MessageLoop::current()); | |
420 if (gaia_auth_for_print->AuthenticateWithLsid(lsid)) { | |
421 // Stash away the user email so we can save it in prefs. | |
422 user_email_ = gaia_auth_for_print->email(); | |
423 // If the same user is re-enabling Cloud Print and we have stashed robot | |
424 // credentials, we will use those. | |
425 if ((0 == base::strcasecmp(user_email_.c_str(), last_user_email.c_str())) && | |
426 !last_robot_refresh_token.empty() && | |
427 !last_robot_email.empty()) { | |
428 DoInitializeWithRobotToken(last_robot_refresh_token, | |
429 last_robot_email, | |
430 proxy_id); | |
431 } | |
432 DoInitializeWithToken(gaia_auth_for_print->auth_token(), | |
433 proxy_id); | |
434 } else { | |
435 // Let the frontend know the of authentication failure. | |
436 OnAuthError(); | |
437 } | |
438 } | 286 } |
439 | 287 |
440 void CloudPrintProxyBackend::Core::DoInitializeWithToken( | 288 void CloudPrintProxyBackend::Core::DoInitializeWithToken( |
441 const std::string cloud_print_token, | 289 const std::string cloud_print_token, |
442 const std::string& proxy_id) { | 290 const std::string& proxy_id) { |
443 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | 291 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); |
444 VLOG(1) << "CP_PROXY: Starting proxy, id: " << proxy_id; | 292 auth_->AuthenticateWithToken(cloud_print_token); |
445 proxy_id_ = proxy_id; | |
446 GetTokenStore()->SetToken(cloud_print_token, false); | |
447 | |
448 // We need to get the credentials of the robot here. | |
449 GURL get_authcode_url = | |
450 CloudPrintHelpers::GetUrlForGetAuthCode(cloud_print_server_url_, | |
451 oauth_client_info_.client_id, | |
452 proxy_id_); | |
453 next_response_handler_ = | |
454 &CloudPrintProxyBackend::Core::HandleGetAuthCodeResponse; | |
455 request_ = new CloudPrintURLFetcher; | |
456 request_->StartGetRequest(get_authcode_url, | |
457 this, | |
458 kCloudPrintAPIMaxRetryCount, | |
459 std::string()); | |
460 } | 293 } |
461 | 294 |
462 void CloudPrintProxyBackend::Core::DoInitializeWithRobotToken( | 295 void CloudPrintProxyBackend::Core::DoInitializeWithRobotToken( |
463 const std::string& robot_oauth_refresh_token, | 296 const std::string& robot_oauth_refresh_token, |
464 const std::string& robot_email, | 297 const std::string& robot_email, |
465 const std::string& proxy_id) { | 298 const std::string& proxy_id) { |
466 robot_email_ = robot_email; | 299 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); |
467 proxy_id_ = proxy_id; | 300 auth_->AuthenticateWithRobotToken(robot_oauth_refresh_token, robot_email); |
468 refresh_token_ = robot_oauth_refresh_token; | |
469 RefreshAccessToken(); | |
470 } | 301 } |
471 | 302 |
472 void CloudPrintProxyBackend::Core::DoInitializeWithRobotAuthCode( | 303 void CloudPrintProxyBackend::Core::DoInitializeWithRobotAuthCode( |
473 const std::string& robot_oauth_auth_code, | 304 const std::string& robot_oauth_auth_code, |
474 const std::string& robot_email, | 305 const std::string& robot_email, |
475 const std::string& proxy_id) { | 306 const std::string& proxy_id) { |
476 robot_email_ = robot_email; | 307 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); |
477 proxy_id_ = proxy_id; | 308 auth_->AuthenticateWithRobotAuthCode(robot_oauth_auth_code, robot_email); |
478 // Now that we have an auth code we need to get the refresh and access tokens. | |
479 oauth_client_.reset(new gaia::GaiaOAuthClient( | |
480 gaia::kGaiaOAuth2Url, | |
481 g_service_process->GetServiceURLRequestContextGetter())); | |
482 oauth_client_->GetTokensFromAuthCode(oauth_client_info_, | |
483 robot_oauth_auth_code, | |
484 kCloudPrintAPIMaxRetryCount, | |
485 this); | |
486 } | 309 } |
487 | 310 |
488 void CloudPrintProxyBackend::Core::PostAuthInitialization() { | 311 void CloudPrintProxyBackend::Core::OnAuthenticationComplete( |
489 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | 312 const std::string& access_token, |
490 // Now we can get down to registering printers. | 313 const std::string& robot_oauth_refresh_token, |
491 print_system_ = | 314 const std::string& robot_email, |
492 cloud_print::PrintSystem::CreateInstance(print_system_settings_.get()); | 315 const std::string& user_email) { |
493 if (!print_system_.get()) { | 316 CloudPrintTokenStore* token_store = GetTokenStore(); |
494 NOTREACHED(); | 317 bool first_time = token_store->token().empty(); |
495 return; // No print system available, fail initalization. | 318 token_store->SetToken(access_token); |
| 319 // Let the frontend know that we have authenticated. |
| 320 backend_->frontend_loop_->PostTask( |
| 321 FROM_HERE, NewRunnableMethod(this, |
| 322 &Core::NotifyAuthenticated, |
| 323 robot_oauth_refresh_token, |
| 324 robot_email, |
| 325 user_email)); |
| 326 if (first_time) { |
| 327 InitNotifications(robot_email, access_token); |
| 328 } else { |
| 329 // If we are refreshing a token, update the XMPP token too. |
| 330 DCHECK(talk_mediator_.get()); |
| 331 talk_mediator_->SetAuthToken(robot_email, |
| 332 access_token, |
| 333 kSyncGaiaServiceId); |
496 } | 334 } |
497 cloud_print::PrintSystem::PrintSystemResult result = print_system_->Init(); | 335 // Start cloud print connector if needed. |
498 | 336 if (!connector_->IsRunning()) { |
499 if (result.succeeded()) { | 337 if (!connector_->Start()) { |
500 notifier::NotifierOptions notifier_options; | 338 // Let the frontend know that we do not have a print system. |
501 notifier_options.request_context_getter = | 339 backend_->frontend_loop_->PostTask( |
502 g_service_process->GetServiceURLRequestContextGetter(); | 340 FROM_HERE, |
503 notifier_options.auth_mechanism = "X-OAUTH2"; | 341 NewRunnableMethod(this, |
504 talk_mediator_.reset(new notifier::TalkMediatorImpl( | 342 &Core::NotifyPrintSystemUnavailable)); |
505 new notifier::MediatorThreadImpl(notifier_options), | 343 } |
506 notifier_options)); | |
507 notifier::Subscription subscription; | |
508 subscription.channel = kCloudPrintPushNotificationsSource; | |
509 subscription.from = kCloudPrintPushNotificationsSource; | |
510 talk_mediator_->AddSubscription(subscription); | |
511 talk_mediator_->SetDelegate(this); | |
512 talk_mediator_->SetAuthToken( | |
513 robot_email_, | |
514 CloudPrintTokenStore::current()->token(), | |
515 kSyncGaiaServiceId); | |
516 talk_mediator_->Login(); | |
517 | |
518 print_server_watcher_ = print_system_->CreatePrintServerWatcher(); | |
519 print_server_watcher_->StartWatching(this); | |
520 | |
521 StartRegistration(); | |
522 } else { | |
523 // We could not initialize the print system. We need to notify the server. | |
524 ReportUserMessage( | |
525 kPrintSystemFailedMessageId, | |
526 result.message(), | |
527 &CloudPrintProxyBackend::Core::HandlePrintSystemUnavailableResponse); | |
528 } | 344 } |
529 } | 345 } |
530 | 346 |
531 void CloudPrintProxyBackend::Core::StartRegistration() { | 347 void CloudPrintProxyBackend::Core::OnInvalidCredentials() { |
532 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | 348 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); |
533 printer_list_.clear(); | 349 VLOG(1) << "CP_CONNECTOR: Auth Error"; |
534 cloud_print::PrintSystem::PrintSystemResult result = | 350 backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, |
535 print_system_->EnumeratePrinters(&printer_list_); | 351 &Core::NotifyAuthenticationFailed)); |
536 complete_list_available_ = result.succeeded(); | |
537 registration_in_progress_ = true; | |
538 if (!result.succeeded()) { | |
539 std::string message = result.message(); | |
540 if (message.empty()) | |
541 message = l10n_util::GetStringUTF8(IDS_CLOUD_PRINT_ENUM_FAILED); | |
542 // There was a failure enumerating printers. Send a message to the server. | |
543 ReportUserMessage( | |
544 kEnumPrintersFailedMessageId, | |
545 message, | |
546 &CloudPrintProxyBackend::Core::HandleEnumPrintersFailedResponse); | |
547 } else { | |
548 // Now we need to ask the server about printers that were registered on the | |
549 // server so that we can trim this list. | |
550 GetRegisteredPrinters(); | |
551 } | |
552 } | 352 } |
553 | 353 |
554 void CloudPrintProxyBackend::Core::EndRegistration() { | 354 void CloudPrintProxyBackend::Core::OnPrintersAvailable( |
| 355 const printing::PrinterList& printers) { |
| 356 // Let the frontend know that we have a list of printers available. |
| 357 backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 358 &Core::NotifyPrinterListAvailable, printers)); |
| 359 } |
| 360 |
| 361 void CloudPrintProxyBackend::Core::OnAuthFailed() { |
| 362 VLOG(1) << "CP_CONNECTOR: Authentication failed in connector."; |
| 363 // Let's stop connecter and refresh token. We'll restart connecter once |
| 364 // new token available. |
| 365 if (connector_->IsRunning()) |
| 366 connector_->Stop(); |
| 367 |
| 368 // Refresh Auth token. |
| 369 auth_->RefreshAccessToken(); |
| 370 } |
| 371 |
| 372 void CloudPrintProxyBackend::Core::InitNotifications( |
| 373 const std::string& robot_email, |
| 374 const std::string& access_token) { |
555 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | 375 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); |
556 request_ = NULL; | 376 |
557 registration_in_progress_ = false; | 377 notifier::NotifierOptions notifier_options; |
558 if (new_printers_available_) { | 378 notifier_options.request_context_getter = |
559 new_printers_available_ = false; | 379 g_service_process->GetServiceURLRequestContextGetter(); |
560 StartRegistration(); | 380 notifier_options.auth_mechanism = "X-OAUTH2"; |
561 } | 381 talk_mediator_.reset(new notifier::TalkMediatorImpl( |
| 382 new notifier::MediatorThreadImpl(notifier_options), |
| 383 notifier_options)); |
| 384 notifier::Subscription subscription; |
| 385 subscription.channel = kCloudPrintPushNotificationsSource; |
| 386 subscription.from = kCloudPrintPushNotificationsSource; |
| 387 talk_mediator_->AddSubscription(subscription); |
| 388 talk_mediator_->SetDelegate(this); |
| 389 talk_mediator_->SetAuthToken(robot_email, access_token, kSyncGaiaServiceId); |
| 390 talk_mediator_->Login(); |
562 } | 391 } |
563 | 392 |
564 void CloudPrintProxyBackend::Core::DoShutdown() { | 393 void CloudPrintProxyBackend::Core::DoShutdown() { |
565 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | 394 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); |
566 VLOG(1) << "CP_PROXY: Shutdown proxy, id: " << proxy_id_; | 395 VLOG(1) << "CP_CONNECTOR: Shutdown connector, id: " << proxy_id_; |
567 if (print_server_watcher_ != NULL) | |
568 print_server_watcher_->StopWatching(); | |
569 | 396 |
570 // Need to kill all running jobs. | 397 if (connector_->IsRunning()) |
571 while (!job_handler_map_.empty()) { | 398 connector_->Stop(); |
572 JobHandlerMap::iterator index = job_handler_map_.begin(); | 399 |
573 // Shutdown will call our OnPrinterJobHandlerShutdown method which will | |
574 // remove this from the map. | |
575 index->second->Shutdown(); | |
576 } | |
577 // Important to delete the TalkMediator on this thread. | 400 // Important to delete the TalkMediator on this thread. |
578 if (talk_mediator_.get()) | 401 if (talk_mediator_.get()) |
579 talk_mediator_->Logout(); | 402 talk_mediator_->Logout(); |
580 talk_mediator_.reset(); | 403 talk_mediator_.reset(); |
581 notifications_enabled_ = false; | 404 notifications_enabled_ = false; |
582 notifications_enabled_since_ = base::TimeTicks(); | 405 notifications_enabled_since_ = base::TimeTicks(); |
583 request_ = NULL; | |
584 token_store_.reset(); | 406 token_store_.reset(); |
585 } | 407 } |
586 | 408 |
587 void CloudPrintProxyBackend::Core::DoRegisterSelectedPrinters( | 409 void CloudPrintProxyBackend::Core::DoRegisterSelectedPrinters( |
588 const printing::PrinterList& printer_list) { | 410 const printing::PrinterList& printer_list) { |
589 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | 411 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); |
590 if (!print_system_.get()) | 412 connector_->RegisterPrinters(printer_list); |
591 return; // No print system available. | |
592 printer_list_.assign(printer_list.begin(), printer_list.end()); | |
593 next_upload_index_ = 0; | |
594 RegisterNextPrinter(); | |
595 } | |
596 | |
597 void CloudPrintProxyBackend::Core::GetRegisteredPrinters() { | |
598 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | |
599 GURL printer_list_url = | |
600 CloudPrintHelpers::GetUrlForPrinterList(cloud_print_server_url_, | |
601 proxy_id_); | |
602 next_response_handler_ = | |
603 &CloudPrintProxyBackend::Core::HandlePrinterListResponse; | |
604 request_ = new CloudPrintURLFetcher; | |
605 request_->StartGetRequest(printer_list_url, | |
606 this, | |
607 kCloudPrintAPIMaxRetryCount, | |
608 std::string()); | |
609 } | |
610 | |
611 void CloudPrintProxyBackend::Core::RegisterNextPrinter() { | |
612 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | |
613 // For the next printer to be uploaded, create a multi-part post request to | |
614 // upload the printer capabilities and the printer defaults. | |
615 if (next_upload_index_ < printer_list_.size()) { | |
616 const printing::PrinterBasicInfo& info = | |
617 printer_list_.at(next_upload_index_); | |
618 // If we are retrying a previous upload, we don't need to fetch the caps | |
619 // and defaults again. | |
620 if (info.printer_name != last_uploaded_printer_name_) { | |
621 cloud_print::PrintSystem::PrinterCapsAndDefaultsCallback* callback = | |
622 NewCallback(this, | |
623 &CloudPrintProxyBackend::Core::OnReceivePrinterCaps); | |
624 // Asnchronously fetch the printer caps and defaults. The story will | |
625 // continue in OnReceivePrinterCaps. | |
626 print_system_->GetPrinterCapsAndDefaults( | |
627 info.printer_name.c_str(), callback); | |
628 } else { | |
629 OnReceivePrinterCaps(true, | |
630 last_uploaded_printer_name_, | |
631 last_uploaded_printer_info_); | |
632 } | |
633 } else { | |
634 EndRegistration(); | |
635 } | |
636 } | |
637 | |
638 void CloudPrintProxyBackend::Core::OnReceivePrinterCaps( | |
639 bool succeeded, | |
640 const std::string& printer_name, | |
641 const printing::PrinterCapsAndDefaults& caps_and_defaults) { | |
642 DCHECK(next_upload_index_ < printer_list_.size()); | |
643 if (succeeded) { | |
644 const printing::PrinterBasicInfo& info = | |
645 printer_list_.at(next_upload_index_); | |
646 | |
647 last_uploaded_printer_name_ = info.printer_name; | |
648 last_uploaded_printer_info_ = caps_and_defaults; | |
649 | |
650 std::string mime_boundary; | |
651 CloudPrintHelpers::CreateMimeBoundaryForUpload(&mime_boundary); | |
652 std::string post_data; | |
653 | |
654 CloudPrintHelpers::AddMultipartValueForUpload(kProxyIdValue, proxy_id_, | |
655 mime_boundary, | |
656 std::string(), &post_data); | |
657 CloudPrintHelpers::AddMultipartValueForUpload(kPrinterNameValue, | |
658 info.printer_name, | |
659 mime_boundary, | |
660 std::string(), &post_data); | |
661 CloudPrintHelpers::AddMultipartValueForUpload(kPrinterDescValue, | |
662 info.printer_description, | |
663 mime_boundary, | |
664 std::string() , &post_data); | |
665 CloudPrintHelpers::AddMultipartValueForUpload( | |
666 kPrinterStatusValue, base::StringPrintf("%d", info.printer_status), | |
667 mime_boundary, std::string(), &post_data); | |
668 // Add printer options as tags. | |
669 CloudPrintHelpers::GenerateMultipartPostDataForPrinterTags(info.options, | |
670 mime_boundary, | |
671 &post_data); | |
672 | |
673 CloudPrintHelpers::AddMultipartValueForUpload( | |
674 kPrinterCapsValue, last_uploaded_printer_info_.printer_capabilities, | |
675 mime_boundary, last_uploaded_printer_info_.caps_mime_type, | |
676 &post_data); | |
677 CloudPrintHelpers::AddMultipartValueForUpload( | |
678 kPrinterDefaultsValue, last_uploaded_printer_info_.printer_defaults, | |
679 mime_boundary, last_uploaded_printer_info_.defaults_mime_type, | |
680 &post_data); | |
681 // Send a hash of the printer capabilities to the server. We will use this | |
682 // later to check if the capabilities have changed | |
683 CloudPrintHelpers::AddMultipartValueForUpload( | |
684 kPrinterCapsHashValue, | |
685 base::MD5String(last_uploaded_printer_info_.printer_capabilities), | |
686 mime_boundary, std::string(), &post_data); | |
687 GURL post_url = CloudPrintHelpers::GetUrlForPrinterRegistration( | |
688 cloud_print_server_url_); | |
689 | |
690 next_response_handler_ = | |
691 &CloudPrintProxyBackend::Core::HandleRegisterPrinterResponse; | |
692 // Terminate the request body | |
693 post_data.append("--" + mime_boundary + "--\r\n"); | |
694 std::string mime_type("multipart/form-data; boundary="); | |
695 mime_type += mime_boundary; | |
696 request_ = new CloudPrintURLFetcher; | |
697 request_->StartPostRequest(post_url, | |
698 this, | |
699 kCloudPrintAPIMaxRetryCount, | |
700 mime_type, | |
701 post_data, | |
702 std::string()); | |
703 } else { | |
704 LOG(ERROR) << "CP_PROXY: Failed to get printer info for: " << | |
705 printer_name; | |
706 // This printer failed to register, notify the server of this failure. | |
707 string16 printer_name_utf16 = UTF8ToUTF16(printer_name); | |
708 std::string status_message = l10n_util::GetStringFUTF8( | |
709 IDS_CLOUD_PRINT_REGISTER_PRINTER_FAILED, | |
710 printer_name_utf16); | |
711 ReportUserMessage( | |
712 kGetPrinterCapsFailedMessageId, | |
713 status_message, | |
714 &CloudPrintProxyBackend::Core::HandleRegisterFailedStatusResponse); | |
715 } | |
716 } | 413 } |
717 | 414 |
718 void CloudPrintProxyBackend::Core::HandlePrinterNotification( | 415 void CloudPrintProxyBackend::Core::HandlePrinterNotification( |
719 const std::string& printer_id) { | 416 const std::string& printer_id) { |
720 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | 417 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); |
721 VLOG(1) << "CP_PROXY: Handle printer notification, id: " << printer_id; | 418 VLOG(1) << "CP_CONNECTOR: Handle printer notification, id: " << printer_id; |
722 JobHandlerMap::iterator index = job_handler_map_.find(printer_id); | 419 connector_->CheckForJobs(kJobFetchReasonNotified, printer_id); |
723 if (index != job_handler_map_.end()) | |
724 index->second->CheckForJobs(kJobFetchReasonNotified); | |
725 } | 420 } |
726 | 421 |
727 void CloudPrintProxyBackend::Core::PollForJobs() { | 422 void CloudPrintProxyBackend::Core::PollForJobs() { |
728 VLOG(1) << "CP_PROXY: Polling for jobs."; | 423 VLOG(1) << "CP_CONNECTOR: Polling for jobs."; |
729 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | 424 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); |
730 for (JobHandlerMap::iterator index = job_handler_map_.begin(); | 425 // Check all printers for jobs. |
731 index != job_handler_map_.end(); index++) { | 426 connector_->CheckForJobs(kJobFetchReasonPoll, std::string()); |
732 // If notifications are on, then we should poll for this printer only if | 427 |
733 // the last time it fetched jobs was before notifications were last enabled. | |
734 bool should_poll = | |
735 !notifications_enabled_ || | |
736 (index->second->last_job_fetch_time() <= notifications_enabled_since_); | |
737 if (should_poll) | |
738 index->second->CheckForJobs(kJobFetchReasonPoll); | |
739 } | |
740 job_poll_scheduled_ = false; | 428 job_poll_scheduled_ = false; |
741 // If we don't have notifications and job polling is enabled, poll again | 429 // If we don't have notifications and job polling is enabled, poll again |
742 // after a while. | 430 // after a while. |
743 if (!notifications_enabled_ && enable_job_poll_) | 431 if (!notifications_enabled_ && enable_job_poll_) |
744 ScheduleJobPoll(); | 432 ScheduleJobPoll(); |
745 } | 433 } |
746 | 434 |
747 void CloudPrintProxyBackend::Core::ScheduleJobPoll() { | 435 void CloudPrintProxyBackend::Core::ScheduleJobPoll() { |
748 if (!job_poll_scheduled_) { | 436 if (!job_poll_scheduled_) { |
749 int interval_in_seconds = base::RandInt(kMinJobPollIntervalSecs, | 437 int interval_in_seconds = base::RandInt(kMinJobPollIntervalSecs, |
750 kMaxJobPollIntervalSecs); | 438 kMaxJobPollIntervalSecs); |
751 MessageLoop::current()->PostDelayedTask( | 439 MessageLoop::current()->PostDelayedTask( |
752 FROM_HERE, | 440 FROM_HERE, |
753 NewRunnableMethod(this, &CloudPrintProxyBackend::Core::PollForJobs), | 441 NewRunnableMethod(this, &CloudPrintProxyBackend::Core::PollForJobs), |
754 interval_in_seconds * 1000); | 442 interval_in_seconds * 1000); |
755 job_poll_scheduled_ = true; | 443 job_poll_scheduled_ = true; |
756 } | 444 } |
757 } | 445 } |
758 | 446 |
759 CloudPrintTokenStore* CloudPrintProxyBackend::Core::GetTokenStore() { | 447 CloudPrintTokenStore* CloudPrintProxyBackend::Core::GetTokenStore() { |
760 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | 448 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); |
761 if (!token_store_.get()) | 449 if (!token_store_.get()) |
762 token_store_.reset(new CloudPrintTokenStore); | 450 token_store_.reset(new CloudPrintTokenStore); |
763 return token_store_.get(); | 451 return token_store_.get(); |
764 } | 452 } |
765 | 453 |
766 // CloudPrintURLFetcher::Delegate implementation. | |
767 CloudPrintURLFetcher::ResponseAction | |
768 CloudPrintProxyBackend::Core::HandleJSONData( | |
769 const content::URLFetcher* source, | |
770 const GURL& url, | |
771 DictionaryValue* json_data, | |
772 bool succeeded) { | |
773 DCHECK(next_response_handler_); | |
774 return (this->*next_response_handler_)(source, url, json_data, succeeded); | |
775 } | |
776 | |
777 void CloudPrintProxyBackend::Core::OnRequestAuthError() { | |
778 OnAuthError(); | |
779 } | |
780 | |
781 void CloudPrintProxyBackend::Core::NotifyPrinterListAvailable( | 454 void CloudPrintProxyBackend::Core::NotifyPrinterListAvailable( |
782 const printing::PrinterList& printer_list) { | 455 const printing::PrinterList& printer_list) { |
783 DCHECK(MessageLoop::current() == backend_->frontend_loop_); | 456 DCHECK(MessageLoop::current() == backend_->frontend_loop_); |
784 backend_->frontend_->OnPrinterListAvailable(printer_list); | 457 backend_->frontend_->OnPrinterListAvailable(printer_list); |
785 } | 458 } |
786 | 459 |
787 void CloudPrintProxyBackend::Core::NotifyAuthenticated( | 460 void CloudPrintProxyBackend::Core::NotifyAuthenticated( |
788 const std::string& robot_oauth_refresh_token, | 461 const std::string& robot_oauth_refresh_token, |
789 const std::string& robot_email, | 462 const std::string& robot_email, |
790 const std::string& user_email) { | 463 const std::string& user_email) { |
791 DCHECK(MessageLoop::current() == backend_->frontend_loop_); | 464 DCHECK(MessageLoop::current() == backend_->frontend_loop_); |
792 backend_->frontend_->OnAuthenticated(robot_oauth_refresh_token, | 465 backend_->frontend_->OnAuthenticated(robot_oauth_refresh_token, |
793 robot_email, | 466 robot_email, |
794 user_email); | 467 user_email); |
795 } | 468 } |
796 | 469 |
797 void CloudPrintProxyBackend::Core::NotifyAuthenticationFailed() { | 470 void CloudPrintProxyBackend::Core::NotifyAuthenticationFailed() { |
798 DCHECK(MessageLoop::current() == backend_->frontend_loop_); | 471 DCHECK(MessageLoop::current() == backend_->frontend_loop_); |
799 backend_->frontend_->OnAuthenticationFailed(); | 472 backend_->frontend_->OnAuthenticationFailed(); |
800 } | 473 } |
801 | 474 |
802 void CloudPrintProxyBackend::Core::NotifyPrintSystemUnavailable() { | 475 void CloudPrintProxyBackend::Core::NotifyPrintSystemUnavailable() { |
803 DCHECK(MessageLoop::current() == backend_->frontend_loop_); | 476 DCHECK(MessageLoop::current() == backend_->frontend_loop_); |
804 backend_->frontend_->OnPrintSystemUnavailable(); | 477 backend_->frontend_->OnPrintSystemUnavailable(); |
805 } | 478 } |
806 | 479 |
807 CloudPrintURLFetcher::ResponseAction | |
808 CloudPrintProxyBackend::Core::HandleGetAuthCodeResponse( | |
809 const content::URLFetcher* source, | |
810 const GURL& url, | |
811 DictionaryValue* json_data, | |
812 bool succeeded) { | |
813 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | |
814 if (!succeeded) { | |
815 OnAuthError(); | |
816 return CloudPrintURLFetcher::STOP_PROCESSING; | |
817 } | |
818 std::string auth_code; | |
819 if (!json_data->GetString(kOAuthCodeValue, &auth_code)) { | |
820 OnAuthError(); | |
821 return CloudPrintURLFetcher::STOP_PROCESSING; | |
822 } | |
823 json_data->GetString(kXMPPJidValue, &robot_email_); | |
824 // Now that we have an auth code we need to get the refresh and access tokens. | |
825 oauth_client_.reset(new gaia::GaiaOAuthClient( | |
826 gaia::kGaiaOAuth2Url, | |
827 g_service_process->GetServiceURLRequestContextGetter())); | |
828 oauth_client_->GetTokensFromAuthCode(oauth_client_info_, | |
829 auth_code, | |
830 kCloudPrintAPIMaxRetryCount, | |
831 this); | |
832 | |
833 return CloudPrintURLFetcher::STOP_PROCESSING; | |
834 } | |
835 | |
836 CloudPrintURLFetcher::ResponseAction | |
837 CloudPrintProxyBackend::Core::HandlePrinterListResponse( | |
838 const content::URLFetcher* source, | |
839 const GURL& url, | |
840 DictionaryValue* json_data, | |
841 bool succeeded) { | |
842 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | |
843 if (!succeeded) { | |
844 NOTREACHED(); | |
845 return CloudPrintURLFetcher::RETRY_REQUEST; | |
846 } | |
847 ListValue* printer_list = NULL; | |
848 // There may be no "printers" value in the JSON | |
849 if (json_data->GetList(kPrinterListValue, &printer_list) && printer_list) { | |
850 for (size_t index = 0; index < printer_list->GetSize(); index++) { | |
851 DictionaryValue* printer_data = NULL; | |
852 if (printer_list->GetDictionary(index, &printer_data)) { | |
853 std::string printer_name; | |
854 printer_data->GetString(kNameValue, &printer_name); | |
855 RemovePrinterFromList(printer_name); | |
856 InitJobHandlerForPrinter(printer_data); | |
857 } else { | |
858 NOTREACHED(); | |
859 } | |
860 } | |
861 } | |
862 request_ = NULL; | |
863 if (!printer_list_.empty()) { | |
864 // Let the frontend know that we have a list of printers available. | |
865 backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, | |
866 &Core::NotifyPrinterListAvailable, printer_list_)); | |
867 } else { | |
868 // No more work to be done here. | |
869 MessageLoop::current()->PostTask( | |
870 FROM_HERE, NewRunnableMethod(this, &Core::EndRegistration)); | |
871 } | |
872 return CloudPrintURLFetcher::STOP_PROCESSING; | |
873 } | |
874 | |
875 void CloudPrintProxyBackend::Core::InitJobHandlerForPrinter( | |
876 DictionaryValue* printer_data) { | |
877 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | |
878 DCHECK(printer_data); | |
879 PrinterJobHandler::PrinterInfoFromCloud printer_info_cloud; | |
880 printer_data->GetString(kIdValue, &printer_info_cloud.printer_id); | |
881 DCHECK(!printer_info_cloud.printer_id.empty()); | |
882 VLOG(1) << "CP_PROXY: Init job handler for printer id: " | |
883 << printer_info_cloud.printer_id; | |
884 JobHandlerMap::iterator index = job_handler_map_.find( | |
885 printer_info_cloud.printer_id); | |
886 // We might already have a job handler for this printer | |
887 if (index == job_handler_map_.end()) { | |
888 printing::PrinterBasicInfo printer_info; | |
889 printer_data->GetString(kNameValue, &printer_info.printer_name); | |
890 DCHECK(!printer_info.printer_name.empty()); | |
891 printer_data->GetString(kPrinterDescValue, | |
892 &printer_info.printer_description); | |
893 // Printer status is a string value which actually contains an integer. | |
894 std::string printer_status; | |
895 if (printer_data->GetString(kPrinterStatusValue, &printer_status)) { | |
896 base::StringToInt(printer_status, &printer_info.printer_status); | |
897 } | |
898 printer_data->GetString(kPrinterCapsHashValue, | |
899 &printer_info_cloud.caps_hash); | |
900 ListValue* tags_list = NULL; | |
901 if (printer_data->GetList(kTagsValue, &tags_list) && tags_list) { | |
902 for (size_t index = 0; index < tags_list->GetSize(); index++) { | |
903 std::string tag; | |
904 if (tags_list->GetString(index, &tag) && | |
905 StartsWithASCII(tag, kTagsHashTagName, false)) { | |
906 std::vector<std::string> tag_parts; | |
907 base::SplitStringDontTrim(tag, '=', &tag_parts); | |
908 DCHECK_EQ(tag_parts.size(), 2U); | |
909 if (tag_parts.size() == 2) | |
910 printer_info_cloud.tags_hash = tag_parts[1]; | |
911 } | |
912 } | |
913 } | |
914 scoped_refptr<PrinterJobHandler> job_handler; | |
915 job_handler = new PrinterJobHandler(printer_info, | |
916 printer_info_cloud, | |
917 cloud_print_server_url_, | |
918 print_system_.get(), | |
919 this); | |
920 job_handler_map_[printer_info_cloud.printer_id] = job_handler; | |
921 job_handler->Initialize(); | |
922 } | |
923 } | |
924 | |
925 void CloudPrintProxyBackend::Core::ReportUserMessage( | |
926 const std::string& message_id, | |
927 const std::string& failure_message, | |
928 ResponseHandler handler) { | |
929 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | |
930 std::string mime_boundary; | |
931 CloudPrintHelpers::CreateMimeBoundaryForUpload(&mime_boundary); | |
932 GURL post_url = CloudPrintHelpers::GetUrlForUserMessage( | |
933 cloud_print_server_url_, | |
934 message_id); | |
935 std::string post_data; | |
936 CloudPrintHelpers::AddMultipartValueForUpload(kMessageTextValue, | |
937 failure_message, | |
938 mime_boundary, | |
939 std::string(), | |
940 &post_data); | |
941 next_response_handler_ = handler; | |
942 // Terminate the request body | |
943 post_data.append("--" + mime_boundary + "--\r\n"); | |
944 std::string mime_type("multipart/form-data; boundary="); | |
945 mime_type += mime_boundary; | |
946 request_ = new CloudPrintURLFetcher; | |
947 request_->StartPostRequest(post_url, | |
948 this, | |
949 kCloudPrintAPIMaxRetryCount, | |
950 mime_type, | |
951 post_data, | |
952 std::string()); | |
953 } | |
954 | |
955 CloudPrintURLFetcher::ResponseAction | |
956 CloudPrintProxyBackend::Core::HandleRegisterPrinterResponse( | |
957 const content::URLFetcher* source, | |
958 const GURL& url, | |
959 DictionaryValue* json_data, | |
960 bool succeeded) { | |
961 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | |
962 if (succeeded) { | |
963 ListValue* printer_list = NULL; | |
964 // There should be a "printers" value in the JSON | |
965 if (json_data->GetList(kPrinterListValue, &printer_list)) { | |
966 DictionaryValue* printer_data = NULL; | |
967 if (printer_list->GetDictionary(0, &printer_data)) | |
968 InitJobHandlerForPrinter(printer_data); | |
969 } | |
970 } | |
971 next_upload_index_++; | |
972 MessageLoop::current()->PostTask( | |
973 FROM_HERE, | |
974 NewRunnableMethod(this, | |
975 &CloudPrintProxyBackend::Core::RegisterNextPrinter)); | |
976 return CloudPrintURLFetcher::STOP_PROCESSING; | |
977 } | |
978 | |
979 CloudPrintURLFetcher::ResponseAction | |
980 CloudPrintProxyBackend::Core::HandleRegisterFailedStatusResponse( | |
981 const content::URLFetcher* source, | |
982 const GURL& url, | |
983 DictionaryValue* json_data, | |
984 bool succeeded) { | |
985 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | |
986 next_upload_index_++; | |
987 MessageLoop::current()->PostTask( | |
988 FROM_HERE, | |
989 NewRunnableMethod(this, | |
990 &CloudPrintProxyBackend::Core::RegisterNextPrinter)); | |
991 return CloudPrintURLFetcher::STOP_PROCESSING; | |
992 } | |
993 | |
994 CloudPrintURLFetcher::ResponseAction | |
995 CloudPrintProxyBackend::Core::HandlePrintSystemUnavailableResponse( | |
996 const content::URLFetcher* source, | |
997 const GURL& url, | |
998 DictionaryValue* json_data, | |
999 bool succeeded) { | |
1000 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | |
1001 // Let the frontend know that we do not have a print system. | |
1002 backend_->frontend_loop_->PostTask( | |
1003 FROM_HERE, | |
1004 NewRunnableMethod(this, | |
1005 &Core::NotifyPrintSystemUnavailable)); | |
1006 return CloudPrintURLFetcher::STOP_PROCESSING; | |
1007 } | |
1008 | |
1009 CloudPrintURLFetcher::ResponseAction | |
1010 CloudPrintProxyBackend::Core::HandleEnumPrintersFailedResponse( | |
1011 const content::URLFetcher* source, | |
1012 const GURL& url, | |
1013 DictionaryValue* json_data, | |
1014 bool succeeded) { | |
1015 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | |
1016 // Now proceed with printer registration. | |
1017 GetRegisteredPrinters(); | |
1018 return CloudPrintURLFetcher::STOP_PROCESSING; | |
1019 } | |
1020 | |
1021 | |
1022 bool CloudPrintProxyBackend::Core::RemovePrinterFromList( | |
1023 const std::string& printer_name) { | |
1024 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | |
1025 for (printing::PrinterList::iterator index = printer_list_.begin(); | |
1026 index != printer_list_.end(); index++) { | |
1027 if (0 == base::strcasecmp(index->printer_name.c_str(), | |
1028 printer_name.c_str())) { | |
1029 index = printer_list_.erase(index); | |
1030 return true; | |
1031 } | |
1032 } | |
1033 return false; | |
1034 } | |
1035 | |
1036 void CloudPrintProxyBackend::Core::RefreshAccessToken() { | |
1037 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | |
1038 oauth_client_.reset(new gaia::GaiaOAuthClient( | |
1039 gaia::kGaiaOAuth2Url, | |
1040 g_service_process->GetServiceURLRequestContextGetter())); | |
1041 oauth_client_->RefreshToken(oauth_client_info_, | |
1042 refresh_token_, | |
1043 kCloudPrintAPIMaxRetryCount, | |
1044 this); | |
1045 } | |
1046 | |
1047 void CloudPrintProxyBackend::Core::OnNotificationStateChange( | 480 void CloudPrintProxyBackend::Core::OnNotificationStateChange( |
1048 bool notification_enabled) { | 481 bool notification_enabled) { |
1049 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | 482 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); |
1050 notifications_enabled_ = notification_enabled; | 483 notifications_enabled_ = notification_enabled; |
1051 if (notifications_enabled_) { | 484 if (notifications_enabled_) { |
1052 notifications_enabled_since_ = base::TimeTicks::Now(); | 485 notifications_enabled_since_ = base::TimeTicks::Now(); |
1053 VLOG(1) << "Notifications for proxy " << proxy_id_ << " were enabled at " | 486 VLOG(1) << "Notifications for connector " << proxy_id_ |
| 487 << " were enabled at " |
1054 << notifications_enabled_since_.ToInternalValue(); | 488 << notifications_enabled_since_.ToInternalValue(); |
1055 } else { | 489 } else { |
1056 LOG(ERROR) << "Notifications for proxy " << proxy_id_ << " disabled."; | 490 LOG(ERROR) << "Notifications for connector " << proxy_id_ << " disabled."; |
1057 notifications_enabled_since_ = base::TimeTicks(); | 491 notifications_enabled_since_ = base::TimeTicks(); |
1058 } | 492 } |
1059 // A state change means one of two cases. | 493 // A state change means one of two cases. |
1060 // Case 1: We just lost notifications. This this case we want to schedule a | 494 // Case 1: We just lost notifications. This this case we want to schedule a |
1061 // job poll if enable_job_poll_ is true. | 495 // job poll if enable_job_poll_ is true. |
1062 // Case 2: Notifications just got re-enabled. In this case we want to schedule | 496 // Case 2: Notifications just got re-enabled. In this case we want to schedule |
1063 // a poll once for jobs we might have missed when we were dark. | 497 // a poll once for jobs we might have missed when we were dark. |
1064 // Note that ScheduleJobPoll will not schedule again if a job poll task is | 498 // Note that ScheduleJobPoll will not schedule again if a job poll task is |
1065 // already scheduled. | 499 // already scheduled. |
1066 if (enable_job_poll_ || notifications_enabled_) | 500 if (enable_job_poll_ || notifications_enabled_) |
1067 ScheduleJobPoll(); | 501 ScheduleJobPoll(); |
1068 } | 502 } |
1069 | 503 |
1070 | 504 |
1071 void CloudPrintProxyBackend::Core::OnIncomingNotification( | 505 void CloudPrintProxyBackend::Core::OnIncomingNotification( |
1072 const notifier::Notification& notification) { | 506 const notifier::Notification& notification) { |
1073 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | 507 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); |
1074 VLOG(1) << "CP_PROXY: Incoming notification."; | 508 VLOG(1) << "CP_CONNECTOR: Incoming notification."; |
1075 if (0 == base::strcasecmp(kCloudPrintPushNotificationsSource, | 509 if (0 == base::strcasecmp(kCloudPrintPushNotificationsSource, |
1076 notification.channel.c_str())) | 510 notification.channel.c_str())) |
1077 HandlePrinterNotification(notification.data); | 511 HandlePrinterNotification(notification.data); |
1078 } | 512 } |
1079 | 513 |
1080 void CloudPrintProxyBackend::Core::OnOutgoingNotification() {} | 514 void CloudPrintProxyBackend::Core::OnOutgoingNotification() {} |
1081 | |
1082 // cloud_print::PrinterChangeNotifier::Delegate implementation | |
1083 void CloudPrintProxyBackend::Core::OnPrinterAdded() { | |
1084 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | |
1085 if (registration_in_progress_) | |
1086 new_printers_available_ = true; | |
1087 else | |
1088 StartRegistration(); | |
1089 } | |
1090 | |
1091 // PrinterJobHandler::Delegate implementation | |
1092 void CloudPrintProxyBackend::Core::OnPrinterJobHandlerShutdown( | |
1093 PrinterJobHandler* job_handler, const std::string& printer_id) { | |
1094 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | |
1095 VLOG(1) << "CP_PROXY: Printer job handle shutdown, id " << printer_id; | |
1096 job_handler_map_.erase(printer_id); | |
1097 } | |
1098 | |
1099 void CloudPrintProxyBackend::Core::OnAuthError() { | |
1100 DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); | |
1101 VLOG(1) << "CP_PROXY: Auth Error"; | |
1102 backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, | |
1103 &Core::NotifyAuthenticationFailed)); | |
1104 } | |
1105 | |
1106 void CloudPrintProxyBackend::Core::OnPrinterNotFound( | |
1107 const std::string& printer_name, | |
1108 bool* delete_from_server) { | |
1109 // If we have a complete list of local printers, then this needs to be deleted | |
1110 // from the server. | |
1111 *delete_from_server = complete_list_available_; | |
1112 } | |
1113 | |
1114 // gaia::GaiaOAuthClient::Delegate implementation. | |
1115 void CloudPrintProxyBackend::Core::OnGetTokensResponse( | |
1116 const std::string& refresh_token, | |
1117 const std::string& access_token, | |
1118 int expires_in_seconds) { | |
1119 refresh_token_ = refresh_token; | |
1120 // After saving the refresh token, this is just like having just refreshed | |
1121 // the access token. Just call OnRefreshTokenResponse. | |
1122 OnRefreshTokenResponse(access_token, expires_in_seconds); | |
1123 } | |
1124 | |
1125 void CloudPrintProxyBackend::Core::OnRefreshTokenResponse( | |
1126 const std::string& access_token, int expires_in_seconds) { | |
1127 // If our current token is not OAuth, we either have no token at all or we | |
1128 // have a ClientLogin token which we just exchanged for an OAuth token. | |
1129 // In this case we need to do the startup initialiazation. | |
1130 // TODO(sanjeevr): Use an enum for state instead of using this as a signal. | |
1131 // I will do this in a follow-up change. | |
1132 CloudPrintTokenStore* token_store = GetTokenStore(); | |
1133 bool first_time = !token_store->token_is_oauth(); | |
1134 token_store->SetToken(access_token, true); | |
1135 // Let the frontend know that we have authenticated. | |
1136 backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, | |
1137 &Core::NotifyAuthenticated, refresh_token_, robot_email_, user_email_)); | |
1138 if (first_time) { | |
1139 PostAuthInitialization(); | |
1140 } else { | |
1141 // If we are refreshing a token, update the XMPP token too. | |
1142 DCHECK(talk_mediator_.get()); | |
1143 talk_mediator_->SetAuthToken(robot_email_, | |
1144 access_token, | |
1145 kSyncGaiaServiceId); | |
1146 } | |
1147 // Schedule a task to refresh the access token again when it is about to | |
1148 // expire. | |
1149 DCHECK(expires_in_seconds > kTokenRefreshGracePeriodSecs); | |
1150 int64 refresh_delay = | |
1151 (expires_in_seconds - kTokenRefreshGracePeriodSecs)*1000; | |
1152 MessageLoop::current()->PostDelayedTask( | |
1153 FROM_HERE, | |
1154 NewRunnableMethod(this, &Core::RefreshAccessToken), | |
1155 refresh_delay); | |
1156 } | |
1157 | |
1158 void CloudPrintProxyBackend::Core::OnOAuthError() { | |
1159 OnAuthError(); | |
1160 } | |
1161 | |
1162 void CloudPrintProxyBackend::Core::OnNetworkError(int response_code) { | |
1163 // Since we specify inifinite retries on network errors, this should never | |
1164 // be called. | |
1165 NOTREACHED() << | |
1166 "OnNetworkError invoked when not expected, response code is " << | |
1167 response_code; | |
1168 } | |
OLD | NEW |