#!/bin/sh
# script to send a pop-up message to a user
# 27-June-2007 Albert Lingelbach Jr. alingelb/at/yahoo/dot/com
# TODO:
#   remote X sessions
#   -all should send to all sessions in cluster

# function that actually sends the message
# local system only
# uses
#   $username - the name of the user
#   $targetdisplay - the destination X session
#   $message - the text of the message
#
sendXmessage ()
{
  # verify that X session is local, root session
  if test `echo $targetdisplay | awk ' { print substr ($0, 0, 1); }'` != ":"
  then
    echo "sendXMsg: only local displays are supported at this time." >&2
    return 1
  elif test `echo $targetdisplay | grep '\.' | wc -w` -ne 0
  then
    echo "sendXmsg: messages should be sent to root displays." >&2
    return 1
  elif test "$username" = "`who am i | cut -d\  -f1`"
  then
    # special case:
    # if sending message to self, no need to add xauth
    # and don't add host name - causes problems
    zenity --info --display=$targetdisplay --text="$message" &
    return 0
  else
    # add host name to display - .Xauthority file standard
    targetdisplay=`hostname`$targetdisplay
  fi

  # get xauth data for desired display
  userhomedir=`grep $username: /etc/passwd | cut -d: -f6`
  if test -f $userhomedir/.Xauthority
  then
    xauthdata=`xauth -f $userhomedir/.Xauthority list |
      grep "$targetdisplay " 2>/dev/null`
  else
    echo "$0: $userhomedir/.Xauthority file not found" >&2
    return 1
  fi

  # verify ~correctness of Xauth data
  if test `echo $xauthdata | wc -w` -ne 3
  then
    echo "$0: error extracting X authority data for $targetdisplay" \
      "from $userhomedir/.Xauthority"
  fi

  # if we didn't already have authority for the display, delete when finished
  if test `xauth list | grep $targetdisplay | wc -w` -eq 0
  then

    # enable writing to target display
    xauth add $xauthdata

    # there is a slight race condition here:
    # if the same user is sending a message to the same recipient
    # at the "same" time,
    # one instance could remove the Xauth
    # before the other instance gets to send the message.
    # or, one instance could see the Xauth that the other added,
    # not know it was temporary, and remove it

    # send the message
    zenity --info --display=$targetdisplay --text="$message" &

    # remove target display from local .Xauthority file, to reduce clutter
    sleep 1 && xauth remove $targetdisplay &

  else  # don't bother deleting Xauth, already had it

    # enable writing to target display
    # do this even if display is already in list - 
    # existing auth could be stale
    xauth add $xauthdata

    # send the message
    zenity --info --display=$targetdisplay --text="$message" &

  fi
}

#------ main code starts here -----

# parse command line
case $# in
  0 | 1)
    echo "USAGE: $0 user [display] message  OR  $0 -all message" >&2
    exit 1
    ;;
  2)
    username=$1
    targetdisplay=
    message=$2
    ;;
  3)
    username=$1
    targetdisplay=$2
    message=$3
    ;;
esac

# single user, or all users ?
if test "$username" = "-all"
then

  # for every user
  for whodata in `who | awk '{ i = index ($0, "(");
        print $1 "-" substr ($0, i+1, length($0)-i-1); }'`
  do
    username=`echo $whodata | cut -d- -f1`
    targetdisplay=`echo $whodata | cut -d- -f2`

    # don't send to remote or non-root X sessions
    if test `echo $targetdisplay | grep '\.' | wc -w` -eq 0 &&
      test `echo $targetdisplay | awk ' { print substr ($0, 0, 1); }'` = ":"
    then
      sendXmessage
    fi
  done

else  # single user

  # get the list of the user's displays
  userdisplays=`who | grep $username |
    awk ' { i = index ($0, "("); print substr ($0, i+1, length($0)-i-1); }'`

  # check validity of args
  if test -z "$targetdisplay"
  then
    displaycount=`echo $userdisplays | wc -w`
    if test $displaycount -eq 1
    then
        targetdisplay=$userdisplays
    elif test $displaycount -eq 0
    then
      echo "$0: user $username not found on" `hostname` >&2
      exit 1
    else
      echo "$0: user $username has more than one display; " \
          "please specify display:" >&2
      echo $userdisplays >&2
      exit 1
    fi
  else
    # is target display valid ?
    if test `echo $userdisplays | grep $targetdisplay | wc -w` -eq 0
    then
      echo "$0: user $username not found on display" \
          `hostname`$targetdisplay >&2
      exit 1
    fi
  fi

  sendXmessage

fi

exit 0

