Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(40)

Side by Side Diff: cloud_print/service/win/cloud_print_service.cc

Issue 10919262: Improved cloud print service installation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « cloud_print/service/service_switches.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "cloud_print/service/win/cloud_print_service.h" 5 #include "cloud_print/service/win/cloud_print_service.h"
6 6
7 #include <atlsecurity.h> 7 #define SECURITY_WIN32
8 #include <security.h>
9
8 #include <iomanip> 10 #include <iomanip>
9 #include <iostream> 11 #include <iostream>
10 12
11 #include "base/at_exit.h" 13 #include "base/at_exit.h"
12 #include "base/command_line.h" 14 #include "base/command_line.h"
13 #include "base/file_path.h" 15 #include "base/file_path.h"
14 #include "base/file_util.h" 16 #include "base/file_util.h"
17 #include "base/guid.h"
15 #include "base/path_service.h" 18 #include "base/path_service.h"
16 #include "base/string_util.h" 19 #include "base/string_util.h"
20 #include "base/utf_string_conversions.h"
17 #include "base/win/scoped_handle.h" 21 #include "base/win/scoped_handle.h"
18 #include "chrome/installer/launcher_support/chrome_launcher_support.h" 22 #include "chrome/installer/launcher_support/chrome_launcher_support.h"
19 #include "cloud_print/service/service_state.h" 23 #include "cloud_print/service/service_state.h"
20 #include "cloud_print/service/service_switches.h" 24 #include "cloud_print/service/service_switches.h"
21 #include "cloud_print/service/win/chrome_launcher.h" 25 #include "cloud_print/service/win/chrome_launcher.h"
22 #include "cloud_print/service/win/local_security_policy.h" 26 #include "cloud_print/service/win/local_security_policy.h"
23 #include "cloud_print/service/win/resource.h" 27 #include "cloud_print/service/win/resource.h"
28 #include "printing/backend/print_backend.h"
24 29
25 namespace { 30 namespace {
26 31
32 const wchar_t kPrintersFileName[] = L"printers.txt";
27 const wchar_t kServiceStateFileName[] = L"Service State"; 33 const wchar_t kServiceStateFileName[] = L"Service State";
28 34
29 // The traits class for Windows Service. 35 // The traits class for Windows Service.
30 class ServiceHandleTraits { 36 class ServiceHandleTraits {
31 public: 37 public:
32 typedef SC_HANDLE Handle; 38 typedef SC_HANDLE Handle;
33 39
34 // Closes the handle. 40 // Closes the handle.
35 static bool CloseHandle(Handle handle) { 41 static bool CloseHandle(Handle handle) {
36 return ::CloseServiceHandle(handle) != FALSE; 42 return ::CloseServiceHandle(handle) != FALSE;
(...skipping 26 matching lines...) Expand all
63 FilePath service_path; 69 FilePath service_path;
64 CHECK(PathService::Get(base::FILE_EXE, &service_path)); 70 CHECK(PathService::Get(base::FILE_EXE, &service_path));
65 71
66 std::cout << "Usage: "; 72 std::cout << "Usage: ";
67 std::cout << service_path.BaseName().value(); 73 std::cout << service_path.BaseName().value();
68 std::cout << " ["; 74 std::cout << " [";
69 std::cout << "["; 75 std::cout << "[";
70 std::cout << "["; 76 std::cout << "[";
71 std::cout << " -" << kInstallSwitch; 77 std::cout << " -" << kInstallSwitch;
72 std::cout << " -" << kUserDataDirSwitch << "=DIRECTORY"; 78 std::cout << " -" << kUserDataDirSwitch << "=DIRECTORY";
73 std::cout << " -" << kRunAsUser << "=USERNAME";
74 std::cout << " -" << kRunAsPassword << "=PASSWORD";
75 std::cout << " [ -" << kQuietSwitch << " ]";
76 std::cout << "]"; 79 std::cout << "]";
77 std::cout << "]"; 80 std::cout << "]";
78 std::cout << " | -" << kUninstallSwitch; 81 std::cout << " | -" << kUninstallSwitch;
79 std::cout << " | -" << kStartSwitch; 82 std::cout << " | -" << kStartSwitch;
80 std::cout << " | -" << kStopSwitch; 83 std::cout << " | -" << kStopSwitch;
81 std::cout << " ]\n"; 84 std::cout << " ]\n";
82 std::cout << "Manages cloud print windows service.\n\n"; 85 std::cout << "Manages cloud print windows service.\n\n";
83 86
84 static const struct { 87 static const struct {
85 const char* name; 88 const char* name;
86 const char* description; 89 const char* description;
87 } kSwitchHelp[] = { 90 } kSwitchHelp[] = {
88 { kInstallSwitch, "Installs cloud print as service." }, 91 { kInstallSwitch, "Installs cloud print as service." },
89 { kUserDataDirSwitch, "User data directory with \"Service State\" file." }, 92 { kUserDataDirSwitch, "User data directory with \"Service State\" file." },
90 { kQuietSwitch, "Fails without questions if something wrong." },
91 { kUninstallSwitch, "Uninstalls service." }, 93 { kUninstallSwitch, "Uninstalls service." },
92 { kStartSwitch, "Starts service. May be combined with installation." }, 94 { kStartSwitch, "Starts service. May be combined with installation." },
93 { kStopSwitch, "Stops service." }, 95 { kStopSwitch, "Stops service." },
94 { kRunAsUser, "Windows user to run the service in form DOMAIN\\USERNAME. "
95 "Make sure user has access to printers." },
96 { kRunAsPassword, "Password for windows user to run the service" },
97 }; 96 };
98 97
99 for (size_t i = 0; i < arraysize(kSwitchHelp); ++i) { 98 for (size_t i = 0; i < arraysize(kSwitchHelp); ++i) {
100 std::cout << std::setiosflags(std::ios::left); 99 std::cout << std::setiosflags(std::ios::left);
101 std::cout << " -" << std::setw(16) << kSwitchHelp[i].name; 100 std::cout << " -" << std::setw(16) << kSwitchHelp[i].name;
102 std::cout << kSwitchHelp[i].description << "\n"; 101 std::cout << kSwitchHelp[i].description << "\n";
103 } 102 }
104 std::cout << "\n"; 103 std::cout << "\n";
105 } 104 }
106 105
107 std::string GetOption(const std::string& name, const std::string& default, 106 std::string GetOption(const std::string& name, const std::string& default,
108 bool secure) { 107 bool secure) {
109 std::cout << "Input \'" << name << "\'"; 108 std::cout << name;
110 if (!default.empty()) { 109 if (!default.empty()) {
111 std::cout << ", press [ENTER] to keep '"; 110 std::cout << ", press [ENTER] to keep '";
112 std::cout << default; 111 std::cout << default;
113 std::cout << "'"; 112 std::cout << "'";
114 } 113 }
115 std::cout << ":"; 114 std::cout << ": ";
116 std::string tmp; 115 std::string tmp;
117 116
118 if (secure) { 117 if (secure) {
119 DWORD saved_mode = 0; 118 DWORD saved_mode = 0;
120 // Don't close. 119 // Don't close.
121 HANDLE stdin_handle = ::GetStdHandle(STD_INPUT_HANDLE); 120 HANDLE stdin_handle = ::GetStdHandle(STD_INPUT_HANDLE);
122 ::GetConsoleMode(stdin_handle, &saved_mode); 121 ::GetConsoleMode(stdin_handle, &saved_mode);
123 ::SetConsoleMode(stdin_handle, saved_mode & ~ENABLE_ECHO_INPUT); 122 ::SetConsoleMode(stdin_handle, saved_mode & ~ENABLE_ECHO_INPUT);
124 std::getline(std::cin, tmp); 123 std::getline(std::cin, tmp);
125 ::SetConsoleMode(stdin_handle, saved_mode); 124 ::SetConsoleMode(stdin_handle, saved_mode);
126 std::cout << "\n"; 125 std::cout << "\n";
127 } else { 126 } else {
128 std::getline(std::cin, tmp); 127 std::getline(std::cin, tmp);
129 } 128 }
130 if (tmp.empty()) 129 if (tmp.empty())
131 return default; 130 return default;
132 return tmp; 131 return tmp;
133 } 132 }
134 133
135 HRESULT WriteFileAsUser(const FilePath& path, const string16& user, 134 bool AskUser(const std::string& request) {
136 const char* data, int size) { 135 for (;;) {
137 ATL::CAccessToken token; 136 std::cout << request << " [Y/n]:";
138 ATL::CAutoRevertImpersonation auto_revert(&token); 137 std::string input;
139 if (!user.empty()) { 138 std::getline(std::cin, input);
140 ATL::CAccessToken thread_token; 139 StringToLowerASCII(&input);
141 if (!thread_token.OpenThreadToken(TOKEN_DUPLICATE | TOKEN_IMPERSONATE)) { 140 if (input.empty() || input == "y") {
142 LOG(ERROR) << "Failed to open thread token."; 141 return true;
143 return HResultFromLastError(); 142 } else if (input == "n") {
144 } 143 return false;
144 }
145 }
146 }
145 147
146 ATL::CSid local_service; 148 string16 GetCurrentUserName() {
147 if (!local_service.LoadAccount(user.c_str())) { 149 ULONG size = 0;
148 LOG(ERROR) << "Failed create SID."; 150 string16 result;
149 return HResultFromLastError(); 151 ::GetUserNameEx(::NameSamCompatible, NULL, &size);
150 } 152 result.resize(size);
151 153 if (result.empty())
152 ATL::CTokenGroups group; 154 return result;
153 group.Add(local_service, 0); 155 if (!::GetUserNameEx(::NameSamCompatible, &result[0], &size))
154 156 result.clear();
155 const ATL::CTokenGroups empty_group; 157 result.resize(size);
156 if (!thread_token.CreateRestrictedToken(&token, empty_group, group)) { 158 return result;
157 LOG(ERROR) << "Failed to create restricted token for " << user << ".";
158 return HResultFromLastError();
159 }
160
161 if (!token.Impersonate()) {
162 LOG(ERROR) << "Failed to impersonate " << user << ".";
163 return HResultFromLastError();
164 }
165 }
166 if (file_util::WriteFile(path, data, size) != size) {
167 LOG(ERROR) << "Failed to write file " << path.value() << ".";
168 return HResultFromLastError();
169 }
170 return S_OK;
171 } 159 }
172 160
173 } // namespace 161 } // namespace
174 162
175 class CloudPrintServiceModule 163 class CloudPrintServiceModule
176 : public ATL::CAtlServiceModuleT<CloudPrintServiceModule, IDS_SERVICENAME> { 164 : public ATL::CAtlServiceModuleT<CloudPrintServiceModule, IDS_SERVICENAME> {
177 public: 165 public:
178 typedef ATL::CAtlServiceModuleT<CloudPrintServiceModule, 166 typedef ATL::CAtlServiceModuleT<CloudPrintServiceModule,
179 IDS_SERVICENAME> Base; 167 IDS_SERVICENAME> Base;
180 168
181 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE, 169 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE,
182 "{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}") 170 "{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}")
183 171
172 CloudPrintServiceModule() : detect_printers_(false) {
173 }
174
184 HRESULT InitializeSecurity() { 175 HRESULT InitializeSecurity() {
185 // TODO(gene): Check if we need to call CoInitializeSecurity and provide 176 // TODO(gene): Check if we need to call CoInitializeSecurity and provide
186 // the appropriate security settings for service. 177 // the appropriate security settings for service.
187 return S_OK; 178 return S_OK;
188 } 179 }
189 180
190 HRESULT InstallService(const string16& user, const string16& password) { 181 HRESULT InstallService(const string16& user,
182 const string16& password,
183 const char* run_switch) {
191 using namespace chrome_launcher_support; 184 using namespace chrome_launcher_support;
192 185
193 // TODO(vitalybuka): consider "lite" version if we don't want unregister 186 // TODO(vitalybuka): consider "lite" version if we don't want unregister
194 // printers here. 187 // printers here.
195 HRESULT hr = UninstallService(); 188 HRESULT hr = UninstallService();
196 if (FAILED(hr)) 189 if (FAILED(hr))
197 return hr; 190 return hr;
198 191
199 if (GetChromePathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION).empty()) { 192 if (GetChromePathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION).empty()) {
200 LOG(WARNING) << "Found no Chrome installed for all users."; 193 LOG(WARNING) << "Found no Chrome installed for all users.";
201 } 194 }
202 195
203 hr = UpdateRegistryAppId(true); 196 hr = UpdateRegistryAppId(true);
204 if (FAILED(hr)) 197 if (FAILED(hr))
205 return hr; 198 return hr;
206 199
207 FilePath service_path; 200 FilePath service_path;
208 CHECK(PathService::Get(base::FILE_EXE, &service_path)); 201 CHECK(PathService::Get(base::FILE_EXE, &service_path));
209 CommandLine command_line(service_path); 202 CommandLine command_line(service_path);
210 command_line.AppendSwitch(kServiceSwitch); 203 command_line.AppendSwitch(run_switch);
211 command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir_); 204 command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir_);
212 205
213 LocalSecurityPolicy local_security_policy; 206 LocalSecurityPolicy local_security_policy;
214 if (local_security_policy.Open()) { 207 if (local_security_policy.Open()) {
215 if (!local_security_policy.IsPrivilegeSet(user, kSeServiceLogonRight)) { 208 if (!local_security_policy.IsPrivilegeSet(user, kSeServiceLogonRight)) {
216 LOG(WARNING) << "Setting " << kSeServiceLogonRight << " for " << user; 209 LOG(WARNING) << "Setting " << kSeServiceLogonRight << " for " << user;
217 if (!local_security_policy.SetPrivilege(user, kSeServiceLogonRight)) { 210 if (!local_security_policy.SetPrivilege(user, kSeServiceLogonRight)) {
218 LOG(ERROR) << "Failed to set" << kSeServiceLogonRight; 211 LOG(ERROR) << "Failed to set" << kSeServiceLogonRight;
219 LOG(ERROR) << "Make sure you can run the service with this user."; 212 LOG(ERROR) << "Make sure you can run the service as " << user << ".";
220 } 213 }
221 } 214 }
222 } else { 215 } else {
223 LOG(ERROR) << "Failed to open security policy."; 216 LOG(ERROR) << "Failed to open security policy.";
224 } 217 }
225 218
226 ServiceHandle scm; 219 ServiceHandle scm;
227 hr = OpenServiceManager(&scm); 220 hr = OpenServiceManager(&scm);
228 if (FAILED(hr)) 221 if (FAILED(hr))
229 return hr; 222 return hr;
230 223
231 ServiceHandle service( 224 ServiceHandle service(
232 ::CreateService( 225 ::CreateService(
233 scm, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS, 226 scm, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS,
234 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, 227 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
235 command_line.GetCommandLineString().c_str(), NULL, NULL, NULL, 228 command_line.GetCommandLineString().c_str(), NULL, NULL, NULL,
236 user.empty() ? NULL : user.c_str(), 229 user.empty() ? NULL : user.c_str(),
237 password.empty() ? NULL : password.c_str())); 230 password.empty() ? NULL : password.c_str()));
238 231
239 if (!service.IsValid()) 232 if (!service.IsValid()) {
233 LOG(ERROR) << "Failed to install service as " << user << ".";
240 return HResultFromLastError(); 234 return HResultFromLastError();
235 }
241 236
242 return S_OK; 237 return S_OK;
243 } 238 }
244 239
245 HRESULT UninstallService() { 240 HRESULT UninstallService() {
241 StopService();
246 if (!Uninstall()) 242 if (!Uninstall())
247 return E_FAIL; 243 return E_FAIL;
248 return UpdateRegistryAppId(false); 244 return UpdateRegistryAppId(false);
249 } 245 }
250 246
251 bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode) { 247 bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode) {
252 CHECK(pnRetCode); 248 CHECK(pnRetCode);
253 CommandLine command_line(CommandLine::NO_PROGRAM); 249 CommandLine command_line(CommandLine::NO_PROGRAM);
254 command_line.ParseFromString(lpCmdLine); 250 command_line.ParseFromString(lpCmdLine);
255 bool is_service = false; 251 bool is_service = false;
256 *pnRetCode = ParseCommandLine(command_line, &is_service); 252 *pnRetCode = ParseCommandLine(command_line, &is_service);
257 if (FAILED(*pnRetCode)) { 253 if (FAILED(*pnRetCode)) {
258 LOG(ERROR) << "Operation failed. 0x" << std::setw(8) << 254 LOG(ERROR) << "Operation failed. 0x" << std::setw(8) <<
259 std::setbase(16) << *pnRetCode; 255 std::setbase(16) << *pnRetCode;
260 } 256 }
261 return is_service; 257 return is_service;
262 } 258 }
263 259
264 HRESULT PreMessageLoop(int nShowCmd) { 260 HRESULT PreMessageLoop(int nShowCmd) {
265 HRESULT hr = Base::PreMessageLoop(nShowCmd); 261 HRESULT hr = Base::PreMessageLoop(nShowCmd);
266 if (FAILED(hr)) 262 if (FAILED(hr))
267 return hr; 263 return hr;
268 264
269 hr = StartConnector(); 265 if (detect_printers_) {
270 if (FAILED(hr)) 266 hr = DetectPrinters();
271 return hr; 267 if (FAILED(hr))
268 return hr;
269 // Don't run message loop and stop service.
270 return S_FALSE;
271 } else {
272 hr = StartConnector();
273 if (FAILED(hr))
274 return hr;
275 }
272 276
273 LogEvent(_T("Service started/resumed")); 277 LogEvent(_T("Service started/resumed"));
274 SetServiceStatus(SERVICE_RUNNING); 278 SetServiceStatus(SERVICE_RUNNING);
275 279
276 return hr; 280 return hr;
277 } 281 }
278 282
279 HRESULT PostMessageLoop() { 283 HRESULT PostMessageLoop() {
280 StopConnector(); 284 StopConnector();
281 return Base::PostMessageLoop(); 285 return Base::PostMessageLoop();
282 } 286 }
283 287
284 private: 288 private:
285 HRESULT ParseCommandLine(const CommandLine& command_line, bool* is_service) { 289 HRESULT ParseCommandLine(const CommandLine& command_line, bool* is_service) {
286 if (!is_service) 290 if (!is_service)
287 return E_INVALIDARG; 291 return E_INVALIDARG;
288 *is_service = false; 292 *is_service = false;
289 293
290 user_data_dir_ = command_line.GetSwitchValuePath(kUserDataDirSwitch); 294 user_data_dir_ = command_line.GetSwitchValuePath(kUserDataDirSwitch);
291 if (command_line.HasSwitch(kStopSwitch)) 295 if (command_line.HasSwitch(kStopSwitch))
292 return StopService(); 296 return StopService();
293 297
294 if (command_line.HasSwitch(kUninstallSwitch)) 298 if (command_line.HasSwitch(kUninstallSwitch))
295 return UninstallService(); 299 return UninstallService();
296 300
297 if (command_line.HasSwitch(kInstallSwitch)) { 301 if (command_line.HasSwitch(kInstallSwitch)) {
298 if (!command_line.HasSwitch(kUserDataDirSwitch) || 302 if (!command_line.HasSwitch(kUserDataDirSwitch)) {
299 !command_line.HasSwitch(kRunAsUser) ||
300 !command_line.HasSwitch(kRunAsPassword)) {
301 InvalidUsage(); 303 InvalidUsage();
302 return S_FALSE; 304 return S_FALSE;
303 } 305 }
304 306
305 HRESULT hr = ProcessServiceState(command_line.HasSwitch(kQuietSwitch)); 307 string16 run_as_user;
308 string16 run_as_password;
309 SelectWindowsAccount(&run_as_user, &run_as_password);
310
311 HRESULT hr = SetupServiceState();
306 if (FAILED(hr)) 312 if (FAILED(hr))
307 return hr; 313 return hr;
308 314
309 CommandLine::StringType run_as_user = 315 hr = InstallService(run_as_user.c_str(), run_as_password.c_str(),
310 command_line.GetSwitchValueNative(kRunAsUser); 316 kServiceSwitch);
311 CommandLine::StringType run_as_password =
312 command_line.GetSwitchValueNative(kRunAsPassword);
313
314 hr = ValidateUserDataDir(run_as_user.c_str());
315
316 hr = InstallService(run_as_user.c_str(), run_as_password.c_str());
317 if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch)) 317 if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch))
318 return StartService(); 318 return StartService();
319 319
320 return hr; 320 return hr;
321 } 321 }
322 322
323 if (command_line.HasSwitch(kStartSwitch)) 323 if (command_line.HasSwitch(kStartSwitch))
324 return StartService(); 324 return StartService();
325 325
326 if (command_line.HasSwitch(kServiceSwitch)) { 326 if (command_line.HasSwitch(kServiceSwitch) ||
327 command_line.HasSwitch(kPrintersSwitch)) {
327 *is_service = true; 328 *is_service = true;
329 detect_printers_ = command_line.HasSwitch(kPrintersSwitch);
328 return S_OK; 330 return S_OK;
329 } 331 }
330 332
331 if (command_line.HasSwitch(kConsoleSwitch)) { 333 if (command_line.HasSwitch(kConsoleSwitch)) {
332 ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE); 334 ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE);
333 HRESULT hr = Run(); 335 HRESULT hr = Run();
334 ::SetConsoleCtrlHandler(NULL, FALSE); 336 ::SetConsoleCtrlHandler(NULL, FALSE);
335 return hr; 337 return hr;
336 } 338 }
337 339
338 InvalidUsage(); 340 InvalidUsage();
339 return S_FALSE; 341 return S_FALSE;
340 } 342 }
341 343
342 HRESULT ValidateUserDataDir(const string16& user) { 344 void SelectWindowsAccount(string16* run_as_user,
343 FilePath temp_file; 345 string16* run_as_password) {
344 const char some_data[] = "1234"; 346 *run_as_user = GetCurrentUserName();
345 if (!file_util::CreateTemporaryFileInDir(user_data_dir_, &temp_file)) 347 for (;;) {
346 return E_FAIL; 348 std::cout << "\nPlease provide Windows account to run service.\n";
347 HRESULT hr = WriteFileAsUser(temp_file, user, some_data, 349 *run_as_user = ASCIIToWide(GetOption("Account as DOMAIN\\USERNAME",
348 sizeof(some_data)); 350 WideToASCII(*run_as_user), false));
349 if (FAILED(hr)) { 351 *run_as_password = ASCIIToWide(GetOption("Password", "", true));
350 LOG(ERROR) << "Failed to write user data. Make sure that account \'" << 352
351 user << "\' has full access to \'" << 353 FilePath printers_filename(user_data_dir_);
352 user_data_dir_.value() << "\'."; 354 printers_filename = printers_filename.Append(kPrintersFileName);
355
356 file_util::Delete(printers_filename, false);
357 if (FAILED(InstallService(run_as_user->c_str(),
358 run_as_password->c_str(),
359 kPrintersSwitch))) {
360 continue;
361 }
362 if (FAILED(StartService())) {
363 LOG(ERROR) << "Failed to start service as " << *run_as_user << ".";
364 continue;
365 }
366 UninstallService();
367 if (!file_util::PathExists(printers_filename)) {
368 LOG(ERROR) << "Service can't create " << printers_filename.value();
369 continue;
370 }
371
372 std::string printers;
373 file_util::ReadFileToString(printers_filename, &printers);
374 std::cout << "\nPrinters available for " << run_as_user << ":\n";
375 std::cout << printers << "\n";
376 file_util::Delete(printers_filename, false);
377
378 if (AskUser("Do you want to use " + WideToASCII(*run_as_user) + "?"))
379 return;
353 } 380 }
354 file_util::Delete(temp_file, false);
355 return hr;
356 } 381 }
357 382
358 HRESULT ProcessServiceState(bool quiet) { 383 HRESULT SetupServiceState() {
359 FilePath file = user_data_dir_.Append(kServiceStateFileName); 384 FilePath file = user_data_dir_.Append(kServiceStateFileName);
360 385
361 for (;;) { 386 for (;;) {
362 std::string contents; 387 std::string contents;
363 ServiceState service_state; 388 ServiceState service_state;
364 389
365 bool is_valid = file_util::ReadFileToString(file, &contents) && 390 bool is_valid = file_util::ReadFileToString(file, &contents) &&
366 service_state.FromString(contents); 391 service_state.FromString(contents);
367 392
368 if (!quiet) { 393 std::cout << "\nFile '" << file.value() << "' content:\n";
369 std::cout << "\n"; 394 std::cout << contents << "\n";
370 std::cout << file.value() << ":\n";
371 std::cout << contents << "\n";
372 }
373 395
374 if (!is_valid) 396 if (!is_valid)
375 LOG(ERROR) << "Invalid file: " << file.value(); 397 LOG(ERROR) << "Invalid file: " << file.value();
376 398
377 if (quiet)
378 return is_valid ? S_OK : HRESULT_FROM_WIN32(ERROR_FILE_INVALID);
379
380 if (!contents.empty()) { 399 if (!contents.empty()) {
381 std::cout << "Do you want to use this file [y/n]:"; 400 if (AskUser("Do you want to use '" + WideToASCII(file.value()) + "'")) {
382 for (;;) { 401 return S_OK;
383 std::string input; 402 } else {
384 std::getline(std::cin, input); 403 is_valid = false;
385 StringToLowerASCII(&input);
386 if (input == "y") {
387 return S_OK;
388 } else if (input == "n") {
389 is_valid = false;
390 break;
391 }
392 } 404 }
393 } 405 }
394 406
395 while (!is_valid) { 407 while (!is_valid) {
408 std::cout << "\nPlease provide Cloud Print Settings.\n";
396 std::string email = GetOption("email", service_state.email(), false); 409 std::string email = GetOption("email", service_state.email(), false);
397 std::string password = GetOption("password", "", true); 410 std::string password = GetOption("password", "", true);
398 std::string proxy_id = GetOption("connector_id", 411 std::string proxy_id = service_state.proxy_id();
399 service_state.proxy_id(), false); 412 if (proxy_id.empty())
413 proxy_id = base::GenerateGUID();
414 proxy_id = GetOption("connector_id", proxy_id, false);
400 is_valid = service_state.Configure(email, password, proxy_id); 415 is_valid = service_state.Configure(email, password, proxy_id);
401 if (is_valid) { 416 if (is_valid) {
402 std::string new_contents = service_state.ToString(); 417 std::string new_contents = service_state.ToString();
403 if (new_contents != contents) { 418 if (new_contents != contents) {
404 size_t written = file_util::WriteFile(file, new_contents.c_str(), 419 size_t written = file_util::WriteFile(file, new_contents.c_str(),
405 new_contents.size()); 420 new_contents.size());
406 if (written != new_contents.size()) { 421 if (written != new_contents.size()) {
407 LOG(ERROR) << "Failed to write file " << file.value() << "."; 422 LOG(ERROR) << "Failed to write file " << file.value() << ".";
408 return HResultFromLastError(); 423 return HResultFromLastError();
409 } 424 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
448 HRESULT hr = OpenService(SERVICE_START, &service); 463 HRESULT hr = OpenService(SERVICE_START, &service);
449 if (FAILED(hr)) 464 if (FAILED(hr))
450 return hr; 465 return hr;
451 if (!::StartService(service, 0, NULL)) 466 if (!::StartService(service, 0, NULL))
452 return HResultFromLastError(); 467 return HResultFromLastError();
453 return S_OK; 468 return S_OK;
454 } 469 }
455 470
456 HRESULT StopService() { 471 HRESULT StopService() {
457 ServiceHandle service; 472 ServiceHandle service;
458 HRESULT hr = OpenService(SERVICE_STOP, &service); 473 HRESULT hr = OpenService(SERVICE_STOP | SERVICE_QUERY_STATUS, &service);
459 if (FAILED(hr)) 474 if (FAILED(hr))
460 return hr; 475 return hr;
461 SERVICE_STATUS status = {0}; 476 SERVICE_STATUS status = {0};
462 if (!::ControlService(service, SERVICE_CONTROL_STOP, &status)) 477 if (!::ControlService(service, SERVICE_CONTROL_STOP, &status))
463 return HResultFromLastError(); 478 return HResultFromLastError();
479 while (::QueryServiceStatus(service, &status) &&
480 status.dwCurrentState > SERVICE_STOPPED) {
481 Sleep(500);
482 }
464 return S_OK; 483 return S_OK;
465 } 484 }
466 485
486 HRESULT DetectPrinters() {
487 FilePath printers_filename(user_data_dir_);
488 printers_filename = printers_filename.Append(kPrintersFileName);
489 std::string printers;
490 scoped_refptr<printing::PrintBackend> backend(
491 printing::PrintBackend::CreateInstance(NULL));
492 printing::PrinterList printer_list;
493 backend->EnumeratePrinters(&printer_list);
494 for (size_t i = 0; i < printer_list.size(); ++i) {
495 printers += printer_list[i].printer_name;
496 printers += "\n";
497 }
498 file_util::WriteFile(printers_filename, printers.c_str(), printers.size());
499 return S_OK;
500 }
501
467 HRESULT StartConnector() { 502 HRESULT StartConnector() {
468 chrome_.reset(new ChromeLauncher(user_data_dir_)); 503 chrome_.reset(new ChromeLauncher(user_data_dir_));
469 return chrome_->Start() ? S_OK : E_FAIL; 504 return chrome_->Start() ? S_OK : E_FAIL;
470 } 505 }
471 506
472 void StopConnector() { 507 void StopConnector() {
473 chrome_->Stop(); 508 if (chrome_.get()) {
474 chrome_.reset(); 509 chrome_->Stop();
510 chrome_.reset();
511 }
475 } 512 }
476 513
477 static BOOL WINAPI ConsoleCtrlHandler(DWORD type); 514 static BOOL WINAPI ConsoleCtrlHandler(DWORD type);
478 515
516 bool detect_printers_;
479 FilePath user_data_dir_; 517 FilePath user_data_dir_;
480 scoped_ptr<ChromeLauncher> chrome_; 518 scoped_ptr<ChromeLauncher> chrome_;
481 }; 519 };
482 520
483 CloudPrintServiceModule _AtlModule; 521 CloudPrintServiceModule _AtlModule;
484 522
485 BOOL CloudPrintServiceModule::ConsoleCtrlHandler(DWORD type) { 523 BOOL CloudPrintServiceModule::ConsoleCtrlHandler(DWORD type) {
486 PostThreadMessage(_AtlModule.m_dwThreadID, WM_QUIT, 0, 0); 524 PostThreadMessage(_AtlModule.m_dwThreadID, WM_QUIT, 0, 0);
487 return TRUE; 525 return TRUE;
488 } 526 }
489 527
490 int main() { 528 int main() {
491 base::AtExitManager at_exit; 529 base::AtExitManager at_exit;
492 return _AtlModule.WinMain(0); 530 return _AtlModule.WinMain(0);
493 } 531 }
OLDNEW
« no previous file with comments | « cloud_print/service/service_switches.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698