Fix build with -Werror=format-security
[screen-lua.git] / src / window.c
bloba800d4ae378f402b38d9adee4d785a99397e0645
1 /* Copyright (c) 2010
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
4 * Copyright (c) 2008, 2009
5 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
6 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
7 * Micah Cowan (micah@cowan.name)
8 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
9 * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
10 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
11 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
12 * Copyright (c) 1987 Oliver Laumann
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3, or (at your option)
17 * any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program (see the file COPYING); if not, see
26 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
29 ****************************************************************
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <signal.h>
35 #include <fcntl.h>
36 #ifndef sun
37 # include <sys/ioctl.h>
38 #endif
40 #include "config.h"
42 #include "screen.h"
43 #include "extern.h"
44 #include "logfile.h" /* logfopen() */
46 extern struct display *displays, *display;
47 extern struct win *windows, *fore, *console_window;
48 extern char *ShellArgs[];
49 extern char *ShellProg;
50 extern char screenterm[];
51 extern char *screenlogfile;
52 extern char HostName[];
53 extern int TtyMode;
54 extern int SilenceWait;
55 extern int real_uid, real_gid, eff_uid, eff_gid;
56 extern char Termcap[];
57 extern char **NewEnv;
58 extern int visual_bell, maxwin;
59 extern struct event logflushev;
60 extern int log_flush, logtstamp_after;
61 extern int ZombieKey_destroy, ZombieKey_resurrect, ZombieKey_onerror;
62 extern struct layer *flayer;
63 extern int maxusercount;
64 extern int pty_preopen;
65 #ifdef ZMODEM
66 extern int zmodem_mode;
67 extern struct mchar mchar_blank;
68 extern char *zmodem_sendcmd;
69 extern char *zmodem_recvcmd;
70 #endif
72 #if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
73 extern struct winsize glwz;
74 #endif
76 #ifdef O_NOCTTY
77 extern int separate_sids;
78 #endif
80 static void WinProcess __P((char **, int *));
81 static void WinRedisplayLine __P((int, int, int, int));
82 static void WinClearLine __P((int, int, int, int));
83 static int WinRewrite __P((int, int, int, struct mchar *, int));
84 static int WinResize __P((int, int));
85 static void WinRestore __P((void));
86 static int DoAutolf __P((char *, int *, int));
87 static void ZombieProcess __P((char **, int *));
88 static void win_readev_fn __P((struct event *, char *));
89 static void win_writeev_fn __P((struct event *, char *));
90 static int muchpending __P((struct win *, struct event *));
91 #ifdef COPY_PASTE
92 static void paste_slowev_fn __P((struct event *, char *));
93 #endif
94 #ifdef PSEUDOS
95 static void pseu_readev_fn __P((struct event *, char *));
96 static void pseu_writeev_fn __P((struct event *, char *));
97 #endif
98 static void win_silenceev_fn __P((struct event *, char *));
99 static void win_destroyev_fn __P((struct event *, char *));
101 static int OpenDevice __P((char **, int, int *, char **));
102 static int ForkWindow __P((struct win *, char **, char *));
103 #ifdef ZMODEM
104 static void zmodem_found __P((struct win *, int, char *, int));
105 static void zmodem_fin __P((char *, int, char *));
106 static int zmodem_parse __P((struct win *, char *, int));
107 #endif
110 struct win **wtab; /* window table */
112 int VerboseCreate = 0; /* XXX move this to user.h */
114 char DefaultShell[] = "/bin/sh";
115 static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
117 /* keep this in sync with the structure definition in window.h */
118 struct NewWindow nwin_undef =
120 -1, /* StartAt */
121 (char *)0, /* aka */
122 (char **)0, /* args */
123 (char *)0, /* dir */
124 (char *)0, /* term */
125 -1, /* aflag */
126 -1, /* flowflag */
127 -1, /* lflag */
128 -1, /* histheight */
129 -1, /* monitor */
130 -1, /* wlock */
131 -1, /* silence */
132 -1, /* wrap */
133 -1, /* logging */
134 -1, /* slowpaste */
135 -1, /* gr */
136 -1, /* c1 */
137 -1, /* bce */
138 -1, /* encoding */
139 (char *)0, /* hstatus */
140 (char *)0 /* charset */
143 struct NewWindow nwin_default =
145 0, /* StartAt */
146 0, /* aka */
147 ShellArgs, /* args */
148 0, /* dir */
149 screenterm, /* term */
150 0, /* aflag */
151 1*FLOW_NOW, /* flowflag */
152 LOGINDEFAULT, /* lflag */
153 DEFAULTHISTHEIGHT, /* histheight */
154 MON_OFF, /* monitor */
155 WLOCK_OFF, /* wlock */
156 0, /* silence */
157 1, /* wrap */
158 0, /* logging */
159 0, /* slowpaste */
160 0, /* gr */
161 1, /* c1 */
162 0, /* bce */
163 0, /* encoding */
164 (char *)0, /* hstatus */
165 (char *)0 /* charset */
168 struct NewWindow nwin_options;
170 static int const_IOSIZE = IOSIZE;
171 static int const_one = 1;
173 void
174 nwin_compose(def, new, res)
175 struct NewWindow *def, *new, *res;
177 #define COMPOSE(x) res->x = new->x != nwin_undef.x ? new->x : def->x
178 COMPOSE(StartAt);
179 COMPOSE(aka);
180 COMPOSE(args);
181 COMPOSE(dir);
182 COMPOSE(term);
183 COMPOSE(aflag);
184 COMPOSE(flowflag);
185 COMPOSE(lflag);
186 COMPOSE(histheight);
187 COMPOSE(monitor);
188 COMPOSE(wlock);
189 COMPOSE(silence);
190 COMPOSE(wrap);
191 COMPOSE(Lflag);
192 COMPOSE(slow);
193 COMPOSE(gr);
194 COMPOSE(c1);
195 COMPOSE(bce);
196 COMPOSE(encoding);
197 COMPOSE(hstatus);
198 COMPOSE(charset);
199 #undef COMPOSE
202 /*****************************************************************
204 * The window layer functions
207 struct LayFuncs WinLf =
209 WinProcess,
211 WinRedisplayLine,
212 WinClearLine,
213 WinRewrite,
214 WinResize,
215 WinRestore,
219 static int
220 DoAutolf(buf, lenp, fr)
221 char *buf;
222 int *lenp;
223 int fr;
225 char *p;
226 int len = *lenp;
227 int trunc = 0;
229 for (p = buf; len > 0; p++, len--)
231 if (*p != '\r')
232 continue;
233 if (fr-- <= 0)
235 trunc++;
236 len--;
238 if (len == 0)
239 break;
240 bcopy(p, p + 1, len++);
241 p[1] = '\n';
243 *lenp = p - buf;
244 return trunc;
247 static void
248 WinProcess(bufpp, lenp)
249 char **bufpp;
250 int *lenp;
252 int l2 = 0, f, *ilen, l = *lenp, trunc;
253 char *ibuf;
255 debug1("WinProcess: %d bytes\n", *lenp);
256 fore = (struct win *)flayer->l_data;
258 if (fore->w_type == W_TYPE_GROUP)
260 *bufpp += *lenp;
261 *lenp = 0;
262 return;
264 if (fore->w_ptyfd < 0) /* zombie? */
266 ZombieProcess(bufpp, lenp);
267 return;
269 #ifdef MULTIUSER
270 /* a pending writelock is this:
271 * fore->w_wlock == WLOCK_AUTO, fore->w_wlockuse = NULL
272 * The user who wants to use this window next, will get the lock, if he can.
274 if (display && fore->w_wlock == WLOCK_AUTO &&
275 !fore->w_wlockuser && !AclCheckPermWin(D_user, ACL_WRITE, fore))
277 fore->w_wlockuser = D_user;
278 debug2("window %d: pending writelock grabbed by user %s\n",
279 fore->w_number, fore->w_wlockuser->u_name);
281 /* if w_wlock is set, only one user may write, else we check acls */
282 if (display && ((fore->w_wlock == WLOCK_OFF) ?
283 AclCheckPermWin(D_user, ACL_WRITE, fore) :
284 (D_user != fore->w_wlockuser)))
286 debug2("window %d, user %s: ", fore->w_number, D_user->u_name);
287 debug2("writelock %d (wlockuser %s)\n", fore->w_wlock,
288 fore->w_wlockuser ? fore->w_wlockuser->u_name : "NULL");
289 Msg(0, "write: permission denied (user %s)", D_user->u_name);
290 *bufpp += *lenp;
291 *lenp = 0;
292 return;
294 #endif /* MULTIUSER */
296 #ifdef BUILTIN_TELNET
297 if (fore->w_type == W_TYPE_TELNET && TelIsline(fore) && *bufpp != fore->w_telbuf)
299 TelProcessLine(bufpp, lenp);
300 return;
302 #endif
304 #ifdef PSEUDOS
305 if (W_UWP(fore))
307 /* we send the user input to our pseudowin */
308 ibuf = fore->w_pwin->p_inbuf; ilen = &fore->w_pwin->p_inlen;
309 f = sizeof(fore->w_pwin->p_inbuf) - *ilen;
311 else
312 #endif /* PSEUDOS */
314 /* we send the user input to the window */
315 ibuf = fore->w_inbuf; ilen = &fore->w_inlen;
316 f = sizeof(fore->w_inbuf) - *ilen;
319 if (l > f)
320 l = f;
321 #ifdef BUILTIN_TELNET
322 while (l > 0)
323 #else
324 if (l > 0)
325 #endif
327 l2 = l;
328 bcopy(*bufpp, ibuf + *ilen, l2);
329 if (fore->w_autolf && (trunc = DoAutolf(ibuf + *ilen, &l2, f - l2)))
330 l -= trunc;
331 #ifdef BUILTIN_TELNET
332 if (fore->w_type == W_TYPE_TELNET && (trunc = DoTelnet(ibuf + *ilen, &l2, f - l2)))
334 l -= trunc;
335 if (fore->w_autolf)
336 continue; /* need exact value */
338 #endif
339 *ilen += l2;
340 *bufpp += l;
341 *lenp -= l;
342 return;
346 static void
347 ZombieProcess(bufpp, lenp)
348 char **bufpp;
349 int *lenp;
351 int l = *lenp;
352 char *buf = *bufpp, b1[10], b2[10];
354 debug1("ZombieProcess: %d bytes\n", *lenp);
355 fore = (struct win *)flayer->l_data;
357 ASSERT(fore->w_ptyfd < 0);
358 *bufpp += *lenp;
359 *lenp = 0;
360 for (; l-- > 0; buf++)
362 if (*(unsigned char *)buf == ZombieKey_destroy)
364 debug1("Turning undead: %d\n", fore->w_number);
365 KillWindow(fore);
366 return;
368 if (*(unsigned char *)buf == ZombieKey_resurrect)
370 debug1("Resurrecting Zombie: %d\n", fore->w_number);
371 WriteString(fore, "\r\n", 2);
372 RemakeWindow(fore);
373 return;
376 b1[AddXChar(b1, ZombieKey_destroy)] = '\0';
377 b2[AddXChar(b2, ZombieKey_resurrect)] = '\0';
378 Msg(0, "Press %s to destroy or %s to resurrect window", b1, b2);
381 static void
382 WinRedisplayLine(y, from, to, isblank)
383 int y, from, to, isblank;
385 debug3("WinRedisplayLine %d %d %d\n", y, from, to);
386 if (y < 0)
387 return;
388 fore = (struct win *)flayer->l_data;
389 if (from == 0 && y > 0 && fore->w_mlines[y - 1].image[fore->w_width] == 0)
390 LCDisplayLineWrap(&fore->w_layer, &fore->w_mlines[y], y, from, to, isblank);
391 else
392 LCDisplayLine(&fore->w_layer, &fore->w_mlines[y], y, from, to, isblank);
395 static int
396 WinRewrite(y, x1, x2, rend, doit)
397 int y, x1, x2, doit;
398 struct mchar *rend;
400 register int cost, dx;
401 register unsigned char *p, *i;
402 #ifdef FONT
403 register unsigned char *f;
404 #endif
405 #ifdef COLOR
406 register unsigned char *c;
407 # ifdef COLORS256
408 register unsigned char *cx;
409 # endif
410 #endif
412 debug3("WinRewrite %d, %d-%d\n", y, x1, x2);
413 fore = (struct win *)flayer->l_data;
414 dx = x2 - x1 + 1;
415 if (doit)
417 i = fore->w_mlines[y].image + x1;
418 while (dx-- > 0)
419 PUTCHAR(*i++);
420 return 0;
422 p = fore->w_mlines[y].attr + x1;
423 #ifdef FONT
424 f = fore->w_mlines[y].font + x1;
425 # ifdef DW_CHARS
426 if (is_dw_font(rend->font))
427 return EXPENSIVE;
428 # endif
429 # ifdef UTF8
430 if (fore->w_encoding && fore->w_encoding != UTF8 && D_encoding == UTF8 && ContainsSpecialDeffont(fore->w_mlines + y, x1, x2, fore->w_encoding))
431 return EXPENSIVE;
432 # endif
433 #endif
434 #ifdef COLOR
435 c = fore->w_mlines[y].color + x1;
436 # ifdef COLORS256
437 cx = fore->w_mlines[y].colorx + x1;
438 # endif
439 #endif
441 cost = dx = x2 - x1 + 1;
442 while(dx-- > 0)
444 if (*p++ != rend->attr)
445 return EXPENSIVE;
446 #ifdef FONT
447 if (*f++ != rend->font)
448 return EXPENSIVE;
449 #endif
450 #ifdef COLOR
451 if (*c++ != rend->color)
452 return EXPENSIVE;
453 # ifdef COLORS256
454 if (*cx++ != rend->colorx)
455 return EXPENSIVE;
456 # endif
457 #endif
459 return cost;
462 static void
463 WinClearLine(y, xs, xe, bce)
464 int y, xs, xe, bce;
466 fore = (struct win *)flayer->l_data;
467 debug3("WinClearLine %d %d-%d\n", y, xs, xe);
468 LClearLine(flayer, y, xs, xe, bce, &fore->w_mlines[y]);
471 static int
472 WinResize(wi, he)
473 int wi, he;
475 fore = (struct win *)flayer->l_data;
476 ChangeWindowSize(fore, wi, he, fore->w_histheight);
477 return 0;
480 static void
481 WinRestore()
483 struct canvas *cv;
484 fore = (struct win *)flayer->l_data;
485 debug1("WinRestore: win %p\n", fore);
486 for (cv = flayer->l_cvlist; cv; cv = cv->c_next)
488 display = cv->c_display;
489 if (cv != D_forecv)
490 continue;
491 /* ChangeScrollRegion(fore->w_top, fore->w_bot); */
492 KeypadMode(fore->w_keypad);
493 CursorkeysMode(fore->w_cursorkeys);
494 SetFlow(fore->w_flow & FLOW_NOW);
495 InsertMode(fore->w_insert);
496 ReverseVideo(fore->w_revvid);
497 CursorVisibility(fore->w_curinv ? -1 : fore->w_curvvis);
498 MouseMode(fore->w_mouse);
502 /*****************************************************************/
506 * DoStartLog constructs a path for the "want to be logfile" in buf and
507 * attempts logfopen.
509 * returns 0 on success.
512 DoStartLog(w, buf, bufsize)
513 struct win *w;
514 char *buf;
515 int bufsize;
517 int n;
518 if (!w || !buf)
519 return -1;
521 strncpy(buf, MakeWinMsg(screenlogfile, w, '%'), bufsize - 1);
522 buf[bufsize - 1] = 0;
524 debug2("DoStartLog: win %d, file %s\n", w->w_number, buf);
526 if (w->w_log != NULL)
527 logfclose(w->w_log);
529 if ((w->w_log = logfopen(buf, islogfile(buf) ? NULL : secfopen(buf, "a"))) == NULL)
530 return -2;
531 if (!logflushev.queued)
533 n = log_flush ? log_flush : (logtstamp_after + 4) / 5;
534 if (n)
536 SetTimeout(&logflushev, n * 1000);
537 evenq(&logflushev);
540 return 0;
544 * Umask & wlock are set for the user of the display,
545 * The display d (if specified) switches to that window.
548 MakeWindow(newwin)
549 struct NewWindow *newwin;
551 register struct win **pp, *p;
552 register int n, i;
553 int f = -1;
554 struct NewWindow nwin;
555 int type, startat;
556 char *TtyName;
557 #ifdef MULTIUSER
558 extern struct acluser *users;
559 #endif
561 if (!wtab)
563 if (!maxwin)
564 maxwin = MAXWIN;
565 wtab = calloc(maxwin, sizeof(struct win *));
568 debug1("NewWindow: StartAt %d\n", newwin->StartAt);
569 debug1("NewWindow: aka %s\n", newwin->aka?newwin->aka:"NULL");
570 debug1("NewWindow: dir %s\n", newwin->dir?newwin->dir:"NULL");
571 debug1("NewWindow: term %s\n", newwin->term?newwin->term:"NULL");
573 nwin_compose(&nwin_default, newwin, &nwin);
574 debug1("NWin: aka %s\n", nwin.aka ? nwin.aka : "NULL");
575 debug1("NWin: wlock %d\n", nwin.wlock);
576 debug1("NWin: Lflag %d\n", nwin.Lflag);
578 startat = nwin.StartAt < maxwin ? nwin.StartAt : 0;
579 pp = wtab + startat;
583 if (*pp == 0)
584 break;
585 if (++pp == wtab + maxwin)
586 pp = wtab;
588 while (pp != wtab + startat);
589 if (*pp)
591 Msg(0, "No more windows.");
592 return -1;
595 #if defined(USRLIMIT) && defined(UTMPOK)
597 * Count current number of users, if logging windows in.
599 if (nwin.lflag && CountUsers() >= USRLIMIT)
601 Msg(0, "User limit reached. Window will not be logged in.");
602 nwin.lflag = 0;
604 #endif
605 n = pp - wtab;
606 debug1("Makewin creating %d\n", n);
608 if ((f = OpenDevice(nwin.args, nwin.lflag, &type, &TtyName)) < 0)
609 return -1;
610 if (type == W_TYPE_GROUP)
611 f = -1;
613 if ((p = (struct win *)calloc(1, sizeof(struct win))) == 0)
615 close(f);
616 Msg(0, "%s", strnomem);
617 return -1;
620 #ifdef UTMPOK
621 if (type != W_TYPE_PTY)
622 nwin.lflag = 0;
623 #endif
625 p->w_type = type;
627 /* save the command line so that zombies can be resurrected */
628 for (i = 0; nwin.args[i] && i < MAXARGS - 1; i++)
629 p->w_cmdargs[i] = SaveStr(nwin.args[i]);
630 p->w_cmdargs[i] = 0;
631 if (nwin.dir)
632 p->w_dir = SaveStr(nwin.dir);
633 if (nwin.term)
634 p->w_term = SaveStr(nwin.term);
636 p->w_number = n;
637 p->w_group = 0;
638 if (fore && fore->w_type == W_TYPE_GROUP)
639 p->w_group = fore;
640 else if (fore && fore->w_group)
641 p->w_group = fore->w_group;
642 #ifdef MULTIUSER
644 * This is dangerous: without a display we use creators umask
645 * This is intended to be usefull for detached startup.
646 * But is still better than default bits with a NULL user.
648 if (NewWindowAcl(p, display ? D_user : users))
650 free((char *)p);
651 close(f);
652 Msg(0, "%s", strnomem);
653 return -1;
655 #endif
656 p->w_layer.l_next = 0;
657 p->w_layer.l_bottom = &p->w_layer;
658 p->w_layer.l_layfn = &WinLf;
659 p->w_layer.l_data = (char *)p;
660 p->w_savelayer = &p->w_layer;
661 p->w_pdisplay = 0;
662 p->w_lastdisp = 0;
664 #ifdef MULTIUSER
665 if (display && !AclCheckPermWin(D_user, ACL_WRITE, p))
666 p->w_wlockuser = D_user;
667 p->w_wlock = nwin.wlock;
668 #endif
669 p->w_ptyfd = f;
670 p->w_aflag = nwin.aflag;
671 p->w_flow = nwin.flowflag | ((nwin.flowflag & FLOW_AUTOFLAG) ? (FLOW_AUTO|FLOW_NOW) : FLOW_AUTO);
672 if (!nwin.aka)
673 nwin.aka = Filename(nwin.args[0]);
674 strncpy(p->w_akabuf, nwin.aka, sizeof(p->w_akabuf) - 1);
675 if ((nwin.aka = rindex(p->w_akabuf, '|')) != NULL)
677 p->w_autoaka = 0;
678 *nwin.aka++ = 0;
679 p->w_title = nwin.aka;
680 p->w_akachange = nwin.aka + strlen(nwin.aka);
682 else
683 p->w_title = p->w_akachange = p->w_akabuf;
684 if (nwin.hstatus)
685 p->w_hstatus = SaveStr(nwin.hstatus);
686 p->w_monitor = nwin.monitor;
687 #ifdef MULTIUSER
688 if (p->w_monitor == MON_ON)
690 /* always tell all users */
691 for (i = 0; i < maxusercount; i++)
692 ACLBYTE(p->w_mon_notify, i) |= ACLBIT(i);
694 #endif
696 * defsilence by Lloyd Zusman (zusman_lloyd@jpmorgan.com)
698 p->w_silence = nwin.silence;
699 p->w_silencewait = SilenceWait;
700 #ifdef MULTIUSER
701 if (p->w_silence == SILENCE_ON)
703 /* always tell all users */
704 for (i = 0; i < maxusercount; i++)
705 ACLBYTE(p->w_lio_notify, i) |= ACLBIT(i);
707 #endif
708 #ifdef COPY_PASTE
709 p->w_slowpaste = nwin.slow;
710 #else
711 nwin.histheight = 0;
712 #endif
714 p->w_norefresh = 0;
715 strncpy(p->w_tty, TtyName, MAXSTR - 1);
717 #if 0
718 /* XXX Fixme display resize */
719 if (ChangeWindowSize(p, display ? D_defwidth : 80,
720 display ? D_defheight : 24,
721 nwin.histheight))
723 FreeWindow(p);
724 return -1;
726 #else
727 if (ChangeWindowSize(p, display ? D_forecv->c_xe - D_forecv->c_xs + 1: 80,
728 display ? D_forecv->c_ye - D_forecv->c_ys + 1 : 24,
729 nwin.histheight))
731 FreeWindow(p);
732 return -1;
734 #endif
736 p->w_encoding = nwin.encoding;
737 ResetWindow(p); /* sets w_wrap, w_c1, w_gr, w_bce */
739 #ifdef FONT
740 if (nwin.charset)
741 SetCharsets(p, nwin.charset);
742 #endif
744 if (VerboseCreate && type != W_TYPE_GROUP)
746 struct display *d = display; /* WriteString zaps display */
748 WriteString(p, ":screen (", 9);
749 WriteString(p, p->w_title, strlen(p->w_title));
750 WriteString(p, "):", 2);
751 for (f = 0; p->w_cmdargs[f]; f++)
753 WriteString(p, " ", 1);
754 WriteString(p, p->w_cmdargs[f], strlen(p->w_cmdargs[f]));
756 WriteString(p, "\r\n", 2);
757 display = d;
760 p->w_deadpid = 0;
761 p->w_pid = 0;
762 #ifdef PSEUDOS
763 p->w_pwin = 0;
764 #endif
766 #ifdef BUILTIN_TELNET
767 if (type == W_TYPE_TELNET)
769 if (TelConnect(p))
771 FreeWindow(p);
772 return -1;
775 else
776 #endif
777 if (type == W_TYPE_PTY)
779 p->w_pid = ForkWindow(p, nwin.args, TtyName);
780 if (p->w_pid < 0)
782 FreeWindow(p);
783 return -1;
788 * Place the new window at the head of the most-recently-used list.
790 if (display && D_fore)
791 D_other = D_fore;
792 *pp = p;
793 p->w_next = windows;
794 windows = p;
796 if (type == W_TYPE_GROUP)
798 SetForeWindow(p);
799 Activate(p->w_norefresh);
800 WindowChanged((struct win*)0, 'w');
801 WindowChanged((struct win*)0, 'W');
802 WindowChanged((struct win*)0, 0);
803 return n;
806 p->w_lflag = nwin.lflag;
807 #ifdef UTMPOK
808 p->w_slot = (slot_t)-1;
809 # ifdef LOGOUTOK
810 debug1("MakeWindow will %slog in.\n", nwin.lflag?"":"not ");
811 if (nwin.lflag & 1)
812 # else /* LOGOUTOK */
813 debug1("MakeWindow will log in, LOGOUTOK undefined in config.h%s.\n",
814 nwin.lflag?"":" (although lflag=0)");
815 # endif /* LOGOUTOK */
817 p->w_slot = (slot_t)0;
818 if (display || (p->w_lflag & 2))
819 SetUtmp(p);
821 # ifdef CAREFULUTMP
822 CarefulUtmp(); /* If all 've been zombies, we've had no slot */
823 # endif
824 #endif /* UTMPOK */
826 if (nwin.Lflag)
828 char buf[1024];
829 DoStartLog(p, buf, sizeof(buf));
832 p->w_readev.fd = p->w_writeev.fd = p->w_ptyfd;
833 p->w_readev.type = EV_READ;
834 p->w_writeev.type = EV_WRITE;
835 p->w_readev.data = p->w_writeev.data = (char *)p;
836 p->w_readev.handler = win_readev_fn;
837 p->w_writeev.handler = win_writeev_fn;
838 p->w_writeev.condpos = &p->w_inlen;
839 evenq(&p->w_readev);
840 evenq(&p->w_writeev);
841 #ifdef COPY_PASTE
842 p->w_paster.pa_slowev.type = EV_TIMEOUT;
843 p->w_paster.pa_slowev.data = (char *)&p->w_paster;
844 p->w_paster.pa_slowev.handler = paste_slowev_fn;
845 #endif
846 p->w_silenceev.type = EV_TIMEOUT;
847 p->w_silenceev.data = (char *)p;
848 p->w_silenceev.handler = win_silenceev_fn;
849 if (p->w_silence > 0)
851 debug("New window has silence enabled.\n");
852 SetTimeout(&p->w_silenceev, p->w_silencewait * 1000);
853 evenq(&p->w_silenceev);
855 p->w_destroyev.type = EV_TIMEOUT;
856 p->w_destroyev.data = 0;
857 p->w_destroyev.handler = win_destroyev_fn;
859 SetForeWindow(p);
860 Activate(p->w_norefresh);
861 WindowChanged((struct win*)0, 'w');
862 WindowChanged((struct win*)0, 'W');
863 WindowChanged((struct win*)0, 0);
864 return n;
868 * Resurrect a window from Zombie state.
869 * The command vector is therefore stored in the window structure.
870 * Note: The terminaltype defaults to screenterm again, the current
871 * working directory is lost.
874 RemakeWindow(p)
875 struct win *p;
877 char *TtyName;
878 int lflag, f;
880 lflag = nwin_default.lflag;
881 if ((f = OpenDevice(p->w_cmdargs, lflag, &p->w_type, &TtyName)) < 0)
882 return -1;
884 strncpy(p->w_tty, *TtyName ? TtyName : p->w_title, MAXSTR - 1);
885 p->w_ptyfd = f;
886 p->w_readev.fd = f;
887 p->w_writeev.fd = f;
888 evenq(&p->w_readev);
889 evenq(&p->w_writeev);
891 if (VerboseCreate)
893 struct display *d = display; /* WriteString zaps display */
895 WriteString(p, ":screen (", 9);
896 WriteString(p, p->w_title, strlen(p->w_title));
897 WriteString(p, "):", 2);
898 for (f = 0; p->w_cmdargs[f]; f++)
900 WriteString(p, " ", 1);
901 WriteString(p, p->w_cmdargs[f], strlen(p->w_cmdargs[f]));
903 WriteString(p, "\r\n", 2);
904 display = d;
907 p->w_deadpid = 0;
908 p->w_pid = 0;
909 #ifdef BUILTIN_TELNET
910 if (p->w_type == W_TYPE_TELNET)
912 if (TelConnect(p))
913 return -1;
915 else
916 #endif
917 if (p->w_type == W_TYPE_PTY)
919 p->w_pid = ForkWindow(p, p->w_cmdargs, TtyName);
920 if (p->w_pid < 0)
921 return -1;
924 #ifdef UTMPOK
925 if (p->w_slot == (slot_t)0 && (display || (p->w_lflag & 2)))
926 SetUtmp(p);
927 # ifdef CAREFULUTMP
928 CarefulUtmp(); /* If all 've been zombies, we've had no slot */
929 # endif
930 #endif
931 WindowChanged(p, 'f');
932 return p->w_number;
935 void
936 CloseDevice(wp)
937 struct win *wp;
939 if (wp->w_ptyfd < 0)
940 return;
941 if (wp->w_type == W_TYPE_PTY)
943 /* pty 4 SALE */
944 (void)chmod(wp->w_tty, 0666);
945 (void)chown(wp->w_tty, 0, 0);
947 close(wp->w_ptyfd);
948 wp->w_ptyfd = -1;
949 wp->w_tty[0] = 0;
950 evdeq(&wp->w_readev);
951 evdeq(&wp->w_writeev);
952 #ifdef BUILTIN_TELNET
953 evdeq(&wp->w_telconnev);
954 #endif
955 wp->w_readev.fd = wp->w_writeev.fd = -1;
958 void
959 FreeWindow(wp)
960 struct win *wp;
962 struct display *d;
963 int i;
964 struct canvas *cv, *ncv;
965 struct layer *l;
967 debug1("FreeWindow %d\n", wp ? wp->w_number: -1);
968 #ifdef PSEUDOS
969 if (wp->w_pwin)
970 FreePseudowin(wp);
971 #endif
972 #ifdef UTMPOK
973 RemoveUtmp(wp);
974 #endif
975 CloseDevice(wp);
977 if (wp == console_window)
979 TtyGrabConsole(-1, -1, "free");
980 console_window = 0;
982 if (wp->w_log != NULL)
983 logfclose(wp->w_log);
984 ChangeWindowSize(wp, 0, 0, 0);
986 if (wp->w_type == W_TYPE_GROUP)
988 struct win *win;
989 for (win = windows; win; win = win->w_next)
990 if (win->w_group == wp)
991 win->w_group = wp->w_group;
994 if (wp->w_hstatus)
995 free(wp->w_hstatus);
996 for (i = 0; wp->w_cmdargs[i]; i++)
997 free(wp->w_cmdargs[i]);
998 if (wp->w_dir)
999 free(wp->w_dir);
1000 if (wp->w_term)
1001 free(wp->w_term);
1002 for (d = displays; d; d = d->d_next)
1004 if (d->d_other == wp)
1005 d->d_other = d->d_fore && d->d_fore->w_next != wp ? d->d_fore->w_next : wp->w_next;
1006 if (d->d_fore == wp)
1007 d->d_fore = NULL;
1008 for (cv = d->d_cvlist; cv; cv = cv->c_next)
1010 for (l = cv->c_layer; l; l = l->l_next)
1011 if (l->l_layfn == &WinLf)
1012 break;
1013 if (!l)
1014 continue;
1015 if ((struct win *)l->l_data != wp)
1016 continue;
1017 if (cv->c_layer == wp->w_savelayer)
1018 wp->w_savelayer = 0;
1019 KillLayerChain(cv->c_layer);
1022 if (wp->w_savelayer)
1023 KillLayerChain(wp->w_savelayer);
1024 for (cv = wp->w_layer.l_cvlist; cv; cv = ncv)
1026 ncv = cv->c_lnext;
1027 cv->c_layer = &cv->c_blank;
1028 cv->c_blank.l_cvlist = cv;
1029 cv->c_lnext = 0;
1030 cv->c_xoff = cv->c_xs;
1031 cv->c_yoff = cv->c_ys;
1032 RethinkViewportOffsets(cv);
1034 wp->w_layer.l_cvlist = 0;
1035 if (flayer == &wp->w_layer)
1036 flayer = 0;
1037 LayerCleanupMemory(&wp->w_layer);
1039 #ifdef MULTIUSER
1040 FreeWindowAcl(wp);
1041 #endif /* MULTIUSER */
1042 evdeq(&wp->w_readev); /* just in case */
1043 evdeq(&wp->w_writeev); /* just in case */
1044 evdeq(&wp->w_silenceev);
1045 evdeq(&wp->w_destroyev);
1046 #ifdef COPY_PASTE
1047 FreePaster(&wp->w_paster);
1048 #endif
1049 free((char *)wp);
1052 static int
1053 OpenDevice(args, lflag, typep, namep)
1054 char **args;
1055 int lflag;
1056 int *typep;
1057 char **namep;
1059 char *arg = args[0];
1060 struct stat st;
1061 int f;
1063 if (!arg)
1064 return -1;
1065 if (strcmp(arg, "//group") == 0)
1067 *typep = W_TYPE_GROUP;
1068 *namep = "telnet";
1069 return 0;
1071 #ifdef BUILTIN_TELNET
1072 if (strcmp(arg, "//telnet") == 0)
1074 f = TelOpen(args + 1);
1075 lflag = 0;
1076 *typep = W_TYPE_TELNET;
1077 *namep = "telnet";
1079 else
1080 #endif
1081 if (strncmp(arg, "//", 2) == 0)
1083 Msg(0, "Invalid argument '%s'", arg);
1084 return -1;
1086 else if ((stat(arg, &st)) == 0 && S_ISCHR(st.st_mode))
1088 if (access(arg, R_OK | W_OK) == -1)
1090 Msg(errno, "Cannot access line '%s' for R/W", arg);
1091 return -1;
1093 debug("OpenDevice: OpenTTY\n");
1094 if ((f = OpenTTY(arg, args[1])) < 0)
1095 return -1;
1096 lflag = 0;
1097 *typep = W_TYPE_PLAIN;
1098 *namep = arg;
1100 else
1102 *typep = W_TYPE_PTY;
1103 f = OpenPTY(namep);
1104 if (f == -1)
1106 Msg(0, "No more PTYs.");
1107 return -1;
1109 #ifdef TIOCPKT
1111 int flag = 1;
1112 if (ioctl(f, TIOCPKT, (char *)&flag))
1114 Msg(errno, "TIOCPKT ioctl");
1115 close(f);
1116 return -1;
1119 #endif /* TIOCPKT */
1121 debug1("fcntl(%d, F_SETFL, FNBLOCK)\n", f);
1122 (void) fcntl(f, F_SETFL, FNBLOCK);
1123 #ifdef linux
1125 * Tenebreux (zeus@ns.acadiacom.net) has Linux 1.3.70 where select
1126 * gets confused in the following condition:
1127 * Open a pty-master side, request a flush on it, then set packet
1128 * mode and call select(). Select will return a possible read, where
1129 * the one byte response to the flush can be found. Select will
1130 * thereafter return a possible read, which yields I/O error.
1132 * If we request another flush *after* switching into packet mode,
1133 * this I/O error does not occur. We receive a single response byte
1134 * although we send two flush requests now.
1136 * Maybe we should not flush at all.
1138 * 10.5.96 jw.
1140 if (*typep == W_TYPE_PTY || *typep == W_TYPE_PLAIN)
1141 tcflush(f, TCIOFLUSH);
1142 #endif
1144 if (*typep != W_TYPE_PTY)
1145 return f;
1147 #ifndef PTYROFS
1148 #ifdef PTYGROUP
1149 if (chown(*namep, real_uid, PTYGROUP) && !eff_uid)
1150 #else
1151 if (chown(*namep, real_uid, real_gid) && !eff_uid)
1152 #endif
1154 Msg(errno, "chown tty");
1155 close(f);
1156 return -1;
1158 #ifdef UTMPOK
1159 if (chmod(*namep, lflag ? TtyMode : (TtyMode & ~022)) && !eff_uid)
1160 #else
1161 if (chmod(*namep, TtyMode) && !eff_uid)
1162 #endif
1164 Msg(errno, "chmod tty");
1165 close(f);
1166 return -1;
1168 #endif
1169 return f;
1173 * Fields w_width, w_height, aflag, number (and w_tty)
1174 * are read from struct win *win. No fields written.
1175 * If pwin is nonzero, filedescriptors are distributed
1176 * between win->w_tty and open(ttyn)
1179 static int
1180 ForkWindow(win, args, ttyn)
1181 struct win *win;
1182 char **args, *ttyn;
1184 int pid;
1185 char tebuf[25];
1186 char ebuf[20];
1187 char shellbuf[7 + MAXPATHLEN];
1188 char *proc;
1189 #ifndef TIOCSWINSZ
1190 char libuf[20], cobuf[20];
1191 #endif
1192 int newfd;
1193 int w = win->w_width;
1194 int h = win->w_height;
1195 #ifdef PSEUDOS
1196 int i, pat, wfdused;
1197 struct pseudowin *pwin = win->w_pwin;
1198 #endif
1199 int slave = -1;
1201 #ifdef O_NOCTTY
1202 if (pty_preopen)
1204 debug("pre-opening slave...\n");
1205 if ((slave = open(ttyn, O_RDWR|O_NOCTTY)) == -1)
1207 Msg(errno, "ttyn");
1208 return -1;
1211 #endif
1212 debug("forking...\n");
1213 proc = *args;
1214 if (proc == 0)
1216 args = ShellArgs;
1217 proc = *args;
1219 fflush(stdout);
1220 fflush(stderr);
1221 switch (pid = fork())
1223 case -1:
1224 Msg(errno, "fork");
1225 break;
1226 case 0:
1227 signal(SIGHUP, SIG_DFL);
1228 signal(SIGINT, SIG_DFL);
1229 signal(SIGQUIT, SIG_DFL);
1230 signal(SIGTERM, SIG_DFL);
1231 #ifdef BSDJOBS
1232 signal(SIGTTIN, SIG_DFL);
1233 signal(SIGTTOU, SIG_DFL);
1234 #endif
1235 #ifdef SIGPIPE
1236 signal(SIGPIPE, SIG_DFL);
1237 #endif
1238 #ifdef SIGXFSZ
1239 signal(SIGXFSZ, SIG_DFL);
1240 #endif
1242 displays = 0; /* beware of Panic() */
1243 if (setgid(real_gid) || setuid(real_uid))
1244 Panic(errno, "Setuid/gid");
1245 eff_uid = real_uid;
1246 eff_gid = real_gid;
1247 #ifdef PSEUDOS
1248 if (!pwin) /* ignore directory if pseudo */
1249 #endif
1250 if (win->w_dir && *win->w_dir && chdir(win->w_dir))
1251 Panic(errno, "Cannot chdir to %s", win->w_dir);
1253 if (display)
1255 brktty(D_userfd);
1256 freetty();
1258 else
1259 brktty(-1);
1260 #ifdef DEBUG
1261 if (dfp && dfp != stderr)
1262 fclose(dfp);
1263 #endif
1264 if (slave != -1)
1266 close(0);
1267 dup(slave);
1268 close(slave);
1269 closeallfiles(win->w_ptyfd);
1270 slave = dup(0);
1272 else
1273 closeallfiles(win->w_ptyfd);
1274 #ifdef DEBUG
1275 if (dfp) /* do not produce child debug, when debug is "off" */
1277 char buf[256];
1279 sprintf(buf, "%s/screen.child", DEBUGDIR);
1280 if ((dfp = fopen(buf, "a")) == 0)
1281 dfp = stderr;
1282 else
1283 (void) chmod(buf, 0666);
1285 debug1("=== ForkWindow: pid %d\n", (int)getpid());
1286 #endif
1287 /* Close the three /dev/null descriptors */
1288 close(0);
1289 close(1);
1290 close(2);
1291 newfd = -1;
1293 * distribute filedescriptors between the ttys
1295 #ifdef PSEUDOS
1296 pat = pwin ? pwin->p_fdpat :
1297 ((F_PFRONT<<(F_PSHIFT*2)) | (F_PFRONT<<F_PSHIFT) | F_PFRONT);
1298 debug1("Using window pattern 0x%x\n", pat);
1299 wfdused = 0;
1300 for(i = 0; i < 3; i++)
1302 if (pat & F_PFRONT << F_PSHIFT * i)
1304 if (newfd < 0)
1306 # ifdef O_NOCTTY
1307 if (separate_sids)
1308 newfd = open(ttyn, O_RDWR);
1309 else
1310 newfd = open(ttyn, O_RDWR|O_NOCTTY);
1311 # else
1312 newfd = open(ttyn, O_RDWR);
1313 # endif
1314 if (newfd < 0)
1315 Panic(errno, "Cannot open %s", ttyn);
1317 else
1318 dup(newfd);
1320 else
1322 dup(win->w_ptyfd);
1323 wfdused = 1;
1326 if (wfdused)
1329 * the pseudo window process should not be surprised with a
1330 * nonblocking filedescriptor. Poor Backend!
1332 debug1("Clearing NBLOCK on window-fd(%d)\n", win->w_ptyfd);
1333 if (fcntl(win->w_ptyfd, F_SETFL, 0))
1334 Msg(errno, "Warning: clear NBLOCK fcntl failed");
1336 #else /* PSEUDOS */
1337 # ifdef O_NOCTTY
1338 if (separate_sids)
1339 newfd = open(ttyn, O_RDWR);
1340 else
1341 newfd = open(ttyn, O_RDWR|O_NOCTTY);
1342 # else
1343 newfd = open(ttyn, O_RDWR);
1344 # endif
1345 if (newfd != 0)
1346 Panic(errno, "Cannot open %s", ttyn);
1347 dup(0);
1348 dup(0);
1349 #endif /* PSEUDOS */
1350 close(win->w_ptyfd);
1351 if (slave != -1)
1352 close(slave);
1353 if (newfd >= 0)
1355 struct mode fakemode, *modep;
1356 InitPTY(newfd);
1357 if (fgtty(newfd))
1358 Msg(errno, "fgtty");
1359 if (display)
1361 debug("ForkWindow: using display tty mode for new child.\n");
1362 modep = &D_OldMode;
1364 else
1366 debug("No display - creating tty setting\n");
1367 modep = &fakemode;
1368 InitTTY(modep, 0);
1369 #ifdef DEBUG
1370 DebugTTY(modep);
1371 #endif
1373 /* We only want echo if the users input goes to the pseudo
1374 * and the pseudo's stdout is not send to the window.
1376 #ifdef PSEUDOS
1377 if (pwin && (!(pat & F_UWP) || (pat & F_PBACK << F_PSHIFT)))
1379 debug1("clearing echo on pseudywin fd (pat %x)\n", pat);
1380 # if defined(POSIX) || defined(TERMIO)
1381 modep->tio.c_lflag &= ~ECHO;
1382 modep->tio.c_iflag &= ~ICRNL;
1383 # else
1384 modep->m_ttyb.sg_flags &= ~ECHO;
1385 # endif
1387 #endif
1388 SetTTY(newfd, modep);
1389 #ifdef TIOCSWINSZ
1390 glwz.ws_col = w;
1391 glwz.ws_row = h;
1392 (void) ioctl(newfd, TIOCSWINSZ, (char *)&glwz);
1393 #endif
1394 /* Always turn off nonblocking mode */
1395 (void)fcntl(newfd, F_SETFL, 0);
1397 #ifndef TIOCSWINSZ
1398 sprintf(libuf, "LINES=%d", h);
1399 sprintf(cobuf, "COLUMNS=%d", w);
1400 NewEnv[5] = libuf;
1401 NewEnv[6] = cobuf;
1402 #endif
1403 #ifdef MAPKEYS
1404 NewEnv[2] = MakeTermcap(display == 0 || win->w_aflag);
1405 #else
1406 if (win->w_aflag)
1407 NewEnv[2] = MakeTermcap(1);
1408 else
1409 NewEnv[2] = Termcap;
1410 #endif
1411 strcpy(shellbuf, "SHELL=");
1412 strncpy(shellbuf + 6, ShellProg + (*ShellProg == '-'), sizeof(shellbuf) - 7);
1413 shellbuf[sizeof(shellbuf) - 1] = 0;
1414 NewEnv[4] = shellbuf;
1415 debug1("ForkWindow: NewEnv[4] = '%s'\n", shellbuf);
1416 if (win->w_term && *win->w_term && strcmp(screenterm, win->w_term) &&
1417 (strlen(win->w_term) < 20))
1419 char *s1, *s2, tl;
1421 sprintf(tebuf, "TERM=%s", win->w_term);
1422 debug2("Makewindow %d with %s\n", win->w_number, tebuf);
1423 tl = strlen(win->w_term);
1424 NewEnv[1] = tebuf;
1425 if ((s1 = index(NewEnv[2], '|')))
1427 if ((s2 = index(++s1, '|')))
1429 if (strlen(NewEnv[2]) - (s2 - s1) + tl < 1024)
1431 bcopy(s2, s1 + tl, strlen(s2) + 1);
1432 bcopy(win->w_term, s1, tl);
1437 sprintf(ebuf, "WINDOW=%d", win->w_number);
1438 NewEnv[3] = ebuf;
1440 if (*proc == '-')
1441 proc++;
1442 if (!*proc)
1443 proc = DefaultShell;
1444 debug1("calling execvpe %s\n", proc);
1445 execvpe(proc, args, NewEnv);
1446 debug1("exec error: %d\n", errno);
1447 Panic(errno, "Cannot exec '%s'", proc);
1448 default:
1449 break;
1451 if (slave != -1)
1452 close(slave);
1453 return pid;
1456 #ifndef HAVE_EXECVPE
1457 void
1458 execvpe(prog, args, env)
1459 char *prog, **args, **env;
1461 register char *path = NULL, *p;
1462 char buf[1024];
1463 char *shargs[MAXARGS + 1];
1464 register int i, eaccess = 0;
1466 if (rindex(prog, '/'))
1467 path = "";
1468 if (!path && !(path = getenv("PATH")))
1469 path = DefaultPath;
1472 for (p = buf; *path && *path != ':'; path++)
1473 if (p - buf < (int)sizeof(buf) - 2)
1474 *p++ = *path;
1475 if (p > buf)
1476 *p++ = '/';
1477 if (p - buf + strlen(prog) >= sizeof(buf) - 1)
1478 continue;
1479 strcpy(p, prog);
1480 execve(buf, args, env);
1481 switch (errno)
1483 case ENOEXEC:
1484 shargs[0] = DefaultShell;
1485 shargs[1] = buf;
1486 for (i = 1; (shargs[i + 1] = args[i]) != NULL; ++i)
1488 execve(DefaultShell, shargs, env);
1489 return;
1490 case EACCES:
1491 eaccess = 1;
1492 break;
1493 case ENOMEM:
1494 case E2BIG:
1495 case ETXTBSY:
1496 return;
1498 } while (*path++);
1499 if (eaccess)
1500 errno = EACCES;
1502 #endif
1504 #ifdef PSEUDOS
1507 winexec(av)
1508 char **av;
1510 char **pp;
1511 char *p, *s, *t;
1512 int i, r = 0, l = 0;
1513 struct win *w;
1514 extern struct display *display;
1515 extern struct win *windows;
1516 struct pseudowin *pwin;
1517 int type;
1519 if ((w = display ? fore : windows) == NULL)
1520 return -1;
1521 if (!*av || w->w_pwin)
1523 Msg(0, "Filter running: %s", w->w_pwin ? w->w_pwin->p_cmd : "(none)");
1524 return -1;
1526 if (w->w_ptyfd < 0)
1528 Msg(0, "You feel dead inside.");
1529 return -1;
1531 if (!(pwin = (struct pseudowin *)calloc(1, sizeof(struct pseudowin))))
1533 Msg(0, "%s", strnomem);
1534 return -1;
1537 /* allow ^a:!!./ttytest as a short form for ^a:exec !.. ./ttytest */
1538 for (s = *av; *s == ' '; s++)
1540 for (p = s; *p == ':' || *p == '.' || *p == '!'; p++)
1542 if (*p != '|')
1543 while (*p && p > s && p[-1] == '.')
1544 p--;
1545 if (*p == '|')
1547 l = F_UWP;
1548 p++;
1550 if (*p)
1551 av[0] = p;
1552 else
1553 av++;
1555 t = pwin->p_cmd;
1556 for (i = 0; i < 3; i++)
1558 *t = (s < p) ? *s++ : '.';
1559 switch (*t++)
1561 case '.':
1562 case '|':
1563 l |= F_PFRONT << (i * F_PSHIFT);
1564 break;
1565 case '!':
1566 l |= F_PBACK << (i * F_PSHIFT);
1567 break;
1568 case ':':
1569 l |= F_PBOTH << (i * F_PSHIFT);
1570 break;
1574 if (l & F_UWP)
1576 *t++ = '|';
1577 if ((l & F_PMASK) == F_PFRONT)
1579 *pwin->p_cmd = '!';
1580 l ^= F_PFRONT | F_PBACK;
1583 if (!(l & F_PBACK))
1584 l |= F_UWP;
1585 *t++ = ' ';
1586 pwin->p_fdpat = l;
1587 debug1("winexec: '%#x'\n", pwin->p_fdpat);
1589 l = MAXSTR - 4;
1590 for (pp = av; *pp; pp++)
1592 p = *pp;
1593 while (*p && l-- > 0)
1594 *t++ = *p++;
1595 if (l <= 0)
1596 break;
1597 *t++ = ' ';
1599 *--t = '\0';
1600 debug1("%s\n", pwin->p_cmd);
1602 if ((pwin->p_ptyfd = OpenDevice(av, 0, &type, &t)) < 0)
1604 free((char *)pwin);
1605 return -1;
1607 strncpy(pwin->p_tty, t, MAXSTR - 1);
1608 w->w_pwin = pwin;
1609 if (type != W_TYPE_PTY)
1611 FreePseudowin(w);
1612 Msg(0, "Cannot only use commands as pseudo win.");
1613 return -1;
1615 if (!(pwin->p_fdpat & F_PFRONT))
1616 evdeq(&w->w_readev);
1617 #ifdef TIOCPKT
1619 int flag = 0;
1621 if (ioctl(pwin->p_ptyfd, TIOCPKT, (char *)&flag))
1623 Msg(errno, "TIOCPKT pwin ioctl");
1624 FreePseudowin(w);
1625 return -1;
1627 if (w->w_type == W_TYPE_PTY && !(pwin->p_fdpat & F_PFRONT))
1629 if (ioctl(w->w_ptyfd, TIOCPKT, (char *)&flag))
1631 Msg(errno, "TIOCPKT win ioctl");
1632 FreePseudowin(w);
1633 return -1;
1637 #endif /* TIOCPKT */
1639 pwin->p_readev.fd = pwin->p_writeev.fd = pwin->p_ptyfd;
1640 pwin->p_readev.type = EV_READ;
1641 pwin->p_writeev.type = EV_WRITE;
1642 pwin->p_readev.data = pwin->p_writeev.data = (char *)w;
1643 pwin->p_readev.handler = pseu_readev_fn;
1644 pwin->p_writeev.handler = pseu_writeev_fn;
1645 pwin->p_writeev.condpos = &pwin->p_inlen;
1646 if (pwin->p_fdpat & (F_PFRONT << F_PSHIFT * 2 | F_PFRONT << F_PSHIFT))
1647 evenq(&pwin->p_readev);
1648 evenq(&pwin->p_writeev);
1649 r = pwin->p_pid = ForkWindow(w, av, t);
1650 if (r < 0)
1651 FreePseudowin(w);
1652 return r;
1655 void
1656 FreePseudowin(w)
1657 struct win *w;
1659 struct pseudowin *pwin = w->w_pwin;
1661 ASSERT(pwin);
1662 if (fcntl(w->w_ptyfd, F_SETFL, FNBLOCK))
1663 Msg(errno, "Warning: FreePseudowin: NBLOCK fcntl failed");
1664 #ifdef TIOCPKT
1665 if (w->w_type == W_TYPE_PTY && !(pwin->p_fdpat & F_PFRONT))
1667 int flag = 1;
1668 if (ioctl(w->w_ptyfd, TIOCPKT, (char *)&flag))
1669 Msg(errno, "Warning: FreePseudowin: TIOCPKT win ioctl");
1671 #endif
1672 /* should be able to use CloseDevice() here */
1673 (void)chmod(pwin->p_tty, 0666);
1674 (void)chown(pwin->p_tty, 0, 0);
1675 if (pwin->p_ptyfd >= 0)
1676 close(pwin->p_ptyfd);
1677 evdeq(&pwin->p_readev);
1678 evdeq(&pwin->p_writeev);
1679 if (w->w_readev.condneg == &pwin->p_inlen)
1680 w->w_readev.condpos = w->w_readev.condneg = 0;
1681 evenq(&w->w_readev);
1682 free((char *)pwin);
1683 w->w_pwin = NULL;
1686 #endif /* PSEUDOS */
1689 #ifdef MULTIUSER
1691 * returns 0, if the lock really has been released
1694 ReleaseAutoWritelock(dis, w)
1695 struct display *dis;
1696 struct win *w;
1698 debug2("ReleaseAutoWritelock: user %s, window %d\n",
1699 dis->d_user->u_name, w->w_number);
1701 /* release auto writelock when user has no other display here */
1702 if (w->w_wlock == WLOCK_AUTO && w->w_wlockuser == dis->d_user)
1704 struct display *d;
1706 for (d = displays; d; d = d->d_next)
1707 if (( d != dis) && (d->d_fore == w) && (d->d_user == dis->d_user))
1708 break;
1709 debug3("%s %s autolock on win %d\n",
1710 dis->d_user->u_name, d ? "keeps" : "releases", w->w_number);
1711 if (!d)
1713 w->w_wlockuser = NULL;
1714 return 0;
1717 return 1;
1721 * returns 0, if the lock really could be obtained
1724 ObtainAutoWritelock(d, w)
1725 struct display *d;
1726 struct win *w;
1728 if ((w->w_wlock == WLOCK_AUTO) &&
1729 !AclCheckPermWin(d->d_user, ACL_WRITE, w) &&
1730 !w->w_wlockuser)
1732 debug2("%s obtained auto writelock for exported window %d\n",
1733 d->d_user->u_name, w->w_number);
1734 w->w_wlockuser = d->d_user;
1735 return 0;
1737 return 1;
1740 #endif /* MULTIUSER */
1744 /********************************************************************/
1746 #ifdef COPY_PASTE
1747 static void
1748 paste_slowev_fn(ev, data)
1749 struct event *ev;
1750 char *data;
1752 struct paster *pa = (struct paster *)data;
1753 struct win *p;
1755 int l = 1;
1756 flayer = pa->pa_pastelayer;
1757 if (!flayer)
1758 pa->pa_pastelen = 0;
1759 if (!pa->pa_pastelen)
1760 return;
1761 p = Layer2Window(flayer);
1762 DoProcess(p, &pa->pa_pasteptr, &l, pa);
1763 pa->pa_pastelen -= 1 - l;
1764 if (pa->pa_pastelen > 0)
1766 SetTimeout(&pa->pa_slowev, p->w_slowpaste);
1767 evenq(&pa->pa_slowev);
1770 #endif
1773 static int
1774 muchpending(p, ev)
1775 struct win *p;
1776 struct event *ev;
1778 struct canvas *cv;
1779 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
1781 display = cv->c_display;
1782 if (D_status == STATUS_ON_WIN && !D_status_bell)
1784 /* wait 'til status is gone */
1785 debug("BLOCKING because of status\n");
1786 ev->condpos = &const_one;
1787 ev->condneg = &D_status;
1788 return 1;
1790 debug2("muchpending %s %d: ", D_usertty, D_blocked);
1791 debug3("%d %d %d\n", D_obufp - D_obuf, D_obufmax, D_blocked_fuzz);
1792 if (D_blocked)
1793 continue;
1794 if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
1796 if (D_nonblock == 0)
1798 debug1("obuf is full, stopping output to display %s\n", D_usertty);
1799 D_blocked = 1;
1800 continue;
1802 debug("BLOCKING because of full obuf\n");
1803 ev->condpos = &D_obuffree;
1804 ev->condneg = &D_obuflenmax;
1805 if (D_nonblock > 0 && !D_blockedev.queued)
1807 debug1("created timeout of %g secs\n", D_nonblock/1000.);
1808 SetTimeout(&D_blockedev, D_nonblock);
1809 evenq(&D_blockedev);
1811 return 1;
1814 return 0;
1817 static void
1818 win_readev_fn(ev, data)
1819 struct event *ev;
1820 char *data;
1822 struct win *p = (struct win *)data;
1823 char buf[IOSIZE], *bp;
1824 int size, len;
1825 #ifdef PSEUDOS
1826 int wtop;
1827 #endif
1829 bp = buf;
1830 size = IOSIZE;
1832 #ifdef PSEUDOS
1833 wtop = p->w_pwin && W_WTOP(p);
1834 if (wtop)
1836 ASSERT(sizeof(p->w_pwin->p_inbuf) == IOSIZE);
1837 size = IOSIZE - p->w_pwin->p_inlen;
1838 if (size <= 0)
1840 ev->condpos = &const_IOSIZE;
1841 ev->condneg = &p->w_pwin->p_inlen;
1842 return;
1845 #endif
1846 if (p->w_layer.l_cvlist && muchpending(p, ev))
1847 return;
1848 #ifdef ZMODEM
1849 if (!p->w_zdisplay)
1850 #endif
1851 if (p->w_blocked)
1853 ev->condpos = &const_one;
1854 ev->condneg = &p->w_blocked;
1855 return;
1857 if (ev->condpos)
1858 ev->condpos = ev->condneg = 0;
1860 if ((len = p->w_outlen))
1862 p->w_outlen = 0;
1863 WriteString(p, p->w_outbuf, len);
1864 return;
1867 debug1("going to read from window fd %d\n", ev->fd);
1868 if ((len = read(ev->fd, buf, size)) < 0)
1870 if (errno == EINTR || errno == EAGAIN)
1871 return;
1872 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1873 if (errno == EWOULDBLOCK)
1874 return;
1875 #endif
1876 debug2("Window %d: read error (errno %d) - killing window\n", p->w_number, errno);
1877 #ifdef BSDWAIT
1878 WindowDied(p, (union wait)0, 0);
1879 #else
1880 WindowDied(p, 0, 0);
1881 #endif
1882 return;
1884 if (len == 0)
1886 debug1("Window %d: EOF - killing window\n", p->w_number);
1887 #ifdef BSDWAIT
1888 WindowDied(p, (union wait)0, 0);
1889 #else
1890 WindowDied(p, 0, 0);
1891 #endif
1892 return;
1894 debug1(" -> %d bytes\n", len);
1895 #ifdef TIOCPKT
1896 if (p->w_type == W_TYPE_PTY)
1898 if (buf[0])
1900 debug1("PAKET %x\n", buf[0]);
1901 if (buf[0] & TIOCPKT_NOSTOP)
1902 WNewAutoFlow(p, 0);
1903 if (buf[0] & TIOCPKT_DOSTOP)
1904 WNewAutoFlow(p, 1);
1906 bp++;
1907 len--;
1909 #endif
1910 #ifdef BUILTIN_TELNET
1911 if (p->w_type == W_TYPE_TELNET)
1912 len = TelIn(p, bp, len, buf + sizeof(buf) - (bp + len));
1913 #endif
1914 if (len == 0)
1915 return;
1916 #ifdef ZMODEM
1917 if (zmodem_mode && zmodem_parse(p, bp, len))
1918 return;
1919 #endif
1920 #ifdef PSEUDOS
1921 if (wtop)
1923 debug("sending input to pwin\n");
1924 bcopy(bp, p->w_pwin->p_inbuf + p->w_pwin->p_inlen, len);
1925 p->w_pwin->p_inlen += len;
1927 #endif
1929 LayPause(&p->w_layer, 1);
1930 WriteString(p, bp, len);
1931 LayPause(&p->w_layer, 0);
1933 return;
1937 static void
1938 win_writeev_fn(ev, data)
1939 struct event *ev;
1940 char *data;
1942 struct win *p = (struct win *)data;
1943 int len;
1944 if (p->w_inlen)
1946 debug2("writing %d bytes to win %d\n", p->w_inlen, p->w_number);
1947 if ((len = write(ev->fd, p->w_inbuf, p->w_inlen)) <= 0)
1948 len = p->w_inlen; /* dead window */
1949 if ((p->w_inlen -= len))
1950 bcopy(p->w_inbuf + len, p->w_inbuf, p->w_inlen);
1952 #ifdef COPY_PASTE
1953 if (p->w_paster.pa_pastelen && !p->w_slowpaste)
1955 struct paster *pa = &p->w_paster;
1956 flayer = pa->pa_pastelayer;
1957 if (flayer)
1958 DoProcess(p, &pa->pa_pasteptr, &pa->pa_pastelen, pa);
1960 #endif
1961 return;
1966 #ifdef PSEUDOS
1968 static void
1969 pseu_readev_fn(ev, data)
1970 struct event *ev;
1971 char *data;
1973 struct win *p = (struct win *)data;
1974 char buf[IOSIZE];
1975 int size, ptow, len;
1977 size = IOSIZE;
1979 ptow = W_PTOW(p);
1980 if (ptow)
1982 ASSERT(sizeof(p->w_inbuf) == IOSIZE);
1983 size = IOSIZE - p->w_inlen;
1984 if (size <= 0)
1986 ev->condpos = &const_IOSIZE;
1987 ev->condneg = &p->w_inlen;
1988 return;
1991 if (p->w_layer.l_cvlist && muchpending(p, ev))
1992 return;
1993 if (p->w_blocked)
1995 ev->condpos = &const_one;
1996 ev->condneg = &p->w_blocked;
1997 return;
1999 if (ev->condpos)
2000 ev->condpos = ev->condneg = 0;
2002 if ((len = p->w_outlen))
2004 p->w_outlen = 0;
2005 WriteString(p, p->w_outbuf, len);
2006 return;
2009 if ((len = read(ev->fd, buf, size)) <= 0)
2011 if (errno == EINTR || errno == EAGAIN)
2012 return;
2013 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
2014 if (errno == EWOULDBLOCK)
2015 return;
2016 #endif
2017 debug2("Window %d: pseudowin read error (errno %d) -- removing pseudowin\n", p->w_number, len ? errno : 0);
2018 FreePseudowin(p);
2019 return;
2021 /* no packet mode on pseudos! */
2022 if (ptow)
2024 bcopy(buf, p->w_inbuf + p->w_inlen, len);
2025 p->w_inlen += len;
2027 WriteString(p, buf, len);
2028 return;
2031 static void
2032 pseu_writeev_fn(ev, data)
2033 struct event *ev;
2034 char *data;
2036 struct win *p = (struct win *)data;
2037 struct pseudowin *pw = p->w_pwin;
2038 int len;
2040 ASSERT(pw);
2041 if (pw->p_inlen == 0)
2042 return;
2043 if ((len = write(ev->fd, pw->p_inbuf, pw->p_inlen)) <= 0)
2044 len = pw->p_inlen; /* dead pseudo */
2045 if ((p->w_pwin->p_inlen -= len))
2046 bcopy(p->w_pwin->p_inbuf + len, p->w_pwin->p_inbuf, p->w_pwin->p_inlen);
2050 #endif /* PSEUDOS */
2052 static void
2053 win_silenceev_fn(ev, data)
2054 struct event *ev;
2055 char *data;
2057 struct win *p = (struct win *)data;
2058 struct canvas *cv;
2059 debug1("FOUND silence win %d\n", p->w_number);
2060 for (display = displays; display; display = display->d_next)
2062 for (cv = D_cvlist; cv; cv = cv->c_next)
2063 if (cv->c_layer->l_bottom == &p->w_layer)
2064 break;
2065 if (cv)
2066 continue; /* user already sees window */
2067 #ifdef MULTIUSER
2068 if (!(ACLBYTE(p->w_lio_notify, D_user->u_id) & ACLBIT(D_user->u_id)))
2069 continue;
2070 #endif
2071 Msg(0, "Window %d: silence for %d seconds", p->w_number, p->w_silencewait);
2075 static void
2076 win_destroyev_fn(ev, data)
2077 struct event *ev;
2078 char *data;
2080 struct win *p = (struct win *)ev->data;
2081 WindowDied(p, p->w_exitstatus, 1);
2084 #ifdef ZMODEM
2086 static int
2087 zmodem_parse(p, bp, len)
2088 struct win *p;
2089 char *bp;
2090 int len;
2092 int i;
2093 char *b2 = bp;
2094 for (i = 0; i < len; i++, b2++)
2096 if (p->w_zauto == 0)
2098 for (; i < len; i++, b2++)
2099 if (*b2 == 030)
2100 break;
2101 if (i == len)
2102 break;
2103 if (i > 1 && b2[-1] == '*' && b2[-2] == '*')
2104 p->w_zauto = 3;
2105 continue;
2107 if (p->w_zauto > 5 || *b2 == "**\030B00"[p->w_zauto] || (p->w_zauto == 5 && *b2 == '1') || (p->w_zauto == 5 && p->w_zdisplay && *b2 == '8'))
2109 if (++p->w_zauto < 6)
2110 continue;
2111 if (p->w_zauto == 6)
2112 p->w_zauto = 0;
2113 if (!p->w_zdisplay)
2115 if (i > 6)
2116 WriteString(p, bp, i + 1 - 6);
2117 WriteString(p, "\r\n", 2);
2118 zmodem_found(p, *b2 == '1', b2 + 1, len - i - 1);
2119 return 1;
2121 else if (p->w_zauto == 7 || *b2 == '8')
2123 int se = p->w_zdisplay->d_blocked == 2 ? 'O' : '\212';
2124 for (; i < len; i++, b2++)
2125 if (*b2 == se)
2126 break;
2127 if (i < len)
2129 zmodem_abort(p, 0);
2130 D_blocked = 0;
2131 D_readev.condpos = D_readev.condneg = 0;
2132 while (len-- > 0)
2133 AddChar(*bp++);
2134 Flush(0);
2135 Activate(D_fore ? D_fore->w_norefresh : 0);
2136 return 1;
2138 p->w_zauto = 6;
2141 else
2142 p->w_zauto = *b2 == '*' ? (p->w_zauto == 2 ? 2 : 1) : 0;
2144 if (p->w_zauto == 0 && bp[len - 1] == '*')
2145 p->w_zauto = len > 1 && bp[len - 2] == '*' ? 2 : 1;
2146 if (p->w_zdisplay)
2148 display = p->w_zdisplay;
2149 while (len-- > 0)
2150 AddChar(*bp++);
2151 return 1;
2153 return 0;
2156 static void
2157 zmodem_fin(buf, len, data)
2158 char *buf;
2159 int len;
2160 char *data;
2162 char *s;
2163 int n;
2165 if (len)
2166 RcLine(buf, strlen(buf) + 1);
2167 else
2169 s = "\030\030\030\030\030\030\030\030\030\030";
2170 n = strlen(s);
2171 LayProcess(&s, &n);
2175 static void
2176 zmodem_found(p, send, bp, len)
2177 struct win *p;
2178 int send;
2179 char *bp;
2180 int len;
2182 char *s;
2183 int i, n;
2184 extern int zmodem_mode;
2186 /* check for abort sequence */
2187 n = 0;
2188 for (i = 0; i < len ; i++)
2189 if (bp[i] != 030)
2190 n = 0;
2191 else if (++n > 4)
2192 return;
2193 if (zmodem_mode == 3 || (zmodem_mode == 1 && p->w_type != W_TYPE_PLAIN))
2195 struct display *d, *olddisplay;
2197 olddisplay = display;
2198 d = p->w_lastdisp;
2199 if (!d || d->d_fore != p)
2200 for (d = displays; d; d = d->d_next)
2201 if (d->d_fore == p)
2202 break;
2203 if (!d && p->w_layer.l_cvlist)
2204 d = p->w_layer.l_cvlist->c_display;
2205 if (!d)
2206 d = displays;
2207 if (!d)
2208 return;
2209 display = d;
2210 RemoveStatus();
2211 p->w_zdisplay = display;
2212 D_blocked = 2 + send;
2213 flayer = &p->w_layer;
2214 ZmodemPage();
2215 display = d;
2216 evdeq(&D_blockedev);
2217 D_readev.condpos = &const_IOSIZE;
2218 D_readev.condneg = &p->w_inlen;
2219 ClearAll();
2220 GotoPos(0, 0);
2221 SetRendition(&mchar_blank);
2222 AddStr("Zmodem active\r\n\r\n");
2223 AddStr(send ? "**\030B01" : "**\030B00");
2224 while (len-- > 0)
2225 AddChar(*bp++);
2226 display = olddisplay;
2227 return;
2229 flayer = &p->w_layer;
2230 Input(":", 100, INP_COOKED, zmodem_fin, NULL, 0);
2231 s = send ? zmodem_sendcmd : zmodem_recvcmd;
2232 n = strlen(s);
2233 LayProcess(&s, &n);
2236 void
2237 zmodem_abort(p, d)
2238 struct win *p;
2239 struct display *d;
2241 struct display *olddisplay = display;
2242 struct layer *oldflayer = flayer;
2243 if (p)
2245 if (p->w_savelayer && p->w_savelayer->l_next)
2247 if (oldflayer == p->w_savelayer)
2248 oldflayer = flayer->l_next;
2249 flayer = p->w_savelayer;
2250 ExitOverlayPage();
2252 p->w_zdisplay = 0;
2253 p->w_zauto = 0;
2254 LRefreshAll(&p->w_layer, 0);
2256 if (d)
2258 display = d;
2259 D_blocked = 0;
2260 D_readev.condpos = D_readev.condneg = 0;
2261 Activate(D_fore ? D_fore->w_norefresh : 0);
2263 display = olddisplay;
2264 flayer = oldflayer;
2267 #endif
2270 WindowChangeNumber(struct win *win, int n)
2272 struct win *p;
2273 int old = win->w_number;
2275 if (n < 0 || n >= maxwin)
2277 Msg(0, "Given window position is invalid.");
2278 return 0;
2281 p = wtab[n];
2282 wtab[n] = win;
2283 win->w_number = n;
2284 wtab[old] = p;
2285 if (p)
2286 p->w_number = old;
2287 #ifdef MULTIUSER
2288 /* exchange the acls for these windows. */
2289 AclWinSwap(old, n);
2290 #endif
2291 #ifdef UTMPOK
2292 /* exchange the utmp-slots for these windows */
2293 if ((win->w_slot != (slot_t) -1) && (win->w_slot != (slot_t) 0))
2295 RemoveUtmp(win);
2296 SetUtmp(win);
2298 if (p && (p->w_slot != (slot_t) -1) && (p->w_slot != (slot_t) 0))
2300 /* XXX: first display wins? */
2301 #if 0
2302 /* Does this make more sense? */
2303 display = p->w_lastdisp ? p->w_lastdisp : p->w_layer.l_cvlist ? p->w_layer.l_cvlist->c_display : 0;
2304 #else
2305 display = win->w_layer.l_cvlist ? win->w_layer.l_cvlist->c_display : 0;
2306 #endif
2307 RemoveUtmp(p);
2308 SetUtmp(p);
2310 #endif
2312 WindowChanged(win, 'n');
2313 WindowChanged((struct win *)0, 'w');
2314 WindowChanged((struct win *)0, 'W');
2315 WindowChanged((struct win *)0, 0);
2316 return 1;