1 /* $OpenBSD: server-fn.c,v 1.26 2009/10/11 10:39:27 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 28 server_fill_environ(struct session *s, struct environ *env) 29 { 30 char tmuxvar[MAXPATHLEN], *term; 31 u_int idx; 32 33 if (session_index(s, &idx) != 0) 34 fatalx("session not found"); 35 xsnprintf(tmuxvar, sizeof tmuxvar, 36 "%s,%ld,%u", socket_path, (long) getpid(), idx); 37 environ_set(env, "TMUX", tmuxvar); 38 39 term = options_get_string(&s->options, "default-terminal"); 40 environ_set(env, "TERM", term); 41 } 42 43 void 44 server_write_error(struct client *c, const char *msg) 45 { 46 struct msg_print_data printdata; 47 48 strlcpy(printdata.msg, msg, sizeof printdata.msg); 49 server_write_client(c, MSG_ERROR, &printdata, sizeof printdata); 50 } 51 52 void 53 server_write_client( 54 struct client *c, enum msgtype type, const void *buf, size_t len) 55 { 56 struct imsgbuf *ibuf = &c->ibuf; 57 58 if (c->flags & CLIENT_BAD) 59 return; 60 log_debug("writing %d to client %d", type, c->ibuf.fd); 61 imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, -1, (void *) buf, len); 62 } 63 64 void 65 server_write_session( 66 struct session *s, enum msgtype type, const void *buf, size_t len) 67 { 68 struct client *c; 69 u_int i; 70 71 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 72 c = ARRAY_ITEM(&clients, i); 73 if (c == NULL || c->session == NULL) 74 continue; 75 if (c->session == s) 76 server_write_client(c, type, buf, len); 77 } 78 } 79 80 void 81 server_redraw_client(struct client *c) 82 { 83 c->flags |= CLIENT_REDRAW; 84 } 85 86 void 87 server_status_client(struct client *c) 88 { 89 c->flags |= CLIENT_STATUS; 90 } 91 92 void 93 server_redraw_session(struct session *s) 94 { 95 struct client *c; 96 u_int i; 97 98 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 99 c = ARRAY_ITEM(&clients, i); 100 if (c == NULL || c->session == NULL) 101 continue; 102 if (c->session == s) 103 server_redraw_client(c); 104 } 105 } 106 107 void 108 server_redraw_session_group(struct session *s) 109 { 110 struct session_group *sg; 111 112 if ((sg = session_group_find(s)) == NULL) 113 server_redraw_session(s); 114 else { 115 TAILQ_FOREACH(s, &sg->sessions, gentry) 116 server_redraw_session(s); 117 } 118 } 119 120 void 121 server_status_session(struct session *s) 122 { 123 struct client *c; 124 u_int i; 125 126 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 127 c = ARRAY_ITEM(&clients, i); 128 if (c == NULL || c->session == NULL) 129 continue; 130 if (c->session == s) 131 server_status_client(c); 132 } 133 } 134 135 void 136 server_status_session_group(struct session *s) 137 { 138 struct session_group *sg; 139 140 if ((sg = session_group_find(s)) == NULL) 141 server_status_session(s); 142 else { 143 TAILQ_FOREACH(s, &sg->sessions, gentry) 144 server_status_session(s); 145 } 146 } 147 148 void 149 server_redraw_window(struct window *w) 150 { 151 struct client *c; 152 u_int i; 153 154 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 155 c = ARRAY_ITEM(&clients, i); 156 if (c == NULL || c->session == NULL) 157 continue; 158 if (c->session->curw->window == w) 159 server_redraw_client(c); 160 } 161 w->flags |= WINDOW_REDRAW; 162 } 163 164 void 165 server_status_window(struct window *w) 166 { 167 struct session *s; 168 u_int i; 169 170 /* 171 * This is slightly different. We want to redraw the status line of any 172 * clients containing this window rather than any where it is the 173 * current window. 174 */ 175 176 for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { 177 s = ARRAY_ITEM(&sessions, i); 178 if (s != NULL && session_has(s, w)) 179 server_status_session(s); 180 } 181 } 182 183 void 184 server_lock(void) 185 { 186 struct client *c; 187 u_int i; 188 189 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 190 c = ARRAY_ITEM(&clients, i); 191 if (c == NULL || c->session == NULL) 192 continue; 193 server_lock_client(c); 194 } 195 } 196 197 void 198 server_lock_session(struct session *s) 199 { 200 struct client *c; 201 u_int i; 202 203 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 204 c = ARRAY_ITEM(&clients, i); 205 if (c == NULL || c->session == NULL || c->session != s) 206 continue; 207 server_lock_client(c); 208 } 209 } 210 211 void 212 server_lock_client(struct client *c) 213 { 214 const char *cmd; 215 size_t cmdlen; 216 struct msg_lock_data lockdata; 217 218 if (c->flags & CLIENT_SUSPENDED) 219 return; 220 221 cmd = options_get_string(&c->session->options, "lock-command"); 222 cmdlen = strlcpy(lockdata.cmd, cmd, sizeof lockdata.cmd); 223 if (cmdlen >= sizeof lockdata.cmd) 224 return; 225 226 tty_stop_tty(&c->tty); 227 tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_SMCUP)); 228 tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_CLEAR)); 229 230 c->flags |= CLIENT_SUSPENDED; 231 server_write_client(c, MSG_LOCK, &lockdata, sizeof lockdata); 232 } 233 234 void 235 server_kill_window(struct window *w) 236 { 237 struct session *s; 238 struct winlink *wl; 239 u_int i; 240 241 for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { 242 s = ARRAY_ITEM(&sessions, i); 243 if (s == NULL || !session_has(s, w)) 244 continue; 245 if ((wl = winlink_find_by_window(&s->windows, w)) == NULL) 246 continue; 247 248 if (session_detach(s, wl)) 249 server_destroy_session_group(s); 250 else { 251 server_redraw_session(s); 252 server_status_session_group(s); 253 } 254 } 255 } 256 257 int 258 server_link_window(struct session *src, struct winlink *srcwl, 259 struct session *dst, int dstidx, int killflag, int selectflag, char **cause) 260 { 261 struct winlink *dstwl; 262 struct session_group *srcsg, *dstsg; 263 264 srcsg = session_group_find(src); 265 dstsg = session_group_find(dst); 266 if (src != dst && srcsg != NULL && dstsg != NULL && srcsg == dstsg) { 267 xasprintf(cause, "sessions are grouped"); 268 return (-1); 269 } 270 271 dstwl = NULL; 272 if (dstidx != -1) 273 dstwl = winlink_find_by_index(&dst->windows, dstidx); 274 if (dstwl != NULL) { 275 if (dstwl->window == srcwl->window) 276 return (0); 277 if (killflag) { 278 /* 279 * Can't use session_detach as it will destroy session 280 * if this makes it empty. 281 */ 282 session_alert_cancel(dst, dstwl); 283 winlink_stack_remove(&dst->lastw, dstwl); 284 winlink_remove(&dst->windows, dstwl); 285 286 /* Force select/redraw if current. */ 287 if (dstwl == dst->curw) { 288 selectflag = 1; 289 dst->curw = NULL; 290 } 291 } 292 } 293 294 if (dstidx == -1) 295 dstidx = -1 - options_get_number(&dst->options, "base-index"); 296 dstwl = session_attach(dst, srcwl->window, dstidx, cause); 297 if (dstwl == NULL) 298 return (-1); 299 300 if (selectflag) 301 session_select(dst, dstwl->idx); 302 server_redraw_session_group(dst); 303 304 return (0); 305 } 306 307 void 308 server_unlink_window(struct session *s, struct winlink *wl) 309 { 310 if (session_detach(s, wl)) 311 server_destroy_session_group(s); 312 else 313 server_redraw_session_group(s); 314 } 315 316 void 317 server_destroy_session_group(struct session *s) 318 { 319 struct session_group *sg; 320 321 if ((sg = session_group_find(s)) == NULL) 322 server_destroy_session(s); 323 else { 324 TAILQ_FOREACH(s, &sg->sessions, gentry) 325 server_destroy_session(s); 326 TAILQ_REMOVE(&session_groups, sg, entry); 327 xfree(sg); 328 } 329 } 330 331 void 332 server_destroy_session(struct session *s) 333 { 334 struct client *c; 335 u_int i; 336 337 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 338 c = ARRAY_ITEM(&clients, i); 339 if (c == NULL || c->session != s) 340 continue; 341 c->session = NULL; 342 server_write_client(c, MSG_EXIT, NULL, 0); 343 } 344 } 345 346 void 347 server_set_identify(struct client *c) 348 { 349 struct timeval tv; 350 int delay; 351 352 delay = options_get_number(&c->session->options, "display-panes-time"); 353 tv.tv_sec = delay / 1000; 354 tv.tv_usec = (delay % 1000) * 1000L; 355 356 if (gettimeofday(&c->identify_timer, NULL) != 0) 357 fatal("gettimeofday failed"); 358 timeradd(&c->identify_timer, &tv, &c->identify_timer); 359 360 c->flags |= CLIENT_IDENTIFY; 361 c->tty.flags |= (TTY_FREEZE|TTY_NOCURSOR); 362 server_redraw_client(c); 363 } 364 365 void 366 server_clear_identify(struct client *c) 367 { 368 if (c->flags & CLIENT_IDENTIFY) { 369 c->flags &= ~CLIENT_IDENTIFY; 370 c->tty.flags &= ~(TTY_FREEZE|TTY_NOCURSOR); 371 server_redraw_client(c); 372 } 373 } 374