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

Annotation of /wakeup.agi

Parent Directory Parent Directory | Revision Log Revision Log


Revision 25 - (hide annotations)
Thu Jan 24 21:31:28 2008 UTC (14 years, 10 months ago) by apollock
File size: 8522 byte(s)
Initial commit

1 apollock 25 #!/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