blob: 758bafa0875458c0949511f84fcc5dc69cd130d8 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/host/it2me_host_user_interface.h"
#include "base/bind.h"
#include "remoting/host/chromoting_host.h"
#include "remoting/host/chromoting_host_context.h"
#include "remoting/host/continue_window.h"
#include "remoting/host/disconnect_window.h"
#include "remoting/host/local_input_monitor.h"
namespace remoting {
class It2MeHostUserInterface::TimerTask {
public:
TimerTask(base::MessageLoopProxy* message_loop,
const base::Closure& task,
int delay_ms)
: thread_proxy_(message_loop) {
thread_proxy_.PostDelayedTask(FROM_HERE, task, delay_ms);
}
private:
ScopedThreadProxy thread_proxy_;
};
It2MeHostUserInterface::It2MeHostUserInterface(ChromotingHost* host,
ChromotingHostContext* context)
: host_(host),
context_(context),
is_monitoring_local_inputs_(false),
ui_thread_proxy_(context->ui_message_loop()) {
}
It2MeHostUserInterface::~It2MeHostUserInterface() {
}
void It2MeHostUserInterface::Init() {
InitFrom(DisconnectWindow::Create(),
ContinueWindow::Create(),
LocalInputMonitor::Create());
}
void It2MeHostUserInterface::InitFrom(
scoped_ptr<DisconnectWindow> disconnect_window,
scoped_ptr<ContinueWindow> continue_window,
scoped_ptr<LocalInputMonitor> monitor) {
disconnect_window_ = disconnect_window.Pass();
continue_window_ = continue_window.Pass();
local_input_monitor_ = monitor.Pass();
host_->AddStatusObserver(this);
}
void It2MeHostUserInterface::OnClientAuthenticated(const std::string& jid) {
if (!authenticated_jid_.empty()) {
// If we already authenticated another client then one of the
// connections may be an attacker, so both are suspect and we have
// to reject the second connection and shutdown the host.
host_->RejectAuthenticatingClient();
context_->network_message_loop()->PostTask(FROM_HERE, base::Bind(
&ChromotingHost::Shutdown, host_, base::Closure()));
return;
}
authenticated_jid_ = jid;
std::string username = jid.substr(0, jid.find('/'));
ui_thread_proxy_.PostTask(FROM_HERE, base::Bind(
&It2MeHostUserInterface::ProcessOnClientAuthenticated,
base::Unretained(this), username));
}
void It2MeHostUserInterface::OnClientDisconnected(const std::string& jid) {
if (jid == authenticated_jid_) {
ui_thread_proxy_.PostTask(FROM_HERE, base::Bind(
&It2MeHostUserInterface::ProcessOnClientDisconnected,
base::Unretained(this)));
}
}
void It2MeHostUserInterface::OnAccessDenied(const std::string& jid) {
}
void It2MeHostUserInterface::OnShutdown() {
// Host status observers must be removed on the network thread, so
// it must happen here instead of in the destructor.
host_->RemoveStatusObserver(this);
}
void It2MeHostUserInterface::Shutdown() {
DCHECK(context_->ui_message_loop()->BelongsToCurrentThread());
MonitorLocalInputs(false);
ShowDisconnectWindow(false, std::string());
ShowContinueWindow(false);
StartContinueWindowTimer(false);
ui_thread_proxy_.Detach();
}
void It2MeHostUserInterface::ProcessOnClientAuthenticated(
const std::string& username) {
DCHECK(context_->ui_message_loop()->BelongsToCurrentThread());
MonitorLocalInputs(true);
ShowDisconnectWindow(true, username);
StartContinueWindowTimer(true);
}
void It2MeHostUserInterface::ProcessOnClientDisconnected() {
DCHECK(context_->ui_message_loop()->BelongsToCurrentThread());
MonitorLocalInputs(false);
ShowDisconnectWindow(false, std::string());
ShowContinueWindow(false);
StartContinueWindowTimer(false);
}
void It2MeHostUserInterface::MonitorLocalInputs(bool enable) {
DCHECK(context_->ui_message_loop()->BelongsToCurrentThread());
if (enable == is_monitoring_local_inputs_)
return;
if (enable) {
local_input_monitor_->Start(host_);
} else {
local_input_monitor_->Stop();
}
is_monitoring_local_inputs_ = enable;
}
void It2MeHostUserInterface::ShowDisconnectWindow(bool show,
const std::string& username) {
DCHECK(context_->ui_message_loop()->BelongsToCurrentThread());
if (show) {
disconnect_window_->Show(host_, username);
} else {
disconnect_window_->Hide();
}
}
void It2MeHostUserInterface::ShowContinueWindow(bool show) {
DCHECK(context_->ui_message_loop()->BelongsToCurrentThread());
if (show) {
continue_window_->Show(host_, base::Bind(
&It2MeHostUserInterface::ContinueSession, base::Unretained(this)));
} else {
continue_window_->Hide();
}
}
void It2MeHostUserInterface::ContinueSession(bool continue_session) {
DCHECK(context_->ui_message_loop()->BelongsToCurrentThread());
if (continue_session) {
host_->PauseSession(false);
timer_task_.reset();
StartContinueWindowTimer(true);
} else {
host_->Shutdown(base::Closure());
}
}
void It2MeHostUserInterface::StartContinueWindowTimer(bool start) {
DCHECK(context_->ui_message_loop()->BelongsToCurrentThread());
if (start) {
timer_task_.reset(new TimerTask(
context_->ui_message_loop(),
base::Bind(&It2MeHostUserInterface::OnContinueWindowTimer,
base::Unretained(this)),
kContinueWindowShowTimeoutMs));
} else {
timer_task_.reset();
}
}
void It2MeHostUserInterface::OnContinueWindowTimer() {
DCHECK(context_->ui_message_loop()->BelongsToCurrentThread());
host_->PauseSession(true);
ShowContinueWindow(true);
timer_task_.reset(new TimerTask(
context_->ui_message_loop(),
base::Bind(&It2MeHostUserInterface::OnShutdownHostTimer,
base::Unretained(this)),
kContinueWindowHideTimeoutMs));
}
void It2MeHostUserInterface::OnShutdownHostTimer() {
DCHECK(context_->ui_message_loop()->BelongsToCurrentThread());
ShowContinueWindow(false);
host_->Shutdown(base::Closure());
}
} // namespace remoting