#!/usr/bin/env bash

#  Using a callsign entered as the parm on the command line, or as entered at the
#  prompt, look it up at using a callsign server and extract the license addr.
#  U.S. callsigns originally fetched at http://callsign.ualr.edu/. That's changed!
#  Continue until "73", "qrt", "quit", or "exit" are entered. ( Or, ^C. HI!HI! )

#  Optionally, a second command line parameter of "1" (and only "1") will
#  run the program _once_ and exit.  Any other parm 2 ($2) is ignored.

#  Written to fetch the licensee address (for QSLing.)       As written it only
#  supports the format of US/VE callsigns.  We pull US callsign addrs from the
#  The University of Arkansas at Little Rock ARC database -- a copy of the
#  FCC database.  We pull Canadian callsign addresses from the hamster.foxhollow.ca
#  web site.  This script will not handle something like: VE4/W3DHJ.
#  Nor do we support all the bizzar Canadian prefixes that the government allows.
#  But, yes, W3DHJ/VE4 works.
#
#  Requires:  bash, clear, curl, cut, expr, (e)grep, lynx, printf, sed, tr
#                         --  possible version and posix sensitivities not known.
#
#  Worked and re-worked to be portable between linux and freeBSD.  Ergo, some
#  of the 'awkwardness' seen in the use of external or internal commands.
#
#     Copyright 2023 Marvin L. Jones
#
#     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 3 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, see <http://www.gnu.org/licenses/>.
#
#  Changes:
#  14-Jul-09 -- Include Canadian callsign lookups: http://www.callsign.ca/ind.php
#  13-Jan-17 -- Canadian callsign lookups chg: http://hamster.foxhollow.ca/ccd/
#  20-Feb-23 -- Script was broken for a long time. (But nobody nagged me about it...)
#               New callsign data source employed to fix it..
#
#  73 Jonesy W3DHJ    email found @ http://W3DHJ.net/      Last Update: 20-Feb-23
#  Copyright 2023 Marvin L. Jones


#  Define text values for 'things' external to the script, and -- so -- which
#  may/will require fiddling with when those external 'things' change:

                                           # U.S. callsign server example
CALL_SRVR="https://callook.info/W1AW/text"
                                           # U.S. callsign server's no hit response.
CALL_ERR="Invalid callsign!"
                                           # VE callsign lookup site.
VE_URL="http://hamster.foxhollow.ca/ccd/?keywords="


function callsign_check ()
                        {
                         CALL2=${CALL1^^}         # Uppercase it.

                         # Look for egress request.
                         [  "$CALL2" = "73"      \
                            -o "$CALL2" = "QRT"  \
                            -o "$CALL2" = "QUIT" \
                            -o "$CALL2" = "EXIT" ] && echo && exit 0

                         # First strip any "/x" suffix. (e.g., /r , /M , /p)
                         CALL2=${CALL2%%/*}

                         # Next locate (1st) numeral position.
                         POSN=$( expr "$CALL2" : "[^0-9]*[0-9]" )

                         # Extract all non-alpha: Ergo district numeral only(?)
                         DISTRICT=${CALL2//[A-Z]/}

                         # 1: multiple numerals (or other crap):
                         [ ${#DISTRICT} -gt 1 ] && return 1

                         # And, insure the single non-alpha is numeric:
                         DISTRICT=${DISTRICT//[0-9]/}
                         # 2: Non-numeric in 'supposed' numeral position:
                         [ ${#DISTRICT} -gt 0 ] && return 2

                         # 4 Numeral not in position 2 or 3:
                         [ "$POSN" -ne 2 -a "$POSN" -ne 3 ] && return 4

                         # Finally, since we are assured it's only alphnumeric,
                         # double check the suffix length.
                         WORK=${CALL2:$POSN}                # Extract the suffix
                         # 8: Invalid suffix length
                         [ ${#WORK} -lt 1 -o ${#WORK} -gt 3 ] && return 8

                         return 0
                        }

PARM="$1"                                           # Get (if any) the input parm.

[ "$2" != "1" ] && clear && printf "\n\n\n\n\n\n\n" # Prep the 'display'.

while [ 1 ]
 do

  if [ -z $PARM ] ; then
    read -p " Enter Callsign: " CALL1               # Prompt for 'raw' callsign.
    CALL1=$( echo $CALL1 | cut -d " " -f1 )         # Strip off on supurios crap.
  else
    CALL1="$PARM"
    echo " Doing Callsign: $CALL1"                  # Callsign on command line.
    PARM=''                                         # null out cmnd line callsign
  fi

  echo -n " "                                       # Park cursor under prompt.

  callsign_check                                    # Call with 'raw' $CALL1;
  RC=$?                                             # return with 'good' $CALL2.
  if [ $RC -ne 0 ] ; then
                                                    # Invalid/Garbage callsign
     [ "$2" != "1" ] && clear
     printf "\n $CALL1\n       Invalid callsign!! (rc=$RC)\n\n"
     [ "$2" != "1" ] && printf "\n\n\n"             # Pad for interactive run.

  elif [ "${CALL2:0:1}" = "V" ] ; then              # Process (possible) VE callsign.

     # Pull the VE license data and trim to just _this_ address on ONE line.
     ADR=$( lynx -dump -nolist "$VE_URL$CALL2"    \
            | grep -A 3 "] $CALL2 "               \
            | tr '\n' '!'                         \
            | sed -e "s/^.*$CALL2 /$CALL2!/"      \
            | sed -e 's/ (.*).*$//'                )

     [ "$2" != "1" ] && clear ; echo                # Prep the display

     case $ADR in                                             # Test for Canadian callsign assigned.
        *"$CALL2"* ) ADR=$( echo $ADR           \
                         | sed -e 's/! */!/g'   \
                         | sed -e 's/!/!  /g'    )
                     echo "  $ADR" | tr '!' '\n'              # Ouput with newlines (re)inserted.
                     ;;
                 * ) echo " $CALL2"                           # Insert callsign if no hit w/VE....
                     echo "     Callsign is not assigned."
                     [ "$2" != "1" ] && printf "\n\n\n"       # Pad output with no hit w/VE....
                     ;;
     esac

  else                                          # Process (possible) U.S. callsign.

     # Pull the license data from callook.info , then process.
     ADR=$( curl "https://callook.info/$CALL2/text" 2> /dev/null )

     [ "$2" != "1" ] && clear ; printf "\n $CALL2\n"               # Prep the display

     if [[ $ADR == *"$CALL_ERR"* ]]; then

      echo "       Unlisted/Invalid callsign!"  # No results for entered callsign.

      [ "$2" != "1" ] && printf  "\n\n\n"                          # Pad output if no hit.

     else                                       # We have results.

      IFS=$'\n'                                 # Newline is our separator.
                                                # Strip unwanted details.
      ADR2=$( echo "$ADR" | grep "$(printf '\t')" | egrep -v '(ude|are|ive|res|ion|FRN):' )
      i=0;
      for LN in ${ADR2}; do                     # Process each line in results.
       echo "  $LN"                             # Echo each line...
       ((i=i+1))                                # Count lines
      done

      [ $i -eq 3 ] && echo                      # Fill in for a missing 4th line

      unset IFS

     fi

     echo                                       # Double space to prompt for next.

  fi
                                                # Exit after 1 time if parm2 == "1".
 [ "$2" = "1" ] && exit 0

 done                                           # while [ 1 ] ... above