simplify autoconfig include mechanism (make tholo happy he can use lint again :-)
[asterisk/asterisk.git] / app.c
diff --git a/app.c b/app.c
index 0bd8612..13b402e 100644 (file)
--- a/app.c
+++ b/app.c
  * \author Mark Spencer <markster@digium.com> 
  */
 
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <regex.h>
 
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
 #include "asterisk/channel.h"
 #include "asterisk/pbx.h"
 #include "asterisk/file.h"
@@ -144,102 +144,23 @@ int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxle
        return res;
 }
 
-int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec)
-{
-       int res;
-       struct ast_filestream *writer;
-       int rfmt;
-       int totalms=0, total;
-       
-       struct ast_frame *f;
-       struct ast_dsp *sildet;
-       /* Play prompt if requested */
-       if (prompt) {
-               res = ast_streamfile(c, prompt, c->language);
-               if (res < 0)
-                       return res;
-               res = ast_waitstream(c,"");
-               if (res < 0)
-                       return res;
-       }
-       rfmt = c->readformat;
-       res = ast_set_read_format(c, AST_FORMAT_SLINEAR);
-       if (res < 0) {
-               ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
-               return -1;
-       }
-       sildet = ast_dsp_new();
-       if (!sildet) {
-               ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
-               return -1;
-       }
-       writer = ast_writefile(dest, dstfmt, "Voice file", 0, 0, 0666);
-       if (!writer) {
-               ast_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt);
-               ast_dsp_free(sildet);
-               return -1;
-       }
-       for(;;) {
-               if ((res = ast_waitfor(c, 2000)) < 0) {
-                       ast_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt);
-                       break;
-               }
-               if (res) {
-                       f = ast_read(c);
-                       if (!f) {
-                               ast_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt);
-                               break;
-                       }
-                       if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
-                               /* Ended happily with DTMF */
-                               ast_frfree(f);
-                               break;
-                       } else if (f->frametype == AST_FRAME_VOICE) {
-                               ast_dsp_silence(sildet, f, &total); 
-                               if (total > silence) {
-                                       /* Ended happily with silence */
-                                       ast_frfree(f);
-                                       break;
-                               }
-                               totalms += f->samples / 8;
-                               if (totalms > maxsec * 1000) {
-                                       /* Ended happily with too much stuff */
-                                       ast_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec);
-                                       ast_frfree(f);
-                                       break;
-                               }
-                               res = ast_writestream(writer, f);
-                               if (res < 0) {
-                                       ast_log(LOG_WARNING, "Failed to write to stream at %s!\n", dest);
-                                       ast_frfree(f);
-                                       break;
-                               }
-                                       
-                       }
-                       ast_frfree(f);
-               }
-       }
-       res = ast_set_read_format(c, rfmt);
-       if (res)
-               ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name);
-       ast_dsp_free(sildet);
-       ast_closestream(writer);
-       return 0;
-}
-
 static int (*ast_has_voicemail_func)(const char *mailbox, const char *folder) = NULL;
-static int (*ast_messagecount_func)(const char *mailbox, int *newmsgs, int *oldmsgs) = NULL;
+static int (*ast_inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsgs) = NULL;
+static int (*ast_messagecount_func)(const char *context, const char *mailbox, const char *folder) = NULL;
 
 void ast_install_vm_functions(int (*has_voicemail_func)(const char *mailbox, const char *folder),
-                             int (*messagecount_func)(const char *mailbox, int *newmsgs, int *oldmsgs))
+                             int (*inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsgs),
+                             int (*messagecount_func)(const char *context, const char *mailbox, const char *folder))
 {
        ast_has_voicemail_func = has_voicemail_func;
+       ast_inboxcount_func = inboxcount_func;
        ast_messagecount_func = messagecount_func;
 }
 
 void ast_uninstall_vm_functions(void)
 {
        ast_has_voicemail_func = NULL;
+       ast_inboxcount_func = NULL;
        ast_messagecount_func = NULL;
 }
 
@@ -257,15 +178,15 @@ int ast_app_has_voicemail(const char *mailbox, const char *folder)
 }
 
 
