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
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)
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.
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 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
29 ****************************************************************
32 #include <sys/types.h>
37 # include <sys/ioctl.h>
44 #include "logfile.h" /* logfopen() */
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
[];
54 extern int SilenceWait
;
55 extern int real_uid
, real_gid
, eff_uid
, eff_gid
;
56 extern char Termcap
[];
58 extern int visual_bell
, maxwin
;
59 extern struct event logflushev
;
60 extern int log_flush
, logtstamp_after
;
61 extern int ZombieKey_destroy
, ZombieKey_resurrect
, ZombieKey_onerror
;
62 extern struct layer
*flayer
;
63 extern int maxusercount
;
64 extern int pty_preopen
;
66 extern int zmodem_mode
;
67 extern struct mchar mchar_blank
;
68 extern char *zmodem_sendcmd
;
69 extern char *zmodem_recvcmd
;
72 #if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
73 extern struct winsize glwz
;
77 extern int separate_sids
;
80 static void WinProcess
__P((char **, int *));
81 static void WinRedisplayLine
__P((int, int, int, int));
82 static void WinClearLine
__P((int, int, int, int));
83 static int WinRewrite
__P((int, int, int, struct mchar
*, int));
84 static int WinResize
__P((int, int));
85 static void WinRestore
__P((void));
86 static int DoAutolf
__P((char *, int *, int));
87 static void ZombieProcess
__P((char **, int *));
88 static void win_readev_fn
__P((struct event
*, char *));
89 static void win_writeev_fn
__P((struct event
*, char *));
90 static int muchpending
__P((struct win
*, struct event
*));
92 static void paste_slowev_fn
__P((struct event
*, char *));
95 static void pseu_readev_fn
__P((struct event
*, char *));
96 static void pseu_writeev_fn
__P((struct event
*, char *));
98 static void win_silenceev_fn
__P((struct event
*, char *));
99 static void win_destroyev_fn
__P((struct event
*, char *));
101 static int OpenDevice
__P((char **, int, int *, char **));
102 static int ForkWindow
__P((struct win
*, char **, char *));
104 static void zmodem_found
__P((struct win
*, int, char *, int));
105 static void zmodem_fin
__P((char *, int, char *));
106 static int zmodem_parse
__P((struct win
*, char *, int));
110 struct win
**wtab
; /* window table */
112 int VerboseCreate
= 0; /* XXX move this to user.h */
114 char DefaultShell
[] = "/bin/sh";
115 static char DefaultPath
[] = ":/usr/ucb:/bin:/usr/bin";
117 /* keep this in sync with the structure definition in window.h */
118 struct NewWindow nwin_undef
=
122 (char **)0, /* args */
124 (char *)0, /* term */
139 (char *)0, /* hstatus */
140 (char *)0 /* charset */
143 struct NewWindow nwin_default
=
147 ShellArgs
, /* args */
149 screenterm
, /* term */
151 1*FLOW_NOW
, /* flowflag */
152 LOGINDEFAULT
, /* lflag */
153 DEFAULTHISTHEIGHT
, /* histheight */
154 MON_OFF
, /* monitor */
155 WLOCK_OFF
, /* wlock */
164 (char *)0, /* hstatus */
165 (char *)0 /* charset */
168 struct NewWindow nwin_options
;
170 static int const_IOSIZE
= IOSIZE
;
171 static int const_one
= 1;
174 nwin_compose(def
, new, res
)
175 struct NewWindow
*def
, *new, *res
;
177 #define COMPOSE(x) res->x = new->x != nwin_undef.x ? new->x : def->x
202 /*****************************************************************
204 * The window layer functions
207 struct LayFuncs WinLf
=
220 DoAutolf(buf
, lenp
, fr
)
229 for (p
= buf
; len
> 0; p
++, len
--)
240 bcopy(p
, p
+ 1, len
++);
248 WinProcess(bufpp
, lenp
)
252 int l2
= 0, f
, *ilen
, l
= *lenp
, trunc
;
255 debug1("WinProcess: %d bytes\n", *lenp
);
256 fore
= (struct win
*)flayer
->l_data
;
258 if (fore
->w_type
== W_TYPE_GROUP
)
264 if (fore
->w_ptyfd
< 0) /* zombie? */
266 ZombieProcess(bufpp
, lenp
);
270 /* a pending writelock is this:
271 * fore->w_wlock == WLOCK_AUTO, fore->w_wlockuse = NULL
272 * The user who wants to use this window next, will get the lock, if he can.
274 if (display
&& fore
->w_wlock
== WLOCK_AUTO
&&
275 !fore
->w_wlockuser
&& !AclCheckPermWin(D_user
, ACL_WRITE
, fore
))
277 fore
->w_wlockuser
= D_user
;
278 debug2("window %d: pending writelock grabbed by user %s\n",
279 fore
->w_number
, fore
->w_wlockuser
->u_name
);
281 /* if w_wlock is set, only one user may write, else we check acls */
282 if (display
&& ((fore
->w_wlock
== WLOCK_OFF
) ?
283 AclCheckPermWin(D_user
, ACL_WRITE
, fore
) :
284 (D_user
!= fore
->w_wlockuser
)))
286 debug2("window %d, user %s: ", fore
->w_number
, D_user
->u_name
);
287 debug2("writelock %d (wlockuser %s)\n", fore
->w_wlock
,
288 fore
->w_wlockuser
? fore
->w_wlockuser
->u_name
: "NULL");
289 Msg(0, "write: permission denied (user %s)", D_user
->u_name
);
294 #endif /* MULTIUSER */
296 #ifdef BUILTIN_TELNET
297 if (fore
->w_type
== W_TYPE_TELNET
&& TelIsline(fore
) && *bufpp
!= fore
->w_telbuf
)
299 TelProcessLine(bufpp
, lenp
);
307 /* we send the user input to our pseudowin */
308 ibuf
= fore
->w_pwin
->p_inbuf
; ilen
= &fore
->w_pwin
->p_inlen
;
309 f
= sizeof(fore
->w_pwin
->p_inbuf
) - *ilen
;
314 /* we send the user input to the window */
315 ibuf
= fore
->w_inbuf
; ilen
= &fore
->w_inlen
;
316 f
= sizeof(fore
->w_inbuf
) - *ilen
;
321 #ifdef BUILTIN_TELNET
328 bcopy(*bufpp
, ibuf
+ *ilen
, l2
);
329 if (fore
->w_autolf
&& (trunc
= DoAutolf(ibuf
+ *ilen
, &l2
, f
- l2
)))
331 #ifdef BUILTIN_TELNET
332 if (fore
->w_type
== W_TYPE_TELNET
&& (trunc
= DoTelnet(ibuf
+ *ilen
, &l2
, f
- l2
)))
336 continue; /* need exact value */
347 ZombieProcess(bufpp
, lenp
)
352 char *buf
= *bufpp
, b1
[10], b2
[10];
354 debug1("ZombieProcess: %d bytes\n", *lenp
);
355 fore
= (struct win
*)flayer
->l_data
;
357 ASSERT(fore
->w_ptyfd
< 0);
360 for (; l
-- > 0; buf
++)
362 if (*(unsigned char *)buf
== ZombieKey_destroy
)
364 debug1("Turning undead: %d\n", fore
->w_number
);
368 if (*(unsigned char *)buf
== ZombieKey_resurrect
)
370 debug1("Resurrecting Zombie: %d\n", fore
->w_number
);
371 WriteString(fore
, "\r\n", 2);
376 b1
[AddXChar(b1
, ZombieKey_destroy
)] = '\0';
377 b2
[AddXChar(b2
, ZombieKey_resurrect
)] = '\0';
378 Msg(0, "Press %s to destroy or %s to resurrect window", b1
, b2
);
382 WinRedisplayLine(y
, from
, to
, isblank
)
383 int y
, from
, to
, isblank
;
385 debug3("WinRedisplayLine %d %d %d\n", y
, from
, to
);
388 fore
= (struct win
*)flayer
->l_data
;
389 if (from
== 0 && y
> 0 && fore
->w_mlines
[y
- 1].image
[fore
->w_width
] == 0)
390 LCDisplayLineWrap(&fore
->w_layer
, &fore
->w_mlines
[y
], y
, from
, to
, isblank
);
392 LCDisplayLine(&fore
->w_layer
, &fore
->w_mlines
[y
], y
, from
, to
, isblank
);
396 WinRewrite(y
, x1
, x2
, rend
, doit
)
400 register int cost
, dx
;
401 register unsigned char *p
, *i
;
403 register unsigned char *f
;
406 register unsigned char *c
;
408 register unsigned char *cx
;
412 debug3("WinRewrite %d, %d-%d\n", y
, x1
, x2
);
413 fore
= (struct win
*)flayer
->l_data
;
417 i
= fore
->w_mlines
[y
].image
+ x1
;
422 p
= fore
->w_mlines
[y
].attr
+ x1
;
424 f
= fore
->w_mlines
[y
].font
+ x1
;
426 if (is_dw_font(rend
->font
))
430 if (fore
->w_encoding
&& fore
->w_encoding
!= UTF8
&& D_encoding
== UTF8
&& ContainsSpecialDeffont(fore
->w_mlines
+ y
, x1
, x2
, fore
->w_encoding
))
435 c
= fore
->w_mlines
[y
].color
+ x1
;
437 cx
= fore
->w_mlines
[y
].colorx
+ x1
;
441 cost
= dx
= x2
- x1
+ 1;
444 if (*p
++ != rend
->attr
)
447 if (*f
++ != rend
->font
)
451 if (*c
++ != rend
->color
)
454 if (*cx
++ != rend
->colorx
)
463 WinClearLine(y
, xs
, xe
, bce
)
466 fore
= (struct win
*)flayer
->l_data
;
467 debug3("WinClearLine %d %d-%d\n", y
, xs
, xe
);
468 LClearLine(flayer
, y
, xs
, xe
, bce
, &fore
->w_mlines
[y
]);
475 fore
= (struct win
*)flayer
->l_data
;
476 ChangeWindowSize(fore
, wi
, he
, fore
->w_histheight
);
484 fore
= (struct win
*)flayer
->l_data
;
485 debug1("WinRestore: win %p\n", fore
);
486 for (cv
= flayer
->l_cvlist
; cv
; cv
= cv
->c_next
)
488 display
= cv
->c_display
;
491 /* ChangeScrollRegion(fore->w_top, fore->w_bot); */
492 KeypadMode(fore
->w_keypad
);
493 CursorkeysMode(fore
->w_cursorkeys
);
494 SetFlow(fore
->w_flow
& FLOW_NOW
);
495 InsertMode(fore
->w_insert
);
496 ReverseVideo(fore
->w_revvid
);
497 CursorVisibility(fore
->w_curinv
? -1 : fore
->w_curvvis
);
498 MouseMode(fore
->w_mouse
);
502 /*****************************************************************/
506 * DoStartLog constructs a path for the "want to be logfile" in buf and
509 * returns 0 on success.
512 DoStartLog(w
, buf
, bufsize
)
521 strncpy(buf
, MakeWinMsg(screenlogfile
, w
, '%'), bufsize
- 1);
522 buf
[bufsize
- 1] = 0;
524 debug2("DoStartLog: win %d, file %s\n", w
->w_number
, buf
);
526 if (w
->w_log
!= NULL
)
529 if ((w
->w_log
= logfopen(buf
, islogfile(buf
) ? NULL
: secfopen(buf
, "a"))) == NULL
)
531 if (!logflushev
.queued
)
533 n
= log_flush
? log_flush
: (logtstamp_after
+ 4) / 5;
536 SetTimeout(&logflushev
, n
* 1000);
544 * Umask & wlock are set for the user of the display,
545 * The display d (if specified) switches to that window.
549 struct NewWindow
*newwin
;
551 register struct win
**pp
, *p
;
554 struct NewWindow nwin
;
558 extern struct acluser
*users
;
565 wtab
= calloc(maxwin
, sizeof(struct win
*));
568 debug1("NewWindow: StartAt %d\n", newwin
->StartAt
);
569 debug1("NewWindow: aka %s\n", newwin
->aka
?newwin
->aka
:"NULL");
570 debug1("NewWindow: dir %s\n", newwin
->dir
?newwin
->dir
:"NULL");
571 debug1("NewWindow: term %s\n", newwin
->term
?newwin
->term
:"NULL");
573 nwin_compose(&nwin_default
, newwin
, &nwin
);
574 debug1("NWin: aka %s\n", nwin
.aka
? nwin
.aka
: "NULL");
575 debug1("NWin: wlock %d\n", nwin
.wlock
);
576 debug1("NWin: Lflag %d\n", nwin
.Lflag
);
578 startat
= nwin
.StartAt
< maxwin
? nwin
.StartAt
: 0;
585 if (++pp
== wtab
+ maxwin
)
588 while (pp
!= wtab
+ startat
);
591 Msg(0, "No more windows.");
595 #if defined(USRLIMIT) && defined(UTMPOK)
597 * Count current number of users, if logging windows in.
599 if (nwin
.lflag
&& CountUsers() >= USRLIMIT
)
601 Msg(0, "User limit reached. Window will not be logged in.");
606 debug1("Makewin creating %d\n", n
);
608 if ((f
= OpenDevice(nwin
.args
, nwin
.lflag
, &type
, &TtyName
)) < 0)
610 if (type
== W_TYPE_GROUP
)
613 if ((p
= (struct win
*)calloc(1, sizeof(struct win
))) == 0)
621 if (type
!= W_TYPE_PTY
)
627 /* save the command line so that zombies can be resurrected */
628 for (i
= 0; nwin
.args
[i
] && i
< MAXARGS
- 1; i
++)
629 p
->w_cmdargs
[i
] = SaveStr(nwin
.args
[i
]);
632 p
->w_dir
= SaveStr(nwin
.dir
);
634 p
->w_term
= SaveStr(nwin
.term
);
638 if (fore
&& fore
->w_type
== W_TYPE_GROUP
)
640 else if (fore
&& fore
->w_group
)
641 p
->w_group
= fore
->w_group
;
644 * This is dangerous: without a display we use creators umask
645 * This is intended to be usefull for detached startup.
646 * But is still better than default bits with a NULL user.
648 if (NewWindowAcl(p
, display
? D_user
: users
))
656 p
->w_layer
.l_next
= 0;
657 p
->w_layer
.l_bottom
= &p
->w_layer
;
658 p
->w_layer
.l_layfn
= &WinLf
;
659 p
->w_layer
.l_data
= (char *)p
;
660 p
->w_savelayer
= &p
->w_layer
;
665 if (display
&& !AclCheckPermWin(D_user
, ACL_WRITE
, p
))
666 p
->w_wlockuser
= D_user
;
667 p
->w_wlock
= nwin
.wlock
;
670 p
->w_aflag
= nwin
.aflag
;
671 p
->w_flow
= nwin
.flowflag
| ((nwin
.flowflag
& FLOW_AUTOFLAG
) ? (FLOW_AUTO
|FLOW_NOW
) : FLOW_AUTO
);
673 nwin
.aka
= Filename(nwin
.args
[0]);
674 strncpy(p
->w_akabuf
, nwin
.aka
, sizeof(p
->w_akabuf
) - 1);
675 if ((nwin
.aka
= rindex(p
->w_akabuf
, '|')) != NULL
)
679 p
->w_title
= nwin
.aka
;
680 p
->w_akachange
= nwin
.aka
+ strlen(nwin
.aka
);
683 p
->w_title
= p
->w_akachange
= p
->w_akabuf
;
685 p
->w_hstatus
= SaveStr(nwin
.hstatus
);
686 p
->w_monitor
= nwin
.monitor
;
688 if (p
->w_monitor
== MON_ON
)
690 /* always tell all users */
691 for (i
= 0; i
< maxusercount
; i
++)
692 ACLBYTE(p
->w_mon_notify
, i
) |= ACLBIT(i
);
696 * defsilence by Lloyd Zusman (zusman_lloyd@jpmorgan.com)
698 p
->w_silence
= nwin
.silence
;
699 p
->w_silencewait
= SilenceWait
;
701 if (p
->w_silence
== SILENCE_ON
)
703 /* always tell all users */
704 for (i
= 0; i
< maxusercount
; i
++)
705 ACLBYTE(p
->w_lio_notify
, i
) |= ACLBIT(i
);
709 p
->w_slowpaste
= nwin
.slow
;
715 strncpy(p
->w_tty
, TtyName
, MAXSTR
- 1);
718 /* XXX Fixme display resize */
719 if (ChangeWindowSize(p
, display
? D_defwidth
: 80,
720 display
? D_defheight
: 24,
727 if (ChangeWindowSize(p
, display
? D_forecv
->c_xe
- D_forecv
->c_xs
+ 1: 80,
728 display
? D_forecv
->c_ye
- D_forecv
->c_ys
+ 1 : 24,
736 p
->w_encoding
= nwin
.encoding
;
737 ResetWindow(p
); /* sets w_wrap, w_c1, w_gr, w_bce */
741 SetCharsets(p
, nwin
.charset
);
744 if (VerboseCreate
&& type
!= W_TYPE_GROUP
)
746 struct display
*d
= display
; /* WriteString zaps display */
748 WriteString(p
, ":screen (", 9);
749 WriteString(p
, p
->w_title
, strlen(p
->w_title
));
750 WriteString(p
, "):", 2);
751 for (f
= 0; p
->w_cmdargs
[f
]; f
++)
753 WriteString(p
, " ", 1);
754 WriteString(p
, p
->w_cmdargs
[f
], strlen(p
->w_cmdargs
[f
]));
756 WriteString(p
, "\r\n", 2);
766 #ifdef BUILTIN_TELNET
767 if (type
== W_TYPE_TELNET
)
777 if (type
== W_TYPE_PTY
)
779 p
->w_pid
= ForkWindow(p
, nwin
.args
, TtyName
);
788 * Place the new window at the head of the most-recently-used list.
790 if (display
&& D_fore
)
796 if (type
== W_TYPE_GROUP
)
799 Activate(p
->w_norefresh
);
800 WindowChanged((struct win
*)0, 'w');
801 WindowChanged((struct win
*)0, 'W');
802 WindowChanged((struct win
*)0, 0);
806 p
->w_lflag
= nwin
.lflag
;
808 p
->w_slot
= (slot_t
)-1;
810 debug1("MakeWindow will %slog in.\n", nwin
.lflag
?"":"not ");
812 # else /* LOGOUTOK */
813 debug1("MakeWindow will log in, LOGOUTOK undefined in config.h%s.\n",
814 nwin
.lflag
?"":" (although lflag=0)");
815 # endif /* LOGOUTOK */
817 p
->w_slot
= (slot_t
)0;
818 if (display
|| (p
->w_lflag
& 2))
822 CarefulUtmp(); /* If all 've been zombies, we've had no slot */
829 DoStartLog(p
, buf
, sizeof(buf
));
832 p
->w_readev
.fd
= p
->w_writeev
.fd
= p
->w_ptyfd
;
833 p
->w_readev
.type
= EV_READ
;
834 p
->w_writeev
.type
= EV_WRITE
;
835 p
->w_readev
.data
= p
->w_writeev
.data
= (char *)p
;
836 p
->w_readev
.handler
= win_readev_fn
;
837 p
->w_writeev
.handler
= win_writeev_fn
;
838 p
->w_writeev
.condpos
= &p
->w_inlen
;
840 evenq(&p
->w_writeev
);
842 p
->w_paster
.pa_slowev
.type
= EV_TIMEOUT
;
843 p
->w_paster
.pa_slowev
.data
= (char *)&p
->w_paster
;
844 p
->w_paster
.pa_slowev
.handler
= paste_slowev_fn
;
846 p
->w_silenceev
.type
= EV_TIMEOUT
;
847 p
->w_silenceev
.data
= (char *)p
;
848 p
->w_silenceev
.handler
= win_silenceev_fn
;
849 if (p
->w_silence
> 0)
851 debug("New window has silence enabled.\n");
852 SetTimeout(&p
->w_silenceev
, p
->w_silencewait
* 1000);
853 evenq(&p
->w_silenceev
);
855 p
->w_destroyev
.type
= EV_TIMEOUT
;
856 p
->w_destroyev
.data
= 0;
857 p
->w_destroyev
.handler
= win_destroyev_fn
;
860 Activate(p
->w_norefresh
);
861 WindowChanged((struct win
*)0, 'w');
862 WindowChanged((struct win
*)0, 'W');
863 WindowChanged((struct win
*)0, 0);
868 * Resurrect a window from Zombie state.
869 * The command vector is therefore stored in the window structure.
870 * Note: The terminaltype defaults to screenterm again, the current
871 * working directory is lost.
880 lflag
= nwin_default
.lflag
;
881 if ((f
= OpenDevice(p
->w_cmdargs
, lflag
, &p
->w_type
, &TtyName
)) < 0)
884 strncpy(p
->w_tty
, *TtyName
? TtyName
: p
->w_title
, MAXSTR
- 1);
889 evenq(&p
->w_writeev
);
893 struct display
*d
= display
; /* WriteString zaps display */
895 WriteString(p
, ":screen (", 9);
896 WriteString(p
, p
->w_title
, strlen(p
->w_title
));
897 WriteString(p
, "):", 2);
898 for (f
= 0; p
->w_cmdargs
[f
]; f
++)
900 WriteString(p
, " ", 1);
901 WriteString(p
, p
->w_cmdargs
[f
], strlen(p
->w_cmdargs
[f
]));
903 WriteString(p
, "\r\n", 2);
909 #ifdef BUILTIN_TELNET
910 if (p
->w_type
== W_TYPE_TELNET
)
917 if (p
->w_type
== W_TYPE_PTY
)
919 p
->w_pid
= ForkWindow(p
, p
->w_cmdargs
, TtyName
);
925 if (p
->w_slot
== (slot_t
)0 && (display
|| (p
->w_lflag
& 2)))
928 CarefulUtmp(); /* If all 've been zombies, we've had no slot */
931 WindowChanged(p
, 'f');
941 if (wp
->w_type
== W_TYPE_PTY
)
944 (void)chmod(wp
->w_tty
, 0666);
945 (void)chown(wp
->w_tty
, 0, 0);
950 evdeq(&wp
->w_readev
);
951 evdeq(&wp
->w_writeev
);
952 #ifdef BUILTIN_TELNET
953 evdeq(&wp
->w_telconnev
);
955 wp
->w_readev
.fd
= wp
->w_writeev
.fd
= -1;
964 struct canvas
*cv
, *ncv
;
967 debug1("FreeWindow %d\n", wp
? wp
->w_number
: -1);
977 if (wp
== console_window
)
979 TtyGrabConsole(-1, -1, "free");
982 if (wp
->w_log
!= NULL
)
983 logfclose(wp
->w_log
);
984 ChangeWindowSize(wp
, 0, 0, 0);
986 if (wp
->w_type
== W_TYPE_GROUP
)
989 for (win
= windows
; win
; win
= win
->w_next
)
990 if (win
->w_group
== wp
)
991 win
->w_group
= wp
->w_group
;
996 for (i
= 0; wp
->w_cmdargs
[i
]; i
++)
997 free(wp
->w_cmdargs
[i
]);
1002 for (d
= displays
; d
; d
= d
->d_next
)
1004 if (d
->d_other
== wp
)
1005 d
->d_other
= d
->d_fore
&& d
->d_fore
->w_next
!= wp
? d
->d_fore
->w_next
: wp
->w_next
;
1006 if (d
->d_fore
== wp
)
1008 for (cv
= d
->d_cvlist
; cv
; cv
= cv
->c_next
)
1010 for (l
= cv
->c_layer
; l
; l
= l
->l_next
)
1011 if (l
->l_layfn
== &WinLf
)
1015 if ((struct win
*)l
->l_data
!= wp
)
1017 if (cv
->c_layer
== wp
->w_savelayer
)
1018 wp
->w_savelayer
= 0;
1019 KillLayerChain(cv
->c_layer
);
1022 if (wp
->w_savelayer
)
1023 KillLayerChain(wp
->w_savelayer
);
1024 for (cv
= wp
->w_layer
.l_cvlist
; cv
; cv
= ncv
)
1027 cv
->c_layer
= &cv
->c_blank
;
1028 cv
->c_blank
.l_cvlist
= cv
;
1030 cv
->c_xoff
= cv
->c_xs
;
1031 cv
->c_yoff
= cv
->c_ys
;
1032 RethinkViewportOffsets(cv
);
1034 wp
->w_layer
.l_cvlist
= 0;
1035 if (flayer
== &wp
->w_layer
)
1037 LayerCleanupMemory(&wp
->w_layer
);
1041 #endif /* MULTIUSER */
1042 evdeq(&wp
->w_readev
); /* just in case */
1043 evdeq(&wp
->w_writeev
); /* just in case */
1044 evdeq(&wp
->w_silenceev
);
1045 evdeq(&wp
->w_destroyev
);
1047 FreePaster(&wp
->w_paster
);
1053 OpenDevice(args
, lflag
, typep
, namep
)
1059 char *arg
= args
[0];
1065 if (strcmp(arg
, "//group") == 0)
1067 *typep
= W_TYPE_GROUP
;
1071 #ifdef BUILTIN_TELNET
1072 if (strcmp(arg
, "//telnet") == 0)
1074 f
= TelOpen(args
+ 1);
1076 *typep
= W_TYPE_TELNET
;
1081 if (strncmp(arg
, "//", 2) == 0)
1083 Msg(0, "Invalid argument '%s'", arg
);
1086 else if ((stat(arg
, &st
)) == 0 && S_ISCHR(st
.st_mode
))
1088 if (access(arg
, R_OK
| W_OK
) == -1)
1090 Msg(errno
, "Cannot access line '%s' for R/W", arg
);
1093 debug("OpenDevice: OpenTTY\n");
1094 if ((f
= OpenTTY(arg
, args
[1])) < 0)
1097 *typep
= W_TYPE_PLAIN
;
1102 *typep
= W_TYPE_PTY
;
1106 Msg(0, "No more PTYs.");
1112 if (ioctl(f
, TIOCPKT
, (char *)&flag
))
1114 Msg(errno
, "TIOCPKT ioctl");
1119 #endif /* TIOCPKT */
1121 debug1("fcntl(%d, F_SETFL, FNBLOCK)\n", f
);
1122 (void) fcntl(f
, F_SETFL
, FNBLOCK
);
1125 * Tenebreux (zeus@ns.acadiacom.net) has Linux 1.3.70 where select
1126 * gets confused in the following condition:
1127 * Open a pty-master side, request a flush on it, then set packet
1128 * mode and call select(). Select will return a possible read, where
1129 * the one byte response to the flush can be found. Select will
1130 * thereafter return a possible read, which yields I/O error.
1132 * If we request another flush *after* switching into packet mode,
1133 * this I/O error does not occur. We receive a single response byte
1134 * although we send two flush requests now.
1136 * Maybe we should not flush at all.
1140 if (*typep
== W_TYPE_PTY
|| *typep
== W_TYPE_PLAIN
)
1141 tcflush(f
, TCIOFLUSH
);
1144 if (*typep
!= W_TYPE_PTY
)
1149 if (chown(*namep
, real_uid
, PTYGROUP
) && !eff_uid
)
1151 if (chown(*namep
, real_uid
, real_gid
) && !eff_uid
)
1154 Msg(errno
, "chown tty");
1159 if (chmod(*namep
, lflag
? TtyMode
: (TtyMode
& ~022)) && !eff_uid
)
1161 if (chmod(*namep
, TtyMode
) && !eff_uid
)
1164 Msg(errno
, "chmod tty");
1173 * Fields w_width, w_height, aflag, number (and w_tty)
1174 * are read from struct win *win. No fields written.
1175 * If pwin is nonzero, filedescriptors are distributed
1176 * between win->w_tty and open(ttyn)
1180 ForkWindow(win
, args
, ttyn
)
1187 char shellbuf
[7 + MAXPATHLEN
];
1190 char libuf
[20], cobuf
[20];
1193 int w
= win
->w_width
;
1194 int h
= win
->w_height
;
1196 int i
, pat
, wfdused
;
1197 struct pseudowin
*pwin
= win
->w_pwin
;
1204 debug("pre-opening slave...\n");
1205 if ((slave
= open(ttyn
, O_RDWR
|O_NOCTTY
)) == -1)
1212 debug("forking...\n");
1221 switch (pid
= fork())
1227 signal(SIGHUP
, SIG_DFL
);
1228 signal(SIGINT
, SIG_DFL
);
1229 signal(SIGQUIT
, SIG_DFL
);
1230 signal(SIGTERM
, SIG_DFL
);
1232 signal(SIGTTIN
, SIG_DFL
);
1233 signal(SIGTTOU
, SIG_DFL
);
1236 signal(SIGPIPE
, SIG_DFL
);
1239 signal(SIGXFSZ
, SIG_DFL
);
1242 displays
= 0; /* beware of Panic() */
1243 if (setgid(real_gid
) || setuid(real_uid
))
1244 Panic(errno
, "Setuid/gid");
1248 if (!pwin
) /* ignore directory if pseudo */
1250 if (win
->w_dir
&& *win
->w_dir
&& chdir(win
->w_dir
))
1251 Panic(errno
, "Cannot chdir to %s", win
->w_dir
);
1261 if (dfp
&& dfp
!= stderr
)
1269 closeallfiles(win
->w_ptyfd
);
1273 closeallfiles(win
->w_ptyfd
);
1275 if (dfp
) /* do not produce child debug, when debug is "off" */
1279 sprintf(buf
, "%s/screen.child", DEBUGDIR
);
1280 if ((dfp
= fopen(buf
, "a")) == 0)
1283 (void) chmod(buf
, 0666);
1285 debug1("=== ForkWindow: pid %d\n", (int)getpid());
1287 /* Close the three /dev/null descriptors */
1293 * distribute filedescriptors between the ttys
1296 pat
= pwin
? pwin
->p_fdpat
:
1297 ((F_PFRONT
<<(F_PSHIFT
*2)) | (F_PFRONT
<<F_PSHIFT
) | F_PFRONT
);
1298 debug1("Using window pattern 0x%x\n", pat
);
1300 for(i
= 0; i
< 3; i
++)
1302 if (pat
& F_PFRONT
<< F_PSHIFT
* i
)
1308 newfd
= open(ttyn
, O_RDWR
);
1310 newfd
= open(ttyn
, O_RDWR
|O_NOCTTY
);
1312 newfd
= open(ttyn
, O_RDWR
);
1315 Panic(errno
, "Cannot open %s", ttyn
);
1329 * the pseudo window process should not be surprised with a
1330 * nonblocking filedescriptor. Poor Backend!
1332 debug1("Clearing NBLOCK on window-fd(%d)\n", win
->w_ptyfd
);
1333 if (fcntl(win
->w_ptyfd
, F_SETFL
, 0))
1334 Msg(errno
, "Warning: clear NBLOCK fcntl failed");
1339 newfd
= open(ttyn
, O_RDWR
);
1341 newfd
= open(ttyn
, O_RDWR
|O_NOCTTY
);
1343 newfd
= open(ttyn
, O_RDWR
);
1346 Panic(errno
, "Cannot open %s", ttyn
);
1349 #endif /* PSEUDOS */
1350 close(win
->w_ptyfd
);
1355 struct mode fakemode
, *modep
;
1358 Msg(errno
, "fgtty");
1361 debug("ForkWindow: using display tty mode for new child.\n");
1366 debug("No display - creating tty setting\n");
1373 /* We only want echo if the users input goes to the pseudo
1374 * and the pseudo's stdout is not send to the window.
1377 if (pwin
&& (!(pat
& F_UWP
) || (pat
& F_PBACK
<< F_PSHIFT
)))
1379 debug1("clearing echo on pseudywin fd (pat %x)\n", pat
);
1380 # if defined(POSIX) || defined(TERMIO)
1381 modep
->tio
.c_lflag
&= ~ECHO
;
1382 modep
->tio
.c_iflag
&= ~ICRNL
;
1384 modep
->m_ttyb
.sg_flags
&= ~ECHO
;
1388 SetTTY(newfd
, modep
);
1392 (void) ioctl(newfd
, TIOCSWINSZ
, (char *)&glwz
);
1394 /* Always turn off nonblocking mode */
1395 (void)fcntl(newfd
, F_SETFL
, 0);
1398 sprintf(libuf
, "LINES=%d", h
);
1399 sprintf(cobuf
, "COLUMNS=%d", w
);
1404 NewEnv
[2] = MakeTermcap(display
== 0 || win
->w_aflag
);
1407 NewEnv
[2] = MakeTermcap(1);
1409 NewEnv
[2] = Termcap
;
1411 strcpy(shellbuf
, "SHELL=");
1412 strncpy(shellbuf
+ 6, ShellProg
+ (*ShellProg
== '-'), sizeof(shellbuf
) - 7);
1413 shellbuf
[sizeof(shellbuf
) - 1] = 0;
1414 NewEnv
[4] = shellbuf
;
1415 debug1("ForkWindow: NewEnv[4] = '%s'\n", shellbuf
);
1416 if (win
->w_term
&& *win
->w_term
&& strcmp(screenterm
, win
->w_term
) &&
1417 (strlen(win
->w_term
) < 20))
1421 sprintf(tebuf
, "TERM=%s", win
->w_term
);
1422 debug2("Makewindow %d with %s\n", win
->w_number
, tebuf
);
1423 tl
= strlen(win
->w_term
);
1425 if ((s1
= index(NewEnv
[2], '|')))
1427 if ((s2
= index(++s1
, '|')))
1429 if (strlen(NewEnv
[2]) - (s2
- s1
) + tl
< 1024)
1431 bcopy(s2
, s1
+ tl
, strlen(s2
) + 1);
1432 bcopy(win
->w_term
, s1
, tl
);
1437 sprintf(ebuf
, "WINDOW=%d", win
->w_number
);
1443 proc
= DefaultShell
;
1444 debug1("calling execvpe %s\n", proc
);
1445 execvpe(proc
, args
, NewEnv
);
1446 debug1("exec error: %d\n", errno
);
1447 Panic(errno
, "Cannot exec '%s'", proc
);
1456 #ifndef HAVE_EXECVPE
1458 execvpe(prog
, args
, env
)
1459 char *prog
, **args
, **env
;
1461 register char *path
= NULL
, *p
;
1463 char *shargs
[MAXARGS
+ 1];
1464 register int i
, eaccess
= 0;
1466 if (rindex(prog
, '/'))
1468 if (!path
&& !(path
= getenv("PATH")))
1472 for (p
= buf
; *path
&& *path
!= ':'; path
++)
1473 if (p
- buf
< (int)sizeof(buf
) - 2)
1477 if (p
- buf
+ strlen(prog
) >= sizeof(buf
) - 1)
1480 execve(buf
, args
, env
);
1484 shargs
[0] = DefaultShell
;
1486 for (i
= 1; (shargs
[i
+ 1] = args
[i
]) != NULL
; ++i
)
1488 execve(DefaultShell
, shargs
, env
);
1512 int i
, r
= 0, l
= 0;
1514 extern struct display
*display
;
1515 extern struct win
*windows
;
1516 struct pseudowin
*pwin
;
1519 if ((w
= display
? fore
: windows
) == NULL
)
1521 if (!*av
|| w
->w_pwin
)
1523 Msg(0, "Filter running: %s", w
->w_pwin
? w
->w_pwin
->p_cmd
: "(none)");
1528 Msg(0, "You feel dead inside.");
1531 if (!(pwin
= (struct pseudowin
*)calloc(1, sizeof(struct pseudowin
))))
1537 /* allow ^a:!!./ttytest as a short form for ^a:exec !.. ./ttytest */
1538 for (s
= *av
; *s
== ' '; s
++)
1540 for (p
= s
; *p
== ':' || *p
== '.' || *p
== '!'; p
++)
1543 while (*p
&& p
> s
&& p
[-1] == '.')
1556 for (i
= 0; i
< 3; i
++)
1558 *t
= (s
< p
) ? *s
++ : '.';
1563 l
|= F_PFRONT
<< (i
* F_PSHIFT
);
1566 l
|= F_PBACK
<< (i
* F_PSHIFT
);
1569 l
|= F_PBOTH
<< (i
* F_PSHIFT
);
1577 if ((l
& F_PMASK
) == F_PFRONT
)
1580 l
^= F_PFRONT
| F_PBACK
;
1587 debug1("winexec: '%#x'\n", pwin
->p_fdpat
);
1590 for (pp
= av
; *pp
; pp
++)
1593 while (*p
&& l
-- > 0)
1600 debug1("%s\n", pwin
->p_cmd
);
1602 if ((pwin
->p_ptyfd
= OpenDevice(av
, 0, &type
, &t
)) < 0)
1607 strncpy(pwin
->p_tty
, t
, MAXSTR
- 1);
1609 if (type
!= W_TYPE_PTY
)
1612 Msg(0, "Cannot only use commands as pseudo win.");
1615 if (!(pwin
->p_fdpat
& F_PFRONT
))
1616 evdeq(&w
->w_readev
);
1621 if (ioctl(pwin
->p_ptyfd
, TIOCPKT
, (char *)&flag
))
1623 Msg(errno
, "TIOCPKT pwin ioctl");
1627 if (w
->w_type
== W_TYPE_PTY
&& !(pwin
->p_fdpat
& F_PFRONT
))
1629 if (ioctl(w
->w_ptyfd
, TIOCPKT
, (char *)&flag
))
1631 Msg(errno
, "TIOCPKT win ioctl");
1637 #endif /* TIOCPKT */
1639 pwin
->p_readev
.fd
= pwin
->p_writeev
.fd
= pwin
->p_ptyfd
;
1640 pwin
->p_readev
.type
= EV_READ
;
1641 pwin
->p_writeev
.type
= EV_WRITE
;
1642 pwin
->p_readev
.data
= pwin
->p_writeev
.data
= (char *)w
;
1643 pwin
->p_readev
.handler
= pseu_readev_fn
;
1644 pwin
->p_writeev
.handler
= pseu_writeev_fn
;
1645 pwin
->p_writeev
.condpos
= &pwin
->p_inlen
;
1646 if (pwin
->p_fdpat
& (F_PFRONT
<< F_PSHIFT
* 2 | F_PFRONT
<< F_PSHIFT
))
1647 evenq(&pwin
->p_readev
);
1648 evenq(&pwin
->p_writeev
);
1649 r
= pwin
->p_pid
= ForkWindow(w
, av
, t
);
1659 struct pseudowin
*pwin
= w
->w_pwin
;
1662 if (fcntl(w
->w_ptyfd
, F_SETFL
, FNBLOCK
))
1663 Msg(errno
, "Warning: FreePseudowin: NBLOCK fcntl failed");
1665 if (w
->w_type
== W_TYPE_PTY
&& !(pwin
->p_fdpat
& F_PFRONT
))
1668 if (ioctl(w
->w_ptyfd
, TIOCPKT
, (char *)&flag
))
1669 Msg(errno
, "Warning: FreePseudowin: TIOCPKT win ioctl");
1672 /* should be able to use CloseDevice() here */
1673 (void)chmod(pwin
->p_tty
, 0666);
1674 (void)chown(pwin
->p_tty
, 0, 0);
1675 if (pwin
->p_ptyfd
>= 0)
1676 close(pwin
->p_ptyfd
);
1677 evdeq(&pwin
->p_readev
);
1678 evdeq(&pwin
->p_writeev
);
1679 if (w
->w_readev
.condneg
== &pwin
->p_inlen
)
1680 w
->w_readev
.condpos
= w
->w_readev
.condneg
= 0;
1681 evenq(&w
->w_readev
);
1686 #endif /* PSEUDOS */
1691 * returns 0, if the lock really has been released
1694 ReleaseAutoWritelock(dis
, w
)
1695 struct display
*dis
;
1698 debug2("ReleaseAutoWritelock: user %s, window %d\n",
1699 dis
->d_user
->u_name
, w
->w_number
);
1701 /* release auto writelock when user has no other display here */
1702 if (w
->w_wlock
== WLOCK_AUTO
&& w
->w_wlockuser
== dis
->d_user
)
1706 for (d
= displays
; d
; d
= d
->d_next
)
1707 if (( d
!= dis
) && (d
->d_fore
== w
) && (d
->d_user
== dis
->d_user
))
1709 debug3("%s %s autolock on win %d\n",
1710 dis
->d_user
->u_name
, d
? "keeps" : "releases", w
->w_number
);
1713 w
->w_wlockuser
= NULL
;
1721 * returns 0, if the lock really could be obtained
1724 ObtainAutoWritelock(d
, w
)
1728 if ((w
->w_wlock
== WLOCK_AUTO
) &&
1729 !AclCheckPermWin(d
->d_user
, ACL_WRITE
, w
) &&
1732 debug2("%s obtained auto writelock for exported window %d\n",
1733 d
->d_user
->u_name
, w
->w_number
);
1734 w
->w_wlockuser
= d
->d_user
;
1740 #endif /* MULTIUSER */
1744 /********************************************************************/
1748 paste_slowev_fn(ev
, data
)
1752 struct paster
*pa
= (struct paster
*)data
;
1756 flayer
= pa
->pa_pastelayer
;
1758 pa
->pa_pastelen
= 0;
1759 if (!pa
->pa_pastelen
)
1761 p
= Layer2Window(flayer
);
1762 DoProcess(p
, &pa
->pa_pasteptr
, &l
, pa
);
1763 pa
->pa_pastelen
-= 1 - l
;
1764 if (pa
->pa_pastelen
> 0)
1766 SetTimeout(&pa
->pa_slowev
, p
->w_slowpaste
);
1767 evenq(&pa
->pa_slowev
);
1779 for (cv
= p
->w_layer
.l_cvlist
; cv
; cv
= cv
->c_lnext
)
1781 display
= cv
->c_display
;
1782 if (D_status
== STATUS_ON_WIN
&& !D_status_bell
)
1784 /* wait 'til status is gone */
1785 debug("BLOCKING because of status\n");
1786 ev
->condpos
= &const_one
;
1787 ev
->condneg
= &D_status
;
1790 debug2("muchpending %s %d: ", D_usertty
, D_blocked
);
1791 debug3("%d %d %d\n", D_obufp
- D_obuf
, D_obufmax
, D_blocked_fuzz
);
1794 if (D_obufp
- D_obuf
> D_obufmax
+ D_blocked_fuzz
)
1796 if (D_nonblock
== 0)
1798 debug1("obuf is full, stopping output to display %s\n", D_usertty
);
1802 debug("BLOCKING because of full obuf\n");
1803 ev
->condpos
= &D_obuffree
;
1804 ev
->condneg
= &D_obuflenmax
;
1805 if (D_nonblock
> 0 && !D_blockedev
.queued
)
1807 debug1("created timeout of %g secs\n", D_nonblock
/1000.);
1808 SetTimeout(&D_blockedev
, D_nonblock
);
1809 evenq(&D_blockedev
);
1818 win_readev_fn(ev
, data
)
1822 struct win
*p
= (struct win
*)data
;
1823 char buf
[IOSIZE
], *bp
;
1833 wtop
= p
->w_pwin
&& W_WTOP(p
);
1836 ASSERT(sizeof(p
->w_pwin
->p_inbuf
) == IOSIZE
);
1837 size
= IOSIZE
- p
->w_pwin
->p_inlen
;
1840 ev
->condpos
= &const_IOSIZE
;
1841 ev
->condneg
= &p
->w_pwin
->p_inlen
;
1846 if (p
->w_layer
.l_cvlist
&& muchpending(p
, ev
))
1853 ev
->condpos
= &const_one
;
1854 ev
->condneg
= &p
->w_blocked
;
1858 ev
->condpos
= ev
->condneg
= 0;
1860 if ((len
= p
->w_outlen
))
1863 WriteString(p
, p
->w_outbuf
, len
);
1867 debug1("going to read from window fd %d\n", ev
->fd
);
1868 if ((len
= read(ev
->fd
, buf
, size
)) < 0)
1870 if (errno
== EINTR
|| errno
== EAGAIN
)
1872 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1873 if (errno
== EWOULDBLOCK
)
1876 debug2("Window %d: read error (errno %d) - killing window\n", p
->w_number
, errno
);
1878 WindowDied(p
, (union wait
)0, 0);
1880 WindowDied(p
, 0, 0);
1886 debug1("Window %d: EOF - killing window\n", p
->w_number
);
1888 WindowDied(p
, (union wait
)0, 0);
1890 WindowDied(p
, 0, 0);
1894 debug1(" -> %d bytes\n", len
);
1896 if (p
->w_type
== W_TYPE_PTY
)
1900 debug1("PAKET %x\n", buf
[0]);
1901 if (buf
[0] & TIOCPKT_NOSTOP
)
1903 if (buf
[0] & TIOCPKT_DOSTOP
)
1910 #ifdef BUILTIN_TELNET
1911 if (p
->w_type
== W_TYPE_TELNET
)
1912 len
= TelIn(p
, bp
, len
, buf
+ sizeof(buf
) - (bp
+ len
));
1917 if (zmodem_mode
&& zmodem_parse(p
, bp
, len
))
1923 debug("sending input to pwin\n");
1924 bcopy(bp
, p
->w_pwin
->p_inbuf
+ p
->w_pwin
->p_inlen
, len
);
1925 p
->w_pwin
->p_inlen
+= len
;
1929 LayPause(&p
->w_layer
, 1);
1930 WriteString(p
, bp
, len
);
1931 LayPause(&p
->w_layer
, 0);
1938 win_writeev_fn(ev
, data
)
1942 struct win
*p
= (struct win
*)data
;
1946 debug2("writing %d bytes to win %d\n", p
->w_inlen
, p
->w_number
);
1947 if ((len
= write(ev
->fd
, p
->w_inbuf
, p
->w_inlen
)) <= 0)
1948 len
= p
->w_inlen
; /* dead window */
1949 if ((p
->w_inlen
-= len
))
1950 bcopy(p
->w_inbuf
+ len
, p
->w_inbuf
, p
->w_inlen
);
1953 if (p
->w_paster
.pa_pastelen
&& !p
->w_slowpaste
)
1955 struct paster
*pa
= &p
->w_paster
;
1956 flayer
= pa
->pa_pastelayer
;
1958 DoProcess(p
, &pa
->pa_pasteptr
, &pa
->pa_pastelen
, pa
);
1969 pseu_readev_fn(ev
, data
)
1973 struct win
*p
= (struct win
*)data
;
1975 int size
, ptow
, len
;
1982 ASSERT(sizeof(p
->w_inbuf
) == IOSIZE
);
1983 size
= IOSIZE
- p
->w_inlen
;
1986 ev
->condpos
= &const_IOSIZE
;
1987 ev
->condneg
= &p
->w_inlen
;
1991 if (p
->w_layer
.l_cvlist
&& muchpending(p
, ev
))
1995 ev
->condpos
= &const_one
;
1996 ev
->condneg
= &p
->w_blocked
;
2000 ev
->condpos
= ev
->condneg
= 0;
2002 if ((len
= p
->w_outlen
))
2005 WriteString(p
, p
->w_outbuf
, len
);
2009 if ((len
= read(ev
->fd
, buf
, size
)) <= 0)
2011 if (errno
== EINTR
|| errno
== EAGAIN
)
2013 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
2014 if (errno
== EWOULDBLOCK
)
2017 debug2("Window %d: pseudowin read error (errno %d) -- removing pseudowin\n", p
->w_number
, len
? errno
: 0);
2021 /* no packet mode on pseudos! */
2024 bcopy(buf
, p
->w_inbuf
+ p
->w_inlen
, len
);
2027 WriteString(p
, buf
, len
);
2032 pseu_writeev_fn(ev
, data
)
2036 struct win
*p
= (struct win
*)data
;
2037 struct pseudowin
*pw
= p
->w_pwin
;
2041 if (pw
->p_inlen
== 0)
2043 if ((len
= write(ev
->fd
, pw
->p_inbuf
, pw
->p_inlen
)) <= 0)
2044 len
= pw
->p_inlen
; /* dead pseudo */
2045 if ((p
->w_pwin
->p_inlen
-= len
))
2046 bcopy(p
->w_pwin
->p_inbuf
+ len
, p
->w_pwin
->p_inbuf
, p
->w_pwin
->p_inlen
);
2050 #endif /* PSEUDOS */
2053 win_silenceev_fn(ev
, data
)
2057 struct win
*p
= (struct win
*)data
;
2059 debug1("FOUND silence win %d\n", p
->w_number
);
2060 for (display
= displays
; display
; display
= display
->d_next
)
2062 for (cv
= D_cvlist
; cv
; cv
= cv
->c_next
)
2063 if (cv
->c_layer
->l_bottom
== &p
->w_layer
)
2066 continue; /* user already sees window */
2068 if (!(ACLBYTE(p
->w_lio_notify
, D_user
->u_id
) & ACLBIT(D_user
->u_id
)))
2071 Msg(0, "Window %d: silence for %d seconds", p
->w_number
, p
->w_silencewait
);
2076 win_destroyev_fn(ev
, data
)
2080 struct win
*p
= (struct win
*)ev
->data
;
2081 WindowDied(p
, p
->w_exitstatus
, 1);
2087 zmodem_parse(p
, bp
, len
)
2094 for (i
= 0; i
< len
; i
++, b2
++)
2096 if (p
->w_zauto
== 0)
2098 for (; i
< len
; i
++, b2
++)
2103 if (i
> 1 && b2
[-1] == '*' && b2
[-2] == '*')
2107 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'))
2109 if (++p
->w_zauto
< 6)
2111 if (p
->w_zauto
== 6)
2116 WriteString(p
, bp
, i
+ 1 - 6);
2117 WriteString(p
, "\r\n", 2);
2118 zmodem_found(p
, *b2
== '1', b2
+ 1, len
- i
- 1);
2121 else if (p
->w_zauto
== 7 || *b2
== '8')
2123 int se
= p
->w_zdisplay
->d_blocked
== 2 ? 'O' : '\212';
2124 for (; i
< len
; i
++, b2
++)
2131 D_readev
.condpos
= D_readev
.condneg
= 0;
2135 Activate(D_fore
? D_fore
->w_norefresh
: 0);
2142 p
->w_zauto
= *b2
== '*' ? (p
->w_zauto
== 2 ? 2 : 1) : 0;
2144 if (p
->w_zauto
== 0 && bp
[len
- 1] == '*')
2145 p
->w_zauto
= len
> 1 && bp
[len
- 2] == '*' ? 2 : 1;
2148 display
= p
->w_zdisplay
;
2157 zmodem_fin(buf
, len
, data
)
2166 RcLine(buf
, strlen(buf
) + 1);
2169 s
= "\030\030\030\030\030\030\030\030\030\030";
2176 zmodem_found(p
, send
, bp
, len
)
2184 extern int zmodem_mode
;
2186 /* check for abort sequence */
2188 for (i
= 0; i
< len
; i
++)
2193 if (zmodem_mode
== 3 || (zmodem_mode
== 1 && p
->w_type
!= W_TYPE_PLAIN
))
2195 struct display
*d
, *olddisplay
;
2197 olddisplay
= display
;
2199 if (!d
|| d
->d_fore
!= p
)
2200 for (d
= displays
; d
; d
= d
->d_next
)
2203 if (!d
&& p
->w_layer
.l_cvlist
)
2204 d
= p
->w_layer
.l_cvlist
->c_display
;
2211 p
->w_zdisplay
= display
;
2212 D_blocked
= 2 + send
;
2213 flayer
= &p
->w_layer
;
2216 evdeq(&D_blockedev
);
2217 D_readev
.condpos
= &const_IOSIZE
;
2218 D_readev
.condneg
= &p
->w_inlen
;
2221 SetRendition(&mchar_blank
);
2222 AddStr("Zmodem active\r\n\r\n");
2223 AddStr(send
? "**\030B01" : "**\030B00");
2226 display
= olddisplay
;
2229 flayer
= &p
->w_layer
;
2230 Input(":", 100, INP_COOKED
, zmodem_fin
, NULL
, 0);
2231 s
= send
? zmodem_sendcmd
: zmodem_recvcmd
;
2241 struct display
*olddisplay
= display
;
2242 struct layer
*oldflayer
= flayer
;
2245 if (p
->w_savelayer
&& p
->w_savelayer
->l_next
)
2247 if (oldflayer
== p
->w_savelayer
)
2248 oldflayer
= flayer
->l_next
;
2249 flayer
= p
->w_savelayer
;
2254 LRefreshAll(&p
->w_layer
, 0);
2260 D_readev
.condpos
= D_readev
.condneg
= 0;
2261 Activate(D_fore
? D_fore
->w_norefresh
: 0);
2263 display
= olddisplay
;
2270 WindowChangeNumber(struct win
*win
, int n
)
2273 int old
= win
->w_number
;
2275 if (n
< 0 || n
>= maxwin
)
2277 Msg(0, "Given window position is invalid.");
2288 /* exchange the acls for these windows. */
2292 /* exchange the utmp-slots for these windows */
2293 if ((win
->w_slot
!= (slot_t
) -1) && (win
->w_slot
!= (slot_t
) 0))
2298 if (p
&& (p
->w_slot
!= (slot_t
) -1) && (p
->w_slot
!= (slot_t
) 0))
2300 /* XXX: first display wins? */
2302 /* Does this make more sense? */
2303 display
= p
->w_lastdisp
? p
->w_lastdisp
: p
->w_layer
.l_cvlist
? p
->w_layer
.l_cvlist
->c_display
: 0;
2305 display
= win
->w_layer
.l_cvlist
? win
->w_layer
.l_cvlist
->c_display
: 0;
2312 WindowChanged(win
, 'n');
2313 WindowChanged((struct win
*)0, 'w');
2314 WindowChanged((struct win
*)0, 'W');
2315 WindowChanged((struct win
*)0, 0);