Extending send.sh with binary support

Posted by JPLa on September 15, 2017

In Sending a binary message - Part 1 we learned how to send a MT binary SMS from command line. Based on that we can add this functionality to the send.sh script.

Usage

Lets see what new command line switches we can add. Out with the old – in with the new (this output is from the diff utility):

37c37
<     echo "Usage: $1 -s sender -r recipient [-m message] [-f filename] [-hex message in hex]" >/dev/stderr
---
>     echo "Usage: $1 -s sender -r recipient [-bin|-text] [-m message] [-smart smart port] [-udh udh in hex] [-f filename] [-hex message in hex]" >/dev/stderr

Documentation from the send script README:

Parameter Value Definition
[-bin |
-text]
Bin | text The message content is a binary or text message.
[-smart] Smart messaging port number The smart messaging destination and originator ports. Remember to use the bin parameter if the content is a binary message.
[-udh] UDH in hex The User Data Header information in hexadecimal format
To find out more about the UDH parameter, see the Nokia Smart Messaging documentation. Do not use this parameter if you do not know how it affects the mobile terminal’s functions.

So we can specify whether it is a text or binary message. But lets first agree that using -smart or -udh switches implies that this is a binary message. And if both -smart and -udh switches are present the last one will override the earlier. (…in other words: Don’t use both of them!)


Yes – I’m slightly changing the semantics to something that makes more sense in Opaali API context. I’d better remember to update the README…


Parsing the arguments

Lets add a new global variable MODE to choose between TEXT and BIN (and FLASH which we will probably also add, but later, not now).

        # message sending mode: TEXT|BIN|FLASH (TEXT is default)
        MODE="TEXT"

We will also rewrite the -hex switch parsing which we added last time. Lets introduce another global variable HEX where we will store the hex string if it was given (and we’ll move decoding the hex string somewhere later in the script).

                -hex)
                shift
                if [[ -n "$1" ]]; then
                    # HEX will contain MESSAGE as hex encoded
                    HEX="$1"
                else
                    error_exit "$0" "missing hex message" "$1"
                fi
                shift
                ;;

We will put the UDH (User Data Header) into global variable UDH and also set MODE to binary:

                -udh)
                shift
                if [[ -n "$1" ]]; then
                    # User Data Header
                    UDH="$1"
                    # UDH implies MODE BIN
                    MODE="BIN"
                else
                    error_exit "$0" "missing UDH" "$1"
                fi
                shift
                ;;

I believe the CGW version of send only supported decimal values for smart messaging port number, so we won’t bother with hex values, either. We’ll construct a UDH containing just the port addressing IE and overwrite any possibly existing UDH value (because if you can construct a UDH then what would you need the -smart parameter for?)

If the port number is less than 256 we can fit it into 8 bits, otherwise we’ll use 16-bit addressing:

                -smart)
                shift
                declare -i SMART
                if [[ -n "$1" ]]; then
                    # smart messaging port number (in decimal)
                    SMART="$1"
                    # SMART implies MODE BIN
                    MODE="BIN"
                    # SMART is implemented as UDH (overwrites possibly existing UDH)
                    if [[  $1 -lt 256 ]]; then
                        # 8-bit port number
                        UDH=$(printf '040402%02x%02x' $SMART $SMART)
                    else
                        # 16-bit port number
                        UDH=$(printf '060504%04x%04x' $SMART $SMART)
                    fi
                else
                    error_exit "$0" "missing port in -smart" "$1"
                fi
                shift
                ;;


(Like last time you can check Wikipedia for more details: Wikipedia: User Data Header.)


And if the mode is specified we will store it into variable MODE:

                -bin)
                MODE="BIN"
                shift
                ;;
                -text)
                MODE="TEXT"
                shift
                ;;

We will also make minor adjustments to the argument post processing and add a call to a new function that will build the text or binary message:

145c184
<         if [ -z "${MESSAGE}" ]; then
---
>         if [[ -z "${MESSAGE}" && -z "${HEX}" ]]; then
164a204,205
>         # build final MESSAGE (including UDH if needed)
>         buildMessage "${MESSAGE}" "${HEX}" "${MODE}" "${UDH}"

