#!/bin/sh

#set -x

# Places for flags:
# $HOME/.flag-cache <- Autogenerated flag (refreshed when hostname changes)
# /etc/flag <- Site admin's flag
# $HOME/.flag <- Local user's flag
# Check them in that order.

# Name available algos as algo_something() and left-align for autodetection
# Order the algos by priority: the first one that is correct will be used
algo_cksum_linux() { printf '%08x\n' $(cksum) | head -n 1; }
algo_cksum_freebsd() { printf '%08x\n' $(cksum -o 3) | head -n 1; }
algo_crc32() { crc32 /dev/stdin; }
algo_crc32sum() { crc32sum; }
algo_crc32sum_linux() { crc32sum-linux; }
algo_crc32sum_freebsd() { crc32sum-freebsd; }
algo_ruby() { ruby -e 'require "zlib"; printf "%08x\n", Zlib.crc32(STDIN.readlines.join)'; }
algo_php() { php -r 'printf("%08x\n", crc32(file_get_contents("/dev/stdin")));'; }
algo_perl() { perl -e 'use String::CRC32; printf("%08x\n", crc32(*STDIN));'; }

find_crc32_algo() {
  sed -e '/^algo_[^(]*()/!d; s/().*$//' "${0}" | while read algo
  do
    if [ "$(printf "meow" | "${algo}" 2>/dev/null)" = "8a106afe" ]
    then
      echo "${algo}"
      break
    fi
  done
}

hash_string() {
  # Hash the passed string into 8 hex characters
  [ "${crc32_algo}" ] || crc32_algo="$(find_crc32_algo)"
  if [ -z "${crc32_algo}" ]
  then
    echo "No crc32 algo found!" >&2
    echo "deadbeef"
    return 1
  else
    printf "%s" "${*}" | "${crc32_algo}" 2>/dev/null | awk '{print $1}'
    return 0
  fi
}

flagcache(){
  myhost="$(/bin/hostname -f)"
  cache="${HOME}/.flag-cache"
  if [ -f "${cache}" ]
  then
    flag_hex="$(awk '/^'${myhost}'/{print $2}' "${cache}")"
  fi
  if [ -z "${flag_hex}" ]
  then
    flag_hex="$(hash_string "${myhost}")" && printf "%s\t%s\n" "${myhost}" "${flag_hex}" >> "${cache}"
  fi
  echo "${flag_hex}"
}

if [ -f "${HOME}/.flag" ]
then
  flag_hex="$(cat "${HOME}/.flag")"
fi

if [ -z "${flag_hex}" ] && [ -f "/usr/local/etc/flag" ]
then
  flag_hex="$(cat "/usr/local/etc/flag")"
fi

if [ -z "${flag_hex}" ]
then
  flag_hex="$(flagcache)"
fi

# Now we definitely have flag_hex
firstchar() {
  char="$(printf '%c' "${data}")"
  data="${data##${char}}"
}

hexdec() {
  if [ -z "${1}" ]
  then
    echo "0"
    return
  fi
  echo $(( 0x${1} + 0 ))
}

flag() {
  if [ -z "${1}" ]
  then
    echo "Usage: flag 'hexcode' [symbol] [shellmode]" >&2
    echo "Generates an ANSI color flag using the specified hex codes" >&2
    echo "Uses the optional symbol (or ' ') to draw the flag" >&2
    echo "shellmode encapsulates all nonprintable codes in \[\] to" >&2
    echo " give the shell hints on how long the string is, for proper" >&2
    echo " wrapping of command prompts." >&2
    return
  fi
  data="${1}"
  sym="${2}"
  shm="${3}"
  [ -n "${shm}" ] && open='\\[' shut='\\]'
  while [ -n "${data}" ]
  do
    firstchar
    ord=$(hexdec "${char}")
    bright="0"
    [ "$(( ${ord} & 8 ))" -gt 0 ] && bright="1;7"
    colour="$(( ${ord} & 7 ))"
    printf "${open}\033[%s;3%s;4%sm${shut}%s" "${bright}" "${colour}" "${colour}" "${sym:-${char}}"
  done
  printf "${open}\033[0m${shut}"
}

pebkac() {
   echo "Usage: $(basename "${0}") [-s #] [-e]" >&2
   echo "Produces a neat little ansi colour 'flag' based off" >&2
   echo " a hash of the machine's hostname (or settable via" >&2
   echo " ~/.flag or /etc/flag) which can uniquely visually" >&2
   echo " identify a machine, at a glance. Useful for placing" >&2
   echo " into /etc/issue or your bash prompt, so that you" >&2
   echo " don't send stupid commands to the wrong machine." >&2
   echo " " >&2
   echo " -s #   Specify which character should be used to" >&2
   echo "         render the flag. If empty, use the hex code." >&2
   echo " -e     Turn on bash encapsulation mode, to provide" >&2
   echo "         hints to Bash on what is or is not printable" >&2
   echo "         so it can wrap your commands appropriately" >&2
   echo "         when used in your prompt" >&2
   echo " " >&2
   echo "This machine's flag is as such: ($(flag "${flag_hex}"))" >&2
   exit 1
}

symbol=""
shellmode=""

while [ -n "${1}" ]
do
  case "${1}" in
  -s)  shift; symbol="${1}" ;;
  -e)  shellmode="yes" ;;
  *)   pebkac ;;
  esac
  shift
done
flag "${flag_hex}" "${symbol}" "${shellmode}"

