#!/bin/sh
# *** Begin of truc file, Version 1.0.6 ***
#  
#   "truc & untruc" scripts allow you to send and receive big files or 
#   directories using e-mail.
#   Copyright 1994-1998 - David Segonds
#  
#   Version 1.0.6, last modification: 23 Jul 98
#   Contact: segonds@ensg.u-nancy.fr
#   URL: http://www.ensg.u-nancy.fr/~segonds/truc
#  
#   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 of the License, 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, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
# truc.lib: Common parameters and functions
VERSION=1.0.6
COPYRIGHT="Copyright 1994-1998 - David Segonds"
DATEM="23 Jul 98"
EMAIL="segonds@ensg.u-nancy.fr"
URL="http://www.ensg.u-nancy.fr/~segonds/truc"
CODES="##SEND##"
CODEH="##HEADER##"
CODEE="##END##"
CODER="##REPORT##"
CODERCV="##RECEIVE##"
CODERE="##REPORT_END##"
STARTD=`pwd`
PROGD=`dirname $0`;cd $PROGD;PROGD=`pwd`;cd $STARTD
MAIL="/usr/lib/sendmail -oi -t"
VERBOSE=0

clean_all()
#%%%%%%%%%%
{
  cd $STARTD
  rm -rf $MY_TMP
}

truc_dirname()
#%%%%%%%%%%%%%
{
  OLDD=`pwd`
  DIRNAME=`dirname $1`
  cd $DIRNAME
  echo `pwd`
  cd $OLDD  
}

