#!/bin/bash

# Rules for chat scripts
# No comments allowed at the end of AT+CGDCONT in chat script
# The last AT+CGDCONT= must use the same context as the dialer.
# If desired, The AT+CGDCONT may be prefixed by #MT[[:space:]]+
# Example:
#MT AT+CGDCONT="IPV6","data","192.168.2.1",0,1,"EXTRA"
#
# If you do not use a comment, the entire AT+CGDCONT command
# must be surrounded by apostrophes.  This command will be executed
# twice, once in the chat wrapper, and a 2nd time in the chat
# itself.
#
# The space after "#MT" may be any number including tabs.
# If #MT AT+CGDCONT= is found, only the last one is chosen.
# Any uncommented AT+CGDCONT= is then ignored.
# If there are not #MT AT+CGDCONT= lines, then any line without
# a comment chararacter before AT+CGDONT= is accepted, but only the
# last one in the file.

NAME=chat_wrapper
CONFIG=/etc/default/${NAME}
function finish
{
        ${LOG} "Launch:" "$@"
	exec "$@"
        # NOTREACHED
}

[[ -f $CONFIG ]] || exit 1

. ${CONFIG} 

: ${REGWAITTIME:=300}
: ${FINALWAIT:=5}

: ${LOG:="/usr/bin/logger -t ${NAME} -p daemon.notice"}

