1 |
#!/usr/bin/perl |
2 |
|
3 |
use strict; |
4 |
use warnings; |
5 |
|
6 |
use Asterisk::AGI; |
7 |
use Time::localtime; |
8 |
use File::Basename; |
9 |
use File::stat; |
10 |
use POSIX qw(strftime); |
11 |
|
12 |
my $TMPDIR="/var/spool/asterisk/tmp"; |
13 |
#my $TMPDIR="/tmp"; |
14 |
my $CALLDIR="/var/spool/asterisk/outgoing"; |
15 |
my $MSGDIR="/tmp"; |
16 |
|
17 |
my $AGI = new Asterisk::AGI; |
18 |
|
19 |
our $callfile; |
20 |
|
21 |
# TODO |
22 |
# Generate a whole new call file, not copy the existing one |
23 |
# Pass the name of the message file (if there is one) as the parameter to wakeconfirm.agi |
24 |
# snooze() needs to work with the generated call file, not that was previously |
25 |
# passed as an argument |
26 |
# Deal with the fact that the hangup handler is called when hanging up after |
27 |
# wakeup call confirmation |
28 |
|
29 |
sub hangup_handler($) |
30 |
{ |
31 |
my ($result) = @_; |
32 |
snooze(2); |
33 |
exit(0); |
34 |
} |
35 |
|
36 |
sub snooze($) |
37 |
{ |
38 |
my ($minutes) = @_; |
39 |
my $time = (split(/\./, $callfile))[0]; |
40 |
my $retrytime = time() + ($minutes * 60); |
41 |
my $newtime = strftime("%H%M", CORE::localtime($retrytime)); |
42 |
my $newcallfile = $callfile; |
43 |
$newcallfile =~ s/^${time}\./${newtime}./; |
44 |
utime($retrytime, $retrytime, $TMPDIR . "/" . $callfile); |
45 |
loggit("Snoozing for $minutes minutes"); |
46 |
loggit("Attempting rename(${TMPDIR}/${callfile}, ${CALLDIR}/${newcallfile}"); |
47 |
return rename("${TMPDIR}/${callfile}", "${CALLDIR}/${newcallfile}"); |
48 |
} |
49 |
|
50 |
sub signal_handler($) |
51 |
{ |
52 |
my ($sig) = @_; |
53 |
loggit("Death by $sig"); |
54 |
exit(0); |
55 |
} |
56 |
|
57 |
sub loggit($) |
58 |
{ |
59 |
my ($message) = @_; |
60 |
open(LOG, ">>", "/tmp/wakeup2.log"); |
61 |
print LOG scalar CORE::localtime(time) . ": " . $message . "\n"; |
62 |
close(LOG); |
63 |
} |
64 |
|
65 |
# Copies the call file back to the temporary directory, filtering out any |
66 |
# retry information. |
67 |
sub copy_call($$) |
68 |
{ |
69 |
my ($src, $dst) = @_; |
70 |
open(SRC, "<", $src); |
71 |
open(DST, ">", $dst . "/" . basename($src)); |
72 |
while(<SRC>) { |
73 |
next if (/^.*Retry:/); |
74 |
print DST $_; |
75 |
} |
76 |
close(SRC); |
77 |
close(DST); |
78 |
} |
79 |
|
80 |
# Create a new call |
81 |
sub create_call($$) |
82 |
{ |
83 |
my ($channel, $message) = @_; |
84 |
my $chan; |
85 |
($chan = $channel) =~ s!/!.!g; |
86 |
my $filename = strftime("%H%M", CORE::localtime()) . "." . $chan . ".call"; |
87 |
open(CALL, ">", $TMPDIR . "/" . $filename) || die "Open for $filename failed: $!"; |
88 |
print CALL "channel: $channel\n"; |
89 |
print CALL "maxretries: 3\n"; |
90 |
print CALL "retrytime: 60\n"; |
91 |
print CALL "waittime: 24\n"; |
92 |
print CALL "callerid: \"Wake Up\" <800>\n"; |
93 |
print CALL "application: AGI\n"; |
94 |
if ($message) { |
95 |
print CALL "data: wakeconfirm.agi|${message}\n"; |
96 |
} else { |
97 |
print CALL "data: wakeconfirm.agi\n"; |
98 |
} |
99 |
close(CALL); |
100 |
return $filename; |
101 |
} |
102 |
|
103 |
# Plays a list of audio files, allowing key-ahead for any of the expected |
104 |
# digits, returns the digit entered or the return code if none entered |
105 |
sub get_digit($$$) |
106 |
{ |
107 |
my ($AGI, $parts, $valid_digits) = @_; |
108 |
my $rc; |
109 |
my $digit = ""; |
110 |
# stream each part, bail out early on valid digit entry |
111 |
foreach my $part (@{$parts}) { |
112 |
$rc = $AGI->stream_file($part, join("", @{$valid_digits})); |
113 |
if ($rc) { |
114 |
last; |
115 |
} |
116 |
} |
117 |
# Save the digit if we got one early |
118 |
if ($rc) { |
119 |
$digit .= ($rc - ord('0')); |
120 |
} else { |
121 |
$rc = $AGI->wait_for_digit(15000); |
122 |
if ($rc) { |
123 |
$digit .= ($rc - ord('0')); |
124 |
} |
125 |
} |
126 |
# return what we got if we got something, otherwise the 0/-1 return code |
127 |
if ($digit) { |
128 |
return $digit; |
129 |
} else { |
130 |
return $rc; |
131 |
} |
132 |
} |
133 |
|
134 |
# Returns true if the user managed to answer the mathematical problem |
135 |
sub confirm_cancel($) |
136 |
{ |
137 |
my ($AGI) = @_; |
138 |
my $rc; |
139 |
my $a = int(rand(99)) + 1; |
140 |
my $b = int(rand(99)) + 1; |
141 |
my $c = $a + $b; |
142 |
|
143 |
$AGI->stream_file('please-answer-the-following'); |
144 |
$AGI->say_number($a); |
145 |
$AGI->stream_file('plus'); |
146 |
$AGI->say_number($b); |
147 |
$rc = $AGI->get_data('equals', 15000, length($c)); |
148 |
|
149 |
if ($rc == $c) { |
150 |
return 1; |
151 |
} else { |
152 |
return 0; |
153 |
} |
154 |
} |
155 |
|
156 |
my %input = $AGI->ReadParse(); |
157 |
my $channel = (split("-", $input{'channel'}))[0]; |
158 |
my $messagefile = $ARGV[0]; |
159 |
$AGI->setcallback(\&hangup_handler); |
160 |
# Cute, Asterisk sends the AGI a SIGHUP if the caller hangs up. |
161 |
$SIG{'HUP'} = 'IGNORE'; |
162 |
|
163 |
my $rc; |
164 |
|
165 |
# Copy the call file back to the $TMPDIR so the hangup handler can reschedule |
166 |
# it if need be |
167 |
#copy_call($CALLDIR . "/" . $callfile, $TMPDIR); |
168 |
$callfile = create_call($channel, $messagefile); |
169 |
|
170 |
$AGI->answer(); |
171 |
|
172 |
sleep(1); |
173 |
|
174 |
$rc = $AGI->stream_file('good'); |
175 |
loggit("(good) \$rc = $rc"); |
176 |
if (localtime->hour() >= 18) { |
177 |
$rc = $AGI->stream_file('evening'); |
178 |
loggit("(evening) \$rc = $rc"); |
179 |
} elsif (localtime->hour() >= 12) { |
180 |
$rc = $AGI->stream_file('afternoon'); |
181 |
loggit("(afternoon) \$rc = $rc"); |
182 |
} else { |
183 |
$rc = $AGI->stream_file('morning'); |
184 |
loggit("(morning) \$rc = $rc"); |
185 |
} |
186 |
|
187 |
$AGI->stream_file('this-is-yr-wakeup-call'); |
188 |
|
189 |
if (($messagefile) && (-r $MSGDIR . "/" . $messagefile)) { |
190 |
loggit("Attempting to play ${MSGDIR}/$messagefile"); |
191 |
$rc = $AGI->stream_file($MSGDIR . "/" . basename($messagefile, ".wav")); |
192 |
loggit("(recording) \$rc = $rc"); |
193 |
} |
194 |
|
195 |
# present menu of choices |
196 |
|
197 |
my $choice; |
198 |
do { |
199 |
$choice = get_digit($AGI, ['to-cancel-wakeup', 'press-1', |
200 |
'to-snooze-for', 'digits/5', 'minutes', 'press-2', 'to-snooze-for', |
201 |
'digits/10', 'minutes', 'press-3', 'to-snooze-for', 'digits/15', |
202 |
'minutes', 'press-4'], [1,2,3,4]); |
203 |
|
204 |
if ($choice == 1) { |
205 |
loggit("User would like to cancel wakeup call"); |
206 |
if (confirm_cancel($AGI)) { |
207 |
loggit("Cancellation confirmed"); |
208 |
if (-r $MSGDIR . "/" . $messagefile) { |
209 |
unlink($MSGDIR . "/" . $messagefile); |
210 |
} |
211 |
$AGI->stream_file('wakeup-call-cancelled'); |
212 |
$AGI->stream_file('goodbye'); |
213 |
sleep(1); |
214 |
$AGI->hangup(); |
215 |
exit(0); |
216 |
} else { |
217 |
loggit("Cancellation not confirmed"); |
218 |
$AGI->stream_file('vm-sorry'); |
219 |
$AGI->stream_file('please-hang-up-and-try-again'); |
220 |
$AGI->stream_file('later'); |
221 |
snooze(2); |
222 |
$AGI->hangup(); |
223 |
exit(0); |
224 |
} |
225 |
} elsif ($choice == 2) { |
226 |
snooze(5); |
227 |
exit(0); |
228 |
} elsif ($choice == 3) { |
229 |
snooze(10); |
230 |
exit(0); |
231 |
} elsif ($choice == 4) { |
232 |
snooze(15); |
233 |
exit(0); |
234 |
} else { |
235 |
loggit("Unexpected response"); |
236 |
} |
237 |
} until ($choice == 1 || $choice == 2 || $choice == 3 || $choice == 4); |
238 |
|
239 |
loggit("This should never be reached"); |