#!/usr/bin/env bash

#  Using a callsign entered as the param on the command line, or as entered at
#  the prompt, look it up at a web source and extract the grid square.
#  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/verify grid squares for VHF QSOs.     As written it only
#  supports the format of US/'VE'/'XE' callsigns -- or, others of that style.
#  It will not handle something like: VE4/W3DHJ.  But, yes, W3DHJ/VE4 works --
#  but returns the home QTH grid for W3DHJ (obviously...).
#  You might find the grid squares for some, but not many, non-USA callsigns.
#  The very active VE and XE ops probably _will_ have their grids listed.
#
#  Requires:  bash, clear, expr, grep, lynx, curl
#                                --  possible version 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.
#
#  16-Jun-10...Changes in upstream information access required a change to
#              the URL for fetching the grid square.
#              While I was at it, I added a UserAgent.
#  10-Jul-12...Changes in upstream information access required a change to
#              the URL for fetching the grid square.
#  07-Aug-12...Again: Changes in upstream information ...
#  21-Feb-13...Again: Changes in upstream information ...  sigh....
#              Update the User Agent.
#  18-Jul-16...Again: Changes upstream (...sigh)
#              javascript issues => incorporate curl
#              Update the User Agent.
#
#     Copyright 2010,2012,2013,2016 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/>
#
#  Jonesy W3DHJ    email @ http://W3DHJ.net/    Last Update: 21-Feb-13
#  Copyright 2010,2012,2013 Marvin L. Jones

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

TMP=$HOME/tmp/                 # curl > temp.html > lynx -dump
                               # You probably want to set this according to your system.
                               # /tmp/ is a universal choice.

GRID_URL='http://www.levinecentral.com/ham/grid_square.php?Call='
                               # Target URL (prefix) ...  The full URL is viz:
                               # http://www.levinecentral.com/ham/grid_square.php?Call=W3DHJ
# See also:                    http://www.ae7q.com/pda/data/Callsign.php?CALL=w3dhj 	(10-Sep-14)

UA='"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36"'                                                               # A UserAgent for `curl` to use.

#RESP_OK="Grid: DM78rf"               # An example when a grid has been returned.
#RESP_BAD="CALL W3DHJ not found."     # An example when a call cannot be found.
                                      # I do not know what the response looks like
                                      # when a valid call returns no grid.

function callsign_check ()
                        {
                         CALL2=$( echo  $CALL1 | tr a-z A-Z ) # 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]" )

                         # And, 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 callsign - if any...

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

while [ 1 ]
 do

  if [ -z $PARM ]; then
    read -p " Enter Callsign: " CALL1       # Prompt for 'raw' callsign.
  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
     echo ; echo " "$CALL1": Invalid callsign!! (rc=$RC)"
     echo

  else
     RESP_OK="Grid:"                        # Returned text when a grid has been returned.
     RESP_BAD="Call "$CALL2" not found."    # Returned text when a call cannot be found.

     RC=$( curl --user-agent "$UA" "$GRID_URL$CALL2" > $TMP/grid_temp.html 2> /dev/null ; echo $? )

     if [ $RC -ne 0 ]
        then
         printf "Fetch of web data failed: \n  $GRID_URL$CALL2 \n"
         exit
     fi

     GRID=$( lynx --nolist --dump $TMP/grid_temp.html        \
             2> /dev/null | grep -E "($RESP_OK|$RESP_BAD)" | awk '{print $2}' )
     # Above:
     # After the `lynx`+`grep`, we either have a line containing viz:
     # "W3DHJ  DM78RF   Update locator of W3DHJ     Delete W3DHJ from database"
     #   -or-
     # "No locator data available for W3DHZ"
     #   -then-
     # after the `awk`, we either have the grid
     #   -or-
     # the callsign ($CALL2) if no callsign found.

     case "$GRID" in
             "$CALL2" )
                       GRID="- callsign not found."
                       ;;
                 *     )
                       GRID=${GRID:0:4}     # Trim to just a 4-char Grid Sq.
                       ;;
     esac

     [ "$2" != "1" ] && clear
     echo ; echo " "$CALL2 $GRID            # Display results.
     echo                                   # Double space to prompt for next.
  fi

  rm $TMP/grid_temp.html                    # Remove the temporary htmlfile.

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

 done