-int ast_app_messagecount(const char *mailbox, int *newmsgs, int *oldmsgs)
+int ast_app_inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
 {
        static int warned = 0;
        if (newmsgs)
                *newmsgs = 0;
        if (oldmsgs)
                *oldmsgs = 0;
-       if (ast_messagecount_func)
-               return ast_messagecount_func(mailbox, newmsgs, oldmsgs);
+       if (ast_inboxcount_func)
+               return ast_inboxcount_func(mailbox, newmsgs, oldmsgs);
 
        if (!warned && (option_verbose > 2)) {
                warned++;
@@ -275,6 +196,20 @@ int ast_app_messagecount(const char *mailbox, int *newmsgs, int *oldmsgs)
        return 0;
 }
 
+int ast_app_messagecount(const char *context, const char *mailbox, const char *folder)
+{
+       static int warned = 0;
+       if (ast_messagecount_func)
+               return ast_messagecount_func(context, mailbox, folder);
+
+       if (!warned && (option_verbose > 2)) {
+               warned++;
+               ast_verbose(VERBOSE_PREFIX_3 "Message count requested for mailbox %s@%s/%s but voicemail not loaded.\n", mailbox, context, folder);
+       }
+
+       return 0;
+}
+
 int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between) 
 {
        const char *ptr;
@@ -414,7 +349,7 @@ int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, in
                if (filename[0] == '/') 
                        ast_copy_string(tmpf, filename, sizeof(tmpf));
                else
-                       snprintf(tmpf, sizeof(tmpf), "%s/%s/%s", (char *)ast_config_AST_VAR_DIR, "sounds", filename);
+                       snprintf(tmpf, sizeof(tmpf), "%s/%s/%s", (char *)ast_config_AST_DATA_DIR, "sounds", filename);
                fd = open(tmpf, O_RDONLY);
                if (fd < 0){
                        ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", tmpf, strerror(errno));
@@ -538,23 +473,37 @@ int ast_play_and_wait(struct ast_channel *chan, const char *fn)
 static int global_silence_threshold = 128;
 static int global_maxsilence = 0;
 
-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)
+/*! Optionally play a sound file or a beep, then record audio and video from the channel.
+ * @param chan Channel to playback to/record from.
+ * @param playfile Filename of sound to play before recording begins.
+ * @param recordfile Filename to record to.
+ * @param maxtime Maximum length of recording (in milliseconds).
+ * @param fmt Format(s) to record message in. Multiple formats may be specified by separating them with a '|'.
+ * @param duration Where to store actual length of the recorded message (in milliseconds).
+ * @param beep Whether to play a beep before starting to record.
+ * @param silencethreshold 
+ * @param maxsilence Length of silence that will end a recording (in milliseconds).
+ * @param path Optional filesystem path to unlock.
+ * @param prepend If true, prepend the recorded audio to an existing file.
+ * @param acceptdtmf DTMF digits that will end the recording.
+ * @param canceldtmf DTMF digits that will cancel the recording.
+ */
+
+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)
 {
-       int d;
+       int d = 0;
        char *fmts;
        char comment[256];
-       int x, fmtcnt=1, res=-1,outmsg=0;
-       struct ast_frame *f;
+       int x, fmtcnt = 1, res = -1, outmsg = 0;
        struct ast_filestream *others[MAX_OTHER_FORMATS];
        char *sfmt[MAX_OTHER_FORMATS];
-       char *stringp=NULL;
+       char *stringp = NULL;
        time_t start, end;
-       struct ast_dsp *sildet=NULL;    /* silence detector dsp */
+       struct ast_dsp *sildet = NULL;   /* silence detector dsp */
        int totalsilence = 0;
-       int dspsilence = 0;
-       int gotsilence = 0;             /* did we timeout for silence? */
-       int rfmt=0;
+       int rfmt = 0;
        struct ast_silence_generator *silgen = NULL;
+       char prependfile[80];
 
        if (silencethreshold < 0)
                silencethreshold = global_silence_threshold;
@@ -569,26 +518,30 @@ int ast_play_and_record(struct ast_channel *chan, const char *playfile, const ch
        }
 
        ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
-       snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
+       snprintf(comment, sizeof(comment), "Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
 
-       if (playfile) {
-               d = ast_play_and_wait(chan, playfile);
+       if (playfile || beep) {
+               if (!beep)
+                       d = ast_play_and_wait(chan, playfile);
                if (d > -1)
-                       d = ast_streamfile(chan, "beep",chan->language);
-               if (!d)
-                       d = ast_waitstream(chan,"");
+                       d = ast_stream_and_wait(chan, "beep", chan->language, "");
                if (d < 0)
                        return -1;
        }
 
+       if (prepend) {
+               ast_copy_string(prependfile, recordfile, sizeof(prependfile));  
+               strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
+       }
+
        fmts = ast_strdupa(fmt);
 
-       stringp=fmts;
+       stringp = fmts;
        strsep(&stringp, "|");
        ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
        sfmt[0] = ast_strdupa(fmts);
 
-       while((fmt = strsep(&stringp, "|"))) {
+       while ((fmt = strsep(&stringp, "|"))) {
                if (fmtcnt > MAX_OTHER_FORMATS - 1) {
                        ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app.c\n");
                        break;
@@ -596,11 +549,11 @@ int ast_play_and_record(struct ast_channel *chan, const char *playfile, const ch
                sfmt[fmtcnt++] = ast_strdupa(fmt);
        }
 
-       time(&start);
-       end=start;  /* pre-initialize end to be same as start in case we never get into loop */
-       for (x=0;x<fmtcnt;x++) {
-               others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
-               ast_verbose( VERBOSE_PREFIX_3 "x=%d, open writing:  %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
+       end = start = time(NULL);  /* pre-initialize end to be same as start in case we never get into loop */
+       for (x = 0; x < fmtcnt; x++) {
+               others[x] = ast_writefile(prepend ? prependfile : recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
+               if (option_verbose > 2)
+                       ast_verbose(VERBOSE_PREFIX_3 "x=%d, open writing:  %s format: %s, %p\n", x, prepend ? prependfile : recordfile, sfmt[x], others[x]);
 
                if (!others[x]) {
                        break;
@@ -626,17 +579,19 @@ int ast_play_and_record(struct ast_channel *chan, const char *playfile, const ch
                }
        }
 
-       /* Request a video update */
-       ast_indicate(chan, AST_CONTROL_VIDUPDATE);
+       if (!prepend) {
+               /* Request a video update */
+               ast_indicate(chan, AST_CONTROL_VIDUPDATE);
 
-       if (ast_opt_transmit_silence)
-               silgen = ast_channel_start_silence_generator(chan);
+               if (ast_opt_transmit_silence)
+                       silgen = ast_channel_start_silence_generator(chan);
+       }
 
        if (x == fmtcnt) {
-       /* Loop forever, writing the packets we read to the writer(s), until
-          we read a # or get a hangup */
-               f = NULL;
-               for(;;) {
+               /* Loop forever, writing the packets we read to the writer(s), until
+                  we read a digit or get a hangup */
+               struct ast_frame *f;
+               for (;;) {
                        res = ast_waitfor(chan, 2000);
                        if (!res) {
                                ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
@@ -657,13 +612,15 @@ int ast_play_and_record(struct ast_channel *chan, const char *playfile, const ch
                                break;
                        if (f->frametype == AST_FRAME_VOICE) {
                                /* write each format */
-                               for (x=0;x<fmtcnt;x++) {
+                               for (x = 0; x < fmtcnt; x++) {
+                                       if (prepend && !others[x])
+                                               break;
                                        res = ast_writestream(others[x], f);
                                }
 
                                /* Silence Detection */
                                if (maxsilence > 0) {
-                                       dspsilence = 0;
+                                       int dspsilence = 0;
                                        ast_dsp_silence(sildet, f, &dspsilence);
                                        if (dspsilence)
                                                totalsilence = dspsilence;
@@ -674,331 +631,139 @@ int ast_play_and_record(struct ast_channel *chan, const char *playfile, const ch
                                                /* Ended happily with silence */
                                                if (option_verbose > 2)
                                                        ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
-                                               ast_frfree(f);
-                                               gotsilence = 1;
-                                               outmsg=2;
+                                               res = 'S';
+                                               outmsg = 2;
                                                break;
                                        }
                                }
                                /* Exit on any error */
                                if (res) {
                                        ast_log(LOG_WARNING, "Error writing frame\n");
-                                       ast_frfree(f);
                                        break;
                                }
                        } else if (f->frametype == AST_FRAME_VIDEO) {
                                /* Write only once */
                                ast_writestream(others[0], f);
                        } else if (f->frametype == AST_FRAME_DTMF) {
-                               if (f->subclass == '#') {
+                               if (prepend) {
+                               /* stop recording with any digit */
+                                       if (option_verbose > 2) 
+                                               ast_verbose(VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
+                                       res = 't';
+                                       outmsg = 2;
+                                       break;
+                               }
+                               if (strchr(acceptdtmf, f->subclass)) {
                                        if (option_verbose > 2)
-                                               ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
-                                       res = '#';
+                                               ast_verbose(VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
+                                       res = f->subclass;
                                        outmsg = 2;
-                                       ast_frfree(f);
                                        break;
                                }
-                               if (f->subclass == '0') {
-                               /* Check for a '0' during message recording also, in case caller wants operator */
+                               if (strchr(canceldtmf, f->subclass)) {
                                        if (option_verbose > 2)
-                                               ast_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass);
-                                       res = '0';
+                                               ast_verbose(VERBOSE_PREFIX_3 "User cancelled message by pressing %c\n", f->subclass);
+                                       res = f->subclass;
                                        outmsg = 0;
-                                       ast_frfree(f);
                                        break;
                                }
                        }
                        if (maxtime) {
-                               time(&end);
+                               end = time(NULL);
                                if (maxtime < (end - start)) {
                                        if (option_verbose > 2)
-                                               ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
-                                       outmsg = 2;
+                                               ast_verbose(VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
                                        res = 't';
-                                       ast_frfree(f);
+                                       outmsg = 2;
                                        break;
                                }
                        }
                        ast_frfree(f);
                }
-               if (end == start) time(&end);
                if (!f) {
                        if (option_verbose > 2)
-                               ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
+                               ast_verbose(VERBOSE_PREFIX_3 "User hung up\n");
                        res = -1;
-                       outmsg=1;
+                       outmsg = 1;
+               } else {
+                       ast_frfree(f);
                }
+               if (end == start)
+                       end = time(NULL);
        } else {
                ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
        }
 
-       if (silgen)
-               ast_channel_stop_silence_generator(chan, silgen);
-
-       *duration = end - start;
-
-       for (x=0;x<fmtcnt;x++) {
-               if (!others[x])
-                       break;
-               if (res > 0) {
-                       if (totalsilence)
-                               ast_stream_rewind(others[x], totalsilence-200);
-                       else
-                               ast_stream_rewind(others[x], 200);
-               }
-               ast_truncstream(others[x]);
-               ast_closestream(others[x]);
-       }
-       if (rfmt) {
-               if (ast_set_read_format(chan, rfmt)) {
-                       ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
-               }
-       }
-       if (outmsg > 1) {
-               /* Let them know recording is stopped */
-               if(!ast_streamfile(chan, "auth-thankyou", chan->language))
-                       ast_waitstream(chan, "");
-       }
-       if (sildet)
-               ast_dsp_free(sildet);
-       return res;
-}
-
-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)
-{
-       int d = 0;
-       char *fmts;
-       char comment[256];
-       int x, fmtcnt=1, res=-1,outmsg=0;
-       struct ast_frame *f;
-       struct ast_filestream *others[MAX_OTHER_FORMATS];
-       struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
-       char *sfmt[MAX_OTHER_FORMATS];
-       char *stringp=NULL;
-       time_t start, end;
-       struct ast_dsp *sildet;         /* silence detector dsp */
-       int totalsilence = 0;
-       int dspsilence = 0;
-       int gotsilence = 0;             /* did we timeout for silence? */
-       int rfmt=0;     
-       char prependfile[80];
-       
-       if (silencethreshold < 0)
-               silencethreshold = global_silence_threshold;
-
-       if (maxsilence < 0)
-               maxsilence = global_maxsilence;
-
-       /* barf if no pointer passed to store duration in */
-       if (duration == NULL) {
-               ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n");
-               return -1;
-       }
-
-       ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
-       snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
-
-       if (playfile || beep) { 
-               if (!beep)
-                       d = ast_play_and_wait(chan, playfile);
-               if (d > -1)
-                       d = ast_streamfile(chan, "beep",chan->language);
-               if (!d)
-                       d = ast_waitstream(chan,"");
-               if (d < 0)
-                       return -1;
+       if (!prepend) {
+               if (silgen)
+                       ast_channel_stop_silence_generator(chan, silgen);
        }
-       ast_copy_string(prependfile, recordfile, sizeof(prependfile));  
-       strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
-                       
-       fmts = ast_strdupa(fmt);
-       
-       stringp=fmts;
-       strsep(&stringp, "|");
-       ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);       
-       sfmt[0] = ast_strdupa(fmts);
-       
-       while((fmt = strsep(&stringp, "|"))) {
-               if (fmtcnt > MAX_OTHER_FORMATS - 1) {
-                       ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app.c\n");
-                       break;
-               }
-               sfmt[fmtcnt++] = ast_strdupa(fmt);
-       }
-
-       time(&start);
-       end=start;  /* pre-initialize end to be same as start in case we never get into loop */
-       for (x=0;x<fmtcnt;x++) {
-               others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
-               ast_verbose( VERBOSE_PREFIX_3 "x=%d, open writing:  %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
-               if (!others[x]) {
-                       break;
-               }
-       }
-       
-       sildet = ast_dsp_new(); /* Create the silence detector */
-       if (!sildet) {
-               ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
-               return -1;
-       }
-       ast_dsp_set_threshold(sildet, silencethreshold);
+       *duration = end - start;
 
-       if (maxsilence > 0) {
-               rfmt = chan->readformat;
-               res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
-               if (res < 0) {
-                       ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
-                       ast_dsp_free(sildet);
-                       return -1;
-               }
-       }
-                                               
-       if (x == fmtcnt) {
-       /* Loop forever, writing the packets we read to the writer(s), until
-          we read a # or get a hangup */
-               f = NULL;
-               for(;;) {
-                       res = ast_waitfor(chan, 2000);
-                       if (!res) {
-                               ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
-                               /* Try one more time in case of masq */
-                               res = ast_waitfor(chan, 2000);
-                               if (!res) {
-                                       ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
-                                       res = -1;
-                               }
-                       }
-                       
-                       if (res < 0) {
-                               f = NULL;
-                               break;
-                       }
-                       f = ast_read(chan);
-                       if (!f)
-                               break;
-                       if (f->frametype == AST_FRAME_VOICE) {
-                               /* write each format */
-                               for (x=0;x<fmtcnt;x++) {
-                                       if (!others[x])
-                                               break;
-                                       res = ast_writestream(others[x], f);
-                               }
-                               
-                               /* Silence Detection */
-                               if (maxsilence > 0) {
-                                       dspsilence = 0;
-                                       ast_dsp_silence(sildet, f, &dspsilence);
-                                       if (dspsilence)
-                                               totalsilence = dspsilence;
-                                       else
-                                               totalsilence = 0;
-                                       
-                                       if (totalsilence > maxsilence) {
-                                       /* Ended happily with silence */
-                                       if (option_verbose > 2) 
-                                               ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
-                                       ast_frfree(f);
-                                       gotsilence = 1;
-                                       outmsg=2;
-                                       break;
-                                       }
-                               }
-                               /* Exit on any error */
-                               if (res) {
-                                       ast_log(LOG_WARNING, "Error writing frame\n");
-                                       ast_frfree(f);
-                                       break;
-                               }
-                       } else if (f->frametype == AST_FRAME_VIDEO) {
-                               /* Write only once */
-                               ast_writestream(others[0], f);
-                       } else if (f->frametype == AST_FRAME_DTMF) {
-                               /* stop recording with any digit */
-                               if (option_verbose > 2) 
-                                       ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
-                               res = 't';
-                               outmsg = 2;
-                               ast_frfree(f);
+       if (!prepend) {
+               for (x = 0; x < fmtcnt; x++) {
+                       if (!others[x])
                                break;
-                       }
-                       if (maxtime) {
-                               time(&end);
-                               if (maxtime < (end - start)) {
-                                       if (option_verbose > 2)
-                                               ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
-                                       res = 't';
-                                       outmsg=2;
-                                       ast_frfree(f);
-                                       break;
-                               }
-                       }
-                       ast_frfree(f);
-               }
-               if (end == start) time(&end);
-               if (!f) {
-                       if (option_verbose > 2) 
-                               ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
-                       res = -1;
-                       outmsg=1;
-#if 0
-                       /* delete all the prepend files */
-                       for (x=0;x<fmtcnt;x++) {
-                               if (!others[x])
-                                       break;
-                               ast_closestream(others[x]);
-                               ast_filedelete(prependfile, sfmt[x]);
-                       }
-#endif
+                       if (res > 0)
+                               ast_stream_rewind(others[x], totalsilence ? totalsilence-200 : 200);
+                       ast_truncstream(others[x]);
+                       ast_closestream(others[x]);
                }
-       } else {
-               ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]); 
        }
-       ast_dsp_free(sildet);
-       *duration = end - start;
-#if 0
-       if (outmsg > 1) {
-#else
-       if (outmsg) {
-#endif
+
+       if (prepend && outmsg) {
+               struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
                struct ast_frame *fr;
-               for (x=0;x<fmtcnt;x++) {
+
+               for (x = 0; x < fmtcnt; x++) {
                        snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
                        realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
                        if (!others[x] || !realfiles[x])
                                break;
-                       if (totalsilence)
-                               ast_stream_rewind(others[x], totalsilence-200);
-                       else
-                               ast_stream_rewind(others[x], 200);
+                       ast_stream_rewind(others[x], totalsilence ? totalsilence-200 : 200);
                        ast_truncstream(others[x]);
                        /* add the original file too */
                        while ((fr = ast_readframe(realfiles[x]))) {
-                               ast_writestream(others[x],fr);
+                               ast_writestream(others[x], fr);
+                               ast_frfree(fr);
                        }
                        ast_closestream(others[x]);
                        ast_closestream(realfiles[x]);
                        ast_filerename(prependfile, recordfile, sfmt[x]);
-#if 0
-                       ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
-#endif
+                       if (option_verbose > 3)
+                               ast_verbose(VERBOSE_PREFIX_4 "Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x], prependfile, recordfile);
                        ast_filedelete(prependfile, sfmt[x]);
                }
        }
-       if (rfmt) {
-               if (ast_set_read_format(chan, rfmt)) {
-                       ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
-               }
+       if (rfmt && ast_set_read_format(chan, rfmt)) {
+               ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
        }
-       if (outmsg) {
-               if (outmsg > 1) {
-                       /* Let them know it worked */
-                       ast_streamfile(chan, "auth-thankyou", chan->language);
-                       ast_waitstream(chan, "");
-               }
-       }       
+       if (outmsg == 2) {
+               ast_stream_and_wait(chan, "auth-thankyou", chan->language, "");
+       }
+       if (sildet)
+               ast_dsp_free(sildet);
        return res;
 }
 
+static char default_acceptdtmf[] = "#";
+static char default_canceldtmf[] = "";
+
+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)
+{
+       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));
+}
+
+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)
+{
+       return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, 0, silencethreshold, maxsilence, path, 0, default_acceptdtmf, default_canceldtmf);
+}
+
+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)
+{
+       return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, beep, silencethreshold, maxsilence, NULL, 1, default_acceptdtmf, default_canceldtmf);
+}
+
 /* Channel group core functions */
 
 int ast_app_group_split_group(const char *data, char *group, int group_max, char *category, int category_max)
@@ -1063,7 +828,7 @@ int ast_app_group_get_count(const char *group, const char *category)
                test = pbx_builtin_getvar_helper(chan, cat);
                if (test && !strcasecmp(test, group))
                        count++;
-               ast_mutex_unlock(&chan->lock);
+               ast_channel_unlock(chan);
        }
 
        return count;
@@ -1093,7 +858,7 @@ int ast_app_group_match_get_count(const char *groupmatch, const char *category)
                test = pbx_builtin_getvar_helper(chan, cat);
                if (test && !regexec(&regexbuf, test, 0, NULL, 0))
                        count++;
-               ast_mutex_unlock(&chan->lock);
+               ast_channel_unlock(chan);
        }
 
        regfree(&regexbuf);
@@ -1157,7 +922,7 @@ enum AST_LOCK_RESULT ast_lock_path(const char *path)
                return AST_LOCK_FAILURE;
        }
 
-       snprintf(fs, strlen(path) + 19, "%s/.lock-%08x", path, rand());
+       snprintf(fs, strlen(path) + 19, "%s/.lock-%08lx", path, ast_random());
        fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
        if (fd < 0) {
                fprintf(stderr, "Unable to create lock file '%s': %s\n", path, strerror(errno));
@@ -1166,7 +931,7 @@ enum AST_LOCK_RESULT ast_lock_path(const char *path)
        close(fd);
 
        snprintf(s, strlen(path) + 9, "%s/.lock", path);
-       time(&start);
+       start = time(NULL);
        while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
                usleep(1);
        if (res) {
@@ -1217,16 +982,14 @@ int ast_record_review(struct ast_channel *chan, const char *playfile, const char
                                cmd = '3';
                                break;
                        } else {
-                               ast_streamfile(chan, "vm-msgsaved", chan->language);
-                               ast_waitstream(chan, "");
+                               ast_stream_and_wait(chan, "vm-msgsaved", chan->language, "");
                                cmd = 't';
                                return res;
                        }
                case '2':
                        /* Review */
                        ast_verbose(VERBOSE_PREFIX_3 "Reviewing the recording\n");
-                       ast_streamfile(chan, recordfile, chan->language);
-                       cmd = ast_waitstream(chan, AST_DIGIT_ANY);
+                       cmd = ast_stream_and_wait(chan, recordfile, chan->language, AST_DIGIT_ANY);
                        break;
                case '3':
                        message_exists = 0;
@@ -1312,19 +1075,15 @@ static int ivr_dispatch(struct ast_channel *chan, struct ast_ivr_option *option,
        case AST_ACTION_NOOP:
                return 0;
        case AST_ACTION_BACKGROUND:
-               res = ast_streamfile(chan, (char *)option->adata, chan->language);
-               if (!res) {
-                       res = ast_waitstream(chan, AST_DIGIT_ANY);
-               } else {
+               res = ast_stream_and_wait(chan, (char *)option->adata, chan->language, AST_DIGIT_ANY);
+               if (res < 0) {
                        ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
                        res = 0;
                }
                return res;
        case AST_ACTION_PLAYBACK:
-               res = ast_streamfile(chan, (char *)option->adata, chan->language);
-               if (!res) {
-                       res = ast_waitstream(chan, "");
-               } else {
+               res = ast_stream_and_wait(chan, (char *)option->adata, chan->language, "");
+               if (res < 0) {
                        ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
                        res = 0;
                }
@@ -1351,12 +1110,12 @@ static int ivr_dispatch(struct ast_channel *chan, struct ast_ivr_option *option,
        case AST_ACTION_BACKLIST:
                res = 0;
                c = ast_strdupa(option->adata);
-               if (c) {
-                       while((n = strsep(&c, ";")))
-                               if ((res = ast_streamfile(chan, n, chan->language)) || (res = ast_waitstream(chan, (option->action == AST_ACTION_BACKLIST) ? AST_DIGIT_ANY : "")))
-                                       break;
-                       ast_stopstream(chan);
+               while ((n = strsep(&c, ";"))) {
+                       if ((res = ast_stream_and_wait(chan, n, chan->language,
+                                       (option->action == AST_ACTION_BACKLIST) ? AST_DIGIT_ANY : "")))
+                               break;
                }
+               ast_stopstream(chan);
                return res;
        default:
                ast_log(LOG_NOTICE, "Unknown dispatch function %d, ignoring!\n", option->action);