Implement window event onslient & onactivity
[screen-lua.git] / src / window.c
bloba6cc9fed06af6ff472ce40ce4dfe97749ff1a28b
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);
954 #ifdef SCRIPT
955 trigger_sevent(&wp->w_sev.onclose, wp);
956 #endif
958 #ifdef PSEUDOS
959 if (wp->w_pwin)
960 FreePseudowin(wp);
961 #endif
962 #ifdef UTMPOK
963 RemoveUtmp(wp);
964 #endif
965 CloseDevice(wp);
967 if (wp == console_window)
969 TtyGrabConsole(-1, -1, "free");
970 console_window = 0;
972 if (wp->w_log != NULL)
973 logfclose(wp->w_log);
974 ChangeWindowSize(wp, 0, 0, 0);
976 if (wp->w_type == W_TYPE_GROUP)
978 struct win *win;
979 for (win = windows; win; win = win->w_next)
980 if (win->w_group == wp)
981 win->w_group = wp->w_group;
984 if (wp->w_hstatus)
985 free(wp->w_hstatus);
986 for (i = 0; wp->w_cmdargs[i]; i++)
987 free(wp->w_cmdargs[i]);
988 if (wp->w_dir)
989 free(wp->w_dir);
990 if (wp->w_term)
991 free(wp->w_term);
992 for (d = displays; d; d = d->d_next)
994 if (d->d_other == wp)
995 d->d_other = d->d_fore && d->d_fore->w_next != wp ? d->d_fore->w_next : wp->w_next;
996 if (d->d_fore == wp)
997 d->d_fore = NULL;
998 for (cv = d->d_cvlist; cv; cv = cv->c_next)
1000 for (l = cv->c_layer; l; l = l->l_next)
1001 if (l->l_layfn == &WinLf)
1002 break;
1003 if (!l)
1004 continue;
1005 if ((struct win *)l->l_data != wp)
1006 continue;
1007 if (cv->c_layer == wp->w_savelayer)
1008 wp->w_savelayer = 0;
1009 KillLayerChain(cv->c_layer);
1012 if (wp->w_savelayer)
1013 KillLayerChain(wp->w_savelayer);
1014 for (cv = wp->w_layer.l_cvlist; cv; cv = ncv)
1016 ncv = cv->c_lnext;
1017 cv->c_layer = &cv->c_blank;
1018 cv->c_blank.l_cvlist = cv;
1019 cv->c_lnext = 0;
1020 cv->c_xoff = cv->c_xs;
1021 cv->c_yoff = cv->c_ys;
1022 RethinkViewportOffsets(cv);
1024 wp->w_layer.l_cvlist = 0;
1025 if (flayer == &wp->w_layer)
1026 flayer = 0;
1028 #ifdef MULTIUSER
1029 FreeWindowAcl(wp);
1030 #endif /* MULTIUSER */
1031 evdeq(&wp->w_readev); /* just in case */
1032 evdeq(&wp->w_writeev); /* just in case */
1033 evdeq(&wp->w_silenceev);
1034 #ifdef COPY_PASTE
1035 FreePaster(&wp->w_paster);
1036 #endif
1038 #ifdef SCRIPT
1039 broker_inv_obj(wp);
1040 #endif
1041 free((char *)wp);
1044 static int
1045 OpenDevice(args, lflag, typep, namep)
1046 char **args;
1047 int lflag;
1048 int *typep;
1049 char **namep;
1051 char *arg = args[0];
1052 struct stat st;
1053 int f;
1055 if (!arg)
1056 return -1;
1057 if (strcmp(arg, "//group") == 0)
1059 *typep = W_TYPE_GROUP;
1060 *namep = "telnet";
1061 return 0;
1063 #ifdef BUILTIN_TELNET
1064 if (strcmp(arg, "//telnet") == 0)
1066 f = TelOpen(args + 1);
1067 lflag = 0;
1068 *typep = W_TYPE_TELNET;
1069 *namep = "telnet";
1071 else
1072 #endif
1073 if (strncmp(arg, "//", 2) == 0)
1075 Msg(0, "Invalid argument '%s'", arg);
1076 return -1;
1078 else if ((stat(arg, &st)) == 0 && S_ISCHR(st.st_mode))
1080 if (access(arg, R_OK | W_OK) == -1)
1082 Msg(errno, "Cannot access line '%s' for R/W", arg);
1083 return -1;
1085 debug("OpenDevice: OpenTTY\n");
1086 if ((f = OpenTTY(arg, args[1])) < 0)
1087 return -1;
1088 lflag = 0;
1089 *typep = W_TYPE_PLAIN;
1090 *namep = arg;
1092 else
1094 *typep = W_TYPE_PTY;
1095 f = OpenPTY(namep);
1096 if (f == -1)
1098 Msg(0, "No more PTYs.");
1099 return -1;
1101 #ifdef TIOCPKT
1103 int flag = 1;
1104 if (ioctl(f, TIOCPKT, (char *)&flag))
1106 Msg(errno, "TIOCPKT ioctl");
1107 close(f);
1108 return -1;
1111 #endif /* TIOCPKT */
1113 debug1("fcntl(%d, F_SETFL, FNBLOCK)\n", f);
1114 (void) fcntl(f, F_SETFL, FNBLOCK);
1115 #ifdef linux
1117 * Tenebreux (zeus@ns.acadiacom.net) has Linux 1.3.70 where select
1118 * gets confused in the following condition:
1119 * Open a pty-master side, request a flush on it, then set packet
1120 * mode and call select(). Select will return a possible read, where
1121 * the one byte response to the flush can be found. Select will
1122 * thereafter return a possible read, which yields I/O error.
1124 * If we request another flush *after* switching into packet mode,
1125 * this I/O error does not occur. We receive a single response byte
1126 * although we send two flush requests now.
1128 * Maybe we should not flush at all.
1130 * 10.5.96 jw.
1132 if (*typep == W_TYPE_PTY || *typep == W_TYPE_PLAIN)
1133 tcflush(f, TCIOFLUSH);
1134 #endif
1136 if (*typep != W_TYPE_PTY)
1137 return f;
1139 #ifndef PTYROFS
1140 #ifdef PTYGROUP
1141 if (chown(*namep, real_uid, PTYGROUP) && !eff_uid)
1142 #else
1143 if (chown(*namep, real_uid, real_gid) && !eff_uid)
1144 #endif
1146 Msg(errno, "chown tty");
1147 close(f);
1148 return -1;
1150 #ifdef UTMPOK
1151 if (chmod(*namep, lflag ? TtyMode : (TtyMode & ~022)) && !eff_uid)
1152 #else
1153 if (chmod(*namep, TtyMode) && !eff_uid)
1154 #endif
1156 Msg(errno, "chmod tty");
1157 close(f);
1158 return -1;
1160 #endif
1161 return f;
1165 * Fields w_width, w_height, aflag, number (and w_tty)
1166 * are read from struct win *win. No fields written.
1167 * If pwin is nonzero, filedescriptors are distributed
1168 * between win->w_tty and open(ttyn)
1171 static int
1172 ForkWindow(win, args, ttyn)
1173 struct win *win;
1174 char **args, *ttyn;
1176 int pid;
1177 char tebuf[25];
1178 char ebuf[20];
1179 char shellbuf[7 + MAXPATHLEN];
1180 char *proc;
1181 #ifndef TIOCSWINSZ
1182 char libuf[20], cobuf[20];
1183 #endif
1184 int newfd;
1185 int w = win->w_width;
1186 int h = win->w_height;
1187 #ifdef PSEUDOS
1188 int i, pat, wfdused;
1189 struct pseudowin *pwin = win->w_pwin;
1190 #endif
1191 int slave = -1;
1193 #ifdef O_NOCTTY
1194 if (pty_preopen)
1196 debug("pre-opening slave...\n");
1197 if ((slave = open(ttyn, O_RDWR|O_NOCTTY)) == -1)
1199 Msg(errno, "ttyn");
1200 return -1;
1203 #endif
1204 debug("forking...\n");
1205 proc = *args;
1206 if (proc == 0)
1208 args = ShellArgs;
1209 proc = *args;
1211 fflush(stdout);
1212 fflush(stderr);
1213 switch (pid = fork())
1215 case -1:
1216 Msg(errno, "fork");
1217 break;
1218 case 0:
1219 signal(SIGHUP, SIG_DFL);
1220 signal(SIGINT, SIG_DFL);
1221 signal(SIGQUIT, SIG_DFL);
1222 signal(SIGTERM, SIG_DFL);
1223 #ifdef BSDJOBS
1224 signal(SIGTTIN, SIG_DFL);
1225 signal(SIGTTOU, SIG_DFL);
1226 #endif
1227 #ifdef SIGPIPE
1228 signal(SIGPIPE, SIG_DFL);
1229 #endif
1230 #ifdef SIGXFSZ
1231 signal(SIGXFSZ, SIG_DFL);
1232 #endif
1234 displays = 0; /* beware of Panic() */
1235 if (setgid(real_gid) || setuid(real_uid))
1236 Panic(errno, "Setuid/gid");
1237 eff_uid = real_uid;
1238 eff_gid = real_gid;
1239 #ifdef PSEUDOS
1240 if (!pwin) /* ignore directory if pseudo */
1241 #endif
1242 if (win->w_dir && *win->w_dir && chdir(win->w_dir))
1243 Panic(errno, "Cannot chdir to %s", win->w_dir);
1245 if (display)
1247 brktty(D_userfd);
1248 freetty();
1250 else
1251 brktty(-1);
1252 #ifdef DEBUG
1253 if (dfp && dfp != stderr)
1254 fclose(dfp);
1255 #endif
1256 if (slave != -1)
1258 close(0);
1259 dup(slave);
1260 close(slave);
1261 closeallfiles(win->w_ptyfd);
1262 slave = dup(0);
1264 else
1265 closeallfiles(win->w_ptyfd);
1266 #ifdef DEBUG
1267 if (dfp) /* do not produce child debug, when debug is "off" */
1269 char buf[256];
1271 sprintf(buf, "%s/screen.child", DEBUGDIR);
1272 if ((dfp = fopen(buf, "a")) == 0)
1273 dfp = stderr;
1274 else
1275 (void) chmod(buf, 0666);
1277 debug1("=== ForkWindow: pid %d\n", (int)getpid());
1278 #endif
1279 /* Close the three /dev/null descriptors */
1280 close(0);
1281 close(1);
1282 close(2);
1283 newfd = -1;
1285 * distribute filedescriptors between the ttys
1287 #ifdef PSEUDOS
1288 pat = pwin ? pwin->p_fdpat :
1289 ((F_PFRONT<<(F_PSHIFT*2)) | (F_PFRONT<<F_PSHIFT) | F_PFRONT);
1290 debug1("Using window pattern 0x%x\n", pat);
1291 wfdused = 0;
1292 for(i = 0; i < 3; i++)
1294 if (pat & F_PFRONT << F_PSHIFT * i)
1296 if (newfd < 0)
1298 # ifdef O_NOCTTY
1299 if (separate_sids)
1300 newfd = open(ttyn, O_RDWR);
1301 else
1302 newfd = open(ttyn, O_RDWR|O_NOCTTY);
1303 # else
1304 newfd = open(ttyn, O_RDWR);
1305 # endif
1306 if (newfd < 0)
1307 Panic(errno, "Cannot open %s", ttyn);
1309 else
1310 dup(newfd);
1312 else
1314 dup(win->w_ptyfd);
1315 wfdused = 1;
1318 if (wfdused)
1321 * the pseudo window process should not be surprised with a
1322 * nonblocking filedescriptor. Poor Backend!
1324 debug1("Clearing NBLOCK on window-fd(%d)\n", win->w_ptyfd);
1325 if (fcntl(win->w_ptyfd, F_SETFL, 0))
1326 Msg(errno, "Warning: clear NBLOCK fcntl failed");
1328 #else /* PSEUDOS */
1329 # ifdef O_NOCTTY
1330 if (separate_sids)
1331 newfd = open(ttyn, O_RDWR);
1332 else
1333 newfd = open(ttyn, O_RDWR|O_NOCTTY);
1334 # else
1335 newfd = open(ttyn, O_RDWR);
1336 # endif
1337 if (newfd != 0)
1338 Panic(errno, "Cannot open %s", ttyn);
1339 dup(0);
1340 dup(0);
1341 #endif /* PSEUDOS */
1342 close(win->w_ptyfd);
1343 if (slave != -1)
1344 close(slave);
1345 if (newfd >= 0)
1347 struct mode fakemode, *modep;
1348 InitPTY(newfd);
1349 if (fgtty(newfd))
1350 Msg(errno, "fgtty");
1351 if (display)
1353 debug("ForkWindow: using display tty mode for new child.\n");
1354 modep = &D_OldMode;
1356 else
1358 debug("No display - creating tty setting\n");
1359 modep = &fakemode;
1360 InitTTY(modep, 0);
1361 #ifdef DEBUG
1362 DebugTTY(modep);
1363 #endif
1365 /* We only want echo if the users input goes to the pseudo
1366 * and the pseudo's stdout is not send to the window.
1368 #ifdef PSEUDOS
1369 if (pwin && (!(pat & F_UWP) || (pat & F_PBACK << F_PSHIFT)))
1371 debug1("clearing echo on pseudywin fd (pat %x)\n", pat);
1372 # if defined(POSIX) || defined(TERMIO)
1373 modep->tio.c_lflag &= ~ECHO;
1374 modep->tio.c_iflag &= ~ICRNL;
1375 # else
1376 modep->m_ttyb.sg_flags &= ~ECHO;
1377 # endif
1379 #endif
1380 SetTTY(newfd, modep);
1381 #ifdef TIOCSWINSZ
1382 glwz.ws_col = w;
1383 glwz.ws_row = h;
1384 (void) ioctl(newfd, TIOCSWINSZ, (char *)&glwz);
1385 #endif
1386 /* Always turn off nonblocking mode */
1387 (void)fcntl(newfd, F_SETFL, 0);
1389 #ifndef TIOCSWINSZ
1390 sprintf(libuf, "LINES=%d", h);
1391 sprintf(cobuf, "COLUMNS=%d", w);
1392 NewEnv[5] = libuf;
1393 NewEnv[6] = cobuf;
1394 #endif
1395 #ifdef MAPKEYS
1396 NewEnv[2] = MakeTermcap(display == 0 || win->w_aflag);
1397 #else
1398 if (win->w_aflag)
1399 NewEnv[2] = MakeTermcap(1);
1400 else
1401 NewEnv[2] = Termcap;
1402 #endif
1403 strcpy(shellbuf, "SHELL=");
1404 strncpy(shellbuf + 6, ShellProg + (*ShellProg == '-'), sizeof(shellbuf) - 7);
1405 shellbuf[sizeof(shellbuf) - 1] = 0;
1406 NewEnv[4] = shellbuf;
1407 debug1("ForkWindow: NewEnv[4] = '%s'\n", shellbuf);
1408 if (win->w_term && *win->w_term && strcmp(screenterm, win->w_term) &&
1409 (strlen(win->w_term) < 20))
1411 char *s1, *s2, tl;
1413 sprintf(tebuf, "TERM=%s", win->w_term);
1414 debug2("Makewindow %d with %s\n", win->w_number, tebuf);
1415 tl = strlen(win->w_term);
1416 NewEnv[1] = tebuf;
1417 if ((s1 = index(NewEnv[2], '|')))
1419 if ((s2 = index(++s1, '|')))
1421 if (strlen(NewEnv[2]) - (s2 - s1) + tl < 1024)
1423 bcopy(s2, s1 + tl, strlen(s2) + 1);
1424 bcopy(win->w_term, s1, tl);
1429 sprintf(ebuf, "WINDOW=%d", win->w_number);
1430 NewEnv[3] = ebuf;
1432 if (*proc == '-')
1433 proc++;
1434 if (!*proc)
1435 proc = DefaultShell;
1436 debug1("calling execvpe %s\n", proc);
1437 execvpe(proc, args, NewEnv);
1438 debug1("exec error: %d\n", errno);
1439 Panic(errno, "Cannot exec '%s'", proc);
1440 default:
1441 break;
1443 if (slave != -1)
1444 close(slave);
1445 return pid;
1448 void
1449 execvpe(prog, args, env)
1450 char *prog, **args, **env;
1452 register char *path = NULL, *p;
1453 char buf[1024];
1454 char *shargs[MAXARGS + 1];
1455 register int i, eaccess = 0;
1457 if (rindex(prog, '/'))
1458 path = "";
1459 if (!path && !(path = getenv("PATH")))
1460 path = DefaultPath;
1463 for (p = buf; *path && *path != ':'; path++)
1464 if (p - buf < (int)sizeof(buf) - 2)
1465 *p++ = *path;
1466 if (p > buf)
1467 *p++ = '/';
1468 if (p - buf + strlen(prog) >= sizeof(buf) - 1)
1469 continue;
1470 strcpy(p, prog);
1471 execve(buf, args, env);
1472 switch (errno)
1474 case ENOEXEC:
1475 shargs[0] = DefaultShell;
1476 shargs[1] = buf;
1477 for (i = 1; (shargs[i + 1] = args[i]) != NULL; ++i)
1479 execve(DefaultShell, shargs, env);
1480 return;
1481 case EACCES:
1482 eaccess = 1;
1483 break;
1484 case ENOMEM:
1485 case E2BIG:
1486 case ETXTBSY:
1487 return;
1489 } while (*path++);
1490 if (eaccess)
1491 errno = EACCES;
1494 #ifdef PSEUDOS
1497 winexec(av)
1498 char **av;
1500 char **pp;
1501 char *p, *s, *t;
1502 int i, r = 0, l = 0;
1503 struct win *w;
1504 extern struct display *display;
1505 extern struct win *windows;
1506 struct pseudowin *pwin;
1507 int type;
1509 if ((w = display ? fore : windows) == NULL)
1510 return -1;
1511 if (!*av || w->w_pwin)
1513 Msg(0, "Filter running: %s", w->w_pwin ? w->w_pwin->p_cmd : "(none)");
1514 return -1;
1516 if (w->w_ptyfd < 0)
1518 Msg(0, "You feel dead inside.");
1519 return -1;
1521 if (!(pwin = (struct pseudowin *)calloc(1, sizeof(struct pseudowin))))
1523 Msg(0, strnomem);
1524 return -1;
1527 /* allow ^a:!!./ttytest as a short form for ^a:exec !.. ./ttytest */
1528 for (s = *av; *s == ' '; s++)
1530 for (p = s; *p == ':' || *p == '.' || *p == '!'; p++)
1532 if (*p != '|')
1533 while (*p && p > s && p[-1] == '.')
1534 p--;
1535 if (*p == '|')
1537 l = F_UWP;
1538 p++;
1540 if (*p)
1541 av[0] = p;
1542 else
1543 av++;
1545 t = pwin->p_cmd;
1546 for (i = 0; i < 3; i++)
1548 *t = (s < p) ? *s++ : '.';
1549 switch (*t++)
1551 case '.':
1552 case '|':
1553 l |= F_PFRONT << (i * F_PSHIFT);
1554 break;
1555 case '!':
1556 l |= F_PBACK << (i * F_PSHIFT);
1557 break;
1558 case ':':
1559 l |= F_PBOTH << (i * F_PSHIFT);
1560 break;
1564 if (l & F_UWP)
1566 *t++ = '|';
1567 if ((l & F_PMASK) == F_PFRONT)
1569 *pwin->p_cmd = '!';
1570 l ^= F_PFRONT | F_PBACK;
1573 if (!(l & F_PBACK))
1574 l |= F_UWP;
1575 *t++ = ' ';
1576 pwin->p_fdpat = l;
1577 debug1("winexec: '%#x'\n", pwin->p_fdpat);
1579 l = MAXSTR - 4;
1580 for (pp = av; *pp; pp++)
1582 p = *pp;
1583 while (*p && l-- > 0)
1584 *t++ = *p++;
1585 if (l <= 0)
1586 break;
1587 *t++ = ' ';
1589 *--t = '\0';
1590 debug1("%s\n", pwin->p_cmd);
1592 if ((pwin->p_ptyfd = OpenDevice(av, 0, &type, &t)) < 0)
1594 free((char *)pwin);
1595 return -1;
1597 strncpy(pwin->p_tty, t, MAXSTR - 1);
1598 w->w_pwin = pwin;
1599 if (type != W_TYPE_PTY)
1601 FreePseudowin(w);
1602 Msg(0, "Cannot only use commands as pseudo win.");
1603 return -1;
1605 if (!(pwin->p_fdpat & F_PFRONT))
1606 evdeq(&w->w_readev);
1607 #ifdef TIOCPKT
1609 int flag = 0;
1611 if (ioctl(pwin->p_ptyfd, TIOCPKT, (char *)&flag))
1613 Msg(errno, "TIOCPKT pwin ioctl");
1614 FreePseudowin(w);
1615 return -1;
1617 if (w->w_type == W_TYPE_PTY && !(pwin->p_fdpat & F_PFRONT))
1619 if (ioctl(w->w_ptyfd, TIOCPKT, (char *)&flag))
1621 Msg(errno, "TIOCPKT win ioctl");
1622 FreePseudowin(w);
1623 return -1;
1627 #endif /* TIOCPKT */
1629 pwin->p_readev.fd = pwin->p_writeev.fd = pwin->p_ptyfd;
1630 pwin->p_readev.type = EV_READ;
1631 pwin->p_writeev.type = EV_WRITE;
1632 pwin->p_readev.data = pwin->p_writeev.data = (char *)w;
1633 pwin->p_readev.handler = pseu_readev_fn;
1634 pwin->p_writeev.handler = pseu_writeev_fn;
1635 pwin->p_writeev.condpos = &pwin->p_inlen;
1636 if (pwin->p_fdpat & (F_PFRONT << F_PSHIFT * 2 | F_PFRONT << F_PSHIFT))
1637 evenq(&pwin->p_readev);
1638 evenq(&pwin->p_writeev);
1639 r = pwin->p_pid = ForkWindow(w, av, t);
1640 if (r < 0)
1641 FreePseudowin(w);
1642 return r;
1645 void
1646 FreePseudowin(w)
1647 struct win *w;
1649 struct pseudowin *pwin = w->w_pwin;
1651 ASSERT(pwin);
1652 if (fcntl(w->w_ptyfd, F_SETFL, FNBLOCK))
1653 Msg(errno, "Warning: FreePseudowin: NBLOCK fcntl failed");
1654 #ifdef TIOCPKT
1655 if (w->w_type == W_TYPE_PTY && !(pwin->p_fdpat & F_PFRONT))
1657 int flag = 1;
1658 if (ioctl(w->w_ptyfd, TIOCPKT, (char *)&flag))
1659 Msg(errno, "Warning: FreePseudowin: TIOCPKT win ioctl");
1661 #endif
1662 /* should be able to use CloseDevice() here */
1663 (void)chmod(pwin->p_tty, 0666);
1664 (void)chown(pwin->p_tty, 0, 0);
1665 if (pwin->p_ptyfd >= 0)
1666 close(pwin->p_ptyfd);
1667 evdeq(&pwin->p_readev);
1668 evdeq(&pwin->p_writeev);
1669 if (w->w_readev.condneg == &pwin->p_inlen)
1670 w->w_readev.condpos = w->w_readev.condneg = 0;
1671 evenq(&w->w_readev);
1672 free((char *)pwin);
1673 w->w_pwin = NULL;
1676 #endif /* PSEUDOS */
1679 #ifdef MULTIUSER
1681 * returns 0, if the lock really has been released
1684 ReleaseAutoWritelock(dis, w)
1685 struct display *dis;
1686 struct win *w;
1688 debug2("ReleaseAutoWritelock: user %s, window %d\n",
1689 dis->d_user->u_name, w->w_number);
1691 /* release auto writelock when user has no other display here */
1692 if (w->w_wlock == WLOCK_AUTO && w->w_wlockuser == dis->d_user)
1694 struct display *d;
1696 for (d = displays; d; d = d->d_next)
1697 if (( d != dis) && (d->d_fore == w) && (d->d_user == dis->d_user))
1698 break;
1699 debug3("%s %s autolock on win %d\n",
1700 dis->d_user->u_name, d ? "keeps" : "releases", w->w_number);
1701 if (!d)
1703 w->w_wlockuser = NULL;
1704 return 0;
1707 return 1;
1711 * returns 0, if the lock really could be obtained
1714 ObtainAutoWritelock(d, w)
1715 struct display *d;
1716 struct win *w;
1718 if ((w->w_wlock == WLOCK_AUTO) &&
1719 !AclCheckPermWin(d->d_user, ACL_WRITE, w) &&
1720 !w->w_wlockuser)
1722 debug2("%s obtained auto writelock for exported window %d\n",
1723 d->d_user->u_name, w->w_number);
1724 w->w_wlockuser = d->d_user;
1725 return 0;
1727 return 1;
1730 #endif /* MULTIUSER */
1734 /********************************************************************/
1736 #ifdef COPY_PASTE
1737 static void
1738 paste_slowev_fn(ev, data)
1739 struct event *ev;
1740 char *data;
1742 struct paster *pa = (struct paster *)data;
1743 struct win *p;
1745 int l = 1;
1746 flayer = pa->pa_pastelayer;
1747 if (!flayer)
1748 pa->pa_pastelen = 0;
1749 if (!pa->pa_pastelen)
1750 return;
1751 p = Layer2Window(flayer);
1752 DoProcess(p, &pa->pa_pasteptr, &l, pa);
1753 pa->pa_pastelen -= 1 - l;
1754 if (pa->pa_pastelen > 0)
1756 SetTimeout(&pa->pa_slowev, p->w_slowpaste);
1757 evenq(&pa->pa_slowev);
1760 #endif
1763 static int
1764 muchpending(p, ev)
1765 struct win *p;
1766 struct event *ev;
1768 struct canvas *cv;
1769 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
1771 display = cv->c_display;
1772 if (D_status == STATUS_ON_WIN && !D_status_bell)
1774 /* wait 'til status is gone */
1775 debug("BLOCKING because of status\n");
1776 ev->condpos = &const_one;
1777 ev->condneg = &D_status;
1778 return 1;
1780 debug2("muchpending %s %d: ", D_usertty, D_blocked);
1781 debug3("%d %d %d\n", D_obufp - D_obuf, D_obufmax, D_blocked_fuzz);
1782 if (D_blocked)
1783 continue;
1784 if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
1786 if (D_nonblock == 0)
1788 debug1("obuf is full, stopping output to display %s\n", D_usertty);
1789 D_blocked = 1;
1790 continue;
1792 debug("BLOCKING because of full obuf\n");
1793 ev->condpos = &D_obuffree;
1794 ev->condneg = &D_obuflenmax;
1795 if (D_nonblock > 0 && !D_blockedev.queued)
1797 debug1("created timeout of %g secs\n", D_nonblock/1000.);
1798 SetTimeout(&D_blockedev, D_nonblock);
1799 evenq(&D_blockedev);
1801 return 1;
1804 return 0;
1807 static void
1808 win_readev_fn(ev, data)
1809 struct event *ev;
1810 char *data;
1812 struct win *p = (struct win *)data;
1813 char buf[IOSIZE], *bp;
1814 int size, len;
1815 #ifdef PSEUDOS
1816 int wtop;
1817 #endif
1819 bp = buf;
1820 size = IOSIZE;
1822 #ifdef PSEUDOS
1823 wtop = p->w_pwin && W_WTOP(p);
1824 if (wtop)
1826 ASSERT(sizeof(p->w_pwin->p_inbuf) == IOSIZE);
1827 size = IOSIZE - p->w_pwin->p_inlen;
1828 if (size <= 0)
1830 ev->condpos = &const_IOSIZE;
1831 ev->condneg = &p->w_pwin->p_inlen;
1832 return;
1835 #endif
1836 if (p->w_layer.l_cvlist && muchpending(p, ev))
1837 return;
1838 #ifdef ZMODEM
1839 if (!p->w_zdisplay)
1840 #endif
1841 if (p->w_blocked)
1843 ev->condpos = &const_one;
1844 ev->condneg = &p->w_blocked;
1845 return;
1847 if (ev->condpos)
1848 ev->condpos = ev->condneg = 0;
1850 if ((len = p->w_outlen))
1852 p->w_outlen = 0;
1853 WriteString(p, p->w_outbuf, len);
1854 return;
1857 debug1("going to read from window fd %d\n", ev->fd);
1858 if ((len = read(ev->fd, buf, size)) < 0)
1860 if (errno == EINTR || errno == EAGAIN)
1861 return;
1862 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1863 if (errno == EWOULDBLOCK)
1864 return;
1865 #endif
1866 debug2("Window %d: read error (errno %d) - killing window\n", p->w_number, errno);
1867 #ifdef BSDWAIT
1868 WindowDied(p, (union wait)0, 0);
1869 #else
1870 WindowDied(p, 0, 0);
1871 #endif
1872 return;
1874 if (len == 0)
1876 debug1("Window %d: EOF - killing window\n", p->w_number);
1877 #ifdef BSDWAIT
1878 WindowDied(p, (union wait)0, 0);
1879 #else
1880 WindowDied(p, 0, 0);
1881 #endif
1882 return;
1884 debug1(" -> %d bytes\n", len);
1885 #ifdef TIOCPKT
1886 if (p->w_type == W_TYPE_PTY)
1888 if (buf[0])
1890 debug1("PAKET %x\n", buf[0]);
1891 if (buf[0] & TIOCPKT_NOSTOP)
1892 WNewAutoFlow(p, 0);
1893 if (buf[0] & TIOCPKT_DOSTOP)
1894 WNewAutoFlow(p, 1);
1896 bp++;
1897 len--;
1899 #endif
1900 #ifdef BUILTIN_TELNET
1901 if (p->w_type == W_TYPE_TELNET)
1902 len = TelIn(p, bp, len, buf + sizeof(buf) - (bp + len));
1903 #endif
1904 if (len == 0)
1905 return;
1906 #ifdef ZMODEM
1907 if (zmodem_mode && zmodem_parse(p, bp, len))
1908 return;
1909 #endif
1910 #ifdef PSEUDOS
1911 if (wtop)
1913 debug("sending input to pwin\n");
1914 bcopy(bp, p->w_pwin->p_inbuf + p->w_pwin->p_inlen, len);
1915 p->w_pwin->p_inlen += len;
1917 #endif
1918 WriteString(p, bp, len);
1919 return;
1923 static void
1924 win_writeev_fn(ev, data)
1925 struct event *ev;
1926 char *data;
1928 struct win *p = (struct win *)data;
1929 int len;
1930 if (p->w_inlen)
1932 debug2("writing %d bytes to win %d\n", p->w_inlen, p->w_number);
1933 if ((len = write(ev->fd, p->w_inbuf, p->w_inlen)) <= 0)
1934 len = p->w_inlen; /* dead window */
1935 if ((p->w_inlen -= len))
1936 bcopy(p->w_inbuf + len, p->w_inbuf, p->w_inlen);
1938 #ifdef COPY_PASTE
1939 if (p->w_paster.pa_pastelen && !p->w_slowpaste)
1941 struct paster *pa = &p->w_paster;
1942 flayer = pa->pa_pastelayer;
1943 if (flayer)
1944 DoProcess(p, &pa->pa_pasteptr, &pa->pa_pastelen, pa);
1946 #endif
1947 return;
1952 #ifdef PSEUDOS
1954 static void
1955 pseu_readev_fn(ev, data)
1956 struct event *ev;
1957 char *data;
1959 struct win *p = (struct win *)data;
1960 char buf[IOSIZE];
1961 int size, ptow, len;
1963 size = IOSIZE;
1965 ptow = W_PTOW(p);
1966 if (ptow)
1968 ASSERT(sizeof(p->w_inbuf) == IOSIZE);
1969 size = IOSIZE - p->w_inlen;
1970 if (size <= 0)
1972 ev->condpos = &const_IOSIZE;
1973 ev->condneg = &p->w_inlen;
1974 return;
1977 if (p->w_layer.l_cvlist && muchpending(p, ev))
1978 return;
1979 if (p->w_blocked)
1981 ev->condpos = &const_one;
1982 ev->condneg = &p->w_blocked;
1983 return;
1985 if (ev->condpos)
1986 ev->condpos = ev->condneg = 0;
1988 if ((len = p->w_outlen))
1990 p->w_outlen = 0;
1991 WriteString(p, p->w_outbuf, len);
1992 return;
1995 if ((len = read(ev->fd, buf, size)) <= 0)
1997 if (errno == EINTR || errno == EAGAIN)
1998 return;
1999 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
2000 if (errno == EWOULDBLOCK)
2001 return;
2002 #endif
2003 debug2("Window %d: pseudowin read error (errno %d) -- removing pseudowin\n", p->w_number, len ? errno : 0);
2004 FreePseudowin(p);
2005 return;
2007 /* no packet mode on pseudos! */
2008 if (ptow)
2010 bcopy(buf, p->w_inbuf + p->w_inlen, len);
2011 p->w_inlen += len;
2013 WriteString(p, buf, len);
2014 return;
2017 static void
2018 pseu_writeev_fn(ev, data)
2019 struct event *ev;
2020 char *data;
2022 struct win *p = (struct win *)data;
2023 struct pseudowin *pw = p->w_pwin;
2024 int len;
2026 ASSERT(pw);
2027 if (pw->p_inlen == 0)
2028 return;
2029 if ((len = write(ev->fd, pw->p_inbuf, pw->p_inlen)) <= 0)
2030 len = pw->p_inlen; /* dead pseudo */
2031 if ((p->w_pwin->p_inlen -= len))
2032 bcopy(p->w_pwin->p_inbuf + len, p->w_pwin->p_inbuf, p->w_pwin->p_inlen);
2036 #endif /* PSEUDOS */
2038 static void
2039 win_silenceev_fn(ev, data)
2040 struct event *ev;
2041 char *data;
2043 struct win *p = (struct win *)data;
2044 struct canvas *cv;
2045 debug1("FOUND silence win %d\n", p->w_number);
2046 for (display = displays; display; display = display->d_next)
2048 for (cv = D_cvlist; cv; cv = cv->c_next)
2049 if (cv->c_layer->l_bottom == &p->w_layer)
2050 break;
2051 if (cv)
2052 continue; /* user already sees window */
2053 #ifdef MULTIUSER
2054 if (!(ACLBYTE(p->w_lio_notify, D_user->u_id) & ACLBIT(D_user->u_id)))
2055 continue;
2056 #endif
2057 #ifdef SCRIPT
2058 if (!trigger_sevent(&p->w_sev.onsilent, p))
2059 #endif
2060 Msg(0, "Window %d: silence for %d seconds", p->w_number, p->w_silencewait);
2064 #ifdef ZMODEM
2066 static int
2067 zmodem_parse(p, bp, len)
2068 struct win *p;
2069 char *bp;
2070 int len;
2072 int i;
2073 char *b2 = bp;
2074 for (i = 0; i < len; i++, b2++)
2076 if (p->w_zauto == 0)
2078 for (; i < len; i++, b2++)
2079 if (*b2 == 030)
2080 break;
2081 if (i == len)
2082 break;
2083 if (i > 1 && b2[-1] == '*' && b2[-2] == '*')
2084 p->w_zauto = 3;
2085 continue;
2087 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'))
2089 if (++p->w_zauto < 6)
2090 continue;
2091 if (p->w_zauto == 6)
2092 p->w_zauto = 0;
2093 if (!p->w_zdisplay)
2095 if (i > 6)
2096 WriteString(p, bp, i + 1 - 6);
2097 WriteString(p, "\r\n", 2);
2098 zmodem_found(p, *b2 == '1', b2 + 1, len - i - 1);
2099 return 1;
2101 else if (p->w_zauto == 7 || *b2 == '8')
2103 int se = p->w_zdisplay->d_blocked == 2 ? 'O' : '\212';
2104 for (; i < len; i++, b2++)
2105 if (*b2 == se)
2106 break;
2107 if (i < len)
2109 zmodem_abort(p, 0);
2110 D_blocked = 0;
2111 D_readev.condpos = D_readev.condneg = 0;
2112 while (len-- > 0)
2113 AddChar(*bp++);
2114 Flush();
2115 Activate(D_fore ? D_fore->w_norefresh : 0);
2116 return 1;
2118 p->w_zauto = 6;
2121 else
2122 p->w_zauto = *b2 == '*' ? (p->w_zauto == 2 ? 2 : 1) : 0;
2124 if (p->w_zauto == 0 && bp[len - 1] == '*')
2125 p->w_zauto = len > 1 && bp[len - 2] == '*' ? 2 : 1;
2126 if (p->w_zdisplay)
2128 display = p->w_zdisplay;
2129 while (len-- > 0)
2130 AddChar(*bp++);
2131 return 1;
2133 return 0;
2136 static void
2137 zmodem_fin(buf, len, data)
2138 char *buf;
2139 int len;
2140 char *data;
2142 char *s;
2143 int n;
2145 if (len)
2146 RcLine(buf, strlen(buf) + 1);
2147 else
2149 s = "\030\030\030\030\030\030\030\030\030\030";
2150 n = strlen(s);
2151 LayProcess(&s, &n);
2155 static void
2156 zmodem_found(p, send, bp, len)
2157 struct win *p;
2158 int send;
2159 char *bp;
2160 int len;
2162 char *s;
2163 int i, n;
2164 extern int zmodem_mode;
2166 /* check for abort sequence */
2167 n = 0;
2168 for (i = 0; i < len ; i++)
2169 if (bp[i] != 030)
2170 n = 0;
2171 else if (++n > 4)
2172 return;
2173 if (zmodem_mode == 3 || (zmodem_mode == 1 && p->w_type != W_TYPE_PLAIN))
2175 struct display *d, *olddisplay;
2177 olddisplay = display;
2178 d = p->w_lastdisp;
2179 if (!d || d->d_fore != p)
2180 for (d = displays; d; d = d->d_next)
2181 if (d->d_fore == p)
2182 break;
2183 if (!d && p->w_layer.l_cvlist)
2184 d = p->w_layer.l_cvlist->c_display;
2185 if (!d)
2186 d = displays;
2187 if (!d)
2188 return;
2189 display = d;
2190 RemoveStatus();
2191 p->w_zdisplay = display;
2192 D_blocked = 2 + send;
2193 flayer = &p->w_layer;
2194 ZmodemPage();
2195 display = d;
2196 evdeq(&D_blockedev);
2197 D_readev.condpos = &const_IOSIZE;
2198 D_readev.condneg = &p->w_inlen;
2199 ClearAll();
2200 GotoPos(0, 0);
2201 SetRendition(&mchar_blank);
2202 AddStr("Zmodem active\r\n\r\n");
2203 AddStr(send ? "**\030B01" : "**\030B00");
2204 while (len-- > 0)
2205 AddChar(*bp++);
2206 display = olddisplay;
2207 return;
2209 flayer = &p->w_layer;
2210 Input(":", 100, INP_COOKED, zmodem_fin, NULL, 0);
2211 s = send ? zmodem_sendcmd : zmodem_recvcmd;
2212 n = strlen(s);
2213 LayProcess(&s, &n);
2216 void
2217 zmodem_abort(p, d)
2218 struct win *p;
2219 struct display *d;
2221 struct display *olddisplay = display;
2222 struct layer *oldflayer = flayer;
2223 if (p)
2225 if (p->w_savelayer && p->w_savelayer->l_next)
2227 if (oldflayer == p->w_savelayer)
2228 oldflayer = flayer->l_next;
2229 flayer = p->w_savelayer;
2230 ExitOverlayPage();
2232 p->w_zdisplay = 0;
2233 p->w_zauto = 0;
2234 LRefreshAll(&p->w_layer, 0);
2236 if (d)
2238 display = d;
2239 D_blocked = 0;
2240 D_readev.condpos = D_readev.condneg = 0;
2241 Activate(D_fore ? D_fore->w_norefresh : 0);
2243 display = olddisplay;
2244 flayer = oldflayer;
2247 #endif