1#!/usr/bin/vm shell 2# Robert J�rdens <rjo@gmx.de> 3# 4# This is the dtmf script. It is called by vgetty when a dtmf code was send by 5# the user. 6# 7# $1 - received DTMF code 8# 9# $2 - name of the recorded voice file or if "-cons_mode", switches on console 10# mode so you can enter the dtmf-codes on your console and will hear all sound 11# going to your soundcard! (you also have to toogle the magic line at the 12# beginning!) 13# 14 15if [ "1$2" = "1-cons_mode" ]; then 16 CONS_MODE="yes" 17else 18 CONS_MODE="no" 19fi 20 21# 22BASENAME=`basename $0` 23DTMF="$1" 24ALREADY_REC="$2" 25# Some dir's 26VOICE_DIR=/var/spool/voice 27MSG_DIR=$VOICE_DIR/messages 28INC_DIR=$VOICE_DIR/incoming 29# Some files (scripts may have to be written) 30CODE=`cat $VOICE_DIR/.code` 31FLAG=$VOICE_DIR/.flag 32TIMESTAMP=$VOICE_DIR/.timestamp 33CONNECT_SCRIPT=$VOICE_DIR/ppp.sh 34FAX_ACTIVATE_SCRIPT=$VOICE_DIR/fax_activate.sh 35# Sound-Files 36GET_CODE=$MSG_DIR/get-code.rmd 37INCORRECT=$MSG_DIR/incorrect.rmd 38GOODBYE=$MSG_DIR/goodbye.rmd 39NO_NEW_MESSAGES=$MSG_DIR/no_new_messages.rmd 40GIMME_COMM=$MSG_DIR/gimme_comm.rmd 41OKAY_DRIN=$MSG_DIR/okay_drin.rmd 42BYE=$MSG_DIR/bye.rmd 43# The TTY's where to toogle the Scroll-LED 44LEDTTY=/dev/tty[1-8] 45# Tries Code 46MAXTRIES=3 47# Timeout beetween two equal numbers to be recognized as two single. Under 48# TIMEOUT: increment (see dtmf_alph) 49TIMEOUT=2 50# Type of your Modem 51MODEM_TYPE=Rockwell 52# Compression 53COMPRESSION=4 54# Sample Rate needed 55SPEED=7200 56 57 58### BEGIN FUNCTIONS 59 60# Define the function to check for an answer and if it is not the desired it 61# will quit! 62answer () { 63 ANSWER=`receive` 64 if [ "$ANSWER" != "$1" ]; then 65 logger -t "${BASENAME}[$$]" "Got '$ANSWER', expected '$1'. Harakiri" 66 kill -KILL $$ 67 fi 68} 69 70# Define the function to receive an answer from the voice library 71receive () { 72 if [ $CONS_MODE = "no" ]; then 73 read -r INPUT <&$VOICE_INPUT 74 else 75 read -r -p "receive: " INPUT 76 fi 77 echo "$INPUT" 78} 79 80# Define the function to send a command to the voice library 81send () { 82 if [ $CONS_MODE = "no" ]; then 83 echo $1 >&$VOICE_OUTPUT 84 kill -PIPE $VOICE_PID 85 else 86 echo "send: $1" 87 fi 88} 89 90# Define the function send a beep 91beep () { 92 if [ $CONS_MODE = "no" ]; then 93 send "BEEP $1 $2" 94 answer "BEEPING" 95 answer "READY" 96 else 97 echo "beep: $1 $2" 98 fi 99} 100 101# Define the function to play a file 102play () { 103 if [ $CONS_MODE = "no" ]; then 104 send "PLAY $1" 105 answer "PLAYING" 106 answer "READY" 107 else 108 rmdtopvf $1 | pvfspeed -s 8000 | pvftobasic > /dev/audio 109 fi 110 logger -t "${BASENAME}[$$]" "Played $1" 111} 112 113# Define the function to play the new messages 114messages () { 115 if [ ! -f $TIMESTAMP ]; then 116 MSGS=`find $INC_DIR/ -type f -name 'v*.rmd' -print` 117 else 118 MSGS=`find $INC_DIR/ -type f -name 'v*.rmd' -newer $TIMESTAMP -print` 119 if [ -z "$MSGS" ]; then 120 BASENAME=`basename $TIMESTAMP` 121 NEWSTAMP=`find $VOICE_DIR -name $BASENAME -cmin -10 -print` 122 if [ "$NEWSTAMP" = "$TIMESTAMP" ]; then 123 MSGS=`find $INC_DIR -type f -name 'v*.rmd' -print` 124 fi 125 fi 126 fi 127 touch $TIMESTAMP-n 128 if [ -x $VOICE_DIR/speakdate.sh ]; then 129 TIME=yes 130 else 131 TIME=no 132 fi 133 TMPDIR=${TMPDIR-/tmp}/dtmf.$$ 134 mkdir -m 0700 $TMPDIR || exit 1 135 trap "rm -rf $TMPDIR" 0 1 2 3 7 13 15 136 TMP=${TMPDIR}/time.rmd.$$ 137 LOCK=${TMPDIR}/time-lock.$$ 138 for i in $MSGS 139 do 140 if [ $TIME = yes ]; then 141 (touch $LOCK ;\ 142 $VOICE_DIR/speakdate.sh $i $SPEED $MODEM_TYPE $COMPRESSION >$TMP ;\ 143 rm -f $LOCK) & 144 fi 145 beep 1320 100 146 play $i 147 beep 1320 100 148 if [ $TIME = yes ]; then 149 while [ -f $LOCK ] 150 do 151 sleep 1 152 done 153 play $TMP 154 rm -f $TMP 155 fi 156 done 157 if [ -z "$MSGS" ]; then 158 play "$NO_NEW_MESSAGES" 159 fi 160 beep 1320 1000 161 rm -f $FLAG $TIMESTAMP 162 mv $TIMESTAMP-n $TIMESTAMP 163# for tty in $LEDTTY; do 164# setleds -scroll < $tty 165# done 166} 167 168# Define the function to read one dtmf code string terminated by # 169getcode () { 170 if [ $CONS_MODE = "no" ]; then 171 RECEIVED="" 172 send "ENABLE EVENTS" 173 answer "READY" 174 send "WAIT 30" 175 answer "WAITING" 176 ANSWER="" 177 while [ "$ANSWER" != "READY" ] 178 do 179 ANSWER=`receive` 180 if [ "$ANSWER" = "RECEIVED_DTMF" ]; then 181 ANSWER=`receive` 182 if [ "$ANSWER" = "*" ]; then 183 RECEIVED="" 184 else 185 case $ANSWER in 186 "#") 187 send "STOP" 188 ;; 189 0|1|2|3|4|5|6|7|8|9) 190 RECEIVED=$RECEIVED$ANSWER 191 ;; 192 *) 193 logger -t "${BASENAME}[$$]" "Ignoring DTMF $ANSWER" 194 ;; 195 esac 196 fi 197 else 198 if [ "$ANSWER" = "SILENCE_DETECTED" ]; then 199 send "STOP" 200 else 201 if [ "$ANSWER" != "READY" ]; then 202 logger -t "${BASENAME}[$$]" "Ignoring $ANSWER" 203 fi 204 fi 205 fi 206 done 207 send "DISABLE EVENTS" 208 answer "READY" 209 else 210 read -r -p "Code: " RECEIVED 211 fi 212 echo "$RECEIVED" 213 } 214 215# Get a SMS-like String from DTMF's. The Code-Table is not standard!! 216dtmf_alph () { 217 TAB_0=(0 + - '#' '*' , '.' : ';' '?' '!' '|' @ / '\\' '$' % � '~' � � � � �) 218 TAB_1=(" " '"' "'" "(" ")" "[" "]" "{" "}" "<" ">") 219 TAB_2=(a b c 2 �) 220 TAB_3=(d e f 3) 221 TAB_4=(g h i 4) 222 TAB_5=(j k l 5) 223 TAB_6=(m n o 6 �) 224 TAB_7=(p q r s 7 �) 225 TAB_8=(t u v 8 �) 226 TAB_9=(w x y z 9) 227 TAB_r=() 228 TAB_s=() 229 230# stty cbreak </dev/tty >/dev/tty 2>&1 231 232 LAST_TIME=10000000000 233 THIS_TIME="0" 234 LAST_CHAR="" 235 THIS_CHAR="" 236 LAST_NUM="" 237 THIS_NUM="" 238 LIST_CHAR=() 239 LIST_NUM=() 240 REPT=0 241 THIS_TAB="" 242 THIS_POS="" 243 LAST_POS="" 244 ALPH="" 245 CHAR="" 246 247 while true; do 248 THIS_NUM=`getone` 249# THIS_NUM=`perl -e 'print getc(STDIN);'` 250# echo -n " " 251 THIS_TIME=`date +'%s'` 252 LIST_NUM=(${LIST_NUM[@]} $THIS_NUM) 253 case $THIS_NUM in 254 "*") 255 if [ "1$LAST_CHAR" != "1" ]; then 256 eval $LAST_CHAR=\${TAB_${LAST_NUM}[$REPT]} 257 fi 258 if [ "$CAPS" = "yes" ]; then 259 caps="no" 260 else 261 caps="yes" 262 if [ "1$LAST_CHAR" != "1" ]; then 263 LAST_CHAR=`echo "$LAST_CHAR" | tr "[:lower:]" "[:upper:]"` 264 fi 265 fi 266# echo -n "made '$LAST_CHAR' caps: '$CAPS'" 267 continue 268 ;; 269 "#") 270 LIST_CHAR[$LAST_POS]=$LAST_CHAR 271 break 272 ;; 273 0|1|2|3|4|5|6|7|8|9) 274 if [ "$THIS_NUM" != "$LAST_NUM" -o $(($THIS_TIME - $TIMEOUT)) \ 275 -ge $LAST_TIME ]; then 276 LIST_CHAR[$LAST_POS]=$LAST_CHAR 277 LAST_NUM=$THIS_NUM 278 LAST_POS=$THIS_POS 279 THIS_POS=$(($THIS_POS + 1)) 280 REPT=0 281# echo -n "added '$LAST_CHAR'" 282 else 283 eval THIS_TAB=(\${TAB_${THIS_NUM}[@]}) 284 if [ "$REPT" -ge "${#THIS_TAB[@]}" ]; then 285 REPT=0 286 else 287 REPT=$(($REPT + 1)) 288 fi 289# echo -n "incremented to '$REPT'" 290 fi 291 ;; 292 *) 293# echo -n "Invalid: '$THIS_CHAR'" 294 THIS_NUM=$LAST_NUM 295 THIS_CHAR=$LAST_CHAR 296 continue 297 ;; 298 esac 299 eval THIS_CHAR=\${TAB_${THIS_NUM}[$REPT]} 300 if [ "$CAPS" = "yes" ]; then 301 THIS_CHAR=`echo "$THIS_CHAR" | tr "[:lower:]" "[:upper:]"` 302 fi 303 LAST_CHAR=$THIS_CHAR 304 LAST_NUM=$THIS_NUM 305 LAST_TIME=$THIS_TIME 306# echo "--now: list '${LIST_CHAR[@]}' and LAST_CHAR '$LAST_CHAR'" 307 done 308 309# stty -cbreak </dev/tty >/dev/tty 2>&1 310# export LIST_CHAR 311 for CHAR in "${LIST_CHAR[@]}"; do 312# echo -n "$CHAR" 313 ALPH="$ALPH$CHAR" 314 done 315 echo "$ALPH" 316} 317 318# exitvm 319exitvm () { 320 play $GOODBYE 321 if [ $CONS_MODE = "no" ]; then 322 send "GOODBYE" 323 answer "GOODBYE SHELL" 324 else 325 echo "Bye" 326 fi 327 exit 0 328} 329 330# getone 331getone () { 332 if [ $CONS_MODE = "no" ]; then 333 RECEIVED="" 334 send "ENABLE EVENTS" 335 answer "READY" 336 send "WAIT 30" 337 answer "WAITING" 338 ANSWER="" 339 while [ "$ANSWER" != "READY" ] 340 do 341 ANSWER=`receive` 342 if [ "$ANSWER" = "RECEIVED_DTMF" ]; then 343 ANSWER=`receive` 344 send "STOP" 345 RECEIVED=$ANSWER 346 else 347 if [ "$ANSWER" = "SILENCE_DETECTED" ]; then 348 send "STOP" 349 else 350 if [ "$ANSWER" != "READY" ]; then 351 logger -t "${BASENAME}[$$]" "Ignoring $ANSWER" 352 fi 353 fi 354 fi 355 done 356 send "DISABLE EVENTS" 357 answer "READY" 358 else 359 read -r -p "Tone: " RECEIVED 360 fi 361 echo "$RECEIVED" 362 } 363 364# Start the festival Server if necessary 365check_fest () { 366 if ps ax 2>&1 | grep festival_server | grep -v grep >/dev/null; then 367 logger -t "${BASENAME}[$$]" "fesitval_server running" 368 else 369 nohup festival_server 2>&1 >/dev/null & 370 logger -t "${BASENAME}[$$]" "fesitval_server started" 371 sleep 5 372 fi 373} 374 375# Say something 376say () { 377 check_fest 378# I really want vm�shell to be able to play from a pipe! --async 379 if [ "1$1" != "1" ]; then 380 echo "$1" | festival_client --tts_mode fundamental --ttw --otype ulaw | basictopvf | pvfspeed -s $SPEED | pvfamp -A 6 | pvftormd $MODEM_TYPE $COMPRESSION > $MSG_DIR/voice_say.rmd 381 else 382 cat - | festival_client --tts_mode fundamental --ttw --otype ulaw | basictopvf | pvfspeed -s $SPEED | pvfamp -A 6 | pvftormd $MODEM_TYPE $COMPRESSION > $MSG_DIR/voice_say.rmd 383 fi 384 play $MSG_DIR/voice_say.rmd 385 rm -f $MSG_DIR/voice_say.rmd 386} 387 388# Synthesise some Speech for later playing (to save time) 389prep_say () { 390 if [ "1$2" == "1" -o ! -s $MSG_DIR/message_${2-prep_say}.rmd ]; then 391 check_fest 392# I really want vm�shell to be able to play from a pipe! --async 393 echo "$1" | festival_client --tts_mode fundamental --ttw --otype ulaw | basictopvf | pvfspeed -s $SPEED | pvfamp -A 6 | pvftormd $MODEM_TYPE $COMPRESSION > $MSG_DIR/message_${2-prep_say}.rmd & 394 sleep 5 395 fi 396} 397 398# Play prepared voice 399play_say () { 400 play $MSG_DIR/message_${1-prep_say}.rmd 401# Don't remove special generated files -- maybe we need 'em later 402# rm -f $MSG_DIR/message_prep_say.rmd 403} 404 405 406### END FUNCTIONS 407### --MAIN-- 408 409if [ $CONS_MODE = "no" ]; then 410 # Let's see if the voice library is talking to us 411 answer "HELLO SHELL" 412 # Let's answer the message 413 send "HELLO VOICE PROGRAM" 414 answer "READY" 415 # Let's check the code 416fi 417 418TRIES=1 419GOT_CORRECT_CODE=no 420 421while [ $TRIES -le $MAXTRIES ] 422do 423 if [ "$DTMF" = "$CODE" ]; then 424 if [ -f $ALREADY_REC ]; then 425 rm -f $ALREADY_REC 426 fi 427 GOT_CORRECT_CODE=yes 428 break 429 else 430 logger -t "${BASENAME}[$$]" "Incorrect DTMF code on try $TRIES" 431 beep 1320 100 432 play "$INCORRECT" 433 fi 434 if [ $TRIES -lt $MAXTRIES ]; then 435 play "$GET_CODE" 436 beep 1320 100 437 DTMF=`getcode` 438 else 439 play "$BYE" 440 play "$GOODBYE" 441 fi 442 TRIES=`expr $TRIES + 1` 443done 444# 445### 446### We are in!! Lets give the Menu! 447### 448 449if [ "$GOT_CORRECT_CODE" = "yes" ]; then 450 prep_say "hash is menu" "help" 451 452 prep_say "zeero is command mode. Enter your command with the provided table 453 and press hash. Then confirm it with hash. -- One plays your list of 454 messages. If there are no new and you ask again it will give you all. -- 455 Two will connect you to your internet provider in a bout one minute. -- 456 Three will activate faxgetty for the next 30 minutes. -- Four lets you 457 record something from the soundcard and play it. -- Star leaves the menu 458 and will hang up the phone." "menu" 459 460 play "$OKAY_DRIN" 461 while true ; do 462 play_say "help" 463 ANSWER=`getone` 464 case "$ANSWER" in 465 "#") 466 play_say "menu" 467 ;; 468 0) 469 logger -t "${BASENAME}[$$]" "Command mode" 470 say "Command mode" 471 COMMAND=`dtmf_alph` 472 beep 1320 100 473 say "Really __ ${COMMAND} __ ?" 474 ANSWER=`getone` 475 beep 1320 100 476 case "$ANSWER" in 477 "#") 478 logger -t "${BASENAME}[$$]" "Command '$COMMAND'" 479 su - rj -c "${COMMAND}" 2>&1 | say 480 ;; 481 *) 482 say "Aborted" 483 ;; 484 esac 485 ;; 486 1) 487 logger -t "${BASENAME}[$$]" "Playing messages" 488 say "Your list of messages" 489 messages 490 ;; 491 2) 492 logger -t "${BASENAME}[$$]" "Connecting via PPP" 493 say "In a bout 1 minute you will be connected" 494 nohup $CONNECT_SCRIPT >/dev/null 2>&1 & 495 ;; 496 3) 497 logger -t "${BASENAME}[$$]" "Run faxgetty for the next 30 min" 498 say "In a bout 1 minute I will be able to receive faxes" 499 nohup $ACTIVATE_FAX >/dev/null 2>&1 & 500 ;; 501 4) 502 say "Seconds to receive and amplification?" 503 SECS=`getcode` 504 beep 1320 100 505 AMP=`getcode` 506 beep 1320 100 507 dd if=/dev/audio bs=8000 count=$SECS | basictopvf | pvfspeed -s $SPEED | pvfamp -A $AMP | pvftormd $MODEM_TYPE $COMPRESSION > $MSG_DIR/abhorch.rmd 508 beep 1320 100 509 play "$MSG_DIR/abhorch.rmd" 510 beep 1320 100 511# rm -f $MSG_DIR/abhorch.rmd 512 ;; 513 "*") 514 play $BYE 515 beep 1320 100 516 exitvm 517 ;; 518 esac 519 done 520fi 521 522### 523### All right, that's it, leave! 524### 525 526exitvm 527