#!/bin/bash
#---------------------------------------------------------------------
## @Synopsis cast is the spell installation utility. It can be called by the user or by sorcery
## @Copyright Original version Copyright 2001 by Kyle Sallee
## @Copyright Some parts copyright 2002 Anders Bruun Olsen et al
## @Copyright Other additions/corrections Copyright 2002 by the Source Mage Team
## Script to cast spells.
#---------------------------------------------------------------------

#-----
## Help... hmm... I wonder what it does...
#-----
function help() {

  cat  <<  EOF

Cast installs single or multiple spells

Example:          cast  nano hdparm sudo
Usage:            cast  [parameters]  [spell]

Optional Parameters:

       --cflags                 Custom CFLAGS
       --cxxflags               Custom CXXFLAGS
       --ldflags                Custom LDFLAGS
       --no-opts                Turn off setting optimization flags, except
                                for those found in --cflags, --cxxflags and
                                --ldflags

-V [on|off]                     Override \$VOYEUR setting

-f  |  --fix                    Discover and fix broken spells
-n  |  --nofix                  Discover, but do not fix broken spells
                                (Both deprecated, use cleanse instead)

-d  |  --download               Force download of sources (overwrite existing
                                files)

-s                              Download all given spells before compiling
       --deps                   Configure spells and determine dependencies,
                                only cast dependencies, not spells themselves

-c  |  --compile                Recompile the spells (dont install from cache).
-r  |  --reconfigure            Select new dependencies for spells (implies -c)

-R  |  --recast-down            Recast depended-upon spells, even if they are
                                already installed...
-B  |  --recast-up              Recast dependent spells, even if they are
                                already installed...

-b  |  --force-base-dep         Force all spells to depend on basesystem

       --from   directory       Specify an alternate for $SOURCE_CACHE
       --url    URL             Specify an alternate download URL

       --pam                    Re-casts all installed spells that
                                can use Linux-PAM

       --queue                  Casts all spells listed in $INSTALL_QUEUE

EOF

  exit  1

}

#---------------------------------------------------------------------
## @Aguments Arguments of cast
## @Globals DEPS_ONLY RECONFIGURE COMPILE 
## @Globals FORCE_DOWNLOAD SOURCE_CACHE SILENT FIX NOFIX SEPARATE
## @Globals BASE_URL INSTALL_QUEUE 
##
## Sets these globals except INSTALL_QUEUE according to cast's 
## arguments.
## Requires some user interaction if --queue is given and starts
## another cast with INSTALL_QUEUE's content as parameter.
#---------------------------------------------------------------------
function process_parameters()  {

  while  [  -n  "$1"  ];  do

    if  echo  "" $1  |  grep  -q  "^ -";  then

      case  $1  in

            --cflags)  export OVERRIDE_CFLAGS="$2";    COMPILE="-c"; shift 2  ;;
          --cxxflags)  export OVERRIDE_CXXFLAGS="$2";  COMPILE="-c"; shift 2  ;;
           --ldflags)  export OVERRIDE_LDFLAGS="$2";   COMPILE="-c"; shift 2  ;;
           --no-opts)  export NO_OPTIMIZATION_FLAGS=1; COMPILE="-c"; shift 1  ;;
                  -V)  export VOYEUR_OVERRIDE="$2";                  shift 2  ;;
              --deps)  export  DEPS_ONLY="$1";                       shift 1  ;;
    -r|--reconfigure)  RECONFIGURE="$1"; COMPILE="-c";               shift 1  ;;
    -R|--recast-down)  RECAST_DOWN="$1";                             shift 1  ;;
      -B|--recast-up)  RECAST_UP="$1";                               shift 1  ;;
 -b|--force-base-dep)  FORCE_BASESYSTEM_DEPENDS=on;                  shift 1  ;;
        -c|--compile)  COMPILE="$1";                                 shift 1  ;;
       -d|--download)  export  FORCE_DOWNLOAD="$1"; COMPILE="-c";    shift 1  ;;
              --from)  export  SOURCE_CACHE=$2;                      shift 2  ;;
            --silent)  SILENT="$1";                                  shift 1  ;;
            -f|--fix)  export  FIX="$1";                             shift 1  ;;
          -n|--nofix)  export  FIX="--fix"                         
                       export  NOFIX="$1";                           shift 1  ;;
                  -s)  export  SEPARATE="$1";                        shift 1  ;;
               --url)  export  BASE_URL="$2";                        shift 2  ;;
               --pam)  cast  -c  `find_pam_aware` ;                  shift 1  ;;
             --queue)  
                       if query "Would you like review the queue history for each spell?" n ; then
                         sorcery review-queue
                       fi

                       if  [  -s $INSTALL_QUEUE  ]; then
                         message -n "${MESSAGE_COLOR}Casting install queue..."
                         message    "${DEFAULT_COLOR}"

                         # remove possible empty lines from queue.
                         grep -Ev '^$' $INSTALL_QUEUE >"$INSTALL_QUEUE.new"
                         rm -f "$INSTALL_QUEUE"
                         mv "$INSTALL_QUEUE.new" "$INSTALL_QUEUE"

                         # cast the queue.
                         # SILENT and RECONFIGURE may be empty, they
                         # must be at the end or it will confuse parameter
                         # parsing
                         cast -c `cat $INSTALL_QUEUE 2>/dev/null` "$SILENT" "$RECONFIGURE"
            
                         # report spells still in queue.
                         if  [  -s  $INSTALL_QUEUE  ] ; then
                           message "${MESSAGE_COLOR}The install queue is not empty, "
                           message "it still contains the following spells: "
                           message "---------------------------------${PROBLEM_COLOR}"
                           message "`cat $INSTALL_QUEUE 2>/dev/null`"
                           message "${DEFAULT_COLOR}"
                         fi
                       fi;                               
                       shift 1                                ;;
                   *)  help                                   ;;
      esac

    else

      shift
 
   fi

  done

}

