~ubuntu-branches/ubuntu/oneiric/mozc/oneiric

« back to all changes in this revision

Viewing changes to client/session.cc

  • Committer: Bazaar Package Importer
  • Author(s): Nobuhiro Iwamatsu
  • Date: 2010-07-14 03:26:47 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100714032647-13qjisj6m8cm8jdx
Tags: 0.12.410.102-1
* New upstream release (Closes: #588971).
  - Add mozc-server, mozc-utils-gui and scim-mozc packages.
* Update debian/rules.
  Add --gypdir option to build_mozc.py.
* Update debian/control.
  - Bumped standards-version to 3.9.0.
  - Update description.
* Add mozc icon (Closes: #588972).
* Add patch which revises issue 18.
  ibus_mozc_issue18.patch
* kFreeBSD build support.
  support_kfreebsd.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
34
34
#include <stdio.h>
35
35
 
36
36
#include "base/base.h"
 
37
#include "base/const.h"
37
38
#include "base/crash_report_util.h"
38
39
#include "base/file_stream.h"
 
40
#include "base/process.h"
 
41
#include "base/run_level.h"
39
42
#include "base/util.h"
40
43
#include "base/version.h"
41
44
#include "ipc/ipc.h"
42
45
#include "session/commands.pb.h"
43
46
 
 
47
#ifdef OS_MACOSX
 
48
#include "base/mac_process.h"
 
49
#endif
 
50
 
44
51
namespace mozc {
45
52
namespace client {
46
53
 
66
73
 
67
74
Session::Session()
68
75
    : id_(0),
69
 
      start_server_handler_(new StartServerHandler),
 
76
      server_launcher_(new ServerLauncher),
70
77
      result_(new char[kResultBufferSize]),
71
78
      preferences_(NULL),
72
79
      timeout_(kDefaultTimeout),
73
80
      server_status_(SERVER_UNKNOWN),
74
81
      server_protocol_version_(0),
75
 
      server_process_id_(0) {
 
82
      server_process_id_(0),
 
83
      last_mode_(commands::DIRECT) {
76
84
  client_factory_ = IPCClientFactory::GetIPCClientFactory();
77
85
}
78
86
 
85
93
  client_factory_ = client_factory;
86
94
}
87
95
 
88
 
void Session::SetStartServerHandler(
89
 
    StartServerHandlerInterface *start_server_handler) {
90
 
  start_server_handler_.reset(start_server_handler);
 
96
void Session::SetServerLauncher(
 
97
    ServerLauncherInterface *server_launcher) {
 
98
  server_launcher_.reset(server_launcher);
 
99
}
 
100
 
 
101
bool Session::IsValidRunLevel() const {
 
102
  return RunLevel::IsValidClientRunLevel();
91
103
}
92
104
 
93
105
bool Session::EnsureConnection() {
101
113
      return false;
102
114
      break;
103
115
    case SERVER_TIMEOUT:
104
 
      OnFatal(StartServerHandlerInterface::SERVER_TIMEOUT);
 
116
      OnFatal(ServerLauncherInterface::SERVER_TIMEOUT);
105
117
      server_status_ = SERVER_FATAL;
106
118
      return false;
107
119
      break;
108
120
    case SERVER_BROKEN_MESSAGE:
109
 
      OnFatal(StartServerHandlerInterface::SERVER_BROKEN_MESSAGE);
 
121
      OnFatal(ServerLauncherInterface::SERVER_BROKEN_MESSAGE);
110
122
      server_status_ = SERVER_FATAL;
111
123
      return false;
112
124
      break;
113
125
    case SERVER_VERSION_MISMATCH:
114
 
      OnFatal(StartServerHandlerInterface::SERVER_VERSION_MISMATCH);
 
126
      OnFatal(ServerLauncherInterface::SERVER_VERSION_MISMATCH);
115
127
      server_status_ = SERVER_FATAL;
116
128
      return false;
117
129
      break;
118
130
    case SERVER_SHUTDOWN:
119
131
#ifdef _DEBUG
120
 
      OnFatal(StartServerHandlerInterface::SERVER_SHUTDOWN);
 
132
      OnFatal(ServerLauncherInterface::SERVER_SHUTDOWN);
121
133
      // don't break here as SERVER_SHUTDOWN and SERVER_UNKNOWN
122
134
      // have basically the same treatment.
123
135
#endif  // _DEBUG
127
139
        return true;
128
140
      } else {
129
141
        LOG(ERROR) << "Cannot start server";
130
 
        OnFatal(StartServerHandlerInterface::SERVER_FATAL);
 
142
        OnFatal(ServerLauncherInterface::SERVER_FATAL);
131
143
        server_status_ = SERVER_FATAL;
132
144
        return false;
133
145
      }
165
177
  const char kFilename[] = "query_of_death.log";
166
178
  const char kLabel[] = "Query of Death";
167
179
  DumpHistorySnapshot(kFilename, kLabel);
168
 
  history_inputs_.clear();
 
180
  ResetHistory();
169
181
}
170
182
 
171
183
void Session::DumpHistorySnapshot(const string &filename,
186
198
 
187
199
void Session::PlaybackHistory() {
188
200
  if (history_inputs_.size() >= kMaxPlayBackSize) {
189
 
    history_inputs_.clear();
 
201
    ResetHistory();
190
202
    return;
191
203
  }
192
204
 
204
216
 
205
217
void Session::PushHistory(const commands::Input &input,
206
218
                          const commands::Output &output) {
 
219
  if (!output.has_consumed() || !output.consumed()) {
 
220
    // Do not remember unconsumed input.
 
221
    return;
 
222
  }
 
223
 
 
224
  // Update mode
 
225
  if (output.has_mode()) {
 
226
    last_mode_ = output.mode();
 
227
  }
 
228
 
207
229
  // don't insert a new input when history_inputs_.size()
208
230
  // reaches to the maximum size. This prevents DOS attack.
209
231
  if (history_inputs_.size() < kMaxPlayBackSize) {
211
233
  }
212
234
 
213
235
  // found context boundary.
 
236
  // don't regard the empty output (output without preedit) as the context
 
237
  // boundary, as the IMEOn command make the empty output.
214
238
  if (input.type() == commands::Input::SEND_KEY &&
215
 
      (!output.has_preedit() || output.has_result())) {
216
 
    history_inputs_.clear();
 
239
      output.has_result()) {
 
240
    ResetHistory();
 
241
  }
 
242
}
 
243
 
 
244
// Clear the history and push IMEOn command for initialize session.
 
245
void Session::ResetHistory() {
 
246
  history_inputs_.clear();
 
247
#ifdef OS_WINDOWS
 
248
  // On Windows, we should send ON key at the first of each input session
 
249
  // excepting the very first session, because when the session is restored,
 
250
  // its state is direct. On the first session, users should send ON key
 
251
  // by themselves.
 
252
  // Note that we are assuming that ResetHistory is called only when the
 
253
  // client is ON.
 
254
  // TODO(toshiyuki): Make sure that this assuming is reasonable or not.
 
255
  // TODO(toshiyuki): Investigate for Mac and remove #ifdef guard.
 
256
  if (last_mode_ != commands::DIRECT) {
 
257
    commands::Input input;
 
258
    input.set_type(commands::Input::SEND_KEY);
 
259
    input.mutable_key()->set_special_key(commands::KeyEvent::ON);
 
260
    input.mutable_key()->set_mode(last_mode_);
 
261
    history_inputs_.push_back(input);
 
262
  }
 
263
#endif
 
264
}
 
265
 
 
266
void Session::GetHistoryInputs(vector<commands::Input> *output) const {
 
267
  output->clear();
 
268
  for (size_t i = 0; i < history_inputs_.size(); ++i) {
 
269
    output->push_back(history_inputs_[i]);
217
270
  }
218
271
}
219
272
 
333
386
  timeout_ = timeout;
334
387
}
335
388
 
 
389
void Session::set_restricted(bool restricted) {
 
390
  server_launcher_->set_restricted(restricted);
 
391
}
 
392
 
 
393
void Session::set_server_program(const string &program_path) {
 
394
  server_launcher_->set_server_program(program_path);
 
395
}
 
396
 
336
397
bool Session::CreateSession() {
337
398
  id_ = 0;
338
399
  commands::Input input;
420
481
 
421
482
bool Session::Shutdown() {
422
483
  CallCommand(commands::Input::SHUTDOWN);
423
 
  if (!start_server_handler_->WaitServer(server_process_id_)) {
 
484
  if (!server_launcher_->WaitServer(server_process_id_)) {
424
485
    LOG(ERROR) << "Cannot shutdown the server";
425
486
    return false;
426
487
  }
445
506
 
446
507
// PingServer ignores all server status
447
508
bool Session::PingServer() const {
 
509
  if (client_factory_ == NULL) {
 
510
    return false;
 
511
  }
 
512
 
448
513
  commands::Input input;
449
514
  commands::Output output;
450
515
 
454
519
 // Call IPC
455
520
  scoped_ptr<IPCClientInterface> client(
456
521
      client_factory_->NewClient(kServerAddress,
457
 
                                 start_server_handler_->server_program()));
 
522
                                 server_launcher_->server_program()));
458
523
 
459
524
  if (client.get() == NULL) {
460
525
    LOG(ERROR) << "Cannot make client object";
514
579
    return false;
515
580
  }
516
581
 
 
582
  if (client_factory_ == NULL) {
 
583
    return false;
 
584
  }
 
585
 
517
586
  // Serialize
518
587
  string request;
519
588
  input.SerializeToString(&request);
521
590
  // Call IPC
522
591
  scoped_ptr<IPCClientInterface> client(
523
592
      client_factory_->NewClient(kServerAddress,
524
 
                                 start_server_handler_->server_program()));
 
593
                                 server_launcher_->server_program()));
525
594
 
526
595
  // set client protocol version.
527
596
  // When an error occurs inside Connected() function,
595
664
}
596
665
 
597
666
bool Session::StartServer() {
598
 
  if (start_server_handler_.get() != NULL) {
599
 
    return start_server_handler_->StartServer(this);
 
667
  if (server_launcher_.get() != NULL) {
 
668
    return server_launcher_->StartServer(this);
600
669
  }
601
670
  return true;
602
671
}
603
672
 
604
673
 
605
 
void Session::OnFatal(StartServerHandlerInterface::ServerErrorType type) {
606
 
  if (start_server_handler_.get() != NULL) {
607
 
    start_server_handler_->OnFatal(type);
 
674
void Session::OnFatal(ServerLauncherInterface::ServerErrorType type) {
 
675
  if (server_launcher_.get() != NULL) {
 
676
    server_launcher_->OnFatal(type);
608
677
  }
609
678
}
610
679
 
662
731
      // force to terminate the process if protocol version is not compatible
663
732
      if (!shutdown_result ||
664
733
          (!call_result && server_protocol_version_ < IPC_PROTOCOL_VERSION)) {
665
 
        if (!start_server_handler_->ForceTerminateServer(kServerAddress)) {
 
734
        if (!server_launcher_->ForceTerminateServer(kServerAddress)) {
666
735
          LOG(ERROR) << "ForceTerminateProcess failed";
667
736
          server_status_ = SERVER_BROKEN_MESSAGE;
668
737
          return false;
669
738
        }
670
739
 
671
 
        if (!start_server_handler_->WaitServer(server_process_id_)) {
 
740
        if (!server_launcher_->WaitServer(server_process_id_)) {
672
741
          LOG(ERROR) << "Cannot terminate server process";
673
742
        }
674
743
      }
710
779
        key.modifier_keys(1) == commands::KeyEvent::CTRL));
711
780
}
712
781
 
 
782
bool Session::LaunchTool(const string &mode, const string &extra_arg) {
 
783
  // Don't execute any child process if the parent process is not
 
784
  // in proper runlevel.
 
785
  if (!IsValidRunLevel()) {
 
786
    return false;
 
787
  }
 
788
 
 
789
  // Validate |mode|.
 
790
  // TODO(taku): better to validate the parameter more carefully.
 
791
  const size_t kModeMaxSize = 32;
 
792
  if (mode.empty() || mode.size() >= kModeMaxSize) {
 
793
    LOG(ERROR) << "Invalid mode: " << mode;
 
794
    return false;
 
795
  }
 
796
 
 
797
  if (mode == "administration_dialog") {
 
798
#ifdef OS_WINDOWS
 
799
    const string path = mozc::Util::JoinPath
 
800
        (mozc::Util::GetServerDirectory(), kMozcTool);
 
801
    wstring wpath;
 
802
    Util::UTF8ToWide(path.c_str(), &wpath);
 
803
    wpath = L"\"" + wpath + L"\"";
 
804
    // Run administration dialog with UAC.
 
805
    // AFAIK, ShellExecute is only the way to launch process with
 
806
    // UAC protection.
 
807
    // No COM operations are executed as ShellExecute is only
 
808
    // used for launching an UAC-process.
 
809
    //
 
810
    // In Windows XP, cannot use "runas", instead, administration
 
811
    // dialog is launched with normal process with "open"
 
812
    // http://b/2415191
 
813
    const int result =
 
814
        reinterpret_cast<int>(::ShellExecute(0,
 
815
                                             mozc::Util::IsVistaOrLater() ?
 
816
                                             L"runas" : L"open",
 
817
                                             wpath.c_str(),
 
818
                                             L"--mode=administration_dialog",
 
819
                                             mozc::Util::GetSystemDir(),
 
820
                                             SW_SHOW));
 
821
    if (result <= 32) {
 
822
      LOG(ERROR) << "::ShellExecute failed: " << result;
 
823
      return false;
 
824
    }
 
825
#endif  // OS_WINDOWS
 
826
 
 
827
    return false;
 
828
  }
 
829
 
 
830
#if defined(OS_WINDOWS) || defined(OS_LINUX)
 
831
  string arg = "--mode=" + mode;
 
832
  if (!extra_arg.empty()) {
 
833
    arg += " ";
 
834
    arg += extra_arg;
 
835
  }
 
836
  if (!mozc::Process::SpawnMozcProcess(kMozcTool, arg)) {
 
837
    LOG(ERROR) << "Cannot execute: " << kMozcTool << " " << arg;
 
838
    return false;
 
839
  }
 
840
#endif  // OS_WINDOWS || OS_LINUX
 
841
 
 
842
  // TODO(taku): move MacProcess inside SpawnMozcProcess.
 
843
  // TODO(taku): support extra_arg.
 
844
#ifdef OS_MACOSX
 
845
  if (!MacProcess::LaunchMozcTool(mode)) {
 
846
    LOG(ERROR) << "Cannot execute: " << mode;
 
847
    return false;
 
848
  }
 
849
#endif  // OS_MACOSX
 
850
 
 
851
  return true;
 
852
}
 
853
 
 
854
bool Session::OpenBrowser(const string &url) {
 
855
  if (!IsValidRunLevel()) {
 
856
    return false;
 
857
  }
 
858
 
 
859
  if (!Process::OpenBrowser(url)) {
 
860
    LOG(ERROR) << "Process::OpenBrowser failed.";
 
861
    return false;
 
862
  }
 
863
 
 
864
  return true;
 
865
}
 
866
 
713
867
}  // namespace client
714
868
}  // namespace mozc