#!/bin/bash

# This file is part of Mkat
#
# Copyright (C) 2004, 2005 Dmitry Maksyoma <ledestin at amur.ru>.
#
# Mkat 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.

#1. Make iso
#2. Burn iso
#3. Add the burned CD to the catalog
#4. Compare files on the CD with the original files

#Sensible defaults for necessary constants
CD_OPTS=('OVERBURN' '-overburn -dao' 'BLANK_MEDIA' 'blank=fast' 'SPEED' 'speed=$SPEED' 'MULTISESSION' '-multi')
DVD_OPTS=('OVERBURN' '-overburn' 'SPEED' '-speed=$SPEED' 'MULTISESSION' '-M' 'SINGLESESSION' '-Z')

RCFILE=mkatrc 
[ -f /etc/$RCFILE ] && source /etc/$RCFILE
[ -z "$MKAT_LIBPATH" ] && \
  { echo >&2 "MKAT_LIBPATH not set (edit /etc/$RCFILE)"; exit 1; }
. "$MKAT_LIBPATH/helpers.sh" || exit 1
load_config /etc/$RCFILE
load_config ~/.$RCFILE

#these options/variables, if defined, will be translated to parameters
#to CD or DVD burning program. Parameter dictionaries are defined in CD_OPTS and
#DVD_OPTS
OPTIONS="OVERBURN BLANK_MEDIA SPEED MULTISESSION SINGLESESSION"

#these vars must be defined
for v in DRIVE CD_BURN_CMD DVD_BURN_CMD CD LISTDIR TMP MKIMAGE_OPTS MKIMAGE_CMD ISO_IMAGE; do
  eval "var=\"\$$v\""
  if [ -z "$var" ]; then 
    echo >&2 "variable not defined: $v. Edit /etc/mkatrc or ~/.mkatrc"
    exit 1
  fi
done

#construct lockfile name following this template: ".$FILE.lock"
ISO_DIR="${ISO_IMAGE%/*}"
[ "$ISO_IMAGE" = "$ISO_DIR" ] && ISO_DIR=
LOCKFILE="${ISO_DIR:+$ISO_DIR/}.${ISO_IMAGE##*/}.lock"

#define constants
RET='
'
CD_FREE_BLOCKS=358400
DVD_FREE_BLOCKS=2295104

function usage {
  echo "usage: $0 [options] <label> <file>..."
  echo "  -n		    print estimated image size, exit"
  echo "  -sSPEED	    set burning speed"
  echo "  -c		    blank rewritable media"
  echo "  -a  --append      multisession disk"
  echo "  -o		    overburn"
  echo "  -rREC_OPTS	    pass parameters to burning program"
  echo "  -iMKIMG_OPTS	    pass parameters to image making program"
  echo "  -mMKAT_OPTS       pass parameters to mkat"
  echo "  -d  --dvd	    burn a DVD"
  echo "      --noimg	    don't create image, just burn"
  echo "      --nocat	    skip catalog"
  echo "      --nocheck	    skip afterburn check"
  echo "      --dbcheck	    check if the files are in mkat db"
  echo "  -y, --yes	    don't ask questions"
  echo "      --simulate    print only, --debug implied"
  echo "      --debug	    how stuff works"
  echo "  -h, --help	    print this help"
  exit $1
}

found=1
while [ $found ]; do
  case "$1" in
    "-h"|"--help") usage 0 ;;
    "-a"|"--append") MULTISESSION=1 ;; 
    "-n") PRINT_ONLY=1 ;;
    "-o") OVERBURN=1 ;;
    "-d"|"--dvd") BURN_DVD=1 ;;
    "--noimg") SKIP_MKIMAGE=1 ;;
    "--nocat") SKIP_CATALOG=1 ;;
    "--nocheck") SKIP_CHECK=1 ;;
    "--dbcheck") DB_CHECK=1 ;;
    "-y"|"--yes") NO_QUESTIONS=1 ;;
    "--simulate") SIMULATE=1; DEBUG=1 ;;
    "--debug") DEBUG=1 ;;
    "-c") BLANK_MEDIA=1;;
       *) unset found ;;
  esac
  [ "${1:0:2}" = "-r" ] && { REC_OPTS="$REC_OPTS ${1:2}"; found=1; }
  [ "${1:0:2}" = "-m" ] && { MKAT_OPTS="${1:2}"; found=1; }
  [ "${1:0:2}" = "-i" ] && { MKIMAGE_OPTS="$MKIMAGE_OPTS ${1:2}"; found=1; }
  if [ "${1:0:2}" = "-s" ]; then
    SPEED=${1:2}
    found=1
  fi
  [ $found ] && shift;
done

[ "$MKISO_OPTS" ] && MKIMAGE_OPTS="$MKIMAGE_OPTS $MKISO_OPTS"
[ -z $MULTISESSION ] && SINGLESESSION=1

function getopt() {
  name=$1; var=$2
  eval arr=("\"\${$name[@]}\"")
  i=0
  for o in "${arr[@]}"; do
    if [ "$o" == "$var" ]; then
      echo ${arr[$(($i+1))]}
      return
    fi
    i=$(($i+1))
  done
}