error ()
#%%%%%%%
{
# 1: Classic
# 2: No clean after message
# 3: Internal error
# 4: User interruption

 MSG=$2
 CODE=$1

 if [ $# -ne 2 ]
 then
   MSG="Internal error when using error function"
   CODE=3
 fi

 echo "Error: $PROG: $MSG" >&2
 if [ $CODE -eq 3 ]
 then
   echo "Please, send a bug report to $EMAIL" >&2
 fi
 echo "Aborting process..." >&2
 if [ $CODE -ne 2 ]
 then
   clean_all
 fi
 exit $CODE;
}

ALP=abcdefghijklmnopqrstuvwxyz

nb_2_str ()
#%%%%%%%%%%
{
 VAL=`expr $1 - 1`
 N1=`expr $VAL / 26`
 N2=`expr $VAL - $N1 \* 26 + 1`
 N1=`expr $N1 + 1`

 S1=`expr substr $ALP $N1 1`
 S2=`expr substr $ALP $N2 1`
 echo $S1$S2
}

str_2_nb ()
#%%%%%%%%%%%
{
 STR=$1
 L1=`expr substr $STR 1 1`
 L2=`expr substr $STR 2 1`
 D1=`expr index $ALP $L1`
 D2=`expr index $ALP $L2`
 echo `expr \( $D1 - 1 \) \* 26 + $D2`
}

msgv ()
#%%%%%%
{
# 0: Always
# 1: Display info messages
# 9: Display debug information

 CODE=$1
 MSG=$2

 if [ $# -ne 2 ]
 then
   error 3 "Internal error in msgv function"
 fi

 if [ "$VERBOSE" -ge $CODE ]
 then
   echo $MSG >&2 
 fi
}

stop_func ()
#%%%%%%%%%%%
{
 error 4 "Ctrl-C pressed"
}

# Trap
trap stop_func 1 2

copyright ()
#%%%%%%%%%%%
{
 msgv 0 "$PROG version $VERSION ($DATEM), $COPYRIGHT"
 msgv 0 "$PROG comes with ABSOLUTELY NO WARRANTY; for details read COPYING file."
 msgv 0 "This is free software, and you are welcome to redistribute it"
 msgv 0 "under certain conditions; read COPYING file for details."
 msgv 0 "You can send bug-reports to $EMAIL"
 msgv 0 "Last version is available at $URL"
 msgv 0 ""
}
# Defaults parameters
LN_SIZE=1500
TIME_SLEEP=15

SEND_REPORT=0
SEND_RECEIPT=""
DO_NOTHING=0
PROMPT_MSG=0
PROG=truc

# Initialisation
if ( (gzip -h ) > /dev/null 2>&1)
then
  COMPRESS="gzip -9"
  CSUF="gz"
else
  COMPRESS=compress
  CSUF="Z"
fi

# default name of the uuencode binary
if ( ( uuenview -h ) > /dev/null 2>&1)
then
  UUENCODE_CMD="uuenview -u"
else
  if ( ( uuencode nonsense < /dev/null ) > /dev/null 2>&1)  
  then
    UUENCODE_CMD="uuencode"
  else
  error 1 "Cannot find any encoder (uuencode or uuenview)"
  fi
fi

usage ()
#%%%%%%%
{
copyright
cat <<END
usage: truc [-h] [-t val] [-l val] [[-p ext]...] [-report] [-r e-mail] [-m] 
            [-n] [-v] [-d] [-q] [-z] [-bz] [-x] e-mail[,...] <file|dir> 
END
}

help()
#%%%%%
{
cat <<EOF

-h        : Get this help
-t val    : Sleep val seconds between each packet sent (default=30)
-l val    : value is the maximum number of lines for a packet
            (default 1500 lines, this is about 90 Kb per packet)
-k val    : value is the maximum size of a packet in Kb (default 90 Kb)
-p val    : Will mail only the specified packet (1, 2, 3, etc.)
            you can have more than one -p option in the command line.
            Warning: This option is not working when sending directories.
-report   : Will mail a report (default=no report mailed)
-r e-mail : Will mail a receipt to e-mail upon 'untruc' completion.
-m        : Will prompt the user for a mail to be sent with the packages
-n        : Seems to do all the job BUT doesn't send anything
-v        : Turn on verbose mode
-d        : Turn on debug mode
-q        : Send will be totally quiet (no message displayed)
-z        : Force the use of compress instead of gzip
-bz       : Force the use of bzip as compressor
-x        : Upon reception, contents will be extracted as far as possible.
e-mail    : E-mail address were you want to mail your file or directory.
            You can provide more than one address if you separate then
            by a comma
file|dir  : Name of the file or directory you want to send
EOF
}

file_2_nb ()
#%%%%%%%%%%
{
 L=`expr $1 : '.*'`
 if [ "$L" -lt 3 ]
 then
   error 3 "Internal error in file_2_nb (1)"
 fi
 SSTR=`expr $L - 2`
 STR=`expr substr $1 $SSTR 3`
 ALPHA=abcdefghijklmnopqrstuvwxyz
 L0=`expr substr $STR 1 1`
 if [ "$L0" != '.' ]
 then
   error 3 "Internal error in file_2_nb (2)"
 fi
 L1=`expr substr $STR 2 1`
 L2=`expr substr $STR 3 1`
 D1=`expr index $ALPHA $L1`
 D2=`expr index $ALPHA $L2`
 echo `expr \( $D1 - 1 \) \* 26 + $D2`
}

what_to_do ()
#%%%%%%%%%%%%
{
 DO_TAR=1
 DO_COMPRESS=1
 DO_UUENCODE=1

 BF=`basename $1`
 AF=$1
 msgv 9 "$AF"
 msgv 9 "$BF"
 
 # Are we processing a directory?
 if [ -d $AF ]
 then
   return
 fi

 DO_TAR=0

 # Are we processing a taz file?
 if [ "$BF" != "`basename $BF .taz`" ]
 then
   DO_COMPRESS=0
 fi

 # Are we processing a tgz file?
 if [ "$BF" != "`basename $BF .tgz`" ]
 then
   DO_COMPRESS=0
 fi

 # Are we processing a gzip file?
 if [ "$BF" != "`basename $BF .gz`" ]
 then
   DO_COMPRESS=0
 fi

 # Are we processing a bzip file?
 if [ "$BF" != "`basename $BF .bz`" ]
 then
   DO_COMPRESS=0
 fi

 # Are we processing a "compress" file?
 if [ "$BF" != "`basename $BF .Z`" ]
 then
   DO_COMPRESS=0
 fi

 # Crypted file?
 if [ "$BF" != "`basename $BF .cr`" ]
 then
   DO_COMPRESS=0
 fi

 # Crypted file?
 if [ "$BF" != "`basename $BF .crypt`" ]
 then
   DO_COMPRESS=0
 fi

 # Crypted file?
 if [ "$BF" != "`basename $BF .pgp`" ]
 then
   DO_COMPRESS=0
 fi

 # Uuencoded file?
 if [ "$BF" != "`basename $BF .uu`" ]
 then
   DO_COMPRESS=0
   DO_UUENCODE=0
 fi
}

create_packet ()
#%%%%%%%%%%%%%%%
{
 if [ $# -ne 2 ]
 then
   error 3 "Problem in create_packet (wrong number of arguments"
 fi
 if [ ! -r $1 ]
 then
   error 1 "Can't read $1"
 fi
 IN=`file_2_nb $1`
 echo "To: $2" > tmp_file
 echo "Subject: [truc] $CFILE ($IN/$NB_PKTS_ALL)" >> tmp_file

echo '#---- cut here ----'>>tmp_file
echo '#!/bin/sh'>>tmp_file
echo '# This is a shell archive (produced by truc 1.0.6).'>>tmp_file
echo '# Copyright 1994-1998 - David Segonds'>>tmp_file
echo '#'>>tmp_file
echo '# To extract the files, save them to FILE, remove everything before the'>>tmp_file
echo '# "#!/bin/sh" line above then type 'sh FILE'.'>>tmp_file
echo '# Beware: files will be extracted and untarred in the current directory.'>>tmp_file
echo '#'>>tmp_file
echo 'F=/tmp/u$$'>>tmp_file
echo 'for i in $0 $*'>>tmp_file
echo 'do'>>tmp_file
echo 'if(csplit -s -f $F $i "/^'$CODERCV'/+1" "/^'$CODERCV'/")>/dev/null 2>&1'>>tmp_file
echo 'then'>>tmp_file
echo 'trap "rm -f $F*" 1 2'>>tmp_file
echo 'rm ${F}00 ${F}02'>>tmp_file
echo 'sh ${F}01 '$OPTIONS_FOR_UNTRUC' $0 $*'>>tmp_file
echo 'rm -f $F*'>>tmp_file
echo 'exit 0'>>tmp_file
echo 'fi'>>tmp_file
echo 'done'>>tmp_file
echo 'echo "Auto-extracting code not found..." >&2'>>tmp_file
echo 'echo "You can use \"untruc\" instead (released with \"truc\")'>>tmp_file
echo 'echo "See http://www.ensg.u-nancy.fr/~segonds/truc"'>>tmp_file
echo 'exit 1'>>tmp_file

 echo $CODEH $PROG  - $COPYRIGHT >> tmp_file
 echo "Version: $VERSION" >> tmp_file
 echo File: $SFILE >> tmp_file
 echo Lines: `cat $1|wc -l` >> tmp_file
 echo Total: $NB_PKTS_ALL packets >> tmp_file
 if [ "$SEND_RECEIPT" != "" ]
 then
   echo Receipt: $SEND_RECEIPT >> tmp_file
 fi
 if [ "$EXEC_BIT" = "1" ]
 then
   echo Exec: 1 >> tmp_file
 fi
 echo $CODES$1 >> tmp_file
 cat $1 >> tmp_file
 echo $CODEE >> tmp_file
}

send_packet ()
#%%%%%%%%%%%%%
{
 if [ -r $1 ]
 then
   create_packet $1 $ADDRESS
 else
   error 1 "Can't read $1"
 fi

# msgv 1 "Mailing $1 to $ADDRESS ($MAIL)"
 IN=`file_2_nb $1`
 msgv 0 "Mailing $CFILE ($IN/$NB_PKTS_ALL) to $ADDRESS ($MAIL)"
 case $DO_NOTHING in
   "0")
     if ( $MAIL < tmp_file )
     then
       msgv 9 "OK"
     else
       error 1 "mail command failed"
     fi
   ;;
   "1")
     msgv 1 "Just a test, nothing sent"
   ;;
   "2")
     cat tmp_file
  esac
  rm -f tmp_file $1
}