Building a Text or Binary Message

Before that last buildMessage function call in parseArguments we have

  • MESSAGE in text form from file, command line or read from stdin
  • alternatively HEX containing a text or binary message as hex encoded
  • for a binary message UDH as given on command line or generated from -smart parameter
  • we also have MODE but we could guess that from UDH already

If we have

  1. a HEX encoded TEXT MODE message we need to decode it into MESSAGE
  2. a UDH we need to append to it the MESSAGE base64 encoded (or HEX which we first decode into binary data)

So the function buildMessage would look like this:

# build a message and store it in global variable MESSAGE
function buildMessage {
    #param 1: message in TEXT format
    #param 2: message in HEX format
    #param 3: MODE
    #param 4: UDH or (null)
    
    if [[ -n "$4" || "$3" == BIN ]]; then
        # UDH implies binary message
        UDH="$4"
        if [[ -z "$2" ]]; then
            # hex encode text
            HEX=$(echo -n "$1" | xxd -p | tr -d "\n")
        else
            HEX="$2"
        fi
        MESSAGE=$(echo -n "$UDH$HEX" | xxd -r -p | base64 | tr -d "\n")
    else
        # text message
        if [[ -z "$1" && -n "$2" ]]; then
            # decode hex message into text
            MESSAGE=$(echo -n "$2" | xxd -r -p)
        else
            MESSAGE="$1"
        fi
    fi
    return 0
}

And when we return from the function call the global variable MESSAGE will contain either the text to be sent or a UDH followed by the binary data.

outboundMessageRequest

It turns out that the only change we need to make to our existing outboundMessageRequest function is choosing the JSON parameter name between “outboundSMSTextMessage” and “outboundSMSBinaryMessage”.

So we will add a third parameter mode to our existing outboundMessageRequest function:

