summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cloud_print/cloud_print.gyp8
-rw-r--r--cloud_print/service/service.gyp5
-rw-r--r--cloud_print/service/win/cloud_print_service.cc101
-rw-r--r--cloud_print/service/win/cloud_print_service.rc2
-rw-r--r--cloud_print/service/win/service_controller.cc12
-rw-r--r--cloud_print/service/win/service_controller.h5
-rw-r--r--cloud_print/service/win/service_ipc_unittest.cc46
-rw-r--r--cloud_print/service/win/service_listener.cc104
-rw-r--r--cloud_print/service/win/service_listener.h41
-rw-r--r--cloud_print/service/win/service_utils.cc2
-rw-r--r--cloud_print/service/win/service_utils.h2
-rw-r--r--cloud_print/service/win/setup_listener.cc124
-rw-r--r--cloud_print/service/win/setup_listener.h83
13 files changed, 468 insertions, 67 deletions
diff --git a/cloud_print/cloud_print.gyp b/cloud_print/cloud_print.gyp
index 30d7e9f..8994449 100644
--- a/cloud_print/cloud_print.gyp
+++ b/cloud_print/cloud_print.gyp
@@ -88,6 +88,7 @@
'conditions': [
['OS=="win"', {
'sources': [
+ 'service/win/service_ipc_unittest.cc',
'virtual_driver/win/port_monitor/port_monitor_unittest.cc',
],
'dependencies': [
@@ -95,6 +96,13 @@
],
}],
],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'AdditionalDependencies': [
+ 'secur32.lib',
+ ],
+ },
+ },
},
],
}
diff --git a/cloud_print/service/service.gyp b/cloud_print/service/service.gyp
index 9dc7975..8e11395 100644
--- a/cloud_print/service/service.gyp
+++ b/cloud_print/service/service.gyp
@@ -35,6 +35,7 @@
'dependencies': [
'<(DEPTH)/base/base.gyp:base',
'<(DEPTH)/build/temp_gyp/googleurl.gyp:googleurl',
+ '<(DEPTH)/ipc/ipc.gyp:ipc',
'<(DEPTH)/net/net.gyp:net',
'<(DEPTH)/printing/printing.gyp:printing',
],
@@ -57,8 +58,12 @@
'win/local_security_policy.h',
'win/service_controller.cc',
'win/service_controller.h',
+ 'win/service_listener.cc',
+ 'win/service_listener.h',
'win/service_utils.cc',
'win/service_utils.h',
+ 'win/setup_listener.cc',
+ 'win/setup_listener.h',
],
},
{
diff --git a/cloud_print/service/win/cloud_print_service.cc b/cloud_print/service/win/cloud_print_service.cc
index c1299c8..0bc922e 100644
--- a/cloud_print/service/win/cloud_print_service.cc
+++ b/cloud_print/service/win/cloud_print_service.cc
@@ -16,19 +16,17 @@
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "chrome/installer/launcher_support/chrome_launcher_support.h"
+#include "base/win/scoped_handle.h"
#include "cloud_print/service/service_state.h"
#include "cloud_print/service/service_switches.h"
#include "cloud_print/service/win/chrome_launcher.h"
#include "cloud_print/service/win/service_controller.h"
+#include "cloud_print/service/win/service_listener.h"
#include "cloud_print/service/win/service_utils.h"
-#include "printing/backend/print_backend.h"
+#include "cloud_print/service/win/setup_listener.h"
namespace {
-const char kChromeIsNotAvalible[] = "\nChrome is not available\n";
-const char kChromeIsAvalible[] = "\nChrome is available\n";
-const wchar_t kRequirementsFileName[] = L"cloud_print_service_requirements.txt";
const wchar_t kServiceStateFileName[] = L"Service State";
void InvalidUsage() {
@@ -113,6 +111,7 @@ bool AskUser(const std::string& request) {
} // namespace
+
class CloudPrintServiceModule
: public ATL::CAtlServiceModuleT<CloudPrintServiceModule, IDS_SERVICENAME> {
public:
@@ -153,13 +152,9 @@ class CloudPrintServiceModule
return hr;
if (check_requirements_) {
- hr = CheckRequirements();
- if (FAILED(hr))
- return hr;
- // Don't run message loop and stop service.
- return S_FALSE;
+ CheckRequirements();
} else {
- hr = StartConnector();
+ HRESULT hr = StartConnector();
if (FAILED(hr))
return hr;
}
@@ -172,6 +167,7 @@ class CloudPrintServiceModule
HRESULT PostMessageLoop() {
StopConnector();
+ setup_listener_.reset();
return Base::PostMessageLoop();
}
@@ -203,7 +199,7 @@ class CloudPrintServiceModule
return hr;
hr = controller_->InstallService(run_as_user, run_as_password,
- kServiceSwitch, user_data_dir_);
+ kServiceSwitch, user_data_dir_, true);
if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch))
return controller_->StartService();
@@ -213,6 +209,14 @@ class CloudPrintServiceModule
if (command_line.HasSwitch(kStartSwitch))
return controller_->StartService();
+ if (command_line.HasSwitch(kConsoleSwitch)) {
+ check_requirements_ = command_line.HasSwitch(kRequirementsSwitch);
+ ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE);
+ HRESULT hr = Run();
+ ::SetConsoleCtrlHandler(NULL, FALSE);
+ return hr;
+ }
+
if (command_line.HasSwitch(kServiceSwitch) ||
command_line.HasSwitch(kRequirementsSwitch)) {
*is_service = true;
@@ -220,12 +224,6 @@ class CloudPrintServiceModule
return S_OK;
}
- if (command_line.HasSwitch(kConsoleSwitch)) {
- ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE);
- HRESULT hr = Run();
- ::SetConsoleCtrlHandler(NULL, FALSE);
- return hr;
- }
InvalidUsage();
return S_FALSE;
@@ -239,42 +237,47 @@ class CloudPrintServiceModule
WideToASCII(*run_as_user), false));
*run_as_password = ASCIIToWide(GetOption("Password", "", true));
- base::FilePath requirements_filename(user_data_dir_);
- requirements_filename =
- requirements_filename.Append(kRequirementsFileName);
-
- file_util::Delete(requirements_filename, false);
- if (file_util::PathExists(requirements_filename)) {
- LOG(ERROR) << "Unable to delete " <<
- requirements_filename.value() << ".";
- continue;
- }
+ SetupListener setup(*run_as_user);
if (FAILED(controller_->InstallService(*run_as_user, *run_as_password,
kRequirementsSwitch,
- user_data_dir_))) {
+ user_data_dir_, false))) {
+ LOG(ERROR) << "Failed to install service as " << *run_as_user << ".";
continue;
}
+
bool service_started = SUCCEEDED(controller_->StartService());
+
+ if (service_started &&
+ !setup.WaitResponce(base::TimeDelta::FromSeconds(30))) {
+ LOG(ERROR) << "Failed to check environment for user " << *run_as_user
+ << ".";
+ }
+
controller_->UninstallService();
if (!service_started) {
LOG(ERROR) << "Failed to start service as " << *run_as_user << ".";
continue;
}
- std::string printers;
- if (!file_util::PathExists(requirements_filename) ||
- !file_util::ReadFileToString(requirements_filename, &printers)) {
- LOG(ERROR) << "Service can't create " << requirements_filename.value();
+ if (setup.user_data_dir().empty()) {
+ LOG(ERROR) << "Service can't access " << user_data_dir_.value() << ".";
continue;
}
-
- if (EndsWith(printers, kChromeIsNotAvalible, true)) {
- LOG(ERROR) << kChromeIsNotAvalible << " for " << *run_as_user << ".";
+ if (setup.chrome_path().empty()) {
+ LOG(ERROR) << "Chrome is not available for " << *run_as_user << ".";
+ continue;
+ }
+ if (!setup.is_xps_availible()) {
+ LOG(ERROR) << "XPS pack is not installed.";
continue;
}
std::cout << "\nService requirements check result: \n";
- std::cout << printers << "\n";
- file_util::Delete(requirements_filename, false);
+ std::cout << "Username: " << setup.user_name()<< "\n";
+ std::cout << "Chrome: " << setup.chrome_path().value()<< "\n";
+ std::cout << "Printers:\n ";
+ std::ostream_iterator<std::string> cout_it(std::cout, "\n ");
+ std::copy(setup.printers().begin(), setup.printers().end(), cout_it);
+ std::cout << "\n";
if (AskUser("Do you want to use " + WideToASCII(*run_as_user) + "?"))
return;
@@ -332,25 +335,8 @@ class CloudPrintServiceModule
return S_OK;
}
- HRESULT CheckRequirements() {
- base::FilePath requirements_filename(user_data_dir_);
- requirements_filename = requirements_filename.Append(kRequirementsFileName);
- std::string output;
- output.append("Printers available for " +
- WideToASCII(GetCurrentUserName()) + ":\n");
- scoped_refptr<printing::PrintBackend> backend(
- printing::PrintBackend::CreateInstance(NULL));
- printing::PrinterList printer_list;
- backend->EnumeratePrinters(&printer_list);
- for (size_t i = 0; i < printer_list.size(); ++i) {
- output += " ";
- output += printer_list[i].printer_name;
- output += "\n";
- }
- base::FilePath chrome = chrome_launcher_support::GetAnyChromePath();
- output.append(chrome.empty() ? kChromeIsNotAvalible : kChromeIsAvalible);
- file_util::WriteFile(requirements_filename, output.c_str(), output.size());
- return S_OK;
+ void CheckRequirements() {
+ setup_listener_.reset(new ServiceListener(user_data_dir_));
}
HRESULT StartConnector() {
@@ -371,6 +357,7 @@ class CloudPrintServiceModule
base::FilePath user_data_dir_;
scoped_ptr<ChromeLauncher> chrome_;
scoped_ptr<ServiceController> controller_;
+ scoped_ptr<ServiceListener> setup_listener_;
};
CloudPrintServiceModule _AtlModule;
diff --git a/cloud_print/service/win/cloud_print_service.rc b/cloud_print/service/win/cloud_print_service.rc
index 294a495..42a18cd 100644
--- a/cloud_print/service/win/cloud_print_service.rc
+++ b/cloud_print/service/win/cloud_print_service.rc
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 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.
diff --git a/cloud_print/service/win/service_controller.cc b/cloud_print/service/win/service_controller.cc
index 428f282..792c757 100644
--- a/cloud_print/service/win/service_controller.cc
+++ b/cloud_print/service/win/service_controller.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 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.
@@ -114,7 +114,8 @@ HRESULT ServiceController::StopService() {
HRESULT ServiceController::InstallService(const string16& user,
const string16& password,
const std::string& run_switch,
- const base::FilePath& user_data_dir) {
+ const base::FilePath& user_data_dir,
+ bool auto_start) {
// TODO(vitalybuka): consider "lite" version if we don't want unregister
// printers here.
HRESULT hr = UninstallService();
@@ -152,9 +153,10 @@ HRESULT ServiceController::InstallService(const string16& user,
ServiceHandle service(
::CreateService(
scm, name_.c_str(), name_.c_str(), SERVICE_ALL_ACCESS,
- SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
- command_line.GetCommandLineString().c_str(), NULL, NULL, NULL,
- user.empty() ? NULL : user.c_str(),
+ SERVICE_WIN32_OWN_PROCESS,
+ auto_start ? SERVICE_AUTO_START : SERVICE_DEMAND_START,
+ SERVICE_ERROR_NORMAL, command_line.GetCommandLineString().c_str(),
+ NULL, NULL, NULL, user.empty() ? NULL : user.c_str(),
password.empty() ? NULL : password.c_str()));
if (!service.IsValid()) {
diff --git a/cloud_print/service/win/service_controller.h b/cloud_print/service/win/service_controller.h
index 4e06059..4f5553b 100644
--- a/cloud_print/service/win/service_controller.h
+++ b/cloud_print/service/win/service_controller.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 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.
@@ -26,7 +26,8 @@ class ServiceController {
HRESULT InstallService(const string16& user,
const string16& password,
const std::string& run_switch,
- const base::FilePath& user_data_dir);
+ const base::FilePath& user_data_dir,
+ bool auto_start);
HRESULT UninstallService();
diff --git a/cloud_print/service/win/service_ipc_unittest.cc b/cloud_print/service/win/service_ipc_unittest.cc
new file mode 100644
index 0000000..095e8d2
--- /dev/null
+++ b/cloud_print/service/win/service_ipc_unittest.cc
@@ -0,0 +1,46 @@
+// Copyright 2013 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 "base/files/scoped_temp_dir.h"
+#include "base/threading/platform_thread.h"
+#include "base/time.h"
+#include "cloud_print/service/win/service_listener.h"
+#include "cloud_print/service/win/service_utils.h"
+#include "cloud_print/service/win/setup_listener.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(ServiceIpcTest, Timeout) {
+ SetupListener setup(GetCurrentUserName());
+ ASSERT_FALSE(setup.WaitResponce(base::TimeDelta::FromSeconds(3)));
+}
+
+TEST(ServiceIpcTest, Sequence) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ SetupListener setup(GetCurrentUserName());
+ ServiceListener service(temp_dir.path());
+ ASSERT_TRUE(setup.WaitResponce(base::TimeDelta::FromSeconds(30)));
+ EXPECT_EQ(setup.user_data_dir(), temp_dir.path());
+ EXPECT_EQ(setup.user_name(), GetCurrentUserName());
+}
+
+TEST(ServiceIpcTest, ReverseSequence) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ ServiceListener service(temp_dir.path());
+ base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
+ SetupListener setup(GetCurrentUserName());
+ ASSERT_TRUE(setup.WaitResponce(base::TimeDelta::FromSeconds(30)));
+ EXPECT_EQ(setup.user_data_dir(), temp_dir.path());
+ EXPECT_EQ(setup.user_name(), GetCurrentUserName());
+}
+
+TEST(ServiceIpcTest, InvaludUser) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ SetupListener setup(L"guest");
+ ServiceListener service(temp_dir.path());
+ ASSERT_FALSE(setup.WaitResponce(base::TimeDelta::FromSeconds(3)));
+}
+
diff --git a/cloud_print/service/win/service_listener.cc b/cloud_print/service/win/service_listener.cc
new file mode 100644
index 0000000..a69f4ef
--- /dev/null
+++ b/cloud_print/service/win/service_listener.cc
@@ -0,0 +1,104 @@
+// Copyright 2013 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 "cloud_print/service/win/service_listener.h"
+
+#include "base/bind.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/json/json_writer.h"
+#include "base/threading/thread.h"
+#include "base/values.h"
+#include "chrome/installer/launcher_support/chrome_launcher_support.h"
+#include "cloud_print/service/win/service_utils.h"
+#include "cloud_print/service/win/setup_listener.h"
+#include "ipc/ipc_channel.h"
+#include "printing/backend/print_backend.h"
+#include "printing/backend/win_helper.h"
+
+namespace {
+
+std::string GetEnvironment(const base::FilePath& user_data_dir) {
+ scoped_refptr<printing::PrintBackend> backend(
+ printing::PrintBackend::CreateInstance(NULL));
+ printing::PrinterList printer_list;
+ backend->EnumeratePrinters(&printer_list);
+ scoped_ptr<base::ListValue> printers(new base::ListValue());
+ for (size_t i = 0; i < printer_list.size(); ++i) {
+ printers->AppendString(printer_list[i].printer_name);
+ }
+
+ base::DictionaryValue environment;
+ environment.Set(SetupListener::kPrintersJsonValueName, printers.release());
+ environment.SetBoolean(SetupListener::kXpsAvailibleJsonValueName,
+ printing::XPSModule::Init());
+ environment.SetString(SetupListener::kUserNameJsonValueName,
+ GetCurrentUserName());
+ environment.SetString(SetupListener::kChromePathJsonValueName,
+ chrome_launcher_support::GetAnyChromePath().value());
+ if (file_util::DirectoryExists(user_data_dir)) {
+ base::FilePath temp_file;
+ if (file_util::CreateTemporaryFileInDir(user_data_dir, &temp_file)) {
+ DCHECK(file_util::PathExists(temp_file));
+ environment.SetString(SetupListener::kUserDataDirJsonValueName,
+ user_data_dir.value());
+ file_util::Delete(temp_file, false);
+ }
+ }
+
+ std::string result;
+ base::JSONWriter::Write(&environment, &result);
+ return result;
+}
+
+} // namespace
+
+ServiceListener::ServiceListener(const base::FilePath& user_data_dir)
+ : ipc_thread_(new base::Thread("ipc_thread")),
+ user_data_dir_(user_data_dir) {
+ ipc_thread_->StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));
+ ipc_thread_->message_loop()->PostTask(FROM_HERE,
+ base::Bind(&ServiceListener::Connect,
+ base::Unretained(this)));
+}
+
+ServiceListener::~ServiceListener() {
+ ipc_thread_->message_loop()->PostTask(FROM_HERE,
+ base::Bind(&ServiceListener::Disconnect,
+ base::Unretained(this)));
+ ipc_thread_->Stop();
+}
+
+bool ServiceListener::OnMessageReceived(const IPC::Message& msg) {
+ return true;
+}
+
+void ServiceListener::OnChannelConnected(int32 peer_pid) {
+ IPC::Message* message = new IPC::Message(0, 0, IPC::Message::PRIORITY_NORMAL);
+ message->WriteString(GetEnvironment(user_data_dir_));
+ channel_->Send(message);
+}
+
+void ServiceListener::Disconnect() {
+ channel_.reset();
+}
+
+void ServiceListener::Connect() {
+ base::win::ScopedHandle handle(
+ ::CreateFile(SetupListener::kSetupPipeName, GENERIC_READ | GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING,
+ SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION |
+ FILE_FLAG_OVERLAPPED, NULL));
+ if (handle.IsValid()) {
+ channel_.reset(new IPC::Channel(IPC::ChannelHandle(handle),
+ IPC::Channel::MODE_CLIENT, this));
+ channel_->Connect();
+ } else {
+ ipc_thread_->message_loop()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&ServiceListener::Connect, base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(500));
+ }
+}
+
diff --git a/cloud_print/service/win/service_listener.h b/cloud_print/service/win/service_listener.h
new file mode 100644
index 0000000..cdbc451
--- /dev/null
+++ b/cloud_print/service/win/service_listener.h
@@ -0,0 +1,41 @@
+// Copyright 2013 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.
+
+#ifndef CLOUD_PRINT_SERVICE_SERVICE_LISTENER_H_
+#define CLOUD_PRINT_SERVICE_SERVICE_LISTENER_H_
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "ipc/ipc_listener.h"
+
+namespace base {
+class Thread;
+} // base
+
+namespace IPC {
+class Channel;
+} // IPC
+
+// Simple IPC listener to run on service side to collect service environment and
+// to send back to setup utility.
+class ServiceListener : public IPC::Listener {
+ public:
+ explicit ServiceListener(const base::FilePath& user_data_dir);
+ virtual ~ServiceListener();
+
+ virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+ virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
+
+ private:
+ void Disconnect();
+ void Connect();
+
+ scoped_ptr<base::Thread> ipc_thread_;
+ scoped_ptr<IPC::Channel> channel_;
+ base::FilePath user_data_dir_;
+};
+
+#endif // CLOUD_PRINT_SERVICE_SERVICE_LISTENER_H_
+
diff --git a/cloud_print/service/win/service_utils.cc b/cloud_print/service/win/service_utils.cc
index acd8c3f..fc06271 100644
--- a/cloud_print/service/win/service_utils.cc
+++ b/cloud_print/service/win/service_utils.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 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.
diff --git a/cloud_print/service/win/service_utils.h b/cloud_print/service/win/service_utils.h
index c3cbfa2..33abb65 100644
--- a/cloud_print/service/win/service_utils.h
+++ b/cloud_print/service/win/service_utils.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 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.
diff --git a/cloud_print/service/win/setup_listener.cc b/cloud_print/service/win/setup_listener.cc
new file mode 100644
index 0000000..3bd4b73
--- /dev/null
+++ b/cloud_print/service/win/setup_listener.cc
@@ -0,0 +1,124 @@
+// Copyright 2013 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 "cloud_print/service/win/setup_listener.h"
+
+#include <atlbase.h>
+#include <atlsecurity.h>
+
+#include "base/bind.h"
+#include "base/guid.h"
+#include "base/json/json_reader.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "ipc/ipc_channel.h"
+
+const char SetupListener::kXpsAvailibleJsonValueName[] = "xps_availible";
+const char SetupListener::kChromePathJsonValueName[] = "chrome_path";
+const char SetupListener::kPrintersJsonValueName[] = "printers";
+const char SetupListener::kUserDataDirJsonValueName[] = "user_data_dir";
+const char SetupListener::kUserNameJsonValueName[] = "user_name";
+const wchar_t SetupListener::kSetupPipeName[] =
+ L"\\\\.\\pipe\\CloudPrintServiceSetup";
+
+SetupListener::SetupListener(const string16& user)
+ : done_event_(new base::WaitableEvent(true, false)),
+ ipc_thread_(new base::Thread("ipc_thread")),
+ succeded_(false),
+ is_xps_availible_(false) {
+ ipc_thread_->StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));
+ ipc_thread_->message_loop()->PostTask(FROM_HERE,
+ base::Bind(&SetupListener::Connect,
+ base::Unretained(this),
+ user));
+}
+
+SetupListener::~SetupListener() {
+ ipc_thread_->message_loop()->PostTask(FROM_HERE,
+ base::Bind(&SetupListener::Disconnect,
+ base::Unretained(this)));
+ ipc_thread_->Stop();
+}
+
+bool SetupListener::OnMessageReceived(const IPC::Message& msg) {
+ PickleIterator iter(msg);
+ std::string json_string;
+ if (!iter.ReadString(&json_string))
+ return false;
+ scoped_ptr<base::Value> value(base::JSONReader::Read(json_string));
+ const base::DictionaryValue* dictionary = NULL;
+ if (!value || !value->GetAsDictionary(&dictionary) || !dictionary) {
+ LOG(ERROR) << "Invalid response from service";
+ return false;
+ }
+
+ const base::ListValue* printers = NULL;
+ if (dictionary->GetList(kPrintersJsonValueName, &printers) && printers) {
+ for (size_t i = 0; i < printers->GetSize(); ++i) {
+ std::string printer;
+ if (printers->GetString(i, &printer) && !printer.empty())
+ printers_.push_back(printer);
+ }
+ }
+ dictionary->GetBoolean(kXpsAvailibleJsonValueName, &is_xps_availible_);
+ dictionary->GetString(kUserNameJsonValueName, &user_name_);
+
+ string16 chrome_path;
+ dictionary->GetString(kChromePathJsonValueName, &chrome_path);
+ chrome_path_ = base::FilePath(chrome_path);
+
+ string16 user_data_dir;
+ dictionary->GetString(kUserDataDirJsonValueName, &user_data_dir);
+ user_data_dir_ = base::FilePath(user_data_dir);
+
+ succeded_ = true;
+ done_event_->Signal();
+ return true;
+}
+
+void SetupListener::OnChannelError() {
+ done_event_->Signal();
+}
+
+bool SetupListener::WaitResponce(const base::TimeDelta& delta) {
+ return done_event_->TimedWait(delta) && succeded_;
+}
+
+void SetupListener::Disconnect() {
+ channel_.reset();
+ ipc_thread_->message_loop()->QuitWhenIdle();
+}
+
+void SetupListener::Connect(const string16& user) {
+ ATL::CDacl dacl;
+
+ ATL::CSid user_sid;
+ if (!user_sid.LoadAccount(user.c_str())) {
+ LOG(ERROR) << "Unable to load Sid for" << user;
+ } else {
+ dacl.AddAllowedAce(user_sid, GENERIC_READ | GENERIC_WRITE);
+ }
+
+ ATL::CSecurityDesc desk;
+ desk.SetDacl(dacl);
+
+ ATL::CSecurityAttributes attribs(desk);
+
+ base::win::ScopedHandle pipe(
+ CreateNamedPipe(kSetupPipeName,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
+ FILE_FLAG_FIRST_PIPE_INSTANCE,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1,
+ IPC::Channel::kReadBufferSize,
+ IPC::Channel::kReadBufferSize, 5000, &attribs));
+ if (pipe.IsValid()) {
+ channel_.reset(new IPC::Channel(IPC::ChannelHandle(pipe),
+ IPC::Channel::MODE_SERVER, this));
+ channel_->Connect();
+ }
+}
+
diff --git a/cloud_print/service/win/setup_listener.h b/cloud_print/service/win/setup_listener.h
new file mode 100644
index 0000000..0be7acf
--- /dev/null
+++ b/cloud_print/service/win/setup_listener.h
@@ -0,0 +1,83 @@
+// Copyright 2013 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.
+
+#ifndef CLOUD_PRINT_SERVICE_SETUP_LISTENER_H_
+#define CLOUD_PRINT_SERVICE_SETUP_LISTENER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/string16.h"
+#include "ipc/ipc_listener.h"
+
+namespace base {
+class Thread;
+class TimeDelta;
+class WaitableEvent;
+} // base
+
+namespace IPC {
+class Channel;
+} // IPC
+
+// Simple IPC listener to run on setup utility size wait message with data about
+// environment from service process.
+class SetupListener : public IPC::Listener {
+ public:
+ static const char kXpsAvailibleJsonValueName[];
+ static const char kChromePathJsonValueName[];
+ static const char kPrintersJsonValueName[];
+ static const char kUserDataDirJsonValueName[];
+ static const char kUserNameJsonValueName[];
+ static const wchar_t kSetupPipeName[];
+
+ explicit SetupListener(const string16& user);
+ virtual ~SetupListener();
+
+ virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+ virtual void OnChannelError() OVERRIDE;
+
+ bool WaitResponce(const base::TimeDelta& delta);
+
+ const base::FilePath& chrome_path() const {
+ return chrome_path_;
+ }
+
+ const base::FilePath& user_data_dir() const {
+ return user_data_dir_;
+ }
+
+ const string16& user_name() const {
+ return user_name_;
+ }
+
+ const std::vector<std::string>& printers() const {
+ return printers_;
+ }
+
+ bool is_xps_availible() const {
+ return is_xps_availible_;
+ }
+
+ private:
+ void Disconnect();
+ void Connect(const string16& user);
+
+ base::FilePath chrome_path_;
+ base::FilePath user_data_dir_;
+ string16 user_name_;
+ std::vector<std::string> printers_;
+ bool is_xps_availible_;
+ bool succeded_;
+
+ scoped_ptr<base::WaitableEvent> done_event_;
+ scoped_ptr<base::Thread> ipc_thread_;
+ scoped_ptr<IPC::Channel> channel_;
+};
+
+#endif // CLOUD_PRINT_SERVICE_SETUP_LISTENER_H_
+