1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "cloud_print/service/win/service_listener.h"
6
7#include "base/bind.h"
8#include "base/file_util.h"
9#include "base/files/file_path.h"
10#include "base/json/json_writer.h"
11#include "base/threading/thread.h"
12#include "base/values.h"
13#include "chrome/installer/launcher_support/chrome_launcher_support.h"
14#include "cloud_print/service/win/service_utils.h"
15#include "cloud_print/service/win/setup_listener.h"
16#include "ipc/ipc_channel.h"
17#include "printing/backend/print_backend.h"
18#include "printing/backend/win_helper.h"
19
20namespace {
21
22std::string GetEnvironment(const base::FilePath& user_data_dir) {
23  scoped_refptr<printing::PrintBackend> backend(
24      printing::PrintBackend::CreateInstance(NULL));
25  printing::PrinterList printer_list;
26  backend->EnumeratePrinters(&printer_list);
27  scoped_ptr<base::ListValue> printers(new base::ListValue());
28  for (size_t i = 0; i < printer_list.size(); ++i) {
29    printers->AppendString(printer_list[i].printer_name);
30  }
31
32  base::DictionaryValue environment;
33  environment.Set(SetupListener::kPrintersJsonValueName, printers.release());
34  environment.SetBoolean(SetupListener::kXpsAvailableJsonValueName,
35                         printing::XPSModule::Init());
36  environment.SetString(SetupListener::kUserNameJsonValueName,
37                        GetCurrentUserName());
38  environment.SetString(SetupListener::kChromePathJsonValueName,
39                        chrome_launcher_support::GetAnyChromePath().value());
40  if (base::CreateDirectory(user_data_dir)) {
41    base::FilePath temp_file;
42    if (base::CreateTemporaryFileInDir(user_data_dir, &temp_file)) {
43      DCHECK(base::PathExists(temp_file));
44      environment.SetString(SetupListener::kUserDataDirJsonValueName,
45                            user_data_dir.value());
46      base::DeleteFile(temp_file, false);
47    }
48  }
49
50  std::string result;
51  base::JSONWriter::Write(&environment, &result);
52  return result;
53}
54
55}  // namespace
56
57ServiceListener::ServiceListener(const base::FilePath& user_data_dir)
58    : ipc_thread_(new base::Thread("ipc_thread")),
59      user_data_dir_(user_data_dir) {
60  ipc_thread_->StartWithOptions(
61      base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
62  ipc_thread_->message_loop()->PostTask(
63      FROM_HERE, base::Bind(&ServiceListener::Connect, base::Unretained(this)));
64}
65
66ServiceListener::~ServiceListener() {
67  ipc_thread_->message_loop()->PostTask(FROM_HERE,
68                                        base::Bind(&ServiceListener::Disconnect,
69                                                   base::Unretained(this)));
70  ipc_thread_->Stop();
71}
72
73bool ServiceListener::OnMessageReceived(const IPC::Message& msg) {
74  return true;
75}
76
77void ServiceListener::OnChannelConnected(int32 peer_pid) {
78  IPC::Message* message = new IPC::Message(0, 0, IPC::Message::PRIORITY_NORMAL);
79  message->WriteString(GetEnvironment(user_data_dir_));
80  channel_->Send(message);
81}
82
83void ServiceListener::Disconnect() {
84  channel_.reset();
85}
86
87void ServiceListener::Connect() {
88  base::win::ScopedHandle handle(
89      ::CreateFile(SetupListener::kSetupPipeName, GENERIC_READ | GENERIC_WRITE,
90                   0, NULL, OPEN_EXISTING,
91                   SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION |
92                   FILE_FLAG_OVERLAPPED, NULL));
93  if (handle.IsValid()) {
94    channel_ = IPC::Channel::CreateClient(IPC::ChannelHandle(handle),
95                                          this);
96    channel_->Connect();
97  } else {
98    ipc_thread_->message_loop()->PostDelayedTask(
99        FROM_HERE,
100        base::Bind(&ServiceListener::Connect, base::Unretained(this)),
101        base::TimeDelta::FromMilliseconds(500));
102  }
103}
104
105