#!/usr/bin/bash

# Created by Ed Attfield
# Last edited: July 9, 2022 by John Chmielewski

# Server Hangup Extension
# Script is not called if caller number or name is in ncidd.whitelist.
# Check for valid North American number plan callers.
# as described by https://en.wikipedia.org/wiki/North_American_Numbering_Plan
#
# This hangup script catches invalid north american phone numbers.
# It expects 10 digit or 1+10 caller ID and hangs up on others including
# private callers.  There is also a check for my definition of stupid
# caller names such as V12345678901234 and 321-555-1212 and +1-321-555-1212

# if this file is present, the calling area code must be in the file
AREACODES=/etc/ncid/valid-area-codes
# this list of valid area codes can be extracted from wikipedia
# with the get-areacodes-list script, see 'man get-areacodes-list'

# Make sure you 'set hupmode = 1|2|3' in ncidd.conf.

# If using hupmode=3, change RECORDING to whatever you want to be played
# when this script indicates hangup.  Normally not needed because it will
# default to the 'set announce' value in ncidd.conf.
RECORDING="CannotBeCompleted.rmd"

########################
# Function Definitions #
########################

usage() {
   cat | more <<EOF

Usage: $script [options] <string>

       Server hangup extension to check for valid North American number plan callers.

       Input: The server passes one <string> on one line to this script:

              *DATE*<mmddyyyy>\\
              *TIME*<hhmm>\\
              *LINE*<lineid>\\
              *NMBR*<number>\\
              *MODE*<1|2|3>\\
              *FNMBR*<formatted number>\\
              *NTYPE*<type of device>\\
              *CTRY*<country code>\\
              *LOCA*<location>\\
              *CARI*<carrier>\\
              *NAME*<name>*

              <number> and <name> have already been changed to aliases
              if applicable.

              There is NO guarantee that the order of the field pairs will
              remain the same in future NCID versions (e.g., *LINE*<lineid>*
              might be moved to the end of the string). Your code must
              take this into account. This example script handles this
              properly.

              When testing, just use the input fields needed. This
              example script only requires the NMBR field. The <string>
              must be enclosed in double quotes.

              For example:
                  $script "*NMBR*4075551212*"

       Output: hupmode value received and description
               if hangup required:
                    if MODE=3, Recording: <file name or full path>
                    HangupReason: <brief reason text>
                    hangup
               if hangup not required:
                    OK

Options are only used for manual testing and are NEVER SENT by the server:

       [-h] [-v]

       -h = show this help

       -v = turns verbose on and sends additional data to STDOUT for
            troubleshooting

EOF
exit 1
}

hangup_exit()
{
   if [ "$MODE" = 3 ]; then
      echo "Recording: $RECORDING";
   fi
   [ -n "$HUPReason" ] && echo "HangupReason: $HUPReason"
   echo "hangup"
   exit 0
}

###############################
# End of function definitions #
###############################

script=`basename $0`

# Options on command line

  show_usage=0

  while getopts :hv opt ; do
      case $opt in
          h) show_usage=1;;
          v) verbose=1;;
         \?) echo "Invalid option: -$OPTARG"
             show_usage=1;;
          :) echo "Option -$OPTARG requires an argument."
             show_usage=1;;
      esac
  done

  [ $show_usage = 1 ] && usage

  shift $((OPTIND-1)) # skip over command line args (if any)

# All passed fields from the server are parsed below, use only fields needed.
tmp=${1#*NAME?}; NAME=${tmp%%\**}
tmp=${1#*NMBR?}; NMBR=${tmp%%\**}
tmp=${1#*LINE?}; LINE=${tmp%%\**}
tmp=${1#*DATE?}; DATE=${tmp%%\**}
tmp=${1#*TIME?}; TIME=${tmp%%\**}
tmp=${1#*MODE?}; MODE=${tmp%%\**}

: ${NMBR:=_nmbr_} # default value if null
: ${NAME:=_name_} # default value if null
: ${MODE:=3}      # default value if null

HUPReason="fake number"

if [ -n "$verbose" ]
then
    echo "NAME:  $NAME"
    echo "NMBR:  $NMBR"
    echo "LINE:  $LINE"
    echo "DATE:  $DATE"
    echo "TIME:  $TIME"
    echo "MODE:  $MODE"

   echo -n "Using HUPMODE $MODE - "
   case $MODE in
       1) echo "Normal hangup" ;;
       2) echo "FAX hangup" ;;
       3) echo "VOICE hangup" ;;
       *) echo "unknown MODE" ;;
   esac
fi

# look for illegal north american phone numbers
# number should be 1+10 digits or 10 digits
# ${#NMBR} shoud be 10 or 11
# 0aaxxxxxxx is illegal
# 1aaxxxxxxx is illegal
# aaa0xxxxxx is illegal
# aaa1xxxxxx is illegal
# the NANP is not assigning area codes with 9 as the second digit
# a9axxxxxxx is illegal
if [[ "${NMBR}" =~ 1[2-9][0-8][0-9][2-9][0-9]{6} ]]
then
   # remove the leading 1
   if [ -n "$verbose" ]; then
      echo "its 11 valid digits"
   fi
   NMBR=${NMBR:1}
elif [[ ! "${NMBR}" =~ [2-9][0-8][0-9][2-9][0-9]{6} ]]
then
   # not 10 digits
   if [ -n "$verbose" ]; then
      echo "not 10 valid digits"
   fi
   hangup_exit
else
   # its 10 digits
   if [ -n "$verbose" ]; then
   echo "its 10 valid digits"
   fi
fi

# look for allowed area codes
if [ -f $AREACODES ]
then
   # search for the number in $AREACODES
   if grep "^${NMBR:0:3}" $AREACODES > /dev/null 2>&1
   then
      # its a known area code
      if [ -n "$verbose" ]; then
      echo "its a known area code"
      fi
   else
       echo "${NMBR:0:3} not in $AREACODES"
       HUPReason="bad area code"
       hangup_exit
   fi
fi

# look for stupid caller names
if [[ "${NAME}" =~ V[0-9]{10,} ]]
then
   # name contains V1234567890...
   if [ -n "$verbose" ]; then
      echo "name is Vnumbernumber"
   fi
   HUPReason="fake name"
   hangup_exit
elif [[ "${NAME}" =~ [-+0-9\ ]{10,} ]]
then
   # a sequence of 10 or more digits/+/-/spaces
   # e.g 1234567890 or 123-456-78
   if [ -n "$verbose" ]; then
      echo "name is all digits"
   fi
   HUPReason="fake name"
   hangup_exit
else
   # name may be ok
   if [ -n "$verbose" ]; then
      echo "name is ok"
   fi
fi

if [[ "${NAME}" == "SPAM RISK" ]]
then
    # received a name of "SPAM RISK" from the provider
    # no need for a hangup reason
   if [ -n "$verbose" ]; then
   echo "name indicates possible SPAM"
   fi
   HUPReason=""
   hangup_exit
fi

# aaa55501xx are reserved for hollywood
if [[ "${NMBR}" =~ [2-9][0-8][0-9]55501[0-9][0-9] ]]
then
   if [ -n "$verbose" ]; then
   echo "from a movie or song"
   fi
   HUPReason="fake number"
   hangup_exit
fi

# the name and number looks good
echo "OK"
exit 0
