I have solved the above and some other problems and would like to share the outcome. The script below will
* work on FreeBSD (like FreeNAS 9)
* support different ESSD commands for account balance and expiration date (like Aldi Talk)
* accept character encodings with German umlauts
* fix some misleading debug output

German users: check out the smsd.config file with German provider settings in this forum.

#!/usr/local/bin/bash

###########################################################################
# Global settings:

get_balance_after=5 # 1 = get the balance after at least one message is sent.

max_age=24 # an integer for hours, 0 = disable periodic checking.

alert_balance=5 # an integer for "euros".

alert_expiration=14 # an integer for days.

# set to "" for no notification
alert_to="491771401303"

###########################################################################
# Device depended settings:

# Comment out the next command if a DEVICENAME setting should be taken from
# the name of this file (which can be a symbolic link). For example:
# /var/spool/sms/regular_run/GSM1.sh
#DEVICENAME="GSM1"

[ -z "$DEVICENAME" ] && tmp=${0##*/} && DEVICENAME=${tmp%%.*}
balance_file="/var/spool/sms/stats/${DEVICENAME}.balance"
counter_file="/var/spool/sms/stats/${DEVICENAME}.counter"
get_balance_flagfile="/var/spool/sms/stats/get.${DEVICENAME}.balance"
regular_run_cmdfile="/var/spool/sms/regular_run/${DEVICENAME}.cmdfile"
regular_run_statfile="$2"
outgoing="/var/spool/sms/outgoing"

###########################################################################
# START OF OPERATOR SPECIFIC SETTINGS

# If more than one modem is used and they have different operator specific
# settings, move this section to the files for each modem and include the
# file here using the following command:
# . /var/spool/sms/regular_run/${DEVICENAME}.operator_settings.sh

# The USSD commands to output to the modem
# several commands may be concatenated with "\n"
# first command should be for balance, optional second for expiration date
ussd_command="AT+CUSD=1,\"*100#\",15\nAT+CUSD=1,\"*102#\",15"
 
# This is an example result for the query:
# 2010-05-09 14:16:11,5, GSM1: CMD: AT+CUSD=1,"*100#": OK +CUSD: 2, ...
# ... "Liittym�si saldo on 22.36 EUR. Puheaikasi vanhenee 27.04.2011.",15

# Defines how balance can be found from the result:
balance_prefix="Ihr Guthaben beträgt: "

# Defines how the balance amount part ends (NOT the radix symbol):
balance_suffix=" ."

# Defines how the expiration date can be found.
# With an empty setting the expiration is not checked.
balance_expiration="endet am "

# Helper function for converting date from the answer to the format yyyy-mm-dd
# Modify this if necessary.
extract_expiration()
{
  # datestamp to format yyyy-mm-dd
  echo "${1:6:4}-${1:3:2}-${1:0:2}"
}

: <<COMMENTBLOCK

Example 2:
..."Balance subscription is EUR 22.36. Your allotted time expires 04/27/2011."

balance_prefix="EUR "
balance_suffix="."
balance_expiration="expires "
Command in extract_expiration(): echo "${1:6:4}-${1:0:2}-${1:3:2}"

Example 3:
..."The balance is 34.84 B. & valid until 26/07/10 "

balance_prefix="is "
balance_suffix="."
balance_expiration="until "
Command in extract_expiration(): echo "20${1:6:2}-${1:3:2}-${1:0:2}"

Example 4:
...Ihr Restguthaben ist CHF 18,87

balance_prefix="CHF "
balance_suffix=","
balance_expiration=""

COMMENTBLOCK


# END OF OPERATOR SPECIFIC SETTINGS
###########################################################################

substr()
{
  local string=$1
  local prefix=$2
  local suffix=$3

  local ppref=${string%${prefix}*}

  # Changed 2010-11-02:
  if [[ "$ppref" == *${prefix}* ]]
  then
    string=${string//\"/}

    local position=$(echo | awk '{
      print index("'
"${string}"'", "'"${prefix}"'")
    }'
)

    if [ $position -gt 0 ]; then
      ppref=${string:0:$(($position - 1))}
    fi
  fi
  # -------------------

  local ssuff=${string#*${suffix}}
  local nopref=${string#${ppref}${prefix}}
  echo ${nopref%${suffix}${ssuff}}
}

#--------------------------------------------------------------------------
date2stamp()
{
  case `uname` in
    FreeBSD)
      if [ ${#1} -gt 10 ]; then
        date -juf "%Y-%m-%d %H:%M:%S" "$1" +%s
      else
        date -juf "%Y-%m-%d" "$1" +%s
      fi
      ;;
    Darwin)
      date -juf "%Y-%m-%d %H:%M:%S" "$1" +%s
      ;;
    *)
      date --utc --date "$1" +%s
      ;;
  esac
}

#--------------------------------------------------------------------------
dateDiff()
{
  local sec=0

  case $1 in
    -s) sec=1; shift;;
    -m) sec=60; shift;;
    -h) sec=3600; shift;;
    -d) sec=86400; shift;;
    *) sec=86400;;
  esac

  local dte1=$(date2stamp "$1")
  local dte2=$(date2stamp "$2")
  local diffSec=$((dte2-dte1))

  echo $((diffSec/sec))
}

