Copyright for 2009
[screen-lua.git] / src / window.c
blob4754a98e9f98e5f3788a0b392de466ecd3eb00a2
1 /* Copyright (c) 2008, 2009
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Micah Cowan (micah@cowan.name)
5 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
6 * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
7 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
8 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
9 * Copyright (c) 1987 Oliver Laumann
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3, or (at your option)
14 * any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program (see the file COPYING); if not, see
23 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <signal.h>
32 #include <fcntl.h>
33 #ifndef sun
34 # include <sys/ioctl.h>
35 #endif
37 #include "config.h"
39 #include "screen.h"
40 #include "extern.h"
41 #include "logfile.h" /* logfopen() */
43 extern struct display *displays, *display;
44 extern struct win *windows, *fore, *wtab[], *console_window;
45 extern char *ShellArgs[];
46 extern char *ShellProg;
47 extern char screenterm[];
48 extern char *screenlogfile;
49 extern char HostName[];
50 extern int TtyMode;
51 extern int SilenceWait;
52 extern int real_uid, real_gid, eff_uid, eff_gid;
53 extern char Termcap[];
54 extern char **NewEnv;
55 extern int visual_bell, maxwin;
56 extern struct event logflushev;
57 extern int log_flush, logtstamp_after;
58 extern int ZombieKey_destroy, ZombieKey_resurrect, ZombieKey_onerror;
59 extern struct layer *flayer;
60 extern int maxusercount;
61 extern int pty_preopen;
62 #ifdef ZMODEM
63 extern int zmodem_mode;
64 extern struct mchar mchar_blank;
65 extern char *zmodem_sendcmd;
66 extern char *zmodem_recvcmd;
67 #endif
69 #if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
70 extern struct winsize glwz;
71 #endif
73 #ifdef O_NOCTTY
74 extern int separate_sids;
75 #endif
77 static void WinProcess __P((char **, int *));
78 static void WinRedisplayLine __P((int, int, int, int));
79 static void WinClearLine __P((int, int, int, int));
80 static int WinRewrite __P((int, int, int, struct mchar *, int));
81 static int WinResize __P((int, int));
82 static void WinRestore __P((void));
83 static int DoAutolf __P((char *, int *, int));
84 static void ZombieProcess __P((char **, int *));
85 static void win_readev_fn __P((struct event *, char *));
86 static void win_writeev_fn __P((struct event *, char *));
87 static int muchpending __P((struct win *, struct event *));
88 #ifdef COPY_PASTE
89 static void paste_slowev_fn __P((struct event *, char *));
90 #endif
91 #ifdef PSEUDOS
92 static void pseu_readev_fn __P((struct event *, char *));
93 static void pseu_writeev_fn __P((struct event *, char *));
94 #endif
95 static void win_silenceev_fn __P((struct event *, char *));
97 static int OpenDevice __P((char **, int, int *, char **));
98 static int ForkWindow __P((struct win *, char **, char *));
99 #ifdef ZMODEM
100 static void zmodem_found __P((struct win *, int, char *, int));
101 static void zmodem_fin __P((char *, int, char *));
102 static int zmodem_parse __P((struct win *, char *, int));
103 #endif
107 int VerboseCreate = 0; /* XXX move this to user.h */
109 char DefaultShell[] = "/bin/sh";
110 static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
112 /* keep this in sync with the structure definition in window.h */
113 struct NewWindow nwin_undef =
115 -1, /* StartAt */
116 (char *)0, /* aka */
117 (char **)0, /* args */
118 (char *)0, /* dir */
119 (char *)0, /* term */
120 -1, /* aflag */
121 -1, /* flowflag */
122 -1, /* lflag */
123 -1, /* histheight */
124 -1, /* monitor */
125 -1, /* wlock */
126 -1, /* silence */
127 -1, /* wrap */
128 -1, /* logging */
129 -1, /* slowpaste */
130 -1, /* gr */
131 -1, /* c1 */
132 -1, /* bce */
133 -1, /* encoding */
134 (char *)0, /* hstatus */
135 (char *)0 /* charset */
138 struct NewWindow nwin_default =
140 0, /* StartAt */
141 0, /* aka */
142 ShellArgs, /* args */
143 0, /* dir */
144 screenterm, /* term */
145 0, /* aflag */
146 1*FLOW_NOW, /* flowflag */
147 LOGINDEFAULT, /* lflag */
148 DEFAULTHISTHEIGHT, /* histheight */
149 MON_OFF, /* monitor */
150 WLOCK_OFF, /* wlock */
151 0, /* silence */
152 1, /* wrap */
153 0, /* logging */
154 0, /* slowpaste */
155 0, /* gr */
156 1, /* c1 */
157 0, /* bce */
158 0, /* encoding */
159 (char *)0, /* hstatus */
160 (char *)0 /* charset */
163 struct NewWindow nwin_options;
165 static int const_IOSIZE = IOSIZE;
166 static int const_one = 1;
168 void
169 nwin_compose(def, new, res)
170 struct NewWindow *def, *new, *res;
172 #define COMPOSE(x) res->x = new->x != nwin_undef.x ? new->x : def->x
173 COMPOSE(StartAt);
174 COMPOSE(aka);
175 COMPOSE(args);
176 COMPOSE(dir);
177 COMPOSE(term);
178 COMPOSE(aflag);
179 COMPOSE(flowflag);
180 COMPOSE(lflag);
181 COMPOSE(histheight);
182 COMPOSE(monitor);
183 COMPOSE(wlock);
184 COMPOSE(silence);
185 COMPOSE(wrap);
186 COMPOSE(Lflag);
187 COMPOSE(slow);
188 COMPOSE(gr);
189 COMPOSE(c1);
190 COMPOSE(bce);
191 COMPOSE(encoding);
192 COMPOSE(hstatus);
193 COMPOSE(charset);
194 #undef COMPOSE
197 /*****************************************************************
199 * The window layer functions
202 struct LayFuncs WinLf =
204 WinProcess,
206 WinRedisplayLine,
207 WinClearLine,
208 WinRewrite,
209 WinResize,
210 WinRestore
213 static int
214 DoAutolf(buf, lenp, fr)
215 char *buf;
216 int *lenp;
217 int fr;
219 char *p;
220 int len = *lenp;
221 int trunc = 0;
223 for (p = buf; len > 0; p++, len--)
225 if (*p != '\r')
226 continue;
227 if (fr-- <= 0)
229 trunc++;
230 len--;
232 if (len == 0)
233 break;
234 bcopy(p, p + 1, len++);
235 p[1] = '\n';
237 *lenp = p - buf;
238 return trunc;
241 static void
242 WinProcess(bufpp, lenp)
243 char **bufpp;
244 int *lenp;
246 int l2 = 0, f, *ilen, l = *lenp, trunc;
247 char *ibuf;
249 debug1("WinProcess: %d bytes\n", *lenp);
250 fore = (struct win *)flayer->l_data;
252 if (fore->w_type == W_TYPE_GROUP)
254 *bufpp += *lenp;
255 *lenp = 0;
256 return;
258 if (fore->w_ptyfd < 0) /* zombie? */
260 ZombieProcess(bufpp, lenp);
261 return;
263 #ifdef MULTIUSER
264 /* a pending writelock is this:
265 * fore->w_wlock == WLOCK_AUTO, fore->w_wlockuse = NULL
266 * The user who wants to use this window next, will get the lock, if he can.
268 if (display && fore->w_wlock == WLOCK_AUTO &&
269 !fore->w_wlockuser && !AclCheckPermWin(D_user, ACL_WRITE, fore))
271 fore->w_wlockuser = D_user;
272 debug2("window %d: pending writelock grabbed by user %s\n",
273 fore->w_number, fore->w_wlockuser->u_name);
275 /* if w_wlock is set, only one user may write, else we check acls */
276 if (display && ((fore->w_wlock == WLOCK_OFF) ?
277 AclCheckPermWin(D_user, ACL_WRITE, fore) :
278 (D_user != fore->w_wlockuser)))
280 debug2("window %d, user %s: ", fore->w_number, D_user->u_name);
281 debug2("writelock %d (wlockuser %s)\n", fore->w_wlock,
282 fore->w_wlockuser ? fore->w_wlockuser->u_name : "NULL");
283 /* XXX FIXME only display !*/
284 WBell(fore, visual_bell);
285 *bufpp += *lenp;
286 *lenp = 0;
287 return;
289 #endif /* MULTIUSER */
291 #ifdef BUILTIN_TELNET
292 if (fore->w_type == W_TYPE_TELNET && TelIsline(fore) && *bufpp != fore->w_telbuf)
294 TelProcessLine(bufpp, lenp);
295 return;
297 #endif
299 #ifdef PSEUDOS
300 if (W_UWP(fore))
302 /* we send the user input to our pseudowin */
303 ibuf = fore->w_pwin->p_inbuf; ilen = &fore->w_pwin->p_inlen;
304 f = sizeof(fore->w_pwin->p_inbuf) - *ilen;
306 else
307 #endif /* PSEUDOS */
309 /* we send the user input to the window */
310 ibuf = fore->w_inbuf; ilen = &fore->w_inlen;
311 f = sizeof(fore->w_inbuf) - *ilen;
314 if (l > f)
315 l = f;
316 #ifdef BUILTIN_TELNET
317 while (l > 0)
318 #else
319 if (l > 0)
320 #endif
322 l2 = l;
323 bcopy(*bufpp, ibuf + *ilen, l2);
324 if (fore->w_autolf && (trunc = DoAutolf(ibuf + *ilen, &l2, f - l2)))
325 l -= trunc;
326 #ifdef BUILTIN_TELNET
327 if (fore->w_type == W_TYPE_TELNET && (trunc = DoTelnet(ibuf + *ilen, &l2, f - l2)))
329 l -= trunc;
330 if (fore->w_autolf)
331 continue; /* need exact value */
333 #endif
334 *ilen += l2;
335 *bufpp += l;
336 *lenp -= l;
337 return;
341 static void
342 ZombieProcess(bufpp, lenp)
343 char **bufpp;
344 int *lenp;
346 int l = *lenp;
347 char *buf = *bufpp, b1[10], b2[10];
349 debug1("ZombieProcess: %d bytes\n", *lenp);
350 fore = (struct win *)flayer->l_data;
352 ASSERT(fore->w_ptyfd < 0);
353 *bufpp += *lenp;
354 *lenp = 0;
355 for (; l-- > 0; buf++)
357 if (*(unsigned char *)buf == ZombieKey_destroy)
359 debug1("Turning undead: %d\n", fore->w_number);
360 KillWindow(fore);
361 return;
363 if (*(unsigned char *)buf == ZombieKey_resurrect)
365 debug1("Resurrecting Zombie: %d\n", fore->w_number);
366 WriteString(fore, "\r\n", 2);
367 RemakeWindow(fore);
368 return;
371 b1[AddXChar(b1, ZombieKey_destroy)] = '\0';
372 b2[AddXChar(b2, ZombieKey_resurrect)] = '\0';
373 Msg(0, "Press %s to destroy or %s to resurrect window", b1, b2);
376 static void
377 WinRedisplayLine(y, from, to, isblank)
378 int y, from, to, isblank;
380 debug3("WinRedisplayLine %d %d %d\n", y, from, to);
381 if (y < 0)
382 return;
383 fore = (struct win *)flayer->l_data;
384 if (from == 0 && y > 0 && fore->w_mlines[y - 1].image[fore->w_width] == 0)
385 LCDisplayLineWrap(&fore->w_layer, &fore->w_mlines[y], y, from, to, isblank);
386 else
387 LCDisplayLine(&fore->w_layer, &fore->w_mlines[y], y, from, to, isblank);
390 static int
391 WinRewrite(y, x1, x2, rend, doit)
392 int y, x1, x2, doit;
393 struct mchar *rend;
395 register int cost, dx;
396 register unsigned char *p, *i;
397 #ifdef FONT
398 register unsigned char *f;
399 #endif
400 #ifdef COLOR
401 register unsigned char *c;
402 # ifdef COLORS256
403 register unsigned char *cx;
404 # endif
405 #endif
407 debug3("WinRewrite %d, %d-%d\n", y, x1, x2);
408 fore = (struct win *)flayer->l_data;
409 dx = x2 - x1 + 1;
410 if (doit)
412 i = fore->w_mlines[y].image + x1;
413 while (dx-- > 0)
414 PUTCHAR(*i++);
415 return 0;
417 p = fore->w_mlines[y].attr + x1;
418 #ifdef FONT
419 f = fore->w_mlines[y].font + x1;
420 # ifdef DW_CHARS
421 if (is_dw_font(rend->font))
422 return EXPENSIVE;
423 # endif
424 # ifdef UTF8
425 if (fore->w_encoding && fore->w_encoding != UTF8 && D_encoding == UTF8 && ContainsSpecialDeffont(fore->w_mlines + y, x1, x2, fore->w_encoding))
426 return EXPENSIVE;
427 # endif
428 #endif
429 #ifdef COLOR
430 c = fore->w_mlines[y].color + x1;
431 # ifdef COLORS256
432 cx = fore->w_mlines[y].colorx + x1;
433 # endif
434 #endif
436 cost = dx = x2 - x1 + 1;
437 while(dx-- > 0)
439 if (*p++ != rend->attr)
440 return EXPENSIVE;
441 #ifdef FONT
442 if (*f++ != rend->font)
443 return EXPENSIVE;
444 #endif
445 #ifdef COLOR
446 if (*c++ != rend->color)
447 return EXPENSIVE;
448 # ifdef COLORS256
449 if (*cx++ != rend->colorx)
450 return EXPENSIVE;
451 # endif
452 #endif
454 return cost;
457 static void
458 WinClearLine(y, xs, xe, bce)
459 int y, xs, xe, bce;
461 fore = (struct win *)flayer->l_data;
462 debug3("WinClearLine %d %d-%d\n", y, xs, xe);
463 LClearLine(flayer, y, xs, xe, bce, &fore->w_mlines[y]);
466 static int
467 WinResize(wi, he)
468 int wi, he;
470 fore = (struct win *)flayer->l_data;
471 ChangeWindowSize(fore, wi, he, fore->w_histheight);
472 return 0;
475 static void
476 WinRestore()
478 struct canvas *cv;
479 fore = (struct win *)flayer->l_data;
480 debug1("WinRestore: win %p\n", fore);
481 for (cv = flayer->l_cvlist; cv; cv = cv->c_next)
483 display = cv->c_display;
484 if (cv != D_forecv)
485 continue;
486 /* ChangeScrollRegion(fore->w_top, fore->w_bot); */
487 KeypadMode(fore->w_keypad);
488 CursorkeysMode(fore->w_cursorkeys);
489 SetFlow(fore->w_flow & FLOW_NOW);
490 InsertMode(fore->w_insert);
491 ReverseVideo(fore->w_revvid);
492 CursorVisibility(fore->w_curinv ? -1 : fore->w_curvvis);
493 MouseMode(fore->w_mouse);
497 /*****************************************************************/
501 * DoStartLog constructs a path for the "want to be logfile" in buf and
502 * attempts logfopen.
504 * returns 0 on success.
507 DoStartLog(w, buf, bufsize)
508 struct win *w;
509 char *buf;
510 int bufsize;
512 int n;
513 if (!w || !buf)
514 return -1;
516 strncpy(buf, MakeWinMsg(screenlogfile, w, '%'), bufsize - 1);
517 buf[bufsize - 1] = 0;
519 debug2("DoStartLog: win %d, file %s\n", w->w_number, buf);
521 if (w->w_log != NULL)
522 logfclose(w->w_log);
524 if ((w->w_log = logfopen(buf, islogfile(buf) ? NULL : secfopen(buf, "a"))) == NULL)
525 return -2;
526 if (!logflushev.queued)
528 n = log_flush ? log_flush : (logtstamp_after + 4) / 5;
529 if (n)
531 SetTimeout(&logflushev, n * 1000);
532 evenq(&logflushev);
535 return 0;
539 * Umask & wlock are set for the user of the display,
540 * The display d (if specified) switches to that window.
543 MakeWindow(newwin)
544 struct NewWindow *newwin;
546 register struct win **pp, *p;
547 register int n, i;
548 int f = -1;
549 struct NewWindow nwin;
550 int type, startat;
551 char *TtyName;
552 #ifdef MULTIUSER
553 extern struct acluser *users;
554 #endif
556 debug1("NewWindow: StartAt %d\n", newwin->StartAt);
557 debug1("NewWindow: aka %s\n", newwin->aka?newwin->aka:"NULL");
558 debug1("NewWindow: dir %s\n", newwin->dir?newwin->dir:"NULL");
559 debug1("NewWindow: term %s\n", newwin->term?newwin->term:"NULL");
561 nwin_compose(&nwin_default, newwin, &nwin);
562 debug1("NWin: aka %s\n", nwin.aka ? nwin.aka : "NULL");
563 debug1("NWin: wlock %d\n", nwin.wlock);
564 debug1("NWin: Lflag %d\n", nwin.Lflag);
566 startat = nwin.StartAt < maxwin ? nwin.StartAt : 0;
567 pp = wtab + startat;
571 if (*pp == 0)
572 break;
573 if (++pp == wtab + maxwin)
574 pp = wtab;
576 while (pp != wtab + startat);
577 if (*pp)
579 Msg(0, "No more windows.");
580 return -1;
583 #if defined(USRLIMIT) && defined(UTMPOK)
585 * Count current number of users, if logging windows in.
587 if (nwin.lflag && CountUsers() >= USRLIMIT)
589 Msg(0, "User limit reached. Window will not be logged in.");
590 nwin.lflag = 0;
592 #endif
593 n = pp - wtab;
594 debug1("Makewin creating %d\n", n);
596 if ((f = OpenDevice(nwin.args, nwin.lflag, &type, &TtyName)) < 0)
597 return -1;
598 if (type == W_TYPE_GROUP)
599 f = -1;
601 if ((p = (struct win *)calloc(1, sizeof(struct win))) == 0)
603 close(f);
604 Msg(0, strnomem);
605 return -1;
608 #ifdef UTMPOK
609 if (type != W_TYPE_PTY)
610 nwin.lflag = 0;
611 #endif
613 p->w_type = type;
615 /* save the command line so that zombies can be resurrected */
616 for (i = 0; nwin.args[i] && i < MAXARGS - 1; i++)
617 p->w_cmdargs[i] = SaveStr(nwin.args[i]);
618 p->w_cmdargs[i] = 0;
619 if (nwin.dir)
620 p->w_dir = SaveStr(nwin.dir);
621 if (nwin.term)
622 p->w_term = SaveStr(nwin.term);
624 p->w_number = n;
625 p->w_group = 0;
626 if (fore && fore->w_type == W_TYPE_GROUP)
627 p->w_group = fore;
628 else if (fore && fore->w_group)
629 p->w_group = fore->w_group;
630 #ifdef MULTIUSER
632 * This is dangerous: without a display we use creators umask
633 * This is intended to be usefull for detached startup.
634 * But is still better than default bits with a NULL user.
636 if (NewWindowAcl(p, display ? D_user : users))
638 free((char *)p);
639 close(f);
640 Msg(0, strnomem);
641 return -1;
643 #endif
644 p->w_layer.l_next = 0;
645 p->w_layer.l_bottom = &p->w_layer;
646 p->w_layer.l_layfn = &WinLf;
647 p->w_layer.l_data = (char *)p;
648 p->w_savelayer = &p->w_layer;
649 p->w_pdisplay = 0;
650 p->w_lastdisp = 0;
652 #ifdef MULTIUSER
653 if (display && !AclCheckPermWin(D_user, ACL_WRITE, p))
654 p->w_wlockuser = D_user;
655 p->w_wlock = nwin.wlock;
656 #endif
657 p->w_ptyfd = f;
658 p->w_aflag = nwin.aflag;
659 p->w_flow = nwin.flowflag | ((nwin.flowflag & FLOW_AUTOFLAG) ? (FLOW_AUTO|FLOW_NOW) : FLOW_AUTO);
660 if (!nwin.aka)
661 nwin.aka = Filename(nwin.args[0]);
662 strncpy(p->w_akabuf, nwin.aka, sizeof(p->w_akabuf) - 1);
663 if ((nwin.aka = rindex(p->w_akabuf, '|')) != NULL)
665 p->w_autoaka = 0;
666 *nwin.aka++ = 0;
667 p->w_title = nwin.aka;
668 p->w_akachange = nwin.aka + strlen(nwin.aka);
670 else
671 p->w_title = p->w_akachange = p->w_akabuf;
672 if (nwin.hstatus)
673 p->w_hstatus = SaveStr(nwin.hstatus);
674 p->w_monitor = nwin.monitor;
675 #ifdef MULTIUSER
676 if (p->w_monitor == MON_ON)
678 /* always tell all users */
679 for (i = 0; i < maxusercount; i++)
680 ACLBYTE(p->w_mon_notify, i) |= ACLBIT(i);
682 #endif
684 * defsilence by Lloyd Zusman (zusman_lloyd@jpmorgan.com)
686 p->w_silence = nwin.silence;
687 p->w_silencewait = SilenceWait;
688 #ifdef MULTIUSER
689 if (p->w_silence == SILENCE_ON)
691 /* always tell all users */
692 for (i = 0; i < maxusercount; i++)
693 ACLBYTE(p->w_lio_notify, i) |= ACLBIT(i);
695 #endif
696 #ifdef COPY_PASTE
697 p->w_slowpaste = nwin.slow;
698 #else
699 nwin.histheight = 0;
700 #endif
702 p->w_norefresh = 0;
703 strncpy(p->w_tty, TtyName, MAXSTR - 1);
705 #if 0
706 /* XXX Fixme display resize */
707 if (ChangeWindowSize(p, display ? D_defwidth : 80,
708 display ? D_defheight : 24,
709 nwin.histheight))
711 FreeWindow(p);
712 return -1;
714 #else
715 if (ChangeWindowSize(p, display ? D_forecv->c_xe - D_forecv->c_xs + 1: 80,
716 display ? D_forecv->c_ye - D_forecv->c_ys + 1 : 24,
717 nwin.histheight))
719 FreeWindow(p);
720 return -1;
722 #endif
724 p->w_encoding = nwin.encoding;
725 ResetWindow(p); /* sets w_wrap, w_c1, w_gr, w_bce */
727 #ifdef FONT
728 if (nwin.charset)
729 SetCharsets(p, nwin.charset);
730 #endif
732 if (VerboseCreate && type != W_TYPE_GROUP)
734 struct display *d = display; /* WriteString zaps display */
736 WriteString(p, ":screen (", 9);
737 WriteString(p, p->w_title, strlen(p->w_title));
738 WriteString(p, "):", 2);
739 for (f = 0; p->w_cmdargs[f]; f++)
741 WriteString(p, " ", 1);
742 WriteString(p, p->w_cmdargs[f], strlen(p->w_cmdargs[f]));
744 WriteString(p, "\r\n", 2);
745 display = d;
748 p->w_deadpid = 0;
749 p->w_pid = 0;
750 #ifdef PSEUDOS
751 p->w_pwin = 0;
752 #endif
754 #ifdef BUILTIN_TELNET
755 if (type == W_TYPE_TELNET)
757 if (TelConnect(p))
759 FreeWindow(p);
760 return -1;
763 else
764 #endif
765 if (type == W_TYPE_PTY)
767 p->w_pid = ForkWindow(p, nwin.args, TtyName);
768 if (p->w_pid < 0)
770 FreeWindow(p);
771 return -1;
776 * Place the new window at the head of the most-recently-used list.
778 if (display && D_fore)
779 D_other = D_fore;
780 *pp = p;
781 p->w_next = windows;
782 windows = p;
784 if (type == W_TYPE_GROUP)
786 SetForeWindow(p);
787 Activate(p->w_norefresh);
788 WindowChanged((struct win*)0, 'w');
789 WindowChanged((struct win*)0, 'W');
790 WindowChanged((struct win*)0, 0);
791 return n;
794 p->w_lflag = nwin.lflag;
795 #ifdef UTMPOK
796 p->w_slot = (slot_t)-1;
797 # ifdef LOGOUTOK
798 debug1("MakeWindow will %slog in.\n", nwin.lflag?"":"not ");
799 if (nwin.lflag & 1)
800 # else /* LOGOUTOK */
801 debug1("MakeWindow will log in, LOGOUTOK undefined in config.h%s.\n",
802 nwin.lflag?"":" (although lflag=0)");
803 # endif /* LOGOUTOK */
805 p->w_slot = (slot_t)0;
806 if (display || (p->w_lflag & 2))
807 SetUtmp(p);
809 # ifdef CAREFULUTMP
810 CarefulUtmp(); /* If all 've been zombies, we've had no slot */
811 # endif
812 #endif /* UTMPOK */
814 if (nwin.Lflag)
816 char buf[1024];
817 DoStartLog(p, buf, sizeof(buf));
820 p->w_readev.fd = p->w_writeev.fd = p->w_ptyfd;
821 p->w_readev.type = EV_READ;
822 p->w_writeev.type = EV_WRITE;
823 p->w_readev.data = p->w_writeev.data = (char *)p;
824 p->w_readev.handler = win_readev_fn;
825 p->w_writeev.handler = win_writeev_fn;
826 p->w_writeev.condpos = &p->w_inlen;
827 evenq(&p->w_readev);
828 evenq(&p->w_writeev);
829 #ifdef COPY_PASTE
830 p->w_paster.pa_slowev.type = EV_TIMEOUT;
831 p->w_paster.pa_slowev.data = (char *)&p->w_paster;
832 p->w_paster.pa_slowev.handler = paste_slowev_fn;
833 #endif
834 p->w_silenceev.type = EV_TIMEOUT;
835 p->w_silenceev.data = (char *)p;
836 p->w_silenceev.handler = win_silenceev_fn;
837 if (p->w_silence > 0)
839 debug("New window has silence enabled.\n");
840 SetTimeout(&p->w_silenceev, p->w_silencewait * 1000);
841 evenq(&p->w_silenceev);
844 SetForeWindow(p);
845 Activate(p->w_norefresh);
846 WindowChanged((struct win*)0, 'w');
847 WindowChanged((struct win*)0, 'W');
848 WindowChanged((struct win*)0, 0);
849 return n;
853 * Resurrect a window from Zombie state.
854 * The command vector is therefore stored in the window structure.
855 * Note: The terminaltype defaults to screenterm again, the current
856 * working directory is lost.
859 RemakeWindow(p)
860 struct win *p;
862 char *TtyName;
863 int lflag, f;
865 lflag = nwin_default.lflag;
866 if ((f = OpenDevice(p->w_cmdargs, lflag, &p->w_type, &TtyName)) < 0)
867 return -1;
869 strncpy(p->w_tty, *TtyName ? TtyName : p->w_title, MAXSTR - 1);
870 p->w_ptyfd = f;
871 p->w_readev.fd = f;
872 p->w_writeev.fd = f;
873 evenq(&p->w_readev);
874 evenq(&p->w_writeev);
876 if (VerboseCreate)
878 struct display *d = display; /* WriteString zaps display */
880 WriteString(p, ":screen (", 9);
881 WriteString(p, p->w_title, strlen(p->w_title));
882 WriteString(p, "):", 2);
883 for (f = 0; p->w_cmdargs[f]; f++)
885 WriteString(p, " ", 1);
886 WriteString(p, p->w_cmdargs[f], strlen(p->w_cmdargs[f]));
888 WriteString(p, "\r\n", 2);
889 display = d;
892 p->w_deadpid = 0;
893 p->w_pid = 0;
894 #ifdef BUILTIN_TELNET
895 if (p->w_type == W_TYPE_TELNET)
897 if (TelConnect(p))
898 return -1;
900 else
901 #endif
902 if (p->w_type == W_TYPE_PTY)
904 p->w_pid = ForkWindow(p, p->w_cmdargs, TtyName);
905 if (p->w_pid < 0)
906 return -1;
909 #ifdef UTMPOK
910 if (p->w_slot == (slot_t)0 && (display || (p->w_lflag & 2)))
911 SetUtmp(p);
912 # ifdef CAREFULUTMP
913 CarefulUtmp(); /* If all 've been zombies, we've had no slot */
914 # endif
915 #endif
916 WindowChanged(p, 'f');
917 return p->w_number;
920 void
921 CloseDevice(wp)
922 struct win *wp;
924 if (wp->w_ptyfd < 0)
925 return;
926 if (wp->w_type == W_TYPE_PTY)
928 /* pty 4 SALE */
929 (void)chmod(wp->w_tty, 0666);
930 (void)chown(wp->w_tty, 0, 0);
932 close(wp->w_ptyfd);
933 wp->w_ptyfd = -1;
934 wp->w_tty[0] = 0;
935 evdeq(&wp->w_readev);
936 evdeq(&wp->w_writeev);
937 #ifdef BUILTIN_TELNET
938 evdeq(&wp->w_telconnev);
939 #endif
940 wp->w_readev.fd = wp->w_writeev.fd = -1;
943 void
944 FreeWindow(wp)
945 struct win *wp;
947 struct display *d;
948 int i;
949 struct canvas *cv, *ncv;
950 struct layer *l;
952 debug1("FreeWindow %d\n", wp ? wp->w_number: -1);
953 #ifdef PSEUDOS
954 if (wp->w_pwin)
955 FreePseudowin(wp);
956 #endif
957 #ifdef UTMPOK
958 RemoveUtmp(wp);
959 #endif
960 CloseDevice(wp);
962 if (wp == console_window)
964 TtyGrabConsole(-1, -1, "free");
965 console_window = 0;
967 if (wp->w_log != NULL)
968 logfclose(wp->w_log);
969 ChangeWindowSize(wp, 0, 0, 0);
971 if (wp->w_type == W_TYPE_GROUP)
973 struct win *win;
974 for (win = windows; win; win = win->w_next)
975 if (win->w_group == wp)
976 win->w_group = wp->w_group;
979 if (wp->w_hstatus)
980 free(wp->w_hstatus);
981 for (i = 0; wp->w_cmdargs[i]; i++)
982 free(wp->w_cmdargs[i]);
983 if (wp->w_dir)
984 free(wp->w_dir);
985 if (wp->w_term)
986 free(wp->w_term);
987 for (d = displays; d; d = d->d_next)
989 if (d->d_other == wp)
990 d->d_other = d->d_fore && d->d_fore->w_next != wp ? d->d_fore->w_next : wp->w_next;
991 if (d->d_fore == wp)
992 d->d_fore = NULL;
993 for (cv = d->d_cvlist; cv; cv = cv->c_next)
995 for (l = cv->c_layer; l; l = l->l_next)
996 if (l->l_layfn == &WinLf)
997 break;
998 if (!l)
999 continue;
1000 if ((struct win *)l->l_data != wp)
1001 continue;
1002 if (cv->c_layer == wp->w_savelayer)
1003 wp->w_savelayer = 0;
1004 KillLayerChain(cv->c_layer);
1007 if (wp->w_savelayer)
1008 KillLayerChain(wp->w_savelayer);
1009 for (cv = wp->w_layer.l_cvlist; cv; cv = ncv)
1011 ncv = cv->c_lnext;
1012 cv->c_layer = &cv->c_blank;
1013 cv->c_blank.l_cvlist = cv;
1014 cv->c_lnext = 0;
1015 cv->c_xoff = cv->c_xs;
1016 cv->c_yoff = cv->c_ys;
1017 RethinkViewportOffsets(cv);
1019 wp->w_layer.l_cvlist = 0;
1020 if (flayer == &wp->w_layer)
1021 flayer = 0;
1023 #ifdef MULTIUSER
1024 FreeWindowAcl(wp);
1025 #endif /* MULTIUSER */
1026 evdeq(&wp->w_readev); /* just in case */
1027 evdeq(&wp->w_writeev); /* just in case */
1028 evdeq(&wp->w_silenceev);
1029 #ifdef COPY_PASTE
1030 FreePaster(&wp->w_paster);
1031 #endif
1032 free((char *)wp);
1035 static int
1036 OpenDevice(args, lflag, typep, namep)
1037 char **args;
1038 int lflag;
1039 int *typep;
1040 char **namep;
1042 char *arg = args[0];
1043 struct stat st;
1044 int f;
1046 if (!arg)
1047 return -1;
1048 if (strcmp(arg, "//group") == 0)
1050 *typep = W_TYPE_GROUP;
1051 *namep = "telnet";
1052 return 0;
1054 #ifdef BUILTIN_TELNET
1055 if (strcmp(arg, "//telnet") == 0)
1057 f = TelOpen(args + 1);
1058 lflag = 0;
1059 *typep = W_TYPE_TELNET;
1060 *namep = "telnet";
1062 else
1063 #endif
1064 if (strncmp(arg, "//", 2) == 0)
1066 Msg(0, "Invalid argument '%s'", arg);
1067 return -1;
1069 else if ((stat(arg, &st)) == 0 && S_ISCHR(st.st_mode))
1071 if (access(arg, R_OK | W_OK) == -1)
1073 Msg(errno, "Cannot access line '%s' for R/W", arg);
1074 return -1;
1076 debug("OpenDevice: OpenTTY\n");
1077 if ((f = OpenTTY(arg, args[1])) < 0)
1078 return -1;
1079 lflag = 0;
1080 *typep = W_TYPE_PLAIN;
1081 *namep = arg;
1083 else
1085 *typep = W_TYPE_PTY;
1086 f = OpenPTY(namep);
1087 if (f == -1)
1089 Msg(0, "No more PTYs.");
1090 return -1;
1092 #ifdef TIOCPKT
1094 int flag = 1;
1095 if (ioctl(f, TIOCPKT, (char *)&flag))
1097 Msg(errno, "TIOCPKT ioctl");
1098 close(f);
1099 return -1;
1102 #endif /* TIOCPKT */
1104 debug1("fcntl(%d, F_SETFL, FNBLOCK)\n", f);
1105 (void) fcntl(f, F_SETFL, FNBLOCK);
1106 #ifdef linux
1108 * Tenebreux (zeus@ns.acadiacom.net) has Linux 1.3.70 where select
1109 * gets confused in the following condition:
1110 * Open a pty-master side, request a flush on it, then set packet
1111 * mode and call select(). Select will return a possible read, where
1112 * the one byte response to the flush can be found. Select will
1113 * thereafter return a possible read, which yields I/O error.
1115 * If we request another flush *after* switching into packet mode,
1116 * this I/O error does not occur. We receive a single response byte
1117 * although we send two flush requests now.
1119 * Maybe we should not flush at all.
1121 * 10.5.96 jw.
1123 if (*typep == W_TYPE_PTY || *typep == W_TYPE_PLAIN)
1124 tcflush(f, TCIOFLUSH);
1125 #endif
1127 if (*typep != W_TYPE_PTY)
1128 return f;
1130 #ifndef PTYROFS
1131 #ifdef PTYGROUP
1132 if (chown(*namep, real_uid, PTYGROUP) && !eff_uid)
1133 #else
1134 if (chown(*namep, real_uid, real_gid) && !eff_uid)
1135 #endif
1137 Msg(errno, "chown tty");
1138 close(f);
1139 return -1;
1141 #ifdef UTMPOK
1142 if (chmod(*namep, lflag ? TtyMode : (TtyMode & ~022)) && !eff_uid)
1143 #else
1144 if (chmod(*namep, TtyMode) && !eff_uid)
1145 #endif
1147 Msg(errno, "chmod tty");
1148 close(f);
1149 return -1;
1151 #endif
1152 return f;
1156 * Fields w_width, w_height, aflag, number (and w_tty)
1157 * are read from struct win *win. No fields written.
1158 * If pwin is nonzero, filedescriptors are distributed
1159 * between win->w_tty and open(ttyn)
1162 static int
1163 ForkWindow(win, args, ttyn)
1164 struct win *win;
1165 char **args, *ttyn;
1167 int pid;
1168 char tebuf[25];
1169 char ebuf[20];
1170 char shellbuf[7 + MAXPATHLEN];
1171 char *proc;
1172 #ifndef TIOCSWINSZ
1173 char libuf[20], cobuf[20];
1174 #endif
1175 int newfd;
1176 int w = win->w_width;
1177 int h = win->w_height;
1178 #ifdef PSEUDOS
1179 int i, pat, wfdused;
1180 struct pseudowin *pwin = win->w_pwin;
1181 #endif
1182 int slave = -1;
1184 #ifdef O_NOCTTY
1185 if (pty_preopen)
1187 debug("pre-opening slave...\n");
1188 if ((slave = open(ttyn, O_RDWR|O_NOCTTY)) == -1)
1190 Msg(errno, "ttyn");
1191 return -1;
1194 #endif
1195 debug("forking...\n");
1196 proc = *args;
1197 if (proc == 0)
1199 args = ShellArgs;
1200 proc = *args;
1202 fflush(stdout);
1203 fflush(stderr);
1204 switch (pid = fork())
1206 case -1:
1207 Msg(errno, "fork");
1208 break;
1209 case 0:
1210 signal(SIGHUP, SIG_DFL);
1211 signal(SIGINT, SIG_DFL);
1212 signal(SIGQUIT, SIG_DFL);
1213 signal(SIGTERM, SIG_DFL);
1214 #ifdef BSDJOBS
1215 signal(SIGTTIN, SIG_DFL);
1216 signal(SIGTTOU, SIG_DFL);
1217 #endif
1218 #ifdef SIGPIPE
1219 signal(SIGPIPE, SIG_DFL);
1220 #endif
1221 #ifdef SIGXFSZ
1222 signal(SIGXFSZ, SIG_DFL);
1223 #endif
1225 displays = 0; /* beware of Panic() */
1226 if (setgid(real_gid) || setuid(real_uid))
1227 Panic(errno, "Setuid/gid");
1228 eff_uid = real_uid;
1229 eff_gid = real_gid;
1230 #ifdef PSEUDOS
1231 if (!pwin) /* ignore directory if pseudo */
1232 #endif
1233 if (win->w_dir && *win->w_dir && chdir(win->w_dir))
1234 Panic(errno, "Cannot chdir to %s", win->w_dir);
1236 if (display)
1238 brktty(D_userfd);
1239 freetty();
1241 else
1242 brktty(-1);
1243 #ifdef DEBUG
1244 if (dfp && dfp != stderr)
1245 fclose(dfp);
1246 #endif
1247 if (slave != -1)
1249 close(0);
1250 dup(slave);
1251 close(slave);
1252 closeallfiles(win->w_ptyfd);
1253 slave = dup(0);
1255 else
1256 closeallfiles(win->w_ptyfd);
1257 #ifdef DEBUG
1258 if (dfp) /* do not produce child debug, when debug is "off" */
1260 char buf[256];
1262 sprintf(buf, "%s/screen.child", DEBUGDIR);
1263 if ((dfp = fopen(buf, "a")) == 0)
1264 dfp = stderr;
1265 else
1266 (void) chmod(buf, 0666);
1268 debug1("=== ForkWindow: pid %d\n", (int)getpid());
1269 #endif
1270 /* Close the three /dev/null descriptors */
1271 close(0);
1272 close(1);
1273 close(2);
1274 newfd = -1;
1276 * distribute filedescriptors between the ttys
1278 #ifdef PSEUDOS
1279 pat = pwin ? pwin->p_fdpat :
1280 ((F_PFRONT<<(F_PSHIFT*2)) | (F_PFRONT<<F_PSHIFT) | F_PFRONT);
1281 debug1("Using window pattern 0x%x\n", pat);
1282 wfdused = 0;
1283 for(i = 0; i < 3; i++)
1285 if (pat & F_PFRONT << F_PSHIFT * i)
1287 if (newfd < 0)
1289 # ifdef O_NOCTTY
1290 if (separate_sids)
1291 newfd = open(ttyn, O_RDWR);
1292 else
1293 newfd = open(ttyn, O_RDWR|O_NOCTTY);
1294 # else
1295 newfd = open(ttyn, O_RDWR);
1296 # endif
1297 if (newfd < 0)
1298 Panic(errno, "Cannot open %s", ttyn);
1300 else
1301 dup(newfd);
1303 else
1305 dup(win->w_ptyfd);
1306 wfdused = 1;
1309 if (wfdused)
1312 * the pseudo window process should not be surprised with a
1313 * nonblocking filedescriptor. Poor Backend!
1315 debug1("Clearing NBLOCK on window-fd(%d)\n", win->w_ptyfd);
1316 if (fcntl(win->w_ptyfd, F_SETFL, 0))
1317 Msg(errno, "Warning: clear NBLOCK fcntl failed");
1319 #else /* PSEUDOS */
1320 # ifdef O_NOCTTY
1321 if (separate_sids)
1322 newfd = open(ttyn, O_RDWR);
1323 else
1324 newfd = open(ttyn, O_RDWR|O_NOCTTY);
1325 # else
1326 newfd = open(ttyn, O_RDWR);
1327 # endif
1328 if (newfd != 0)
1329 Panic(errno, "Cannot open %s", ttyn);
1330 dup(0);
1331 dup(0);
1332 #endif /* PSEUDOS */
1333 close(win->w_ptyfd);
1334 if (slave != -1)
1335 close(slave);
1336 if (newfd >= 0)
1338 struct mode fakemode, *modep;
1339 InitPTY(newfd);
1340 if (fgtty(newfd))
1341 Msg(errno, "fgtty");
1342 if (display)
1344 debug("ForkWindow: using display tty mode for new child.\n");
1345 modep = &D_OldMode;
1347 else
1349 debug("No display - creating tty setting\n");
1350 modep = &fakemode;
1351 InitTTY(modep, 0);
1352 #ifdef DEBUG
1353 DebugTTY(modep);
1354 #endif
1356 /* We only want echo if the users input goes to the pseudo
1357 * and the pseudo's stdout is not send to the window.
1359 #ifdef PSEUDOS
1360 if (pwin && (!(pat & F_UWP) || (pat & F_PBACK << F_PSHIFT)))
1362 debug1("clearing echo on pseudywin fd (pat %x)\n", pat);
1363 # if defined(POSIX) || defined(TERMIO)
1364 modep->tio.c_lflag &= ~ECHO;
1365 modep->tio.c_iflag &= ~ICRNL;
1366 # else
1367 modep->m_ttyb.sg_flags &= ~ECHO;
1368 # endif
1370 #endif
1371 SetTTY(newfd, modep);
1372 #ifdef TIOCSWINSZ
1373 glwz.ws_col = w;
1374 glwz.ws_row = h;
1375 (void) ioctl(newfd, TIOCSWINSZ, (char *)&glwz);
1376 #endif
1377 /* Always turn off nonblocking mode */
1378 (void)fcntl(newfd, F_SETFL, 0);
1380 #ifndef TIOCSWINSZ
1381 sprintf(libuf, "LINES=%d", h);
1382 sprintf(cobuf, "COLUMNS=%d", w);
1383 NewEnv[5] = libuf;
1384 NewEnv[6] = cobuf;
1385 #endif
1386 #ifdef MAPKEYS
1387 NewEnv[2] = MakeTermcap(display == 0 || win->w_aflag);
1388 #else
1389 if (win->w_aflag)
1390 NewEnv[2] = MakeTermcap(1);
1391 else
1392 NewEnv[2] = Termcap;
1393 #endif
1394 strcpy(shellbuf, "SHELL=");
1395 strncpy(shellbuf + 6, ShellProg + (*ShellProg == '-'), sizeof(shellbuf) - 7);
1396 shellbuf[sizeof(shellbuf) - 1] = 0;
1397 NewEnv[4] = shellbuf;
1398 debug1("ForkWindow: NewEnv[4] = '%s'\n", shellbuf);
1399 if (win->w_term && *win->w_term && strcmp(screenterm, win->w_term) &&
1400 (strlen(win->w_term) < 20))
1402 char *s1, *s2, tl;
1404 sprintf(tebuf, "TERM=%s", win->w_term);
1405 debug2("Makewindow %d with %s\n", win->w_number, tebuf);
1406 tl = strlen(win->w_term);
1407 NewEnv[1] = tebuf;
1408 if ((s1 = index(NewEnv[2], '|')))
1410 if ((s2 = index(++s1, '|')))
1412 if (strlen(NewEnv[2]) - (s2 - s1) + tl < 1024)
1414 bcopy(s2, s1 + tl, strlen(s2) + 1);
1415 bcopy(win->w_term, s1, tl);
1420 sprintf(ebuf, "WINDOW=%d", win->w_number);
1421 NewEnv[3] = ebuf;
1423 if (*proc == '-')
1424 proc++;
1425 if (!*proc)
1426 proc = DefaultShell;
1427 debug1("calling execvpe %s\n", proc);
1428 execvpe(proc, args, NewEnv);
1429 debug1("exec error: %d\n", errno);
1430 Panic(errno, "Cannot exec '%s'", proc);
1431 default:
1432 break;
1434 if (slave != -1)
1435 close(slave);
1436 return pid;
1439 void
1440 execvpe(prog, args, env)
1441 char *prog, **args, **env;
1443 register char *path = NULL, *p;
1444 char buf[1024];
1445 char *shargs[MAXARGS + 1];
1446 register int i, eaccess = 0;
1448 if (rindex(prog, '/'))
1449 path = "";
1450 if (!path && !(path = getenv("PATH")))
1451 path = DefaultPath;
1454 for (p = buf; *path && *path != ':'; path++)
1455 if (p - buf < (int)sizeof(buf) - 2)
1456 *p++ = *path;
1457 if (p > buf)
1458 *p++ = '/';
1459 if (p - buf + strlen(prog) >= sizeof(buf) - 1)
1460 continue;
1461 strcpy(p, prog);
1462 execve(buf, args, env);
1463 switch (errno)
1465 case ENOEXEC:
1466 shargs[0] = DefaultShell;
1467 shargs[1] = buf;
1468 for (i = 1; (shargs[i + 1] = args[i]) != NULL; ++i)
1470 execve(DefaultShell, shargs, env);
1471 return;
1472 case EACCES:
1473 eaccess = 1;
1474 break;
1475 case ENOMEM:
1476 case E2BIG:
1477 case ETXTBSY:
1478 return;
1480 } while (*path++);
1481 if (eaccess)
1482 errno = EACCES;
1485 #ifdef PSEUDOS
1488 winexec(av)
1489 char **av;
1491 char **pp;
1492 char *p, *s, *t;
1493 int i, r = 0, l = 0;
1494 struct win *w;
1495 extern struct display *display;
1496 extern struct win *windows;
1497 struct pseudowin *pwin;
1498 int type;
1500 if ((w = display ? fore : windows) == NULL)
1501 return -1;
1502 if (!*av || w->w_pwin)
1504 Msg(0, "Filter running: %s", w->w_pwin ? w->w_pwin->p_cmd : "(none)");
1505 return -1;
1507 if (w->w_ptyfd < 0)
1509 Msg(0, "You feel dead inside.");
1510 return -1;
1512 if (!(pwin = (struct pseudowin *)calloc(1, sizeof(struct pseudowin))))
1514 Msg(0, strnomem);
1515 return -1;
1518 /* allow ^a:!!./ttytest as a short form for ^a:exec !.. ./ttytest */
1519 for (s = *av; *s == ' '; s++)
1521 for (p = s; *p == ':' || *p == '.' || *p == '!'; p++)
1523 if (*p != '|')
1524 while (*p && p > s && p[-1] == '.')
1525 p--;
1526 if (*p == '|')
1528 l = F_UWP;
1529 p++;
1531 if (*p)
1532 av[0] = p;
1533 else
1534 av++;
1536 t = pwin->p_cmd;
1537 for (i = 0; i < 3; i++)
1539 *t = (s < p) ? *s++ : '.';
1540 switch (*t++)
1542 case '.':
1543 case '|':
1544 l |= F_PFRONT << (i * F_PSHIFT);
1545 break;
1546 case '!':
1547 l |= F_PBACK << (i * F_PSHIFT);
1548 break;
1549 case ':':
1550 l |= F_PBOTH << (i * F_PSHIFT);
1551 break;
1555 if (l & F_UWP)
1557 *t++ = '|';
1558 if ((l & F_PMASK) == F_PFRONT)
1560 *pwin->p_cmd = '!';
1561 l ^= F_PFRONT | F_PBACK;
1564 if (!(l & F_PBACK))
1565 l |= F_UWP;
1566 *t++ = ' ';
1567 pwin->p_fdpat = l;
1568 debug1("winexec: '%#x'\n", pwin->p_fdpat);
1570 l = MAXSTR - 4;
1571 for (pp = av; *pp; pp++)
1573 p = *pp;
1574 while (*p && l-- > 0)
1575 *t++ = *p++;
1576 if (l <= 0)
1577 break;
1578 *t++ = ' ';
1580 *--t = '\0';
1581 debug1("%s\n", pwin->p_cmd);
1583 if ((pwin->p_ptyfd = OpenDevice(av, 0, &type, &t)) < 0)
1585 free((char *)pwin);
1586 return -1;
1588 strncpy(pwin->p_tty, t, MAXSTR - 1);
1589 w->w_pwin = pwin;
1590 if (type != W_TYPE_PTY)
1592 FreePseudowin(w);
1593 Msg(0, "Cannot only use commands as pseudo win.");
1594 return -1;
1596 if (!(pwin->p_fdpat & F_PFRONT))
1597 evdeq(&w->w_readev);
1598 #ifdef TIOCPKT
1600 int flag = 0;
1602 if (ioctl(pwin->p_ptyfd, TIOCPKT, (char *)&flag))
1604 Msg(errno, "TIOCPKT pwin ioctl");
1605 FreePseudowin(w);
1606 return -1;
1608 if (w->w_type == W_TYPE_PTY && !(pwin->p_fdpat & F_PFRONT))
1610 if (ioctl(w->w_ptyfd, TIOCPKT, (char *)&flag))
1612 Msg(errno, "TIOCPKT win ioctl");
1613 FreePseudowin(w);
1614 return -1;
1618 #endif /* TIOCPKT */
1620 pwin->p_readev.fd = pwin->p_writeev.fd = pwin->p_ptyfd;
1621 pwin->p_readev.type = EV_READ;
1622 pwin->p_writeev.type = EV_WRITE;
1623 pwin->p_readev.data = pwin->p_writeev.data = (char *)w;
1624 pwin->p_readev.handler = pseu_readev_fn;
1625 pwin->p_writeev.handler = pseu_writeev_fn;
1626 pwin->p_writeev.condpos = &pwin->p_inlen;
1627 if (pwin->p_fdpat & (F_PFRONT << F_PSHIFT * 2 | F_PFRONT << F_PSHIFT))
1628 evenq(&pwin->p_readev);
1629 evenq(&pwin->p_writeev);
1630 r = pwin->p_pid = ForkWindow(w, av, t);
1631 if (r < 0)
1632 FreePseudowin(w);
1633 return r;
1636 void
1637 FreePseudowin(w)
1638 struct win *w;
1640 struct pseudowin *pwin = w->w_pwin;
1642 ASSERT(pwin);
1643 if (fcntl(w->w_ptyfd, F_SETFL, FNBLOCK))
1644 Msg(errno, "Warning: FreePseudowin: NBLOCK fcntl failed");
1645 #ifdef TIOCPKT
1646 if (w->w_type == W_TYPE_PTY && !(pwin->p_fdpat & F_PFRONT))
1648 int flag = 1;
1649 if (ioctl(w->w_ptyfd, TIOCPKT, (char *)&flag))
1650 Msg(errno, "Warning: FreePseudowin: TIOCPKT win ioctl");
1652 #endif
1653 /* should be able to use CloseDevice() here */
1654 (void)chmod(pwin->p_tty, 0666);
1655 (void)chown(pwin->p_tty, 0, 0);
1656 if (pwin->p_ptyfd >= 0)
1657 close(pwin->p_ptyfd);
1658 evdeq(&pwin->p_readev);
1659 evdeq(&pwin->p_writeev);
1660 if (w->w_readev.condneg == &pwin->p_inlen)
1661 w->w_readev.condpos = w->w_readev.condneg = 0;
1662 evenq(&w->w_readev);
1663 free((char *)pwin);
1664 w->w_pwin = NULL;
1667 #endif /* PSEUDOS */
1670 #ifdef MULTIUSER
1672 * returns 0, if the lock really has been released
1675 ReleaseAutoWritelock(dis, w)
1676 struct display *dis;
1677 struct win *w;
1679 debug2("ReleaseAutoWritelock: user %s, window %d\n",
1680 dis->d_user->u_name, w->w_number);
1682 /* release auto writelock when user has no other display here */
1683 if (w->w_wlock == WLOCK_AUTO && w->w_wlockuser == dis->d_user)
1685 struct display *d;
1687 for (d = displays; d; d = d->d_next)
1688 if (( d != dis) && (d->d_fore == w) && (d->d_user == dis->d_user))
1689 break;
1690 debug3("%s %s autolock on win %d\n",
1691 dis->d_user->u_name, d ? "keeps" : "releases", w->w_number);
1692 if (!d)
1694 w->w_wlockuser = NULL;
1695 return 0;
1698 return 1;
1702 * returns 0, if the lock really could be obtained
1705 ObtainAutoWritelock(d, w)
1706 struct display *d;
1707 struct win *w;
1709 if ((w->w_wlock == WLOCK_AUTO) &&
1710 !AclCheckPermWin(d->d_user, ACL_WRITE, w) &&
1711 !w->w_wlockuser)
1713 debug2("%s obtained auto writelock for exported window %d\n",
1714 d->d_user->u_name, w->w_number);
1715 w->w_wlockuser = d->d_user;
1716 return 0;
1718 return 1;
1721 #endif /* MULTIUSER */
1725 /********************************************************************/
1727 #ifdef COPY_PASTE
1728 static void
1729 paste_slowev_fn(ev, data)
1730 struct event *ev;
1731 char *data;
1733 struct paster *pa = (struct paster *)data;
1734 struct win *p;
1736 int l = 1;
1737 flayer = pa->pa_pastelayer;
1738 if (!flayer)
1739 pa->pa_pastelen = 0;
1740 if (!pa->pa_pastelen)
1741 return;
1742 p = Layer2Window(flayer);
1743 DoProcess(p, &pa->pa_pasteptr, &l, pa);
1744 pa->pa_pastelen -= 1 - l;
1745 if (pa->pa_pastelen > 0)
1747 SetTimeout(&pa->pa_slowev, p->w_slowpaste);
1748 evenq(&pa->pa_slowev);
1751 #endif
1754 static int
1755 muchpending(p, ev)
1756 struct win *p;
1757 struct event *ev;
1759 struct canvas *cv;
1760 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
1762 display = cv->c_display;
1763 if (D_status == STATUS_ON_WIN && !D_status_bell)
1765 /* wait 'til status is gone */
1766 debug("BLOCKING because of status\n");
1767 ev->condpos = &const_one;
1768 ev->condneg = &D_status;
1769 return 1;
1771 debug2("muchpending %s %d: ", D_usertty, D_blocked);
1772 debug3("%d %d %d\n", D_obufp - D_obuf, D_obufmax, D_blocked_fuzz);
1773 if (D_blocked)
1774 continue;
1775 if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
1777 if (D_nonblock == 0)
1779 debug1("obuf is full, stopping output to display %s\n", D_usertty);
1780 D_blocked = 1;
1781 continue;
1783 debug("BLOCKING because of full obuf\n");
1784 ev->condpos = &D_obuffree;
1785 ev->condneg = &D_obuflenmax;
1786 if (D_nonblock > 0 && !D_blockedev.queued)
1788 debug1("created timeout of %g secs\n", D_nonblock/1000.);
1789 SetTimeout(&D_blockedev, D_nonblock);
1790 evenq(&D_blockedev);
1792 return 1;
1795 return 0;
1798 static void
1799 win_readev_fn(ev, data)
1800 struct event *ev;
1801 char *data;
1803 struct win *p = (struct win *)data;
1804 char buf[IOSIZE], *bp;
1805 int size, len;
1806 #ifdef PSEUDOS
1807 int wtop;
1808 #endif
1810 bp = buf;
1811 size = IOSIZE;
1813 #ifdef PSEUDOS
1814 wtop = p->w_pwin && W_WTOP(p);
1815 if (wtop)
1817 ASSERT(sizeof(p->w_pwin->p_inbuf) == IOSIZE);
1818 size = IOSIZE - p->w_pwin->p_inlen;
1819 if (size <= 0)
1821 ev->condpos = &const_IOSIZE;
1822 ev->condneg = &p->w_pwin->p_inlen;
1823 return;
1826 #endif
1827 if (p->w_layer.l_cvlist && muchpending(p, ev))
1828 return;
1829 #ifdef ZMODEM
1830 if (!p->w_zdisplay)
1831 #endif
1832 if (p->w_blocked)
1834 ev->condpos = &const_one;
1835 ev->condneg = &p->w_blocked;
1836 return;
1838 if (ev->condpos)
1839 ev->condpos = ev->condneg = 0;
1841 if ((len = p->w_outlen))
1843 p->w_outlen = 0;
1844 WriteString(p, p->w_outbuf, len);
1845 return;
1848 debug1("going to read from window fd %d\n", ev->fd);
1849 if ((len = read(ev->fd, buf, size)) < 0)
1851 if (errno == EINTR || errno == EAGAIN)
1852 return;
1853 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1854 if (errno == EWOULDBLOCK)
1855 return;
1856 #endif
1857 debug2("Window %d: read error (errno %d) - killing window\n", p->w_number, errno);
1858 #ifdef BSDWAIT
1859 WindowDied(p, (union wait)0, 0);
1860 #else
1861 WindowDied(p, 0, 0);
1862 #endif
1863 return;
1865 if (len == 0)
1867 debug1("Window %d: EOF - killing window\n", p->w_number);
1868 #ifdef BSDWAIT
1869 WindowDied(p, (union wait)0, 0);
1870 #else
1871 WindowDied(p, 0, 0);
1872 #endif
1873 return;
1875 debug1(" -> %d bytes\n", len);
1876 #ifdef TIOCPKT
1877 if (p->w_type == W_TYPE_PTY)
1879 if (buf[0])
1881 debug1("PAKET %x\n", buf[0]);
1882 if (buf[0] & TIOCPKT_NOSTOP)
1883 WNewAutoFlow(p, 0);
1884 if (buf[0] & TIOCPKT_DOSTOP)
1885 WNewAutoFlow(p, 1);
1887 bp++;
1888 len--;
1890 #endif
1891 #ifdef BUILTIN_TELNET
1892 if (p->w_type == W_TYPE_TELNET)
1893 len = TelIn(p, bp, len, buf + sizeof(buf) - (bp + len));
1894 #endif
1895 if (len == 0)
1896 return;
1897 #ifdef ZMODEM
1898 if (zmodem_mode && zmodem_parse(p, bp, len))
1899 return;
1900 #endif
1901 #ifdef PSEUDOS
1902 if (wtop)
1904 debug("sending input to pwin\n");
1905 bcopy(bp, p->w_pwin->p_inbuf + p->w_pwin->p_inlen, len);
1906 p->w_pwin->p_inlen += len;
1908 #endif
1909 WriteString(p, bp, len);
1910 return;
1914 static void
1915 win_writeev_fn(ev, data)
1916 struct event *ev;
1917 char *data;
1919 struct win *p = (struct win *)data;
1920 int len;
1921 if (p->w_inlen)
1923 debug2("writing %d bytes to win %d\n", p->w_inlen, p->w_number);
1924 if ((len = write(ev->fd, p->w_inbuf, p->w_inlen)) <= 0)
1925 len = p->w_inlen; /* dead window */
1926 if ((p->w_inlen -= len))
1927 bcopy(p->w_inbuf + len, p->w_inbuf, p->w_inlen);
1929 #ifdef COPY_PASTE
1930 if (p->w_paster.pa_pastelen && !p->w_slowpaste)
1932 struct paster *pa = &p->w_paster;
1933 flayer = pa->pa_pastelayer;
1934 if (flayer)
1935 DoProcess(p, &pa->pa_pasteptr, &pa->pa_pastelen, pa);
1937 #endif
1938 return;
1943 #ifdef PSEUDOS
1945 static void
1946 pseu_readev_fn(ev, data)
1947 struct event *ev;
1948 char *data;
1950 struct win *p = (struct win *)data;
1951 char buf[IOSIZE];
1952 int size, ptow, len;
1954 size = IOSIZE;
1956 ptow = W_PTOW(p);
1957 if (ptow)
1959 ASSERT(sizeof(p->w_inbuf) == IOSIZE);
1960 size = IOSIZE - p->w_inlen;
1961 if (size <= 0)
1963 ev->condpos = &const_IOSIZE;
1964 ev->condneg = &p->w_inlen;
1965 return;
1968 if (p->w_layer.l_cvlist && muchpending(p, ev))
1969 return;
1970 if (p->w_blocked)
1972 ev->condpos = &const_one;
1973 ev->condneg = &p->w_blocked;
1974 return;
1976 if (ev->condpos)
1977 ev->condpos = ev->condneg = 0;
1979 if ((len = p->w_outlen))
1981 p->w_outlen = 0;
1982 WriteString(p, p->w_outbuf, len);
1983 return;
1986 if ((len = read(ev->fd, buf, size)) <= 0)
1988 if (errno == EINTR || errno == EAGAIN)
1989 return;
1990 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1991 if (errno == EWOULDBLOCK)
1992 return;
1993 #endif
1994 debug2("Window %d: pseudowin read error (errno %d) -- removing pseudowin\n", p->w_number, len ? errno : 0);
1995 FreePseudowin(p);
1996 return;
1998 /* no packet mode on pseudos! */
1999 if (ptow)
2001 bcopy(buf, p->w_inbuf + p->w_inlen, len);
2002 p->w_inlen += len;
2004 WriteString(p, buf, len);
2005 return;
2008 static void
2009 pseu_writeev_fn(ev, data)
2010 struct event *ev;
2011 char *data;
2013 struct win *p = (struct win *)data;
2014 struct pseudowin *pw = p->w_pwin;
2015 int len;
2017 ASSERT(pw);
2018 if (pw->p_inlen == 0)
2019 return;
2020 if ((len = write(ev->fd, pw->p_inbuf, pw->p_inlen)) <= 0)
2021 len = pw->p_inlen; /* dead pseudo */
2022 if ((p->w_pwin->p_inlen -= len))
2023 bcopy(p->w_pwin->p_inbuf + len, p->w_pwin->p_inbuf, p->w_pwin->p_inlen);
2027 #endif /* PSEUDOS */
2029 static void
2030 win_silenceev_fn(ev, data)
2031 struct event *ev;
2032 char *data;
2034 struct win *p = (struct win *)data;
2035 struct canvas *cv;
2036 debug1("FOUND silence win %d\n", p->w_number);
2037 for (display = displays; display; display = display->d_next)
2039 for (cv = D_cvlist; cv; cv = cv->c_next)
2040 if (cv->c_layer->l_bottom == &p->w_layer)
2041 break;
2042 if (cv)
2043 continue; /* user already sees window */
2044 #ifdef MULTIUSER
2045 if (!(ACLBYTE(p->w_lio_notify, D_user->u_id) & ACLBIT(D_user->u_id)))
2046 continue;
2047 #endif
2048 Msg(0, "Window %d: silence for %d seconds", p->w_number, p->w_silencewait);
2052 #ifdef ZMODEM
2054 static int
2055 zmodem_parse(p, bp, len)
2056 struct win *p;
2057 char *bp;
2058 int len;
2060 int i;
2061 char *b2 = bp;
2062 for (i = 0; i < len; i++, b2++)
2064 if (p->w_zauto == 0)
2066 for (; i < len; i++, b2++)
2067 if (*b2 == 030)
2068 break;
2069 if (i == len)
2070 break;
2071 if (i > 1 && b2[-1] == '*' && b2[-2] == '*')
2072 p->w_zauto = 3;
2073 continue;
2075 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'))
2077 if (++p->w_zauto < 6)
2078 continue;
2079 if (p->w_zauto == 6)
2080 p->w_zauto = 0;
2081 if (!p->w_zdisplay)
2083 if (i > 6)
2084 WriteString(p, bp, i + 1 - 6);
2085 WriteString(p, "\r\n", 2);
2086 zmodem_found(p, *b2 == '1', b2 + 1, len - i - 1);
2087 return 1;
2089 else if (p->w_zauto == 7 || *b2 == '8')
2091 int se = p->w_zdisplay->d_blocked == 2 ? 'O' : '\212';
2092 for (; i < len; i++, b2++)
2093 if (*b2 == se)
2094 break;
2095 if (i < len)
2097 zmodem_abort(p, 0);
2098 D_blocked = 0;
2099 D_readev.condpos = D_readev.condneg = 0;
2100 while (len-- > 0)
2101 AddChar(*bp++);
2102 Flush();
2103 Activate(D_fore ? D_fore->w_norefresh : 0);
2104 return 1;
2106 p->w_zauto = 6;
2109 else
2110 p->w_zauto = *b2 == '*' ? (p->w_zauto == 2 ? 2 : 1) : 0;
2112 if (p->w_zauto == 0 && bp[len - 1] == '*')
2113 p->w_zauto = len > 1 && bp[len - 2] == '*' ? 2 : 1;
2114 if (p->w_zdisplay)
2116 display = p->w_zdisplay;
2117 while (len-- > 0)
2118 AddChar(*bp++);
2119 return 1;
2121 return 0;
2124 static void
2125 zmodem_fin(buf, len, data)
2126 char *buf;
2127 int len;
2128 char *data;
2130 char *s;
2131 int n;
2133 if (len)
2134 RcLine(buf, strlen(buf) + 1);
2135 else
2137 s = "\030\030\030\030\030\030\030\030\030\030";
2138 n = strlen(s);
2139 LayProcess(&s, &n);
2143 static void
2144 zmodem_found(p, send, bp, len)
2145 struct win *p;
2146 int send;
2147 char *bp;
2148 int len;
2150 char *s;
2151 int i, n;
2152 extern int zmodem_mode;
2154 /* check for abort sequence */
2155 n = 0;
2156 for (i = 0; i < len ; i++)
2157 if (bp[i] != 030)
2158 n = 0;
2159 else if (++n > 4)
2160 return;
2161 if (zmodem_mode == 3 || (zmodem_mode == 1 && p->w_type != W_TYPE_PLAIN))
2163 struct display *d, *olddisplay;
2165 olddisplay = display;
2166 d = p->w_lastdisp;
2167 if (!d || d->d_fore != p)
2168 for (d = displays; d; d = d->d_next)
2169 if (d->d_fore == p)
2170 break;
2171 if (!d && p->w_layer.l_cvlist)
2172 d = p->w_layer.l_cvlist->c_display;
2173 if (!d)
2174 d = displays;
2175 if (!d)
2176 return;
2177 display = d;
2178 RemoveStatus();
2179 p->w_zdisplay = display;
2180 D_blocked = 2 + send;
2181 flayer = &p->w_layer;
2182 ZmodemPage();
2183 display = d;
2184 evdeq(&D_blockedev);
2185 D_readev.condpos = &const_IOSIZE;
2186 D_readev.condneg = &p->w_inlen;
2187 ClearAll();
2188 GotoPos(0, 0);
2189 SetRendition(&mchar_blank);
2190 AddStr("Zmodem active\r\n\r\n");
2191 AddStr(send ? "**\030B01" : "**\030B00");
2192 while (len-- > 0)
2193 AddChar(*bp++);
2194 display = olddisplay;
2195 return;
2197 flayer = &p->w_layer;
2198 Input(":", 100, INP_COOKED, zmodem_fin, NULL, 0);
2199 s = send ? zmodem_sendcmd : zmodem_recvcmd;
2200 n = strlen(s);
2201 LayProcess(&s, &n);
2204 void
2205 zmodem_abort(p, d)
2206 struct win *p;
2207 struct display *d;
2209 struct display *olddisplay = display;
2210 struct layer *oldflayer = flayer;
2211 if (p)
2213 if (p->w_savelayer && p->w_savelayer->l_next)
2215 if (oldflayer == p->w_savelayer)
2216 oldflayer = flayer->l_next;
2217 flayer = p->w_savelayer;
2218 ExitOverlayPage();
2220 p->w_zdisplay = 0;
2221 p->w_zauto = 0;
2222 LRefreshAll(&p->w_layer, 0);
2224 if (d)
2226 display = d;
2227 D_blocked = 0;
2228 D_readev.condpos = D_readev.condneg = 0;
2229 Activate(D_fore ? D_fore->w_norefresh : 0);
2231 display = olddisplay;
2232 flayer = oldflayer;
2235 #endif