print_job_handler.cc revision 3551c9c881056c480085172ff9840cab31610854
1558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// found in the LICENSE file.
4558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
5558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "cloud_print/gcp20/prototype/print_job_handler.h"
6558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/bind.h"
83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/command_line.h"
9558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "base/file_util.h"
103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/format_macros.h"
113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/guid.h"
12558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "base/logging.h"
133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/message_loop/message_loop.h"
143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/rand_util.h"
153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/strings/string_util.h"
16558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "base/strings/stringprintf.h"
173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/time/time.h"
18558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
19558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochnamespace {
20558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const int kDraftExpirationSec = 10;
223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const int kLocalPrintJobExpirationSec = 20;
233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const int kErrorTimeoutSec = 30;
243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Errors simulation constants:
263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const double kPaperJamProbability = 0.2;
273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const int kTooManyDraftsTimeout = 10;
283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const int kMaxDrafts = 5;
293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
30558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochconst base::FilePath::CharType kJobsPath[] = FILE_PATH_LITERAL("printjobs");
31558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool ValidateTicket(const std::string& ticket) {
333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return true;
343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)std::string GenerateId() {
373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return StringToLowerASCII(base::GenerateGUID());
383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
40558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}  // namespace
41558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)struct PrintJobHandler::LocalPrintJobExtended {
433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  LocalPrintJobExtended(const LocalPrintJob& job, const std::string& ticket)
443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      : data(job),
453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        ticket(ticket),
463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        state(LocalPrintJob::STATE_DRAFT) {}
473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  LocalPrintJobExtended() : state(LocalPrintJob::STATE_DRAFT) {}
483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ~LocalPrintJobExtended() {}
493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  LocalPrintJob data;
513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string ticket;
523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  LocalPrintJob::State state;
533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::Time expiration;
543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)struct PrintJobHandler::LocalPrintJobDraft {
573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  LocalPrintJobDraft() {}
583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  LocalPrintJobDraft(const std::string& ticket, const base::Time& expiration)
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      : ticket(ticket),
603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        expiration(expiration) {}
613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ~LocalPrintJobDraft() {}
623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string ticket;
643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::Time expiration;
653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)using base::StringPrintf;
683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
69558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochPrintJobHandler::PrintJobHandler() {
70558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
71558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
72558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochPrintJobHandler::~PrintJobHandler() {
73558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
74558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)LocalPrintJob::CreateResult PrintJobHandler::CreatePrintJob(
763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& ticket,
773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    std::string* job_id_out,
783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // TODO(maksymb): Use base::TimeDelta for timeout values
793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int* expires_in_out,
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // TODO(maksymb): Use base::TimeDelta for timeout values
813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int* error_timeout_out,
823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    std::string* error_description) {
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ValidateTicket(ticket))
843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return LocalPrintJob::CREATE_INVALID_TICKET;
853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Let's simulate at least some errors just for testing.
873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (CommandLine::ForCurrentProcess()->HasSwitch("simulate-printing-errors")) {
883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (base::RandDouble() <= kPaperJamProbability) {
893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      *error_description = "Paper jam, try again";
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return LocalPrintJob::CREATE_PRINTER_ERROR;
913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (drafts.size() > kMaxDrafts) {  // Another simulation of error: business
943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      *error_timeout_out = kTooManyDraftsTimeout;
953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return LocalPrintJob::CREATE_PRINTER_BUSY;
963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string id = GenerateId();
1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  drafts[id] = LocalPrintJobDraft(
1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      ticket,
1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::Time::Now() + base::TimeDelta::FromSeconds(kDraftExpirationSec));
1033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
1043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      FROM_HERE,
1053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::Bind(&PrintJobHandler::ForgetDraft, AsWeakPtr(), id),
1063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::TimeDelta::FromSeconds(kDraftExpirationSec));
1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  *job_id_out = id;
1093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  *expires_in_out = kDraftExpirationSec;
1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return LocalPrintJob::CREATE_SUCCESS;
1113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)LocalPrintJob::SaveResult PrintJobHandler::SaveLocalPrintJob(
1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const LocalPrintJob& job,
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    std::string* job_id_out,
1163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int* expires_in_out,
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    std::string* error_description_out,
1183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int* timeout_out) {
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string id;
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int expires_in;
1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  switch (CreatePrintJob(std::string(), &id, &expires_in,
1233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                         timeout_out, error_description_out)) {
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case LocalPrintJob::CREATE_INVALID_TICKET:
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      NOTREACHED();
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return LocalPrintJob::SAVE_SUCCESS;
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case LocalPrintJob::CREATE_PRINTER_BUSY:
1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return LocalPrintJob::SAVE_PRINTER_BUSY;
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case LocalPrintJob::CREATE_PRINTER_ERROR:
1323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return LocalPrintJob::SAVE_PRINTER_ERROR;
1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case LocalPrintJob::CREATE_SUCCESS:
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      *job_id_out = id;
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return CompleteLocalPrintJob(job, id, expires_in_out,
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                   error_description_out, timeout_out);
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    default:
1403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      NOTREACHED();
1413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return LocalPrintJob::SAVE_SUCCESS;
1423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)LocalPrintJob::SaveResult PrintJobHandler::CompleteLocalPrintJob(
1463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const LocalPrintJob& job,
1473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& job_id,
1483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int* expires_in_out,
1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    std::string* error_description_out,
1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int* timeout_out) {
1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!drafts.count(job_id)) {
1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    *timeout_out = kErrorTimeoutSec;
1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return LocalPrintJob::SAVE_INVALID_PRINT_JOB;
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string suffix = StringPrintf("%s:%s",
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                    job.user_name.c_str(),
1583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                    job.client_name.c_str());
1593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string file_extension;
1603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(maksymb): Gather together this type checking with Printer
1613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // supported types in kCdd.
1623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (job.content_type == "application/pdf") {
1633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    file_extension = "pdf";
1643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else if (job.content_type == "image/pwg-raster") {
1653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    file_extension = "pwg";
1663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else if (job.content_type == "image/jpeg") {
1673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    file_extension = "jpg";
1683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else {
1693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    error_description_out->clear();
1703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return LocalPrintJob::SAVE_INVALID_DOCUMENT_TYPE;
1713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CompleteDraft(job_id, job);
1733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::map<std::string, LocalPrintJobExtended>::iterator current_job =
1743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      jobs.find(job_id);
1753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!SavePrintJob(current_job->second.data.content,
1773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    current_job->second.ticket,
1783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    base::Time::Now(),
1793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    StringPrintf("%s", job_id.c_str()),
1803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    suffix,
1813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    current_job->second.data.job_name, file_extension)) {
1823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    SetJobState(job_id, LocalPrintJob::STATE_ABORTED);
1833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    *error_description_out = "IO error";
1843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return LocalPrintJob::SAVE_PRINTER_ERROR;
1853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  SetJobState(job_id, LocalPrintJob::STATE_DONE);
1883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  *expires_in_out = static_cast<int>(GetJobExpiration(job_id).InSeconds());
1893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return LocalPrintJob::SAVE_SUCCESS;
1903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool PrintJobHandler::GetJobState(const std::string& id,
1933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                  LocalPrintJob::Info* info_out) {
1943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  using base::Time;
1953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::map<std::string, LocalPrintJobDraft>::iterator draft = drafts.find(id);
1973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (draft != drafts.end()) {
1983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    info_out->state = LocalPrintJob::STATE_DRAFT;
1993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    info_out->expires_in =
2003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        static_cast<int>((draft->second.expiration - Time::Now()).InSeconds());
2013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return true;
2023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::map<std::string, LocalPrintJobExtended>::iterator job = jobs.find(id);
2053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (job != jobs.end()) {
2063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    info_out->state = job->second.state;
2073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    info_out->expires_in = static_cast<int>(GetJobExpiration(id).InSeconds());
2083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return true;
2093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return false;
2113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
2123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool PrintJobHandler::SavePrintJob(const std::string& content,
214558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                   const std::string& ticket,
2153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                   const base::Time& create_time,
2163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                   const std::string& id,
2173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                   const std::string& job_name_suffix,
2183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                   // suffix is not extension
2193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                   // it may be used to mark local printer jobs
2203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                   const std::string& title,
2213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                   const std::string& file_extension) {
222558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  VLOG(1) << "Printing printjob: \"" + title + "\"";
223558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  base::FilePath directory(kJobsPath);
224558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!base::DirectoryExists(directory) &&
2263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      !file_util::CreateDirectory(directory)) {
227558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    LOG(WARNING) << "Cannot create directory: " << directory.value();
228558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return false;
229558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
230558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::Time::Exploded create_time_exploded;
2323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  create_time.UTCExplode(&create_time_exploded);
2333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string job_name =
2343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      StringPrintf("%.4d%.2d%.2d-%.2d:%.2d:%.2d-%.3dms.%s",
2353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          create_time_exploded.year,
2363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          create_time_exploded.month,
2373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          create_time_exploded.day_of_month,
2383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          create_time_exploded.hour,
2393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          create_time_exploded.minute,
2403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          create_time_exploded.second,
2413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          create_time_exploded.millisecond,
2423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          id.c_str());
2433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!job_name_suffix.empty())
2443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    job_name += "." + job_name_suffix;
245558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  directory = directory.AppendASCII(job_name);
246558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!base::DirectoryExists(directory) &&
2483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      !file_util::CreateDirectory(directory)) {
249558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    LOG(WARNING) << "Cannot create directory: " << directory.value();
250558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return false;
251558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
252558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
253558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  int written = file_util::WriteFile(directory.AppendASCII("ticket.xml"),
254558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                     ticket.data(),
255558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                     static_cast<int>(ticket.size()));
256558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (static_cast<size_t>(written) != ticket.size()) {
257558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    LOG(WARNING) << "Cannot save ticket.";
258558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return false;
259558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
260558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  written = file_util::WriteFile(
2623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      directory.AppendASCII("data." + file_extension),
2633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      content.data(), static_cast<int>(content.size()));
2643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (static_cast<size_t>(written) != content.size()) {
265558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    LOG(WARNING) << "Cannot save data.";
266558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return false;
267558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
268558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  LOG(INFO) << "Saved printjob: " << job_name << ": " << title;
270558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return true;
271558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
272558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void PrintJobHandler::SetJobState(const std::string& id,
2743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                  LocalPrintJob::State state) {
2753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(!drafts.count(id)) << "Draft should be completed at first";
2763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::map<std::string, LocalPrintJobExtended>::iterator job = jobs.find(id);
2783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(job != jobs.end());
2793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  job->second.state = state;
2803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  switch (state) {
2813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case LocalPrintJob::STATE_DRAFT:
2823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      NOTREACHED();
2833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
2843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case LocalPrintJob::STATE_ABORTED:
2853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case LocalPrintJob::STATE_DONE:
2863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      job->second.expiration =
2873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          base::Time::Now() +
2883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          base::TimeDelta::FromSeconds(kLocalPrintJobExpirationSec);
2893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::MessageLoop::current()->PostDelayedTask(
2903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          FROM_HERE,
2913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          base::Bind(&PrintJobHandler::ForgetLocalJob, AsWeakPtr(), id),
2923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          base::TimeDelta::FromSeconds(kLocalPrintJobExpirationSec));
2933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
2943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    default:
2953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      NOTREACHED();
2963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
2983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void PrintJobHandler::CompleteDraft(const std::string& id,
3003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                    const LocalPrintJob& job) {
3013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::map<std::string, LocalPrintJobDraft>::iterator draft = drafts.find(id);
3023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (draft != drafts.end()) {
3033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    jobs[id] = LocalPrintJobExtended(job, draft->second.ticket);
3043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    drafts.erase(draft);
3053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
3073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// TODO(maksymb): Use base::Time for expiration
3093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)base::TimeDelta PrintJobHandler::GetJobExpiration(const std::string& id) const {
3103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(jobs.count(id));
3113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::Time expiration = jobs.at(id).expiration;
3123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (expiration.is_null())
3133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return base::TimeDelta::FromSeconds(kLocalPrintJobExpirationSec);
3143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return expiration - base::Time::Now();
3153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
3163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void PrintJobHandler::ForgetDraft(const std::string& id) {
3183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  drafts.erase(id);
3193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
3203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void PrintJobHandler::ForgetLocalJob(const std::string& id) {
3223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  jobs.erase(id);
3233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
3243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
325