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"
48
#include "base/mac_process.h"
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();
85
93
client_factory_ = client_factory;
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);
101
bool Session::IsValidRunLevel() const {
102
return RunLevel::IsValidClientRunLevel();
93
105
bool Session::EnsureConnection() {
103
115
case SERVER_TIMEOUT:
104
OnFatal(StartServerHandlerInterface::SERVER_TIMEOUT);
116
OnFatal(ServerLauncherInterface::SERVER_TIMEOUT);
105
117
server_status_ = SERVER_FATAL;
108
120
case SERVER_BROKEN_MESSAGE:
109
OnFatal(StartServerHandlerInterface::SERVER_BROKEN_MESSAGE);
121
OnFatal(ServerLauncherInterface::SERVER_BROKEN_MESSAGE);
110
122
server_status_ = SERVER_FATAL;
113
125
case SERVER_VERSION_MISMATCH:
114
OnFatal(StartServerHandlerInterface::SERVER_VERSION_MISMATCH);
126
OnFatal(ServerLauncherInterface::SERVER_VERSION_MISMATCH);
115
127
server_status_ = SERVER_FATAL;
118
130
case SERVER_SHUTDOWN:
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.
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.
225
if (output.has_mode()) {
226
last_mode_ = output.mode();
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) {
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()) {
244
// Clear the history and push IMEOn command for initialize session.
245
void Session::ResetHistory() {
246
history_inputs_.clear();
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
252
// Note that we are assuming that ResetHistory is called only when the
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);
266
void Session::GetHistoryInputs(vector<commands::Input> *output) const {
268
for (size_t i = 0; i < history_inputs_.size(); ++i) {
269
output->push_back(history_inputs_[i]);
455
520
scoped_ptr<IPCClientInterface> client(
456
521
client_factory_->NewClient(kServerAddress,
457
start_server_handler_->server_program()));
522
server_launcher_->server_program()));
459
524
if (client.get() == NULL) {
460
525
LOG(ERROR) << "Cannot make client object";
522
591
scoped_ptr<IPCClientInterface> client(
523
592
client_factory_->NewClient(kServerAddress,
524
start_server_handler_->server_program()));
593
server_launcher_->server_program()));
526
595
// set client protocol version.
527
596
// When an error occurs inside Connected() function,
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);
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);
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;
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";
710
779
key.modifier_keys(1) == commands::KeyEvent::CTRL));
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()) {
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;
797
if (mode == "administration_dialog") {
799
const string path = mozc::Util::JoinPath
800
(mozc::Util::GetServerDirectory(), kMozcTool);
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
807
// No COM operations are executed as ShellExecute is only
808
// used for launching an UAC-process.
810
// In Windows XP, cannot use "runas", instead, administration
811
// dialog is launched with normal process with "open"
814
reinterpret_cast<int>(::ShellExecute(0,
815
mozc::Util::IsVistaOrLater() ?
818
L"--mode=administration_dialog",
819
mozc::Util::GetSystemDir(),
822
LOG(ERROR) << "::ShellExecute failed: " << result;
830
#if defined(OS_WINDOWS) || defined(OS_LINUX)
831
string arg = "--mode=" + mode;
832
if (!extra_arg.empty()) {
836
if (!mozc::Process::SpawnMozcProcess(kMozcTool, arg)) {
837
LOG(ERROR) << "Cannot execute: " << kMozcTool << " " << arg;
840
#endif // OS_WINDOWS || OS_LINUX
842
// TODO(taku): move MacProcess inside SpawnMozcProcess.
843
// TODO(taku): support extra_arg.
845
if (!MacProcess::LaunchMozcTool(mode)) {
846
LOG(ERROR) << "Cannot execute: " << mode;
854
bool Session::OpenBrowser(const string &url) {
855
if (!IsValidRunLevel()) {
859
if (!Process::OpenBrowser(url)) {
860
LOG(ERROR) << "Process::OpenBrowser failed.";
713
867
} // namespace client
714
868
} // namespace mozc