#---------------------------------------------------------------------
## @Arguments cast's arguments
## Goes through arguments and prints spells or parameters that are no
## switches rather.
#---------------------------------------------------------------------
function strip_parameters()  {

  while  [  -n  "$1"  ];  do

    if  echo  "" $1  |  grep  -q  "^ -";  then

      case  $1  in

                  --deps)  shift 1  ;;
                --cflags)  shift 2  ;;
              --cxxflags)  shift 2  ;;
               --ldflags)  shift 2  ;;
               --no-opts)  shift 1  ;;
                      -V)  shift 2  ;;
        -R|--recast-down)  shift 1  ;;
          -B|--recast-up)  shift 1  ;;
     -b|--force-base-dep)  shift 1  ;;
        -r|--reconfigure)  shift 1  ;;
                  --from)  shift 2  ;;
                --silent)  shift 1  ;;
                -f|--fix)  shift 1  ;;
              -n|--nofix)  shift 1  ;;
            -c|--compile)  shift 1  ;;
           -d|--download)  shift 1  ;;
                      -s)  shift 1  ;;
                   --url)  shift 2  ;;
                   --pam)  shift 1  ;;
                 --queue)  shift 1  ;;
                       *)  shift 1  ;;

      esac

    else

      echo  $1
      shift
 
   fi

  done

}