send_report ()
#%%%%%%%%%%%%%
{
 msgv 9 "Send a report: $SEND_REPORT"
 if [ "$SEND_REPORT" != 1 ]
 then
   return
 fi

 cat<<END >report
Subject: $BFILE Report

$CODER
========

Version: $VERSION
File sent: $FILE
$NB_PKTS packets, maximum $LN_SIZE lines each
END

 ls -l $SFILE.* >> report
 echo $CODERE >> report
 if [ "$DO_NOTHING" != 1 ]
 then
   msgv 1 "Mailing report to $ADDRESS ($MAIL)"
   if ( $MAIL $ADDRESS < report )
   then
     msgv 9 "OK"
   else
     error 1 "mail command failed"
   fi
 else
   msgv 1 "Just a test, nothing sent"
 fi
}

send_mesg ()
#%%%%%%%%%%%
{
 msgv 9 "Send a message: $PROMPT_MSG"
 if [ "$PROMPT_MSG" != 1 ]
 then
   return
 fi

 if [ "$DO_NOTHING" != 1 ]
 then
   if [ "$PROMPT_MSG" = 1 ]
   then
     echo "Enter your message terminated by an alone '.' on the last line"
     $MAIL $ADDRESS
   fi
 else
   msgv 1 "Just a test, nothing sent"
 fi
}

