summaryrefslogtreecommitdiff
path: root/localkannel-dispatch
blob: 1cb937f5666afe5bc0e22706087f8192f9ee491d (plain)
  1. #!/bin/sh
  2. set -e
  3. vardir=/var/lib/kannel/hello
  4. sbindir=/usr/local/sbin
  5. exit0() {
  6. [ -n "$1" ] && echo "$1"
  7. exit 0
  8. }
  9. exit1() {
  10. response="${1:+Error: }${1:-Internal error!}"
  11. # FIXME: pass error messages via stderr (not stdout)
  12. # echo >&2 "$response"
  13. echo "$response"
  14. [ -z "$SMS_SMSC$SMS_URL" ] || $sbindir/localsendsms "$to" "$response"
  15. exit 1
  16. }
  17. # Based on Text::Unidecode bug#8017: http://rt.cpan.org/Ticket/Display.html?id=8017#txn-322351
  18. lctransliterate() {
  19. echo "$1" | perl -C1 -n \
  20. -e 'use Text::Unidecode;' \
  21. -e 'use Encode 2.12 qw(encode decode _utf8_off);' \
  22. -e 'print lc(decode("GSM0338", encode("GSM0338", $_,' \
  23. -e 'sub {$a=unidecode(chr $_[0]); _utf8_off($a); $a;}' \
  24. -e ')));'
  25. return $res;
  26. }
  27. uriunescape() {
  28. if [ 0 = "$urldecode" ]; then
  29. echo "$@"
  30. else
  31. echo "$@" | perl -e 'use URI::Escape; print lc(uri_unescape(<STDIN>));'
  32. fi
  33. }
  34. # Resolve var from "variable = value" pair in file below /etc/local
  35. getfilevar() {
  36. file="/etc/local/$1"
  37. var="$2"
  38. grep -m1 "^$var" "$file" | awk -F '(= )' '{print $2}'
  39. }
  40. lastservicephone() {
  41. logfile=/var/log/kannel/smsbox.log
  42. tac $logfile $logfile.1 \
  43. | perl -ne "/INFO: Starting to service <.*> from <$1> to <([^<>]*)>/ and print \$1 and exit 0"
  44. }
  45. #from=`uriunescape "$1" | sed -e 's/\+/ /g'`; shift
  46. from=`uriunescape "$1"`; shift
  47. #to=`uriunescape "$1" | sed -e 's/\+/ /g'`; shift
  48. to=`uriunescape "$1"`; shift
  49. # FIXME: avoid stripping ALL plusses
  50. set -- `uriunescape "$@" | sed -e 's/\+/ /g'`
  51. #set -- `uriunescape "$@"`
  52. app_raw="$1"
  53. app=`lctransliterate "$1"`; shift
  54. export debug
  55. SMS_PHONE="$from"
  56. urldecode=0
  57. export SMS_PHONE urldecode
  58. case "$SMS_REALM" in
  59. test)
  60. provider="dummy"
  61. mdpath="/home/hearth/public_webdata/hearth/content/sms"
  62. export mdpath
  63. ;;
  64. hello)
  65. provider="local"
  66. # provider="coolsms"
  67. # provider="clickatell"
  68. mdpath="/home/hearth/public_webdata/hearth/content/sms"
  69. export mdpath
  70. ;;
  71. hellobudapest)
  72. provider="clickatell"
  73. addtestphones="+36307418279" # Jonas
  74. addphones=""
  75. gotestphones="+36307418279" # Jonas
  76. gophones=""
  77. SMS_ERRFROM="+36307418279" # Jonas
  78. SMS_ERRTO1="+36307418279" # Jonas
  79. # SMS_ERRTO2="+36307418241" # Emma
  80. SMS_ERRTO2="+36703782127" # Emma
  81. mdpath="/home/www-hearth/public_webdata/hellobudapest/content/sms"
  82. export SMS_ERRFROM SMS_ERRTO1 SMS_ERRTO2 mdpath
  83. ;;
  84. hellotorino)
  85. provider="clickatell"
  86. gotestphones="+393453915741 +393453805531 +393453801457" # Jonas, Jacob, Vera
  87. gophones="+393407574815 +393407574813 +393381467977 +393478617029" # Alessandra, Vela, Marco, Silvia
  88. SMS_ERRFROM="+393453915741" # Jonas
  89. SMS_ERRTO1="+393453801457" # Vera
  90. SMS_ERRTO2="+393483281187" # Rescue
  91. mdpath="/home/www-hearth/public_webdata/hellotorino/content/sms"
  92. export SMS_ERRFROM SMS_ERRTO1 SMS_ERRTO2 mdpath
  93. ;;
  94. cyber)
  95. provider="local"
  96. mdpath="/home/cyberhus/public_webdata/mdsms/content/sms"
  97. export mdpath
  98. ;;
  99. *)
  100. exit1 "unknown realm \"$SMS_REALM\"!"
  101. ;;
  102. esac
  103. case "$provider" in
  104. dummy)
  105. dummy=1
  106. ADMIN_OK=1
  107. export ADMIN_OK dummy
  108. ;;
  109. local)
  110. export SMS_SMSC
  111. ;;
  112. coolsms)
  113. unset SMS_SMSC
  114. SMS_URL="https://sms.coolsmsc.dk:8081/"
  115. SMS_USER=$(getfilevar coolsms user)
  116. SMS_PW=$(getfilevar coolsms pw)
  117. SMS_CP="cp1252"
  118. SMS_MSGTAG="message"
  119. export SMS_URL SMS_USER SMS_PW SMS_CP SMS_MSGTAG
  120. ;;
  121. # supports concatenation and req_feat (e.g 48: sender ID)
  122. # does not support DLR, and only concatenates max. 3 smses
  123. clickatell)
  124. unset SMS_SMSC
  125. SMS_URL="https://api.clickatell.com/http/sendmsg"
  126. SMS_USER=$(getfilevar clickatell user)
  127. SMS_PW=$(getfilevar clickatell pw)
  128. SMS_CP="iso8859-1"
  129. SMS_USERTAG="user"
  130. SMS_API=$(getfilevar clickatell api)
  131. SMS_CALLBACK="3"
  132. SMS_CONCAT="3"
  133. SMS_ESCALATE="1"
  134. SMS_VALIDITY="1"
  135. SMS_REQ_FEAT="24611" # 1+2+32+8192+16384 = text+8bit+numeric_src+dlr+concat
  136. stripprefix="1"
  137. 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
  138. ;;
  139. # supports DLR
  140. # Kannel clickatell profile supports concatenation but not req_feat
  141. # Kannel generic profile supports req_feat but not concatenation
  142. clickatell_via_kannel)
  143. SMS_SMSC="X"
  144. SMS_CONCATENATION="1"
  145. SMS_DLR_MASK="7"
  146. 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"
  147. SMS_CP="iso8859-1"
  148. SMS_VALIDITY="1"
  149. SMS_BINFO="req_feat=24611&concat=3&escalate=1%validity=1" # 1+2+32+8192+16384 = text+8bit+numeric_src+dlr+concat
  150. stripprefix="1"
  151. export SMS_SMSC SMS_CONCATENATION SMS_DLR_MASK SMS_DLR_URL SMS_CP SMS_VALIDITY SMS_BINFO stripprefix
  152. ;;
  153. routo_via_kannel)
  154. SMS_SMSC="Y"
  155. export SMS_SMSC
  156. ;;
  157. *)
  158. exit1 "unknown provider \"$provider\"!"
  159. ;;
  160. esac
  161. # FIXME: some safety net against abusing this imposter feature
  162. #if [ -n "$REDIRECT_OK" ]; then
  163. case "$app" in
  164. @*)
  165. # FIXME: Avoid hardcoding national prefix
  166. targetphone="$(echo "$app" | perl -pe 's/^@//;' -e 's/^([^+])/+36\1/')"
  167. # TODO: silence errors - or better: bounce those back to original sender
  168. targetfrom=$(lastservicephone "$targetphone")
  169. [ -n "$targetfrom" ] || exit1 "refusing to redirect: unknown target phone number \"$targetphone\"."
  170. SMS_PHONE="$targetfrom" $sbindir/localmarkdown2sms "$targetphone" "$@"
  171. exit 0
  172. ;;
  173. esac
  174. #fi
  175. if [ -n "$GROUP_OK" ]; then
  176. case "$app" in
  177. !*)
  178. group="$(echo "$app" | perl -pe 's/^!//;')"
  179. members=$(cd "$vardir/user" && grep -lF "$group" */group | perl -pe "s,/group$,,") || members=
  180. [ -n "$members" ] || exit1 "Message redirected for none: no members resolved in group \"$group\"!"
  181. for member in $members; do
  182. phone=$(head -n 1 "$vardir/user/$member/phone") || nophone="${nophone+$nophone }$member"
  183. [ -z "$phone" ] || $sbindir/localmarkdown2sms "$phone" "$@"
  184. done
  185. [ -n "$members" ] || exit1 "Message redirected for none: no members resolved in group \"$group\"!"
  186. membercount=$(echo "$members" | wc --word)
  187. [ -z "$nophone" ] || nophonecount=$(echo "$nophone" | wc --word)
  188. [ -z "$nophone" ] || exit1 "Message redirected for $membercount members of group \"$group\", but failed for $nophonecount of them (could not resolve phone number)!"
  189. exit0 "Message redirected for $membercount members of group \"$group\"."
  190. ;;
  191. esac
  192. fi
  193. case "$app" in
  194. /*)
  195. cmd="$(echo "$app" | perl -pe 's/^\///;')"
  196. case "$cmd" in
  197. ping)
  198. if [ "help" = "$1" ]; then
  199. $sbindir/localsendsms "$to" "Usage:
  200. /ping [...]
  201. Respond \"pong\" and echo back any addition input."
  202. exit 0
  203. fi
  204. $sbindir/localsendsms "$to" pong "$@"
  205. exit 0
  206. ;;
  207. add|addtest)
  208. if [ "help" = "$1" ]; then
  209. $sbindir/localsendsms "$to" "Usage:
  210. /add ID PHONE [MSG]...]
  211. Register PHONE as ID,
  212. and (if included) send MSG to subscribers."
  213. exit 0
  214. fi
  215. id="$(echo "$1" | perl -ne '/^(\d\d)$/ and print $1;')"
  216. [ -n "$id" ] || exit1 "wrong or missing id: must be 2 digits."
  217. shift
  218. # FIXME: avoid juggling with leading plus here when no longer stripped from input
  219. # phone="$(echo "$1" | perl -ne 's/^(?=[^+])/+36/;' -e '/^(\+\d\d\d+)$/ and print $1;')"
  220. phone="$(echo "$1" | perl -ne '/^(\d\d\d+)$/ and print $1;')"
  221. [ -n "$phone" ] || exit1 "wrong or missing phone number: must be only digits with leading + and at least 3 digits."
  222. targetfrom=$(lastservicephone "\+$phone")
  223. [ -n "$targetfrom" ] || exit1 "unknown phone +$phone: it must have been used with the system recently."
  224. phone="+$phone"
  225. shift
  226. case "$cmd" in
  227. addtest)
  228. msgphones="$addtestphones"
  229. ;;
  230. add)
  231. msgphones="$addphones"
  232. ;;
  233. esac
  234. str=$($sbindir/localsmsadmin add user "$id" "$phone")
  235. $sbindir/localsendsms "$to" "[info] \"$cmd\": $str."
  236. if [ -n "$*" ]; then
  237. for msgphone in $msgphones; do
  238. $sbindir/localsendsms "$msgphone" "[info] $id $phone $@"
  239. done
  240. $sbindir/localsendsms "$to" "[info] $id $phone added/updated. trailing message forwarded to subscribers."
  241. else
  242. $sbindir/localsendsms "$to" "[info] $id $phone added/updated. (no trailing message passed to subscribers)."
  243. fi
  244. exit 0
  245. ;;
  246. # FIXME: generalize this ugly hacks somehow, and secure against random use
  247. go|gotest|so|sotest)
  248. case "$cmd" in
  249. go*)
  250. basecmd="go"
  251. realcmd="hello"
  252. ;;
  253. so*)
  254. basecmd="so"
  255. realcmd="szia"
  256. ;;
  257. esac
  258. if [ "help" = "$1" ]; then
  259. $sbindir/localsendsms "$to" "Usage:
  260. /$basecmd PHONE... [MSG...]
  261. /${basecmd}test PHONE... [MSG...]
  262. /$basecmd help
  263. Start thread \"$realcmd\" on behalf of each PHONE,
  264. and (if included) send MSG to subscribers."
  265. exit 0
  266. fi
  267. [ -n "$1" ] || exit1 "target phone number missing (try \"/$cmd help\" for usage)"
  268. case "$cmd" in
  269. gotest|sotest)
  270. phones="$gotestphones"
  271. ;;
  272. go|so)
  273. phones="$gophones"
  274. ;;
  275. esac
  276. # FIXME: avoid juggling with leading plus here when no longer stripped from input
  277. # FIXME: make country code optional again when plus no longer stripped from input
  278. # FIXME: Avoid hardcoding national prefix
  279. while [ -n "$1" ]; do
  280. # targetphone="$(echo "$1" | perl -ne 's/^(?=[^+])/+36/;' -e '/^(\+\d\d\d+)$/ and print $1;')"
  281. targetphone="$(echo "$1" | perl -ne '/^(\d\d\d+)$/ and print $1;')"
  282. [ -n "$targetphone" ] || continue
  283. # Sanity check
  284. targetfrom=$(lastservicephone "\+$targetphone")
  285. [ -n "$targetfrom" ] || exit1 "refusing to redirect: unknown target phone number +$targetphone."
  286. targetphones="${targetphones:+$targetphones }\+$targetphone"
  287. shift
  288. done
  289. # send responses (threaded one last, to work in debug mode)
  290. if [ -n "$*" ]; then
  291. for phone in $phones; do
  292. $sbindir/localsendsms "$phone" "[$cmd] $@"
  293. done
  294. $sbindir/localsendsms "$to" "[info] \"$cmd\" thread started for $targetphones and trailing message forwarded to subscribers."
  295. else
  296. $sbindir/localsendsms "$to" "[info] \"$cmd\" thread started for $targetphones (no trailing message passed to subscribers)."
  297. fi
  298. for phone in $targetphones; do
  299. SMS_PHONE=$(lastservicephone "$phone") $sbindir/localmarkdown2sms "$phone" "$realcmd"
  300. done
  301. exit 0
  302. ;;
  303. esac
  304. candidates=$(cd "$vardir/user" && grep -lF "$to" */phone | perl -pe "s,/phone$,,") || candidates=
  305. [ -z "$candidates" ] || $(grep -vqF "$candidates" "$vardir/group/admin/user") || admin=true
  306. if [ -n "$ADMIN_OK" ] && [ -n "$admin" ]; then
  307. str="$($sbindir/localsmsadmin "$cmd" "$@" 2>&1)" || exit1 "$str"
  308. $sbindir/localsendsms "$to" $str
  309. exit 0
  310. elif [ "help" = "$cmd" ]; then
  311. $sbindir/localsendsms "$to" "Commands:
  312. /ping [...]
  313. /COMMAND help
  314. /help
  315. try e.g. \"/del help\"."
  316. exit 0
  317. fi
  318. ;;
  319. esac
  320. #FIXME: if sender has a mission, check for "done": process missionpending and report result to mission members
  321. # yb)
  322. # s="$(links -dump "http://www.yubnub.org/parser/parse?command=$@")"
  323. # $sbindir/localsendsms "$to" "$s"
  324. # exit 0
  325. # ;;
  326. # Bail out if another thread already active targeted same user
  327. # FIXME: avoid juggling with leading plus here when no longer stripped from input
  328. if pgrep -f "$to"; then
  329. for errorto in $SMS_ERRTO1 $SMS_ERRTO2; do
  330. SMS_PHONE="$SMS_ERRFROM" $sbindir/localsendsms "$errorto" "[warning] silently suppressed \"$app_raw\" for $to busy already"
  331. done
  332. exit 0
  333. fi
  334. $sbindir/localmarkdown2sms "$to" "$app_raw" "$@"