#! /bin/sh # sayto --- front end for `write' to send messages atomically # Copyright (C) 1995 Noah S. Friedman # Author: Noah Friedman # Created: 1993-10-05 # $Id: sayto,v 1.7 1996/06/13 22:23:01 friedman Exp $ # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, you can either send email to this # program's maintainer or write to: The Free Software Foundation, # Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA. # Commentary: # Code: progname=`echo "$0" | sed -e 's/[^\/]*\///g'` bq='`' eq="'" # Ed is the standard text editor. stdeditor=ed usage="Usage: $progname {options} [user1{:tty1}] {user2{:tty2}} {...} Options are: -D, --debug Turn on shell debugging ($bq${bq}set -x$eq$eq). -e, --edit Invoke editor to edit message before sending. The editor is specified by the environment variable ${bq}EDITOR$eq, otherwise the program ${bq}$stdeditor$eq is used. -E, --empty-ok Send message even if empty. -f, --file FILE Read message text from file FILE. -h, --help You're looking at it. -q, --quiet Do not print confirmation about messages sent. " debug= edit= empty_ok= infile= verbose=t # Usage: eval "$getopt"; value=$optarg # or optarg_optional=t; eval "$getopt"; value=$optarg # # This function automatically shifts the positional args as appropriate. # The argument to an option is optional if the variable `optarg_optional' # is non-empty. Otherwise, the argument is required and getopt will cause # the program to exit on an error. optarg_optional is reset to be empty # after every call to getopt. The argument (if any) is stored in the # variable `optarg'. # # Long option syntax is `--foo=bar' or `--foo bar'. 2nd argument # won't get used if first long option syntax was used. # # Note: because of broken bourne shells, using --foo=bar syntax can # actually screw the quoting of args that end with trailing newlines. # Specifically, most shells strip trailing newlines from substituted # output, regardless of quoting. getopt=' { optarg= case "$1" in --*=* ) optarg=`echo "$1" | sed -e "1s/^[^=]*=//"` shift ;; * ) case ${2+set} in set ) optarg="$2" shift shift ;; * ) case "$optarg_optional" in "" ) case "$1" in --*=* ) option=`echo "$1" | sed -e "1s/=.*//;q"` ;; * ) option="$1" ;; esac exec 1>&2 echo "$progname: option $bq$option$eq requires argument." echo "$progname: use $bq--help$eq to list option syntax." exit 1 ;; esac ;; esac ;; esac optarg_optional= }' while : ; do case $# in 0) break ;; esac case "$1" in -D | --debug | --d* ) debug=t shift ;; -e | --edit | -ed* ) edit=t shift ;; -E | --empty-ok | -em* ) empty_ok=t shift ;; -f | --file* | -f* ) eval "$getopt" infile="$optarg" ;; -h | --help | --h ) echo "$usage" 1>&2 exit 0 ;; -q | --quiet | --q* ) verbose= shift ;; -- ) # Stop option processing shift break ;; -? | --* ) case "$1" in --*=* ) arg=`echo "$1" | sed -e 's/=.*//'` ;; * ) arg="$1" ;; esac exec 1>&2 echo "$progname: unknown or ambiguous option $bq$arg$eq" echo "$progname: Use $bq--help$eq for a list of options." exit 1 ;; -??* ) # Split grouped single options into separate args and try again optarg="$1" shift set fnord `echo "x$optarg" | sed -e 's/^x-//;s/\(.\)/-\1 /g'` ${1+"$@"} shift ;; * ) break ;; esac done case "$debug" in t ) set -x ;; esac case $# in 0 ) echo "$usage" 1>&2; exit 1 ;; esac case "$infile" in '' ) : ;; * ) exec 0< "$infile" ;; esac case "$verbose" in t ) exec 3>&1 ;; * ) exec 3> /dev/null ;; esac write=${SAYTOWRITE-write} nodelete=t file="$infile" exitstat=0 if test -t 0 ; then umask 077 file="${TMPDIR-/tmp}/$progname$$" test "$debug" = t || nodelete= # The || pair of commands used to be a case statement, but bash 1.14 had # parsing bugs. trap 'test "$nodelete" = t || rm -f "$file" trap "" 0 1 3 15 exit ${exitstat-0} ' 0 1 3 15 trap 'echo "[Interrupted. No message sent.]" 1>&3 exitstat=130 exit $exitstat ' 2 if (> "$file") 2> /dev/null; then case "$edit" in t ) echo "[Editing message with $bq${EDITOR-$stdeditor}$eq...]" 1>&3 ${EDITOR-$stdeditor} $file exitstat=$? ;; * ) echo "[Enter message, ending with C-d on a new line when finished, or C-c to abort.]" 1>&3 cat > "$file" exitstat=$? ;; esac case "$exitstat" in 0 ) : ;; * ) exec 1>&2 echo "*** $progname: Editor exited unsuccessfully." echo "*** $progname: No message sent. Sorry." exit $exitstat ;; esac else exitstat=$? exec 1>&2 echo "*** $progname: $file: Cannot create temporary file; aborting." exit $exitstat fi fi if test -s "$file"; then : else case "$empty_ok" in t ) echo "[Sending empty message.]" 1>&3 ;; * ) echo "[Message is empty. Not sending.]" 1>&3 exit 1 ;; esac fi # If only args were in format "user tty", rewrite them to "user:tty" # for parsing by the mechanism below equipped to handle multiple # user:tty pairs. case "$#" in 2 ) case "$2" in /dev/* | tty* | pts/* ) set fnord "$1:$2" shift ;; esac ;; esac exitstat=0 for user in ${1+"$@"}; do tty= case "$user" in *:* ) oIFS="$IFS" IFS=':' set fnord $user IFS="$oIFS" user=$2 tty="$3" # The `write' program implicitly adds "/dev", so strip it out here case "$tty" in /dev/* ) tty=`echo "$tty" | sed -e 's/\/dev\///'` ;; esac ;; esac case "$tty" in '' ) s="$user" ;; * ) s="$user on /dev/$tty" ;; esac if $write $user $tty < "$file" ; then echo "[Message sent to $s using $bq$write$eq.]" 1>&3 else echo "*** $progname: $bq$write$eq to $s was unsuccessful." 1>&2 nodelete=t exitstat=1 fi done case "$exitstat:$nodelete" in 1:t ) if test -t 0; then echo "*** $progname: message retained in $bq$file$eq." 1>&2 fi exit $exitstat ;; esac # sayto ends here