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