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