1 /* $OpenBSD: server-fn.c,v 1.29 2009/11/13 17:33:07 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 21 #include <string.h> 22 #include <time.h> 23 #include <unistd.h> 24 25 #include "tmux.h" 26 27 void server_callback_identify(int, short, void *); 28 29 void 30 server_fill_environ(struct session *s, struct environ *env) 31 { 32 char tmuxvar[MAXPATHLEN], *term; 33 u_int idx; 34 35 if (session_index(s, &idx) != 0) 36 fatalx("session not found"); 37 xsnprintf(tmuxvar, sizeof tmuxvar, 38 "%s,%ld,%u", socket_path, (long) getpid(), idx); 39 environ_set(env, "TMUX", tmuxvar); 40 41 term = options_get_string(&s->options, "default-terminal"); 42 environ_set(env, "TERM", term); 43 } 44 45 void 46 server_write_error(struct client *c, const char *msg) 47 { 48 struct msg_print_data printdata; 49 50 strlcpy(printdata.msg, msg, sizeof printdata.msg); 51 server_write_client(c, MSG_ERROR, &printdata, sizeof printdata); 52 } 53 54 void 55 server_write_client( 56 struct client *c, enum msgtype type, const void *buf, size_t len) 57 { 58 struct imsgbuf *ibuf = &c->ibuf; 59 60 if (c->flags & CLIENT_BAD) 61 return; 62 log_debug("writing %d to client %d", type, c->ibuf.fd); 63 imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, -1, (void *) buf, len); 64 server_update_event(c); 65 } 66 67 void 68 server_write_session( 69 struct session *s, enum msgtype type, const void *buf, size_t len) 70 { 71 struct client *c; 72 u_int i; 73 74 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 75 c = ARRAY_ITEM(&clients, i); 76 if (c == NULL || c->session == NULL) 77 continue; 78 if (c->session == s) 79 server_write_client(c, type, buf, len); 80 } 81 } 82 83 void 84 server_redraw_client(struct client *c) 85 { 86 c->flags |= CLIENT_REDRAW; 87 } 88 89 void 90 server_status_client(struct client *c) 91 { 92 c->flags |= CLIENT_STATUS; 93 } 94 95 void 96 server_redraw_session(struct session *s) 97 { 98 struct client *c; 99 u_int i; 100 101 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 102 c = ARRAY_ITEM(&clients, i); 103 if (c == NULL || c->session == NULL) 104 continue; 105 if (c->session == s) 106 server_redraw_client(c); 107 } 108 } 109 110 void 111 server_redraw_session_group(struct session *s) 112 { 113 struct session_group *sg; 114 115 if ((sg = session_group_find(s)) == NULL) 116 server_redraw_session(s); 117 else { 118 TAILQ_FOREACH(s, &sg->sessions, gentry) 119 server_redraw_session(s); 120 } 121 } 122 123 void 124 server_status_session(struct session *s) 125 { 126 struct client *c; 127 u_int i; 128 129 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 130 c = ARRAY_ITEM(&clients, i); 131 if (c == NULL || c->session == NULL) 132 continue; 133 if (c->session == s) 134 server_status_client(c); 135 } 136 } 137 138 void 139 server_status_session_group(struct session *s) 140 { 141 struct session_group *sg; 142 143 if ((sg = session_group_find(s)) == NULL) 144 server_status_session(s); 145 else { 146 TAILQ_FOREACH(s, &sg->sessions, gentry) 147 server_status_session(s); 148 } 149 } 150 151 void 152 server_redraw_window(struct window *w) 153 { 154 struct client *c; 155 u_int i; 156 157 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 158 c = ARRAY_ITEM(&clients, i); 159 if (c == NULL || c->session == NULL) 160 continue; 161 if (c->session->curw->window == w) 162 server_redraw_client(c); 163 } 164 w->flags |= WINDOW_REDRAW; 165 } 166 167 void 168 server_status_window(struct window *w) 169 { 170 struct session *s; 171 u_int i; 172 173 /* 174 * This is slightly different. We want to redraw the status line of any 175 * clients containing this window rather than any where it is the 176 * current window. 177 */ 178 179 for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { 180 s = ARRAY_ITEM(&sessions, i); 181 if (s != NULL && session_has(s, w)) 182 server_status_session(s); 183 } 184 } 185 186 void 187 server_lock(void) 188 { 189 struct client *c; 190 u_int i; 191 192 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 193 c = ARRAY_ITEM(&clients, i); 194 if (c == NULL || c->session == NULL) 195 continue; 196 server_lock_client(c); 197 } 198 } 199 200 void 201 server_lock_session(struct session *s) 202 { 203 struct client *c; 204 u_int i; 205 206 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 207 c = ARRAY_ITEM(&clients, i); 208 if (c == NULL || c->session == NULL || c->session != s) 209 continue; 210 server_lock_client(c); 211 } 212 } 213 214 void 215 server_lock_client(struct client *c) 216 { 217 const char *cmd; 218 size_t cmdlen; 219 struct msg_lock_data lockdata; 220 221 if (c->flags & CLIENT_SUSPENDED) 222 return; 223 224 cmd = options_get_string(&c->session->options, "lock-command"); 225 cmdlen = strlcpy(lockdata.cmd, cmd, sizeof lockdata.cmd); 226 if (cmdlen >= sizeof lockdata.cmd) 227 return; 228 229 tty_stop_tty(&c->tty); 230 tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_SMCUP)); 231 tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_CLEAR)); 232 233 c->flags |= CLIENT_SUSPENDED; 234 server_write_client(c, MSG_LOCK, &lockdata, sizeof lockdata); 235 } 236 237 void 238 server_kill_window(struct window *w) 239 { 240 struct session *s; 241 struct winlink *wl; 242 u_int i; 243 244 for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { 245 s = ARRAY_ITEM(&sessions, i); 246 if (s == NULL || !session_has(s, w)) 247 continue; 248 if ((wl = winlink_find_by_window(&s->windows, w)) == NULL) 249 continue; 250 251 if (session_detach(s, wl)) 252 server_destroy_session_group(s); 253 else { 254 server_redraw_session(s); 255 server_status_session_group(s); 256 } 257 } 258 } 259 260 int 261 server_link_window(struct session *src, struct winlink *srcwl, 262 struct session *dst, int dstidx, int killflag, int selectflag, char **cause) 263 { 264 struct winlink *dstwl; 265 struct session_group *srcsg, *dstsg; 266 267 srcsg = session_group_find(src); 268 dstsg = session_group_find(dst); 269 if (src != dst && srcsg != NULL && dstsg != NULL && srcsg == dstsg) { 270 xasprintf(cause, "sessions are grouped"); 271 return (-1); 272 } 273 274 dstwl = NULL; 275 if (dstidx != -1) 276 dstwl = winlink_find_by_index(&dst->windows, dstidx); 277 if (dstwl != NULL) { 278 if (dstwl->window == srcwl->window) 279 return (0); 280 if (killflag) { 281 /* 282 * Can't use session_detach as it will destroy session 283 * if this makes it empty. 284 */ 285 session_alert_cancel(dst, dstwl); 286 winlink_stack_remove(&dst->lastw, dstwl); 287 winlink_remove(&dst->windows, dstwl); 288 289 /* Force select/redraw if current. */ 290 if (dstwl == dst->curw) { 291 selectflag = 1; 292 dst->curw = NULL; 293 } 294 } 295 } 296 297 if (dstidx == -1) 298 dstidx = -1 - options_get_number(&dst->options, "base-index"); 299 dstwl = session_attach(dst, srcwl->window, dstidx, cause); 300 if (dstwl == NULL) 301 return (-1); 302 303 if (selectflag) 304 session_select(dst, dstwl->idx); 305 server_redraw_session_group(dst); 306 307 return (0); 308 } 309 310 void 311 server_unlink_window(struct session *s, struct winlink *wl) 312 { 313 if (session_detach(s, wl)) 314 server_destroy_session_group(s); 315 else 316 server_redraw_session_group(s); 317 } 318 319 void 320 server_destroy_pane(struct window_pane *wp) 321 { 322 struct window *w = wp->window; 323 324 close(wp->fd); 325 bufferevent_free(wp->event); 326 wp->fd = -1; 327 328 if (options_get_number(&w->options, "remain-on-exit")) 329 return; 330 331 layout_close_pane(wp); 332 window_remove_pane(w, wp); 333 334 if (TAILQ_EMPTY(&w->panes)) 335 server_kill_window(w); 336 else 337 server_redraw_window(w); 338 } 339 340 void 341 server_destroy_session_group(struct session *s) 342 { 343 struct session_group *sg; 344 345 if ((sg = session_group_find(s)) == NULL) 346 server_destroy_session(s); 347 else { 348 TAILQ_FOREACH(s, &sg->sessions, gentry) 349 server_destroy_session(s); 350 TAILQ_REMOVE(&session_groups, sg, entry); 351 xfree(sg); 352 } 353 } 354 355 void 356 server_destroy_session(struct session *s) 357 { 358 struct client *c; 359 u_int i; 360 361 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 362 c = ARRAY_ITEM(&clients, i); 363 if (c == NULL || c->session != s) 364 continue; 365 c->session = NULL; 366 server_write_client(c, MSG_EXIT, NULL, 0); 367 } 368 } 369 370 void 371 server_set_identify(struct client *c) 372 { 373 struct timeval tv; 374 int delay; 375 376 delay = options_get_number(&c->session->options, "display-panes-time"); 377 tv.tv_sec = delay / 1000; 378 tv.tv_usec = (delay % 1000) * 1000L; 379 380 evtimer_del(&c->identify_timer); 381 evtimer_set(&c->identify_timer, server_callback_identify, c); 382 evtimer_add(&c->identify_timer, &tv); 383 384 c->flags |= CLIENT_IDENTIFY; 385 c->tty.flags |= (TTY_FREEZE|TTY_NOCURSOR); 386 server_redraw_client(c); 387 } 388 389 void 390 server_clear_identify(struct client *c) 391 { 392 if (c->flags & CLIENT_IDENTIFY) { 393 c->flags &= ~CLIENT_IDENTIFY; 394 c->tty.flags &= ~(TTY_FREEZE|TTY_NOCURSOR); 395 server_redraw_client(c); 396 } 397 } 398 399 void 400 server_callback_identify(unused int fd, unused short events, void *data) 401 { 402 struct client *c = data; 403 404 server_clear_identify(c); 405 } 406 407 void 408 server_update_event(struct client *c) 409 { 410 short events; 411 412 events = 0; 413 if (!(c->flags & CLIENT_BAD)) 414 events |= EV_READ; 415 if (c->ibuf.w.queued > 0) 416 events |= EV_WRITE; 417 event_del(&c->event); 418 event_set(&c->event, c->ibuf.fd, events, server_client_callback, c); 419 event_add(&c->event, NULL); 420 } 421