${LOG} Timeout is $REGWAITTIME, execute "$@" 
((i=$#))
chatscript="${!i}"
${LOG} Parsing chat script "$chatscript"

# CONTEXT is last context string in chat script
CONTEXT=$(egrep "^#MT[[:space:]]+(AT\+CGDCONT=.*)" ${chatscript} | tail -1)
if ((${#CONTEXT} == 0)) ; then
    CONTEXT=$(egrep "^[^#]+AT\+CGDCONT=" ${chatscript} | tail -1)
    [[ $CONTEXT =~ \'(AT\+CGDCONT=([0-9]+)[^$\']+) ]]
else
    [[ $CONTEXT =~ (AT\+CGDCONT=([0-9]+).*)$ ]]
fi

# CONTEXTNUM is the context number that is configured in the dialer.
CONTEXT="${BASH_REMATCH[1]}"
if ((${#CONTEXT} == 0)) ; then
	${LOG} No context specifiction in the chat script
        finish "$@"
	# NOTREACHED
fi
((CONTEXTNUM=${BASH_REMATCH[2]}))


${LOG} "Using Context ${CONTEXTNUM} based on chat script: ${CONTEXT}"

# At this point if there is no context number, we can skip everything else.

# Get Modem's context settings
MCONTEXT=$(/usr/bin/radio-cmd ${RADIOOPTION} -t10000 'AT+CGDCONT?' 2>&1 | tr -d '\r')
if [[ $MCONTEXT =~ [Ee][Rr][Rr][Oo][Rr] ]] ; then
    RADIOOPTION="${RADIOOPTION2}"
    MCONTEXT=$(/usr/bin/radio-cmd ${RADIOOPTION} -t10000 'AT+CGDCONT?' 2>&1 | tr -d '\r')
fi
	
if ! [[ $MCONTEXT =~ \+CGDCONT:[[:space:]]+${CONTEXTNUM},\"([^\"]*)\",\"([^\"]*)\",\"([^\"]*)\",([0-9]+),([0-9]+)([^$'\n']*) ]] ; then
    logger -s -p daemon.error "No valid context in modem.  Is it ready?"
    echo "$MCONTEXT" | logger -s -p daemon.error
fi

MPDP="${BASH_REMATCH[1]}"
MAPN="${BASH_REMATCH[2]}"
MADDR="${BASH_REMATCH[3]}"
MDCOMP="${BASH_REMATCH[4]}"
MHCOMP="${BASH_REMATCH[5]}"
MFULLBOAT="${BASH_REMATCH[6]}"

[[ $CONTEXT =~ AT\+CGDCONT=${CONTEXTNUM},\"([^\"]*)\",\"([^\"]*)\"(,\"([^\"]*)\"(,([0-9]+)(,([0-9]+)(,[^\']*))*)*)* ]]
PDP="${BASH_REMATCH[1]}"
APN="${BASH_REMATCH[2]}"
ADDR="${BASH_REMATCH[4]}"  # Optional
DCOMP="${BASH_REMATCH[6]}"  # Optional
HCOMP="${BASH_REMATCH[8]}"  # Optional
FULLBOAT="${BASH_REMATCH[9]}"  # Optional

# On some modems there are more parameters than others.
if [[ $MFULLBOAT != $FULLBOAT ]] ; then
	${LOG} "Only the first five context parameters are considered.  The rest will be ignored."
	${LOG} "modem: \"$MFULLBOAT\""
	${LOG} "chat script: \"$FULLBOAT\""
fi

if ((${#DCOMP} == 0)) ; then
	((DCOMP=0))  # Default
fi
if ((${#HCOMP} == 0)) ; then
	((HCOMP=0))  # Default
fi

# Only update context on a mismatch between chat and modem.
if [[ $MPDP != $PDP ]] || [[ $MAPN != $APN ]] || \
	[[ $MADDR != $ADDR ]] || ((MDCOMP != DCOMP)) || \
	((MHCOMP != HCOMP)) ; then
   ${LOG} "Modem context $MPDP,$MAPN,$MADDR,$MDCOMP,$MHCOMP does not match chat script"
   ${LOG} "Chat script context $PDP,$APN,$ADDR,$DCOMP,$HCOMP does not match the modem"
   if [[ $MPDP != $PDP ]] ; then
	${LOG} "PDP mismatch"
   fi
   if [[ $MAPN != $APN ]] ; then
	${LOG} "APN mismatch"
   fi
   if [[ $MADDR != $ADDR ]] ; then
	${LOG} "ADDR mismatch"
   fi
   if [[ $MDCOMP != $DCOMP ]] ; then
	${LOG} "DCOMP mismatch"
   fi
   if [[ $MHCOMP != $HCOMP ]] ; then
	${LOG} "HCOMP mismatch"
   fi
   if [[ $MFULLBOAT != $FULLBOAT ]] ; then
	${LOG} "Final parameter mismatches ignored"
	${LOG} "Parameter 6 and up on the modem:"
	${LOG} "\"${MFULLBOAT}\""
	${LOG} "Parameter 6 and up on the chat script:"
	${LOG} "\"${FULLBOAT}\""
   fi
   ${LOG} "$MCONTEXT"
   ${LOG} "Dropping registration with carrier to set context"
   # Need to deregister
   /usr/bin/radio-cmd ${RADIOOPTION} -t10000 'AT+COPS=2'
   # H5 radios do not like addresses that are empty with ""
   if ((${#ADDR} == 0)) ; then
     CMDSTR="AT+CGDCONT=${CONTEXTNUM},\"${PDP}\",\"${APN}\",,$DCOMP,${HCOMP}${FULLBOAT}"
   else
     CMDSTR="AT+CGDCONT=${CONTEXTNUM},\"${PDP}\",\"${APN}\",\"${ADDR}\",$DCOMP,${HCOMP}${FULLBOAT}"
   fi
   ${LOG} "Issued command /usr/bin/radio-cmd ${RADIOOPTION} -t10000 ..."
   ${LOG} "... ${CMDSTR}"

   # If we fail to set the APN, sleep and try it again for up to 10 seconds.
   result=1
   count=10
   while ((result != 0)) && ((count > 0)) ; do 
     ((count--)) || true
     LOGMSG=$(/usr/bin/radio-cmd ${RADIOOPTION} -t10000 "${CMDSTR}" 2>&1)
     result=$?
     ${LOG} "Result ${result}, Got response ${LOGMSG}"
     if [[ $LOGMSG =~ ERROR ]] ; then
	result=1
     fi
     sleep 1
   done

   # re-enable the modem to defaults.
   /usr/bin/radio-cmd ${RADIOOPTION} -t10000 'AT+COPS=0'
   sleep 1

   # Some older modems will not re-register after the COPS
   # command if you do not reset them using CFUN.
   /usr/bin/radio-cmd ${RADIOOPTION} -t10000 'AT+CFUN=0'
   /usr/bin/radio-cmd ${RADIOOPTION} -t10000 'AT+CFUN=1'

   # Abort PPP if the Context is not correct.  We don't want
   # to cause the carrier to disable the account by dialing
   # out with a bad APN.
   if ((result != 0)) ; then
	${LOG} "AT+CGDCONT failed, aborting"
	exit $result
   fi
   sleep 1
   ${LOG} "New context is set.  Wait up to $REGWAITTIME seconds to register"
   # Wait for registration
   uptime=$(cat /proc/uptime)
   [[ $uptime =~ ^([^\.]*) ]]
   t0=${BASH_REMATCH[1]}
   while ! [[ $(/usr/bin/radio-query ${RADIOOPTION} --netreg) =~ ^REGISTERED$ ]] ; do
      sleep 5
      uptime=$(cat /proc/uptime)
      [[ $uptime =~ ^([^\.]*) ]]
      t1=${BASH_REMATCH[1]}
      if ((t1-t0 > REGWAITTIME)) ; then
	   ${LOG} "$((t1-t0)) seconds has expired"
	   exit 1
      fi	
   done
   uptime=$(cat /proc/uptime)
   [[ $uptime =~ ^([^\.]*) ]]
   t1=${BASH_REMATCH[1]}
   ${LOG} "Re-registered in $((t1-t0)) seconds -- wait ${FINALWAIT} more seconds"
   sleep $FINALWAIT
else
   ${LOG} "Context $CONTEXTNUM matches and nothing to do."
fi
finish "$@"
# NOTREACHED
