Treat //foo as an argument instead of as a command
[screen-lua.git] / src / window.c
blob0a96155b5de53f556d2931097e5c8706b1aaace7
1 /* Copyright (c) 1993-2002
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 ****************************************************************
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <signal.h>
27 #include <fcntl.h>
28 #ifndef sun
29 # include <sys/ioctl.h>
30 #endif
32 #include "config.h"
34 #include "screen.h"
35 #include "extern.h"
36 #include "logfile.h" /* logfopen() */
38 extern struct display *displays, *display;
39 extern struct win *windows, *fore, *wtab[], *console_window;
40 extern char *ShellArgs[];
41 extern char *ShellProg;
42 extern char screenterm[];
43 extern char *screenlogfile;
44 extern char HostName[];
45 extern int TtyMode;
46 extern int SilenceWait;
47 extern int real_uid, real_gid, eff_uid, eff_gid;
48 extern char Termcap[];
49 extern char **NewEnv;
50 extern int visual_bell, maxwin;
51 extern struct event logflushev;
52 extern int log_flush, logtstamp_after;
53 extern int ZombieKey_destroy, ZombieKey_resurrect, ZombieKey_onerror;
54 extern struct layer *flayer;
55 extern int maxusercount;
56 extern int pty_preopen;
57 #ifdef ZMODEM
58 extern int zmodem_mode;
59 extern struct mchar mchar_blank;
60 extern char *zmodem_sendcmd;
61 extern char *zmodem_recvcmd;
62 #endif
64 #if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
65 extern struct winsize glwz;
66 #endif
68 #ifdef O_NOCTTY
69 extern int separate_sids;
70 #endif
72 static void WinProcess __P((char **, int *));
73 static void WinRedisplayLine __P((int, int, int, int));
74 static void WinClearLine __P((int, int, int, int));
75 static int WinRewrite __P((int, int, int, struct mchar *, int));
76 static int WinResize __P((int, int));
77 static void WinRestore __P((void));
78 static int DoAutolf __P((char *, int *, int));
79 static void ZombieProcess __P((char **, int *));
80 static void win_readev_fn __P((struct event *, char *));
81 static void win_writeev_fn __P((struct event *, char *));
82 static int muchpending __P((struct win *, struct event *));
83 #ifdef COPY_PASTE
84 static void paste_slowev_fn __P((struct event *, char *));
85 #endif
86 #ifdef PSEUDOS
87 static void pseu_readev_fn __P((struct event *, char *));
88 static void pseu_writeev_fn __P((struct event *, char *));
89 #endif
90 static void win_silenceev_fn __P((struct event *, char *));
92 static int OpenDevice __P((char **, int, int *, char **));
93 static int ForkWindow __P((struct win *, char **, char *));
94 #ifdef ZMODEM
95 static void zmodem_found __P((struct win *, int, char *, int));
96 static void zmodem_fin __P((char *, int, char *));
97 static int zmodem_parse __P((struct win *, char *, int));
98 #endif
102 int VerboseCreate = 0; /* XXX move this to user.h */
104 char DefaultShell[] = "/bin/sh";
105 static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
107 /* keep this in sync with the structure definition in window.h */
108 struct NewWindow nwin_undef =
110 -1, /* StartAt */
111 (char *)0, /* aka */
112 (char **)0, /* args */
113 (char *)0, /* dir */
114 (char *)0, /* term */
115 -1, /* aflag */
116 -1, /* flowflag */
117 -1, /* lflag */
118 -1, /* histheight */
119 -1, /* monitor */
120 -1, /* wlock */
121 -1, /* silence */
122 -1, /* wrap */
123 -1, /* logging */
124 -1, /* slowpaste */
125 -1, /* gr */
126 -1, /* c1 */
127 -1, /* bce */
128 -1, /* encoding */
129 (char *)0, /* hstatus */
130 (char *)0 /* charset */
133 struct NewWindow nwin_default =
135 0, /* StartAt */
136 0, /* aka */
137 ShellArgs, /* args */
138 0, /* dir */
139 screenterm, /* term */
140 0, /* aflag */
141 1*FLOW_NOW, /* flowflag */
142 LOGINDEFAULT, /* lflag */
143 DEFAULTHISTHEIGHT, /* histheight */
144 MON_OFF, /* monitor */
145 WLOCK_OFF, /* wlock */
146 0, /* silence */
147 1, /* wrap */
148 0, /* logging */
149 0, /* slowpaste */
150 0, /* gr */
151 1, /* c1 */
152 0, /* bce */
153 0, /* encoding */
154 (char *)0, /* hstatus */
155 (char *)0 /* charset */
158 struct NewWindow nwin_options;
160 static int const_IOSIZE = IOSIZE;
161 static int const_one = 1;
163 void
164 nwin_compose(def, new, res)
165 struct NewWindow *def, *new, *res;
167 #define COMPOSE(x) res->x = new->x != nwin_undef.x ? new->x : def->x
168 COMPOSE(StartAt);
169 COMPOSE(aka);
170 COMPOSE(args);
171 COMPOSE(dir);
172 COMPOSE(term);
173 COMPOSE(aflag);
174 COMPOSE(flowflag);
175 COMPOSE(lflag);
176 COMPOSE(histheight);
177 COMPOSE(monitor);
178 COMPOSE(wlock);
179 COMPOSE(silence);
180 COMPOSE(wrap);
181 COMPOSE(Lflag);
182 COMPOSE(slow);
183 COMPOSE(gr);
184 COMPOSE(c1);
185 COMPOSE(bce);
186 COMPOSE(encoding);
187 COMPOSE(hstatus);
188 COMPOSE(charset);
189 #undef COMPOSE
192 /*****************************************************************
194 * The window layer functions
197 struct LayFuncs WinLf =
199 WinProcess,
201 WinRedisplayLine,
202 WinClearLine,
203 WinRewrite,
204 WinResize,
205 WinRestore
208 static int
209 DoAutolf(buf, lenp, fr)
210 char *buf;
211 int *lenp;
212 int fr;
214 char *p;
215 int len = *lenp;
216 int trunc = 0;
218 for (p = buf; len > 0; p++, len--)
220 if (*p != '\r')
221 continue;
222 if (fr-- <= 0)
224 trunc++;
225 len--;
227 if (len == 0)
228 break;
229 bcopy(p, p + 1, len++);
230 p[1] = '\n';
232 *lenp = p - buf;
233 return trunc;
236 static void
237 WinProcess(bufpp, lenp)
238 char **bufpp;
239 int *lenp;
241 int l2 = 0, f, *ilen, l = *lenp, trunc;
242 char *ibuf;
244 debug1("WinProcess: %d bytes\n", *lenp);
245 fore = (struct win *)flayer->l_data;
247 if (fore->w_type == W_TYPE_GROUP)
249 *bufpp += *lenp;
250 *lenp = 0;
251 return;
253 if (fore->w_ptyfd < 0) /* zombie? */
255 ZombieProcess(bufpp, lenp);
256 return;
258 #ifdef MULTIUSER
259 /* a pending writelock is this:
260 * fore->w_wlock == WLOCK_AUTO, fore->w_wlockuse = NULL
261 * The user who wants to use this window next, will get the lock, if he can.
263 if (display && fore->w_wlock == WLOCK_AUTO &&
264 !fore->w_wlockuser && !AclCheckPermWin(D_user, ACL_WRITE, fore))
266 fore->w_wlockuser = D_user;
267 debug2("window %d: pending writelock grabbed by user %s\n",
268 fore->w_number, fore->w_wlockuser->u_name);
270 /* if w_wlock is set, only one user may write, else we check acls */
271 if (display && ((fore->w_wlock == WLOCK_OFF) ?
272 AclCheckPermWin(D_user, ACL_WRITE, fore) :
273 (D_user != fore->w_wlockuser)))
275 debug2("window %d, user %s: ", fore->w_number, D_user->u_name);
276 debug2("writelock %d (wlockuser %s)\n", fore->w_wlock,
277 fore->w_wlockuser ? fore->w_wlockuser->u_name : "NULL");
278 /* XXX FIXME only display !*/
279 WBell(fore, visual_bell);
280 *bufpp += *lenp;
281 *lenp = 0;
282 return;
284 #endif /* MULTIUSER */
286 #ifdef BUILTIN_TELNET
287 if (fore->w_type == W_TYPE_TELNET && TelIsline(fore) && *bufpp != fore->w_telbuf)
289 TelProcessLine(bufpp, lenp);
290 return;
292 #endif
294 #ifdef PSEUDOS
295 if (W_UWP(fore))
297 /* we send the user input to our pseudowin */
298 ibuf = fore->w_pwin->p_inbuf; ilen = &fore->w_pwin->p_inlen;
299 f = sizeof(fore->w_pwin->p_inbuf) - *ilen;
301 else
302 #endif /* PSEUDOS */
304 /* we send the user input to the window */
305 ibuf = fore->w_inbuf; ilen = &fore->w_inlen;
306 f = sizeof(fore->w_inbuf) - *ilen;
309 if (l > f)
310 l = f;
311 #ifdef BUILTIN_TELNET
312 while (l > 0)
313 #else
314 if (l > 0)
315 #endif
317 l2 = l;
318 bcopy(*bufpp, ibuf + *ilen, l2);
319 if (fore->w_autolf && (trunc = DoAutolf(ibuf + *ilen, &l2, f - l2)))
320 l -= trunc;
321 #ifdef BUILTIN_TELNET
322 if (fore->w_type == W_TYPE_TELNET && (trunc = DoTelnet(ibuf + *ilen, &l2, f - l2)))
324 l -= trunc;
325 if (fore->w_autolf)
326 continue; /* need exact value */
328 #endif
329 *ilen += l2;
330 *bufpp += l;
331 *lenp -= l;
332 return;
336 static void
337 ZombieProcess(bufpp, lenp)
338 char **bufpp;
339 int *lenp;
341 int l = *lenp;
342 char *buf = *bufpp, b1[10], b2[10];
344 debug1("ZombieProcess: %d bytes\n", *lenp);
345 fore = (struct win *)flayer->l_data;
347 ASSERT(fore->w_ptyfd < 0);
348 *bufpp += *lenp;
349 *lenp = 0;
350 for (; l-- > 0; buf++)
352 if (*(unsigned char *)buf == ZombieKey_destroy)
354 debug1("Turning undead: %d\n", fore->w_number);
355 KillWindow(fore);
356 return;
358 if (*(unsigned char *)buf == ZombieKey_resurrect)
360 debug1("Resurrecting Zombie: %d\n", fore->w_number);
361 WriteString(fore, "\r\n", 2);
362 RemakeWindow(fore);
363 return;
366 b1[AddXChar(b1, ZombieKey_destroy)] = '\0';
367 b2[AddXChar(b2, ZombieKey_resurrect)] = '\0';
368 Msg(0, "Press %s to destroy or %s to resurrect window", b1, b2);
371 static void
372 WinRedisplayLine(y, from, to, isblank)
373 int y, from, to, isblank;
375 debug3("WinRedisplayLine %d %d %d\n", y, from, to);
376 if (y < 0)
377 return;
378 fore = (struct win *)flayer->l_data;
379 if (from == 0 && y > 0 && fore->w_mlines[y - 1].image[fore->w_width] == 0)
380 LCDisplayLineWrap(&fore->w_layer, &fore->w_mlines[y], y, from, to, isblank);
381 else
382 LCDisplayLine(&fore->w_layer, &fore->w_mlines[y], y, from, to, isblank);
385 static int
386 WinRewrite(y, x1, x2, rend, doit)
387 int y, x1, x2, doit;
388 struct mchar *rend;
390 register int cost, dx;
391 register unsigned char *p, *i;
392 #ifdef FONT
393 register unsigned char *f;
394 #endif
395 #ifdef COLOR
396 register unsigned char *c;
397 # ifdef COLORS256
398 register unsigned char *cx;
399 # endif
400 #endif
402 debug3("WinRewrite %d, %d-%d\n", y, x1, x2);
403 fore = (struct win *)flayer->l_data;
404 dx = x2 - x1 + 1;
405 if (doit)
407 i = fore->w_mlines[y].image + x1;
408 while (dx-- > 0)
409 PUTCHAR(*i++);
410 return 0;
412 p = fore->w_mlines[y].attr + x1;
413 #ifdef FONT
414 f = fore->w_mlines[y].font + x1;
415 # ifdef DW_CHARS
416 if (is_dw_font(rend->font))
417 return EXPENSIVE;
418 # endif
419 # ifdef UTF8
420 if (fore->w_encoding && fore->w_encoding != UTF8 && D_encoding == UTF8 && ContainsSpecialDeffont(fore->w_mlines + y, x1, x2, fore->w_encoding))
421 return EXPENSIVE;
422 # endif
423 #endif
424 #ifdef COLOR
425 c = fore->w_mlines[y].color + x1;
426 # ifdef COLORS256
427 cx = fore->w_mlines[y].colorx + x1;
428 # endif
429 #endif
431 cost = dx = x2 - x1 + 1;
432 while(dx-- > 0)
434 if (*p++ != rend->attr)
435 return EXPENSIVE;
436 #ifdef FONT
437 if (*f++ != rend->font)
438 return EXPENSIVE;
439 #endif
440 #ifdef COLOR
441 if (*c++ != rend->color)
442 return EXPENSIVE;
443 # ifdef COLORS256
444 if (*cx++ != rend->colorx)
445 return EXPENSIVE;
446 # endif
447 #endif
449 return cost;
452 static void
453 WinClearLine(y, xs, xe, bce)
454 int y, xs, xe, bce;
456 fore = (struct win *)flayer->l_data;
457 debug3("WinClearLine %d %d-%d\n", y, xs, xe);
458 LClearLine(flayer, y, xs, xe, bce, &fore->w_mlines[y]);
461 static int
462 WinResize(wi, he)
463 int wi, he;
465 fore = (struct win *)flayer->l_data;
466 ChangeWindowSize(fore, wi, he, fore->w_histheight);
467 return 0;
470 static void
471 WinRestore()
473 struct canvas *cv;
474 fore = (struct win *)flayer->l_data;
475 debug1("WinRestore: win %p\n", fore);
476 for (cv = flayer->l_cvlist; cv; cv = cv->c_next)
478 display = cv->c_display;
479 if (cv != D_forecv)
480 continue;
481 /* ChangeScrollRegion(fore->w_top, fore->w_bot); */
482 KeypadMode(fore->w_keypad);
483 CursorkeysMode(fore->w_cursorkeys);
484 SetFlow(fore->w_flow & FLOW_NOW);
485 InsertMode(fore->w_insert);
486 ReverseVideo(fore->w_revvid);
487 CursorVisibility(fore->w_curinv ? -1 : fore->w_curvvis);
488 MouseMode(fore->w_mouse);
492 /*****************************************************************/
496 * DoStartLog constructs a path for the "want to be logfile" in buf and
497 * attempts logfopen.
499 * returns 0 on success.
502 DoStartLog(w, buf, bufsize)
503 struct win *w;
504 char *buf;
505 int bufsize;
507 int n;
508 if (!w || !buf)
509 return -1;
511 strncpy(buf, MakeWinMsg(screenlogfile, w, '%'), bufsize - 1);
512 buf[bufsize - 1] = 0;
514 debug2("DoStartLog: win %d, file %s\n", w->w_number, buf);
516 if (w->w_log != NULL)
517 logfclose(w->w_log);
519 if ((w->w_log = logfopen(buf, islogfile(buf) ? NULL : secfopen(buf, "a"))) == NULL)
520 return -2;
521 if (!logflushev.queued)
523 n = log_flush ? log_flush : (logtstamp_after + 4) / 5;
524 if (n)
526 SetTimeout(&logflushev, n * 1000);
527 evenq(&logflushev);
530 return 0;
534 * Umask & wlock are set for the user of the display,
535 * The display d (if specified) switches to that window.
538 MakeWindow(newwin)
539 struct NewWindow *newwin;
541 register struct win **pp, *p;
542 register int n, i;
543 int f = -1;
544 struct NewWindow nwin;
545 int type, startat;
546 char *TtyName;
547 #ifdef MULTIUSER
548 extern struct acluser *users;
549 #endif
551 debug1("NewWindow: StartAt %d\n", newwin->StartAt);
552 debug1("NewWindow: aka %s\n", newwin->aka?newwin->aka:"NULL");
553 debug1("NewWindow: dir %s\n", newwin->dir?newwin->dir:"NULL");
554 debug1("NewWindow: term %s\n", newwin->term?newwin->term:"NULL");
556 nwin_compose(&nwin_default, newwin, &nwin);
557 debug1("NWin: aka %s\n", nwin.aka ? nwin.aka : "NULL");
558 debug1("NWin: wlock %d\n", nwin.wlock);
559 debug1("NWin: Lflag %d\n", nwin.Lflag);
561 startat = nwin.StartAt < maxwin ? nwin.StartAt : 0;
562 pp = wtab + startat;
566 if (*pp == 0)
567 break;
568 if (++pp == wtab + maxwin)
569 pp = wtab;
571 while (pp != wtab + startat);
572 if (*pp)
574 Msg(0, "No more windows.");
575 return -1;
578 #if defined(USRLIMIT) && defined(UTMPOK)
580 * Count current number of users, if logging windows in.
582 if (nwin.lflag && CountUsers() >= USRLIMIT)
584 Msg(0, "User limit reached. Window will not be logged in.");
585 nwin.lflag = 0;
587 #endif
588 n = pp - wtab;
589 debug1("Makewin creating %d\n", n);
591 if ((f = OpenDevice(nwin.args, nwin.lflag, &type, &TtyName)) < 0)
592 return -1;
593 if (type == W_TYPE_GROUP)
594 f = -1;
596 if ((p = (struct win *)malloc(sizeof(struct win))) == 0)
598 close(f);
599 Msg(0, strnomem);
600 return -1;
602 bzero((char *)p, (int)sizeof(struct win));
604 #ifdef UTMPOK
605 if (type != W_TYPE_PTY)
606 nwin.lflag = 0;
607 #endif
609 p->w_type = type;
611 /* save the command line so that zombies can be resurrected */
612 for (i = 0; nwin.args[i] && i < MAXARGS - 1; i++)
613 p->w_cmdargs[i] = SaveStr(nwin.args[i]);
614 p->w_cmdargs[i] = 0;
615 if (nwin.dir)
616 p->w_dir = SaveStr(nwin.dir);
617 if (nwin.term)
618 p->w_term = SaveStr(nwin.term);
620 p->w_number = n;
621 p->w_group = 0;
622 if (p->w_type != W_TYPE_GROUP && fore && fore->w_type == W_TYPE_GROUP)
623 p->w_group = fore;
624 else if (p->w_type != W_TYPE_GROUP && fore && fore->w_group)
625 p->w_group = fore->w_group;
626 #ifdef MULTIUSER
628 * This is dangerous: without a display we use creators umask
629 * This is intended to be usefull for detached startup.
630 * But is still better than default bits with a NULL user.
632 if (NewWindowAcl(p, display ? D_user : users))
634 free((char *)p);
635 close(f);
636 Msg(0, strnomem);
637 return -1;
639 #endif
640 p->w_layer.l_next = 0;
641 p->w_layer.l_bottom = &p->w_layer;
642 p->w_layer.l_layfn = &WinLf;
643 p->w_layer.l_data = (char *)p;
644 p->w_savelayer = &p->w_layer;
645 p->w_pdisplay = 0;
646 p->w_lastdisp = 0;
648 #ifdef MULTIUSER
649 if (display && !AclCheckPermWin(D_user, ACL_WRITE, p))
650 p->w_wlockuser = D_user;
651 p->w_wlock = nwin.wlock;
652 #endif
653 p->w_ptyfd = f;
654 p->w_aflag = nwin.aflag;
655 p->w_flow = nwin.flowflag | ((nwin.flowflag & FLOW_AUTOFLAG) ? (FLOW_AUTO|FLOW_NOW) : FLOW_AUTO);
656 if (!nwin.aka)
657 nwin.aka = Filename(nwin.args[0]);
658 strncpy(p->w_akabuf, nwin.aka, sizeof(p->w_akabuf) - 1);
659 if ((nwin.aka = rindex(p->w_akabuf, '|')) != NULL)
661 p->w_autoaka = 0;
662 *nwin.aka++ = 0;
663 p->w_title = nwin.aka;
664 p->w_akachange = nwin.aka + strlen(nwin.aka);
666 else
667 p->w_title = p->w_akachange = p->w_akabuf;
668 if (nwin.hstatus)
669 p->w_hstatus = SaveStr(nwin.hstatus);
670 p->w_monitor = nwin.monitor;
671 #ifdef MULTIUSER
672 if (p->w_monitor == MON_ON)
674 /* always tell all users */
675 for (i = 0; i < maxusercount; i++)
676 ACLBYTE(p->w_mon_notify, i) |= ACLBIT(i);
678 #endif
680 * defsilence by Lloyd Zusman (zusman_lloyd@jpmorgan.com)
682 p->w_silence = nwin.silence;
683 p->w_silencewait = SilenceWait;
684 #ifdef MULTIUSER
685 if (p->w_silence == SILENCE_ON)
687 /* always tell all users */
688 for (i = 0; i < maxusercount; i++)
689 ACLBYTE(p->w_lio_notify, i) |= ACLBIT(i);
691 #endif
692 #ifdef COPY_PASTE
693 p->w_slowpaste = nwin.slow;
694 #else
695 nwin.histheight = 0;
696 #endif
698 p->w_norefresh = 0;
699 strncpy(p->w_tty, TtyName, MAXSTR - 1);
701 #if 0
702 /* XXX Fixme display resize */
703 if (ChangeWindowSize(p, display ? D_defwidth : 80,
704 display ? D_defheight : 24,
705 nwin.histheight))
707 FreeWindow(p);
708 return -1;
710 #else
711 if (ChangeWindowSize(p, display ? D_forecv->c_xe - D_forecv->c_xs + 1: 80,
712 display ? D_forecv->c_ye - D_forecv->c_ys + 1 : 24,
713 nwin.histheight))
715 FreeWindow(p);
716 return -1;
718 #endif
720 p->w_encoding = nwin.encoding;
721 ResetWindow(p); /* sets w_wrap, w_c1, w_gr, w_bce */
723 #ifdef FONT
724 if (nwin.charset)
725 SetCharsets(p, nwin.charset);
726 #endif
728 if (VerboseCreate && type != W_TYPE_GROUP)
730 struct display *d = display; /* WriteString zaps display */
732 WriteString(p, ":screen (", 9);
733 WriteString(p, p->w_title, strlen(p->w_title));
734 WriteString(p, "):", 2);
735 for (f = 0; p->w_cmdargs[f]; f++)
737 WriteString(p, " ", 1);
738 WriteString(p, p->w_cmdargs[f], strlen(p->w_cmdargs[f]));
740 WriteString(p, "\r\n", 2);
741 display = d;
744 p->w_deadpid = 0;
745 p->w_pid = 0;
746 #ifdef PSEUDOS
747 p->w_pwin = 0;
748 #endif
750 #ifdef BUILTIN_TELNET
751 if (type == W_TYPE_TELNET)
753 if (TelConnect(p))
755 FreeWindow(p);
756 return -1;
759 else
760 #endif
761 if (type == W_TYPE_PTY)
763 p->w_pid = ForkWindow(p, nwin.args, TtyName);
764 if (p->w_pid < 0)
766 FreeWindow(p);
767 return -1;
772 * Place the new window at the head of the most-recently-used list.
774 if (display && D_fore)
775 D_other = D_fore;
776 *pp = p;
777 p->w_next = windows;
778 windows = p;
780 if (type == W_TYPE_GROUP)
782 SetForeWindow(p);
783 Activate(p->w_norefresh);
784 WindowChanged((struct win*)0, 'w');
785 WindowChanged((struct win*)0, 'W');
786 WindowChanged((struct win*)0, 0);
787 return n;
790 p->w_lflag = nwin.lflag;
791 #ifdef UTMPOK
792 p->w_slot = (slot_t)-1;
793 # ifdef LOGOUTOK
794 debug1("MakeWindow will %slog in.\n", nwin.lflag?"":"not ");
795 if (nwin.lflag & 1)
796 # else /* LOGOUTOK */
797 debug1("MakeWindow will log in, LOGOUTOK undefined in config.h%s.\n",
798 nwin.lflag?"":" (although lflag=0)");
799 # endif /* LOGOUTOK */
801 p->w_slot = (slot_t)0;
802 if (display || (p->w_lflag & 2))
803 SetUtmp(p);
805 # ifdef CAREFULUTMP
806 CarefulUtmp(); /* If all 've been zombies, we've had no slot */
807 # endif
808 #endif /* UTMPOK */
810 if (nwin.Lflag)
812 char buf[1024];
813 DoStartLog(p, buf, sizeof(buf));
816 p->w_readev.fd = p->w_writeev.fd = p->w_ptyfd;
817 p->w_readev.type = EV_READ;
818 p->w_writeev.type = EV_WRITE;
819 p->w_readev.data = p->w_writeev.data = (char *)p;
820 p->w_readev.handler = win_readev_fn;
821 p->w_writeev.handler = win_writeev_fn;
822 p->w_writeev.condpos = &p->w_inlen;
823 evenq(&p->w_readev);
824 evenq(&p->w_writeev);
825 #ifdef COPY_PASTE
826 p->w_paster.pa_slowev.type = EV_TIMEOUT;
827 p->w_paster.pa_slowev.data = (char *)&p->w_paster;
828 p->w_paster.pa_slowev.handler = paste_slowev_fn;
829 #endif
830 p->w_silenceev.type = EV_TIMEOUT;
831 p->w_silenceev.data = (char *)p;
832 p->w_silenceev.handler = win_silenceev_fn;
833 if (p->w_silence > 0)
835 debug("New window has silence enabled.\n");
836 SetTimeout(&p->w_silenceev, p->w_silencewait * 1000);
837 evenq(&p->w_silenceev);
840 SetForeWindow(p);
841 Activate(p->w_norefresh);
842 WindowChanged((struct win*)0, 'w');
843 WindowChanged((struct win*)0, 'W');
844 WindowChanged((struct win*)0, 0);
845 return n;
849 * Resurrect a window from Zombie state.
850 * The command vector is therefore stored in the window structure.
851 * Note: The terminaltype defaults to screenterm again, the current
852 * working directory is lost.
855 RemakeWindow(p)
856 struct win *p;
858 char *TtyName;
859 int lflag, f;
861 lflag = nwin_default.lflag;
862 if ((f = OpenDevice(p->w_cmdargs, lflag, &p->w_type, &TtyName)) < 0)
863 return -1;
865 strncpy(p->w_tty, *TtyName ? TtyName : p->w_title, MAXSTR - 1);
866 p->w_ptyfd = f;
867 p->w_readev.fd = f;
868 p->w_writeev.fd = f;
869 evenq(&p->w_readev);
870 evenq(&p->w_writeev);
872 if (VerboseCreate)
874 struct display *d = display; /* WriteString zaps display */
876 WriteString(p, ":screen (", 9);
877 WriteString(p, p->w_title, strlen(p->w_title));
878 WriteString(p, "):", 2);
879 for (f = 0; p->w_cmdargs[f]; f++)
881 WriteString(p, " ", 1);
882 WriteString(p, p->w_cmdargs[f], strlen(p->w_cmdargs[f]));
884 WriteString(p, "\r\n", 2);
885 display = d;
888 p->w_deadpid = 0;
889 p->w_pid = 0;
890 #ifdef BUILTIN_TELNET
891 if (p->w_type == W_TYPE_TELNET)
893 if (TelConnect(p))
894 return -1;
896 else
897 #endif
898 if (p->w_type == W_TYPE_PTY)
900 p->w_pid = ForkWindow(p, p->w_cmdargs, TtyName);
901 if (p->w_pid < 0)
902 return -1;
905 #ifdef UTMPOK
906 if (p->w_slot == (slot_t)0 && (display || (p->w_lflag & 2)))
907 SetUtmp(p);
908 # ifdef CAREFULUTMP
909 CarefulUtmp(); /* If all 've been zombies, we've had no slot */
910 # endif
911 #endif
912 WindowChanged(p, 'f');
913 return p->w_number;
916 void
917 CloseDevice(wp)
918 struct win *wp;
920 if (wp->w_ptyfd < 0)
921 return;
922 if (wp->w_type == W_TYPE_PTY)
924 /* pty 4 SALE */
925 (void)chmod(wp->w_tty, 0666);
926 (void)chown(wp->w_tty, 0, 0);
928 close(wp->w_ptyfd);
929 wp->w_ptyfd = -1;
930 wp->w_tty[0] = 0;
931 evdeq(&wp->w_readev);
932 evdeq(&wp->w_writeev);
933 #ifdef BUILTIN_TELNET
934 evdeq(&wp->w_telconnev);
935 #endif
936 wp->w_readev.fd = wp->w_writeev.fd = -1;
939 void
940 FreeWindow(wp)
941 struct win *wp;
943 struct display *d;
944 int i;
945 struct canvas *cv, *ncv;
946 struct layer *l;
948 debug1("FreeWindow %d\n", wp ? wp->w_number: -1);
949 #ifdef PSEUDOS
950 if (wp->w_pwin)
951 FreePseudowin(wp);
952 #endif
953 #ifdef UTMPOK
954 RemoveUtmp(wp);
955 #endif
956 CloseDevice(wp);
958 if (wp == console_window)
960 TtyGrabConsole(-1, -1, "free");
961 console_window = 0;
963 if (wp->w_log != NULL)
964 logfclose(wp->w_log);
965 ChangeWindowSize(wp, 0, 0, 0);
967 if (wp->w_type == W_TYPE_GROUP)
969 struct win *win;
970 for (win = windows; win; win = win->w_next)
971 if (win->w_group == wp)
972 win->w_group = wp->w_group;
975 if (wp->w_hstatus)
976 free(wp->w_hstatus);
977 for (i = 0; wp->w_cmdargs[i]; i++)
978 free(wp->w_cmdargs[i]);
979 if (wp->w_dir)
980 free(wp->w_dir);
981 if (wp->w_term)
982 free(wp->w_term);
983 for (d = displays; d; d = d->d_next)
985 if (d->d_other == wp)
986 d->d_other = d->d_fore && d->d_fore->w_next != wp ? d->d_fore->w_next : wp->w_next;
987 if (d->d_fore == wp)
988 d->d_fore = NULL;
989 for (cv = d->d_cvlist; cv; cv = cv->c_next)
991 for (l = cv->c_layer; l; l = l->l_next)
992 if (l->l_layfn == &WinLf)
993 break;
994 if (!l)
995 continue;
996 if ((struct win *)l->l_data != wp)
997 continue;
998 if (cv->c_layer == wp->w_savelayer)
999 wp->w_savelayer = 0;
1000 KillLayerChain(cv->c_layer);
1003 if (wp->w_savelayer)
1004 KillLayerChain(wp->w_savelayer);
1005 for (cv = wp->w_layer.l_cvlist; cv; cv = ncv)
1007 ncv = cv->c_lnext;
1008 cv->c_layer = &cv->c_blank;
1009 cv->c_blank.l_cvlist = cv;
1010 cv->c_lnext = 0;
1011 cv->c_xoff = cv->c_xs;
1012 cv->c_yoff = cv->c_ys;
1013 RethinkViewportOffsets(cv);
1015 wp->w_layer.l_cvlist = 0;
1016 if (flayer == &wp->w_layer)
1017 flayer = 0;
1019 #ifdef MULTIUSER
1020 FreeWindowAcl(wp);
1021 #endif /* MULTIUSER */
1022 evdeq(&wp->w_readev); /* just in case */
1023 evdeq(&wp->w_writeev); /* just in case */
1024 evdeq(&wp->w_silenceev);
1025 #ifdef COPY_PASTE
1026 FreePaster(&wp->w_paster);
1027 #endif
1028 free((char *)wp);
1031 static int
1032 OpenDevice(args, lflag, typep, namep)
1033 char **args;
1034 int lflag;
1035 int *typep;
1036 char **namep;
1038 char *arg = args[0];
1039 struct stat st;
1040 int f;
1042 if (!arg)
1043 return -1;
1044 if (strcmp(arg, "//group") == 0)
1046 *typep = W_TYPE_GROUP;
1047 *namep = "telnet";
1048 return 0;
1050 #ifdef BUILTIN_TELNET
1051 if (strcmp(arg, "//telnet") == 0)
1053 f = TelOpen(args + 1);
1054 lflag = 0;
1055 *typep = W_TYPE_TELNET;
1056 *namep = "telnet";
1058 else
1059 #endif
1060 if (strncmp(arg, "//", 2) == 0)
1062 Msg(0, "Invalid argument '%s'", arg);
1063 return -1;
1065 else if ((stat(arg, &st)) == 0 && S_ISCHR(st.st_mode))
1067 if (access(arg, R_OK | W_OK) == -1)
1069 Msg(errno, "Cannot access line '%s' for R/W", arg);
1070 return -1;
1072 debug("OpenDevice: OpenTTY\n");
1073 if ((f = OpenTTY(arg, args[1])) < 0)
1074 return -1;
1075 lflag = 0;
1076 *typep = W_TYPE_PLAIN;
1077 *namep = arg;
1079 else
1081 *typep = W_TYPE_PTY;
1082 f = OpenPTY(namep);
1083 if (f == -1)
1085 Msg(0, "No more PTYs.");
1086 return -1;
1088 #ifdef TIOCPKT
1090 int flag = 1;
1091 if (ioctl(f, TIOCPKT, (char *)&flag))
1093 Msg(errno, "TIOCPKT ioctl");
1094 close(f);
1095 return -1;
1098 #endif /* TIOCPKT */
1100 debug1("fcntl(%d, F_SETFL, FNBLOCK)\n", f);
1101 (void) fcntl(f, F_SETFL, FNBLOCK);
1102 #ifdef linux
1104 * Tenebreux (zeus@ns.acadiacom.net) has Linux 1.3.70 where select
1105 * gets confused in the following condition:
1106 * Open a pty-master side, request a flush on it, then set packet
1107 * mode and call select(). Select will return a possible read, where
1108 * the one byte response to the flush can be found. Select will
1109 * thereafter return a possible read, which yields I/O error.
1111 * If we request another flush *after* switching into packet mode,
1112 * this I/O error does not occur. We receive a single response byte
1113 * although we send two flush requests now.
1115 * Maybe we should not flush at all.
1117 * 10.5.96 jw.
1119 if (*typep == W_TYPE_PTY || *typep == W_TYPE_PLAIN)
1120 tcflush(f, TCIOFLUSH);
1121 #endif
1123 if (*typep != W_TYPE_PTY)
1124 return f;
1126 #ifndef PTYROFS
1127 #ifdef PTYGROUP
1128 if (chown(*namep, real_uid, PTYGROUP) && !eff_uid)
1129 #else
1130 if (chown(*namep, real_uid, real_gid) && !eff_uid)
1131 #endif
1133 Msg(errno, "chown tty");
1134 close(f);
1135 return -1;
1137 #ifdef UTMPOK
1138 if (chmod(*namep, lflag ? TtyMode : (TtyMode & ~022)) && !eff_uid)
1139 #else
1140 if (chmod(*namep, TtyMode) && !eff_uid)
1141 #endif
1143 Msg(errno, "chmod tty");
1144 close(f);
1145 return -1;
1147 #endif
1148 return f;
1152 * Fields w_width, w_height, aflag, number (and w_tty)
1153 * are read from struct win *win. No fields written.
1154 * If pwin is nonzero, filedescriptors are distributed
1155 * between win->w_tty and open(ttyn)
1158 static int
1159 ForkWindow(win, args, ttyn)
1160 struct win *win;
1161 char **args, *ttyn;
1163 int pid;
1164 char tebuf[25];
1165 char ebuf[20];
1166 char shellbuf[7 + MAXPATHLEN];
1167 char *proc;
1168 #ifndef TIOCSWINSZ
1169 char libuf[20], cobuf[20];
1170 #endif
1171 int newfd;
1172 int w = win->w_width;
1173 int h = win->w_height;
1174 #ifdef PSEUDOS
1175 int i, pat, wfdused;
1176 struct pseudowin *pwin = win->w_pwin;
1177 #endif
1178 int slave = -1;
1180 #ifdef O_NOCTTY
1181 if (pty_preopen)
1183 debug("pre-opening slave...\n");
1184 if ((slave = open(ttyn, O_RDWR|O_NOCTTY)) == -1)
1186 Msg(errno, "ttyn");
1187 return -1;
1190 #endif
1191 debug("forking...\n");
1192 proc = *args;
1193 if (proc == 0)
1195 args = ShellArgs;
1196 proc = *args;
1198 fflush(stdout);
1199 fflush(stderr);
1200 switch (pid = fork())
1202 case -1:
1203 Msg(errno, "fork");
1204 break;
1205 case 0:
1206 signal(SIGHUP, SIG_DFL);
1207 signal(SIGINT, SIG_DFL);
1208 signal(SIGQUIT, SIG_DFL);
1209 signal(SIGTERM, SIG_DFL);
1210 #ifdef BSDJOBS
1211 signal(SIGTTIN, SIG_DFL);
1212 signal(SIGTTOU, SIG_DFL);
1213 #endif
1214 #ifdef SIGPIPE
1215 signal(SIGPIPE, SIG_DFL);
1216 #endif
1217 #ifdef SIGXFSZ
1218 signal(SIGXFSZ, SIG_DFL);
1219 #endif
1221 displays = 0; /* beware of Panic() */
1222 if (setgid(real_gid) || setuid(real_uid))
1223 Panic(errno, "Setuid/gid");
1224 eff_uid = real_uid;
1225 eff_gid = real_gid;
1226 #ifdef PSEUDOS
1227 if (!pwin) /* ignore directory if pseudo */
1228 #endif
1229 if (win->w_dir && *win->w_dir && chdir(win->w_dir))
1230 Panic(errno, "Cannot chdir to %s", win->w_dir);
1232 if (display)
1234 brktty(D_userfd);
1235 freetty();
1237 else
1238 brktty(-1);
1239 #ifdef DEBUG
1240 if (dfp && dfp != stderr)
1241 fclose(dfp);
1242 #endif
1243 if (slave != -1)
1245 close(0);
1246 dup(slave);
1247 close(slave);
1248 closeallfiles(win->w_ptyfd);
1249 slave = dup(0);
1251 else
1252 closeallfiles(win->w_ptyfd);
1253 #ifdef DEBUG
1254 if (dfp) /* do not produce child debug, when debug is "off" */
1256 char buf[256];
1258 sprintf(buf, "%s/screen.child", DEBUGDIR);
1259 if ((dfp = fopen(buf, "a")) == 0)
1260 dfp = stderr;
1261 else
1262 (void) chmod(buf, 0666);
1264 debug1("=== ForkWindow: pid %d\n", (int)getpid());
1265 #endif
1266 /* Close the three /dev/null descriptors */
1267 close(0);
1268 close(1);
1269 close(2);
1270 newfd = -1;
1272 * distribute filedescriptors between the ttys
1274 #ifdef PSEUDOS
1275 pat = pwin ? pwin->p_fdpat :
1276 ((F_PFRONT<<(F_PSHIFT*2)) | (F_PFRONT<<F_PSHIFT) | F_PFRONT);
1277 debug1("Using window pattern 0x%x\n", pat);
1278 wfdused = 0;
1279 for(i = 0; i < 3; i++)
1281 if (pat & F_PFRONT << F_PSHIFT * i)
1283 if (newfd < 0)
1285 # ifdef O_NOCTTY
1286 if (separate_sids)
1287 newfd = open(ttyn, O_RDWR);
1288 else
1289 newfd = open(ttyn, O_RDWR|O_NOCTTY);
1290 # else
1291 newfd = open(ttyn, O_RDWR);
1292 # endif
1293 if (newfd < 0)
1294 Panic(errno, "Cannot open %s", ttyn);
1296 else
1297 dup(newfd);
1299 else
1301 dup(win->w_ptyfd);
1302 wfdused = 1;
1305 if (wfdused)
1308 * the pseudo window process should not be surprised with a
1309 * nonblocking filedescriptor. Poor Backend!
1311 debug1("Clearing NBLOCK on window-fd(%d)\n", win->w_ptyfd);
1312 if (fcntl(win->w_ptyfd, F_SETFL, 0))
1313 Msg(errno, "Warning: clear NBLOCK fcntl failed");
1315 #else /* PSEUDOS */
1316 # ifdef O_NOCTTY
1317 if (separate_sids)
1318 newfd = open(ttyn, O_RDWR);
1319 else
1320 newfd = open(ttyn, O_RDWR|O_NOCTTY);
1321 # else
1322 newfd = open(ttyn, O_RDWR);
1323 # endif
1324 if (newfd != 0)
1325 Panic(errno, "Cannot open %s", ttyn);
1326 dup(0);
1327 dup(0);
1328 #endif /* PSEUDOS */
1329 close(win->w_ptyfd);
1330 if (slave != -1)
1331 close(slave);
1332 if (newfd >= 0)
1334 struct mode fakemode, *modep;
1335 InitPTY(newfd);
1336 if (fgtty(newfd))
1337 Msg(errno, "fgtty");
1338 if (display)
1340 debug("ForkWindow: using display tty mode for new child.\n");
1341 modep = &D_OldMode;
1343 else
1345 debug("No display - creating tty setting\n");
1346 modep = &fakemode;
1347 InitTTY(modep, 0);
1348 #ifdef DEBUG
1349 DebugTTY(modep);
1350 #endif
1352 /* We only want echo if the users input goes to the pseudo
1353 * and the pseudo's stdout is not send to the window.
1355 #ifdef PSEUDOS
1356 if (pwin && (!(pat & F_UWP) || (pat & F_PBACK << F_PSHIFT)))
1358 debug1("clearing echo on pseudywin fd (pat %x)\n", pat);
1359 # if defined(POSIX) || defined(TERMIO)
1360 modep->tio.c_lflag &= ~ECHO;
1361 modep->tio.c_iflag &= ~ICRNL;
1362 # else
1363 modep->m_ttyb.sg_flags &= ~ECHO;
1364 # endif
1366 #endif
1367 SetTTY(newfd, modep);
1368 #ifdef TIOCSWINSZ
1369 glwz.ws_col = w;
1370 glwz.ws_row = h;
1371 (void) ioctl(newfd, TIOCSWINSZ, (char *)&glwz);
1372 #endif
1373 /* Always turn off nonblocking mode */
1374 (void)fcntl(newfd, F_SETFL, 0);
1376 #ifndef TIOCSWINSZ
1377 sprintf(libuf, "LINES=%d", h);
1378 sprintf(cobuf, "COLUMNS=%d", w);
1379 NewEnv[5] = libuf;
1380 NewEnv[6] = cobuf;
1381 #endif
1382 #ifdef MAPKEYS
1383 NewEnv[2] = MakeTermcap(display == 0 || win->w_aflag);
1384 #else
1385 if (win->w_aflag)
1386 NewEnv[2] = MakeTermcap(1);
1387 else
1388 NewEnv[2] = Termcap;
1389 #endif
1390 strcpy(shellbuf, "SHELL=");
1391 strncpy(shellbuf + 6, ShellProg + (*ShellProg == '-'), sizeof(shellbuf) - 7);
1392 shellbuf[sizeof(shellbuf) - 1] = 0;
1393 NewEnv[4] = shellbuf;
1394 debug1("ForkWindow: NewEnv[4] = '%s'\n", shellbuf);
1395 if (win->w_term && *win->w_term && strcmp(screenterm, win->w_term) &&
1396 (strlen(win->w_term) < 20))
1398 char *s1, *s2, tl;
1400 sprintf(tebuf, "TERM=%s", win->w_term);
1401 debug2("Makewindow %d with %s\n", win->w_number, tebuf);
1402 tl = strlen(win->w_term);
1403 NewEnv[1] = tebuf;
1404 if ((s1 = index(NewEnv[2], '|')))
1406 if ((s2 = index(++s1, '|')))
1408 if (strlen(NewEnv[2]) - (s2 - s1) + tl < 1024)
1410 bcopy(s2, s1 + tl, strlen(s2) + 1);
1411 bcopy(win->w_term, s1, tl);
1416 sprintf(ebuf, "WINDOW=%d", win->w_number);
1417 NewEnv[3] = ebuf;
1419 if (*proc == '-')
1420 proc++;
1421 if (!*proc)
1422 proc = DefaultShell;
1423 debug1("calling execvpe %s\n", proc);
1424 execvpe(proc, args, NewEnv);
1425 debug1("exec error: %d\n", errno);
1426 Panic(errno, "Cannot exec '%s'", proc);
1427 default:
1428 break;
1430 if (slave != -1)
1431 close(slave);
1432 return pid;
1435 void
1436 execvpe(prog, args, env)
1437 char *prog, **args, **env;
1439 register char *path = NULL, *p;
1440 char buf[1024];
1441 char *shargs[MAXARGS + 1];
1442 register int i, eaccess = 0;
1444 if (rindex(prog, '/'))
1445 path = "";
1446 if (!path && !(path = getenv("PATH")))
1447 path = DefaultPath;
1450 for (p = buf; *path && *path != ':'; path++)
1451 if (p - buf < (int)sizeof(buf) - 2)
1452 *p++ = *path;
1453 if (p > buf)
1454 *p++ = '/';
1455 if (p - buf + strlen(prog) >= sizeof(buf) - 1)
1456 continue;
1457 strcpy(p, prog);
1458 execve(buf, args, env);
1459 switch (errno)
1461 case ENOEXEC:
1462 shargs[0] = DefaultShell;
1463 shargs[1] = buf;
1464 for (i = 1; (shargs[i + 1] = args[i]) != NULL; ++i)
1466 execve(DefaultShell, shargs, env);
1467 return;
1468 case EACCES:
1469 eaccess = 1;
1470 break;
1471 case ENOMEM:
1472 case E2BIG:
1473 case ETXTBSY:
1474 return;
1476 } while (*path++);
1477 if (eaccess)
1478 errno = EACCES;
1481 #ifdef PSEUDOS
1484 winexec(av)
1485 char **av;
1487 char **pp;
1488 char *p, *s, *t;
1489 int i, r = 0, l = 0;
1490 struct win *w;
1491 extern struct display *display;
1492 extern struct win *windows;
1493 struct pseudowin *pwin;
1494 int type;
1496 if ((w = display ? fore : windows) == NULL)
1497 return -1;
1498 if (!*av || w->w_pwin)
1500 Msg(0, "Filter running: %s", w->w_pwin ? w->w_pwin->p_cmd : "(none)");
1501 return -1;
1503 if (w->w_ptyfd < 0)
1505 Msg(0, "You feel dead inside.");
1506 return -1;
1508 if (!(pwin = (struct pseudowin *)malloc(sizeof(struct pseudowin))))
1510 Msg(0, strnomem);
1511 return -1;
1513 bzero((char *)pwin, (int)sizeof(*pwin));
1515 /* allow ^a:!!./ttytest as a short form for ^a:exec !.. ./ttytest */
1516 for (s = *av; *s == ' '; s++)
1518 for (p = s; *p == ':' || *p == '.' || *p == '!'; p++)
1520 if (*p != '|')
1521 while (*p && p > s && p[-1] == '.')
1522 p--;
1523 if (*p == '|')
1525 l = F_UWP;
1526 p++;
1528 if (*p)
1529 av[0] = p;
1530 else
1531 av++;
1533 t = pwin->p_cmd;
1534 for (i = 0; i < 3; i++)
1536 *t = (s < p) ? *s++ : '.';
1537 switch (*t++)
1539 case '.':
1540 case '|':
1541 l |= F_PFRONT << (i * F_PSHIFT);
1542 break;
1543 case '!':
1544 l |= F_PBACK << (i * F_PSHIFT);
1545 break;
1546 case ':':
1547 l |= F_PBOTH << (i * F_PSHIFT);
1548 break;
1552 if (l & F_UWP)
1554 *t++ = '|';
1555 if ((l & F_PMASK) == F_PFRONT)
1557 *pwin->p_cmd = '!';
1558 l ^= F_PFRONT | F_PBACK;
1561 if (!(l & F_PBACK))
1562 l |= F_UWP;
1563 *t++ = ' ';
1564 pwin->p_fdpat = l;
1565 debug1("winexec: '%#x'\n", pwin->p_fdpat);
1567 l = MAXSTR - 4;
1568 for (pp = av; *pp; pp++)
1570 p = *pp;
1571 while (*p && l-- > 0)
1572 *t++ = *p++;
1573 if (l <= 0)
1574 break;
1575 *t++ = ' ';
1577 *--t = '\0';
1578 debug1("%s\n", pwin->p_cmd);
1580 if ((pwin->p_ptyfd = OpenDevice(av, 0, &type, &t)) < 0)
1582 free((char *)pwin);
1583 return -1;
1585 strncpy(pwin->p_tty, t, MAXSTR - 1);
1586 w->w_pwin = pwin;
1587 if (type != W_TYPE_PTY)
1589 FreePseudowin(w);
1590 Msg(0, "Cannot only use commands as pseudo win.");
1591 return -1;
1593 if (!(pwin->p_fdpat & F_PFRONT))
1594 evdeq(&w->w_readev);
1595 #ifdef TIOCPKT
1597 int flag = 0;
1599 if (ioctl(pwin->p_ptyfd, TIOCPKT, (char *)&flag))
1601 Msg(errno, "TIOCPKT pwin ioctl");
1602 FreePseudowin(w);
1603 return -1;
1605 if (w->w_type == W_TYPE_PTY && !(pwin->p_fdpat & F_PFRONT))
1607 if (ioctl(w->w_ptyfd, TIOCPKT, (char *)&flag))
1609 Msg(errno, "TIOCPKT win ioctl");
1610 FreePseudowin(w);
1611 return -1;
1615 #endif /* TIOCPKT */
1617 pwin->p_readev.fd = pwin->p_writeev.fd = pwin->p_ptyfd;
1618 pwin->p_readev.type = EV_READ;
1619 pwin->p_writeev.type = EV_WRITE;
1620 pwin->p_readev.data = pwin->p_writeev.data = (char *)w;
1621 pwin->p_readev.handler = pseu_readev_fn;
1622 pwin->p_writeev.handler = pseu_writeev_fn;
1623 pwin->p_writeev.condpos = &pwin->p_inlen;
1624 if (pwin->p_fdpat & (F_PFRONT << F_PSHIFT * 2 | F_PFRONT << F_PSHIFT))
1625 evenq(&pwin->p_readev);
1626 evenq(&pwin->p_writeev);
1627 r = pwin->p_pid = ForkWindow(w, av, t);
1628 if (r < 0)
1629 FreePseudowin(w);
1630 return r;
1633 void
1634 FreePseudowin(w)
1635 struct win *w;
1637 struct pseudowin *pwin = w->w_pwin;
1639 ASSERT(pwin);
1640 if (fcntl(w->w_ptyfd, F_SETFL, FNBLOCK))
1641 Msg(errno, "Warning: FreePseudowin: NBLOCK fcntl failed");
1642 #ifdef TIOCPKT
1643 if (w->w_type == W_TYPE_PTY && !(pwin->p_fdpat & F_PFRONT))
1645 int flag = 1;
1646 if (ioctl(w->w_ptyfd, TIOCPKT, (char *)&flag))
1647 Msg(errno, "Warning: FreePseudowin: TIOCPKT win ioctl");
1649 #endif
1650 /* should be able to use CloseDevice() here */
1651 (void)chmod(pwin->p_tty, 0666);
1652 (void)chown(pwin->p_tty, 0, 0);
1653 if (pwin->p_ptyfd >= 0)
1654 close(pwin->p_ptyfd);
1655 evdeq(&pwin->p_readev);
1656 evdeq(&pwin->p_writeev);
1657 if (w->w_readev.condneg == &pwin->p_inlen)
1658 w->w_readev.condpos = w->w_readev.condneg = 0;
1659 evenq(&w->w_readev);
1660 free((char *)pwin);
1661 w->w_pwin = NULL;
1664 #endif /* PSEUDOS */
1667 #ifdef MULTIUSER
1669 * returns 0, if the lock really has been released
1672 ReleaseAutoWritelock(dis, w)
1673 struct display *dis;
1674 struct win *w;
1676 debug2("ReleaseAutoWritelock: user %s, window %d\n",
1677 dis->d_user->u_name, w->w_number);
1679 /* release auto writelock when user has no other display here */
1680 if (w->w_wlock == WLOCK_AUTO && w->w_wlockuser == dis->d_user)
1682 struct display *d;
1684 for (d = displays; d; d = d->d_next)
1685 if (( d != dis) && (d->d_fore == w) && (d->d_user == dis->d_user))
1686 break;
1687 debug3("%s %s autolock on win %d\n",
1688 dis->d_user->u_name, d ? "keeps" : "releases", w->w_number);
1689 if (!d)
1691 w->w_wlockuser = NULL;
1692 return 0;
1695 return 1;
1699 * returns 0, if the lock really could be obtained
1702 ObtainAutoWritelock(d, w)
1703 struct display *d;
1704 struct win *w;
1706 if ((w->w_wlock == WLOCK_AUTO) &&
1707 !AclCheckPermWin(d->d_user, ACL_WRITE, w) &&
1708 !w->w_wlockuser)
1710 debug2("%s obtained auto writelock for exported window %d\n",
1711 d->d_user->u_name, w->w_number);
1712 w->w_wlockuser = d->d_user;
1713 return 0;
1715 return 1;
1718 #endif /* MULTIUSER */
1722 /********************************************************************/
1724 #ifdef COPY_PASTE
1725 static void
1726 paste_slowev_fn(ev, data)
1727 struct event *ev;
1728 char *data;
1730 struct paster *pa = (struct paster *)data;
1731 struct win *p;
1733 int l = 1;
1734 flayer = pa->pa_pastelayer;
1735 if (!flayer)
1736 pa->pa_pastelen = 0;
1737 if (!pa->pa_pastelen)
1738 return;
1739 p = Layer2Window(flayer);
1740 DoProcess(p, &pa->pa_pasteptr, &l, pa);
1741 pa->pa_pastelen -= 1 - l;
1742 if (pa->pa_pastelen > 0)
1744 SetTimeout(&pa->pa_slowev, p->w_slowpaste);
1745 evenq(&pa->pa_slowev);
1748 #endif
1751 static int
1752 muchpending(p, ev)
1753 struct win *p;
1754 struct event *ev;
1756 struct canvas *cv;
1757 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
1759 display = cv->c_display;
1760 if (D_status == STATUS_ON_WIN && !D_status_bell)
1762 /* wait 'til status is gone */
1763 debug("BLOCKING because of status\n");
1764 ev->condpos = &const_one;
1765 ev->condneg = &D_status;
1766 return 1;
1768 debug2("muchpending %s %d: ", D_usertty, D_blocked);
1769 debug3("%d %d %d\n", D_obufp - D_obuf, D_obufmax, D_blocked_fuzz);
1770 if (D_blocked)
1771 continue;
1772 if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
1774 if (D_nonblock == 0)
1776 debug1("obuf is full, stopping output to display %s\n", D_usertty);
1777 D_blocked = 1;
1778 continue;
1780 debug("BLOCKING because of full obuf\n");
1781 ev->condpos = &D_obuffree;
1782 ev->condneg = &D_obuflenmax;
1783 if (D_nonblock > 0 && !D_blockedev.queued)
1785 debug1("created timeout of %g secs\n", D_nonblock/1000.);
1786 SetTimeout(&D_blockedev, D_nonblock);
1787 evenq(&D_blockedev);
1789 return 1;
1792 return 0;
1795 static void
1796 win_readev_fn(ev, data)
1797 struct event *ev;
1798 char *data;
1800 struct win *p = (struct win *)data;
1801 char buf[IOSIZE], *bp;
1802 int size, len;
1803 #ifdef PSEUDOS
1804 int wtop;
1805 #endif
1807 bp = buf;
1808 size = IOSIZE;
1810 #ifdef PSEUDOS
1811 wtop = p->w_pwin && W_WTOP(p);
1812 if (wtop)
1814 ASSERT(sizeof(p->w_pwin->p_inbuf) == IOSIZE);
1815 size = IOSIZE - p->w_pwin->p_inlen;
1816 if (size <= 0)
1818 ev->condpos = &const_IOSIZE;
1819 ev->condneg = &p->w_pwin->p_inlen;
1820 return;
1823 #endif
1824 if (p->w_layer.l_cvlist && muchpending(p, ev))
1825 return;
1826 #ifdef ZMODEM
1827 if (!p->w_zdisplay)
1828 #endif
1829 if (p->w_blocked)
1831 ev->condpos = &const_one;
1832 ev->condneg = &p->w_blocked;
1833 return;
1835 if (ev->condpos)
1836 ev->condpos = ev->condneg = 0;
1838 if ((len = p->w_outlen))
1840 p->w_outlen = 0;
1841 WriteString(p, p->w_outbuf, len);
1842 return;
1845 debug1("going to read from window fd %d\n", ev->fd);
1846 if ((len = read(ev->fd, buf, size)) < 0)
1848 if (errno == EINTR || errno == EAGAIN)
1849 return;
1850 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1851 if (errno == EWOULDBLOCK)
1852 return;
1853 #endif
1854 debug2("Window %d: read error (errno %d) - killing window\n", p->w_number, errno);
1855 WindowDied(p, 0, 0);
1856 return;
1858 if (len == 0)
1860 debug1("Window %d: EOF - killing window\n", p->w_number);
1861 WindowDied(p, 0, 0);
1862 return;
1864 debug1(" -> %d bytes\n", len);
1865 #ifdef TIOCPKT
1866 if (p->w_type == W_TYPE_PTY)
1868 if (buf[0])
1870 debug1("PAKET %x\n", buf[0]);
1871 if (buf[0] & TIOCPKT_NOSTOP)
1872 WNewAutoFlow(p, 0);
1873 if (buf[0] & TIOCPKT_DOSTOP)
1874 WNewAutoFlow(p, 1);
1876 bp++;
1877 len--;
1879 #endif
1880 #ifdef BUILTIN_TELNET
1881 if (p->w_type == W_TYPE_TELNET)
1882 len = TelIn(p, bp, len, buf + sizeof(buf) - (bp + len));
1883 #endif
1884 if (len == 0)
1885 return;
1886 #ifdef ZMODEM
1887 if (zmodem_mode && zmodem_parse(p, bp, len))
1888 return;
1889 #endif
1890 #ifdef PSEUDOS
1891 if (wtop)
1893 debug("sending input to pwin\n");
1894 bcopy(bp, p->w_pwin->p_inbuf + p->w_pwin->p_inlen, len);
1895 p->w_pwin->p_inlen += len;
1897 #endif
1898 WriteString(p, bp, len);
1899 return;
1903 static void
1904 win_writeev_fn(ev, data)
1905 struct event *ev;
1906 char *data;
1908 struct win *p = (struct win *)data;
1909 int len;
1910 if (p->w_inlen)
1912 debug2("writing %d bytes to win %d\n", p->w_inlen, p->w_number);
1913 if ((len = write(ev->fd, p->w_inbuf, p->w_inlen)) <= 0)
1914 len = p->w_inlen; /* dead window */
1915 if ((p->w_inlen -= len))
1916 bcopy(p->w_inbuf + len, p->w_inbuf, p->w_inlen);
1918 #ifdef COPY_PASTE
1919 if (p->w_paster.pa_pastelen && !p->w_slowpaste)
1921 struct paster *pa = &p->w_paster;
1922 flayer = pa->pa_pastelayer;
1923 if (flayer)
1924 DoProcess(p, &pa->pa_pasteptr, &pa->pa_pastelen, pa);
1926 #endif
1927 return;
1932 #ifdef PSEUDOS
1934 static void
1935 pseu_readev_fn(ev, data)
1936 struct event *ev;
1937 char *data;
1939 struct win *p = (struct win *)data;
1940 char buf[IOSIZE];
1941 int size, ptow, len;
1943 size = IOSIZE;
1945 ptow = W_PTOW(p);
1946 if (ptow)
1948 ASSERT(sizeof(p->w_inbuf) == IOSIZE);
1949 size = IOSIZE - p->w_inlen;
1950 if (size <= 0)
1952 ev->condpos = &const_IOSIZE;
1953 ev->condneg = &p->w_inlen;
1954 return;
1957 if (p->w_layer.l_cvlist && muchpending(p, ev))
1958 return;
1959 if (p->w_blocked)
1961 ev->condpos = &const_one;
1962 ev->condneg = &p->w_blocked;
1963 return;
1965 if (ev->condpos)
1966 ev->condpos = ev->condneg = 0;
1968 if ((len = p->w_outlen))
1970 p->w_outlen = 0;
1971 WriteString(p, p->w_outbuf, len);
1972 return;
1975 if ((len = read(ev->fd, buf, size)) <= 0)
1977 if (errno == EINTR || errno == EAGAIN)
1978 return;
1979 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1980 if (errno == EWOULDBLOCK)
1981 return;
1982 #endif
1983 debug2("Window %d: pseudowin read error (errno %d) -- removing pseudowin\n", p->w_number, len ? errno : 0);
1984 FreePseudowin(p);
1985 return;
1987 /* no packet mode on pseudos! */
1988 if (ptow)
1990 bcopy(buf, p->w_inbuf + p->w_inlen, len);
1991 p->w_inlen += len;
1993 WriteString(p, buf, len);
1994 return;
1997 static void
1998 pseu_writeev_fn(ev, data)
1999 struct event *ev;
2000 char *data;
2002 struct win *p = (struct win *)data;
2003 struct pseudowin *pw = p->w_pwin;
2004 int len;
2006 ASSERT(pw);
2007 if (pw->p_inlen == 0)
2008 return;
2009 if ((len = write(ev->fd, pw->p_inbuf, pw->p_inlen)) <= 0)
2010 len = pw->p_inlen; /* dead pseudo */
2011 if ((p->w_pwin->p_inlen -= len))
2012 bcopy(p->w_pwin->p_inbuf + len, p->w_pwin->p_inbuf, p->w_pwin->p_inlen);
2016 #endif /* PSEUDOS */
2018 static void
2019 win_silenceev_fn(ev, data)
2020 struct event *ev;
2021 char *data;
2023 struct win *p = (struct win *)data;
2024 struct canvas *cv;
2025 debug1("FOUND silence win %d\n", p->w_number);
2026 for (display = displays; display; display = display->d_next)
2028 for (cv = D_cvlist; cv; cv = cv->c_next)
2029 if (cv->c_layer->l_bottom == &p->w_layer)
2030 break;
2031 if (cv)
2032 continue; /* user already sees window */
2033 #ifdef MULTIUSER
2034 if (!(ACLBYTE(p->w_lio_notify, D_user->u_id) & ACLBIT(D_user->u_id)))
2035 continue;
2036 #endif
2037 Msg(0, "Window %d: silence for %d seconds", p->w_number, p->w_silencewait);
2041 #ifdef ZMODEM
2043 static int
2044 zmodem_parse(p, bp, len)
2045 struct win *p;
2046 char *bp;
2047 int len;
2049 int i;
2050 char *b2 = bp;
2051 for (i = 0; i < len; i++, b2++)
2053 if (p->w_zauto == 0)
2055 for (; i < len; i++, b2++)
2056 if (*b2 == 030)
2057 break;
2058 if (i == len)
2059 break;
2060 if (i > 1 && b2[-1] == '*' && b2[-2] == '*')
2061 p->w_zauto = 3;
2062 continue;
2064 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'))
2066 if (++p->w_zauto < 6)
2067 continue;
2068 if (p->w_zauto == 6)
2069 p->w_zauto = 0;
2070 if (!p->w_zdisplay)
2072 if (i > 6)
2073 WriteString(p, bp, i + 1 - 6);
2074 WriteString(p, "\r\n", 2);
2075 zmodem_found(p, *b2 == '1', b2 + 1, len - i - 1);
2076 return 1;
2078 else if (p->w_zauto == 7 || *b2 == '8')
2080 int se = p->w_zdisplay->d_blocked == 2 ? 'O' : '\212';
2081 for (; i < len; i++, b2++)
2082 if (*b2 == se)
2083 break;
2084 if (i < len)
2086 zmodem_abort(p, 0);
2087 D_blocked = 0;
2088 D_readev.condpos = D_readev.condneg = 0;
2089 while (len-- > 0)
2090 AddChar(*bp++);
2091 Flush();
2092 Activate(D_fore ? D_fore->w_norefresh : 0);
2093 return 1;
2095 p->w_zauto = 6;
2098 else
2099 p->w_zauto = *b2 == '*' ? (p->w_zauto == 2 ? 2 : 1) : 0;
2101 if (p->w_zauto == 0 && bp[len - 1] == '*')
2102 p->w_zauto = len > 1 && bp[len - 2] == '*' ? 2 : 1;
2103 if (p->w_zdisplay)
2105 display = p->w_zdisplay;
2106 while (len-- > 0)
2107 AddChar(*bp++);
2108 return 1;
2110 return 0;
2113 static void
2114 zmodem_fin(buf, len, data)
2115 char *buf;
2116 int len;
2117 char *data;
2119 char *s;
2120 int n;
2122 if (len)
2123 RcLine(buf, strlen(buf) + 1);
2124 else
2126 s = "\030\030\030\030\030\030\030\030\030\030";
2127 n = strlen(s);
2128 LayProcess(&s, &n);
2132 static void
2133 zmodem_found(p, send, bp, len)
2134 struct win *p;
2135 int send;
2136 char *bp;
2137 int len;
2139 char *s;
2140 int i, n;
2141 extern int zmodem_mode;
2143 /* check for abort sequence */
2144 n = 0;
2145 for (i = 0; i < len ; i++)
2146 if (bp[i] != 030)
2147 n = 0;
2148 else if (++n > 4)
2149 return;
2150 if (zmodem_mode == 3 || (zmodem_mode == 1 && p->w_type != W_TYPE_PLAIN))
2152 struct display *d, *olddisplay;
2154 olddisplay = display;
2155 d = p->w_lastdisp;
2156 if (!d || d->d_fore != p)
2157 for (d = displays; d; d = d->d_next)
2158 if (d->d_fore == p)
2159 break;
2160 if (!d && p->w_layer.l_cvlist)
2161 d = p->w_layer.l_cvlist->c_display;
2162 if (!d)
2163 d = displays;
2164 if (!d)
2165 return;
2166 display = d;
2167 RemoveStatus();
2168 p->w_zdisplay = display;
2169 D_blocked = 2 + send;
2170 flayer = &p->w_layer;
2171 ZmodemPage();
2172 display = d;
2173 evdeq(&D_blockedev);
2174 D_readev.condpos = &const_IOSIZE;
2175 D_readev.condneg = &p->w_inlen;
2176 ClearAll();
2177 GotoPos(0, 0);
2178 SetRendition(&mchar_blank);
2179 AddStr("Zmodem active\r\n\r\n");
2180 AddStr(send ? "**\030B01" : "**\030B00");
2181 while (len-- > 0)
2182 AddChar(*bp++);
2183 display = olddisplay;
2184 return;
2186 flayer = &p->w_layer;
2187 Input(":", 100, INP_COOKED, zmodem_fin, NULL, 0);
2188 s = send ? zmodem_sendcmd : zmodem_recvcmd;
2189 n = strlen(s);
2190 LayProcess(&s, &n);
2193 void
2194 zmodem_abort(p, d)
2195 struct win *p;
2196 struct display *d;
2198 struct display *olddisplay = display;
2199 struct layer *oldflayer = flayer;
2200 if (p)
2202 if (p->w_savelayer && p->w_savelayer->l_next)
2204 if (oldflayer == p->w_savelayer)
2205 oldflayer = flayer->l_next;
2206 flayer = p->w_savelayer;
2207 ExitOverlayPage();
2209 p->w_zdisplay = 0;
2210 p->w_zauto = 0;
2211 LRefreshAll(&p->w_layer, 0);
2213 if (d)
2215 display = d;
2216 D_blocked = 0;
2217 D_readev.condpos = D_readev.condneg = 0;
2218 Activate(D_fore ? D_fore->w_norefresh : 0);
2220 display = olddisplay;
2221 flayer = oldflayer;
2224 #endif