summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xlocalkannel-dispatch168
-rwxr-xr-xlocalmarkdown2sms12
-rwxr-xr-xlocalsendsms10
-rwxr-xr-xlocalshowkannelsms2
-rwxr-xr-xlocalsmsadmin323
5 files changed, 421 insertions, 94 deletions
diff --git a/localkannel-dispatch b/localkannel-dispatch
index ac2aae4..f1fcf5f 100755
--- a/localkannel-dispatch
+++ b/localkannel-dispatch
@@ -2,9 +2,20 @@
set -e
-exit1() {
- echo >&2 "Error: $1"
- echo >&2 "Exiting..."
+vardir=/var/lib/kannel/hello
+sbindir=/usr/local/sbin
+
+exit0() {
+ [ -n "$1" ] && echo "$1"
+ exit 0
+}
+exit1() {
+ [ -z "$1" ] || echo "Error: $1" || echo "Internal error!"
+ 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
}
@@ -25,8 +36,8 @@ uriunescape() {
from=`uriunescape "$1"`; shift
#to=`uriunescape "$1" | sed -e 's/\+/ /g'`; shift
to=`uriunescape "$1"`; shift
-#set -- `uriunescape "$@" | sed -e 's/\+/ /g'`
-set -- `uriunescape "$@"`
+set -- `uriunescape "$@" | sed -e 's/\+/ /g'`
+#set -- `uriunescape "$@"`
app_raw="$1"
app=`simpleword "$1"`; shift
@@ -37,6 +48,11 @@ urldecode=0
export SMS_PHONE urldecode
case "$SMS_REALM" in
+ test)
+ provider="dummy"
+ mdpath="/home/hearth/public_webdata/hearth/content/sms"
+ export mdpath
+ ;;
hello)
provider="local"
# provider="coolsms"
@@ -50,10 +66,15 @@ case "$SMS_REALM" in
export mdpath
;;
*)
- exit1 "unknown realm \"$SMS_REALM\""
+ exit1 "unknown realm \"$SMS_REALM\"!"
;;
esac
case "$provider" in
+ dummy)
+ dummy=1
+ ADMIN_OK=1
+ export ADMIN_OK dummy
+ ;;
local)
export SMS_SMSC
;;
@@ -79,101 +100,66 @@ case "$provider" in
SMS_SMSC="X"
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"
- export SMS_SMSC SMS_DLR_MASK SMS_DLR_URL
+ SMS_VALIDITY="1"
+ stripprefix="1"
+ export SMS_SMSC SMS_DLR_MASK SMS_DLR_URL SMS_VALIDITY stripprefix
+ ;;
+ routo)
+ SMS_SMSC="Y"
+ export SMS_SMSC
;;
*)
- exit1 "unknown provider \"$provider\""
+ exit1 "unknown provider \"$provider\"!"
;;
esac
-# by now sms connection should work, so let sender get errors too
-exit1() {
- echo >&2 "Error: $1"
- /usr/local/sbin/localsendsms "$to" "Error: $1"
- echo >&2 "Exiting..."
- exit 1
-}
-
-return1() {
- echo >&2 "Error: $1"
- echo "$1"
- exit 1
-}
-
-vardir="/var/lib/kannel/hello"
-findobjects() {
- set -e
- object="$1"; shift || return1 "Internal error in routine \"findobjects\" (empty object)!"
- limit="$@"
- regex="$(echo "$limit" | perl -ne '/^\/(.+)\/$/ and print $1')"
- args="$(echo "$limit" | perl -ne 's/.*?([a-z0-9]+).*?/ $1/g and print')"
- [ -d "$vardir/$object" ] || return
- if [ -z "$*" ]; then
- cd "$vardir/$object" && find * -maxdepth 1 -type d
- elif [ -n "$regex" ]; then
- cd "$vardir/$object" && find * -maxdepth 1 -type d -regex "$regex"
- elif [ -n $args ]; then
- cd "$vardir/$object" && ls -1d $args
- else
- return1 "Internal error in routine \"findobjects\" (illegal limit)!"
- fi
-}
-addobject() {
- set -e
- object="$1"
- name="$2"
- oldname="$(findobjects "$object" "$name")" || return1 "$oldname"
- [ -z "$oldname" ] || return1 "$object \"$name\" already exist."
- [ -n "$name" ] || return1 "Internal error in routine \"addobject\" (empty name)!"
- mkdir -p "$vardir/$object/$name"
- chgrp --reference="$vardir" "$vardir/$object/$name"
- echo "$name"
-}
-
+if [ -n "$REDIRECT_OK" ]; then
case "$app" in
@*)
- [ -n "$REDIRECT_OK" ] || exit1 "Redirection not permitted here!"
to="$(echo "$app" | perl -pe 's/^@//;' -e 's/^([^+])/+45\1/')"
# TODO: silence errors - or better: bounce those back to original sender
- /usr/local/sbin/localmarkdown2sms "$to" "$@"
- ;;
-# !*)
-# [ -n "$GROUP_OK" ] || exit1 "Redirection to group not permitted here!"
-# group="$(echo "$app" | perl -pe 's/^!//;')"
-# for to in $(echo "$group" | perl ...); do
-# /usr/local/sbin/localmarkdown2sms "$to" "$@"
-# done
-# ;;
- /*)
- [ -n "$ADMIN_OK" ] || exit1 "Administrative commands not permitted here!"
- cmd="$(echo "$app" | perl -pe 's/^\///;')"
- case "$cmd" in
- add|create)
- case "$1" in
- user|group)
- object="$1"; shift || exit1 "Internal error while adding object."
- name="$(addobject "$object" "$@")" || exit1 "Failed adding $object${name+: $name}!"
- /usr/local/sbin/localsendsms "$to" "$object \"$name\" added."
- ;;
- *)
- exit1 "Cannot add \"$1\" (try \"add user\" or \"add group\" instead)."
- ;;
- esac
- ;;
- status)
- msg="$(/usr/local/sbin/localshowkannelstatus)"
- /usr/local/sbin/localsendsms "$to" "$msg"
- ;;
- *)
- exit1 "unknown command \"$cmd\""
- ;;
- esac
+ $sbindir/localmarkdown2sms "$to" "$@"
+ exit 0
;;
- yb)
- s="$(links -dump "http://www.yubnub.org/parser/parse?command=$@")"
- /usr/local/sbin/localsendsms "$to" "$s"
+esac
+fi
+
+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=
+ [ -n "$members" ] || exit1 "Message redirected for none: no members resolved in group \"$group\"!"
+ for member in $members; do
+ phone=$(head -n 1 "$vardir/user/$member/phone") || nophone="${nophone+$nophone }$member"
+ [ -z "$phone" ] || $sbindir/localmarkdown2sms "$phone" "$@"
+ done
+ [ -n "$members" ] || exit1 "Message redirected for none: no members resolved in group \"$group\"!"
+ membercount=$(echo "$members" | wc --word)
+ [ -z "$nophone" ] || nophonecount=$(echo "$nophone" | wc --word)
+ [ -z "$nophone" ] || exit1 "Message redirected for $membercount members of group \"$group\", but failed for $nophonecount of them (could not resolve phone number)!"
+ exit0 "Message redirected for $membercount members of group \"$group\"."
;;
- *)
- /usr/local/sbin/localmarkdown2sms "$to" "$app_raw" "$@"
+esac
+fi
+
+case "$app" in
+ /*)
+ 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
+ cmd="$(echo "$app" | perl -pe 's/^\///;')"
+ str="$($sbindir/localsmsadmin "$cmd" "$@" 2>&1)" || exit1 "$str"
+ $sbindir/localsendsms "$to" $str
+ exit 0
+ fi
;;
esac
+
+# yb)
+# s="$(links -dump "http://www.yubnub.org/parser/parse?command=$@")"
+# $sbindir/localsendsms "$to" "$s"
+# exit 0
+# ;;
+
+$sbindir/localmarkdown2sms "$to" "$app_raw" "$@"
diff --git a/localmarkdown2sms b/localmarkdown2sms
index 6843195..cb35ca8 100755
--- a/localmarkdown2sms
+++ b/localmarkdown2sms
@@ -48,6 +48,11 @@ my $sms_msgtag = $ENV{SMS_MSGTAG} || "text";
my $sms_cp = $ENV{SMS_CP} || "utf8";
my $sms_concat = $ENV{SMS_CONCAT};
my $sms_dlr_mask = $ENV{SMS_DLR_MASK};
+my $sms_dlr_url = $ENV{SMS_DLR_URL};
+my $sms_validity = $ENV{SMS_VALIDITY};
+my $sms_req_feat = $ENV{SMS_REQ_FEAT};
+my $sms_binfo = $ENV{SMS_BINFO};
+my $stripprefix = $ENV{stripprefix};
my $path = $ENV{mdpath};
my (%file, %delay, %reply);
@@ -61,7 +66,8 @@ my ($key) = lc (shift @ARGV);
# strip international prefix
# (prefix is optional some places and illegal at other places - forgot where)
-$phone =~ s/\+/ /g;
+$phone =~ s/^\+//g if ($stripprefix);
+$sms_phone =~ s/^\+//g if ($stripprefix);
# strip non-word chars from keyword (and use only first chunk of word chars)
$key =~ s/.*?(\w+).*?/$1/;
@@ -207,6 +213,10 @@ sub sendmsg {
$url .= '&smsc=' . uri_escape($sms_smsc) if ($sms_smsc);
$url .= '&concat=' . uri_escape($sms_concat) if ($sms_concat);
$url .= '&dlr-mask=' . uri_escape($sms_dlr_mask) if ($sms_dlr_mask);
+ $url .= '&dlr-url=' . uri_escape($sms_dlr_url) if ($sms_dlr_url);
+ $url .= '&validity=' . uri_escape($sms_validity) if ($sms_validity);
+ $url .= '&req_feat=' . uri_escape($sms_req_feat) if ($sms_req_feat);
+ $url .= '&binfo=' . uri_escape($sms_binfo) if ($sms_binfo);
$url .= '&' . $sms_msgtag . '=' . uri_escape(transliterate($sms_cp, $msg));
DEBUG "Sending request: $url";
my $response = $ua->request(HTTP::Request->new('GET', $url));
diff --git a/localsendsms b/localsendsms
index ec1468a..0bd22c2 100755
--- a/localsendsms
+++ b/localsendsms
@@ -27,6 +27,10 @@ my $sms_cp = $ENV{SMS_CP} || "utf8";
my $sms_concat = $ENV{SMS_CONCAT};
my $sms_dlr_mask = $ENV{SMS_DLR_MASK};
my $sms_dlr_url = $ENV{SMS_DLR_URL};
+my $sms_validity = $ENV{SMS_VALIDITY};
+my $sms_req_feat = $ENV{SMS_REQ_FEAT};
+my $sms_binfo = $ENV{SMS_BINFO};
+my $stripprefix = $ENV{stripprefix};
# decode data if passed from kannel
if ($urldecode) {
@@ -36,7 +40,8 @@ my ($phone) = shift @ARGV;
# strip international prefix
# (prefix is optional some places and illegal at other places - forgot where)
-#$phone =~ s/\+/ /g;
+$phone =~ s/^\+//g if ($stripprefix);
+$sms_phone =~ s/^\+//g if ($stripprefix);
if ($debug) {
Log::Log4perl->easy_init($DEBUG);
@@ -77,6 +82,9 @@ sub sendmsg {
$url .= '&concat=' . uri_escape($sms_concat) if ($sms_concat);
$url .= '&dlr-mask=' . uri_escape($sms_dlr_mask) if ($sms_dlr_mask);
$url .= '&dlr-url=' . uri_escape($sms_dlr_url) if ($sms_dlr_url);
+ $url .= '&validity=' . uri_escape($sms_validity) if ($sms_validity);
+ $url .= '&req_feat=' . uri_escape($sms_req_feat) if ($sms_req_feat);
+ $url .= '&binfo=' . uri_escape($sms_binfo) if ($sms_binfo);
$url .= '&' . $sms_msgtag . '=' . uri_escape(transliterate($sms_cp, $msg));
DEBUG "Sending request: $url";
my $response = $ua->request(HTTP::Request->new('GET', $url));
diff --git a/localshowkannelsms b/localshowkannelsms
index 437b72b..46c04bd 100755
--- a/localshowkannelsms
+++ b/localshowkannelsms
@@ -17,6 +17,6 @@ lslogfiles() {
}
#lslogfiles | xargs zcat -f | perl -ne '/^(\S+ +\S+) .*Starting to service <(.*)> from <.*> to <\+4530959593>$/ and print "$1 $2\n"; /^\S+ (\S+) .*sendsms sender:<\S+:\+4530959593> .*msg:<(.*?)>?$/ and print " $1 $2\n"; /^(...................)(?<!\d\d\d\d\-\d\d\-\d\d \d\d:\d\d:\d\d)(.*?)>?$/ and print " $1$2\n"'
-lslogfiles | xargs zcat -f | perl -ne '/^(\S+ +\S+) .*Starting to service <(.*)> from <.*> to <\+4530640636>$/ and print "$1 $2\n"; /^\S+ (\S+) .*sendsms sender:<\S+:\+4530959593> .*msg:<(.*?)>?$/ and print " $1 $2\n"; /^(...................)(?<!\d\d\d\d\-\d\d\-\d\d \d\d:\d\d:\d\d)(.*?)>?$/ and print " $1$2\n"'
+lslogfiles | xargs zcat -f | perl -ne '/^(\S+ +\S+) .*Starting to service <(.*)> from <.*> to / and print "$1 $2\n"; /^\S+ (\S+) .*sendsms sender:<\S+:.*msg:<(.*?)>?$/ and print " $1 $2\n"; /^(...................)(?<!\d\d\d\d\-\d\d\-\d\d \d\d:\d\d:\d\d)(.*?)>?$/ and print " $1$2\n"'
exit 0
diff --git a/localsmsadmin b/localsmsadmin
new file mode 100755
index 0000000..054db55
--- /dev/null
+++ b/localsmsadmin
@@ -0,0 +1,323 @@
+#!/bin/sh
+
+set -e
+
+# make data writable both from kannel and designated shell accounts
+umask 0007
+
+vardir=/var/lib/kannel/hello
+sbindir=/usr/local/sbin
+
+exit0() {
+ [ -n "$1" ] && echo "$1"
+ exit 0
+}
+exit1() {
+ [ -z "$1" ] || echo "Error: $1" || echo "Internal error!"
+ response="${1+Error: $1}${-Internal error!}"
+# FIXME: pass error messages via stderr (not stdout)
+# echo >&2 "$response"
+ echo "$response"
+ exit 1
+}
+
+findobjects() {
+ set -e
+ type="$1"; [ -n "$type" ] || return1 "Internal error (findobjects: empty type)!"; shift
+ limit="$@"
+ regex="$(echo "$limit" | perl -ne '/^\/(.+)\/$/ and print $1')"
+ args="$(echo "$limit" | perl -ne 's/.*?([a-z0-9]+).*?/ $1/g and print')"
+ [ -d "$vardir/$type" ] || exit0
+ if [ -z "$*" ]; then
+ cd "$vardir/$type" && find -mindepth 1 -maxdepth 1 -type d -printf '%f\n'
+ elif [ -n "$regex" ]; then
+ cd "$vardir/$type" && find -mindepth 1 -maxdepth 1 -type d -regex "$regex"
+ elif [ -n $args ]; then
+ args_multiline="$(echo "$args" | perl -pe 's/[[:space:]]+/\n/g')"
+ cd "$vardir/$type" && ! find -mindepth 1 -maxdepth 1 -type d -printf '%f\n' \
+ | grep -Fx "$args_multiline" || true
+ else
+ exit1 "Internal error (findobjects: illegal limit)!"
+ fi
+}
+finditems() {
+ set -e
+ type="$1"; [ -n "$type" ] || exit1 "Internal error (finditems: empty type)!"; shift
+ name="$1"; [ -n "$name" ] || exit1 "Internal error (finditems: empty name)!"; shift
+ limit="$@"
+ regex="$(echo "$limit" | perl -ne '/^\/(.+)\/$/ and print $1')"
+ args="$(echo "$limit" | perl -ne 's/.*?([a-z0-9]+).*?/ $1/g and print')"
+ dir="$type/$name"
+ [ -d "$vardir/$dir" ] || exit0
+ if [ -z "$*" ]; then
+ cd "$vardir/$dir" && find -mindepth 1 -maxdepth 1 -type f -printf '%f\n'
+ elif [ -n "$regex" ]; then
+ cd "$vardir/$dir" && find -mindepth 1 -maxdepth 1 -type f -regex "$regex"
+ elif [ -n $args ]; then
+ args_multiline="$(echo "$args" | perl -pe 's/[[:space:]]+/\n/g')"
+ cd "$vardir/$dir" && ! find -mindepth 1 -maxdepth 1 -type f -printf '%f\n' \
+ | grep -Fx "$args_multiline" || true
+ else
+ exit1 "Internal error (finditems: illegal limit)!"
+ fi
+}
+getitem() {
+ set -e
+ type="$1"; [ -n "$type" ] || exit1 "Internal error (getitem: empty type)!"; shift
+ name="$1"; [ -n "$name" ] || exit1 "Internal error (getitem: empty name)!"; shift
+ item="$1"; [ -n "$item" ] || exit1 "Internal error (getitem: empty item)!"; shift
+ file="$type/$name/$item"
+ [ ! -s "$vardir/$file" ] || cat "$vardir/$file"
+}
+additem() {
+ set -e
+ type="$1"; [ -n "$type" ] || exit1 "Internal error (additem: empty type)!"; shift
+ name="$1"; [ -n "$name" ] || exit1 "Internal error (additem: empty name)!"; shift
+ item="$1"; [ -n "$item" ] || exit1 "Internal error (additem: empty item)!"; shift
+ data="$*"; [ -n "$data" ] || exit1 "Internal error (additem: empty data)!"; shift
+ data="$(echo "$data" | perl -0 -pe 's/\s+/ /g; s/^\s+//; s/\s+$//')"
+ truename="$(findobjects "$type" "$name")" || exit1 "$truename"
+ [ -n "$truename" ] || exit1 "No $type named \"$name\"!"
+ file="$type/$truename/$item"
+# [ ! -s "$vardir/$file" ] || linecount="$(grep -c . "$vardir/$file")"
+# echo "$data" >> "$vardir/$file"
+# chgrp --reference="$vardir" "$vardir/$file"
+# echo "$data${linecount+ (on top of $linecount other values)}"
+ [ ! -s "$vardir/$file" ] || linecount="$(grep -c . "$vardir/$file")"
+ echo "$data" > "$vardir/$file"
+# chgrp --reference="$vardir" "$vardir/$file"
+ echo "$data"
+}
+addobject() {
+ set -e
+ type="$1"; [ -n "$type" ] || exit1 "Internal error (addobject: empty type)!"; shift
+ name="$1"; [ -n "$name" ] || exit1 "Internal error (addobject: empty name)!"; shift
+ fallback="$1"; [ -n "$fallback" ] || exit1 "Internal error (addobject: empty fallback)!"; shift
+ [ -z "$*" ] || exit1 "Internal error (addobject: too many options)!"
+ case "$fallback" in
+ keep|replace|fail) :;;
+ *) exit1 "Internal error (addobject: unknown fallback)!";;
+ esac
+
+# if [ -e "$vardir/$type/$name" ]; then
+ oldname="$(findobjects "$type" "$name")" || exit1 "$oldname"
+ if [ -n "$oldname" ]; then
+ case "$fallback" in
+ keep)
+ action="kept"
+ ;;
+ replace)
+ delopbject "$type" "$oldname"
+ ;;
+# TODO rename)
+# TODO renameopbject "$type" "$oldname"
+# TODO ;;
+ fail)
+ exit1 "Adding $type failed ($name already exists)!"
+ ;;
+ esac
+ else
+ mkdir -p "$vardir/$type/$name"
+# chgrp -R --reference="$vardir" "$vardir/$type"
+ fi
+}
+
+cmd="$1"; shift
+case "$cmd" in
+ add|create)
+ type="$1"; [ -n "$type" ] || exit1 "Internal error (empty type)!"; shift
+ name="$1"; [ -n "$name" ] || exit1 "Internal error (empty name)!"; shift
+ oldname="$(findobjects "$type" "$name")" || exit1 "$oldname"
+
+ case "$type" in
+ default)
+ case "$name" in
+ session|prefix)
+ item="$name"
+ data="$1"
+ ;;
+ *)
+ exit1 "unknown default \"$1\""
+ ;;
+ esac
+ str=$(addobject "$type" "$name" keep) || exit1 "$str"
+ str=$(additem "$type" "$name" "$item" "$data") || exit1 "$str"
+ response="Added $type $name $data"
+ ;;
+ user)
+ session="$(getitem "default" "session" "session")" || exit1 "Internal error: $session"
+ [ -z "$session" ] || session_group="$(getitem "session" "$session" "group")" || exit1 "Internal error: $session_group"
+ plural=
+ for chunk in $@; do
+ case $chunk in
+ +[[:digit:]]*)
+ [ -z "$phone" ] || exit1 "Too many phone numbers (use only a single number, e.g. 40843136 or +4540843136)!"
+ phone="$chunk"
+ ;;
+ [[:digit:]][[:digit:]][[:digit:]][[:digit:]]*)
+ [ -z "$phone" ] || exit1 "Too many phone numbers (use only a single number, e.g. 40843136 or +4540843136)!"
+ [ -z "$session" ] || prefix="$(getitem "session" "$session" "prefix")" || exit1 "Internal error: $prefix"
+ [ -n "$prefix" ] || exit1 "Missing prefix (use international phone numbering, e.g. +4540843136${session+, or add default prefix to session $session})!"
+ # TODO: optionally validate $phone_min and $phone_max
+ phone="$prefix$chunk"
+ ;;
+ [[:alpha:]][[:alnum:]]*)
+ [ -z "$groups" ] || plural=true
+ groups="${groups+$groups }$chunk"
+ ;;
+ *)
+ exit1 "Internal error (unknown user item \"$1\")!"
+ ;;
+ esac
+ done
+ response="Added $type $name"
+ fallback=fail
+ if [ -z "$oldname" ]; then
+ [ -n "$phone" ] || exit1 "Missing phone number (required)!"
+ else
+ [ -n "$phone$groups" ] || exit1 "No items to update (include one or more of phone number and groups)!"
+ fallback=keep
+ response="Updated $type $name"
+ fi
+ str=$(addobject "$type" "$name" "$fallback") || exit1 "$str"
+ [ -z "$phone" ] || dummy="$(additem "$type" "$name" "phone" "$phone")"
+# TODO: distinguish session group from included ones (i.e. mention explicitly if added)
+ [ -z "$session_group" ] || groups="$session_group $groups"
+ for group in $groups; do
+# TODO: strip existing, duplicate and session groups, and mention stripping in response
+ dummy="$(additem "$type" "$name" "group" "$group")"
+ done
+ if [ -n "$phone" ]; then
+ if [ -n "$groups" ]; then
+ response="$response with phone $phone and group${plural+s} $groups"
+ else
+ response="$response with phone $phone"
+ fi
+ elif [ -n "$groups" ]; then
+ response="$response with group${plural+s} $groups"
+ fi
+ ;;
+ group)
+ for chunk in $@; do
+ case $chunk in
+ [[:alpha:]][[:alnum:]]*)
+ [ -z "$session" ] || exit1 "Too many sessions (a group can be only in a single session)!"
+ session="$chunk"
+ ;;
+ *)
+ exit1 "Internal error (unknown group item \"$1\")!"
+ ;;
+ esac
+ done
+ response="Added $type $name"
+ fallback=fail
+ if [ -n "$oldname" ]; then
+ [ -n "$session" ] || exit1 "Group already exists (and no session name to update was included)!"
+ fallback=keep
+ response="Updated $type $name"
+ fi
+ str=$(addobject "$type" "$name" "$fallback") || exit1 "$str"
+ [ -z "$session" ] || dummy="$(additem "$type" "$name" "session" "$session")"
+ [ -z "$session" ] || response="$response with session $session"
+ ;;
+ session)
+ for chunk in $@; do
+ case $chunk in
+ +[[:digit:]]*)
+ [ -z "$prefix" ] || exit1 "Too many country prefixes (use only one, e.g. +45)!"
+ prefix="$chunk"
+ ;;
+ [[:alpha:]][[:alnum:]]*)
+ [ -z "$group" ] || exit1 "Too many default groups (use only one)!"
+# FIXME: fail if group does not exist
+ group="$chunk"
+ ;;
+ *)
+ exit1 "Internal error (unknown session item \"$1\")!"
+ ;;
+ esac
+ done
+# TODO: distinguish default prefix from included one (i.e. mention explicitly if added)
+ [ -n "$prefix" ] || prefix="$(getitem "default" "prefix" "prefix")" || exit1 "Internal error: $prefix"
+ response="Added $type $name"
+ fallback=fail
+ if [ -n "$oldname" ]; then
+ [ -n "$prefix$group" ] || exit1 "Session already exists (and no default group or country prefix to add/update was included)!"
+ fallback=keep
+ response="Updated $type $name"
+ fi
+ str=$(addobject "$type" "$name" "$fallback") || exit1 "$str"
+ [ -z "$prefix" ] || dummy="$(additem "$type" "$name" "prefix" "$prefix")"
+ [ -z "$group" ] || dummy="$(additem "$type" "$name" "group" "$group")"
+ if [ -n "$prefix" ]; then
+ if [ -n "$group" ]; then
+ response="$response with default country prefix $prefix and default group $group"
+ else
+ response="$response with default country prefix $prefix"
+ fi
+ elif [ -n "$group" ]; then
+ response="$response with default group $group"
+ fi
+ ;;
+ *)
+ exit1 "Cannot add \"$1\" (try \"/help\" to see supported commands)!"
+ ;;
+ esac
+ exit0 "$response"
+ ;;
+ del|delete|remove)
+ case "$1" in
+ default|user|group|session)
+ type="$1"; shift
+ name="$1"; [ -n "$name" ] || exit1 "Internal error (empty name)!"; shift
+ [ -z "$*" ] || exit1 "Internal error (too many options)!"
+ oldname="$(findobjects "$type" "$name")" || exit1 "Internal error${oldname+: $oldname}"
+ [ -n "$oldname" ] || exit1 "No $type named \"$name\"!"
+ items="$(finditems "$type" "$name")" || exit1 "Internal error${items+: $items}"
+# TODO: find user by phone number
+ for item in $items; do
+ rm "$vardir/$type/$name/$item" || exit1 "Internal error during $type $name item removal!"
+ done
+# FIXME: remove items of other objects referencing this object
+ rmdir "$vardir/$type/$name" || exit1 "Internal error during $type $name object removal!"
+ exit0 "Deleted $type: $name."
+ ;;
+ *)
+ exit1 "Cannot delete \"$1\" (try \"/help\" to see supported commands)!"
+ ;;
+ esac
+ ;;
+ list|show|view)
+ case "$1" in
+ default|user|group|session)
+ type="$1"; shift
+ response="$(listobject "$type" "$@")" || exit1 "Failed listing $type${response+: $response}"
+ exit0 "Listing $type: $response."
+ ;;
+ *)
+ exit1 "Cannot list \"$1\" (try \"/help\" to see supported commands)!"
+ ;;
+ esac
+ ;;
+ help)
+ cat <<EOF
+Admin commands:
+/add user NICK [+PREFIX]NUMBER [GROUP ...]
+/add group GROUP [USER ...]
+/add session SESSION [PREFIX] [GROUP]
+/add default prefix|session VALUE
+/del user NICK|NUMBER
+/del group GROUP
+/del session SESSION
+/del default prefix|session
+EOF
+ exit 0
+ ;;
+ status)
+ response="$($sbindir/localshowkannelstatus)"
+ exit0 "$response"
+ ;;
+ *)
+ exit1 "unknown command \"$cmd\"!"
+ ;;
+esac