read_command_line()
#%%%%%%%%%%%%%%%%%%
{
 while [ `echo X$1 | awk '{print substr($1,2,1)}'` = "-" ]
 do
 case $1 in
 "-h")
   usage
   help
   exit 0
   ;;
 "-t")
   TIME_SLEEP=$2
   shift 2
   ;;
 "-p")
   NEW_PACKET_TO_RESEND="$2"
   shift 2
   if [ -z "`echo $PACKETS_TO_RESEND | grep $NEW_PACKET_TO_RESEND`" ]
   then
   PACKETS_TO_RESEND="$PACKETS_TO_RESEND $NEW_PACKET_TO_RESEND"
   fi
   ;;
 "-l")
   LN_SIZE=$2
   shift 2
   ;;
 "-k")
   LN_SIZE=`expr $2 \* 16`
   shift 2
   ;;
 "-n")
   DO_NOTHING=1
   shift 1
   ;;
 "-report")
   SEND_REPORT=1
   shift 1
   ;;
 "-r")
   SEND_RECEIPT=$2
   shift 2
   ;;
 "-m")
   PROMPT_MSG=1
   shift 1
   ;;
 "-d")
   VERBOSE=9
   shift 1
   ;;
 "-q")
   VERBOSE=-1
   shift 1
   ;;
 "-v")
   VERBOSE=1
   shift 1
   ;;
 "-z")
   COMPRESS=compress
   CSUF="Z"
   shift 1
   ;;
 "-bz")
   COMPRESS=bzip
   CSUF="bz"
   shift 1
   ;;
 "-x")
   OPTIONS_FOR_UNTRUC="-x"
   shift 1
   ;;
 "-c")
   DO_NOTHING=2
   shift 1
   ;;
 *)
   OPTION=$1
   msgv 9 "$OPTION"
   usage     
   error 1 "Option not recognized: $OPTION"
   esac
 done
    
 if [ $# = 0 ]
 then
   usage
   exit 0
 fi

 if [ $# -ne 2 ]
 then
   usage
   error 1 "Wrong number of arguments"
 fi

 if [ $LN_SIZE -lt 500 ]
 then
   error 1 "Chosen packet size is too small. Use something over 500 lines."
 fi
    
 ADDRESS=$1
 FILE=`dirname $2`/`basename $2`
}

# Main program
#%%%%%%%%%%%%%

if [ $# = 0 ]
then
  usage
  exit 0
fi

OPTIONS=$*

if [ -r $HOME/.trucrc ]
then
  CONFIG_FILE=1
  DEFAULT_OPTIONS=`head -1 $HOME/.trucrc`
else
  CONFIG_FILE=0
  DEFAULT_OPTIONS=""
fi

read_command_line $DEFAULT_OPTIONS $OPTIONS
BFILE=`basename $FILE`
MY_TMP=/tmp/send_tmpdir_$BFILE_$$

copyright

if [ -r $HOME/.truc ]
then
  msgv 0 'WARNING: $HOME/.truc was ignored. Rename it into $HOME/.trucrc'
fi

if [ "$CONFIG_FILE" -eq "1" ]
then
  msgv 1 "Default options: $DEFAULT_OPTIONS"
else
  msgv 1 "No $HOME/.truc found"
fi

if [ "$DO_NOTHING" -eq "1" ]
then
  msgv 1 "I will not mail anything, just a test"
fi

msgv 9 "Address: $ADDRESS" 
msgv 9 "File to process: $FILE"
what_to_do $FILE
msgv 9 "Do the tar: $DO_TAR"
msgv 9 "Do the compression: $DO_COMPRESS"
msgv 9 "Do the uuencode: $DO_UUENCODE"

#Select the untruc script to include
for prog in $PROGD/untruc $STARTD/untruc `type untruc | cut -f3 -d' '`
do
  if [ -x $prog ]
  then
    UNTRUC_DIR=`dirname $prog`
    if [ "$UNTRUC_DIR" = "." ]
    then
      UNTRUC_DIR=`pwd`
    fi
    UNTRUC_PROG=$UNTRUC_DIR/untruc
    break
  fi
done

msgv 9 "UNTRUC_PROG: $UNTRUC_PROG"
if [ "$UNTRUC_PROG" = "" ]
then
  error 1 "untruc script to be included in sent packets not found..."
fi

if [ ! -x $UNTRUC_PROG ]
then
  error 1 "untruc script to be included in sent packets not found..."
fi

if [ "$PACKETS_TO_RESEND" != "" ]
then
  if [ "$DO_TAR" -eq "1" ]
  then
    error 1 "Sorry but I can't send a directory with -p option"
  fi
  msgv 1 "I will only send packets: $PACKETS_TO_RESEND"
fi

if [ -r $FILE ]
then
  msgv 0 "Start processing $FILE"
else
  error 1 "$FILE not found"
fi

if  [ -d $MY_TMP ]
then
  error 2 "$MY_TMP already existing. Send is probably already running"
else
  mkdir $MY_TMP
fi

if [ "$DO_TAR" -eq "1" ]
then
  msgv 1 "Taring $FILE"
  cd `dirname $FILE`
  msgv 9 "I'm in `pwd`"
  if (tar cf $MY_TMP/$BFILE.tar $BFILE)
  then
    TFILE=$BFILE.tar
  else
    error 1 "tar command failed"
  fi
  cd $STARTD
else
  if [ "$DO_COMPRESS" -eq "1" ]
  then
    msgv 1 "Copying $FILE"
    if (cp `truc_dirname $FILE`/$BFILE $MY_TMP/$BFILE )
    then
      TFILE=$BFILE
    else
      error 1 "cp command failed"
    fi
  else
    msgv 1 "Linking $FILE"
    if (ln -s `truc_dirname $FILE`/$BFILE $MY_TMP/$BFILE )
    then
      TFILE=$BFILE
    else
      error 1 "ln -s command failed"
    fi
  fi
fi

cd $MY_TMP

if [ "$DO_COMPRESS" -eq "1" ]
then
  msgv 1 "Compressing $TFILE using \"$COMPRESS\""
  if ( $COMPRESS $TFILE )
  then
    CFILE=$TFILE.$CSUF
  else
    error 1 "$COMPRESS command failed"
  fi
else
  CFILE=$TFILE
fi

if [ -x $CFILE ]
then
  EXEC_BIT=1
else
  EXEC_BIT=0
fi

if [ "$DO_UUENCODE" -eq "1" ]
then
  msgv 1 "Uuencoding $CFILE"
  if ($UUENCODE_CMD $CFILE < $CFILE > $CFILE.uu )
  then
    rm -f $CFILE
    UFILE=$CFILE.uu
  else
    error 1 "$UUENCODE_CMD command failed"
  fi
else
  UFILE=$CFILE
fi

SFILE=`head -1 $UFILE | awk '{print $3}'`
msgv 9 "SFILE: $SFILE"

echo $CODERCV > $UFILE.tmp
SED_FILE=sed_file_$$
cat <<EOF > $SED_FILE
/^#[^!]/D
/^ *$/D
/^$/D
s/^ *//g
s/ *$//g
EOF
cat $UNTRUC_PROG | sed -f $SED_FILE >> $UFILE.tmp
echo $CODERCV >> $UFILE.tmp
cat $UFILE >> $UFILE.tmp
mv $UFILE.tmp $UFILE

msgv 1 "Splitting $UFILE (maximum $LN_SIZE lines by packet)"
if (split -$LN_SIZE $UFILE $SFILE. )
then
  rm -f $UFILE
else
  error 1 "split command failed"
fi

INDEXES=$PACKETS_TO_RESEND
PACKETS_TO_RESEND=""
for i in $INDEXES
do
  PACKETS_TO_RESEND="$PACKETS_TO_RESEND %`nb_2_str $i`"
done

if [ "$PACKETS_TO_RESEND" != "" ]
then
  PKTS=`echo $PACKETS_TO_RESEND | sed -e "s/%/$SFILE./g"`
else
  PKTS=`ls $SFILE.*`
fi

NB_PKTS=`echo $PKTS |wc -w`
NB_PKTS_ALL=`ls -1 $SFILE.* |wc -l|sed 's/^ *//g'`

if [ $NB_PKTS != 1 ]
then
  msgv 1 "$NB_PKTS packets are going to be sent."
  msgv 1 "Waiting $TIME_SLEEP seconds between each of them"
else
  msgv 1 "Only 1 packet is going to be sent"
fi

IPKT=1
for i in $PKTS
do
  if [ "$IPKT" != 1 ]
  then 
    msgv 1 "Waiting $TIME_SLEEP seconds"
    if [ "$DO_NOTHING" != 1 ]
    then
      sleep $TIME_SLEEP
    fi
  fi
  send_packet $i
  IPKT=`expr $IPKT + 1`
done

send_report
send_mesg

clean_all

exit 0
# *** End of truc file, Version 1.0.6 ***