###########################################################################

test -e "$counter_file" || exit 1

# triggering balance based on number of SMSes sent requires stats: in smsd.conf place
# stats = <directory of this script>
messages=$(formail -zx ${DEVICENAME}: < "$counter_file")

if [ "$1" = "PRE_RUN" ]; then

  get_balance=0

  # Get the balance if it was requested:
  [ -w "$get_balance_flagfile" ] && get_balance=1 && \
     unlink "$get_balance_flagfile"

  if [ -r "$balance_file" ]; then
    # Get the balance if a defined number of messages were sent.
    messagesb=$(formail -zx Messages: < "$balance_file")
    [ $(($messages - $messagesb)) -ge $get_balance_after ] && get_balance=1
  else
    # Get the balance because the previous value is not known.
    get_balance=1
  fi

  # Check the age of the last query if necessary:
  if [ $get_balance = 0 ] && [ $max_age -gt 0 ]; then
    last_query=$(formail -zx Last_query: < "$balance_file")
    age=$(dateDiff -h "$last_query" "$(date +"%Y-%m-%d %T")")
    [ $age -ge $max_age ] && get_balance=1
  fi

  # NOTE: option -e necessary for bash on FreeBSD to process '\n' between commands
  [ $get_balance -gt 0 ] && echo -e "$ussd_command" > "$regular_run_cmdfile"
 
 

