diff -r 3be96a4c8c18 -r f29abea29121 asterisk/wakeup.agi --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/asterisk/wakeup.agi Mon Apr 27 12:19:05 2009 +0200 @@ -0,0 +1,733 @@ +#! @l_prefix@/bin/perl +# +# wakeup.agi 1.1 +# +# A wakeup agi script for Asterisk +# +# Copyright (C) 2007 +# +# Jonas Arndt +# +# This program is free software, distributed under the terms of the +# GNU General Public License v2. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +use strict; +use Time::Local; +$|=1; +# Setup some variables +my %AGI; my $DEBUG=0; +# Some constants +my $OUTDIR="@l_prefix@/var/asterisk/spool/outgoing"; +my $WAKEDIR="@l_prefix@/var/asterisk/spool/tmp"; +my $debugfile="@l_prefix@/var/asterisk/spool/tmp/wakeup.log"; +my $DEBUGOUT = "filehandle"; +my $CALL = "filehandle"; +my $TOUCH = "/usr/bin/touch"; + +############ check_result ########## +# Use this to check the result of # +# a sent command # +# I pretty much stole this from # +# the regular agi-test.agi # +#################################### +sub checkresult { + my ($res) = @_; + my $retval; + chomp $res; + if ($res =~ /^200/) { + $res =~ /result=(-?\d+)/; + if (!length($1)) { + print DEBUGOUT "FAIL ($res)\n"; + exit(1); + } elsif ($DEBUG=1) { + print DEBUGOUT "PASS ($1)\n"; + } + } else { + print STDERR "FAIL (unexpected result '$res')\n"; + exit(1); + } +} + + +############ send_file ############# +# Use this to send a wave file on # +# the channel # +# # +#################################### +sub send_file { + my ($myfile) = @_; + chomp($myfile); + if ($DEBUG == 1 ) { + print DEBUGOUT "Sending stream $myfile \n"; + } + print "STREAM FILE $myfile \"0123456789\"\n"; + my $result = ; + &checkresult($result); + $result =~ /result=(-?\d+)/; + return $1; +} + +############ hangup ############### +# Use this to hand up a channel # +# the channel # +# # +#################################### +sub hangup { + if ($DEBUG == 1 ) { + print DEBUGOUT "Hanging up \n"; + } + print "HANGUP \"\" \n"; + my $result = ; + &checkresult($result); +} + +############ say_number ############ +# Use this to say a number # +# over the channel # +# # +#################################### +sub say_number { + my ($mynumber) = @_; + chomp($mynumber); + if ($DEBUG == 1 ) { + print DEBUGOUT "Saying number $mynumber \n"; + } + print "SAY NUMBER $mynumber \"0123456789\"\n"; + my $result = ; + &checkresult($result); + $result =~ /result=(-?\d+)/; + return $1; +} + +############ say_digits ############ +# Use this to say a digits # +# over the channel # +# # +#################################### +sub say_digits { + my ($mynumber) = @_; + chomp($mynumber); + if ($DEBUG == 1 ) { + print DEBUGOUT "Saying digits $mynumber \n"; + } + print "SAY DIGITS $mynumber \"0123456789\"\n"; + my $result = ; + &checkresult($result); +} + +############ get_choice ############ +# Use this to receive a DTMF # +# choice from the channel # +# # +#################################### +sub get_choice { + if ($DEBUG == 1 ) { + print DEBUGOUT "Getting choice \n"; + } + print "WAIT FOR DIGIT 15000\n"; + my $result = ; + &checkresult($result); + $result =~ /result=(-?\d+)/; + return $1; +} + +############ answer ############### +# Anser the channel # +# # +#################################### +sub answer { + if ($DEBUG == 1 ) { + print DEBUGOUT "Answering the channel \n"; + } + print "ANSWER\n"; + my $result = ; + &checkresult($result); + $result =~ /result=(-?\d+)/; + return $1; +} + +######## get_data ################## +# Feed with (file, maxnumbers) # +# where file is the sound file # +# to be played and maxnumbers is # +# the maximum amount of digits to # +# allow in the answer # +#################################### +sub get_data { + my @mydata = @_; + my $myfile = $mydata[0]; + my $mymax = $mydata[1]; + if ($DEBUG == 1 ) { + print DEBUGOUT "Getting data \n"; + } + print "GET DATA $myfile 15000 $mymax \n"; + my $result = ; + &checkresult($result); + $result =~ /result=(-?\d+)/; + return $1; +} + +###### check_outstanding_calls ##### +# Are there any outstanding wakeup # +# calls for this extensions? # +# Pass the extension to the # +# function. The function returns # +# a list of files # +#################################### +sub check_outstanding_calls { + my $myext = @_; + #opendir DIR, $WAKEDIR; + opendir DIR, $OUTDIR; + my @files = grep {/$myext/} readdir(DIR); + closedir DIR; + return @files; +} + +######## get_extension ############# +# Receive the AIG variable and # +# return the extension # +#################################### +sub get_extension { + my (@aig) = @_; + if ($aig[11] == '') { + print STDERR "No extension found in function get_exension \n"; + return "FAIL"; + } + my $myext = $aig[11]; + return $myext; +} + +######## get_context ############### +# Receive the AIG variable and # +# return the context # +#################################### +sub get_context { + my (@aig) = @_; + if ($aig[8] == '') { + print STDERR "No extension found in function get_exension \n"; + return "FAIL"; + } + my $mycont = $aig[8]; + return $mycont; +} + +########### get_clid ############### +# Receive the AIG variable and # +# return the clid # +#################################### +sub get_clid { + my (@aig) = @_; + if ($aig[1] == '') { + print STDERR "No clid found in function get_clid \n"; + return "FAIL"; + } + my $myext = $aig[1]; + return $myext; +} +########### init_agi ############### +# Use this to initialize the AGI # +# variable # +# # +#################################### +sub init_agi { + while() { + chomp; + last unless length($_); + if (/^agi_(\w+)\:\s+(.*)$/) { + $AGI{$1} = $2; + } + } +} + +############ ascii2num ############# +# Removes 48 to get a number out # +# of the asciss return # +#################################### +sub ascii2num { + my ($asc) = @_; + my $ret; + $ret = $asc - 48; + return $ret; +} + + +########### Welcome ############### +# This is the welcome menu # +# # +#################################### +sub welcome { + my $ret = 0; + $ret = &send_file("welcome"); + if ($ret == 0) { + $ret = &send_file("for-wakeup-call"); + } + if ($ret == 0) { + $ret = &send_file("press-1"); + } + if ($ret == 0) { + $ret = &send_file("for-a-list-of"); + } + if ($ret == 0) { + $ret = &send_file("or"); + } + if ($ret == 0) { + $ret = &send_file("to-cancel-wakeup"); + } + if ($ret != 0) { + $ret = &ascii2num($ret); + } + if ($ret == 0) { + $ret = &get_data("press-2",1); + } + if ($ret == 1) { + $ret = &schedule_new(); + } elsif ($ret == 2) { + &manage_calls(); + } else { + $ret = &send_file("goodbye"); + } +} + +######### manage_calls ############# +# This is what is called if you # +# want to manage already scheduled # +# wakeup calls # +#################################### + +sub manage_calls { + my $checker = "false"; + my @calls; + my $del; + #my $ret; + my $hours; + my $minutes; + # Send out a welcome message and ask for return + @calls = &check_outstanding_calls($AGI{callerid}); + if ($#calls + 1 == 0) { + $del = &send_file("not-rqsted-wakeup"); + $del = &send_file("goodbye"); + } else { + foreach (@calls) { + $del = 0; + my $wakefile = $_; + my @wakeup = split /\./, $_; + my $time = $wakeup[0]; + $_ = $time; + /(^[0-9][0-9])/; + my $hours = $1; + /^[0-9][0-9]([0-9][0-9])/; + my $minutes = $1; + $del = &send_file("rqsted-wakeup-for"); + if ($del == 0) { + $del = &say_number($hours); + } + if ($del == 0) { + if ($minutes >= 10 ) { + $del = &say_number($minutes); + } elsif ($minutes > 0 && $minutes < 10) { + $del = &send_file("digits/oh"); + $del = &say_number($minutes); + } + } + if ($del == 0) { + $del = &send_file("digits/oclock"); + } + if ($del == 0) { + $del = &send_file("to-cancel-wakeup"); + } + if ($del == 0) { + $del = &send_file("press-1"); + } + if ($del == 0) { + $del = &send_file("otherwise-press"); + } + if ($del != 0) { + $del = &ascii2num($del); + } + if ($del == 0) { + $del = &get_data("digits/2",1); + } + if ($del == 1) { + my @sysargs = ("rm", "-f", "$WAKEDIR/$wakefile", "$OUTDIR/$wakefile"); + system(@sysargs) == 0 + or die "system @sysargs failed: $?"; + $del = &send_file("cancelled"); + } + } + $del = &send_file("goodbye"); + } + +} + +######## schedule_new ############## +# This is the menu to schedule a # +# a new wakeup call # +#################################### +sub schedule_new { + my $checker = "false"; + my $ret_var; + my $ret_dummy = 0; + my $time; + my $perm; + my $file; + my $calltype; + my $extension; + my $context; + my $hours; + my $minutes; + if ($DEBUG == 1 ) { + print DEBUGOUT "From schedule_new\n"; + } + while ( $checker eq "false" ) { + $ret_var = &send_file("to-rqst-wakeup-call"); + if ($ret_var != 0) { + my $tmp = &get_data("silence/1",3); + $ret_var = &ascii2num($ret_var); + $ret_var = $ret_var . $tmp; + } else { + $ret_var = &get_data("enter-a-time",4); + } +# if ($ret_var < 1300 && $ret_var >= 0100) { +# my $pm = &get_data("1-for-am-2-for-pm",1); +# if ($pm == 2 && $ret_var <= 1159) { +# $ret_var = $ret_var + 1200; +# $checker = "true"; +# } elsif ($pm == 1 && $ret_var > 1159) { +# $ret_var = $ret_var - 1200; +# # Fix the zero +# $ret_var = "00" . $ret_var; +# $checker = "true"; +# } else { +# $checker = "true"; +# } +# } elsif ($ret_var > 2359) { +# $ret_dummy = &send_file("please-try-again"); +# } else { +# $checker = "true"; +# } + if ($ret_var > 2359) { + $ret_dummy = &send_file("please-try-again"); + } else { + $checker = "true"; + } + } + $perm = 0; + $perm = &send_file("wakeup-for-one-time"); + if ($perm == 0) { + $perm = &send_file("press-1"); + } + if ($perm == 0) { + $perm = &send_file("for-a-daily-wakeup-call"); + } + if ($perm != 0) { + $perm = &ascii2num($perm); + } + if ($perm == 0) { + $perm = $perm = &get_data("press-2",1); + } + # Open the file and populate it with data + $extension = $AGI{callerid}; + $context = $AGI{context}; + if ($perm == 2) { + $file = "$WAKEDIR/$ret_var.perm.1.$extension.call"; + $calltype = "perm"; + open (CALL, '>', $file) or die "Cannot open call file for write :$!"; + } else { + $file = "$WAKEDIR/$ret_var.temp.1.$extension.call"; + $calltype = "temp"; + open (CALL, '>', $file) or die "Cannot open call file for write :$!"; + } + my $myprint = "channel: Local" . "/" . $extension . "@" . $context . "\n"; + print CALL $myprint; + print CALL "maxretries: 3\n"; + print CALL "retrytime: 60\n"; + print CALL "waittime: 60\n"; + print CALL "callerid: \"AsterPBX Weckruf\" <$AGI{extension}>\n"; + print CALL "application: AGI\n"; + print CALL "data: wakeup|$ret_var.$calltype.1.$extension.call\n"; + close ($CALL); + # Now touch the file + # Get the time variable + $time = get_time_string($ret_var); + my @command = ("$TOUCH", "-t", "$time", "${file}"); + system(@command) == 0 + or die "system @command failed: $?"; + # Move it to the OUT directory + my @command = ("mv", "${file}", "${OUTDIR}/"); + system(@command) == 0 + or die "system @command failed: $?"; + + # Stream out the wakeup + $_ = $ret_var; + /(^[0-9][0-9])/; + my $hours = $1; + /^[0-9][0-9]([0-9][0-9])/; + my $minutes = $1; + $ret_dummy = &send_file("rqsted-wakeup-for"); + $ret_dummy = &say_number($hours); + if ($minutes >= 10 ) { + &say_number($minutes); + } elsif ($minutes > 0 && $minutes < 10) { + &send_file("digits/oh"); + &say_number($minutes); + } + $ret_dummy = &send_file("digits/oclock"); + $ret_dummy = &send_file("goodbye"); + return $ret_var; +} + +######## get_time_string ########### +# This will return the time string # +# when inputing a string like # +# hhmi # +#################################### +sub get_time_string { + my ($intime) = @_; + my $minutes = substr($intime, 2, 4); + my $hours = substr($intime, 0, 2); + my $tmpepoch; + my $day; + my $month; + my $ret_val; + my $epoch = time(); + my @timedata = localtime($epoch); + # Insert the minutes and hours from input + $timedata[1] = $minutes; + $timedata[2] = $hours; + # Get tmpepoch + $tmpepoch = timelocal(@timedata); + #Now compare them + if ($tmpepoch < $epoch) { # Means it is tomorrow + $tmpepoch += 86400; # Add 24 hours + } + # Now get the new timedata + my @timedata = localtime($tmpepoch); + $minutes = $timedata[1]; + $hours = $timedata[2]; + $day = $timedata[3]; + $month = $timedata[4] + 1; + #Correct the "First hour after midnight" problem + if ($minutes < 10) { + $minutes = "0" . $minutes; + } + if ($hours < 10) { + $hours = "0" . $hours; + } + if ($day < 10) { + $day = "0" . $day; + } + if ($month < 10) { + $month = "0" . $month; + } + $ret_val = $month . $day . $hours . $minutes; + return $ret_val; +} + +############ new_time ############## +# This will return the time string # +# with a time set 10 minute into # +# the future # +# The string is # +# MMDDhhmi # +#################################### +sub new_time { + my ($input) = @_; + my @timedata; + my $minutes; + my $hours; + my $day; + my $month; + my $ret_val; + my $epoc = time(); + if ($input eq "10m") { + # add 10 minutes + $epoc += 600; + #$epoc += 120; #just for debugs + } else { + # add 24 hours + $epoc += 86400; + } + @timedata = localtime($epoc); + $minutes = $timedata[1]; + $hours = $timedata[2]; + $day = $timedata[3]; + $month = $timedata[4] + 1; + #Correct the "First hour after midnight" problem + if ($minutes < 10) { + $minutes = "0" . $minutes; + } + if ($hours < 10) { + $hours = "0" . $hours; + } + if ($day < 10) { + $day = "0" . $day; + } + if ($month < 10) { + $month = "0" . $month; + } + $ret_val = $month . $day . $hours . $minutes; + return $ret_val; +} + +########### snooze ################ +# This is the menu to snooze the # +# wakeup call # +#################################### +sub snooze { + my ($oldfile) = @_; + my $newfile; + my $extension; + my $context; + my @filestore = split (/\./, $oldfile); + my @permstore = split (/\./, $oldfile); + my $time; + my $ret_var = 0; + my $ret_dummy; + my $myprint; + # Answer the channel + &answer(); + # Is this a reoccuring call, then add 24h + if ($permstore[1] eq "perm") { + $permstore[2] += 1; #Just to get a new file name + $newfile = join(".",@permstore); + $extension = $AGI{extension}; + $context = $AGI{context}; + # Open the file + open (CALL, '>', "${WAKEDIR}/${newfile}") or die "Cannot open call file for write :$!"; + $myprint = "channel: Local" . "/" . $extension . "@" . $context . "\n"; + print CALL $myprint; + print CALL "maxretries: 3\n"; + print CALL "retrytime: 60\n"; + print CALL "waittime: 60\n"; + print CALL "callerid: \"AsterPBX Weckruf\" <$AGI{callerid}>\n"; + print CALL "application: AGI\n"; + print CALL "data: wakeup|$newfile\n"; + close ($CALL); + # Get a time 24h from now + $time = &new_time("24h"); + # Touch the file with the new time + my @command = ("$TOUCH", "-t", "$time", "${WAKEDIR}/${newfile}"); + system(@command) == 0 + or die "system @command failed: $?"; + # Now move it + my @command = ("mv", "${WAKEDIR}/${newfile}", "${OUTDIR}/${newfile}"); + system(@command) == 0 + or die "system @command failed: $?"; + } + #Replace the file name time with snooze + $filestore[1] = "snooze"; + # Also add 10 minutes to the name + $time = new_time("10m"); + $filestore[0] = substr($time, 4, 8); + # Get the new file name + $newfile = join(".",@filestore); + $ret_var = &send_file("this-is-yr-wakeup-call"); + if ($ret_var == 0 ) { + $ret_var = &send_file("to-confirm-wakeup"); + } + if ($ret_var == 0 ) { + $ret_var = &send_file("press-1"); + } + if ($ret_var == 0 ) { + $ret_var = &send_file("to-snooze-for"); + } + if ($ret_var == 0 ) { + $ret_var = &send_file("digits/10"); + } + if ($ret_var == 0 ) { + $ret_var = &send_file("minutes"); + } + if ($ret_var != 0 ) { + $ret_var = &ascii2num($ret_var); + } + if ($ret_var == 0 ) { + $ret_var = &get_data("press-2",1); + } + if ($ret_var == 2 ) { + # Populate some variables + $time = &new_time("10m"); + $extension = $AGI{extension}; + $context = $AGI{context}; + # Open the file + open (CALL, '>', "${WAKEDIR}/${newfile}") or die "Cannot open call file for write :$!"; + $myprint = "channel: Local" . "/" . $extension . "@" . $context . "\n"; + print CALL $myprint; + print CALL "maxretries: 3\n"; + print CALL "retrytime: 60\n"; + print CALL "waittime: 60\n"; + print CALL "callerid: \"AsterPBX Weckruf\" <$AGI{callerid}>\n"; + print CALL "application: AGI\n"; + print CALL "data: wakeup|$newfile\n"; + close ($CALL); + # Touch the file with the new time + my @command = ("$TOUCH", "-t", "$time", "${WAKEDIR}/${newfile}"); + system(@command) == 0 + or die "system @command failed: $?"; + # Now move it + my @command = ("mv", "${WAKEDIR}/${newfile}", "${OUTDIR}/${newfile}"); + system(@command) == 0 + or die "system @command failed: $?"; + $ret_dummy = &send_file("goodbye"); + + } elsif ($ret_var == 1) { + $ret_dummy = &send_file("goodbye"); + } else { + $ret_dummy = &send_file("goodbye"); + } + + # Stream out the wakeup + return 0; +} + +########### main program ########### +# Here goes the main program # +# # +#################################### + +my $numargs = $#ARGV + 1; +if ($DEBUG == 1) { + open (DEBUGOUT, '>', $debugfile) or die "Cannot open $debugfile for write :$!"; +} + +# Start by reading in the stuff Asterisk is sending +&init_agi(); # Comment out in case of debug outside Asterisk + +# If DEBUG is set, dump the AGI variable +if ($DEBUG == 1) { + foreach my $i (sort keys %AGI) { + print DEBUGOUT " -- $i = $AGI{$i}\n"; + } +} + +if ( $numargs == 0 ) { + &welcome(); + &hangup(); + exit(0); +} elsif ( $ARGV[0] eq "move" ) { + &move(); + &hangup(); + exit(0); +} else { + &snooze($ARGV[0]); + &hangup(); + exit(0); +} + +if ($DEBUG ==1) { + close $DEBUGOUT; +}