#---------------------------------------------------------------------
## Cast a single spell. When this function is called, all dependencies
## have been taken care of and we are allowed to cast this.
## @Globals SPELL
#---------------------------------------------------------------------
function cast_spell()  { (

  debug "cast" "Casting spell [$SPELL]"
  set_term_title "Casting spell [$SPELL]"

  run_details 
  load_build_api || return 1

# these both prompt, and prompting should NOT occur at this point
# someday they will get split to a query and action pair (like use_xinetd
# and install_xinetd) (afk 4/10/04)
  run_security  &&
  run_conflicts || return 1

  # show_downloading tail -f's (essentially) the download log as it
  # comes in, or if downloading is complete, cats the download log, in
  # either case it blocks until downloading is complete by the presence of
  # a ${download_log}.done file. If SEPARATE is set, then all downloading
  # is done first, so there is no need to wait for it to complete.
  if [[ ! $SEPARATE ]] ; then
    show_downloading $SPELL
  fi

  verify_sources ||   return 1
  
  # wait for solo casts, to finish and ensure that others can't
  acquire_cast_lock

  # all this needs to reorganized and stuff...later

  IW_LOG="$TMP_DIR/$SPELL.iw"

  #some minor discussion occured about having this, i'll leave it out for now
  activity_log  "cast"  "$SPELL"  "$VERSION"  "start"

  # must declare OPS before sourcing config
  local OPTS
  run_spell_config                            

  # this should probably be moved...
  spell_depends=$(hash_get uncommitted_hash $SPELL)
  test -e $spell_depends && 
  OPTS="$OPTS $(get_depends_options $spell_depends $SPELL)"
  
  # this will run through the whole build process
  run_build_spell
  rc=$?

  # This is the home for anything and everything we do
  # when a phase4 succeeds or fails, no more spreading things out
  # into multiple functions.

  cd /

  pop_install_queue "$SPELL"    

  # hooks back out to the build_api to do whatever needs to be done
  if [ $rc == 0 ] ; then
    run_spell_success
  else
    run_spell_failure $rc
  fi


  unlock_resources "cast" "$SPELL"
  #It's OK to try to release a lock you don't have
  unlock_resources "solo" "cast"

  return $rc

) }

##Removed *_solo functions, Duff 2002/11/01