else

  # 2011-06-29: Check that USSD command is found:
  result=""
  if [ -r "$regular_run_statfile" ]; then
    tmp=${ussd_command%%"\n"*} # throw away all but first ussd command
    tmp=${tmp//\"/\\\"} # escape double quotes
    tmp=${tmp//\*/\\*} # escape asterisks
    # concatenate responses and check if it contains the first command
    result=$(tr -d "\n\r" < "$regular_run_statfile" | grep "$tmp")
  fi

  if [ -n "$result" ]; then

    balance_low=-1 # Initial value means unknown.
    balance=-1
    balance_alerted=""
    expiration_low=-1
    expiration=-1
    expiration_alerted=""
    sms_alert=""
    current_alert=""

    # 2010-11-02: Change Ctrl-B to $
    result=$(echo "${result//$'\x02'/$}")

    # Check that required words exists:
    if [[ "$result" == *${balance_prefix}* ]] && \
       [[ "$result" == *${balance_suffix}* ]]
    then
      # Get the balance and check it:
      balance=$(substr "$result" "$balance_prefix" "$balance_suffix")
      balance_low=0
     
      if [ $(expr "$balance" + 1 2> /dev/null) ]; then
        [ $balance -le $alert_balance ] && balance_low=1
      else
        #echo "Error while parsing an integer: $balance"
        echo "Balance $balance is above warning threshold $alert_balance"
      fi
    else
      echo "Error while parsing the answer (balance): $result"
    fi

    # Get the expiration date if defined, and check it:
    if [ -n "$balance_expiration" ]; then
      if [[ "$result" == *${balance_expiration}* ]]; then
        expiration_low=0
        expiration=$(substr "$result" "$balance_expiration" "")
        expiration=$(extract_expiration "$expiration")
        expiration=$(dateDiff -d "$(date +"%Y-%m-%d")" "$expiration")
        echo "time until expiration in days is $expiration days"
        [ $expiration -le $alert_expiration ] && expiration_low=1
      else
        echo "Error while parsing the answer (expiration): $result"
      fi
    fi



    if [ -e "$balance_file" ]; then
      # Get previous values:
      current_alert=$(formail -zx Current_alert: < "$balance_file")
      balance_alerted=$(formail -zx Balance_alerted: < "$balance_file")
      expiration_alerted=$(formail -zx Expiration_alerted: < "$balance_file")
    fi

    balance_gone_low=0 # added 2010-11-03
    # If not yet alerted and the balance has gone low, alert now:
    if [ -z "$balance_alerted" ] && [ $balance_low = 1 ]; then
      balance_gone_low=1
      balance_alerted=$(date +"%Y-%m-%d %T")
      tmp="The balance has gone low ($balance)."
      echo "$tmp" # This message goes to the smsd.log
      [ -z "$sms_alert" ] && sms_alert="Alert:"
      sms_alert="${sms_alert} ${tmp}"

      # If the expiration is already alerted, but the issue is still active,
      # include it in the message:
      if [ -n "$expiration_alerted" ] && [ $expiration_low = 1 ]; then
        sms_alert="${sms_alert} The expiration is also near ($expiration days)."
      fi
    fi

    # Remove an outdated alert:
    [ -n "$balance_alerted" ] && [ $balance_low = 0 ] && balance_alerted=""

    # If not yet alerted and the expiration is near, alert now:
    if [ -z "$expiration_alerted" ] && [ $expiration_low = 1 ]; then
      expiration_alerted=$(date +"%Y-%m-%d %T")
      tmp="The expiration is near ($expiration days)."
      echo "$tmp" # This message goes to the smsd.log
      [ -z "$sms_alert" ] && sms_alert="Alert:"
      sms_alert="${sms_alert} ${tmp}"

      # If the balance is already alerted, but the issue is still active,
      # include it in the message:
      if [ -n "$balance_alerted" ] && [ $balance_low = 1 ]; then
        if [ $balance_gone_low -eq 0 ]; then
          sms_alert="${sms_alert} The balance is also low ($balance)."
        fi
      fi
    fi

    # Remove an outdated alert:
    [ -n "$expiration_alerted" ] && [ $expiration_low = 0 ] && \
       expiration_alerted=""

    [ -z "$balance_alerted" ] && [ -z "$expiration_alerted" ] && \
       current_alert=""

    if [ -n "$sms_alert" ] && [ -n "$alert_to" ]; then
      # Send the SMS:
      FILE=$(mktemp /tmp/alert_XXXXXX)
      echo "To: $alert_to" >> $FILE
      echo "" >> $FILE
      echo "$DEVICENAME $sms_alert" >> $FILE
      FILE2=$(mktemp "${outgoing}/send_XXXXXX")
      mv $FILE "$FILE2"
    fi

    # Save the details:
    DATE=$(date +"%Y-%m-%d %T")
    echo "Last_query: $DATE" > "$balance_file"
    [ -n "$sms_alert" ] && current_alert="${DATE}, $sms_alert"
    [ -n "$current_alert" ] && \
       echo "Current_alert: $current_alert" >> "$balance_file"
    echo "Messages: $messages" >> "$balance_file"
    echo "Balance: $balance" >> "$balance_file"
    [ -n "$balance_expiration" ] && \
       echo "Expiration: $expiration" >> "$balance_file"
    [ -n "$balance_alerted" ] && \
       echo "Balance_alerted: $balance_alerted" >> "$balance_file"
    [ -n "$expiration_alerted" ] && \
       echo "Expiration_alerted: $expiration_alerted" >> "$balance_file"
    #echo "" >> "$balance_file"
    #echo "$result" >> "$balance_file"
  fi
fi

exit 0
 
 
'bash' Syntax Highlight powered by GeSHi



Enjoy!