# make an outboundMessageRequest
function outboundMessageRequest {
    #param 1: recipientAddress
    #param 2: message
    #param 3: mode - BIN or TEXT
    #global: senderAddress - sender address string
    #global: senderNameString - sender name string with comma or empty string
    #global: access_token - access token string
    #global: deli - resource URL to be used when querying status

    # urlencode + and :
    local sender=$(echo -n "$senderAddress" | sed -e s/\+/%2B/g -e s/\:/%3A/g)

    local outboundSMStype=""
    # choose a text or binary message
    if [[ $3 == "BIN" ]]; then
        outboundSMStype="outboundSMSBinaryMessage"
    else
        outboundSMStype="outboundSMSTextMessage"
    fi
    
    
    # call Opaali API and capture the interesting parts from the output"
    local output=$(curl -k -s -d "{\"outboundMessageRequest\":{\"address\":[\"$1\"],\"senderAddress\":\"$senderAddress\",\"$outboundSMStype\":{\"message\":\"$2\"}$senderNameString}}" --header 'Content-Type:application/json' --header "Authorization: Bearer $access_token" https://api.opaali.telia.fi/production/messaging/v1/outbound/$sender/requests | grep -E 'resourceURL|error')

# the rest of the function is not shown here as there will be no changes to it!
# ...

And finally we will add the new mode parameter to our function call:

284c363
<     outboundMessageRequest "${RECIPIENT}" "${MESSAGE}"
---
>     outboundMessageRequest "${RECIPIENT}" "${MESSAGE}" "${MODE}"

Examples

Lets use our old vCalendar example and set vcal_udh and vcal_msg:

$ vcal_udh=06050423f50000

$ vcal_msg=$(cat example.vcal | xxd -p | tr -d "\n")

$ ./send.sh  -s '$JPLa' -r '+358401234567' -udh $vcal_udh -hex $vcal_msg
SENT: tel:+358401234567 DeliveredToNetwork

$

The data received at the other end looked similar to that which we got the last time when sending from command line using curl.

Because -udh implies -bin we don’t necessarily need to give the vCalendar data (which is text anyway) hex encoded:

$ ./send.sh  -s '$JPLa' -r '+358401234567' -udh $vcal_udh -m "$(cat example.vcal)"
SENT: tel:+358401234567 DeliveredToNetwork

$

The data received is almost identical to the first example, but as bash is a unix-style command shell the line endings were just LF instead of CR+LF (depending on the receiving terminal this may or may not be significant).

Or we can use the -smart parameter and avoid constructing a UDH:

$ ./send.sh  -s '$JPLa' -r '+358401234567' -smart 9205 -m "$(cat example.vcal)"
SENT: tel:+358401234567 DeliveredToNetwork

$ ./send.sh  -s '$JPLa' -r '+358401234567' -bin -smart 9205 -m "$(cat example.vcal)"
SENT: tel:+358401234567 DeliveredToNetwork

$

We can even abuse the syntax a bit by leaving out the -udh parameter, adding the -bin parameter and giving UDH+data together as a single hex string:

$ ./send.sh  -s '$JPLa' -r '+358401234567' -bin -hex 06050423f50000424547494e3a5643414c454e4441520d0a56455253494f4e3a312e300d0a424547494e3a564556454e540d0a4445534352495054494f4e3a5374656572696e672047726f7570206d656574696e6720696e20506f7274616c0d0a445453544152543a3230303030393036543130303030300d0a4454454e443a3230303030393036543132303030300d0a454e443a564556454e540d0a454e443a5643414c454e4441520d0a
SENT: tel:+358401234567 DeliveredToNetwork

$

This works with Opaali API because it is assumed that the binary message always starts with a UDH so the UDH present flag is always set for binary messages.


This BTW does not work with CGW where UDH is separately provided to the API. You can send the message, but the UDH flag is not set, which will confuse the receiving end. Yes, I ran the test on the original send.exe of CGW:

$ /c/Program\ Files\ \(x86\)/CGW/send.exe  -s '$JPLa' -r '+358401234567' -bin -hex 06050423f50000424547494e3a5643414c454e4441520d0a56455253494f4e3a312e300d0a424547494e3a564556454e540d0a4445534352495054494f4e3a5374656572696e672047726f7570206d656574696e6720696e20506f7274616c0d0a445453544152543a3230303030393036543130303030300d0a4454454e443a3230303030393036543132303030300d0a454e443a564556454e540d0a454e443a5643414c454e4441520d0a
SENT: 00358401234567 Delivered to the SMSC

Also, the following syntax doesn’t seem to work on CGW (although our send.sh script accepts it):

$ /c/Program\ Files\ \(x86\)/CGW/send.exe  -s '$JPLa' -r '+358401234567' -bin -smart 9205 -m "$(cat example.vcal)"
FAIL: 00358401234567 No message to send

Looks like you shouldn’t give the message in text format with the -bin parameter. Giving it as a hex string works:

$ /c/Program\ Files\ \(x86\)/CGW/send.exe  -s '$JPLa' -r '+358401234567' -bin -smart 9205 -hex $vcal_msg
SENT: 00358401234567 Delivered to the SMSC

The rest of the examples worked on CGW also:

$ /c/Program\ Files\ \(x86\)/CGW/send.exe  -s '$JPLa' -r '+358401234567' -smart 9205 -m "$(cat example.vcal)"
SENT: 00358401234567 Delivered to the SMSC

$ /c/Program\ Files\ \(x86\)/CGW/send.exe  -s '$JPLa' -r '+358401234567' -udh $vcal_udh -m "$(cat example.vcal)" 
SENT: 00358401234567 Delivered to the SMSC

$ /c/Program\ Files\ \(x86\)/CGW/send.exe  -s '$JPLa' -r '+358401234567' -udh $vcal_udh -hex $vcal_msg
SENT: 00358401234567 Delivered to the SMSC


See Extending send.sh with -hex switch for the previous related episode.


JPLa is a member of the Content Gateway (CGW) to Opaali migration team, specialising in programming related issues and API usage.