/* $OpenBSD$ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <event.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <paths.h>
#include <unistd.h>
#include "tmux.h"
void server_client_handle_key(int, struct mouse_event *, void *);
void server_client_repeat_timer(int, short, void *);
void server_client_check_exit(struct client *);
void server_client_check_backoff(struct client *);
void server_client_check_redraw(struct client *);
void server_client_set_title(struct client *);
void server_client_reset_state(struct client *);
void server_client_in_callback(struct bufferevent *, short, void *);
void server_client_out_callback(struct bufferevent *, short, void *);
void server_client_err_callback(struct bufferevent *, short, void *);
int server_client_msg_dispatch(struct client *);
void server_client_msg_command(struct client *, struct msg_command_data *);
void server_client_msg_identify(
struct client *, struct msg_identify_data *, int);
void server_client_msg_shell(struct client *);
void printflike2 server_client_msg_error(struct cmd_ctx *, const char *, ...);
void printflike2 server_client_msg_print(struct cmd_ctx *, const char *, ...);
void printflike2 server_client_msg_info(struct cmd_ctx *, const char *, ...);
/* Create a new client. */
void
server_client_create(int fd)
{
struct client *c;
int mode;
u_int i;
if ((mode = fcntl(fd, F_GETFL)) == -1)
fatal("fcntl failed");
if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed");
c = xcalloc(1, sizeof *c);
c->references = 0;
imsg_init(&c->ibuf, fd);
server_update_event(c);
if (gettimeofday(&c->creation_time, NULL) != 0)
fatal("gettimeofday failed");
memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time);
c->stdin_event = NULL;
c->stdout_event = NULL;
c->stderr_event = NULL;
c->tty.fd = -1;
c->title = NULL;
c->session = NULL;
c->last_session = UINT_MAX;
c->tty.sx = 80;
c->tty.sy = 24;
screen_init(&c->status, c->tty.sx, 1, 0);
job_tree_init(&c->status_jobs);
c->message_string = NULL;
ARRAY_INIT(&c->message_log);
c->prompt_string = NULL;
c->prompt_buffer = NULL;
c->prompt_index = 0;
evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
if (ARRAY_ITEM(&clients, i) == NULL) {
ARRAY_SET(&clients, i, c);
return;
}
}
ARRAY_ADD(&clients, c);
log_debug("new client %d", fd);
}
/* Lost a client. */
void
server_client_lost(struct client *c)
{
struct message_entry *msg;
u_int i;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
if (ARRAY_ITEM(&clients, i) == c)
ARRAY_SET(&clients, i, NULL);
}
log_debug("lost client %d", c->ibuf.fd);
/*
* If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
* and tty_free might close an unrelated fd.
*/
if (c->flags & CLIENT_TERMINAL)
tty_free(&c->tty);
if (c->stdin_fd != -1)
close(c->stdin_fd);
if (c->stdin_event != NULL)
bufferevent_free(c->stdin_event);
if (c->stdout_fd != -1)
close(c->stdout_fd);
if (c->stdout_event != NULL)
bufferevent_free(c->stdout_event);
if