#---------------------------------------------------------------------
## @Globals SPELLS
## @Stdout User information ("Collating dependencies")
## @Globals SPELL DEPS_ONLY
##
## Do dependency resolution. Takes the spells in the $SPELLS variable
## and resolves them. A superset list is created called $SPELLS_TO_CAST
#---------------------------------------------------------------------
function pass_one()  {
  #  This pass does configuration and dependency identification.
  debug "cast" "Starting pass_one()"

  echo -n "Computing previously installed dependencies..."
  compute_installed_depends "dep_f_hash"
  echo
  compute_uninstalled_depends "to_cast" "back_hash" "bad_spells" $SPELLS

  SPELLS_TO_CAST=$(hash_get_table_fields "to_cast"|tr '\n' ' ')

  SPELLS="$SPELLS ${UP_DEPENDS[*]}"

  # special case of no spell making it through dependency resolution
  # or if DEPS_ONLY is set, there arent any dependent spells to cast
  if [ -z "$SPELLS_TO_CAST" ] ; then 
    local cannot_cast=$(hash_get_table_fields "bad_spells")
    message "${PROBLEM_COLOR}No spells to cast!${DEFAULT_COLOR}"
    message "${MESSAGE_COLOR}Cannot cast these spells:${DEFAULT_COLOR}"
    message "---------------------------"
    message "${PROBLEM_COLOR}${cannot_cast}" | tr '[:blank:]' '\n' | column 
    message "${DEFAULT_COLOR}"
    exit 1
  fi

  # if only doing the deps, find the dependencies and make them the
  # SPELLS list, then recompute the full list of spells that needs to be cast
  if  [[ "$DEPS_ONLY" ]] ;  then
    local dep_spell
    SPELLS=$(
      for spell in $SPELLS; do
        for dep_spell in $(hash_get to_cast $spell); do
          spell_ok $dep_spell || echo $dep_spell
        done
      done|sort|uniq)
    spells=( $SPELLS )
    hash_reset deps_only
    hash_reset looked_at
    for ((i=0;$i<${#spells[@]}; i++)); do
      if [[ "${spells[$i]}" ]] &&
         ! [[ $(hash_get looked_at "${spells[$i]}") ]] ; then
        hash_put looked_at "${spells[$i]}" done
        if ! spell_ok ${spells[$i]}; then
          hash_put deps_only ${spells[$i]} done
          new_spells=$(for each in $(hash_get to_cast "${spells[$i]}"); do
            echo $each
          done)
        fi
        spells=( ${spells[@]} $new_spells )
        unset new_spells
      fi
    done
    SPELLS_TO_CAST=$(hash_get_table_fields "deps_only"|tr '\n' ' ')
    hash_reset deps_only
    hash_reset looked_at
    if [ -z "$SPELLS_TO_CAST" ] ; then 
      local parents=$(hash_get_table_fields "to_cast")
      message "${PROBLEM_COLOR}No spells to cast!${DEFAULT_COLOR}"
      message "${MESSAGE_COLOR}None of the spells have dependencies" \
              "to cast:${DEFAULT_COLOR}"
      message "---------------------------"
      message "${PROBLEM_COLOR}${parents}" | tr '[:blank:]' '\n' | column 
      message "${DEFAULT_COLOR}"
      exit 1
    fi
  fi

  message "${MESSAGE_COLOR}Collating dependencies...${DEFAULT_COLOR}"

  # have new depends overwrite existing ones
  for i in $SPELLS_TO_CAST; do
    hash_put dep_f_hash $i "$(hash_get to_cast $i)"
  done

  debug "cast" "pass_one, done with SPELLS=$SPELLS"

}


#---------------------------------------------------------------------
## @Arguments Spells to be cast
## @Stdout the "Spells are to be cast" message.
## @Stdin User interface, y or n  
## @Globals SEPARATE
## Asks whether you want to cast the listed spells or not.
## Returns if not. 
## Then it starts pass three and four by calling make.
## Depending on SEPARATE it starts pass three in the background
## or not.
#---------------------------------------------------------------------
function pass_two()  {
  #  This pass downloads required sources.
  #  And starts the make process
  debug "cast" "Starting pass_two()"

  unset_details

  message "${MESSAGE_COLOR}Spells are to be cast:${DEFAULT_COLOR}"
  message "---------------------------"
  message "${SPELL_COLOR}${SPELLS_TO_CAST}" | tr '[:blank:]' '\n' | column 
  message "${DEFAULT_COLOR}"

  if ! query "Do you want to cast these spells?" "y" ; then
    message "Ok, quitting cast. Figure out what you want."
  return 1
  fi

  rm -f $TMP_DIR/pass_three.done # dont return until this file exists
  MINUS_K=yes
  if  [[  $SEPARATE   ]] ; then
    ( CAST_PASS="three" 
      depengine_entry_point "$SPELLS" "$SPELLS_TO_CAST"
      if [[ $SCREEN_NAME ]] ; then
        screen_notify "$SCREEN_NAME" "Done downloading"
        screen_kill_window "$SCREEN_NAME" $SCREEN_SUMMON_WIN
      fi
      touch $TMP_DIR/pass_three.done
    )
  else
    ( CAST_PASS="three"
      trap exit INT TERM # this keep a rather nasty message
                                    # from appearing if we get killed
      depengine_entry_point "$SPELLS" "$SPELLS_TO_CAST"
      if [[ $SCREEN_NAME ]] ; then
        screen_notify "$SCREEN_NAME" "Done downloading"
        screen_kill_window "$SCREEN_NAME" $SCREEN_SUMMON_WIN
      fi
      touch $TMP_DIR/pass_three.done &>/dev/null
    ) &
  fi
  
  debug "cast" "Starting stage four make."
  
  (
    CAST_PASS="four" 
    depengine_entry_point "$SPELLS" "$SPELLS_TO_CAST"
    touch $TMP_DIR/pass_four.done
  )

  
  # pass three might not finish, give it a short amount of time to complete
  # in case its near the end of a download or something, if after a minute
  # it doesn't finish just kill everything off.
  # in 1.14 this may be improved, see bug 8763
  local i
  let i=0
  if ! test -e $TMP_DIR/pass_three.done; then
    message "Download pass has not completed yet, pausing momentarily"
  fi
  while ! test -e $TMP_DIR/pass_three.done; do 
    sleep 5
    let i+=5
    if [[ $i -gt 60 ]] ; then
      message "Download pass did not finish, killing it off."
      # this is rather violent, but job control in bash lame and theres
      # no other way to kill everything off effectively :-(
      ps x|grep $TMP_DIR|awk '{print $1}'|grep -v $$|xargs kill &>/dev/null
      echo -n .; sleep 1
      ps x|grep $TMP_DIR|awk '{print $1}'|grep -v $$|xargs kill &>/dev/null
      echo -n .; sleep 1
      ps x|grep $TMP_DIR|awk '{print $1}'|grep -v $$|xargs kill -9 &>/dev/null
      echo -n .;  sleep 1
      echo
      break
    fi
  done

}

#---------------------------------------------------------------------

## @param spellname
## @Globals SPELL
## Sets SPELL to the spellname and calls summon_spell with spellname
## as argument. This is equivalent to calling summon, but without the
## overhead.
## (Is being called by make)
## If in screen mode it also execs a tail to the summon window
#---------------------------------------------------------------------
function pass_three()  {
  debug "cast" "pass_three - $*"
  unset CAST_PASS
  trap exit INT TERM
  local SPELL=$1

  # download_log is removed with it's .done in libcast
  local download_log=$(get_spell_dl_log $SPELL)

  if [[ $SCREEN_NAME ]] && [ ! -p $TMP_DIR/download.fifo ] ; then
    # Create the summon window
    mkfifo $TMP_DIR/download.fifo
    # Neither tail not cat work properly on FIFOs so a while loop will
    # have to be used
    screen_new_window "$SCREEN_NAME" $SCREEN_SUMMON_WIN "Summon $SPELL" \
      /bin/bash -c  'while : ; do 
          read LINE && echo $LINE || sleep 0.1 ; 
        done < '$TMP_DIR/download.fifo
    sleep 0.1
  fi
  if [[ $SCREEN_NAME ]] ; then
    # A summon window is already up, just change the name
    screen_name_window "$SCREEN_NAME" $SCREEN_SUMMON_WIN "Summon $SPELL"
    # symlink the d/l log to the fifo
    ln -s $TMP_DIR/download.fifo $download_log
  else 
    # normal non-screen cast, create a normal file
    touch $download_log
  fi
  
  # check if this is being resurrected and if so, dont summon
  # this will go away when resurrect support and dependency resolution merge
  if ! [[ $COMPILE ]] ; then
    VERSION=$(codex_set_current_spell_by_name $SPELL &> /dev/null;echo $VERSION)
    if [[ $VERSION ]] && can_resurrect $SPELL $VERSION &> /dev/null ; then
      # The 2>/dev/null is necessary because the dir may not exist
      echo "pass_three thought that $SPELL was being resurrected" \
        > $download_log 2>/dev/null
      # touch the 'log' file just in case the spell disagreed so cast doesnt
      # hang forever
      touch ${download_log}.done &>/dev/null
      return
    fi
  fi
  
  if  [[  $SEPARATE   ]] ; then
    summon_spell "$SPELL" >"$download_log"
  else
    lock_file   $download_log
    summon_spell "$SPELL" >  "$download_log"
    unlock_file   $download_log
  fi
  
  # This is to notify show_downloading/cast_spell that it is done with
  # this source
  touch "${download_log}.done"
}

#---------------------------------------------------------------------
## @param spellname
## @Globals SPELL COMPILE
## Sets SPELL to spellname.
## Calls trigger "pre_cast"
## If COMPILE is not set and it can be resurrected 
## (can_resurrect SPELL) it calls resurrect with SPELL as argument.
## Otherwise it calls cast_spell.
## If resurrect or cast_spell returned 0 it calls trigger "cast"
## (Is being called by make)
#---------------------------------------------------------------------
function pass_four()  {

  debug "cast" "pass_four - $*"
  local do_resurrect=no
  local VERSION
  unset CAST_PASS
  SPELL=$1

  trigger "pre_cast"

  if ! [[ $COMPILE ]] ; then
    # hacky way to get the latest version
    VERSION=$(codex_set_current_spell_by_name $SPELL &> /dev/null;echo $VERSION)
    if [[ ! $VERSION ]] ; then
      message "Cant find spell version for some reason, is $SPELL a spell?"
    else
      can_resurrect $SPELL $VERSION &> /dev/null && do_resurrect=yes
    fi
  fi

  # this is a hacky way to tell what version we're updating from
  # if any, we can use it to find md5 logs for installing config type
  # files, it mostly is here for libresurrect.real_install_config_file
  local OLD_SPELL_VERSION
  spell_ok $SPELL && OLD_SPELL_VERSION=$(installed_version $SPELL)

  local rc
  if [[ "$do_resurrect" == "yes" ]] ; then
    resurrect $SPELL $VERSION
    rc=$?
    # this is here for safety in case resurrect bails out somewhere
    # we didnt expect it to
    unlock_resources "libgrimoire" "install"
    unlock_resources "cast" "$SPELL"
    unlock_resources "solo" "cast"
  else
    cast_spell $*
    rc=$?
  fi

  return $rc
}


#---------------------------------------------------------------------
## @Globals SUCCESS_LIST FAILED_LIST CHECK_TRIGGERS_SUCCESS
## CHECK_TRIGGERS_FAILURE
## Does report generation.
#---------------------------------------------------------------------
function pass_five()  {

  debug "cast" "Function : pass_five"

  # must exist or we get problems with checks here.
  touch $SUCCESS_LIST
  touch $FAILED_LIST
  touch $CHECK_TRIGGERS_SUCCESS
  touch $CHECK_TRIGGERS_FAILURE
  touch $CONFLICT_LIST
  
  debug "pass_five" "SUCCESS LIST is : `cat $SUCCESS_LIST 2>/dev/null`"
  debug "pass_five" "FAILED LIST is : `cat $FAILED_LIST 2>/dev/null`"
  debug "pass_five" "CONFLICT LIST is : `cat $CONFLICT_LIST 2>/dev/null`"

  if [ -s $SUCCESS_LIST ] ; then

    message "${MESSAGE_COLOR}Finished processing install requests."
    message ""
    message "Spells installed successfully:"
    message "------------------------------${SPELL_COLOR}"

    for item in `cat $SUCCESS_LIST 2>/dev/null`; do
      message "$item"
    done | column
   
    set_term_title "Casting successfull."
    message "${DEFAULT_COLOR}"

  fi 

  if  [  -s  $CHECK_TRIGGERS_SUCCESS ] ; then
    message "${DEFAULT_COLOR}"
    message "${MESSAGE_COLOR}Spells that had a check_self trigger succeed:"
    message "-----------------------------------------------${SPELL_COLOR}"
    for item in `cat $CHECK_TRIGGERS_SUCCESS 2>/dev/null`; do
      message "$item"
    done | column
    message "${DEFAULT_COLOR}"
  fi

  if  [  -s  $CHECK_TRIGGERS_FAILURE ] ; then
    message "${DEFAULT_COLOR}"
    message "${MESSAGE_COLOR}Spells that had a check_self trigger fail:"
    message "-----------------------------------------------${SPELL_COLOR}"
    for item in `cat $CHECK_TRIGGERS_FAILURE 2>/dev/null`; do
      message "$item"
    done | column
    message "${DEFAULT_COLOR}"
  fi

  local NOT_CAST
  NOT_CAST=$( { hash_get_table_fields to_cast 
    cat $SUCCESS_LIST
    cat $FAILED_LIST
    cat $CHECK_TRIGGERS_SUCCESS
    } | sort | uniq -u ) # all not caught otherwise
  if [[ "$NOT_CAST" ]] ;then
    message "${DEFAULT_COLOR}" #being paranoid
    message "${MESSAGE_COLOR}Spells that have been dropped:"
    message "------------------------------${QUERY_COLOR}"
    message "$NOT_CAST" | column
    message "${DEFAULT_COLOR}"
  fi

  if  [  -s  $CONFLICT_LIST   ] ; then
    message "${DEFAULT_COLOR}"
    message "${MESSAGE_COLOR}Spells that have been removed due to conflicts:"
    message "-----------------------------------------------${QUERY_COLOR}"
    for item in `cat $CONFLICT_LIST 2>/dev/null`; do
      message "$item"
    done | column
    message "${DEFAULT_COLOR}"
  fi
  
  #
  # To check for failed spells, we only need to see what is remaining in the 
  # install queue.
  #
  if  [  -s  $FAILED_LIST   ] ; then
    
    message "${DEFAULT_COLOR}"
    message "${MESSAGE_COLOR}Spells that encountered problems:"
    message "---------------------------------${PROBLEM_COLOR}"

    for item in `cat $FAILED_LIST 2>/dev/null`; do
      message "$item"
    done | column

    set_term_title "Casting failed."
    message "${DEFAULT_COLOR}"
    return 1

  fi 
  
  debug "cast" "End of pass_five"

}

#---------------------------------------------------------------------
## @Arguments Spells to cast
## @Globals CAST_PASS
## 
## Starts the passes and sets CAST_PASS accordingly.
#---------------------------------------------------------------------
function pass_zero()  {

  debug "cast" "Starting pass_zero()"
  debug "pass_zero" "Starting passes 1,2,3,4 with : '$*'"
  debug "pass_zero" "   and with spells : '$SPELLS'"
  export  CAST_PASS="one";    pass_one $*  &&
  export  CAST_PASS="two";    pass_two $SPELLS
  #pass_three and _four are run via pass_two
  debug "pass_zero" "Starting pass 5 with: '$@'"
  export  CAST_PASS="five";  pass_five "$@"


}

#---------------------------------------------------------------------
## @STDOUT User information ("Cleaning up as well as I can...")
## That function is being called when the process receives 
## SIGINT. It then calls cleanup.
#---------------------------------------------------------------------
function int_trap()
{
  message "${PROBLEM_COLOR}SIGINT${DEFAULT_COLOR}"
  message "Cleaning up as well as I can..."
  cast_cleanup
  if [[ $SCREEN_NAME ]] ; then
    message -n "Press a key to exit screen."
    read -n 1
	screen_quit "$SCREEN_NAME"
  fi
  exit 1
}

#---------------------------------------------------------------------
## Used for cleaning up. Deleting some files and $TMP_DIR.
#---------------------------------------------------------------------
function cast_cleanup() {
  $STD_DEBUG
  cleanup_tmp_dir $TMP_DIR
}

#---------------------------------------------------------------------
## @Arguments arguments of cast
## @Globals FIX CAST_PASS 
## @return 0 always
## Starts prameter processing and casts the given spells.
## The list of given spells is being searched for invalid spells
## which are then being reported. Then the passes are being started
## according to CAST_PASS
#---------------------------------------------------------------------
function main()  {
  debug "cast" "main() - $*"
  local T_SPELLS
  process_parameters        "$@"
  SPELLS=`strip_parameters  "$@"`

  for spell in $SPELLS ; do
    codex_does_spell_exist $spell
    if [ $? -eq 0 ] ; then
      T_SPELLS="$T_SPELLS $spell"
    fi
  done
  SPELLS=$T_SPELLS

  if ! [[ $SPELLS ]]; then
    return 1
  fi

  case  $CAST_PASS  in
     one)  pass_one    $SPELLS  ;; #Never matches
     two)  pass_two    $SPELLS  ;; #Never matches
   three)  pass_three  $SPELLS  ;; #d/l sources, Never matches
    four)  pass_four   $SPELLS  ;; #real casting, Never matches
    five)  pass_five   $SPELLS  ;; #cast report
       *)  pass_zero   $SPELLS  ;; #start everything
  esac
  local rc=$?

  return $rc
}


