#---
## @Synopsis Tries to change the source verification in favour of upstream gpg
##
## @Globals "version" "versions" SPELL_KEYRING SPELL_SIGNATURE SPELL_UPDATED
## @Globals SPELL_NAME SPELL_VERSION
#---
function convert_to_upstream_gpg() {
  local update_counter=${#versions[@]} source su i new_value new_su new_source
  local version_switch j ll ll_max mirrors num_of_mirrors
  if query "Do you want to do it for $version?" y; then
    multiversion_check
    SPELL_VERSION="$version"

    get_sources_and_urls
#echo -e "---\n${source_urls[@]}\n---"
    i=
    SPELL_KEYRING=
    ll_max=$(wc -l <<< "$sources_and_urls")
    for (( ll=1; ll <= $ll_max; ll++ )); do
      # use the original DETAILS, as we already changed the VERSION
      current_check=$(eval ${version_switch:-:}; . DETAILS.orig &> /dev/null; eval echo \$SOURCE${i}_HASH\$SOURCE${i}_GPG\$SOURCE${i}_IGNORE\$\{MD5[${i:-0}]\})

      read source su mirrors <<< $(sed -n "$ll p" <<< "$sources_and_urls")
      num_of_mirrors=$(wc -w <<< "$mirrors")

      if [[ -z $current_check ]]; then
        error_msg "Missing SOURCE${i}_HASH/SOURCE${i}_GPG/SOURCE${i}_IGNORE"
        message "Add the appropriate one to the spell!"
        inc_src_num i
        continue
      fi

      # skip already upstream signed sources and SOURCE_IGNORE
      if grep -Eq "UPSTREAM_KEY|volatile|signature|unversioned" <<< "$current_check"; then
        message "SOURCE${i} is already upstream signed or the verification is ignored."
        inc_src_num i
        continue
      fi

      if ! grep -Eq "^((sha(512|256|1)|md5):.*|[^:]*)$" <<< "$current_check"; then
        # probably a non-upstream SOURCE_GPG
        if ! grep -q "gurus.gpg" <<< "$current_check"; then
          echo "SOURCE${i}_GPG=$current_check"
          error_msg "This looks like an upstream keyring and should be marked as such."
          error_msg "Probably with :UPSTREAM_KEY at the end of $current_check."
          echo
          inc_src_num i
          continue
        fi
      fi

      guess_signature_url verbose
      echo

      j="$i"
      inc_to_unique_src_num j

      SPELL_SIGNATURE="$new_su"
      query_spell_signature
      [[ $SPELL_SIGNATURE == skip ]] && continue
      while ! url_verify "$SPELL_SIGNATURE" &> /dev/null; do
        error_msg "You entered a bad signature url!"
        echo
        unset SPELL_SIGNATURE
        query_spell_signature
      done
      substitute_with_variables new_source "$source" SOURCE$i \
        "$SPELL_NAME" {SPELL} "$SPELL_VERSION" {VERSION}

      echo
      quill_get_spell_keyring

      substitute_with_variables SPELL_SIGNATURE "$su" {SOURCE${i}_URL[0]} \
        "$new_source" SOURCE$j "$SPELL_NAME" {SPELL} "$SPELL_VERSION" {VERSION}

      # two modes of new line insertion
      # for single-versioned spells we can have the prettier one
      # for multiversioned ones we use the safe(r), but uglier aggregate one
      if [[ -z $version_switch ]]; then
        # sed in the new source[j] right after source[i]
        new_value=$(count_spaces SOURCE${j})
        sed -i "/^\s*SOURCE$i=/ s%^.*$%&\n${new_value}SOURCE${j}=$new_source%" DETAILS
        SPELL_UPDATED=y

        # sed in the new su$j right after su$i or last su$i[]
        new_value=$(count_spaces SOURCE${j}_URL[$num_of_mirrors])
        sed -i "/^\s*SOURCE${i}_URL\[$num_of_mirrors\]=/ s%^.*$%&\n${new_value}SOURCE${j}_URL[0]=$SPELL_SIGNATURE%" DETAILS

        # ignore the signature
        new_value=$(count_spaces SOURCE${j}_IGNORE)
        sed -i "s%^.*${current_check}.*$%&\n${new_value}SOURCE${j}_IGNORE=signature%" DETAILS

        # finally change verification to upstream source_gpg
        new_value=$(count_spaces SOURCE${i}_GPG)
        sed -i "s%^.*${current_check}.*$%${new_value}SOURCE${i}_GPG=$SPELL_KEYRING:\$SOURCE$j:UPSTREAM_KEY%" DETAILS

        # SOURCE must be first since others reference it
        # compare line numbers and move the vars if necessary
        local s_ln su_ln sgpg_ln
        s_ln=$(sed -n "/^\s*SOURCE$j=$new_source/=" DETAILS)
        sgpg_ln=$(sed -n "/^\s*SOURCE${i}_GPG=$SPELL_KEYRING:\$SOURCE$j:UPSTREAM_KEY/=" DETAILS)
        if (( $s_ln > $sgpg_ln )); then
          sed -i "$sgpg_ln{ x;d }; $s_ln G" DETAILS
          si_ln=$(sed -n "/^\s*SOURCE${j}_IGNORE=signature/=" DETAILS)
          s_ln=$(sed -n "/^\s*SOURCE$j=$new_source/=" DETAILS)
          sed -i "$si_ln{ x;d }; $s_ln G" DETAILS
          s_ln=$(sed -n "/^\s*SOURCE$j=$new_source/=" DETAILS)
        fi
        SPELL_SIGNATURE=$(sed 's,[][],\\&,g' <<< "$SPELL_SIGNATURE")
        su_ln=$(sed -n "/^\s*SOURCE${j}_URL\[.*\]=$SPELL_SIGNATURE/=" DETAILS)
        if (( $s_ln > $su_ln )); then
          sed -i "$su_ln{ x;d }; $s_ln G" DETAILS
        fi



        # now that the order is pretty much fine, add any other mirrors
        local mirror_url suffix mirror_num=1

        if [[ $num_of_mirrors != 0 ]]; then
          # get the suffix that was used from new_source
          suffix="${new_source##*.}"

          # traverse over mirror numbers in reverse, so mirrors end up
          # ordered ascendingly, since we're adding them at a fixed location
          for mirror_url in $mirrors; do
            if url_verify "$mirror_url.$suffix" > /dev/null; then
              # add it after original, first su
              new_value=$(count_spaces SOURCE${j}_URL[$mirror_num])

              # expand vars first
              substitute_with_variables mirror_url "$mirror_url" {SOURCE${i}_URL[$mirror_num]}
              sed -i "/^\s*SOURCE${j}_URL\[0\]=/ s%^.*$%&\n${new_value}SOURCE${j}_URL[$mirror_num]=$mirror_url.$suffix%" DETAILS
            fi
            let mirror_num++
          done
        fi



      else
        # sed in the new source[j] before $current_check
        new_value=$(count_spaces SOURCE${j})
        sed -i "s%^.*${current_check}.*$%${new_value}SOURCE${j}=$new_source\n&%" DETAILS
        SPELL_UPDATED=y

        # sed in the new su[j] right after source[j] (before $current_check)
        new_value=$(count_spaces SOURCE${j}_URL[0])
        sed -i "s%^.*${current_check}.*$%${new_value}SOURCE${j}_URL[0]=$SPELL_SIGNATURE\n&%" DETAILS

        # ignore the signature after $current_check
        new_value=$(count_spaces SOURCE${j}_IGNORE)
        sed -i "s%^.*${current_check}.*$%&\n${new_value}SOURCE${j}_IGNORE=signature%" DETAILS

        # finally change verification to upstream source_gpg
        new_value=$(count_spaces SOURCE${i}_GPG)
        sed -i "s%^.*${current_check}.*$%${new_value}SOURCE${i}_GPG=$SPELL_KEYRING:\$SOURCE$j:UPSTREAM_KEY%" DETAILS
      fi

      inc_src_num i
    done

    [[ $SPELL_UPDATED == n ]] && return 0

    echo
    add_history_entries "DETAILS: converted to upstream signature checking"
    echo

    # ugly, but avoids excessive suing
    if query "Do you want to try if the new verification system works?" y; then
      SOURCE_DIRECTORY=$(conditional_get_var SOURCE_DIRECTORY)
      codex_get_spell_paths $(codex_find_spell_by_name $SPELL_NAME)
      $QUILL_SUDO -c ". /etc/sorcery/config; . $QUILL_MODULES/libcore;
      . $QUILL_MODULES/libcopy; . $QUILL_MODULES/libupdate
      SPELL_NAME=$SPELL_NAME; QUILL_SPELL_DIR=$QUILL_SPELL_DIR
      get_sources_and_urls
      summon_sources || exit 1
      quill_final_put_in_grimoire $GRIMOIRE $SECTION no
      delve -c start PRE_BUILD $SPELL_NAME; rc=\$?
      rm -r $SOURCE_DIRECTORY
      if [[ \$rc == 0 ]]; then
        message "Success!"
      else
        error_msg "Failed!"
      fi
      sleep 2"
    fi

  else
    let update_counter-=1
  fi
  [[ $update_counter == 0 ]] && continue 2 # there were no updates

}

#---
## @Synopsis guesses signature urls from the source url
##
## @param silent - silent to print nothing
##
## @return 0 if a guess is a valid url
## @return 1 otherwise
##
## @Globals "i" "su" "source"
function guess_signature_url() {
  local suffix silent=$1

  [[ $silent != silent ]] && message -n "Trying to guess the signature url for SOURCE$i ... "
  for suffix in sig asc sign; do
    if url_verify "$su.$suffix" &> /dev/null; then
      new_su="$su.$suffix"
      new_source="$source.$suffix"
      [[ $silent != silent ]] && message "Success!"
      return 0
    fi
  done
  [[ $silent != silent ]] && message "Failed."
  return 1
}

#---
## @Synopsis sets up SPELL_KEYRING, either from an exsisting or from
## @Synopsis a remote one
##
## @Globals SPELL_KEYRING QUILL_MODE QUILL_SPELL_DIR SPELL_NAME
## @Globals QUILL_TMP_DIR
function quill_get_spell_keyring() {
  # return if a previous pass already set it
  [[ -n $SPELL_KEYRING ]] && return 0

  if query "Is the appropriate keyring already in the grimoire?" n; then
    # list them as suggestions
    codex_get_spell_paths $(codex_find_spell_by_name $SPELL_NAME)
    case $QUILL_MODE in
    apprentice)
      message "Here is a list of grimoire level keyrings:"
      find $GRIMOIRE -maxdepth 1 -iname "*.gpg" -printf "%P\n" ;;
    mage)
      message "Here is a list of grimoire and section level keyrings:"
      find $GRIMOIRE -maxdepth 2 -iname "*.gpg" -printf "%P\n" ;;
    wizard)
      message "Here is a list of all keyrings:"
      find $GRIMOIRE -iname "*.gpg" -printf "%P\n" ;;
    esac | grep -v gurus.gpg | column
    shopt -s nullglob
    query_string SPELL_KEYRING "Which of the above is the correct keyring? " *.gpg
    shopt -u nullglob

    local kr_path=$(dirname $SPELL_KEYRING)
    if [[ $QUILL_MODE != apprentice && $kr_path != "." ]]; then
      if [[ $kr_path != $SECTION && $kr_path != $SECTION/$SPELL_NAME ]]; then
        message "Copying the keyring to the spell dir as it is not a grimoire"
        message "level one, from the same section nor from the same spell!\n"
        cp $GRIMOIRE/$SPELL_KEYRING "$QUILL_SPELL_DIR/$SPELL_NAME"
        add_history_entry "${SPELL_KEYRING##*/}: added gpg keyring from $kr_path"
      fi
      SPELL_KEYRING=$(basename $SPELL_KEYRING)
    fi
    unset GRIMOIRE SECTION GRIMOIRE_NAME SECTION_DIRECTORY
  else
    # get a hint from the failed verification
    message "Creating a keyring from the key that made the signature ..."
    $QUILL_SUDO -c "wget -nc -P $SOURCE_CACHE $SPELL_SIGNATURE ${SPELL_SIGNATURE%.*}"
    # get the key id, reuse a var
    SPELL_KEYRING=$(gpg --verify $SOURCE_CACHE/${SPELL_SIGNATURE##*/} 2>&1 | sed -n 's,^.* key ID ,,p')

    # create the keyring
    gpg --import-options import-minimal --no-default-keyring --keyring \
      $QUILL_SPELL_DIR/$SPELL_NAME/$SPELL_KEYRING.gpg --recv-keys $SPELL_KEYRING

    SPELL_KEYRING=$SPELL_KEYRING.gpg

    if query "Is there a more complete keyring available?" y; then
      rm $QUILL_SPELL_DIR/$SPELL_NAME/$SPELL_KEYRING
      unset SPELL_KEYRING
      query_spell_keyring
      while ! url_verify "$SPELL_KEYRING" &> /dev/null; do
        error_msg "You entered a bad keyring url!"
        unset SPELL_KEYRING
        query_spell_keyring
      done
      wget -nc -P $QUILL_SPELL_DIR/$SPELL_NAME/ "$SPELL_KEYRING"
      SPELL_KEYRING=$(basename "$SPELL_KEYRING")
    fi

    rm -f $QUILL_SPELL_DIR/$SPELL_NAME/*.gpg~
    add_history_entry "$SPELL_KEYRING: added gpg keyring"
  fi

}

##
## @Globals SPELL_SIGNATURE
function query_spell_signature(){
  if [[ $SPELL_SIGNATURE ]] &&
    ! query "Is $SPELL_SIGNATURE the proper signature url?" y; then
    query_msg "Please enter the url of the signature:"
    read "SPELL_SIGNATURE"
  fi
  while ! [[ $SPELL_SIGNATURE ]]; do
    query_msg "Please enter the url of the signature or 'skip' to skip this source:"
    read "SPELL_SIGNATURE"
  done
}

##
## @Globals SPELL_KEYRING
function query_spell_keyring(){
  while ! [[ $SPELL_KEYRING ]]; do
    query_msg "Please enter the url of the keyring:"
    read "SPELL_KEYRING"
  done
}

#---
## @Synopsis silently check if a signed version of the source exsist
## @Synopsis and if so, verbosely try to sell it
##
## @return 0 if a valid signature was found
## @return 1 otherwise
##
## @Globals "source" "sources_and_urls"
#---
function upstream_gpg_ad() {
  # plug in the ad for upstream sigs if valid urls were found
  local su=$(sed -n "s,^$source \(\S*\) .*$,\1,p" <<< "$sources_and_urls")
  guess_signature_url silent &&
  message "${MESSAGE_COLOR}Cool! It looks like this spell would easily be" &&
  message "converted to upstream signing. Please choose that option from" &&
  message "the menu once this update finishes.$DEFAULT_COLOR"
}

#---
## @Synopsis Unexpands SOURCE_GPG if necessary to be later able to match it
##
## @Globals "current_check" "version_switch"
##
## @return 0 if current_check was found
## @return 1 otherwise
#---
function unexpand_source_gpg()
{
  local j

  if grep -q "$current_check" DETAILS.orig
  then
    return 0
  else # looks like it is expanded
    current_check=$(
    eval ${version_switch:-:}; . DETAILS.orig &> /dev/null;
    for j in `get_source_nums s`
    do
      j="${j%s}"
      SOURCE=$(eval echo \$SOURCE$j)
      substitute_with_variables current_check "$SOURCE" {SOURCE$j}
    done
    substitute_with_variables current_check "$SPELL_NAME" {SPELL} "$VERSION" {VERSION}
    echo $current_check
    )
  fi
  if grep -q "$current_check" DETAILS.orig
  then # maybe the author doesn't like the ugly braces too
    return 0
  else
    current_check="$(tr -d "{}" <<< "$current_check")"
  fi
  if grep -q "$current_check" DETAILS.orig
  then
    return 0
  else # give up
    error_msg "Giving up, you'll have to update SOURCE${i}_(GPG|HASH) yourself."
    return 1
  fi
}

#---
## @Synopsis Removes unneeded sigs
##
## @param old version
## @Globals none
#---
function remove_old_sigs()
{
  local version="$1" files
  if ! grep -q "VERSION=$version *$" DETAILS;
  then
    # compgen has a plain wierd output
    # lynx wants interactivity and no 404s
    # the glob could expand to more than one file, so test -e could break
    files=$(compgen -G "*$version*.sig" | tr '\n' ' ')
    files="$files $(compgen -G "*$version*.asc" | tr '\n' ' ')"
    files="$files $(compgen -G "*$version*.sign" | tr '\n' ' ')"
    [[ $files != "  " ]] && rm -i $files
  fi

}

#---
##
## 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
##
#---
