| Index: chrome/browser/printing/cloud_print/printer_job_handler.cc
|
| ===================================================================
|
| --- chrome/browser/printing/cloud_print/printer_job_handler.cc (revision 0)
|
| +++ chrome/browser/printing/cloud_print/printer_job_handler.cc (revision 0)
|
| @@ -0,0 +1,560 @@
|
| +// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chrome/browser/printing/cloud_print/printer_job_handler.h"
|
| +
|
| +#include "base/file_util.h"
|
| +#include "base/json/json_reader.h"
|
| +#include "base/md5.h"
|
| +#include "base/string_util.h"
|
| +#include "base/utf_string_conversions.h"
|
| +#include "base/values.h"
|
| +#include "chrome/browser/printing/cloud_print/cloud_print_consts.h"
|
| +#include "chrome/browser/printing/cloud_print/cloud_print_helpers.h"
|
| +#include "chrome/browser/printing/cloud_print/job_status_updater.h"
|
| +#include "googleurl/src/gurl.h"
|
| +#include "net/http/http_response_headers.h"
|
| +
|
| +PrinterJobHandler::PrinterJobHandler(
|
| + const cloud_print::PrinterBasicInfo& printer_info,
|
| + const std::string& printer_id,
|
| + const std::string& caps_hash,
|
| + const std::string& auth_token,
|
| + Delegate* delegate)
|
| + : printer_info_(printer_info),
|
| + printer_id_(printer_id),
|
| + auth_token_(auth_token),
|
| + last_caps_hash_(caps_hash),
|
| + delegate_(delegate),
|
| + local_job_id_(-1),
|
| + next_response_handler_(NULL),
|
| + server_error_count_(0),
|
| + print_thread_("Chrome_CloudPrintJobPrintThread"),
|
| + shutting_down_(false),
|
| + server_job_available_(false),
|
| + printer_update_pending_(true),
|
| + printer_delete_pending_(false),
|
| + task_in_progress_(false) {
|
| +}
|
| +
|
| +bool PrinterJobHandler::Initialize() {
|
| + if (cloud_print::IsValidPrinter(printer_info_.printer_name)) {
|
| + printer_change_notifier_.StartWatching(printer_info_.printer_name, this);
|
| + NotifyJobAvailable();
|
| + } else {
|
| + // This printer does not exist any more. Delete it from the server.
|
| + OnPrinterDeleted();
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +PrinterJobHandler::~PrinterJobHandler() {
|
| + printer_change_notifier_.StopWatching();
|
| +}
|
| +
|
| +void PrinterJobHandler::Reset() {
|
| + print_data_url_.clear();
|
| + job_details_.Clear();
|
| + request_.reset();
|
| + print_thread_.Stop();
|
| +}
|
| +
|
| +void PrinterJobHandler::Start() {
|
| + if (task_in_progress_) {
|
| + // Multiple Starts can get posted because of multiple notifications
|
| + // We want to ignore the other ones that happen when a task is in progress.
|
| + return;
|
| + }
|
| + Reset();
|
| + if (!shutting_down_) {
|
| + // Check if we have work to do.
|
| + if (HavePendingTasks()) {
|
| + if (printer_delete_pending_) {
|
| + printer_delete_pending_ = false;
|
| + task_in_progress_ = true;
|
| + MakeServerRequest(
|
| + CloudPrintHelpers::GetUrlForPrinterDelete(printer_id_),
|
| + &PrinterJobHandler::HandlePrinterDeleteResponse);
|
| + }
|
| + if (!task_in_progress_ && printer_update_pending_) {
|
| + printer_update_pending_ = false;
|
| + task_in_progress_ = UpdatePrinterInfo();
|
| + }
|
| + if (!task_in_progress_ && server_job_available_) {
|
| + task_in_progress_ = true;
|
| + server_job_available_ = false;
|
| + // We need to fetch any pending jobs for this printer
|
| + MakeServerRequest(CloudPrintHelpers::GetUrlForJobFetch(printer_id_),
|
| + &PrinterJobHandler::HandleJobMetadataResponse);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +void PrinterJobHandler::Stop() {
|
| + task_in_progress_ = false;
|
| + Reset();
|
| + if (HavePendingTasks()) {
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Start));
|
| + }
|
| +}
|
| +
|
| +void PrinterJobHandler::NotifyJobAvailable() {
|
| + server_job_available_ = true;
|
| + if (!task_in_progress_) {
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Start));
|
| + }
|
| +}
|
| +
|
| +bool PrinterJobHandler::UpdatePrinterInfo() {
|
| + // We need to update the parts of the printer info that have changed
|
| + // (could be printer name, description, status or capabilities).
|
| + cloud_print::PrinterBasicInfo printer_info;
|
| + printer_change_notifier_.GetCurrentPrinterInfo(&printer_info);
|
| + cloud_print::PrinterCapsAndDefaults printer_caps;
|
| + std::string post_data;
|
| + std::string mime_boundary;
|
| + if (cloud_print::GetPrinterCapsAndDefaults(printer_info.printer_name,
|
| + &printer_caps)) {
|
| + std::string caps_hash = MD5String(printer_caps.printer_capabilities);
|
| + CloudPrintHelpers::CreateMimeBoundaryForUpload(&mime_boundary);
|
| + if (caps_hash != last_caps_hash_) {
|
| + // Hashes don't match, we need to upload new capabilities (the defaults
|
| + // go for free along with the capabilities)
|
| + last_caps_hash_ = caps_hash;
|
| + CloudPrintHelpers::AddMultipartValueForUpload(
|
| + kPrinterCapsValue, printer_caps.printer_capabilities,
|
| + mime_boundary, printer_caps.caps_mime_type, &post_data);
|
| + CloudPrintHelpers::AddMultipartValueForUpload(
|
| + kPrinterDefaultsValue, printer_caps.printer_defaults,
|
| + mime_boundary, printer_caps.defaults_mime_type,
|
| + &post_data);
|
| + CloudPrintHelpers::AddMultipartValueForUpload(
|
| + WideToUTF8(kPrinterCapsHashValue).c_str(), caps_hash, mime_boundary,
|
| + std::string(), &post_data);
|
| + }
|
| + }
|
| + if (printer_info.printer_name != printer_info_.printer_name) {
|
| + CloudPrintHelpers::AddMultipartValueForUpload(kPrinterNameValue,
|
| + printer_info.printer_name,
|
| + mime_boundary,
|
| + std::string(), &post_data);
|
| + }
|
| + if (printer_info.printer_description != printer_info_.printer_description) {
|
| + CloudPrintHelpers::AddMultipartValueForUpload(
|
| + kPrinterDescValue, printer_info.printer_description, mime_boundary,
|
| + std::string() , &post_data);
|
| + }
|
| + if (printer_info.printer_status != printer_info_.printer_status) {
|
| + CloudPrintHelpers::AddMultipartValueForUpload(
|
| + kPrinterStatusValue, StringPrintf("%d", printer_info.printer_status),
|
| + mime_boundary, std::string(), &post_data);
|
| + }
|
| + printer_info_ = printer_info;
|
| + bool ret = false;
|
| + if (!post_data.empty()) {
|
| + // Terminate the request body
|
| + post_data.append("--" + mime_boundary + "--\r\n");
|
| + std::string mime_type("multipart/form-data; boundary=");
|
| + mime_type += mime_boundary;
|
| + request_.reset(
|
| + new URLFetcher(CloudPrintHelpers::GetUrlForPrinterUpdate(printer_id_),
|
| + URLFetcher::POST, this));
|
| + CloudPrintHelpers::PrepCloudPrintRequest(request_.get(), auth_token_);
|
| + request_->set_upload_data(mime_type, post_data);
|
| + next_response_handler_ = &PrinterJobHandler::HandlePrinterUpdateResponse;
|
| + request_->Start();
|
| + ret = true;
|
| + }
|
| + return ret;
|
| +}
|
| +
|
| +// URLFetcher::Delegate implementation.
|
| +void PrinterJobHandler::OnURLFetchComplete(
|
| + const URLFetcher* source, const GURL& url, const URLRequestStatus& status,
|
| + int response_code, const ResponseCookies& cookies,
|
| + const std::string& data) {
|
| + if (!shutting_down_) {
|
| + DCHECK(source == request_.get());
|
| + // We need a next response handler because we are strictly a sequential
|
| + // state machine. We need each response handler to tell us which state to
|
| + // advance to next.
|
| + DCHECK(next_response_handler_);
|
| + if (!(this->*next_response_handler_)(source, url, status,
|
| + response_code, cookies, data)) {
|
| + // By contract, if the response handler returns false, it wants us to
|
| + // retry the request (upto the usual limit after which we give up and
|
| + // send the state machine to the Stop state);
|
| + HandleServerError(url);
|
| + }
|
| + }
|
| +}
|
| +
|
| +// JobStatusUpdater::Delegate implementation
|
| +bool PrinterJobHandler::OnJobCompleted(JobStatusUpdater* updater) {
|
| + bool ret = false;
|
| + for (JobStatusUpdaterList::iterator index = job_status_updater_list_.begin();
|
| + index != job_status_updater_list_.end(); index++) {
|
| + if (index->get() == updater) {
|
| + job_status_updater_list_.erase(index);
|
| + ret = true;
|
| + break;
|
| + }
|
| + }
|
| + return ret;
|
| +}
|
| +
|
| + // cloud_print::PrinterChangeNotifier::Delegate implementation
|
| +void PrinterJobHandler::OnPrinterAdded() {
|
| + // Should never get this notification for a printer
|
| + NOTREACHED();
|
| +}
|
| +
|
| +void PrinterJobHandler::OnPrinterDeleted() {
|
| + printer_delete_pending_ = true;
|
| + if (!task_in_progress_) {
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Start));
|
| + }
|
| +}
|
| +
|
| +void PrinterJobHandler::OnPrinterChanged() {
|
| + printer_update_pending_ = true;
|
| + if (!task_in_progress_) {
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Start));
|
| + }
|
| +}
|
| +
|
| +void PrinterJobHandler::OnJobChanged() {
|
| + // Some job on the printer changed. Loop through all our JobStatusUpdaters
|
| + // and have them check for updates.
|
| + for (JobStatusUpdaterList::iterator index = job_status_updater_list_.begin();
|
| + index != job_status_updater_list_.end(); index++) {
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE, NewRunnableMethod(index->get(),
|
| + &JobStatusUpdater::UpdateStatus));
|
| + }
|
| +}
|
| +
|
| +bool PrinterJobHandler::HandlePrinterUpdateResponse(
|
| + const URLFetcher* source, const GURL& url, const URLRequestStatus& status,
|
| + int response_code, const ResponseCookies& cookies,
|
| + const std::string& data) {
|
| + bool ret = false;
|
| + // If there was a network error or a non-200 response (which, for our purposes
|
| + // is the same as a network error), we want to retry.
|
| + if (status.is_success() && (response_code == 200)) {
|
| + bool succeeded = false;
|
| + DictionaryValue* response_dict = NULL;
|
| + CloudPrintHelpers::ParseResponseJSON(data, &succeeded, &response_dict);
|
| + // If we get valid JSON back, we are done.
|
| + if (NULL != response_dict) {
|
| + ret = true;
|
| + }
|
| + }
|
| + if (ret) {
|
| + // We are done here. Go to the Stop state
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Stop));
|
| + } else {
|
| + // Since we failed to update the server, set the flag again.
|
| + printer_update_pending_ = true;
|
| + }
|
| + return ret;
|
| +}
|
| +
|
| +bool PrinterJobHandler::HandlePrinterDeleteResponse(
|
| + const URLFetcher* source, const GURL& url, const URLRequestStatus& status,
|
| + int response_code, const ResponseCookies& cookies,
|
| + const std::string& data) {
|
| + bool ret = false;
|
| + // If there was a network error or a non-200 response (which, for our purposes
|
| + // is the same as a network error), we want to retry.
|
| + if (status.is_success() && (response_code == 200)) {
|
| + bool succeeded = false;
|
| + DictionaryValue* response_dict = NULL;
|
| + CloudPrintHelpers::ParseResponseJSON(data, &succeeded, &response_dict);
|
| + // If we get valid JSON back, we are done.
|
| + if (NULL != response_dict) {
|
| + ret = true;
|
| + }
|
| + }
|
| + if (ret) {
|
| + // The printer has been deleted. Shutdown the handler class.
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Shutdown));
|
| + } else {
|
| + // Since we failed to update the server, set the flag again.
|
| + printer_delete_pending_ = true;
|
| + }
|
| + return ret;
|
| +}
|
| +
|
| +bool PrinterJobHandler::HandleJobMetadataResponse(
|
| + const URLFetcher* source, const GURL& url, const URLRequestStatus& status,
|
| + int response_code, const ResponseCookies& cookies,
|
| + const std::string& data) {
|
| + // If there was a network error or a non-200 response (which, for our purposes
|
| + // is the same as a network error), we want to retry.
|
| + if (!status.is_success() || (response_code != 200)) {
|
| + return false;
|
| + }
|
| + bool succeeded = false;
|
| + DictionaryValue* response_dict = NULL;
|
| + CloudPrintHelpers::ParseResponseJSON(data, &succeeded, &response_dict);
|
| + if (NULL == response_dict) {
|
| + // If we did not get a valid JSON response, we need to retry.
|
| + return false;
|
| + }
|
| + Task* next_task = NULL;
|
| + if (succeeded) {
|
| + ListValue* job_list = NULL;
|
| + response_dict->GetList(kJobListValue, &job_list);
|
| + if (job_list) {
|
| + // Even though it is a job list, for now we are only interested in the
|
| + // first job
|
| + DictionaryValue* job_data = NULL;
|
| + if (job_list->GetDictionary(0, &job_data)) {
|
| + job_data->GetString(kIdValue, &job_details_.job_id_);
|
| + job_data->GetString(kTitleValue, &job_details_.job_title_);
|
| + std::string print_ticket_url;
|
| + job_data->GetString(kTicketUrlValue, &print_ticket_url);
|
| + job_data->GetString(kFileUrlValue, &print_data_url_);
|
| + next_task = NewRunnableMethod(
|
| + this, &PrinterJobHandler::MakeServerRequest,
|
| + GURL(print_ticket_url.c_str()),
|
| + &PrinterJobHandler::HandlePrintTicketResponse);
|
| + }
|
| + }
|
| + }
|
| + if (!next_task) {
|
| + // If we got a valid JSON but there were no jobs, we are done
|
| + next_task = NewRunnableMethod(this, &PrinterJobHandler::Stop);
|
| + }
|
| + delete response_dict;
|
| + DCHECK(next_task);
|
| + MessageLoop::current()->PostTask(FROM_HERE, next_task);
|
| + return true;
|
| +}
|
| +
|
| +bool PrinterJobHandler::HandlePrintTicketResponse(
|
| + const URLFetcher* source, const GURL& url, const URLRequestStatus& status,
|
| + int response_code, const ResponseCookies& cookies,
|
| + const std::string& data) {
|
| + // If there was a network error or a non-200 response (which, for our purposes
|
| + // is the same as a network error), we want to retry.
|
| + if (!status.is_success() || (response_code != 200)) {
|
| + return false;
|
| + }
|
| + if (cloud_print::ValidatePrintTicket(printer_info_.printer_name, data)) {
|
| + job_details_.print_ticket_ = data;
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE,
|
| + NewRunnableMethod(this,
|
| + &PrinterJobHandler::MakeServerRequest,
|
| + GURL(print_data_url_.c_str()),
|
| + &PrinterJobHandler::HandlePrintDataResponse));
|
| + } else {
|
| + // The print ticket was not valid. We are done here.
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::JobFailed,
|
| + INVALID_JOB_DATA));
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool PrinterJobHandler::HandlePrintDataResponse(const URLFetcher* source,
|
| + const GURL& url,
|
| + const URLRequestStatus& status,
|
| + int response_code,
|
| + const ResponseCookies& cookies,
|
| + const std::string& data) {
|
| + // If there was a network error or a non-200 response (which, for our purposes
|
| + // is the same as a network error), we want to retry.
|
| + if (!status.is_success() || (response_code != 200)) {
|
| + return false;
|
| + }
|
| + Task* next_task = NULL;
|
| + if (file_util::CreateTemporaryFile(&job_details_.print_data_file_path_)) {
|
| + int ret = file_util::WriteFile(job_details_.print_data_file_path_,
|
| + data.c_str(),
|
| + data.length());
|
| + source->response_headers()->GetMimeType(
|
| + &job_details_.print_data_mime_type_);
|
| + DCHECK(ret == static_cast<int>(data.length()));
|
| + if (ret == static_cast<int>(data.length())) {
|
| + next_task = NewRunnableMethod(this, &PrinterJobHandler::StartPrinting);
|
| + }
|
| + }
|
| + // If there was no task allocated above, then there was an error in
|
| + // saving the print data, bail out here.
|
| + if (!next_task) {
|
| + next_task = NewRunnableMethod(this, &PrinterJobHandler::JobFailed,
|
| + JOB_DOWNLOAD_FAILED);
|
| + }
|
| + MessageLoop::current()->PostTask(FROM_HERE, next_task);
|
| + return true;
|
| +}
|
| +
|
| +void PrinterJobHandler::StartPrinting() {
|
| + // We are done with the request object for now.
|
| + request_.reset();
|
| + if (!shutting_down_) {
|
| + if (!print_thread_.Start()) {
|
| + JobFailed(PRINT_FAILED);
|
| + } else {
|
| + print_thread_.message_loop()->PostTask(
|
| + FROM_HERE, NewRunnableFunction(&PrinterJobHandler::DoPrint,
|
| + job_details_,
|
| + printer_info_.printer_name, this,
|
| + MessageLoop::current()));
|
| + }
|
| + }
|
| +}
|
| +
|
| +void PrinterJobHandler::JobFailed(PrintJobError error) {
|
| + if (!shutting_down_) {
|
| + UpdateJobStatus(cloud_print::PRINT_JOB_STATUS_ERROR, error);
|
| + }
|
| +}
|
| +
|
| +void PrinterJobHandler::JobSpooled(cloud_print::PlatformJobId local_job_id) {
|
| + if (!shutting_down_) {
|
| + local_job_id_ = local_job_id;
|
| + UpdateJobStatus(cloud_print::PRINT_JOB_STATUS_IN_PROGRESS, SUCCESS);
|
| + print_thread_.Stop();
|
| + }
|
| +}
|
| +
|
| +void PrinterJobHandler::Shutdown() {
|
| + Reset();
|
| + shutting_down_ = true;
|
| + while (!job_status_updater_list_.empty()) {
|
| + // Calling Stop() will cause the OnJobCompleted to be called which will
|
| + // remove the updater object from the list.
|
| + job_status_updater_list_.front()->Stop();
|
| + }
|
| + if (delegate_) {
|
| + delegate_->OnPrinterJobHandlerShutdown(this, printer_id_);
|
| + }
|
| +}
|
| +
|
| +void PrinterJobHandler::HandleServerError(const GURL& url) {
|
| + Task* task_to_retry = NewRunnableMethod(this,
|
| + &PrinterJobHandler::MakeServerRequest,
|
| + url, next_response_handler_);
|
| + Task* task_on_give_up = NewRunnableMethod(this, &PrinterJobHandler::Stop);
|
| + CloudPrintHelpers::HandleServerError(&server_error_count_, kMaxRetryCount,
|
| + -1, kBaseRetryInterval, task_to_retry,
|
| + task_on_give_up);
|
| +}
|
| +
|
| +void PrinterJobHandler::UpdateJobStatus(cloud_print::PrintJobStatus status,
|
| + PrintJobError error) {
|
| + if (!shutting_down_) {
|
| + if (!job_details_.job_id_.empty()) {
|
| + ResponseHandler response_handler = NULL;
|
| + if (error == SUCCESS) {
|
| + response_handler =
|
| + &PrinterJobHandler::HandleSuccessStatusUpdateResponse;
|
| + } else {
|
| + response_handler =
|
| + &PrinterJobHandler::HandleFailureStatusUpdateResponse;
|
| + }
|
| + MakeServerRequest(
|
| + CloudPrintHelpers::GetUrlForJobStatusUpdate(job_details_.job_id_,
|
| + status),
|
| + response_handler);
|
| + }
|
| + }
|
| +}
|
| +
|
| +bool PrinterJobHandler::HandleSuccessStatusUpdateResponse(
|
| + const URLFetcher* source, const GURL& url, const URLRequestStatus& status,
|
| + int response_code, const ResponseCookies& cookies,
|
| + const std::string& data) {
|
| + // If there was a network error or a non-200 response (which, for our purposes
|
| + // is the same as a network error), we want to retry.
|
| + if (!status.is_success() || (response_code != 200)) {
|
| + return false;
|
| + }
|
| + // The print job has been spooled locally. We now need to create an object
|
| + // that monitors the status of the job and updates the server.
|
| + scoped_refptr<JobStatusUpdater> job_status_updater =
|
| + new JobStatusUpdater(printer_info_.printer_name, job_details_.job_id_,
|
| + local_job_id_, auth_token_, this);
|
| + job_status_updater_list_.push_back(job_status_updater);
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE, NewRunnableMethod(job_status_updater.get(),
|
| + &JobStatusUpdater::UpdateStatus));
|
| + bool succeeded = false;
|
| + CloudPrintHelpers::ParseResponseJSON(data, &succeeded, NULL);
|
| + if (succeeded) {
|
| + // Since we just printed successfully, we want to look for more jobs.
|
| + server_job_available_ = true;
|
| + }
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Stop));
|
| + return true;
|
| +}
|
| +
|
| +bool PrinterJobHandler::HandleFailureStatusUpdateResponse(
|
| + const URLFetcher* source, const GURL& url, const URLRequestStatus& status,
|
| + int response_code, const ResponseCookies& cookies,
|
| + const std::string& data) {
|
| + // If there was a network error or a non-200 response (which, for our purposes
|
| + // is the same as a network error), we want to retry.
|
| + if (!status.is_success() || (response_code != 200)) {
|
| + return false;
|
| + }
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE, NewRunnableMethod(this, &PrinterJobHandler::Stop));
|
| + return true;
|
| +}
|
| +
|
| +void PrinterJobHandler::MakeServerRequest(const GURL& url,
|
| + ResponseHandler response_handler) {
|
| + if (!shutting_down_) {
|
| + request_.reset(new URLFetcher(url, URLFetcher::GET, this));
|
| + server_error_count_ = 0;
|
| + CloudPrintHelpers::PrepCloudPrintRequest(request_.get(), auth_token_);
|
| + // Set up the next response handler
|
| + next_response_handler_ = response_handler;
|
| + request_->Start();
|
| + }
|
| +}
|
| +
|
| +bool PrinterJobHandler::HavePendingTasks() {
|
| + return server_job_available_ || printer_update_pending_ ||
|
| + printer_delete_pending_;
|
| +}
|
| +
|
| +
|
| +void PrinterJobHandler::DoPrint(const JobDetails& job_details,
|
| + const std::string& printer_name,
|
| + PrinterJobHandler* job_handler,
|
| + MessageLoop* job_message_loop) {
|
| + DCHECK(job_handler);
|
| + DCHECK(job_message_loop);
|
| + cloud_print::PlatformJobId job_id = -1;
|
| + if (cloud_print::SpoolPrintJob(job_details.print_ticket_,
|
| + job_details.print_data_file_path_,
|
| + job_details.print_data_mime_type_,
|
| + printer_name,
|
| + job_details.job_title_, &job_id)) {
|
| + job_message_loop->PostTask(FROM_HERE,
|
| + NewRunnableMethod(job_handler,
|
| + &PrinterJobHandler::JobSpooled,
|
| + job_id));
|
| + } else {
|
| + job_message_loop->PostTask(FROM_HERE,
|
| + NewRunnableMethod(job_handler,
|
| + &PrinterJobHandler::JobFailed,
|
| + PRINT_FAILED));
|
| + }
|
| +}
|
| +
|
|
|
| Property changes on: chrome\browser\printing\cloud_print\printer_job_handler.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|