#!/bin/ksh
# @(#) ulock.ksh 2.0 96/06/18
# 91/01/15 john h. dubois iii (john@armory.com)
# 91/02/25: only lock ttys that being with the same letter as current tty,
#          or that begin with a digit if current tty does.
# 91/02/27: make keys dead instead of mapping to ^A; use LOCKMAP var
# 92/08/04: use ttys= instead of unset ttys
# 96/06/18 Auto-generate mapchan file.

# ulock: lock all multiscreens or mscreens that the user is logged into.
# Locks ttys by using mapchan to make all keys dead keys, 
# so all characters are discarded.
# When lock exits all of the other ttys are unlocked with mapchan -n.
# Current tty is locked with "lock".

name=${0##*/}
mfile=.lockmap
if [ $# -gt 0 ]; then
    print \
"$name: lock all multiscreens or mscreens that the user is logged into.
     If the name of the current TTY begins with a letter, all TTYs that the
user is logged into that begin with that letter (except the current TTY) are
locked with mapchan.
     If the name of the current TTY begins with a digit, all TTYs that the user
is logged into that begin with a digit (except the current TTY) are locked with
mapchan.
     lock is then run to lock the current TTY.  When lock exits all of the
other TTYs are also unlocked.
     The first time $name is run, it creates a mapchan file name $mfile in the
invoking user's home directory to use to lock TTYs.  If the environment
variable LOCKMAP is set, it is used instead; in that case the file must already
exist."
	exit
fi

# Set USER, TTY (current tty), and LOCKMAP if they are not already set
[ -z "$USER" ] && USER=`logname`
[ -z "$TTY" ] && TTY=`tty`
if [ -z "$LOCKMAP" ]; then
    LOCKMAP=$HOME/$mfile
    if [ ! -f "$LOCKMAP" ]; then
	> $lockmap || exit 1
	{
	print \
	"# mapchan file to discard all terminal input, generated by $name"
	print "input"
	typeset -i i=1
	while [ i -lt 256 ]; do
	    print "dead\t$i"
	    let i+=1
	done
	print "\noutput"
	} > $LOCKMAP 
    fi
fi
tty=${TTY#/dev/}

# Get tty type identifier (first char of tty name after /dev/tty)
ttyn=${tty#tty}
ttylet=${ttyn#?}
ttylet=${ttyn%$ttylet}

# Set tty search pattern depending on tty type
[[ $ttylet = [0-9] ]] && ttypat='tty[0-9]*' || ttypat=tty$ttylet\*

#set users to USER and ALTUSERS separated by | so they can be used as a pattern
users=`( IFS=\|; set $USER $ALTUSERS; echo "$*"; )`

echo "Looking for ttys logged into by: $USER $ALTUSERS"

# set ttys to all ttys of current type that user is logged into,
# other than current tty

# Don't unset ttys because 3.2v4 ksh gives nonzero status if it wasn't set,
# so that set -e shell will exit
ttys=
who | while read user line time; do
[[ ( ( $user = @($users) ) && ( $line != $tty ) ) && ( $line = $ttypat ) ]] \
	&& ttys="$ttys $line"
done

# sort tty list
set $tty $ttys
set -s

# If no ttys of current type other than current tty, 
# don't bother with mapchan etc.
if [ -n "$ttys" ]; then
    if [ ! -r $LOCKMAP ]; then
	echo "Cannot read $LOCKMAP."
	exit 1
    fi
    echo Locking: $*.
    # Unmap channels on normal exit or exit due to interrupt
    trap "echo Unlocking: $*.; mapchan -n $ttys 2> /dev/null" exit
    mapchan -f $LOCKMAP $ttys
else
    echo "Locking $tty (no other ttys of current type)."
fi

# For some reason one version of lock sends sigint to shell when it exits!
# Ignore interrupt 2.
trap "" 2	

lock
