#!/bin/sh
# *** Begin of untruc file, Version 1.0.7 ***
#  
#   "truc & untruc" scripts allow you to send and receive big files or 
#   directories using e-mail.
#   Copyright 1994-1998 - David Segonds
#  
#   Version 1.0.7, last modification: 30 Oct 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.7
COPYRIGHT="Copyright 1994-1998 - David Segonds"
DATEM="30 Oct 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

my_substr()
#%%%%%%%
{
 echo `$AWK 'BEGIN{print substr("'$1'",'$2','$3');}'`
}

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

 S1=`my_substr $ALP $N1 1`
 S2=`my_substr $ALP $N2 1`
 echo $S1$S2
}

str_2_nb ()
#%%%%%%%%%%%
{
 STR=$1
 L1=`my_substr $STR 1 1`
 L2=`my_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 ""
}

select_awk ()
#%%%%%%%%%%%
{
 for i in nawk awk
 do
   if ( $i 'BEGIN{}' > /dev/null 2>&1 )
   then
     AWK=$i
     return
   fi
 done
}

TMP_PREF=tmp_csplit
MY_TMP=/tmp/untruc_tmpdir_$$
GO_FURTHER=0
PROG=untruc

usage ()
{
cat <<END
usage: untruc [-h] [-x] [-v] [-d] [-q] [-r {yes|no} ] filename [filename2 ...]

-h       : Get this help
-x       : To extract as far as possible the content of the received file
           (i.e., .gz will be gunzipped, .tar untarred, etc.)
-v       : Verbose
-d       : Debug (Will print some debug message)
-q       : untruc will be totally quiet (no output message)
-r yes   : If sender ask for a receipt, it will be automatically sent.
-r no    : No receipt will be sent in any case.
filename : Files to process (at least one)
END
}

what_to_do ()
{
 BF=`basename $1`

 if [ "$BF" != "`basename $BF .gz`" ]
 then
   echo GZ `basename $BF .gz`
 fi

 if [ "$BF" != "`basename $BF .bz`" ]
 then
   echo BZ `basename $BF .bz`
 fi

 if [ "$BF" != "`basename $BF .bz2`" ]
 then
   echo BZ2 `basename $BF .bz2`
 fi

 if [ "$BF" != "`basename $BF .taz`" ]
 then
   echo GZ `basename $BF .taz`.tar
 fi

 if [ "$BF" != "`basename $BF .tgz`" ]
 then
   echo GZ `basename $BF .tgz`.tar
 fi

 if [ "$BF" != "`basename $BF .Z`" ]
 then
   echo Z `basename $BF .Z`
 fi

 if [ "$BF" != "`basename $BF .cr`" ]
 then
   echo CRYPT `basename $BF .cr`
 fi

 if [ "$BF" != "`basename $BF .crypt`" ]
 then
   echo CRYPT `basename $BF .crypt`
 fi

 if [ "$BF" != "`basename $BF .pgp`" ]
 then
   echo PGP `basename $BF .pgp`
 fi

 if [ "$BF" != "`basename $BF .tar`" ]
 then
   echo TAR `basename $BF .tar`
 fi
}

go_further ()
{
  if [ $GO_FURTHER -eq 0 ]
  then
    return
  fi

  if [ $# -eq 0 ]
  then
    error 3 "go_further needs an argument"
  fi

  GFILE=$1
  msgv 0 "Extracting $GFILE"
  STOP=0
  while [ $STOP -eq 0 ]
  do
    RET=`what_to_do $GFILE`
    WHAT=`echo $RET | $AWK '{print $1}'`
    NGFILE=`echo $RET | $AWK '{print $2}'`
    case $WHAT in
    "CRYPT")
      msgv 1 "Uncrypt your file"
      if ( crypt < $GFILE > $NGFILE )
      then
        msgv 9 "crypt OK"
      else
        error 1 "crypt command failed"
      fi
    ;;
    "PGP")
      msgv 1 "Ununcipher your file"
      if ( pgp $GFILE )
      then
        msgv 9 "pgp OK"
      else
        error 1 "pgp command failed"
      fi
    ;;
    "TAR")
      msgv 1 "Untar your file"
      if ( tar xvf $GFILE )
      then
        msgv 9 "tar OK"
        rm $GFILE
        STOP=1
      else
        error 1 "tar command failed"
      fi
    ;;
    "GZ")
      msgv 1 "gunzip your file"
      if ( gzip -d $GFILE )
      then
        msgv 9 "gz OK"
      else
        error 1 "gzip -d command failed"
      fi
    ;; 
    "BZ")
      msgv 1 "bunzip your file"
      if ( bzip -d $GFILE )
      then
        msgv 9 "bz OK"
      else
        error 1 "bzip -d command failed"
      fi
    ;;
    "BZ2")
      msgv 1 "bunzip2 your file"
      if ( bzip2 -d $GFILE )
      then
        msgv 9 "bz2 OK"
      else
        error 1 "bzip2 -d command failed"
      fi
    ;;
    "Z")
      msgv 1 "uncompress your file"
      if ( uncompress $GFILE )
      then
        msgv 9 "Z OK"
      else
        error 1 "uncompress command failed"
      fi
    ;;
    *) STOP=1
    esac
    GFILE=$NGFILE
  done
}

read_command_line()
#%%%%%%%%%%%%%%%%%%
{
    while [ `echo X$1 | $AWK '{print substr($1,2,1)}'` = "-" ]
    do
    case $1 in
    "-h")
        copyright
        usage
        exit 0
    ;;
    "-x")
        GO_FURTHER=1
        shift 1
    ;;
    "-d")
        VERBOSE=9
        shift 1
    ;;
    "-q")
        VERBOSE=-1
        shift 1
    ;;
    "-v")
        VERBOSE=1
        shift 1
    ;;
    "-r")
        RECEIPT_ANSWER=$2
        shift 2
    ;;
    *)
        OPTION=$1
        msgv 9 "$OPTION"
        usage     
        error 1 "Option not recognized: $OPTION"
    esac
    done	
    
    FILES_TO_PROCESS=$*    
}

# Main program
if [ $# -eq 0 ]
then
  copyright 
  usage
  exit 0
fi

OPTIONS=$*

# Select the awk version to use
select_awk

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

read_command_line $DEFAULT_OPTIONS $OPTIONS

copyright

if [ $# -eq 0 ]
then
 usage
 exit 0
fi

if  [ -d $MY_TMP ]
then
  error 2 "$MY_TMP already existing" >&2
else
  if (mkdir $MY_TMP)
  then
    msgv 9 "mkdir OK"
  else
    error 1 "mkdir command failed"
  fi
fi

for FILE in $FILES_TO_PROCESS
do
  BFILE=`basename $FILE`
  FILE=`truc_dirname $FILE`/$BFILE
  msgv 9 "FILE: $FILE BFILE: $BFILE"
  if( ln -s $FILE $MY_TMP/$BFILE )
  then
    msgv 9 "ln -s OK"
  else
    error 1 "ln -s command failed"
  fi

  cd $MY_TMP
  FILE=$BFILE
  msgv 1 "Excluding untruc source"
  EXIT=""
  while [ "$EXIT" = "" ]
  do
    if( csplit -s -f tmp_file $FILE "/^$CODERCV/" "/^$CODERCV/+1">/dev/null 2>&1 )
    then
      msgv 9 "One exclusion"
      rm $FILE
      cat tmp_file00 tmp_file02 > $FILE
      rm tmp_file*
    else
      EXIT="1"
    fi
  done

  msgv 0 "Preprocessing $FILE"
  NB_HDR=`grep -n $CODEH $FILE | wc -l`
  if [ $NB_HDR = 0 ]
  then
    msgv 0 "Keyword $CODEH not found in $FILE... Trying uudecode"
    cd $STARTD
    if ( uudecode $FILE )
    then
      msgv 0 "$FILE successfully uudecoded"
      cd $MY_TMP
      FILE=`grep begin $FILE | cut -f3 -d' '`
      FILE_TO_GO_FURTHER=`echo $FILE_TO_GO_FURTHER $FILE`
    else
      cd $MY_TMP
      msgv 0 "uudecode failed. $FILE ignored"
    fi
  else
    NB_HDR=`expr $NB_HDR - 1`
    msgv 9 "Debug"
    if [ "$NB_HDR" -gt 99 ]
    then
      error 1 "$NB_HDR packets in one file, the maximum is 99"
    fi
    if (csplit -s -f $TMP_PREF. $FILE "/^$CODEH/" "{$NB_HDR}")
    then
      msgv 9 "csplit OK"
    else
      error 1 "csplit command failed"
    fi
    rm $TMP_PREF.00 $FILE
    for i in `ls $TMP_PREF.*`
    do
     grep -n $CODES $i > tmp_line
     if [ `cat tmp_line | wc -l` != 1 ]
     then 
       error 1 "$CODES not found in packet $i for the file $FILE"
     fi
     FILENAME=`cat tmp_line | sed "s/.*$CODES//"`

     grep "File" $i > tmp_line
     if [ `cat tmp_line | wc -l` = 0 ]
     then 
       error 1 "\"File\" Keyword not found in packet $i for the file $FILE"
     fi
     FILE_LIST_NEW=`cat tmp_line | sed "s/.*File://"`
     if [ -z "`echo $FILE_LIST | grep $FILE_LIST_NEW`" ]
     then
       FILE_LIST="$FILE_LIST $FILE_LIST_NEW"
     fi

     mv $i $FILENAME
    done
  fi
  cd $STARTD
done

cd $MY_TMP
for FILE in $FILE_LIST
do
  SKIP=0
  RECEIPT=""

  msgv 0 "Building $FILE"
  i=$FILE.aa
  if test ! -r $i
  then
    msgv 0 "First packet for $FILE is missing"
    SKIP=1 
  fi

  if [ $SKIP = 0 ]
  then
    grep "Total" $i > tmp_line
    if [ `cat tmp_line | wc -l` = 0 ]
    then 
      error 1 "\"Total\" Keyword not found in packet $i for the file $FILE"
      SKIP=1
    else
      NB_PACKETS=`cat tmp_line | sed "s/.*Total: //"| cut -d " " -f 1`
    fi    

    grep "Receipt" $i > tmp_line
    if [ `cat tmp_line | wc -l` != 0 ]
    then 
      RECEIPT=`cat tmp_line | sed "s/.*Receipt: //"`
    fi 

    grep "Exec" $i > tmp_line
    if [ `cat tmp_line | wc -l` != 0 ]
    then
      EXEC_BIT=`cat tmp_line | sed "s/.*Exec: //"`
    else 
      EXEC_BIT=0
    fi

    I_HAVE=`ls -1 $FILE.* | wc -l`
    if [ $I_HAVE != $NB_PACKETS ]
    then
      MISSING=`expr $NB_PACKETS - $I_HAVE`
      if [ "$MISSING" != "1" ]
      then
        M1="s are"
        M2="them"
      else
        M1=" is"
        M2="it"
      fi
      msgv 0 "I should have $NB_PACKETS packets. $MISSING packet$M1 missing:"
      ls $FILE* | sed "s/^$FILE\.//g" > arrived
      NI=1
      rm -f liste_pkts
      while [ "$NI" -le "$NB_PACKETS" ]
      do
        nb_2_str $NI >> liste_pkts
        NI=`expr $NI + 1`
      done
      ALPHA_MISSING=`diff arrived liste_pkts | grep ">" | sed 's/> //g'`
      INDEX_MISSING=""
      for i in $ALPHA_MISSING
      do
        INDEX_MISSING="$INDEX_MISSING `str_2_nb $i`"
      done
      msgv 0 "$INDEX_MISSING"
msgv 0 "-p option can be used to resend $M2 except if a directory was sent."
      SKIP=1
    fi
  fi # ? SKIP = 0

  if [ $SKIP = 0 ]
  then 
    for i in `ls $FILE.*`
    do
      msgv 1 "$i"
      csplit -s -f $TMP_PREF. $i "/^$CODES/+1" "/^$CODEE/"
      cat $TMP_PREF.01 >> $FILE.uu
      rm $i
    done
    rm $TMP_PREF.*
    uudecode $FILE.uu
    if ( cp -i $FILE $STARTD )
    then
      msgv 0 "$FILE successfully rebuilt"
      if [ "$RECEIPT" != "" -a "$RECEIPT_ANSWER" != "no" ]
      then
        if [ "$RECEIPT_ANSWER" = "yes" ]
        then
          ANSWER=""
        else 
          echo -n "$RECEIPT asked for a receipt. Do I send one? (yes/no)[yes] "
          read ANSWER
        fi
        if [ "$ANSWER" = "yes" -o "$ANSWER" = "" ]
        then
          echo "To: $RECEIPT" > tmp_file
          echo "Subject: [untruc] Receipt for $FILE" >> tmp_file
          echo "$FILE has been successfully rebuilt" >> tmp_file
          echo "*** Message generated by untruc $VERSION ***" >> tmp_file
          if ( $MAIL < tmp_file )
          then
            msgv 0 "Receipt sent to $RECEIPT"
          else
            error 1 "Error when sending receipt"
          fi
        fi
      fi
    else
      error 1 "Copy of $FILE failed! Rebuilding failed!"
    fi
    chmod u+rw $STARTD/$FILE
    if [ "$EXEC_BIT" = "1" ]
    then
      msgv 1 "Making the file $FILE executable"
      chmod u+x $STARTD/$FILE
    fi
    FILE_TO_GO_FURTHER=`echo $FILE_TO_GO_FURTHER $FILE`
  fi
done
cd $STARTD

for FILE in $FILE_TO_GO_FURTHER
do
  go_further $FILE
done

rm -rf $MY_TMP

exit 0
# *** End of untruc file, Version 1.0.7 ***

