(closes issue #7852)
[asterisk/asterisk.git] / main / app.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Convenient Application Routines
22  *
23  * \author Mark Spencer <markster@digium.com> 
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/time.h>
34 #include <signal.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include <dirent.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/file.h>
41 #include <regex.h>
42
43 #include "asterisk/channel.h"
44 #include "asterisk/pbx.h"
45 #include "asterisk/file.h"
46 #include "asterisk/app.h"
47 #include "asterisk/dsp.h"
48 #include "asterisk/logger.h"
49 #include "asterisk/options.h"
50 #include "asterisk/utils.h"
51 #include "asterisk/lock.h"
52 #include "asterisk/indications.h"
53 #include "asterisk/linkedlists.h"
54
55 #define MAX_OTHER_FORMATS 10
56
57 static AST_RWLIST_HEAD_STATIC(groups, ast_group_info);
58
59 /*!
60  * \brief This function presents a dialtone and reads an extension into 'collect' 
61  * which must be a pointer to a **pre-initialized** array of char having a 
62  * size of 'size' suitable for writing to.  It will collect no more than the smaller 
63  * of 'maxlen' or 'size' minus the original strlen() of collect digits.
64  * \param chan struct.
65  * \param context 
66  * \param collect 
67  * \param size 
68  * \param maxlen
69  * \param timeout timeout in seconds
70  *
71  * \return 0 if extension does not exist, 1 if extension exists
72 */
73 int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout) 
74 {
75         struct ind_tone_zone_sound *ts;
76         int res = 0, x = 0;
77
78         if (maxlen > size)
79                 maxlen = size;
80         
81         if (!timeout && chan->pbx)
82                 timeout = chan->pbx->dtimeout;
83         else if (!timeout)
84                 timeout = 5;
85
86         if ((ts = ast_get_indication_tone(chan->zone, "dial")) && ts->data[0])
87                 res = ast_playtones_start(chan, 0, ts->data, 0);
88         else 
89                 ast_log(LOG_NOTICE,"Huh....? no dial for indications?\n");
90         
91         for (x = strlen(collect); x < maxlen; ) {
92                 res = ast_waitfordigit(chan, timeout);
93                 if (!ast_ignore_pattern(context, collect))
94                         ast_playtones_stop(chan);
95                 if (res < 1)
96                         break;
97                 if (res == '#')
98                         break;
99                 collect[x++] = res;
100                 if (!ast_matchmore_extension(chan, context, collect, 1, chan->cid.cid_num))
101                         break;
102         }
103
104         if (res >= 0)
105                 res = ast_exists_extension(chan, context, collect, 1, chan->cid.cid_num) ? 1 : 0;
106
107         return res;
108 }
109
110 /*!
111  * \brief ast_app_getdata
112  * \param c The channel to read from
113  * \param prompt The file to stream to the channel
114  * \param s The string to read in to.  Must be at least the size of your length
115  * \param maxlen How many digits to read (maximum)
116  * \param timeout set timeout to 0 for "standard" timeouts. Set timeout to -1 for 
117  *      "ludicrous time" (essentially never times out) */
118 int ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout)
119 {
120         int res = 0, to, fto;
121         char *front, *filename;
122
123         /* XXX Merge with full version? XXX */
124         
125         if (maxlen)
126                 s[0] = '\0';
127
128         if (!prompt)
129                 prompt="";
130
131         filename = ast_strdupa(prompt);
132         while ((front = strsep(&filename, "&"))) {
133                 if (!ast_strlen_zero(front)) {
134                         res = ast_streamfile(c, front, c->language);
135                         if (res)
136                                 continue;
137                 }
138                 if (ast_strlen_zero(filename)) {
139                         /* set timeouts for the last prompt */
140                         fto = c->pbx ? c->pbx->rtimeout * 1000 : 6000;
141                         to = c->pbx ? c->pbx->dtimeout * 1000 : 2000;
142
143                         if (timeout > 0) 
144                                 fto = to = timeout;
145                         if (timeout < 0) 
146                                 fto = to = 1000000000;
147                 } else {
148                         /* there is more than one prompt, so
149                            get rid of the long timeout between 
150                            prompts, and make it 50ms */
151                         fto = 50;
152                         to = c->pbx ? c->pbx->dtimeout * 1000 : 2000;
153                 }
154                 res = ast_readstring(c, s, maxlen, to, fto, "#");
155                 if (!ast_strlen_zero(s))
156                         return res;
157         }
158         
159         return res;
160 }
161
162 /* The lock type used by ast_lock_path() / ast_unlock_path() */
163 static enum AST_LOCK_TYPE ast_lock_type = AST_LOCK_TYPE_LOCKFILE;
164
165 int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
166 {
167         int res, to = 2000, fto = 6000;
168
169         if (!ast_strlen_zero(prompt)) {
170                 res = ast_streamfile(c, prompt, c->language);
171                 if (res < 0)
172                         return res;
173         }
174         
175         if (timeout > 0) 
176                 fto = to = timeout;
177         if (timeout < 0) 
178                 fto = to = 1000000000;
179
180         res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
181
182         return res;
183 }
184
185 static int (*ast_has_voicemail_func)(const char *mailbox, const char *folder) = NULL;
186 static int (*ast_inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsgs) = NULL;
187 static int (*ast_messagecount_func)(const char *context, const char *mailbox, const char *folder) = NULL;
188
189 void ast_install_vm_functions(int (*has_voicemail_func)(const char *mailbox, const char *folder),
190                               int (*inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsgs),
191                               int (*messagecount_func)(const char *context, const char *mailbox, const char *folder))
192 {
193         ast_has_voicemail_func = has_voicemail_func;
194         ast_inboxcount_func = inboxcount_func;
195         ast_messagecount_func = messagecount_func;
196 }
197
198 void ast_uninstall_vm_functions(void)
199 {
200         ast_has_voicemail_func = NULL;
201         ast_inboxcount_func = NULL;
202         ast_messagecount_func = NULL;
203 }
204
205 int ast_app_has_voicemail(const char *mailbox, const char *folder)
206 {
207         static int warned = 0;
208         if (ast_has_voicemail_func)
209                 return ast_has_voicemail_func(mailbox, folder);
210
211         if (!warned) {
212                 ast_verb(3, "Message check requested for mailbox %s/folder %s but voicemail not loaded.\n", mailbox, folder ? folder : "INBOX");
213                 warned++;
214         }
215         return 0;
216 }
217
218
219 int ast_app_inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
220 {
221         static int warned = 0;
222         if (newmsgs)
223                 *newmsgs = 0;
224         if (oldmsgs)
225                 *oldmsgs = 0;
226         if (ast_inboxcount_func)
227                 return ast_inboxcount_func(mailbox, newmsgs, oldmsgs);
228
229         if (!warned) {
230                 warned++;
231                 ast_verb(3, "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox);
232         }
233
234         return 0;
235 }
236
237 int ast_app_messagecount(const char *context, const char *mailbox, const char *folder)
238 {
239         static int warned = 0;
240         if (ast_messagecount_func)
241                 return ast_messagecount_func(context, mailbox, folder);
242
243         if (!warned) {
244                 warned++;
245                 ast_verb(3, "Message count requested for mailbox %s@%s/%s but voicemail not loaded.\n", mailbox, context, folder);
246         }
247
248         return 0;
249 }
250
251 int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration) 
252 {
253         const char *ptr;
254         int res = 0;
255
256         if (!between)
257                 between = 100;
258
259         if (peer)
260                 res = ast_autoservice_start(peer);
261
262         if (!res)
263                 res = ast_waitfor(chan, 100);
264
265         /* ast_waitfor will return the number of remaining ms on success */
266         if (res < 0)
267                 return res;
268
269         for (ptr = digits; *ptr; ptr++) {
270                 if (*ptr == 'w') {
271                         /* 'w' -- wait half a second */
272                         if ((res = ast_safe_sleep(chan, 500)))
273                                 break;
274                 } else if (strchr("0123456789*#abcdfABCDF", *ptr)) {
275                         /* Character represents valid DTMF */
276                         if (*ptr == 'f' || *ptr == 'F') {
277                                 /* ignore return values if not supported by channel */
278                                 ast_indicate(chan, AST_CONTROL_FLASH);
279                         } else
280                                 ast_senddigit(chan, *ptr, duration);
281                         /* pause between digits */
282                         if ((res = ast_safe_sleep(chan, between)))
283                                 break;
284                 } else
285                         ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n",*ptr);
286         }
287
288         if (peer) {
289                 /* Stop autoservice on the peer channel, but don't overwrite any error condition 
290                    that has occurred previously while acting on the primary channel */
291                 if (ast_autoservice_stop(peer) && !res)
292                         res = -1;
293         }
294
295         return res;
296 }
297
298 struct linear_state {
299         int fd;
300         int autoclose;
301         int allowoverride;
302         int origwfmt;
303 };
304
305 static void linear_release(struct ast_channel *chan, void *params)
306 {
307         struct linear_state *ls = params;
308         
309         if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt))
310                 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, ls->origwfmt);
311
312         if (ls->autoclose)
313                 close(ls->fd);
314
315         ast_free(params);
316 }
317
318 static int linear_generator(struct ast_channel *chan, void *data, int len, int samples)
319 {
320         short buf[2048 + AST_FRIENDLY_OFFSET / 2];
321         struct linear_state *ls = data;
322         struct ast_frame f = {
323                 .frametype = AST_FRAME_VOICE,
324                 .subclass = AST_FORMAT_SLINEAR,
325                 .data = buf + AST_FRIENDLY_OFFSET / 2,
326                 .offset = AST_FRIENDLY_OFFSET,
327         };
328         int res;
329
330         len = samples * 2;
331         if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
332                 ast_log(LOG_WARNING, "Can't generate %d bytes of data!\n" ,len);
333                 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
334         }
335         res = read(ls->fd, buf + AST_FRIENDLY_OFFSET/2, len);
336         if (res > 0) {
337                 f.datalen = res;
338                 f.samples = res / 2;
339                 ast_write(chan, &f);
340                 if (res == len)
341                         return 0;
342         }
343         return -1;
344 }
345
346 static void *linear_alloc(struct ast_channel *chan, void *params)
347 {
348         struct linear_state *ls = params;
349
350         if (!params)
351                 return NULL;
352
353         /* In this case, params is already malloc'd */
354         if (ls->allowoverride)
355                 ast_set_flag(chan, AST_FLAG_WRITE_INT);
356         else
357                 ast_clear_flag(chan, AST_FLAG_WRITE_INT);
358
359         ls->origwfmt = chan->writeformat;
360
361         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
362                 ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
363                 ast_free(ls);
364                 ls = params = NULL;
365         }
366
367         return params;
368 }
369
370 static struct ast_generator linearstream = 
371 {
372         alloc: linear_alloc,
373         release: linear_release,
374         generate: linear_generator,
375 };
376
377 int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, int allowoverride)
378 {
379         struct linear_state *lin;
380         char tmpf[256];
381         int res = -1;
382         int autoclose = 0;
383         if (fd < 0) {
384                 if (ast_strlen_zero(filename))
385                         return -1;
386                 autoclose = 1;
387                 if (filename[0] == '/') 
388                         ast_copy_string(tmpf, filename, sizeof(tmpf));
389                 else
390                         snprintf(tmpf, sizeof(tmpf), "%s/%s/%s", ast_config_AST_DATA_DIR, "sounds", filename);
391                 if ((fd = open(tmpf, O_RDONLY)) < 0) {
392                         ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", tmpf, strerror(errno));
393                         return -1;
394                 }
395         }
396         if ((lin = ast_calloc(1, sizeof(*lin)))) {
397                 lin->fd = fd;
398                 lin->allowoverride = allowoverride;
399                 lin->autoclose = autoclose;
400                 res = ast_activate_generator(chan, &linearstream, lin);
401         }
402         return res;
403 }
404
405 int ast_control_streamfile(struct ast_channel *chan, const char *file,
406                            const char *fwd, const char *rev,
407                            const char *stop, const char *pause,
408                            const char *restart, int skipms, long *offsetms) 
409 {
410         char *breaks = NULL;
411         char *end = NULL;
412         int blen = 2;
413         int res;
414         long pause_restart_point = 0;
415         long offset = 0;
416
417         if (offsetms) 
418                 offset = *offsetms * 8; /* XXX Assumes 8kHz */
419
420         if (stop)
421                 blen += strlen(stop);
422         if (pause)
423                 blen += strlen(pause);
424         if (restart)
425                 blen += strlen(restart);
426
427         if (blen > 2) {
428                 breaks = alloca(blen + 1);
429                 breaks[0] = '\0';
430                 if (stop)
431                         strcat(breaks, stop);
432                 if (pause)
433                         strcat(breaks, pause);
434                 if (restart)
435                         strcat(breaks, restart);
436         }
437         if (chan->_state != AST_STATE_UP)
438                 res = ast_answer(chan);
439
440         if (file) {
441                 if ((end = strchr(file,':'))) {
442                         if (!strcasecmp(end, ":end")) {
443                                 *end = '\0';
444                                 end++;
445                         }
446                 }
447         }
448
449         for (;;) {
450                 ast_stopstream(chan);
451                 res = ast_streamfile(chan, file, chan->language);
452                 if (!res) {
453                         if (pause_restart_point) {
454                                 ast_seekstream(chan->stream, pause_restart_point, SEEK_SET);
455                                 pause_restart_point = 0;
456                         }
457                         else if (end || offset < 0) {
458                                 if (offset == -8) 
459                                         offset = 0;
460                                 ast_verb(3, "ControlPlayback seek to offset %ld from end\n", offset);
461
462                                 ast_seekstream(chan->stream, offset, SEEK_END);
463                                 end = NULL;
464                                 offset = 0;
465                         } else if (offset) {
466                                 ast_verb(3, "ControlPlayback seek to offset %ld\n", offset);
467                                 ast_seekstream(chan->stream, offset, SEEK_SET);
468                                 offset = 0;
469                         };
470                         res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
471                 }
472
473                 if (res < 1)
474                         break;
475
476                 /* We go at next loop if we got the restart char */
477                 if (restart && strchr(restart, res)) {
478                         ast_debug(1, "we'll restart the stream here at next loop\n");
479                         pause_restart_point = 0;
480                         continue;
481                 }
482
483                 if (pause && strchr(pause, res)) {
484                         pause_restart_point = ast_tellstream(chan->stream);
485                         for (;;) {
486                                 ast_stopstream(chan);
487                                 res = ast_waitfordigit(chan, 1000);
488                                 if (!res)
489                                         continue;
490                                 else if (res == -1 || strchr(pause, res) || (stop && strchr(stop, res)))
491                                         break;
492                         }
493                         if (res == *pause) {
494                                 res = 0;
495                                 continue;
496                         }
497                 }
498
499                 if (res == -1)
500                         break;
501
502                 /* if we get one of our stop chars, return it to the calling function */
503                 if (stop && strchr(stop, res))
504                         break;
505         }
506
507         if (pause_restart_point) {
508                 offset = pause_restart_point;
509         } else {
510                 if (chan->stream) {
511                         offset = ast_tellstream(chan->stream);
512                 } else {
513                         offset = -8;  /* indicate end of file */
514                 }
515         }
516
517         if (offsetms) 
518                 *offsetms = offset / 8; /* samples --> ms ... XXX Assumes 8 kHz */
519
520         ast_stopstream(chan);
521
522         return res;
523 }
524
525 int ast_play_and_wait(struct ast_channel *chan, const char *fn)
526 {
527         int d = 0;
528
529         if ((d = ast_streamfile(chan, fn, chan->language)))
530                 return d;
531
532         d = ast_waitstream(chan, AST_DIGIT_ANY);
533
534         ast_stopstream(chan);
535
536         return d;
537 }
538
539 static int global_silence_threshold = 128;
540 static int global_maxsilence = 0;
541
542 /*! Optionally play a sound file or a beep, then record audio and video from the channel.
543  * \param chan Channel to playback to/record from.
544  * \param playfile Filename of sound to play before recording begins.
545  * \param recordfile Filename to record to.
546  * \param maxtime Maximum length of recording (in milliseconds).
547  * \param fmt Format(s) to record message in. Multiple formats may be specified by separating them with a '|'.
548  * \param duration Where to store actual length of the recorded message (in milliseconds).
549  * \param beep Whether to play a beep before starting to record.
550  * \param silencethreshold 
551  * \param maxsilence Length of silence that will end a recording (in milliseconds).
552  * \param path Optional filesystem path to unlock.
553  * \param prepend If true, prepend the recorded audio to an existing file.
554  * \param acceptdtmf DTMF digits that will end the recording.
555  * \param canceldtmf DTMF digits that will cancel the recording.
556  */
557
558 static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int beep, int silencethreshold, int maxsilence, const char *path, int prepend, const char *acceptdtmf, const char *canceldtmf)
559 {
560         int d = 0;
561         char *fmts;
562         char comment[256];
563         int x, fmtcnt = 1, res = -1, outmsg = 0;
564         struct ast_filestream *others[MAX_OTHER_FORMATS];
565         char *sfmt[MAX_OTHER_FORMATS];
566         char *stringp = NULL;
567         time_t start, end;
568         struct ast_dsp *sildet = NULL;   /* silence detector dsp */
569         int totalsilence = 0;
570         int rfmt = 0;
571         struct ast_silence_generator *silgen = NULL;
572         char prependfile[80];
573
574         if (silencethreshold < 0)
575                 silencethreshold = global_silence_threshold;
576
577         if (maxsilence < 0)
578                 maxsilence = global_maxsilence;
579
580         /* barf if no pointer passed to store duration in */
581         if (!duration) {
582                 ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
583                 return -1;
584         }
585
586         ast_debug(1, "play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
587         snprintf(comment, sizeof(comment), "Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
588
589         if (playfile || beep) {
590                 if (!beep)
591                         d = ast_play_and_wait(chan, playfile);
592                 if (d > -1)
593                         d = ast_stream_and_wait(chan, "beep", "");
594                 if (d < 0)
595                         return -1;
596         }
597
598         if (prepend) {
599                 ast_copy_string(prependfile, recordfile, sizeof(prependfile));  
600                 strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
601         }
602
603         fmts = ast_strdupa(fmt);
604
605         stringp = fmts;
606         strsep(&stringp, "|");
607         ast_debug(1, "Recording Formats: sfmts=%s\n", fmts);
608         sfmt[0] = ast_strdupa(fmts);
609
610         while ((fmt = strsep(&stringp, "|"))) {
611                 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
612                         ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app.c\n");
613                         break;
614                 }
615                 sfmt[fmtcnt++] = ast_strdupa(fmt);
616         }
617
618         end = start = time(NULL);  /* pre-initialize end to be same as start in case we never get into loop */
619         for (x = 0; x < fmtcnt; x++) {
620                 others[x] = ast_writefile(prepend ? prependfile : recordfile, sfmt[x], comment, O_TRUNC, 0, AST_FILE_MODE);
621                 ast_verb(3, "x=%d, open writing:  %s format: %s, %p\n", x, prepend ? prependfile : recordfile, sfmt[x], others[x]);
622
623                 if (!others[x])
624                         break;
625         }
626
627         if (path)
628                 ast_unlock_path(path);
629
630         if (maxsilence > 0) {
631                 sildet = ast_dsp_new(); /* Create the silence detector */
632                 if (!sildet) {
633                         ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
634                         return -1;
635                 }
636                 ast_dsp_set_threshold(sildet, silencethreshold);
637                 rfmt = chan->readformat;
638                 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
639                 if (res < 0) {
640                         ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
641                         ast_dsp_free(sildet);
642                         return -1;
643                 }
644         }
645
646         if (!prepend) {
647                 /* Request a video update */
648                 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
649
650                 if (ast_opt_transmit_silence)
651                         silgen = ast_channel_start_silence_generator(chan);
652         }
653
654         if (x == fmtcnt) {
655                 /* Loop forever, writing the packets we read to the writer(s), until
656                    we read a digit or get a hangup */
657                 struct ast_frame *f;
658                 for (;;) {
659                         res = ast_waitfor(chan, 2000);
660                         if (!res) {
661                                 ast_debug(1, "One waitfor failed, trying another\n");
662                                 /* Try one more time in case of masq */
663                                 res = ast_waitfor(chan, 2000);
664                                 if (!res) {
665                                         ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
666                                         res = -1;
667                                 }
668                         }
669
670                         if (res < 0) {
671                                 f = NULL;
672                                 break;
673                         }
674                         f = ast_read(chan);
675                         if (!f)
676                                 break;
677                         if (f->frametype == AST_FRAME_VOICE) {
678                                 /* write each format */
679                                 for (x = 0; x < fmtcnt; x++) {
680                                         if (prepend && !others[x])
681                                                 break;
682                                         res = ast_writestream(others[x], f);
683                                 }
684
685                                 /* Silence Detection */
686                                 if (maxsilence > 0) {
687                                         int dspsilence = 0;
688                                         ast_dsp_silence(sildet, f, &dspsilence);
689                                         if (dspsilence)
690                                                 totalsilence = dspsilence;
691                                         else
692                                                 totalsilence = 0;
693
694                                         if (totalsilence > maxsilence) {
695                                                 /* Ended happily with silence */
696                                                 ast_verb(3, "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
697                                                 res = 'S';
698                                                 outmsg = 2;
699                                                 break;
700                                         }
701                                 }
702                                 /* Exit on any error */
703                                 if (res) {
704                                         ast_log(LOG_WARNING, "Error writing frame\n");
705                                         break;
706                                 }
707                         } else if (f->frametype == AST_FRAME_VIDEO) {
708                                 /* Write only once */
709                                 ast_writestream(others[0], f);
710                         } else if (f->frametype == AST_FRAME_DTMF) {
711                                 if (prepend) {
712                                 /* stop recording with any digit */
713                                         ast_verb(3, "User ended message by pressing %c\n", f->subclass);
714                                         res = 't';
715                                         outmsg = 2;
716                                         break;
717                                 }
718                                 if (strchr(acceptdtmf, f->subclass)) {
719                                         ast_verb(3, "User ended message by pressing %c\n", f->subclass);
720                                         res = f->subclass;
721                                         outmsg = 2;
722                                         break;
723                                 }
724                                 if (strchr(canceldtmf, f->subclass)) {
725                                         ast_verb(3, "User cancelled message by pressing %c\n", f->subclass);
726                                         res = f->subclass;
727                                         outmsg = 0;
728                                         break;
729                                 }
730                         }
731                         if (maxtime) {
732                                 end = time(NULL);
733                                 if (maxtime < (end - start)) {
734                                         ast_verb(3, "Took too long, cutting it short...\n");
735                                         res = 't';
736                                         outmsg = 2;
737                                         break;
738                                 }
739                         }
740                         ast_frfree(f);
741                 }
742                 if (!f) {
743                         ast_verb(3, "User hung up\n");
744                         res = -1;
745                         outmsg = 1;
746                 } else {
747                         ast_frfree(f);
748                 }
749                 if (end == start)
750                         end = time(NULL);
751         } else {
752                 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
753         }
754
755         if (!prepend) {
756                 if (silgen)
757                         ast_channel_stop_silence_generator(chan, silgen);
758         }
759         *duration = end - start;
760
761         if (!prepend) {
762                 for (x = 0; x < fmtcnt; x++) {
763                         if (!others[x])
764                                 break;
765                         if (res > 0)
766                                 ast_stream_rewind(others[x], totalsilence ? totalsilence - 200 : 200);
767                         ast_truncstream(others[x]);
768                         ast_closestream(others[x]);
769                 }
770         }
771
772         if (prepend && outmsg) {
773                 struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
774                 struct ast_frame *fr;
775
776                 for (x = 0; x < fmtcnt; x++) {
777                         snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
778                         realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
779                         if (!others[x] || !realfiles[x])
780                                 break;
781                         ast_stream_rewind(others[x], totalsilence ? totalsilence - 200 : 200);
782                         ast_truncstream(others[x]);
783                         /* add the original file too */
784                         while ((fr = ast_readframe(realfiles[x]))) {
785                                 ast_writestream(others[x], fr);
786                                 ast_frfree(fr);
787                         }
788                         ast_closestream(others[x]);
789                         ast_closestream(realfiles[x]);
790                         ast_filerename(prependfile, recordfile, sfmt[x]);
791                         ast_verb(4, "Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x], prependfile, recordfile);
792                         ast_filedelete(prependfile, sfmt[x]);
793                 }
794         }
795         if (rfmt && ast_set_read_format(chan, rfmt)) {
796                 ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
797         }
798         if (outmsg == 2) {
799                 ast_stream_and_wait(chan, "auth-thankyou", "");
800         }
801         if (sildet)
802                 ast_dsp_free(sildet);
803         return res;
804 }
805
806 static char default_acceptdtmf[] = "#";
807 static char default_canceldtmf[] = "";
808
809 int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf)
810 {
811         return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, 0, silencethreshold, maxsilence, path, 0, S_OR(acceptdtmf, default_acceptdtmf), S_OR(canceldtmf, default_canceldtmf));
812 }
813
814 int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path)
815 {
816         return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, 0, silencethreshold, maxsilence, path, 0, default_acceptdtmf, default_canceldtmf);
817 }
818
819 int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence)
820 {
821         return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, beep, silencethreshold, maxsilence, NULL, 1, default_acceptdtmf, default_canceldtmf);
822 }
823
824 /* Channel group core functions */
825
826 int ast_app_group_split_group(const char *data, char *group, int group_max, char *category, int category_max)
827 {
828         int res = 0;
829         char tmp[256];
830         char *grp = NULL, *cat = NULL;
831
832         if (!ast_strlen_zero(data)) {
833                 ast_copy_string(tmp, data, sizeof(tmp));
834                 grp = tmp;
835                 cat = strchr(tmp, '@');
836                 if (cat) {
837                         *cat = '\0';
838                         cat++;
839                 }
840         }
841
842         if (!ast_strlen_zero(grp))
843                 ast_copy_string(group, grp, group_max);
844         else
845                 res = -1;
846
847         if (!ast_strlen_zero(cat))
848                 ast_copy_string(category, cat, category_max);
849
850         return res;
851 }
852
853 int ast_app_group_set_channel(struct ast_channel *chan, const char *data)
854 {
855         int res = 0;
856         char group[80] = "", category[80] = "";
857         struct ast_group_info *gi = NULL;
858         size_t len = 0;
859         
860         if (ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category)))
861                 return -1;
862         
863         /* Calculate memory we will need if this is new */
864         len = sizeof(*gi) + strlen(group) + 1;
865         if (!ast_strlen_zero(category))
866                 len += strlen(category) + 1;
867         
868         AST_RWLIST_WRLOCK(&groups);
869         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&groups, gi, list) {
870                 if ((gi->chan == chan) && ((ast_strlen_zero(category) && ast_strlen_zero(gi->category)) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) {
871                         AST_RWLIST_REMOVE_CURRENT(&groups, list);
872                         free(gi);
873                         break;
874                 }
875         }
876         AST_RWLIST_TRAVERSE_SAFE_END
877
878         if ((gi = calloc(1, len))) {
879                 gi->chan = chan;
880                 gi->group = (char *) gi + sizeof(*gi);
881                 strcpy(gi->group, group);
882                 if (!ast_strlen_zero(category)) {
883                         gi->category = (char *) gi + sizeof(*gi) + strlen(group) + 1;
884                         strcpy(gi->category, category);
885                 }
886                 AST_RWLIST_INSERT_TAIL(&groups, gi, list);
887         } else {
888                 res = -1;
889         }
890         
891         AST_RWLIST_UNLOCK(&groups);
892         
893         return res;
894 }
895
896 int ast_app_group_get_count(const char *group, const char *category)
897 {
898         struct ast_group_info *gi = NULL;
899         int count = 0;
900
901         if (ast_strlen_zero(group))
902                 return 0;
903         
904         AST_RWLIST_RDLOCK(&groups);
905         AST_RWLIST_TRAVERSE(&groups, gi, list) {
906                 if (!strcasecmp(gi->group, group) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category))))
907                         count++;
908         }
909         AST_RWLIST_UNLOCK(&groups);
910
911         return count;
912 }
913
914 int ast_app_group_match_get_count(const char *groupmatch, const char *category)
915 {
916         struct ast_group_info *gi = NULL;
917         regex_t regexbuf;
918         int count = 0;
919
920         if (ast_strlen_zero(groupmatch))
921                 return 0;
922
923         /* if regex compilation fails, return zero matches */
924         if (regcomp(&regexbuf, groupmatch, REG_EXTENDED | REG_NOSUB))
925                 return 0;
926
927         AST_RWLIST_RDLOCK(&groups);
928         AST_RWLIST_TRAVERSE(&groups, gi, list) {
929                 if (!regexec(&regexbuf, gi->group, 0, NULL, 0) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category))))
930                         count++;
931         }
932         AST_RWLIST_UNLOCK(&groups);
933
934         regfree(&regexbuf);
935
936         return count;
937 }
938
939 int ast_app_group_update(struct ast_channel *old, struct ast_channel *new)
940 {
941         struct ast_group_info *gi = NULL;
942
943         AST_RWLIST_WRLOCK(&groups);
944         AST_RWLIST_TRAVERSE(&groups, gi, list) {
945                 if (gi->chan == old)
946                         gi->chan = new;
947         }
948         AST_RWLIST_UNLOCK(&groups);
949
950         return 0;
951 }
952
953 int ast_app_group_discard(struct ast_channel *chan)
954 {
955         struct ast_group_info *gi = NULL;
956         
957         AST_RWLIST_WRLOCK(&groups);
958         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&groups, gi, list) {
959                 if (gi->chan == chan) {
960                         AST_RWLIST_REMOVE_CURRENT(&groups, list);
961                         ast_free(gi);
962                 }
963         }
964         AST_RWLIST_TRAVERSE_SAFE_END
965         AST_RWLIST_UNLOCK(&groups);
966         
967         return 0;
968 }
969
970 int ast_app_group_list_wrlock(void)
971 {
972         return AST_RWLIST_WRLOCK(&groups);
973 }
974
975 int ast_app_group_list_rdlock(void)
976 {
977         return AST_RWLIST_RDLOCK(&groups);
978 }
979
980 struct ast_group_info *ast_app_group_list_head(void)
981 {
982         return AST_RWLIST_FIRST(&groups);
983 }
984
985 int ast_app_group_list_unlock(void)
986 {
987         return AST_RWLIST_UNLOCK(&groups);
988 }
989
990 unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
991 {
992         int argc;
993         char *scan;
994         int paren = 0, quote = 0;
995
996         if (!buf || !array || !arraylen)
997                 return 0;
998
999         memset(array, 0, arraylen * sizeof(*array));
1000
1001         scan = buf;
1002
1003         for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
1004                 array[argc] = scan;
1005                 for (; *scan; scan++) {
1006                         if (*scan == '(')
1007                                 paren++;
1008                         else if (*scan == ')') {
1009                                 if (paren)
1010                                         paren--;
1011                         } else if (*scan == '"' && delim != '"') {
1012                                 quote = quote ? 0 : 1;
1013                                 /* Remove quote character from argument */
1014                                 memmove(scan, scan + 1, strlen(scan));
1015                                 scan--;
1016                         } else if (*scan == '\\') {
1017                                 /* Literal character, don't parse */
1018                                 memmove(scan, scan + 1, strlen(scan));
1019                         } else if ((*scan == delim) && !paren && !quote) {
1020                                 *scan++ = '\0';
1021                                 break;
1022                         }
1023                 }
1024         }
1025
1026         if (*scan)
1027                 array[argc++] = scan;
1028
1029         return argc;
1030 }
1031
1032 static enum AST_LOCK_RESULT ast_lock_path_lockfile(const char *path)
1033 {
1034         char *s;
1035         char *fs;
1036         int res;
1037         int fd;
1038         int lp = strlen(path);
1039         time_t start;
1040
1041         s = alloca(lp + 10); 
1042         fs = alloca(lp + 20);
1043
1044         snprintf(fs, strlen(path) + 19, "%s/.lock-%08lx", path, ast_random());
1045         fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, AST_FILE_MODE);
1046         if (fd < 0) {
1047                 ast_log(LOG_ERROR, "Unable to create lock file '%s': %s\n", path, strerror(errno));
1048                 return AST_LOCK_PATH_NOT_FOUND;
1049         }
1050         close(fd);
1051
1052         snprintf(s, strlen(path) + 9, "%s/.lock", path);
1053         start = time(NULL);
1054         while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
1055                 usleep(1);
1056
1057         unlink(fs);
1058
1059         if (res) {
1060                 ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
1061                 return AST_LOCK_TIMEOUT;
1062         } else {
1063                 ast_debug(1, "Locked path '%s'\n", path);
1064                 return AST_LOCK_SUCCESS;
1065         }
1066 }
1067
1068 static int ast_unlock_path_lockfile(const char *path)
1069 {
1070         char *s;
1071         int res;
1072
1073         s = alloca(strlen(path) + 10);
1074
1075         snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
1076
1077         if ((res = unlink(s)))
1078                 ast_log(LOG_ERROR, "Could not unlock path '%s': %s\n", path, strerror(errno));
1079         else {
1080                 ast_debug(1, "Unlocked path '%s'\n", path);
1081         }
1082
1083         return res;
1084 }
1085
1086 struct path_lock {
1087         AST_LIST_ENTRY(path_lock) le;
1088         int fd;
1089         char *path;
1090 };
1091
1092 static AST_LIST_HEAD_STATIC(path_lock_list, path_lock);
1093
1094 static void path_lock_destroy(struct path_lock *obj)
1095 {
1096         if (obj->fd >= 0)
1097                 close(obj->fd);
1098         if (obj->path)
1099                 free(obj->path);
1100         free(obj);
1101 }
1102
1103 static enum AST_LOCK_RESULT ast_lock_path_flock(const char *path)
1104 {
1105         char *fs;
1106         int res;
1107         int fd;
1108         time_t start;
1109         struct path_lock *pl;
1110         struct stat st, ost;
1111
1112         fs = alloca(strlen(path) + 20);
1113
1114         snprintf(fs, strlen(path) + 19, "%s/lock", path);
1115         if (lstat(fs, &st) == 0) {
1116                 if ((st.st_mode & S_IFMT) == S_IFLNK) {
1117                         ast_log(LOG_WARNING, "Unable to create lock file "
1118                                         "'%s': it's already a symbolic link\n",
1119                                         fs);
1120                         return AST_LOCK_FAILURE;
1121                 }
1122                 if (st.st_nlink > 1) {
1123                         ast_log(LOG_WARNING, "Unable to create lock file "
1124                                         "'%s': %u hard links exist\n",
1125                                         fs, (unsigned int) st.st_nlink);
1126                         return AST_LOCK_FAILURE;
1127                 }
1128         }
1129         fd = open(fs, O_WRONLY | O_CREAT, 0600);
1130         if (fd < 0) {
1131                 ast_log(LOG_WARNING, "Unable to create lock file '%s': %s\n",
1132                                 fs, strerror(errno));
1133                 return AST_LOCK_PATH_NOT_FOUND;
1134         }
1135         pl = ast_calloc(1, sizeof(*pl));
1136         if (!pl) {
1137                 /* We don't unlink the lock file here, on the possibility that
1138                  * someone else created it - better to leave a little mess
1139                  * than create a big one by destroying someone elses lock
1140                  * and causing something to be corrupted.
1141                  */
1142                 close(fd);
1143                 return AST_LOCK_FAILURE;
1144         }
1145         pl->fd = fd;
1146         pl->path = strdup(path);
1147
1148         time(&start);
1149         while (((res = flock(pl->fd, LOCK_EX | LOCK_NB)) < 0) &&
1150                         (errno == EWOULDBLOCK) && (time(NULL) - start < 5))
1151                 usleep(1000);
1152         if (res) {
1153                 ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n",
1154                                 path, strerror(errno));
1155                 /* No unlinking of lock done, since we tried and failed to
1156                  * flock() it.
1157                  */
1158                 path_lock_destroy(pl);
1159                 return AST_LOCK_TIMEOUT;
1160         }
1161
1162         /* Check for the race where the file is recreated or deleted out from
1163          * underneath us.
1164          */
1165         if (lstat(fs, &st) != 0 && fstat(pl->fd, &ost) != 0 &&
1166                         st.st_dev != ost.st_dev &&
1167                         st.st_ino != ost.st_ino) {
1168                 ast_log(LOG_WARNING, "Unable to create lock file '%s': "
1169                                 "file changed underneath us\n", fs);
1170                 path_lock_destroy(pl);
1171                 return AST_LOCK_FAILURE;
1172         }
1173
1174         /* Success: file created, flocked, and is the one we started with */
1175         AST_LIST_LOCK(&path_lock_list);
1176         AST_LIST_INSERT_TAIL(&path_lock_list, pl, le);
1177         AST_LIST_UNLOCK(&path_lock_list);
1178
1179         ast_debug(1, "Locked path '%s'\n", path);
1180
1181         return AST_LOCK_SUCCESS;
1182 }
1183
1184 static int ast_unlock_path_flock(const char *path)
1185 {
1186         char *s;
1187         struct path_lock *p;
1188
1189         s = alloca(strlen(path) + 20);
1190
1191         AST_LIST_LOCK(&path_lock_list);
1192         AST_LIST_TRAVERSE_SAFE_BEGIN(&path_lock_list, p, le) {
1193                 if (!strcmp(p->path, path)) {
1194                         AST_LIST_REMOVE_CURRENT(&path_lock_list, le);
1195                         break;
1196                 }
1197         }
1198         AST_LIST_TRAVERSE_SAFE_END;
1199         AST_LIST_UNLOCK(&path_lock_list);
1200
1201         if (p) {
1202                 snprintf(s, strlen(path) + 19, "%s/lock", path);
1203                 unlink(s);
1204                 path_lock_destroy(p);
1205                 ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
1206         } else
1207                 ast_log(LOG_DEBUG, "Failed to unlock path '%s': "
1208                                 "lock not found\n", path);
1209
1210         return 0;
1211 }
1212
1213 void ast_set_lock_type(enum AST_LOCK_TYPE type)
1214 {
1215         ast_lock_type = type;
1216 }
1217
1218 enum AST_LOCK_RESULT ast_lock_path(const char *path)
1219 {
1220         enum AST_LOCK_RESULT r = AST_LOCK_FAILURE;
1221
1222         switch (ast_lock_type) {
1223         case AST_LOCK_TYPE_LOCKFILE:
1224                 r = ast_lock_path_lockfile(path);
1225                 break;
1226         case AST_LOCK_TYPE_FLOCK:
1227                 r = ast_lock_path_flock(path);
1228                 break;
1229         }
1230
1231         return r;
1232 }
1233
1234 int ast_unlock_path(const char *path)
1235 {
1236         int r = 0;
1237
1238         switch (ast_lock_type) {
1239         case AST_LOCK_TYPE_LOCKFILE:
1240                 r = ast_unlock_path_lockfile(path);
1241                 break;
1242         case AST_LOCK_TYPE_FLOCK:
1243                 r = ast_unlock_path_flock(path);
1244                 break;
1245         }
1246
1247         return r;
1248 }
1249
1250 int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path) 
1251 {
1252         int silencethreshold = 128; 
1253         int maxsilence = 0;
1254         int res = 0;
1255         int cmd = 0;
1256         int max_attempts = 3;
1257         int attempts = 0;
1258         int recorded = 0;
1259         int message_exists = 0;
1260         /* Note that urgent and private are for flagging messages as such in the future */
1261
1262         /* barf if no pointer passed to store duration in */
1263         if (!duration) {
1264                 ast_log(LOG_WARNING, "Error ast_record_review called without duration pointer\n");
1265                 return -1;
1266         }
1267
1268         cmd = '3';       /* Want to start by recording */
1269
1270         while ((cmd >= 0) && (cmd != 't')) {
1271                 switch (cmd) {
1272                 case '1':
1273                         if (!message_exists) {
1274                                 /* In this case, 1 is to record a message */
1275                                 cmd = '3';
1276                                 break;
1277                         } else {
1278                                 ast_stream_and_wait(chan, "vm-msgsaved", "");
1279                                 cmd = 't';
1280                                 return res;
1281                         }
1282                 case '2':
1283                         /* Review */
1284                         ast_verb(3, "Reviewing the recording\n");
1285                         cmd = ast_stream_and_wait(chan, recordfile, AST_DIGIT_ANY);
1286                         break;
1287                 case '3':
1288                         message_exists = 0;
1289                         /* Record */
1290                         if (recorded == 1)
1291                                 ast_verb(3, "Re-recording\n");
1292                         else    
1293                                 ast_verb(3, "Recording\n");
1294                         recorded = 1;
1295                         cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, path);
1296                         if (cmd == -1) {
1297                         /* User has hung up, no options to give */
1298                                 return cmd;
1299                         }
1300                         if (cmd == '0') {
1301                                 break;
1302                         } else if (cmd == '*') {
1303                                 break;
1304                         } 
1305                         else {
1306                                 /* If all is well, a message exists */
1307                                 message_exists = 1;
1308                                 cmd = 0;
1309                         }
1310                         break;
1311                 case '4':
1312                 case '5':
1313                 case '6':
1314                 case '7':
1315                 case '8':
1316                 case '9':
1317                 case '*':
1318                 case '#':
1319                         cmd = ast_play_and_wait(chan, "vm-sorry");
1320                         break;
1321                 default:
1322                         if (message_exists) {
1323                                 cmd = ast_play_and_wait(chan, "vm-review");
1324                         }
1325                         else {
1326                                 cmd = ast_play_and_wait(chan, "vm-torerecord");
1327                                 if (!cmd)
1328                                         cmd = ast_waitfordigit(chan, 600);
1329                         }
1330                         
1331                         if (!cmd)
1332                                 cmd = ast_waitfordigit(chan, 6000);
1333                         if (!cmd) {
1334                                 attempts++;
1335                         }
1336                         if (attempts > max_attempts) {
1337                                 cmd = 't';
1338                         }
1339                 }
1340         }
1341         if (cmd == 't')
1342                 cmd = 0;
1343         return cmd;
1344 }
1345
1346 #define RES_UPONE (1 << 16)
1347 #define RES_EXIT  (1 << 17)
1348 #define RES_REPEAT (1 << 18)
1349 #define RES_RESTART ((1 << 19) | RES_REPEAT)
1350
1351 static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata);
1352
1353 static int ivr_dispatch(struct ast_channel *chan, struct ast_ivr_option *option, char *exten, void *cbdata)
1354 {
1355         int res;
1356         int (*ivr_func)(struct ast_channel *, void *);
1357         char *c;
1358         char *n;
1359         
1360         switch (option->action) {
1361         case AST_ACTION_UPONE:
1362                 return RES_UPONE;
1363         case AST_ACTION_EXIT:
1364                 return RES_EXIT | (((unsigned long)(option->adata)) & 0xffff);
1365         case AST_ACTION_REPEAT:
1366                 return RES_REPEAT | (((unsigned long)(option->adata)) & 0xffff);
1367         case AST_ACTION_RESTART:
1368                 return RES_RESTART ;
1369         case AST_ACTION_NOOP:
1370                 return 0;
1371         case AST_ACTION_BACKGROUND:
1372                 res = ast_stream_and_wait(chan, (char *)option->adata, AST_DIGIT_ANY);
1373                 if (res < 0) {
1374                         ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
1375                         res = 0;
1376                 }
1377                 return res;
1378         case AST_ACTION_PLAYBACK:
1379                 res = ast_stream_and_wait(chan, (char *)option->adata, "");
1380                 if (res < 0) {
1381                         ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
1382                         res = 0;
1383                 }
1384                 return res;
1385         case AST_ACTION_MENU:
1386                 res = ast_ivr_menu_run_internal(chan, (struct ast_ivr_menu *)option->adata, cbdata);
1387                 /* Do not pass entry errors back up, treaat ast though ti was an "UPONE" */
1388                 if (res == -2)
1389                         res = 0;
1390                 return res;
1391         case AST_ACTION_WAITOPTION:
1392                 res = ast_waitfordigit(chan, 1000 * (chan->pbx ? chan->pbx->rtimeout : 10));
1393                 if (!res)
1394                         return 't';
1395                 return res;
1396         case AST_ACTION_CALLBACK:
1397                 ivr_func = option->adata;
1398                 res = ivr_func(chan, cbdata);
1399                 return res;
1400         case AST_ACTION_TRANSFER:
1401                 res = ast_parseable_goto(chan, option->adata);
1402                 return 0;
1403         case AST_ACTION_PLAYLIST:
1404         case AST_ACTION_BACKLIST:
1405                 res = 0;
1406                 c = ast_strdupa(option->adata);
1407                 while ((n = strsep(&c, ";"))) {
1408                         if ((res = ast_stream_and_wait(chan, n,
1409                                         (option->action == AST_ACTION_BACKLIST) ? AST_DIGIT_ANY : "")))
1410                                 break;
1411                 }
1412                 ast_stopstream(chan);
1413                 return res;
1414         default:
1415                 ast_log(LOG_NOTICE, "Unknown dispatch function %d, ignoring!\n", option->action);
1416                 return 0;
1417         };
1418         return -1;
1419 }
1420
1421 static int option_exists(struct ast_ivr_menu *menu, char *option)
1422 {
1423         int x;
1424         for (x = 0; menu->options[x].option; x++)
1425                 if (!strcasecmp(menu->options[x].option, option))
1426                         return x;
1427         return -1;
1428 }
1429
1430 static int option_matchmore(struct ast_ivr_menu *menu, char *option)
1431 {
1432         int x;
1433         for (x = 0; menu->options[x].option; x++)
1434                 if ((!strncasecmp(menu->options[x].option, option, strlen(option))) && 
1435                                 (menu->options[x].option[strlen(option)]))
1436                         return x;
1437         return -1;
1438 }
1439
1440 static int read_newoption(struct ast_channel *chan, struct ast_ivr_menu *menu, char *exten, int maxexten)
1441 {
1442         int res=0;
1443         int ms;
1444         while (option_matchmore(menu, exten)) {
1445                 ms = chan->pbx ? chan->pbx->dtimeout : 5000;
1446                 if (strlen(exten) >= maxexten - 1) 
1447                         break;
1448                 res = ast_waitfordigit(chan, ms);
1449                 if (res < 1)
1450                         break;
1451                 exten[strlen(exten) + 1] = '\0';
1452                 exten[strlen(exten)] = res;
1453         }
1454         return res > 0 ? 0 : res;
1455 }
1456
1457 static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
1458 {
1459         /* Execute an IVR menu structure */
1460         int res=0;
1461         int pos = 0;
1462         int retries = 0;
1463         char exten[AST_MAX_EXTENSION] = "s";
1464         if (option_exists(menu, "s") < 0) {
1465                 strcpy(exten, "g");
1466                 if (option_exists(menu, "g") < 0) {
1467                         ast_log(LOG_WARNING, "No 's' nor 'g' extension in menu '%s'!\n", menu->title);
1468                         return -1;
1469                 }
1470         }
1471         while (!res) {
1472                 while (menu->options[pos].option) {
1473                         if (!strcasecmp(menu->options[pos].option, exten)) {
1474                                 res = ivr_dispatch(chan, menu->options + pos, exten, cbdata);
1475                                 ast_debug(1, "IVR Dispatch of '%s' (pos %d) yields %d\n", exten, pos, res);
1476                                 if (res < 0)
1477                                         break;
1478                                 else if (res & RES_UPONE)
1479                                         return 0;
1480                                 else if (res & RES_EXIT)
1481                                         return res;
1482                                 else if (res & RES_REPEAT) {
1483                                         int maxretries = res & 0xffff;
1484                                         if ((res & RES_RESTART) == RES_RESTART) {
1485                                                 retries = 0;
1486                                         } else
1487                                                 retries++;
1488                                         if (!maxretries)
1489                                                 maxretries = 3;
1490                                         if ((maxretries > 0) && (retries >= maxretries)) {
1491                                                 ast_debug(1, "Max retries %d exceeded\n", maxretries);
1492                                                 return -2;
1493                                         } else {
1494                                                 if (option_exists(menu, "g") > -1) 
1495                                                         strcpy(exten, "g");
1496                                                 else if (option_exists(menu, "s") > -1)
1497                                                         strcpy(exten, "s");
1498                                         }
1499                                         pos = 0;
1500                                         continue;
1501                                 } else if (res && strchr(AST_DIGIT_ANY, res)) {
1502                                         ast_debug(1, "Got start of extension, %c\n", res);
1503                                         exten[1] = '\0';
1504                                         exten[0] = res;
1505                                         if ((res = read_newoption(chan, menu, exten, sizeof(exten))))
1506                                                 break;
1507                                         if (option_exists(menu, exten) < 0) {
1508                                                 if (option_exists(menu, "i")) {
1509                                                         ast_debug(1, "Invalid extension entered, going to 'i'!\n");
1510                                                         strcpy(exten, "i");
1511                                                         pos = 0;
1512                                                         continue;
1513                                                 } else {
1514                                                         ast_debug(1, "Aborting on invalid entry, with no 'i' option!\n");
1515                                                         res = -2;
1516                                                         break;
1517                                                 }
1518                                         } else {
1519                                                 ast_debug(1, "New existing extension: %s\n", exten);
1520                                                 pos = 0;
1521                                                 continue;
1522                                         }
1523                                 }
1524                         }
1525                         pos++;
1526                 }
1527                 ast_debug(1, "Stopping option '%s', res is %d\n", exten, res);
1528                 pos = 0;
1529                 if (!strcasecmp(exten, "s"))
1530                         strcpy(exten, "g");
1531                 else
1532                         break;
1533         }
1534         return res;
1535 }
1536
1537 int ast_ivr_menu_run(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
1538 {
1539         int res = ast_ivr_menu_run_internal(chan, menu, cbdata);
1540         /* Hide internal coding */
1541         return res > 0 ? 0 : res;
1542 }
1543         
1544 char *ast_read_textfile(const char *filename)
1545 {
1546         int fd, count = 0, res;
1547         char *output = NULL;
1548         struct stat filesize;
1549
1550         if (stat(filename, &filesize) == -1) {
1551                 ast_log(LOG_WARNING, "Error can't stat %s\n", filename);
1552                 return NULL;
1553         }
1554
1555         count = filesize.st_size + 1;
1556
1557         if ((fd = open(filename, O_RDONLY)) < 0) {
1558                 ast_log(LOG_WARNING, "Cannot open file '%s' for reading: %s\n", filename, strerror(errno));
1559                 return NULL;
1560         }
1561
1562         if ((output = ast_malloc(count))) {
1563                 res = read(fd, output, count - 1);
1564                 if (res == count - 1) {
1565                         output[res] = '\0';
1566                 } else {
1567                         ast_log(LOG_WARNING, "Short read of %s (%d of %d): %s\n", filename, res, count - 1, strerror(errno));
1568                         ast_free(output);
1569                         output = NULL;
1570                 }
1571         }
1572
1573         close(fd);
1574
1575         return output;
1576 }
1577
1578 int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
1579 {
1580         char *s, *arg;
1581         int curarg, res = 0;
1582         unsigned int argloc;
1583
1584         ast_clear_flag(flags, AST_FLAGS_ALL);
1585
1586         if (!optstr)
1587                 return 0;
1588
1589         s = optstr;
1590         while (*s) {
1591                 curarg = *s++ & 0x7f;   /* the array (in app.h) has 128 entries */
1592                 ast_set_flag(flags, options[curarg].flag);
1593                 argloc = options[curarg].arg_index;
1594                 if (*s == '(') {
1595                         /* Has argument */
1596                         arg = ++s;
1597                         if ((s = strchr(s, ')'))) {
1598                                 if (argloc)
1599                                         args[argloc - 1] = arg;
1600                                 *s++ = '\0';
1601                         } else {
1602                                 ast_log(LOG_WARNING, "Missing closing parenthesis for argument '%c' in string '%s'\n", curarg, arg);
1603                                 res = -1;
1604                                 break;
1605                         }
1606                 } else if (argloc) {
1607                         args[argloc - 1] = NULL;
1608                 }
1609         }
1610
1611         return res;
1612 }
1613
1614 /* the following function will probably only be used in app_dial, until app_dial is reorganized to
1615    better handle the large number of options it provides. After it is, you need to get rid of this variant 
1616    -- unless, of course, someone else digs up some use for large flag fields. */
1617
1618 int ast_app_parse_options64(const struct ast_app_option *options, struct ast_flags64 *flags, char **args, char *optstr)
1619 {
1620         char *s, *arg;
1621         int curarg, res = 0;
1622         unsigned int argloc;
1623
1624         flags->flags = 0;
1625         
1626         if (!optstr)
1627                 return 0;
1628
1629         s = optstr;
1630         while (*s) {
1631                 curarg = *s++ & 0x7f;   /* the array (in app.h) has 128 entries */
1632                 ast_set_flag64(flags, options[curarg].flag);
1633                 argloc = options[curarg].arg_index;
1634                 if (*s == '(') {
1635                         /* Has argument */
1636                         arg = ++s;
1637                         if ((s = strchr(s, ')'))) {
1638                                 if (argloc)
1639                                         args[argloc - 1] = arg;
1640                                 *s++ = '\0';
1641                         } else {
1642                                 ast_log(LOG_WARNING, "Missing closing parenthesis for argument '%c' in string '%s'\n", curarg, arg);
1643                                 res = -1;
1644                                 break;
1645                         }
1646                 } else if (argloc) {
1647                         args[argloc - 1] = NULL;
1648                 }
1649         }
1650
1651         return res;
1652 }
1653