/[svn.andrew.net.au]/asterisk/wakeup.agi
ViewVC logotype

Contents of /asterisk/wakeup.agi

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (show annotations)
Thu Jan 24 21:32:32 2008 UTC (15 years, 4 months ago) by apollock
File size: 8522 byte(s)
Initial commit

1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 use Asterisk::AGI;
7 use POSIX qw (strftime mktime);
8 use Date::Parse;
9 use File::stat;
10
11 ##
12 # Functional TODO:
13 # - Move all of the configuration to a separate file
14 # - write a get_digits() like get_digit()
15 # Cleanup/Optimisation TODO:
16
17 my $TMPDIR="/var/spool/asterisk/tmp";
18 my $CALLDIR="/var/spool/asterisk/outgoing";
19 my $MSGDIR="/tmp";
20
21 sub get_meridian($)
22 {
23 my ($AGI) = @_;
24 my $rc;
25 do {
26 $rc = $AGI->get_data('1-for-am-2-for-pm', 7000, 1);
27 } until ($rc == 1 || $rc == 2);
28 return $rc;
29 }
30
31 sub valid_time($)
32 {
33 my ($time) = @_;
34 return ($time =~ /^((?:0?[0-9]|1[0-9]|2[0-3])[0-5][0-9])$/);
35 }
36
37 # Plays a list of audio files, allowing key-ahead for any of the expected
38 # digits, returns the digit entered or the return code if none entered
39 # TODO: loop if an invalid digit is entered? Or leave that up to the caller?
40 sub get_digit($$$)
41 {
42 my ($AGI, $parts, $valid_digits) = @_;
43 my $rc;
44 my $digit = "";
45 # stream each part, bail out early on valid digit entry
46 foreach my $part (@{$parts}) {
47 $rc = $AGI->stream_file($part, join("", @{$valid_digits}));
48 if ($rc) {
49 $digit .= ($rc - ord('0'));
50 last;
51 }
52 }
53 # We have our digit already, get out of here
54 if (length($digit)) {
55 return $digit;
56 } else {
57 $rc = $AGI->wait_for_digit(7000);
58 if ($rc > 0) {
59 $digit .= ($rc - ord('0'));
60 return $digit;
61 } else {
62 return $rc;
63 }
64 }
65 }
66
67 sub get_wakeuptime($)
68 {
69 my ($AGI) = @_;
70 my $rc;
71 my $digits = "";
72 my @parts = ('please-enter-the', 'time', 'for', 'your');
73 foreach my $part (@parts) {
74 $rc = $AGI->stream_file($part, join("", 0..9));
75 if ($rc) {
76 last;
77 }
78 }
79 if ($rc) {
80 # got a digit already by virtue of preempting things
81 $digits .= ($rc - 48);
82 loggit("early \$digits = $digits");
83 # read 2-3 digits
84 LOOP: {
85 do {
86 $rc = $AGI->wait_for_digit(15000);
87 loggit("\$rc = " . ($rc - 48));
88 last if ($rc == 0);
89 $digits .= ($rc - 48);
90 } until(length($digits) == 4);
91 }
92 loggit("Received individual (first early) $digits");
93 } else {
94 # read 3-4 digits
95 $digits = $AGI->get_data('wakeup-call', 15000, 4);
96 }
97 loggit("Received $digits");
98 if (length($digits) < 4) {
99 # need to confirm am/pm
100 my $meridian = get_meridian($AGI);
101 if ($meridian == 1) {
102 # prepend a zero
103 $digits = "0" . $digits;
104 } else {
105 # convert to 24 hour time
106 my ($first, $rest) = (substr($digits, 0, 1), substr($digits, 1));
107 $first = $first + 12;
108 $digits = $first . $rest;
109 }
110 }
111 loggit("Time entered: $digits");
112 return $digits;
113 }
114
115 sub say_wakeuptime($$$)
116 {
117 my ($AGI, $wakeuptime, $tomorrow) = @_;
118 my $pm = 0;
119
120 if ($wakeuptime > 1159) {
121 $wakeuptime -= 1200;
122 $pm = 1;
123 }
124
125 if ($wakeuptime <= 59) {
126 $wakeuptime += 1200;
127 }
128
129 if (length($wakeuptime) < 4) {
130 $wakeuptime = "0" . $wakeuptime;
131 }
132
133 my ($hour, $min) = (substr($wakeuptime, 0, 2), substr($wakeuptime, 2, 2));
134 my ($hour1, $hour2) = (substr($hour, 0, 1), substr($hour, 1, 1));
135 my ($min1, $min2) = (substr($min, 0, 1), substr($min, 1, 1));
136
137 $AGI->stream_file('rqsted-wakeup-for');
138
139 if ($tomorrow) {
140 $AGI->stream_file('tomorrow');
141 } else {
142 $AGI->stream_file('today');
143 }
144
145 $AGI->stream_file('at');
146
147 if ($hour1 == 0) {
148 $AGI->stream_file("digits/$hour2");
149 } else {
150 $AGI->stream_file("digits/$hour");
151 }
152
153 if ($min == 0) {
154 $AGI->stream_file('digits/oclock');
155 } else {
156 if ($min1 == 0) {
157 $AGI->stream_file('digits/oh');
158 $AGI->stream_file("digits/$min2");
159 } elsif ($min <= 20) {
160 $AGI->stream_file("digits/$min");
161 } else {
162 $min1 = int($min / 10) * 10;
163 $AGI->stream_file("digits/$min1");
164 $min2 = $min % 10;
165 if ($min2 > 0) {
166 $AGI->stream_file("digits/$min2");
167 }
168 }
169 }
170 if ($pm) {
171 $AGI->stream_file('digits/p-m');
172 } else {
173 $AGI->stream_file('digits/a-m');
174 }
175 }
176
177 sub say_wakeuptime_from_file($$)
178 {
179 my ($AGI, $filename) = @_;
180
181 # get time of wakeup call
182 # should we assume the filename is correct, or the mtime?
183 # mtime is more authoritative...
184 my $stat = stat($CALLDIR . "/" . $filename);
185 my $wakeuptime = strftime("%H%M", localtime($stat->mtime));
186 if ($wakeuptime <= strftime("%H%M", localtime())) {
187 say_wakeuptime($AGI, $wakeuptime, 1);
188 } else {
189 say_wakeuptime($AGI, $wakeuptime, 0);
190 }
191
192 }
193
194 sub cancel_wakeupcall($$)
195 {
196 my ($AGI, $wakeupcall) = @_;
197 if (-f $CALLDIR . "/" . $wakeupcall) {
198 loggit("Unlinking ${CALLDIR}/${wakeupcall}");
199 unlink($CALLDIR . "/" . $wakeupcall);
200 }
201 if (-f $MSGDIR . "/" . $wakeupcall . ".wav") {
202 loggit("Unlinking ${CALLDIR}/${wakeupcall}.wav");
203 unlink($MSGDIR . "/" . $wakeupcall . "wav");
204 }
205 $AGI->stream_file('your');
206 $AGI->stream_file('wakeup-call');
207 $AGI->stream_file('has-been');
208 $AGI->stream_file('cancelled');
209 $AGI->stream_file('goodbye');
210 sleep(1);
211 $AGI->hangup();
212 }
213
214 sub record_wakeup_message($$)
215 {
216 my ($AGI, $filename) = @_;
217 my $rc;
218
219 $AGI->stream_file('say-temp-msg-prs-pound');
220 $AGI->stream_file('beep');
221 $rc = $AGI->record_file($MSGDIR . "/" . $filename, "wav", '#', -1, 1);
222 return $filename . ".wav";
223 }
224
225 sub schedule_wakeupcall($$$)
226 {
227 my ($AGI, $channel, $wakeuptime) = @_;
228 my $rc;
229 my $digit;
230 my $message;
231 my $filename;
232
233 ($filename = $channel) =~ s!/!.!g;
234 $filename = $wakeuptime . "." . $filename . ".call";
235 loggit("\$filename = $filename");
236
237 # Ask to schedule message
238 do {
239 $digit = get_digit($AGI, ['to-leave-message-for', 'your',
240 'wakeup-call', 'press-1', 'otherwise', 'press-0'], [0,1]);
241 loggit("get_digit returned '$digit'");
242 } until ($digit == 0 || $digit == 1);
243 if ($digit == 1) {
244 # we need to record a message
245 $message = record_wakeup_message($AGI, $filename);
246 }
247 # we're all good, schedule wakeup
248 open(CALL, ">", $TMPDIR . "/" . $filename);
249 print CALL "channel: $channel\n";
250 print CALL "maxretries: 3\n";
251 print CALL "retrytime: 60\n";
252 print CALL "waittime: 24\n";
253 print CALL "callerid: \"Wake Up\" <800>\n";
254 print CALL "application: AGI\n";
255 if ($message) {
256 print CALL "data: wakeconfirm.agi|${message}\n";
257 } else {
258 print CALL "data: wakeconfirm.agi\n";
259 }
260 close(CALL);
261 # if the current time is after the specified time, it will be
262 # tomorrow
263 my $now = strftime("%H%M", localtime());
264 my (undef, undef, undef, $mday, $mon, $year, $wday, $yday, $isdst) = localtime();
265 my ($hour, $min) = (substr($wakeuptime, 0, 2), substr($wakeuptime, 2, 2));
266 my $time_t;
267 my $tomorrow = 0;
268 if ($now >= $wakeuptime) {
269 $tomorrow = 1;
270 $time_t = mktime(0, $min, $hour, $mday+1, $mon, $year, $wday, $yday, $isdst);
271 loggit("Scheduling call for tomorrow ($time_t)");
272 utime($time_t, $time_t, $TMPDIR . "/" . $filename);
273 } else {
274 $tomorrow = 0;
275 $time_t = mktime(0, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
276 loggit("Scheduling call for today ($time_t)");
277 utime($time_t, $time_t, $TMPDIR . "/" . $filename);
278 }
279 rename($TMPDIR . "/" . $filename, $CALLDIR . "/" . $filename);
280 say_wakeuptime($AGI, $wakeuptime, $tomorrow);
281 $AGI->stream_file('goodbye');
282 sleep(1);
283 $AGI->hangup();
284 }
285
286 sub get_wakeupcall($)
287 {
288 my ($channel) = @_;
289 my $filename;
290 ($filename = $channel) =~ s!/!.!g;
291 # Need to check for files ending in $extension in $CALLDIR
292 opendir(CALLDIR, $CALLDIR);
293 my @wakeupcalls = grep { /^\d{4}\.${filename}\.call$/ && -f "$CALLDIR/$_" } readdir(CALLDIR);
294 closedir(CALLDIR);
295 return \@wakeupcalls;
296 }
297
298 sub loggit($)
299 {
300 my ($message) = @_;
301 open(LOG, ">>", "/tmp/wakeup2.log");
302 print LOG scalar localtime(time) . ": " . $message . "\n";
303 close(LOG);
304 }
305
306 my $AGI = new Asterisk::AGI;
307 my $rc;
308 my $channel;
309 my $existing_wakeup;
310
311 my %input = $AGI->ReadParse();
312 $channel = (split("-", $input{'channel'}))[0];
313
314 $AGI->answer();
315 sleep(1);
316 $rc = $AGI->stream_file('welcome');
317 $existing_wakeup = get_wakeupcall($channel);
318
319 if (scalar @{$existing_wakeup}) {
320 # Need to do stuff here
321 # press 1 to schedule, 2 to cancel
322 loggit("I think there's existing wakeup calls");
323 loggit(join(",", @{$existing_wakeup}));
324 say_wakeuptime_from_file($AGI, $existing_wakeup->[0]);
325 my $digit = "";
326 do {
327 $digit = get_digit($AGI, ['for-wakeup-call', 'press-1',
328 'to-cancel-wakeup', 'press-2'], [1..2]);
329 } until ($digit == 1 || $digit == 2);
330 loggit("Received $digit");
331 if ($digit == 1) {
332 # schedule wakeupcall
333 my $wakeuptime;
334 do {
335 $wakeuptime = get_wakeuptime($AGI);
336 } until (valid_time($wakeuptime));
337 schedule_wakeupcall($AGI, $channel, $wakeuptime)
338 } else {
339 # cancel wakeupcall
340 cancel_wakeupcall($AGI, $existing_wakeup->[0]);
341 }
342
343 } else {
344 my $wakeuptime;
345 do {
346 $wakeuptime = get_wakeuptime($AGI);
347 } until (valid_time($wakeuptime));
348 schedule_wakeupcall($AGI, $channel, $wakeuptime)
349 }

Properties

Name Value
svn:executable

  ViewVC Help
Powered by ViewVC 1.1.22