summaryrefslogtreecommitdiffstats
path: root/cloud_print/service/win/setup_listener.cc
blob: 57c3a15eb26b47af1db161c2b15e0ca5e078f619 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// 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/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread.h"
#include "base/values.h"
#include "cloud_print/service/win/service_utils.h"
#include "ipc/ipc_channel.h"

const char SetupListener::kXpsAvailableJsonValueName[] = "xps_available";
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 base::string16& user)
    : done_event_(new base::WaitableEvent(true, false)),
      ipc_thread_(new base::Thread("ipc_thread")),
      succeded_(false),
      is_xps_available_(false) {
  ipc_thread_->StartWithOptions(
      base::Thread::Options(base::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) {
  base::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(kXpsAvailableJsonValueName, &is_xps_available_);
  dictionary->GetString(kUserNameJsonValueName, &user_name_);

  base::string16 chrome_path;
  dictionary->GetString(kChromePathJsonValueName, &chrome_path);
  chrome_path_ = base::FilePath(chrome_path);

  base::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 base::string16& user) {
  ATL::CDacl dacl;

  ATL::CSid user_sid;
  if (!user_sid.LoadAccount(ReplaceLocalHostInName(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_ = IPC::Channel::CreateServer(IPC::ChannelHandle(pipe.Get()),
                                          this);
    channel_->Connect();
  }
}