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