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