. /etc/sorcery/config
[[ $VOYEUR_OVERRIDE ]] && VOYEUR="$VOYEUR_OVERRIDE"
if    [  $#      -eq  0  ];  then  help  |  $PAGER

elif  [[  $1 == -h  ]]  ||  [[  $1 == --help  ]] ; then help
elif  [  "$UID"  -gt  0  ];  then

  echo  "Enter the root password, please."
  PARAMS=$(consolidate_params "$@")
  su -c "$0 $PARAMS" root

elif  [  ${0:0:5} !=  "/tmp/"  ];  then

  # Make a nice dir structure to put stuff in, this exits if it fails
  mk_tmp_dirs cast

  export SAFE_CAST="$TMP_DIR/casting.safe"
  export SUCCESS_LIST="$TMP_DIR/success_list"
  export FAILED_LIST="$TMP_DIR/failed_list"
  export CONFLICT_LIST="$TMP_DIR/conflict_list"
  export CHECK_TRIGGERS_SUCCESS="$TMP_DIR/check_trigger_success_list"
  export CHECK_TRIGGERS_FAILURE="$TMP_DIR/check_trigger_failure_list"
  lock_file $SAFE_CAST
  
  cp  $0  $SAFE_CAST
  chmod +x $SAFE_CAST
  exec bash $SAFE_CAST "$@"
  
else
  export TOP_LEVEL=${TOP_LEVEL:-$SHLVL}
  if  [[  $NICE != "0"  ]] ; then
    renice $NICE -p $$  >/dev/null
  fi
  
  # If we are in a screen, weird things happen if we make another screen.
  # So disable screen mode if we are in a screen aready which wasn't started 
  # by smgl. We also have to make sure this is the top level cast so the SA
  # won't see the message over and over and over
  if  [[ $TERM == screen ]]       &&
      [[ $TOP_LEVEL == $SHLVL ]]  &&
      [[ $SCREEN == on ]]         &&
      [[ ! $SCREEN_NAME ]] 
  then
    export SCREEN_OVERRIDE=no
    message "${MESSAGE_COLOR}Although screen mode is enabled, you already seem to be in a another"
    message "screen session. Screen-in-screen is disabled."
    message "Continuing with screen mode off.${DEFAULT}"
  fi
  
  # Disable screen mode if the appropriate env var is set
  if  [[ $SCREEN_OVERRIDE ]]       &&
      [[ $SCREEN == on ]]
  then
    export SCREEN=$SCREEN_OVERRIDE
    debug "cast" "Turning $SCREEN_OVERRIDE screen mode"
  fi

  # If screen mode is on, but we aren't in screen, start a new session 
  # Call to screen_start never exits 
  if  [[ $SCREEN == on ]]         && 
      [[ $TERM != screen ]]
  then
    export SCREEN_NAME="ScreenCast $*"
    screen_start "ScreenCast $*" "$0" "$@"
    echo "WTF?? We should not get here. screen_start execs!"
    exit 1
  fi
  
  # If running in screen, screen mode is on, screen was started by us
  # and finally, it hasn't been initialized yet.
  if  [[ $TERM == screen ]]       && 
      [[ $SCREEN == on ]]         && 
      [[ $SCREEN_NAME ]]          && 
      [[ ! $SCREEN_INITIALIZED ]]
  then
    debug "cast" "Initializing screen windows"
    screen_name_window "$SCREEN_NAME" $SCREEN_MAIN_WIN "Main"

    # Start debugging window if debugging is on and not set to /dev*
    if  [[ $DEBUG ]]              && 
        [[ ${DEBUG#/dev} == $DEBUG ]]
    then 
      touch $DEBUG
      screen_new_window "$SCREEN_NAME" $SCREEN_DEBUG_WIN "Debug" \
      	tail -f -n 0 -s 0.1 $DEBUG
      #screen_unmonitor_window "$SCREEN_NAME" $SCREEN_DEBUG_WIN
    fi

    screen_switch_window "$SCREEN_NAME" $SCREEN_MAIN_WIN
    screen_monitor_window "$SCREEN_NAME" $SCREEN_MAIN_WIN
    screen_quick_intro
    export SCREEN_INITIALIZED=yes
  fi

  trap int_trap INT
  main  "$@"
  rc=$?
  if [ $SHLVL -eq $TOP_LEVEL ] ; then
    unlock_file $SAFE_CAST
    cast_cleanup
  fi
  if [[ $SCREEN_NAME ]] && [[ $TOP_LEVEL -eq $SHLVL ]] ;  then
    screen_notify "$SCREEN_NAME" "Done casting"
    message -n "Press enter to exit screen."
    read 
    screen_quit "$SCREEN_NAME"
  fi
  exit $rc
fi

debug "cast" "exiting..."

#---------------------------------------------------------------------
##=back
##
##=head1 LICENSE
##
## This software 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 software 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 software; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
##
#---------------------------------------------------------------------

