Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / cloud_print / service / win / cloud_print_service_config.cc
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 <atlbase.h>
6 #include <atlapp.h>  // NOLINT
7
8 #include "base/at_exit.h"
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/command_line.h"
12 #include "base/file_util.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/message_loop/message_pump_dispatcher.h"
15 #include "base/run_loop.h"
16 #include "base/strings/string16.h"
17 #include "base/threading/thread.h"
18 #include "chrome/common/chrome_constants.h"
19 #include "cloud_print/common/win/cloud_print_utils.h"
20 #include "cloud_print/resources.h"
21 #include "cloud_print/service/service_state.h"
22 #include "cloud_print/service/win/chrome_launcher.h"
23 #include "cloud_print/service/win/service_controller.h"
24 #include "cloud_print/service/win/service_utils.h"
25 #include "cloud_print/service/win/setup_listener.h"
26
27 using cloud_print::LoadLocalString;
28 using cloud_print::GetErrorMessage;
29
30 class SetupDialog : public base::RefCounted<SetupDialog>,
31                     public ATL::CDialogImpl<SetupDialog> {
32  public:
33   // Enables accelerators.
34   class Dispatcher : public base::MessagePumpDispatcher {
35    public:
36     explicit Dispatcher(SetupDialog* dialog) : dialog_(dialog) {}
37     virtual ~Dispatcher() {};
38
39     // MessagePumpDispatcher:
40     virtual uint32_t Dispatch(const MSG& msg) OVERRIDE {
41       MSG msg2 = msg;
42       uint32_t action = POST_DISPATCH_NONE;
43       if (!dialog_->IsDialogMessage(&msg2))
44         action = POST_DISPATCH_PERFORM_DEFAULT;
45       return action;
46     }
47
48    private:
49     scoped_refptr<SetupDialog> dialog_;
50   };
51
52   typedef ATL::CDialogImpl<SetupDialog> Base;
53   enum { IDD = IDD_SETUP_DIALOG };
54
55   BEGIN_MSG_MAP(SetupDialog)
56     MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
57     MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnCtrColor)
58     MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
59     COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
60     COMMAND_ID_HANDLER(IDC_START, OnStart)
61     COMMAND_ID_HANDLER(IDC_INSTALL, OnInstall)
62     COMMAND_ID_HANDLER(IDC_LOGGING, OnLogging)
63   END_MSG_MAP()
64
65   SetupDialog();
66  private:
67   // Window Message Handlers
68   LRESULT OnInitDialog(UINT message, WPARAM wparam, LPARAM lparam,
69                        BOOL& handled);
70   LRESULT OnCtrColor(UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled);
71   LRESULT OnCancel(UINT, INT nIdentifier, HWND, BOOL& handled);
72   LRESULT OnStart(UINT, INT nIdentifier, HWND, BOOL& handled);
73   LRESULT OnInstall(UINT, INT nIdentifier, HWND, BOOL& handled);
74   LRESULT OnLogging(UINT, INT nIdentifier, HWND, BOOL& handled);
75   LRESULT OnDestroy(UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled);
76
77   void PostUITask(const base::Closure& task);
78   void PostIOTask(const base::Closure& task);
79
80   // UI Calls.
81
82   // Disables all controls after users actions.
83   void DisableControls();
84   // Updates state of controls after when we received service status.
85   void SetState(ServiceController::State state, const base::string16& user,
86                  bool is_logging_enabled);
87   // Show message box with error.
88   void ShowErrorMessageBox(const base::string16& error_message);
89   // Show use message box instructions how to deal with opened Chrome window.
90   void AskToCloseChrome();
91   base::string16 GetDlgItemText(int id) const;
92   base::string16 GetUser() const;
93   base::string16 GetPassword() const;
94   bool IsLoggingEnabled() const;
95   bool IsInstalled() const {
96     return state_ > ServiceController::STATE_NOT_FOUND;
97   }
98
99   // IO Calls.
100   // Installs service.
101   void Install(const base::string16& user, const base::string16& password,
102                bool enable_logging);
103   // Starts service.
104   void Start();
105   // Stops service.
106   void Stop();
107   // Uninstall service.
108   void Uninstall();
109   // Update service state.
110   void UpdateState();
111   // Posts task to UI thread to show error using string id.
112   void ShowError(int string_id);
113   // Posts task to UI thread to show error using string.
114   void ShowError(const base::string16& error_message);
115   // Posts task to UI thread to show error using error code.
116   void ShowError(HRESULT hr);
117
118   ServiceController::State state_;
119   base::Thread worker_;
120
121   base::MessageLoop* ui_loop_;
122   base::MessageLoop* io_loop_;
123
124   ServiceController controller_;
125 };
126
127 SetupDialog::SetupDialog()
128     : state_(ServiceController::STATE_NOT_FOUND),
129       worker_("worker") {
130   ui_loop_ = base::MessageLoop::current();
131   DCHECK(base::MessageLoopForUI::IsCurrent());
132
133   worker_.StartWithOptions(
134       base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
135   io_loop_ = worker_.message_loop();
136   DCHECK(io_loop_->IsType(base::MessageLoop::TYPE_IO));
137 }
138
139 void SetupDialog::PostUITask(const base::Closure& task) {
140   ui_loop_->PostTask(FROM_HERE, task);
141 }
142
143 void SetupDialog::PostIOTask(const base::Closure& task) {
144   io_loop_->PostTask(FROM_HERE, task);
145 }
146
147 void SetupDialog::ShowErrorMessageBox(const base::string16& error_message) {
148   DCHECK(base::MessageLoopForUI::IsCurrent());
149   MessageBox(error_message.c_str(),
150              LoadLocalString(IDS_OPERATION_FAILED_TITLE).c_str(),
151              MB_ICONERROR | MB_OK);
152 }
153
154 void SetupDialog::AskToCloseChrome() {
155   DCHECK(base::MessageLoopForUI::IsCurrent());
156   MessageBox(LoadLocalString(IDS_ADD_PRINTERS_USING_CHROME).c_str(),
157              LoadLocalString(IDS_CONTINUE_IN_CHROME_TITLE).c_str(),
158              MB_OK);
159 }
160
161 void SetupDialog::SetState(ServiceController::State status,
162                            const base::string16& user,
163                            bool is_logging_enabled) {
164   DCHECK(base::MessageLoopForUI::IsCurrent());
165   state_ = status;
166
167   DWORD status_string = 0;
168   switch(status) {
169   case ServiceController::STATE_NOT_FOUND:
170     status_string = IDS_SERVICE_NOT_FOUND;
171     break;
172   case ServiceController::STATE_STOPPED:
173     status_string = IDS_SERVICE_STOPPED;
174     break;
175   case ServiceController::STATE_RUNNING:
176     status_string = IDS_SERVICE_RUNNING;
177     break;
178   }
179   SetDlgItemText(IDC_STATUS,
180                  status_string ? LoadLocalString(status_string).c_str() : L"");
181   if (IsInstalled()) {
182     SetDlgItemText(IDC_USER, user.c_str());
183     CheckDlgButton(IDC_LOGGING,
184                    is_logging_enabled ? BST_CHECKED : BST_UNCHECKED);
185   }
186
187   ATL::CWindow start_button = GetDlgItem(IDC_START);
188   DWORD start_string = (status == ServiceController::STATE_STOPPED) ?
189                        IDS_SERVICE_START : IDS_SERVICE_STOP;
190   start_button.SetWindowText(LoadLocalString(start_string).c_str());
191   start_button.ShowWindow(IsInstalled() ? SW_SHOW : SW_HIDE);
192   start_button.EnableWindow(TRUE);
193
194   ATL::CWindow install_button = GetDlgItem(IDC_INSTALL);
195   DWORD install_string = IsInstalled() ? IDS_SERVICE_UNINSTALL :
196                                          IDS_SERVICE_INSTALL;
197   install_button.SetWindowText(LoadLocalString(install_string).c_str());
198   install_button.ShowWindow(SW_SHOW);
199   install_button.EnableWindow(TRUE);
200
201   if (!IsInstalled()) {
202     GetDlgItem(IDC_USER).EnableWindow(TRUE);
203     GetDlgItem(IDC_PASSWORD).EnableWindow(TRUE);
204     GetDlgItem(IDC_LOGGING).EnableWindow(TRUE);
205   }
206 }
207
208 LRESULT SetupDialog::OnInitDialog(UINT message, WPARAM wparam, LPARAM lparam,
209                                   BOOL& handled) {
210   ATLVERIFY(CenterWindow());
211
212   WTL::CIcon icon;
213   if (icon.LoadIcon(MAKEINTRESOURCE(IDI_ICON))) {
214     SetIcon(icon);
215   }
216
217   SetWindowText(LoadLocalString(IDS_SETUP_PROGRAM_NAME).c_str());
218   SetDlgItemText(IDC_STATE_LABEL, LoadLocalString(IDS_STATE_LABEL).c_str());
219   SetDlgItemText(IDC_USER_LABEL, LoadLocalString(IDS_USER_LABEL).c_str());
220   SetDlgItemText(IDC_PASSWORD_LABEL,
221                  LoadLocalString(IDS_PASSWORD_LABEL).c_str());
222   SetDlgItemText(IDC_LOGGING, LoadLocalString(IDS_LOGGING_LABEL).c_str());
223   SetDlgItemText(IDCANCEL, LoadLocalString(IDS_CLOSE).c_str());
224
225   SetState(ServiceController::STATE_UNKNOWN, L"", false);
226   DisableControls();
227
228   SetDlgItemText(IDC_USER, GetCurrentUserName().c_str());
229
230   PostIOTask(base::Bind(&SetupDialog::UpdateState, this));
231
232   return 0;
233 }
234
235 LRESULT SetupDialog::OnCtrColor(UINT message, WPARAM wparam, LPARAM lparam,
236                                 BOOL& handled) {
237   HWND window = reinterpret_cast<HWND>(lparam);
238   if (GetDlgItem(IDC_LOGO).m_hWnd == window) {
239     return reinterpret_cast<LRESULT>(::GetStockObject(WHITE_BRUSH));
240   }
241   return 0;
242 }
243
244 LRESULT SetupDialog::OnStart(UINT, INT nIdentifier, HWND, BOOL& handled) {
245   DisableControls();
246   DCHECK(IsInstalled());
247   if (state_ == ServiceController::STATE_RUNNING)
248     PostIOTask(base::Bind(&SetupDialog::Stop, this));
249   else
250     PostIOTask(base::Bind(&SetupDialog::Start, this));
251   return 0;
252 }
253
254 LRESULT SetupDialog::OnInstall(UINT, INT nIdentifier, HWND, BOOL& handled) {
255   DisableControls();
256   if (IsInstalled()) {
257     PostIOTask(base::Bind(&SetupDialog::Uninstall, this));
258   } else {
259     PostIOTask(base::Bind(&SetupDialog::Install, this, GetUser(),
260                           GetPassword(), IsLoggingEnabled()));
261   }
262   return 0;
263 }
264
265 LRESULT SetupDialog::OnLogging(UINT, INT nIdentifier, HWND, BOOL& handled) {
266   CheckDlgButton(IDC_LOGGING, IsLoggingEnabled()? BST_UNCHECKED : BST_CHECKED);
267   return 0;
268 }
269
270 LRESULT SetupDialog::OnCancel(UINT, INT nIdentifier, HWND, BOOL& handled) {
271   DestroyWindow();
272   return 0;
273 }
274
275 LRESULT SetupDialog::OnDestroy(UINT message, WPARAM wparam, LPARAM lparam,
276                                BOOL& handled) {
277   base::MessageLoop::current()->PostTask(FROM_HERE,
278                                          base::MessageLoop::QuitClosure());
279   return 1;
280 }
281
282 void SetupDialog::DisableControls() {
283   GetDlgItem(IDC_START).EnableWindow(FALSE);
284   GetDlgItem(IDC_INSTALL).EnableWindow(FALSE);
285   GetDlgItem(IDC_USER).EnableWindow(FALSE);
286   GetDlgItem(IDC_PASSWORD).EnableWindow(FALSE);
287   GetDlgItem(IDC_LOGGING).EnableWindow(FALSE);
288 }
289
290 base::string16 SetupDialog::GetDlgItemText(int id) const {
291   const ATL::CWindow& item = GetDlgItem(id);
292   size_t length = item.GetWindowTextLength();
293   base::string16 result(length + 1, L'\0');
294   result.resize(item.GetWindowText(&result[0], result.size()));
295   return result;
296 }
297
298 base::string16 SetupDialog::GetUser() const {
299   return GetDlgItemText(IDC_USER);
300 }
301
302 base::string16 SetupDialog::GetPassword() const {
303   return GetDlgItemText(IDC_PASSWORD);
304 }
305
306 bool SetupDialog::IsLoggingEnabled() const{
307   return IsDlgButtonChecked(IDC_LOGGING) == BST_CHECKED;
308 }
309
310 void SetupDialog::UpdateState() {
311   DCHECK(base::MessageLoopForIO::IsCurrent());
312   controller_.UpdateState();
313   PostUITask(base::Bind(&SetupDialog::SetState, this, controller_.state(),
314                         controller_.user(), controller_.is_logging_enabled()));
315 }
316
317 void SetupDialog::ShowError(const base::string16& error_message) {
318   DCHECK(base::MessageLoopForIO::IsCurrent());
319   PostUITask(base::Bind(&SetupDialog::SetState,
320                         this,
321                         ServiceController::STATE_UNKNOWN,
322                         L"",
323                         false));
324   PostUITask(base::Bind(&SetupDialog::ShowErrorMessageBox, this,
325                         error_message));
326   LOG(ERROR) << error_message;
327 }
328
329 void SetupDialog::ShowError(int string_id) {
330   ShowError(cloud_print::LoadLocalString(string_id));
331 }
332
333 void SetupDialog::ShowError(HRESULT hr) {
334   ShowError(GetErrorMessage(hr));
335 }
336
337 void SetupDialog::Install(const base::string16& user,
338                           const base::string16& password,
339                           bool enable_logging) {
340   // Don't forget to update state on exit.
341   base::ScopedClosureRunner scoped_update_status(
342         base::Bind(&SetupDialog::UpdateState, this));
343
344   DCHECK(base::MessageLoopForIO::IsCurrent());
345
346   SetupListener setup(GetUser());
347   HRESULT hr = controller_.InstallCheckService(user, password,
348                                                base::FilePath());
349   if (FAILED(hr))
350     return ShowError(hr);
351
352   {
353     // Always uninstall service after requirements check.
354     base::ScopedClosureRunner scoped_uninstall(
355         base::Bind(base::IgnoreResult(&ServiceController::UninstallService),
356                    base::Unretained(&controller_)));
357
358     hr = controller_.StartService();
359     if (FAILED(hr))
360       return ShowError(hr);
361
362     if (!setup.WaitResponce(base::TimeDelta::FromSeconds(30)))
363       return ShowError(IDS_ERROR_FAILED_START_SERVICE);
364   }
365
366   if (setup.user_data_dir().empty())
367     return ShowError(IDS_ERROR_NO_DATA_DIR);
368
369   if (setup.chrome_path().empty())
370     return ShowError(IDS_ERROR_NO_CHROME);
371
372   if (!setup.is_xps_available())
373     return ShowError(IDS_ERROR_NO_XPS);
374
375   base::FilePath file = setup.user_data_dir();
376   file = file.Append(chrome::kServiceStateFileName);
377
378   std::string proxy_id;
379   std::string contents;
380
381   if (base::ReadFileToString(file, &contents)) {
382     ServiceState service_state;
383     if (service_state.FromString(contents))
384       proxy_id = service_state.proxy_id();
385   }
386   PostUITask(base::Bind(&SetupDialog::AskToCloseChrome, this));
387   contents = ChromeLauncher::CreateServiceStateFile(proxy_id, setup.printers());
388
389   if (contents.empty())
390     return ShowError(IDS_ERROR_FAILED_CREATE_CONFIG);
391
392   size_t written = file_util::WriteFile(file, contents.c_str(),
393                                         contents.size());
394   if (written != contents.size()) {
395     DWORD last_error = GetLastError();
396     if (!last_error)
397       return ShowError(IDS_ERROR_FAILED_CREATE_CONFIG);
398     return ShowError(HRESULT_FROM_WIN32(last_error));
399   }
400
401   hr = controller_.InstallConnectorService(user, password, base::FilePath(),
402                                            enable_logging);
403   if (FAILED(hr))
404     return ShowError(hr);
405
406   hr = controller_.StartService();
407   if (FAILED(hr))
408     return ShowError(hr);
409 }
410
411 void SetupDialog::Start() {
412   DCHECK(base::MessageLoopForIO::IsCurrent());
413   HRESULT hr = controller_.StartService();
414   if (FAILED(hr))
415     ShowError(hr);
416   UpdateState();
417 }
418
419 void SetupDialog::Stop() {
420   DCHECK(base::MessageLoopForIO::IsCurrent());
421   HRESULT hr = controller_.StopService();
422   if (FAILED(hr))
423     ShowError(hr);
424   UpdateState();
425 }
426
427 void SetupDialog::Uninstall() {
428   DCHECK(base::MessageLoopForIO::IsCurrent());
429   HRESULT hr = controller_.UninstallService();
430   if (FAILED(hr))
431     ShowError(hr);
432   UpdateState();
433 }
434
435 class CloudPrintServiceConfigModule
436     : public ATL::CAtlExeModuleT<CloudPrintServiceConfigModule> {
437 };
438
439 CloudPrintServiceConfigModule _AtlModule;
440
441 int WINAPI WinMain(__in  HINSTANCE hInstance,
442                    __in  HINSTANCE hPrevInstance,
443                    __in  LPSTR lpCmdLine,
444                    __in  int nCmdShow) {
445   base::AtExitManager at_exit;
446   CommandLine::Init(0, NULL);
447
448   base::MessageLoopForUI loop;
449   scoped_refptr<SetupDialog> dialog(new SetupDialog());
450   dialog->Create(NULL);
451   dialog->ShowWindow(SW_SHOW);
452   SetupDialog::Dispatcher dispatcher(dialog);
453   base::RunLoop run_loop(&dispatcher);
454   run_loop.Run();
455   return 0;
456 }