Changelog the last few changes.
[screen-lua.git] / src / window.c
blob20bceac693a69e53f575faa820114f61b3eb6047
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, *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 *));
96 static void win_destroyev_fn __P((struct event *, char *));
98 static int OpenDevice __P((char **, int, int *, char **));
99 static int ForkWindow __P((struct win *, char **, char *));
100 #ifdef ZMODEM
101 static void zmodem_found __P((struct win *, int, char *, int));
102 static void zmodem_fin __P((char *, int, char *));
103 static int zmodem_parse __P((struct win *, char *, int));
104 #endif
107 struct win **wtab; /* window table */
109 int VerboseCreate = 0; /* XXX move this to user.h */
111 char DefaultShell[] = "/bin/sh";
112 static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
114 /* keep this in sync with the structure definition in window.h */
115 struct NewWindow nwin_undef =
117 -1, /* StartAt */
118 (char *)0, /* aka */
119 (char **)0, /* args */
120 (char *)0, /* dir */
121 (char *)0, /* term */
122 -1, /* aflag */
123 -1, /* flowflag */
124 -1, /* lflag */
125 -1, /* histheight */
126 -1, /* monitor */
127 -1, /* wlock */
128 -1, /* silence */
129 -1, /* wrap */
130 -1, /* logging */
131 -1, /* slowpaste */
132 -1, /* gr */
133 -1, /* c1 */
134 -1, /* bce */
135 -1, /* encoding */
136 (char *)0, /* hstatus */
137 (char *)0 /* charset */
140 struct NewWindow nwin_default =
142 0, /* StartAt */
143 0, /* aka */
144 ShellArgs, /* args */
145 0, /* dir */
146 screenterm, /* term */
147 0, /* aflag */
148 1*FLOW_NOW, /* flowflag */
149 LOGINDEFAULT, /* lflag */
150 DEFAULTHISTHEIGHT, /* histheight */
151 MON_OFF, /* monitor */
152 WLOCK_OFF, /* wlock */
153 0, /* silence */
154 1, /* wrap */
155 0, /* logging */
156 0, /* slowpaste */
157 0, /* gr */
158 1, /* c1 */
159 0, /* bce */
160 0, /* encoding */
161 (char *)0, /* hstatus */
162 (char *)0 /* charset */
165 struct NewWindow nwin_options;
167 static int const_IOSIZE = IOSIZE;
168 static int const_one = 1;
170 void
171 nwin_compose(def, new, res)
172 struct NewWindow *def, *new, *res;
174 #define COMPOSE(x) res->x = new->x != nwin_undef.x ? new->x : def->x
175 COMPOSE(StartAt);
176 COMPOSE(aka);
177 COMPOSE(args);
178 COMPOSE(dir);
179 COMPOSE(term);
180 COMPOSE(aflag);
181 COMPOSE(flowflag);
182 COMPOSE(lflag);
183 COMPOSE(histheight);
184 COMPOSE(monitor);
185 COMPOSE(wlock);
186 COMPOSE(silence);
187 COMPOSE(wrap);
188 COMPOSE(Lflag);
189 COMPOSE(slow);
190 COMPOSE(gr);
191 COMPOSE(c1);
192 COMPOSE(bce);
193 COMPOSE(encoding);
194 COMPOSE(hstatus);
195 COMPOSE(charset);
196 #undef COMPOSE
199 /*****************************************************************
201 * The window layer functions
204 struct LayFuncs WinLf =
206 WinProcess,
208 WinRedisplayLine,
209 WinClearLine,
210 WinRewrite,
211 WinResize,
212 WinRestore
215 static int
216 DoAutolf(buf, lenp, fr)
217 char *buf;
218 int *lenp;
219 int fr;
221 char *p;
222 int len = *lenp;
223 int trunc = 0;
225 for (p = buf; len > 0; p++, len--)
227 if (*p != '\r')
228 continue;
229 if (fr-- <= 0)
231 trunc++;
232 len--;
234 if (len == 0)
235 break;
236 bcopy(p, p + 1, len++);
237 p[1] = '\n';
239 *lenp = p - buf;
240 return trunc;
243 static void
244 WinProcess(bufpp, lenp)
245 char **bufpp;
246 int *lenp;
248 int l2 = 0, f, *ilen, l = *lenp, trunc;
249 char *ibuf;
251 debug1("WinProcess: %d bytes\n", *lenp);
252 fore = (struct win *)flayer->l_data;
254 if (fore->w_type == W_TYPE_GROUP)
256 *bufpp += *lenp;
257 *lenp = 0;
258 return;
260 if (fore->w_ptyfd < 0) /* zombie? */
262 ZombieProcess(bufpp, lenp);
263 return;
265 #ifdef MULTIUSER
266 /* a pending writelock is this:
267 * fore->w_wlock == WLOCK_AUTO, fore->w_wlockuse = NULL
268 * The user who wants to use this window next, will get the lock, if he can.
270 if (display && fore->w_wlock == WLOCK_AUTO &&
271 !fore->w_wlockuser && !AclCheckPermWin(D_user, ACL_WRITE, fore))
273 fore->w_wlockuser = D_user;
274 debug2("window %d: pending writelock grabbed by user %s\n",
275 fore->w_number, fore->w_wlockuser->u_name);
277 /* if w_wlock is set, only one user may write, else we check acls */
278 if (display && ((fore->w_wlock == WLOCK_OFF) ?
279 AclCheckPermWin(D_user, ACL_WRITE, fore) :
280 (D_user != fore->w_wlockuser)))
282 debug2("window %d, user %s: ", fore->w_number, D_user->u_name);
283 debug2("writelock %d (wlockuser %s)\n", fore->w_wlock,
284 fore->w_wlockuser ? fore->w_wlockuser->u_name : "NULL");
285 Msg(0, "write: permission denied (user %s)", D_user->u_name);
286 *bufpp += *lenp;
287 *lenp = 0;
288 return;
290 #endif /* MULTIUSER */
292 #ifdef BUILTIN_TELNET
293 if (fore->w_type == W_TYPE_TELNET && TelIsline(fore) && *bufpp != fore->w_telbuf)
295 TelProcessLine(bufpp, lenp);
296 return;
298 #endif
300 #ifdef PSEUDOS
301 if (W_UWP(fore))
303 /* we send the user input to our pseudowin */
304 ibuf = fore->w_pwin->p_inbuf; ilen = &fore->w_pwin->p_inlen;
305 f = sizeof(fore->w_pwin->p_inbuf) - *ilen;
307 else
308 #endif /* PSEUDOS */
310 /* we send the user input to the window */
311 ibuf = fore->w_inbuf; ilen = &fore->w_inlen;
312 f = sizeof(fore->w_inbuf) - *ilen;
315 if (l > f)
316 l = f;
317 #ifdef BUILTIN_TELNET
318 while (l > 0)
319 #else
320 if (l > 0)
321 #endif
323 l2 = l;
324 bcopy(*bufpp, ibuf + *ilen, l2);
325 if (fore->w_autolf && (trunc = DoAutolf(ibuf + *ilen, &l2, f - l2)))
326 l -= trunc;
327 #ifdef BUILTIN_TELNET
328 if (fore->w_type == W_TYPE_TELNET && (trunc = DoTelnet(ibuf + *ilen, &l2, f - l2)))
330 l -= trunc;
331 if (fore->w_autolf)
332 continue; /* need exact value */
334 #endif
335 *ilen += l2;
336 *bufpp += l;
337 *lenp -= l;
338 return;
342 static void
343 ZombieProcess(bufpp, lenp)
344 char **bufpp;
345 int *lenp;
347 int l = *lenp;
348 char *buf = *bufpp, b1[10], b2[10];
350 debug1("ZombieProcess: %d bytes\n", *lenp);
351 fore = (struct win *)flayer->l_data;
353 ASSERT(fore->w_ptyfd < 0);
354 *bufpp += *lenp;
355 *lenp = 0;
356 for (; l-- > 0; buf++)
358 if (*(unsigned char *)buf == ZombieKey_destroy)
360 debug1("Turning undead: %d\n", fore->w_number);
361 KillWindow(fore);
362 return;
364 if (*(unsigned char *)buf == ZombieKey_resurrect)
366 debug1("Resurrecting Zombie: %d\n", fore->w_number);
367 WriteString(fore, "\r\n", 2);
368 RemakeWindow(fore);
369 return;
372 b1[AddXChar(b1, ZombieKey_destroy)] = '\0';
373 b2[AddXChar(b2, ZombieKey_resurrect)] = '\0';
374 Msg(0, "Press %s to destroy or %s to resurrect window", b1, b2);
377 static void
378 WinRedisplayLine(y, from, to, isblank)
379 int y, from, to, isblank;
381 debug3("WinRedisplayLine %d %d %d\n", y, from, to);
382 if (y < 0)
383 return;
384 fore = (struct win *)flayer->l_data;
385 if (from == 0 && y > 0 && fore->w_mlines[y - 1].image[fore->w_width] == 0)
386 LCDisplayLineWrap(&fore->w_layer, &fore->w_mlines[y], y, from, to, isblank);
387 else
388 LCDisplayLine(&fore->w_layer, &fore->w_mlines[y], y, from, to, isblank);
391 static int
392 WinRewrite(y, x1, x2, rend, doit)
393 int y, x1, x2, doit;
394 struct mchar *rend;
396 register int cost, dx;
397 register unsigned char *p, *i;
398 #ifdef FONT
399 register unsigned char *f;
400 #endif
401 #ifdef COLOR
402 register unsigned char *c;
403 # ifdef COLORS256
404 register unsigned char *cx;
405 # endif
406 #endif
408 debug3("WinRewrite %d, %d-%d\n", y, x1, x2);
409 fore = (struct win *)flayer->l_data;
410 dx = x2 - x1 + 1;
411 if (doit)
413 i = fore->w_mlines[y].image + x1;
414 while (dx-- > 0)
415 PUTCHAR(*i++);
416 return 0;
418 p = fore->w_mlines[y].attr + x1;
419 #ifdef FONT
420 f = fore->w_mlines[y].font + x1;
421 # ifdef DW_CHARS
422 if (is_dw_font(rend->font))
423 return EXPENSIVE;
424 # endif
425 # ifdef UTF8
426 if (fore->w_encoding && fore->w_encoding != UTF8 && D_encoding == UTF8 && ContainsSpecialDeffont(fore->w_mlines + y, x1, x2, fore->w_encoding))
427 return EXPENSIVE;
428 # endif
429 #endif
430 #ifdef COLOR
431 c = fore->w_mlines[y].color + x1;
432 # ifdef COLORS256
433 cx = fore->w_mlines[y].colorx + x1;
434 # endif
435 #endif
437 cost = dx = x2 - x1 + 1;
438 while(dx-- > 0)
440 if (*p++ != rend->attr)
441 return EXPENSIVE;
442 #ifdef FONT
443 if (*f++ != rend->font)
444 return EXPENSIVE;
445 #endif
446 #ifdef COLOR
447 if (*c++ != rend->color)
448 return EXPENSIVE;
449 # ifdef COLORS256
450 if (*cx++ != rend->colorx)
451 return EXPENSIVE;
452 # endif
453 #endif
455 return cost;
458 static void
459 WinClearLine(y, xs, xe, bce)
460 int y, xs, xe, bce;
462 fore = (struct win *)flayer->l_data;
463 debug3("WinClearLine %d %d-%d\n", y, xs, xe);
464 LClearLine(flayer, y, xs, xe, bce, &fore->w_mlines[y]);
467 static int
468 WinResize(wi, he)
469 int wi, he;
471 fore = (struct win *)flayer->l_data;
472 ChangeWindowSize(fore, wi, he, fore->w_histheight);
473 return 0;
476 static void
477 WinRestore()
479 struct canvas *cv;
480 fore = (struct win *)flayer->l_data;
481 debug1("WinRestore: win %p\n", fore);
482 for (cv = flayer->l_cvlist; cv; cv = cv->c_next)
484 display = cv->c_display;
485 if (cv != D_forecv)
486 continue;
487 /* ChangeScrollRegion(fore->w_top, fore->w_bot); */
488 KeypadMode(fore->w_keypad);
489 CursorkeysMode(fore->w_cursorkeys);
490 SetFlow(fore->w_flow & FLOW_NOW);
491 InsertMode(fore->w_insert);
492 ReverseVideo(fore->w_revvid);
493 CursorVisibility(fore->w_curinv ? -1 : fore->w_curvvis);
494 MouseMode(fore->w_mouse);
498 /*****************************************************************/
502 * DoStartLog constructs a path for the "want to be logfile" in buf and
503 * attempts logfopen.
505 * returns 0 on success.
508 DoStartLog(w, buf, bufsize)
509 struct win *w;
510 char *buf;
511 int bufsize;
513 int n;
514 if (!w || !buf)
515 return -1;
517 strncpy(buf, MakeWinMsg(screenlogfile, w, '%'), bufsize - 1);
518 buf[bufsize - 1] = 0;
520 debug2("DoStartLog: win %d, file %s\n", w->w_number, buf);
522 if (w->w_log != NULL)
523 logfclose(w->w_log);
525 if ((w->w_log = logfopen(buf, islogfile(buf) ? NULL : secfopen(buf, "a"))) == NULL)
526 return -2;
527 if (!logflushev.queued)
529 n = log_flush ? log_flush : (logtstamp_after + 4) / 5;
530 if (n)
532 SetTimeout(&logflushev, n * 1000);
533 evenq(&logflushev);
536 return 0;
540 * Umask & wlock are set for the user of the display,
541 * The display d (if specified) switches to that window.
544 MakeWindow(newwin)
545 struct NewWindow *newwin;
547 register struct win **pp, *p;
548 register int n, i;
549 int f = -1;
550 struct NewWindow nwin;
551 int type, startat;
552 char *TtyName;
553 #ifdef MULTIUSER
554 extern struct acluser *users;
555 #endif
557 if (!wtab)
559 if (!maxwin)
560 maxwin = MAXWIN;
561 wtab = calloc(maxwin, sizeof(struct win *));
564 debug1("NewWindow: StartAt %d\n", newwin->StartAt);
565 debug1("NewWindow: aka %s\n", newwin->aka?newwin->aka:"NULL");
566 debug1("NewWindow: dir %s\n", newwin->dir?newwin->dir:"NULL");
567 debug1("NewWindow: term %s\n", newwin->term?newwin->term:"NULL");
569 nwin_compose(&nwin_default, newwin, &nwin);
570 debug1("NWin: aka %s\n", nwin.aka ? nwin.aka : "NULL");
571 debug1("NWin: wlock %d\n", nwin.wlock);
572 debug1("NWin: Lflag %d\n", nwin.Lflag);
574 startat = nwin.StartAt < maxwin ? nwin.StartAt : 0;
575 pp = wtab + startat;
579 if (*pp == 0)
580 break;
581 if (++pp == wtab + maxwin)
582 pp = wtab;
584 while (pp != wtab + startat);
585 if (*pp)
587 Msg(0, "No more windows.");
588 return -1;
591 #if defined(USRLIMIT) && defined(UTMPOK)
593 * Count current number of users, if logging windows in.
595 if (nwin.lflag && CountUsers() >= USRLIMIT)
597 Msg(0, "User limit reached. Window will not be logged in.");
598 nwin.lflag = 0;
600 #endif
601 n = pp - wtab;
602 debug1("Makewin creating %d\n", n);
604 if ((f = OpenDevice(nwin.args, nwin.lflag, &type, &TtyName)) < 0)
605 return -1;
606 if (type == W_TYPE_GROUP)
607 f = -1;
609 if ((p = (struct win *)calloc(1, sizeof(struct win))) == 0)
611 close(f);
612 Msg(0, strnomem);
613 return -1;
616 #ifdef UTMPOK
617 if (type != W_TYPE_PTY)
618 nwin.lflag = 0;
619 #endif
621 p->w_type = type;
623 /* save the command line so that zombies can be resurrected */
624 for (i = 0; nwin.args[i] && i < MAXARGS - 1; i++)
625 p->w_cmdargs[i] = SaveStr(nwin.args[i]);
626 p->w_cmdargs[i] = 0;
627 if (nwin.dir)
628 p->w_dir = SaveStr(nwin.dir);
629 if (nwin.term)
630 p->w_term = SaveStr(nwin.term);
632 p->w_number = n;
633 p->w_group = 0;
634 if (fore && fore->w_type == W_TYPE_GROUP)
635 p->w_group = fore;
636 else if (fore && fore->w_group)
637 p->w_group = fore->w_group;
638 #ifdef MULTIUSER
640 * This is dangerous: without a display we use creators umask
641 * This is intended to be usefull for detached startup.
642 * But is still better than default bits with a NULL user.
644 if (NewWindowAcl(p, display ? D_user : users))
646 free((char *)p);
647 close(f);
648 Msg(0, strnomem);
649 return -1;
651 #endif
652 p->w_layer.l_next = 0;
653 p->w_layer.l_bottom = &p->w_layer;
654 p->w_layer.l_layfn = &WinLf;
655 p->w_layer.l_data = (char *)p;
656 p->w_savelayer = &p->w_layer;
657 p->w_pdisplay = 0;
658 p->w_lastdisp = 0;
660 #ifdef MULTIUSER
661 if (display && !AclCheckPermWin(D_user, ACL_WRITE, p))
662 p->w_wlockuser = D_user;
663 p->w_wlock = nwin.wlock;
664 #endif
665 p->w_ptyfd = f;
666 p->w_aflag = nwin.aflag;
667 p->w_flow = nwin.flowflag | ((nwin.flowflag & FLOW_AUTOFLAG) ? (FLOW_AUTO|FLOW_NOW) : FLOW_AUTO);
668 if (!nwin.aka)
669 nwin.aka = Filename(nwin.args[0]);
670 strncpy(p->w_akabuf, nwin.aka, sizeof(p->w_akabuf) - 1);
671 if ((nwin.aka = rindex(p->w_akabuf, '|')) != NULL)
673 p->w_autoaka = 0;
674 *nwin.aka++ = 0;
675 p->w_title = nwin.aka;
676 p->w_akachange = nwin.aka + strlen(nwin.aka);
678 else
679 p->w_title = p->w_akachange = p->w_akabuf;
680 if (nwin.hstatus)
681 p->w_hstatus = SaveStr(nwin.hstatus);
682 p->w_monitor = nwin.monitor;
683 #ifdef MULTIUSER
684 if (p->w_monitor == MON_ON)
686 /* always tell all users */
687 for (i = 0; i < maxusercount; i++)
688 ACLBYTE(p->w_mon_notify, i) |= ACLBIT(i);
690 #endif
692 * defsilence by Lloyd Zusman (zusman_lloyd@jpmorgan.com)
694 p->w_silence = nwin.silence;
695 p->w_silencewait = SilenceWait;
696 #ifdef MULTIUSER
697 if (p->w_silence == SILENCE_ON)
699 /* always tell all users */
700 for (i = 0; i < maxusercount; i++)
701 ACLBYTE(p->w_lio_notify, i) |= ACLBIT(i);
703 #endif
704 #ifdef COPY_PASTE
705 p->w_slowpaste = nwin.slow;
706 #else
707 nwin.histheight = 0;
708 #endif
710 p->w_norefresh = 0;
711 strncpy(p->w_tty, TtyName, MAXSTR - 1);
713 #if 0
714 /* XXX Fixme display resize */
715 if (ChangeWindowSize(p, display ? D_defwidth : 80,
716 display ? D_defheight : 24,
717 nwin.histheight))
719 FreeWindow(p);
720 return -1;
722 #else
723 if (ChangeWindowSize(p, display ? D_forecv->c_xe - D_forecv->c_xs + 1: 80,
724 display ? D_forecv->c_ye - D_forecv->c_ys + 1 : 24,
725 nwin.histheight))
727 FreeWindow(p);
728 return -1;
730 #endif
732 p->w_encoding = nwin.encoding;
733 ResetWindow(p); /* sets w_wrap, w_c1, w_gr, w_bce */
735 #ifdef FONT
736 if (nwin.charset)
737 SetCharsets(p, nwin.charset);
738 #endif
740 if (VerboseCreate && type != W_TYPE_GROUP)
742 struct display *d = display; /* WriteString zaps display */
744 WriteString(p, ":screen (", 9);
745 WriteString(p, p->w_title, strlen(p->w_title));
746 WriteString(p, "):", 2);
747 for (f = 0; p->w_cmdargs[f]; f++)
749 WriteString(p, " ", 1);
750 WriteString(p, p->w_cmdargs[f], strlen(p->w_cmdargs[f]));
752 WriteString(p, "\r\n", 2);
753 display = d;
756 p->w_deadpid = 0;
757 p->w_pid = 0;
758 #ifdef PSEUDOS
759 p->w_pwin = 0;
760 #endif
762 #ifdef BUILTIN_TELNET
763 if (type == W_TYPE_TELNET)
765 if (TelConnect(p))
767 FreeWindow(p);
768 return -1;
771 else
772 #endif
773 if (type == W_TYPE_PTY)
775 p->w_pid = ForkWindow(p, nwin.args, TtyName);
776 if (p->w_pid < 0)
778 FreeWindow(p);
779 return -1;
784 * Place the new window at the head of the most-recently-used list.
786 if (display && D_fore)
787 D_other = D_fore;
788 *pp = p;
789 p->w_next = windows;
790 windows = p;
792 if (type == W_TYPE_GROUP)
794 SetForeWindow(p);
795 Activate(p->w_norefresh);
796 WindowChanged((struct win*)0, 'w');
797 WindowChanged((struct win*)0, 'W');
798 WindowChanged((struct win*)0, 0);
799 return n;
802 p->w_lflag = nwin.lflag;
803 #ifdef UTMPOK
804 p->w_slot = (slot_t)-1;
805 # ifdef LOGOUTOK
806 debug1("MakeWindow will %slog in.\n", nwin.lflag?"":"not ");
807 if (nwin.lflag & 1)
808 # else /* LOGOUTOK */
809 debug1("MakeWindow will log in, LOGOUTOK undefined in config.h%s.\n",
810 nwin.lflag?"":" (although lflag=0)");
811 # endif /* LOGOUTOK */
813 p->w_slot = (slot_t)0;
814 if (display || (p->w_lflag & 2))
815 SetUtmp(p);
817 # ifdef CAREFULUTMP
818 CarefulUtmp(); /* If all 've been zombies, we've had no slot */
819 # endif
820 #endif /* UTMPOK */
822 if (nwin.Lflag)
824 char buf[1024];
825 DoStartLog(p, buf, sizeof(buf));
828 p->w_readev.fd = p->w_writeev.fd = p->w_ptyfd;
829 p->w_readev.type = EV_READ;
830 p->w_writeev.type = EV_WRITE;
831 p->w_readev.data = p->w_writeev.data = (char *)p;
832 p->w_readev.handler = win_readev_fn;
833 p->w_writeev.handler = win_writeev_fn;
834 p->w_writeev.condpos = &p->w_inlen;
835 evenq(&p->w_readev);
836 evenq(&p->w_writeev);
837 #ifdef COPY_PASTE
838 p->w_paster.pa_slowev.type = EV_TIMEOUT;
839 p->w_paster.pa_slowev.data = (char *)&p->w_paster;
840 p->w_paster.pa_slowev.handler = paste_slowev_fn;
841 #endif
842 p->w_silenceev.type = EV_TIMEOUT;
843 p->w_silenceev.data = (char *)p;
844 p->w_silenceev.handler = win_silenceev_fn;
845 if (p->w_silence > 0)
847 debug("New window has silence enabled.\n");
848 SetTimeout(&p->w_silenceev, p->w_silencewait * 1000);
849 evenq(&p->w_silenceev);
851 p->w_destroyev.type = EV_TIMEOUT;
852 p->w_destroyev.data = 0;
853 p->w_destroyev.handler = win_destroyev_fn;
855 SetForeWindow(p);
856 Activate(p->w_norefresh);
857 WindowChanged((struct win*)0, 'w');
858 WindowChanged((struct win*)0, 'W');
859 WindowChanged((struct win*)0, 0);
860 return n;
864 * Resurrect a window from Zombie state.
865 * The command vector is therefore stored in the window structure.
866 * Note: The terminaltype defaults to screenterm again, the current
867 * working directory is lost.
870 RemakeWindow(p)
871 struct win *p;
873 char *TtyName;
874 int lflag, f;
876 lflag = nwin_default.lflag;
877 if ((f = OpenDevice(p->w_cmdargs, lflag, &p->w_type, &TtyName)) < 0)
878 return -1;
880 strncpy(p->w_tty, *TtyName ? TtyName : p->w_title, MAXSTR - 1);
881 p->w_ptyfd = f;
882 p->w_readev.fd = f;
883 p->w_writeev.fd = f;
884 evenq(&p->w_readev);
885 evenq(&p->w_writeev);
887 if (VerboseCreate)
889 struct display *d = display; /* WriteString zaps display */
891 WriteString(p, ":screen (", 9);
892 WriteString(p, p->w_title, strlen(p->w_title));
893 WriteString(p, "):", 2);
894 for (f = 0; p->w_cmdargs[f]; f++)
896 WriteString(p, " ", 1);
897 WriteString(p, p->w_cmdargs[f], strlen(p->w_cmdargs[f]));
899 WriteString(p, "\r\n", 2);
900 display = d;
903 p->w_deadpid = 0;
904 p->w_pid = 0;
905 #ifdef BUILTIN_TELNET
906 if (p->w_type == W_TYPE_TELNET)
908 if (TelConnect(p))
909 return -1;
911 else
912 #endif
913 if (p->w_type == W_TYPE_PTY)
915 p->w_pid = ForkWindow(p, p->w_cmdargs, TtyName);
916 if (p->w_pid < 0)
917 return -1;
920 #ifdef UTMPOK
921 if (p->w_slot == (slot_t)0 && (display || (p->w_lflag & 2)))
922 SetUtmp(p);
923 # ifdef CAREFULUTMP
924 CarefulUtmp(); /* If all 've been zombies, we've had no slot */
925 # endif
926 #endif
927 WindowChanged(p, 'f');
928 return p->w_number;
931 void
932 CloseDevice(wp)
933 struct win *wp;
935 if (wp->w_ptyfd < 0)
936 return;
937 if (wp->w_type == W_TYPE_PTY)
939 /* pty 4 SALE */
940 (void)chmod(wp->w_tty, 0666);
941 (void)chown(wp->w_tty, 0, 0);
943 close(wp->w_ptyfd);
944 wp->w_ptyfd = -1;
945 wp->w_tty[0] = 0;
946 evdeq(&wp->w_readev);
947 evdeq(&wp->w_writeev);
948 #ifdef BUILTIN_TELNET
949 evdeq(&wp->w_telconnev);
950 #endif
951 wp->w_readev.fd = wp->w_writeev.fd = -1;
954 void
955 FreeWindow(wp)
956 struct win *wp;
958 struct display *d;
959 int i;
960 struct canvas *cv, *ncv;
961 struct layer *l;
963 debug1("FreeWindow %d\n", wp ? wp->w_number: -1);
964 #ifdef PSEUDOS
965 if (wp->w_pwin)
966 FreePseudowin(wp);
967 #endif
968 #ifdef UTMPOK
969 RemoveUtmp(wp);
970 #endif
971 CloseDevice(wp);
973 if (wp == console_window)
975 TtyGrabConsole(-1, -1, "free");
976 console_window = 0;
978 if (wp->w_log != NULL)
979 logfclose(wp->w_log);
980 ChangeWindowSize(wp, 0, 0, 0);
982 if (wp->w_type == W_TYPE_GROUP)
984 struct win *win;
985 for (win = windows; win; win = win->w_next)
986 if (win->w_group == wp)
987 win->w_group = wp->w_group;
990 if (wp->w_hstatus)
991 free(wp->w_hstatus);
992 for (i = 0; wp->w_cmdargs[i]; i++)
993 free(wp->w_cmdargs[i]);
994 if (wp->w_dir)
995 free(wp->w_dir);
996 if (wp->w_term)
997 free(wp->w_term);
998 for (d = displays; d; d = d->d_next)
1000 if (d->d_other == wp)
1001 d->d_other = d->d_fore && d->d_fore->w_next != wp ? d->d_fore->w_next : wp->w_next;
1002 if (d->d_fore == wp)
1003 d->d_fore = NULL;
1004 for (cv = d->d_cvlist; cv; cv = cv->c_next)
1006 for (l = cv->c_layer; l; l = l->l_next)
1007 if (l->l_layfn == &WinLf)
1008 break;
1009 if (!l)
1010 continue;
1011 if ((struct win *)l->l_data != wp)
1012 continue;
1013 if (cv->c_layer == wp->w_savelayer)
1014 wp->w_savelayer = 0;
1015 KillLayerChain(cv->c_layer);
1018 if (wp->w_savelayer)
1019 KillLayerChain(wp->w_savelayer);
1020 for (cv = wp->w_layer.l_cvlist; cv; cv = ncv)
1022 ncv = cv->c_lnext;
1023 cv->c_layer = &cv->c_blank;
1024 cv->c_blank.l_cvlist = cv;
1025 cv->c_lnext = 0;
1026 cv->c_xoff = cv->c_xs;
1027 cv->c_yoff = cv->c_ys;
1028 RethinkViewportOffsets(cv);
1030 wp->w_layer.l_cvlist = 0;
1031 if (flayer == &wp->w_layer)
1032 flayer = 0;
1033 LayerCleanupMemory(&wp->w_layer);
1035 #ifdef MULTIUSER
1036 FreeWindowAcl(wp);
1037 #endif /* MULTIUSER */
1038 evdeq(&wp->w_readev); /* just in case */
1039 evdeq(&wp->w_writeev); /* just in case */
1040 evdeq(&wp->w_silenceev);
1041 evdeq(&wp->w_destroyev);
1042 #ifdef COPY_PASTE
1043 FreePaster(&wp->w_paster);
1044 #endif
1045 free((char *)wp);
1048 static int
1049 OpenDevice(args, lflag, typep, namep)
1050 char **args;
1051 int lflag;
1052 int *typep;
1053 char **namep;
1055 char *arg = args[0];
1056 struct stat st;
1057 int f;
1059 if (!arg)
1060 return -1;
1061 if (strcmp(arg, "//group") == 0)
1063 *typep = W_TYPE_GROUP;
1064 *namep = "telnet";
1065 return 0;
1067 #ifdef BUILTIN_TELNET
1068 if (strcmp(arg, "//telnet") == 0)
1070 f = TelOpen(args + 1);
1071 lflag = 0;
1072 *typep = W_TYPE_TELNET;
1073 *namep = "telnet";
1075 else
1076 #endif
1077 if (strncmp(arg, "//", 2) == 0)
1079 Msg(0, "Invalid argument '%s'", arg);
1080 return -1;
1082 else if ((stat(arg, &st)) == 0 && S_ISCHR(st.st_mode))
1084 if (access(arg, R_OK | W_OK) == -1)
1086 Msg(errno, "Cannot access line '%s' for R/W", arg);
1087 return -1;
1089 debug("OpenDevice: OpenTTY\n");
1090 if ((f = OpenTTY(arg, args[1])) < 0)
1091 return -1;
1092 lflag = 0;
1093 *typep = W_TYPE_PLAIN;
1094 *namep = arg;
1096 else
1098 *typep = W_TYPE_PTY;
1099 f = OpenPTY(namep);
1100 if (f == -1)
1102 Msg(0, "No more PTYs.");
1103 return -1;
1105 #ifdef TIOCPKT
1107 int flag = 1;
1108 if (ioctl(f, TIOCPKT, (char *)&flag))
1110 Msg(errno, "TIOCPKT ioctl");
1111 close(f);
1112 return -1;
1115 #endif /* TIOCPKT */
1117 debug1("fcntl(%d, F_SETFL, FNBLOCK)\n", f);
1118 (void) fcntl(f, F_SETFL, FNBLOCK);
1119 #ifdef linux
1121 * Tenebreux (zeus@ns.acadiacom.net) has Linux 1.3.70 where select
1122 * gets confused in the following condition:
1123 * Open a pty-master side, request a flush on it, then set packet
1124 * mode and call select(). Select will return a possible read, where
1125 * the one byte response to the flush can be found. Select will
1126 * thereafter return a possible read, which yields I/O error.
1128 * If we request another flush *after* switching into packet mode,
1129 * this I/O error does not occur. We receive a single response byte
1130 * although we send two flush requests now.
1132 * Maybe we should not flush at all.
1134 * 10.5.96 jw.
1136 if (*typep == W_TYPE_PTY || *typep == W_TYPE_PLAIN)
1137 tcflush(f, TCIOFLUSH);
1138 #endif
1140 if (*typep != W_TYPE_PTY)
1141 return f;
1143 #ifndef PTYROFS
1144 #ifdef PTYGROUP
1145 if (chown(*namep, real_uid, PTYGROUP) && !eff_uid)
1146 #else
1147 if (chown(*namep, real_uid, real_gid) && !eff_uid)
1148 #endif
1150 Msg(errno, "chown tty");
1151 close(f);
1152 return -1;
1154 #ifdef UTMPOK
1155 if (chmod(*namep, lflag ? TtyMode : (TtyMode & ~022)) && !eff_uid)
1156 #else
1157 if (chmod(*namep, TtyMode) && !eff_uid)
1158 #endif
1160 Msg(errno, "chmod tty");
1161 close(f);
1162 return -1;
1164 #endif
1165 return f;
1169 * Fields w_width, w_height, aflag, number (and w_tty)
1170 * are read from struct win *win. No fields written.
1171 * If pwin is nonzero, filedescriptors are distributed
1172 * between win->w_tty and open(ttyn)
1175 static int
1176 ForkWindow(win, args, ttyn)
1177 struct win *win;
1178 char **args, *ttyn;
1180 int pid;
1181 char tebuf[25];
1182 char ebuf[20];
1183 char shellbuf[7 + MAXPATHLEN];
1184 char *proc;
1185 #ifndef TIOCSWINSZ
1186 char libuf[20], cobuf[20];
1187 #endif
1188 int newfd;
1189 int w = win->w_width;
1190 int h = win->w_height;
1191 #ifdef PSEUDOS
1192 int i, pat, wfdused;
1193 struct pseudowin *pwin = win->w_pwin;
1194 #endif
1195 int slave = -1;
1197 #ifdef O_NOCTTY
1198 if (pty_preopen)
1200 debug("pre-opening slave...\n");
1201 if ((slave = open(ttyn, O_RDWR|O_NOCTTY)) == -1)
1203 Msg(errno, "ttyn");
1204 return -1;
1207 #endif
1208 debug("forking...\n");
1209 proc = *args;
1210 if (proc == 0)
1212 args = ShellArgs;
1213 proc = *args;
1215 fflush(stdout);
1216 fflush(stderr);
1217 switch (pid = fork())
1219 case -1:
1220 Msg(errno, "fork");
1221 break;
1222 case 0:
1223 signal(SIGHUP, SIG_DFL);
1224 signal(SIGINT, SIG_DFL);
1225 signal(SIGQUIT, SIG_DFL);
1226 signal(SIGTERM, SIG_DFL);
1227 #ifdef BSDJOBS
1228 signal(SIGTTIN, SIG_DFL);
1229 signal(SIGTTOU, SIG_DFL);
1230 #endif
1231 #ifdef SIGPIPE
1232 signal(SIGPIPE, SIG_DFL);
1233 #endif
1234 #ifdef SIGXFSZ
1235 signal(SIGXFSZ, SIG_DFL);
1236 #endif
1238 displays = 0; /* beware of Panic() */
1239 if (setgid(real_gid) || setuid(real_uid))
1240 Panic(errno, "Setuid/gid");
1241 eff_uid = real_uid;
1242 eff_gid = real_gid;
1243 #ifdef PSEUDOS
1244 if (!pwin) /* ignore directory if pseudo */
1245 #endif
1246 if (win->w_dir && *win->w_dir && chdir(win->w_dir))
1247 Panic(errno, "Cannot chdir to %s", win->w_dir);
1249 if (display)
1251 brktty(D_userfd);
1252 freetty();
1254 else
1255 brktty(-1);
1256 #ifdef DEBUG
1257 if (dfp && dfp != stderr)
1258 fclose(dfp);
1259 #endif
1260 if (slave != -1)
1262 close(0);
1263 dup(slave);
1264 close(slave);
1265 closeallfiles(win->w_ptyfd);
1266 slave = dup(0);
1268 else
1269 closeallfiles(win->w_ptyfd);
1270 #ifdef DEBUG
1271 if (dfp) /* do not produce child debug, when debug is "off" */
1273 char buf[256];
1275 sprintf(buf, "%s/screen.child", DEBUGDIR);
1276 if ((dfp = fopen(buf, "a")) == 0)
1277 dfp = stderr;
1278 else
1279 (void) chmod(buf, 0666);
1281 debug1("=== ForkWindow: pid %d\n", (int)getpid());
1282 #endif
1283 /* Close the three /dev/null descriptors */
1284 close(0);
1285 close(1);
1286 close(2);
1287 newfd = -1;
1289 * distribute filedescriptors between the ttys
1291 #ifdef PSEUDOS
1292 pat = pwin ? pwin->p_fdpat :
1293 ((F_PFRONT<<(F_PSHIFT*2)) | (F_PFRONT<<F_PSHIFT) | F_PFRONT);
1294 debug1("Using window pattern 0x%x\n", pat);
1295 wfdused = 0;
1296 for(i = 0; i < 3; i++)
1298 if (pat & F_PFRONT << F_PSHIFT * i)
1300 if (newfd < 0)
1302 # ifdef O_NOCTTY
1303 if (separate_sids)
1304 newfd = open(ttyn, O_RDWR);
1305 else
1306 newfd = open(ttyn, O_RDWR|O_NOCTTY);
1307 # else
1308 newfd = open(ttyn, O_RDWR);
1309 # endif
1310 if (newfd < 0)
1311 Panic(errno, "Cannot open %s", ttyn);
1313 else
1314 dup(newfd);
1316 else
1318 dup(win->w_ptyfd);
1319 wfdused = 1;
1322 if (wfdused)
1325 * the pseudo window process should not be surprised with a
1326 * nonblocking filedescriptor. Poor Backend!
1328 debug1("Clearing NBLOCK on window-fd(%d)\n", win->w_ptyfd);
1329 if (fcntl(win->w_ptyfd, F_SETFL, 0))
1330 Msg(errno, "Warning: clear NBLOCK fcntl failed");
1332 #else /* PSEUDOS */
1333 # ifdef O_NOCTTY
1334 if (separate_sids)
1335 newfd = open(ttyn, O_RDWR);
1336 else
1337 newfd = open(ttyn, O_RDWR|O_NOCTTY);
1338 # else
1339 newfd = open(ttyn, O_RDWR);
1340 # endif
1341 if (newfd != 0)
1342 Panic(errno, "Cannot open %s", ttyn);
1343 dup(0);
1344 dup(0);
1345 #endif /* PSEUDOS */
1346 close(win->w_ptyfd);
1347 if (slave != -1)
1348 close(slave);
1349 if (newfd >= 0)
1351 struct mode fakemode, *modep;
1352 InitPTY(newfd);
1353 if (fgtty(newfd))
1354 Msg(errno, "fgtty");
1355 if (display)
1357 debug("ForkWindow: using display tty mode for new child.\n");
1358 modep = &D_OldMode;
1360 else
1362 debug("No display - creating tty setting\n");
1363 modep = &fakemode;
1364 InitTTY(modep, 0);
1365 #ifdef DEBUG
1366 DebugTTY(modep);
1367 #endif
1369 /* We only want echo if the users input goes to the pseudo
1370 * and the pseudo's stdout is not send to the window.
1372 #ifdef PSEUDOS
1373 if (pwin && (!(pat & F_UWP) || (pat & F_PBACK << F_PSHIFT)))
1375 debug1("clearing echo on pseudywin fd (pat %x)\n", pat);
1376 # if defined(POSIX) || defined(TERMIO)
1377 modep->tio.c_lflag &= ~ECHO;
1378 modep->tio.c_iflag &= ~ICRNL;
1379 # else
1380 modep->m_ttyb.sg_flags &= ~ECHO;
1381 # endif
1383 #endif
1384 SetTTY(newfd, modep);
1385 #ifdef TIOCSWINSZ
1386 glwz.ws_col = w;
1387 glwz.ws_row = h;
1388 (void) ioctl(newfd, TIOCSWINSZ, (char *)&glwz);
1389 #endif
1390 /* Always turn off nonblocking mode */
1391 (void)fcntl(newfd, F_SETFL, 0);
1393 #ifndef TIOCSWINSZ
1394 sprintf(libuf, "LINES=%d", h);
1395 sprintf(cobuf, "COLUMNS=%d", w);
1396 NewEnv[5] = libuf;
1397 NewEnv[6] = cobuf;
1398 #endif
1399 #ifdef MAPKEYS
1400 NewEnv[2] = MakeTermcap(display == 0 || win->w_aflag);
1401 #else
1402 if (win->w_aflag)
1403 NewEnv[2] = MakeTermcap(1);
1404 else
1405 NewEnv[2] = Termcap;
1406 #endif
1407 strcpy(shellbuf, "SHELL=");
1408 strncpy(shellbuf + 6, ShellProg + (*ShellProg == '-'), sizeof(shellbuf) - 7);
1409 shellbuf[sizeof(shellbuf) - 1] = 0;
1410 NewEnv[4] = shellbuf;
1411 debug1("ForkWindow: NewEnv[4] = '%s'\n", shellbuf);
1412 if (win->w_term && *win->w_term && strcmp(screenterm, win->w_term) &&
1413 (strlen(win->w_term) < 20))
1415 char *s1, *s2, tl;
1417 sprintf(tebuf, "TERM=%s", win->w_term);
1418 debug2("Makewindow %d with %s\n", win->w_number, tebuf);
1419 tl = strlen(win->w_term);
1420 NewEnv[1] = tebuf;
1421 if ((s1 = index(NewEnv[2], '|')))
1423 if ((s2 = index(++s1, '|')))
1425 if (strlen(NewEnv[2]) - (s2 - s1) + tl < 1024)
1427 bcopy(s2, s1 + tl, strlen(s2) + 1);
1428 bcopy(win->w_term, s1, tl);
1433 sprintf(ebuf, "WINDOW=%d", win->w_number);
1434 NewEnv[3] = ebuf;
1436 if (*proc == '-')
1437 proc++;
1438 if (!*proc)
1439 proc = DefaultShell;
1440 debug1("calling execvpe %s\n", proc);
1441 execvpe(proc, args, NewEnv);
1442 debug1("exec error: %d\n", errno);
1443 Panic(errno, "Cannot exec '%s'", proc);
1444 default:
1445 break;
1447 if (slave != -1)
1448 close(slave);
1449 return pid;
1452 #ifndef HAVE_EXECVPE
1453 void
1454 execvpe(prog, args, env)
1455 char *prog, **args, **env;
1457 register char *path = NULL, *p;
1458 char buf[1024];
1459 char *shargs[MAXARGS + 1];
1460 register int i, eaccess = 0;
1462 if (rindex(prog, '/'))
1463 path = "";
1464 if (!path && !(path = getenv("PATH")))
1465 path = DefaultPath;
1468 for (p = buf; *path && *path != ':'; path++)
1469 if (p - buf < (int)sizeof(buf) - 2)
1470 *p++ = *path;
1471 if (p > buf)
1472 *p++ = '/';
1473 if (p - buf + strlen(prog) >= sizeof(buf) - 1)
1474 continue;
1475 strcpy(p, prog);
1476 execve(buf, args, env);
1477 switch (errno)
1479 case ENOEXEC:
1480 shargs[0] = DefaultShell;
1481 shargs[1] = buf;
1482 for (i = 1; (shargs[i + 1] = args[i]) != NULL; ++i)
1484 execve(DefaultShell, shargs, env);
1485 return;
1486 case EACCES:
1487 eaccess = 1;
1488 break;
1489 case ENOMEM:
1490 case E2BIG:
1491 case ETXTBSY:
1492 return;
1494 } while (*path++);
1495 if (eaccess)
1496 errno = EACCES;
1498 #endif
1500 #ifdef PSEUDOS
1503 winexec(av)
1504 char **av;
1506 char **pp;
1507 char *p, *s, *t;
1508 int i, r = 0, l = 0;
1509 struct win *w;
1510 extern struct display *display;
1511 extern struct win *windows;
1512 struct pseudowin *pwin;
1513 int type;
1515 if ((w = display ? fore : windows) == NULL)
1516 return -1;
1517 if (!*av || w->w_pwin)
1519 Msg(0, "Filter running: %s", w->w_pwin ? w->w_pwin->p_cmd : "(none)");
1520 return -1;
1522 if (w->w_ptyfd < 0)
1524 Msg(0, "You feel dead inside.");
1525 return -1;
1527 if (!(pwin = (struct pseudowin *)calloc(1, sizeof(struct pseudowin))))
1529 Msg(0, strnomem);
1530 return -1;
1533 /* allow ^a:!!./ttytest as a short form for ^a:exec !.. ./ttytest */
1534 for (s = *av; *s == ' '; s++)
1536 for (p = s; *p == ':' || *p == '.' || *p == '!'; p++)
1538 if (*p != '|')
1539 while (*p && p > s && p[-1] == '.')
1540 p--;
1541 if (*p == '|')
1543 l = F_UWP;
1544 p++;
1546 if (*p)
1547 av[0] = p;
1548 else
1549 av++;
1551 t = pwin->p_cmd;
1552 for (i = 0; i < 3; i++)
1554 *t = (s < p) ? *s++ : '.';
1555 switch (*t++)
1557 case '.':
1558 case '|':
1559 l |= F_PFRONT << (i * F_PSHIFT);
1560 break;
1561 case '!':
1562 l |= F_PBACK << (i * F_PSHIFT);
1563 break;
1564 case ':':
1565 l |= F_PBOTH << (i * F_PSHIFT);
1566 break;
1570 if (l & F_UWP)
1572 *t++ = '|';
1573 if ((l & F_PMASK) == F_PFRONT)
1575 *pwin->p_cmd = '!';
1576 l ^= F_PFRONT | F_PBACK;
1579 if (!(l & F_PBACK))
1580 l |= F_UWP;
1581 *t++ = ' ';
1582 pwin->p_fdpat = l;
1583 debug1("winexec: '%#x'\n", pwin->p_fdpat);
1585 l = MAXSTR - 4;
1586 for (pp = av; *pp; pp++)
1588 p = *pp;
1589 while (*p && l-- > 0)
1590 *t++ = *p++;
1591 if (l <= 0)
1592 break;
1593 *t++ = ' ';
1595 *--t = '\0';
1596 debug1("%s\n", pwin->p_cmd);
1598 if ((pwin->p_ptyfd = OpenDevice(av, 0, &type, &t)) < 0)
1600 free((char *)pwin);
1601 return -1;
1603 strncpy(pwin->p_tty, t, MAXSTR - 1);
1604 w->w_pwin = pwin;
1605 if (type != W_TYPE_PTY)
1607 FreePseudowin(w);
1608 Msg(0, "Cannot only use commands as pseudo win.");
1609 return -1;
1611 if (!(pwin->p_fdpat & F_PFRONT))
1612 evdeq(&w->w_readev);
1613 #ifdef TIOCPKT
1615 int flag = 0;
1617 if (ioctl(pwin->p_ptyfd, TIOCPKT, (char *)&flag))
1619 Msg(errno, "TIOCPKT pwin ioctl");
1620 FreePseudowin(w);
1621 return -1;
1623 if (w->w_type == W_TYPE_PTY && !(pwin->p_fdpat & F_PFRONT))
1625 if (ioctl(w->w_ptyfd, TIOCPKT, (char *)&flag))
1627 Msg(errno, "TIOCPKT win ioctl");
1628 FreePseudowin(w);
1629 return -1;
1633 #endif /* TIOCPKT */
1635 pwin->p_readev.fd = pwin->p_writeev.fd = pwin->p_ptyfd;
1636 pwin->p_readev.type = EV_READ;
1637 pwin->p_writeev.type = EV_WRITE;
1638 pwin->p_readev.data = pwin->p_writeev.data = (char *)w;
1639 pwin->p_readev.handler = pseu_readev_fn;
1640 pwin->p_writeev.handler = pseu_writeev_fn;
1641 pwin->p_writeev.condpos = &pwin->p_inlen;
1642 if (pwin->p_fdpat & (F_PFRONT << F_PSHIFT * 2 | F_PFRONT << F_PSHIFT))
1643 evenq(&pwin->p_readev);
1644 evenq(&pwin->p_writeev);
1645 r = pwin->p_pid = ForkWindow(w, av, t);
1646 if (r < 0)
1647 FreePseudowin(w);
1648 return r;
1651 void
1652 FreePseudowin(w)
1653 struct win *w;
1655 struct pseudowin *pwin = w->w_pwin;
1657 ASSERT(pwin);
1658 if (fcntl(w->w_ptyfd, F_SETFL, FNBLOCK))
1659 Msg(errno, "Warning: FreePseudowin: NBLOCK fcntl failed");
1660 #ifdef TIOCPKT
1661 if (w->w_type == W_TYPE_PTY && !(pwin->p_fdpat & F_PFRONT))
1663 int flag = 1;
1664 if (ioctl(w->w_ptyfd, TIOCPKT, (char *)&flag))
1665 Msg(errno, "Warning: FreePseudowin: TIOCPKT win ioctl");
1667 #endif
1668 /* should be able to use CloseDevice() here */
1669 (void)chmod(pwin->p_tty, 0666);
1670 (void)chown(pwin->p_tty, 0, 0);
1671 if (pwin->p_ptyfd >= 0)
1672 close(pwin->p_ptyfd);
1673 evdeq(&pwin->p_readev);
1674 evdeq(&pwin->p_writeev);
1675 if (w->w_readev.condneg == &pwin->p_inlen)
1676 w->w_readev.condpos = w->w_readev.condneg = 0;
1677 evenq(&w->w_readev);
1678 free((char *)pwin);
1679 w->w_pwin = NULL;
1682 #endif /* PSEUDOS */
1685 #ifdef MULTIUSER
1687 * returns 0, if the lock really has been released
1690 ReleaseAutoWritelock(dis, w)
1691 struct display *dis;
1692 struct win *w;
1694 debug2("ReleaseAutoWritelock: user %s, window %d\n",
1695 dis->d_user->u_name, w->w_number);
1697 /* release auto writelock when user has no other display here */
1698 if (w->w_wlock == WLOCK_AUTO && w->w_wlockuser == dis->d_user)
1700 struct display *d;
1702 for (d = displays; d; d = d->d_next)
1703 if (( d != dis) && (d->d_fore == w) && (d->d_user == dis->d_user))
1704 break;
1705 debug3("%s %s autolock on win %d\n",
1706 dis->d_user->u_name, d ? "keeps" : "releases", w->w_number);
1707 if (!d)
1709 w->w_wlockuser = NULL;
1710 return 0;
1713 return 1;
1717 * returns 0, if the lock really could be obtained
1720 ObtainAutoWritelock(d, w)
1721 struct display *d;
1722 struct win *w;
1724 if ((w->w_wlock == WLOCK_AUTO) &&
1725 !AclCheckPermWin(d->d_user, ACL_WRITE, w) &&
1726 !w->w_wlockuser)
1728 debug2("%s obtained auto writelock for exported window %d\n",
1729 d->d_user->u_name, w->w_number);
1730 w->w_wlockuser = d->d_user;
1731 return 0;
1733 return 1;
1736 #endif /* MULTIUSER */
1740 /********************************************************************/
1742 #ifdef COPY_PASTE
1743 static void
1744 paste_slowev_fn(ev, data)
1745 struct event *ev;
1746 char *data;
1748 struct paster *pa = (struct paster *)data;
1749 struct win *p;
1751 int l = 1;
1752 flayer = pa->pa_pastelayer;
1753 if (!flayer)
1754 pa->pa_pastelen = 0;
1755 if (!pa->pa_pastelen)
1756 return;
1757 p = Layer2Window(flayer);
1758 DoProcess(p, &pa->pa_pasteptr, &l, pa);
1759 pa->pa_pastelen -= 1 - l;
1760 if (pa->pa_pastelen > 0)
1762 SetTimeout(&pa->pa_slowev, p->w_slowpaste);
1763 evenq(&pa->pa_slowev);
1766 #endif
1769 static int
1770 muchpending(p, ev)
1771 struct win *p;
1772 struct event *ev;
1774 struct canvas *cv;
1775 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
1777 display = cv->c_display;
1778 if (D_status == STATUS_ON_WIN && !D_status_bell)
1780 /* wait 'til status is gone */
1781 debug("BLOCKING because of status\n");
1782 ev->condpos = &const_one;
1783 ev->condneg = &D_status;
1784 return 1;
1786 debug2("muchpending %s %d: ", D_usertty, D_blocked);
1787 debug3("%d %d %d\n", D_obufp - D_obuf, D_obufmax, D_blocked_fuzz);
1788 if (D_blocked)
1789 continue;
1790 if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
1792 if (D_nonblock == 0)
1794 debug1("obuf is full, stopping output to display %s\n", D_usertty);
1795 D_blocked = 1;
1796 continue;
1798 debug("BLOCKING because of full obuf\n");
1799 ev->condpos = &D_obuffree;
1800 ev->condneg = &D_obuflenmax;
1801 if (D_nonblock > 0 && !D_blockedev.queued)
1803 debug1("created timeout of %g secs\n", D_nonblock/1000.);
1804 SetTimeout(&D_blockedev, D_nonblock);
1805 evenq(&D_blockedev);
1807 return 1;
1810 return 0;
1813 static void
1814 win_readev_fn(ev, data)
1815 struct event *ev;
1816 char *data;
1818 struct win *p = (struct win *)data;
1819 char buf[IOSIZE], *bp;
1820 int size, len;
1821 #ifdef PSEUDOS
1822 int wtop;
1823 #endif
1825 bp = buf;
1826 size = IOSIZE;
1828 #ifdef PSEUDOS
1829 wtop = p->w_pwin && W_WTOP(p);
1830 if (wtop)
1832 ASSERT(sizeof(p->w_pwin->p_inbuf) == IOSIZE);
1833 size = IOSIZE - p->w_pwin->p_inlen;
1834 if (size <= 0)
1836 ev->condpos = &const_IOSIZE;
1837 ev->condneg = &p->w_pwin->p_inlen;
1838 return;
1841 #endif
1842 if (p->w_layer.l_cvlist && muchpending(p, ev))
1843 return;
1844 #ifdef ZMODEM
1845 if (!p->w_zdisplay)
1846 #endif
1847 if (p->w_blocked)
1849 ev->condpos = &const_one;
1850 ev->condneg = &p->w_blocked;
1851 return;
1853 if (ev->condpos)
1854 ev->condpos = ev->condneg = 0;
1856 if ((len = p->w_outlen))
1858 p->w_outlen = 0;
1859 WriteString(p, p->w_outbuf, len);
1860 return;
1863 debug1("going to read from window fd %d\n", ev->fd);
1864 if ((len = read(ev->fd, buf, size)) < 0)
1866 if (errno == EINTR || errno == EAGAIN)
1867 return;
1868 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1869 if (errno == EWOULDBLOCK)
1870 return;
1871 #endif
1872 debug2("Window %d: read error (errno %d) - killing window\n", p->w_number, errno);
1873 #ifdef BSDWAIT
1874 WindowDied(p, (union wait)0, 0);
1875 #else
1876 WindowDied(p, 0, 0);
1877 #endif
1878 return;
1880 if (len == 0)
1882 debug1("Window %d: EOF - killing window\n", p->w_number);
1883 #ifdef BSDWAIT
1884 WindowDied(p, (union wait)0, 0);
1885 #else
1886 WindowDied(p, 0, 0);
1887 #endif
1888 return;
1890 debug1(" -> %d bytes\n", len);
1891 #ifdef TIOCPKT
1892 if (p->w_type == W_TYPE_PTY)
1894 if (buf[0])
1896 debug1("PAKET %x\n", buf[0]);
1897 if (buf[0] & TIOCPKT_NOSTOP)
1898 WNewAutoFlow(p, 0);
1899 if (buf[0] & TIOCPKT_DOSTOP)
1900 WNewAutoFlow(p, 1);
1902 bp++;
1903 len--;
1905 #endif
1906 #ifdef BUILTIN_TELNET
1907 if (p->w_type == W_TYPE_TELNET)
1908 len = TelIn(p, bp, len, buf + sizeof(buf) - (bp + len));
1909 #endif
1910 if (len == 0)
1911 return;
1912 #ifdef ZMODEM
1913 if (zmodem_mode && zmodem_parse(p, bp, len))
1914 return;
1915 #endif
1916 #ifdef PSEUDOS
1917 if (wtop)
1919 debug("sending input to pwin\n");
1920 bcopy(bp, p->w_pwin->p_inbuf + p->w_pwin->p_inlen, len);
1921 p->w_pwin->p_inlen += len;
1923 #endif
1925 LayPause(&p->w_layer, 1);
1926 WriteString(p, bp, len);
1927 LayPause(&p->w_layer, 0);
1929 return;
1933 static void
1934 win_writeev_fn(ev, data)
1935 struct event *ev;
1936 char *data;
1938 struct win *p = (struct win *)data;
1939 int len;
1940 if (p->w_inlen)
1942 debug2("writing %d bytes to win %d\n", p->w_inlen, p->w_number);
1943 if ((len = write(ev->fd, p->w_inbuf, p->w_inlen)) <= 0)
1944 len = p->w_inlen; /* dead window */
1945 if ((p->w_inlen -= len))
1946 bcopy(p->w_inbuf + len, p->w_inbuf, p->w_inlen);
1948 #ifdef COPY_PASTE
1949 if (p->w_paster.pa_pastelen && !p->w_slowpaste)
1951 struct paster *pa = &p->w_paster;
1952 flayer = pa->pa_pastelayer;
1953 if (flayer)
1954 DoProcess(p, &pa->pa_pasteptr, &pa->pa_pastelen, pa);
1956 #endif
1957 return;
1962 #ifdef PSEUDOS
1964 static void
1965 pseu_readev_fn(ev, data)
1966 struct event *ev;
1967 char *data;
1969 struct win *p = (struct win *)data;
1970 char buf[IOSIZE];
1971 int size, ptow, len;
1973 size = IOSIZE;
1975 ptow = W_PTOW(p);
1976 if (ptow)
1978 ASSERT(sizeof(p->w_inbuf) == IOSIZE);
1979 size = IOSIZE - p->w_inlen;
1980 if (size <= 0)
1982 ev->condpos = &const_IOSIZE;
1983 ev->condneg = &p->w_inlen;
1984 return;
1987 if (p->w_layer.l_cvlist && muchpending(p, ev))
1988 return;
1989 if (p->w_blocked)
1991 ev->condpos = &const_one;
1992 ev->condneg = &p->w_blocked;
1993 return;
1995 if (ev->condpos)
1996 ev->condpos = ev->condneg = 0;
1998 if ((len = p->w_outlen))
2000 p->w_outlen = 0;
2001 WriteString(p, p->w_outbuf, len);
2002 return;
2005 if ((len = read(ev->fd, buf, size)) <= 0)
2007 if (errno == EINTR || errno == EAGAIN)
2008 return;
2009 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
2010 if (errno == EWOULDBLOCK)
2011 return;
2012 #endif
2013 debug2("Window %d: pseudowin read error (errno %d) -- removing pseudowin\n", p->w_number, len ? errno : 0);
2014 FreePseudowin(p);
2015 return;
2017 /* no packet mode on pseudos! */
2018 if (ptow)
2020 bcopy(buf, p->w_inbuf + p->w_inlen, len);
2021 p->w_inlen += len;
2023 WriteString(p, buf, len);
2024 return;
2027 static void
2028 pseu_writeev_fn(ev, data)
2029 struct event *ev;
2030 char *data;
2032 struct win *p = (struct win *)data;
2033 struct pseudowin *pw = p->w_pwin;
2034 int len;
2036 ASSERT(pw);
2037 if (pw->p_inlen == 0)
2038 return;
2039 if ((len = write(ev->fd, pw->p_inbuf, pw->p_inlen)) <= 0)
2040 len = pw->p_inlen; /* dead pseudo */
2041 if ((p->w_pwin->p_inlen -= len))
2042 bcopy(p->w_pwin->p_inbuf + len, p->w_pwin->p_inbuf, p->w_pwin->p_inlen);
2046 #endif /* PSEUDOS */
2048 static void
2049 win_silenceev_fn(ev, data)
2050 struct event *ev;
2051 char *data;
2053 struct win *p = (struct win *)data;
2054 struct canvas *cv;
2055 debug1("FOUND silence win %d\n", p->w_number);
2056 for (display = displays; display; display = display->d_next)
2058 for (cv = D_cvlist; cv; cv = cv->c_next)
2059 if (cv->c_layer->l_bottom == &p->w_layer)
2060 break;
2061 if (cv)
2062 continue; /* user already sees window */
2063 #ifdef MULTIUSER
2064 if (!(ACLBYTE(p->w_lio_notify, D_user->u_id) & ACLBIT(D_user->u_id)))
2065 continue;
2066 #endif
2067 Msg(0, "Window %d: silence for %d seconds", p->w_number, p->w_silencewait);
2071 static void
2072 win_destroyev_fn(ev, data)
2073 struct event *ev;
2074 char *data;
2076 struct win *p = (struct win *)ev->data;
2077 WindowDied(p, p->w_exitstatus, 1);
2080 #ifdef ZMODEM
2082 static int
2083 zmodem_parse(p, bp, len)
2084 struct win *p;
2085 char *bp;
2086 int len;
2088 int i;
2089 char *b2 = bp;
2090 for (i = 0; i < len; i++, b2++)
2092 if (p->w_zauto == 0)
2094 for (; i < len; i++, b2++)
2095 if (*b2 == 030)
2096 break;
2097 if (i == len)
2098 break;
2099 if (i > 1 && b2[-1] == '*' && b2[-2] == '*')
2100 p->w_zauto = 3;
2101 continue;
2103 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'))
2105 if (++p->w_zauto < 6)
2106 continue;
2107 if (p->w_zauto == 6)
2108 p->w_zauto = 0;
2109 if (!p->w_zdisplay)
2111 if (i > 6)
2112 WriteString(p, bp, i + 1 - 6);
2113 WriteString(p, "\r\n", 2);
2114 zmodem_found(p, *b2 == '1', b2 + 1, len - i - 1);
2115 return 1;
2117 else if (p->w_zauto == 7 || *b2 == '8')
2119 int se = p->w_zdisplay->d_blocked == 2 ? 'O' : '\212';
2120 for (; i < len; i++, b2++)
2121 if (*b2 == se)
2122 break;
2123 if (i < len)
2125 zmodem_abort(p, 0);
2126 D_blocked = 0;
2127 D_readev.condpos = D_readev.condneg = 0;
2128 while (len-- > 0)
2129 AddChar(*bp++);
2130 Flush(0);
2131 Activate(D_fore ? D_fore->w_norefresh : 0);
2132 return 1;
2134 p->w_zauto = 6;
2137 else
2138 p->w_zauto = *b2 == '*' ? (p->w_zauto == 2 ? 2 : 1) : 0;
2140 if (p->w_zauto == 0 && bp[len - 1] == '*')
2141 p->w_zauto = len > 1 && bp[len - 2] == '*' ? 2 : 1;
2142 if (p->w_zdisplay)
2144 display = p->w_zdisplay;
2145 while (len-- > 0)
2146 AddChar(*bp++);
2147 return 1;
2149 return 0;
2152 static void
2153 zmodem_fin(buf, len, data)
2154 char *buf;
2155 int len;
2156 char *data;
2158 char *s;
2159 int n;
2161 if (len)
2162 RcLine(buf, strlen(buf) + 1);
2163 else
2165 s = "\030\030\030\030\030\030\030\030\030\030";
2166 n = strlen(s);
2167 LayProcess(&s, &n);
2171 static void
2172 zmodem_found(p, send, bp, len)
2173 struct win *p;
2174 int send;
2175 char *bp;
2176 int len;
2178 char *s;
2179 int i, n;
2180 extern int zmodem_mode;
2182 /* check for abort sequence */
2183 n = 0;
2184 for (i = 0; i < len ; i++)
2185 if (bp[i] != 030)
2186 n = 0;
2187 else if (++n > 4)
2188 return;
2189 if (zmodem_mode == 3 || (zmodem_mode == 1 && p->w_type != W_TYPE_PLAIN))
2191 struct display *d, *olddisplay;
2193 olddisplay = display;
2194 d = p->w_lastdisp;
2195 if (!d || d->d_fore != p)
2196 for (d = displays; d; d = d->d_next)
2197 if (d->d_fore == p)
2198 break;
2199 if (!d && p->w_layer.l_cvlist)
2200 d = p->w_layer.l_cvlist->c_display;
2201 if (!d)
2202 d = displays;
2203 if (!d)
2204 return;
2205 display = d;
2206 RemoveStatus();
2207 p->w_zdisplay = display;
2208 D_blocked = 2 + send;
2209 flayer = &p->w_layer;
2210 ZmodemPage();
2211 display = d;
2212 evdeq(&D_blockedev);
2213 D_readev.condpos = &const_IOSIZE;
2214 D_readev.condneg = &p->w_inlen;
2215 ClearAll();
2216 GotoPos(0, 0);
2217 SetRendition(&mchar_blank);
2218 AddStr("Zmodem active\r\n\r\n");
2219 AddStr(send ? "**\030B01" : "**\030B00");
2220 while (len-- > 0)
2221 AddChar(*bp++);
2222 display = olddisplay;
2223 return;
2225 flayer = &p->w_layer;
2226 Input(":", 100, INP_COOKED, zmodem_fin, NULL, 0);
2227 s = send ? zmodem_sendcmd : zmodem_recvcmd;
2228 n = strlen(s);
2229 LayProcess(&s, &n);
2232 void
2233 zmodem_abort(p, d)
2234 struct win *p;
2235 struct display *d;
2237 struct display *olddisplay = display;
2238 struct layer *oldflayer = flayer;
2239 if (p)
2241 if (p->w_savelayer && p->w_savelayer->l_next)
2243 if (oldflayer == p->w_savelayer)
2244 oldflayer = flayer->l_next;
2245 flayer = p->w_savelayer;
2246 ExitOverlayPage();
2248 p->w_zdisplay = 0;
2249 p->w_zauto = 0;
2250 LRefreshAll(&p->w_layer, 0);
2252 if (d)
2254 display = d;
2255 D_blocked = 0;
2256 D_readev.condpos = D_readev.condneg = 0;
2257 Activate(D_fore ? D_fore->w_norefresh : 0);
2259 display = olddisplay;
2260 flayer = oldflayer;
2263 #endif