#TRANSLATE OPTIONS (e.g. -o => -overburn)
[ $BURN_DVD ] && OPTS="DVD_OPTS" || OPTS="CD_OPTS"
for o in $OPTIONS; do
  eval OPTION_CHECKED="\$$o"
  if [ "$OPTION_CHECKED" ]; then
    val=`getopt $OPTS $o`
    [ "$val" ] && eval val="\"$val\"" && REC_OPTS="$REC_OPTS $val"
  fi
done

#label and files must be provided
if [ -z $SKIP_MKIMAGE ]; then
  [ "$#" -lt 2 ] && {
    echo >&2 "not enough parameters"
    usage 1
  }
  #vars needed for $MKIMAGE_CMD
  LABEL="$1"; shift; FILES=("$@")
fi

#Check if files you're about to write are already archived (i.e. exist
#in mkat database)
if [ $DB_CHECK ]; then
  echo "Checking if the files are in mkat db"
  for f in "${FILES[@]}"; do
    mkat -m "$f"
    [ $? -eq 0 ] && ALREADY_IN_DB=1
  done
  if [ $ALREADY_IN_DB ]; then
    echo "Some files you are about to write are already in the mkat database." 
    read -p "Press Enter to write anyway or Control-C to abort"
    [ $? -ne 0 ] && exit
  fi
fi

set -e

#MAKE ISO IMAGE
if [ $PRINT_ONLY ]; then
  str=`mkisofs -print-size $MKIMAGE_OPTS "${FILES[@]}"`
  echo "$str"
  size=`echo $str | tail -1`
  echo $(($size*2048/1024**2))Mb
  [ $BURN_DVD ] && FREE_BLOCKS=$DVD_FREE_BLOCKS || FREE_BLOCKS=$CD_FREE_BLOCKS
  #complain if doesn't fit on media
  if [ $size -gt $FREE_BLOCKS ]; then 
    echo "won't fit: media size is $FREE_BLOCKS blocks, but $size blocks are to be written."
    diff=$(($size-$FREE_BLOCKS)) 
    echo "diff: $diff blocks or $(($diff*2048/1024**2))Mb"
  #suggest how much can be added to fill space
  elif [ $size -lt $FREE_BLOCKS ]; then
    diff=$(($FREE_BLOCKS-$size))
    echo "$diff more blocks or $(($diff*2048/1024**2))Mb could be added to fill space"
  fi
  exit
elif [ -z $SKIP_MKIMAGE ]; then
  echo "making ISO image"
  eval "debug $MKIMAGE_CMD"
  if [ -z $SIMULATE ]; then
    [ -d "$TMP" ] || mkdir -p "$TMP"
    debug "checking for lockfile $LOCKFILE"
    set +e
    dotlockfile -c $LOCKFILE
    if [ $? -eq 0 ]; then
      echo "$ISO_IMAGE is locked, probably being burned now"
      exit 1
    fi
    set -e

    #possible security issue when using existing directory
    #I check that current UID is the owner and the directory isn't world
    #writable
    if [ -d "$TMP" ]; then
      stat=(`stat -c '%u %A' "$TMP"`)
      [ ${stat[0]} = $EUID ] || \
	{ echo >&2 "error: $TMP isn't owned by current UID: $UID"; exit 1;}
      [ ${stat[1]:$((-2)):1} = "-" ] || \
        { echo >&2 "error: $TMP is world writable"; exit 1;}
    else
      #set umask=0022 only if $TMP resides in /tmp
      saved_umask=`umask`
      expr match "$TMP" /tmp
      [ $? -eq 0 ] && umask 0022
      mkdir "$TMP"
      umask $saved_umask
    fi
    eval "$MKIMAGE_CMD"
  fi
fi

#BURN
if [ -z $NO_QUESTIONS ] && [ -z $SKIP_MKIMAGE ]; then
  read -p "Press Enter to proceed to burn or Control-C to abort"
fi
echo "BURN!"
unset IFS
if [ -z $BURN_DVD ]; then
  eval "cmd=\"$CD_BURN_CMD\""
else
  eval "cmd=\"$DVD_BURN_CMD\""
fi
debug "$cmd"

if [ -z $SIMULATE ]; then
  debug "creating lock file before burning"
  dotlockfile $LOCKFILE && trap "dotlockfile -u $LOCKFILE" EXIT
  $cmd
  debug "releasing lock file"
  dotlockfile -u $LOCKFILE && trap - EXIT
fi

#CATALOG
if [ ! $SKIP_CATALOG ] && [ $CD ]; then
  echo "Catalog..."
  if [ $SIMULATE ]; then
    echo "mkat $MKAT_OPTS"
  else
    mkat $MKAT_OPTS
  fi
fi

IFS=$RET
#AFTERBURN CHECK
if [ ! $SKIP_CHECK ] && [ $CD ]; then
  set +e
  echo "Afterburn check..."
  if [ -z $SIMULATE ]; then
    for f in "${FILES[@]}"; do
      cmp "$f" "$CD/`basename "$f"`"
    done
  fi
fi

debug "going to sleep for $AUTOFS_DELAY seconds and eject"
[ -z $SIMULATE ] && sleep $AUTOFS_DELAY && eject
