- #!/bin/sh
- set -e
- vardir=/var/lib/kannel/hello
- sbindir=/usr/local/sbin
- exit0() {
- [ -n "$1" ] && echo "$1"
- exit 0
- }
- exit1() {
- response="${1:+Error: }${1:-Internal error!}"
- # FIXME: pass error messages via stderr (not stdout)
- # echo >&2 "$response"
- echo "$response"
- [ -z "$SMS_SMSC$SMS_URL" ] || $sbindir/localsendsms "$to" "$response"
- exit 1
- }
- grepescape() {
- echo "$1" | perl -pe 's/(?=[+])/\\/g'
- }
- # Based on Text::Unidecode bug#8017: http://rt.cpan.org/Ticket/Display.html?id=8017#txn-322351
- lctransliterate() {
- echo "$1" | perl -n \
- -e 'use Text::Unidecode;' \
- -e 'use Encode 2.12 qw(encode decode _utf8_off);' \
- -e 'print lc(decode("GSM0338", encode("GSM0338", decode("UTF-8", $_),' \
- -e 'sub {$a=unidecode(chr $_[0]); _utf8_off($a); $a;}' \
- -e ')));'
- return $res;
- }
- uriunescape() {
- if [ 0 = "$urldecode" ]; then
- echo "$@"
- else
- echo "$@" | perl -e 'use URI::Escape; print uri_unescape(<STDIN>);'
- fi
- }
- # Resolve var from "variable = value" pair in file below /etc/local
- getfilevar() {
- file="/etc/local/$1"
- var="$2"
- grep -m1 "^$var" "$file" | awk -F '(= )' '{print $2}'
- }
- lastservicephone() {
- logfile=/var/log/kannel/smsbox.log
- tac $logfile $logfile.1 \
- | perl -ne "/INFO: Starting to service <.*> from <$1> to <([^<>]*)>/ and print \$1 and exit 0"
- }
- #from=`uriunescape "$1" | sed -e 's/\+/ /g'`; shift
- from=`uriunescape "$1"`; shift
- #to=`uriunescape "$1" | sed -e 's/\+/ /g'`; shift
- to=`uriunescape "$1"`; shift
- # FIXME: avoid stripping ALL plusses
- set -- `uriunescape "$@" | sed -e 's/\+/ /g'`
- #set -- `uriunescape "$@"`
- app_raw="$1"
- app=`lctransliterate "$1"`; shift
- export debug
- SMS_PHONE="$from"
- urldecode=0
- export SMS_PHONE urldecode
- case "$SMS_REALM" in
- test)
- ccc="${ccc:-99}"
- provider="dummy"
- mdpath="/home/hearth/public_webdata/hearth/content/sms"
- export mdpath
- ;;
- hello)
- ccc="45"
- provider="local"
- # provider="coolsms"
- # provider="clickatell"
- mdpath="/home/hearth/public_webdata/hearth/content/sms"
- export mdpath
- ;;
- hellobudapest)
- ccc="36"
- # provider="clickatell"
- provider="local"
- addtestphones="+36307418279" # Jonas
- addphones=""
- gotestphones="+36307418279" # Jonas
- gophones=""
- SMS_ERRFROM="+36307418279" # Jonas
- SMS_ERRTO1="+36307418279" # Jonas
- SMS_ERRTO2="+36307418241" # Emma
- # SMS_ERRTO2="+36703782127" # Emma
- mdpath="/home/www-hearth/public_webdata/hellobudapest/content/sms"
- export SMS_ERRFROM SMS_ERRTO1 SMS_ERRTO2 mdpath
- ;;
- hellotorino)
- ccc="39"
- provider="clickatell"
- gotestphones="+393453915741 +393453805531 +393453801457" # Jonas, Jacob, Vera
- gophones="+393407574815 +393407574813 +393381467977 +393478617029" # Alessandra, Vela, Marco, Silvia
- SMS_ERRFROM="+393453915741" # Jonas
- SMS_ERRTO1="+393453801457" # Vera
- SMS_ERRTO2="+393483281187" # Rescue
- mdpath="/home/www-hearth/public_webdata/hellotorino/content/sms"
- export SMS_ERRFROM SMS_ERRTO1 SMS_ERRTO2 mdpath
- ;;
- cyber)
- ccc="45"
- provider="local"
- mdpath="/home/cyberhus/public_webdata/mdsms/content/sms"
- export mdpath
- ;;
- hpm)
- ccc="84"
- provider="local"
- mdpath="/home/www-sms/public_webdata/hpm/content/sms"
- export mdpath
- ;;
- *)
- exit1 "unknown realm \"$SMS_REALM\"!"
- ;;
- esac
- case "$provider" in
- dummy)
- dummy=1
- ADMIN_OK=1
- export ADMIN_OK dummy
- ;;
- local)
- export SMS_SMSC
- ;;
- coolsms)
- unset SMS_SMSC
- SMS_URL="https://sms.coolsmsc.dk:8081/"
- SMS_USER=$(getfilevar coolsms user)
- SMS_PW=$(getfilevar coolsms pw)
- SMS_CP="cp1252"
- SMS_MSGTAG="message"
- export SMS_URL SMS_USER SMS_PW SMS_CP SMS_MSGTAG
- ;;
- # supports concatenation and req_feat (e.g 48: sender ID)
- # does not support DLR, and only concatenates max. 3 smses
- clickatell)
- unset SMS_SMSC
- SMS_URL="https://api.clickatell.com/http/sendmsg"
- SMS_USER=$(getfilevar clickatell user)
- SMS_PW=$(getfilevar clickatell pw)
- SMS_CP="iso8859-1"
- SMS_USERTAG="user"
- SMS_API=$(getfilevar clickatell api)
- SMS_CALLBACK="3"
- SMS_CONCAT="3"
- SMS_ESCALATE="1"
- SMS_VALIDITY="1"
- SMS_REQ_FEAT="24611" # 1+2+32+8192+16384 = text+8bit+numeric_src+dlr+concat
- stripprefix="1"
- export SMS_URL SMS_USER SMS_PW SMS_CP SMS_USERTAG SMS_API SMS_CALLBACK SMS_CONCAT SMS_ESCALATE SMS_VALIDITY SMS_REQ_FEAT stripprefix
- ;;
- # supports DLR
- # Kannel clickatell profile supports concatenation but not req_feat
- # Kannel generic profile supports req_feat but not concatenation
- clickatell_via_kannel)
- SMS_SMSC="X"
- SMS_CONCATENATION="1"
- SMS_DLR_MASK="7"
- SMS_DLR_URL="http://helloearth.jones.dk/test.cgi?type=dlr&msgid=XXX&smsid=%I&from=%p&to=%P&time=%t&unixtime=%T&dlr=%d&dlrmsg=%A"
- SMS_CP="iso8859-1"
- SMS_VALIDITY="1"
- SMS_BINFO="req_feat=24611&concat=3&escalate=1%validity=1" # 1+2+32+8192+16384 = text+8bit+numeric_src+dlr+concat
- stripprefix="1"
- export SMS_SMSC SMS_CONCATENATION SMS_DLR_MASK SMS_DLR_URL SMS_CP SMS_VALIDITY SMS_BINFO stripprefix
- ;;
- routo_via_kannel)
- SMS_SMSC="Y"
- export SMS_SMSC
- ;;
- *)
- exit1 "unknown provider \"$provider\"!"
- ;;
- esac
- # FIXME: some safety net against abusing this imposter feature
- #if [ -n "$REDIRECT_OK" ]; then
- case "$app" in
- @*)
- # FIXME: Avoid hardcoding country code
- targetphone="$(echo "$app" | perl -pe 's/^@//;' -e 's/^([^+])/+'"$ccc"'\1/')"
- # TODO: silence errors - or better: bounce those back to original sender
- targetfrom=$(lastservicephone "$targetphone")
- [ -n "$targetfrom" ] || exit1 "refusing to redirect: unknown target phone number \"$targetphone\"."
- SMS_PHONE="$targetfrom" $sbindir/localmarkdown2sms "$targetphone" "$@"
- exit 0
- ;;
- esac
- #fi
- # FIXME: some safety net against abuse
- #if [ -n "$GROUP_OK" ]; then
- case "$app" in
- !*)
- group="$(echo "$app" | perl -pe 's/^!//;')"
- members=$(cd "$vardir/user" && grep -lF "$group" */group | perl -pe "s,/group$,,") || members=
- # FIXME: check that sender is member
- # TODO: permit non-member as sender if $REDIRECT_OK
- [ -n "$members" ] || exit1 "Message not sent: no members found in group \"$group\"!"
- for member in $members; do
- phone=$(head -n 1 "$vardir/user/$member/phone") || nophone="${nophone+$nophone }$member"
- [ -z "$phone" ] || $sbindir/localsendsms "$phone" "$@"
- done
- membercount=$(echo "$members" | wc --word)
- [ -z "$nophone" ] || nophonecount=$(echo "$nophone" | wc --word)
- [ -z "$nophone" ] || exit1 "Message sent to $membercount members of group \"$group\", but failed for $nophonecount of them (could not resolve phone number)!"
- exit0 "Message sent to all $membercount members of group \"$group\"."
- ;;
- esac
- #fi
- case "$app" in
- /*)
- cmd="$(echo "$app" | perl -pe 's/^\///;')"
- case "$cmd" in
- ping)
- if [ "help" = "$1" ]; then
- $sbindir/localsendsms "$to" "Usage:
- /ping [...]
- Respond \"pong\" and echo back any addition input."
- exit 0
- fi
- $sbindir/localsendsms "$to" pong "$@"
- exit 0
- ;;
- add|addtest)
- if [ "help" = "$1" ]; then
- $sbindir/localsendsms "$to" "Usage:
- /add ID PHONE [MSG]...]
- Register PHONE as ID,
- and (if included) send MSG to subscribers."
- exit 0
- fi
- id="$(echo "$1" | perl -ne '/^(\d\d)$/ and print $1;')"
- [ -n "$id" ] || exit1 "wrong or missing id: must be 2 digits."
- shift
- # FIXME: avoid juggling with leading plus here when no longer stripped from input
- # FIXME: make country code optional when plus no longer stripped from input
- # FIXME: Avoid hardcoding country code
- # phone="$(echo "$1" | perl -ne 's/^(?=[^+])/+'"$ccc"'/;' -e '/^(\+\d\d\d+)$/ and print $1;')"
- phone="$(echo "$1" | perl -ne '/^(\d\d\d+)$/ and print $1;')"
- [ -n "$phone" ] || exit1 "wrong or missing phone number: must be only digits with leading + and at least 3 digits."
- targetfrom=$(lastservicephone "\+$phone")
- [ -n "$targetfrom" ] || exit1 "unknown phone +$phone: it must have been used with the system recently."
- phone="+$phone"
- shift
- case "$cmd" in
- addtest)
- msgphones="$addtestphones"
- ;;
- add)
- msgphones="$addphones"
- ;;
- esac
- str=$($sbindir/localsmsadmin add user "$id" "$phone")
- $sbindir/localsendsms "$to" "[info] \"$cmd\": $str."
- if [ -n "$*" ]; then
- for msgphone in $msgphones; do
- $sbindir/localsendsms "$msgphone" "[info] $id $phone $@"
- done
- $sbindir/localsendsms "$to" "[info] $id $phone added/updated. trailing message forwarded to subscribers."
- else
- $sbindir/localsendsms "$to" "[info] $id $phone added/updated. (no trailing message passed to subscribers)."
- fi
- exit 0
- ;;
- # FIXME: generalize this ugly hacks somehow, and secure against random use
- go|gotest|so|sotest)
- case "$cmd" in
- go*)
- basecmd="go"
- realcmd="hello"
- ;;
- so*)
- basecmd="so"
- realcmd="szia"
- ;;
- esac
- if [ "help" = "$1" ]; then
- $sbindir/localsendsms "$to" "Usage:
- /$basecmd PHONE... [MSG...]
- /${basecmd}test PHONE... [MSG...]
- /$basecmd help
- Start thread \"$realcmd\" on behalf of each PHONE,
- and (if included) send MSG to subscribers."
- exit 0
- fi
- [ -n "$1" ] || exit1 "target phone number missing (try \"/$cmd help\" for usage)"
- case "$cmd" in
- gotest|sotest)
- phones="$gotestphones"
- ;;
- go|so)
- phones="$gophones"
- ;;
- esac
- # FIXME: avoid juggling with leading plus here when no longer stripped from input
- # FIXME: make country code optional again when plus no longer stripped from input
- # FIXME: Avoid hardcoding country code
- while [ -n "$1" ]; do
- # targetphone="$(echo "$1" | perl -ne 's/^(?=[^+])/+'"$ccc"'/;' -e '/^(\+\d\d\d+)$/ and print $1;')"
- targetphone="$(echo "$1" | perl -ne '/^(\d\d\d+)$/ and print $1;')"
- [ -n "$targetphone" ] || continue
- # Sanity check
- targetfrom=$(lastservicephone "\+$targetphone")
- [ -n "$targetfrom" ] || exit1 "refusing to redirect: unknown target phone number +$targetphone."
- targetphones="${targetphones:+$targetphones }\+$targetphone"
- shift
- done
- # send responses (threaded one last, to work in debug mode)
- if [ -n "$*" ]; then
- for phone in $phones; do
- $sbindir/localsendsms "$phone" "[$cmd] $@"
- done
- $sbindir/localsendsms "$to" "[info] \"$cmd\" thread started for $targetphones and trailing message forwarded to subscribers."
- else
- $sbindir/localsendsms "$to" "[info] \"$cmd\" thread started for $targetphones (no trailing message passed to subscribers)."
- fi
- for phone in $targetphones; do
- SMS_PHONE=$(lastservicephone "$phone") $sbindir/localmarkdown2sms "$phone" "$realcmd"
- done
- exit 0
- ;;
- esac
- candidates=$(cd "$vardir/user" && grep -lF "$to" */phone | perl -pe "s,/phone$,,") || candidates=
- [ -z "$candidates" ] || $(grep -vqF "$candidates" "$vardir/group/admin/user") || admin=true
- if [ -n "$ADMIN_OK" ] && [ -n "$admin" ]; then
- str="$($sbindir/localsmsadmin "$cmd" "$@" 2>&1)" || exit1 "$str"
- $sbindir/localsendsms "$to" $str
- exit 0
- elif [ "help" = "$cmd" ]; then
- $sbindir/localsendsms "$to" "Commands:
- /ping [...]
- /COMMAND help
- /help
- try e.g. \"/del help\"."
- exit 0
- fi
- ;;
- esac
- #FIXME: if sender has a mission, check for "done": process missionpending and report result to mission members
- # yb)
- # s="$(links -dump "http://www.yubnub.org/parser/parse?command=$@")"
- # $sbindir/localsendsms "$to" "$s"
- # exit 0
- # ;;
- # Bail out if another thread already active targeted same user
- if pgrep -f "$(grepescape "$to")"; then
- for errorto in $SMS_ERRTO1 $SMS_ERRTO2; do
- SMS_PHONE="$SMS_ERRFROM" $sbindir/localsendsms "$errorto" "[warning] silently suppressed \"$app_raw\" for $to busy already"
- done
- exit 0
- fi
- if [ -d /etc/local/sms.d ]; then
- run-parts --exit-on-error --arg="$from" --arg="$to" --arg="$app" --arg="$*" /etc/local/sms.d || exit 0
- fi
- $sbindir/localmarkdown2sms "$to" "$app_raw" "$@"
|