make datastore creation and destruction a generic API since it is not really channel...
[asterisk/asterisk.git] / res / res_agi.c
index ae87391..8cfc391 100644 (file)
@@ -20,7 +20,7 @@
  *
  * \brief AGI - the Asterisk Gateway Interface
  *
- * \author Mark Spencer <markster@digium.com> 
+ * \author Mark Spencer <markster@digium.com>
  */
 
 #include "asterisk.h"
@@ -100,10 +100,10 @@ static int agidebug = 0;
 #define AGI_PORT 4573
 
 enum agi_result {
+       AGI_RESULT_FAILURE = -1,
        AGI_RESULT_SUCCESS,
        AGI_RESULT_SUCCESS_FAST,
        AGI_RESULT_SUCCESS_ASYNC,
-       AGI_RESULT_FAILURE,
        AGI_RESULT_NOTFOUND,
        AGI_RESULT_HANGUP,
 };
@@ -162,9 +162,9 @@ static void agi_destroy_commands_cb(void *data)
        struct agi_cmd *cmd;
        AST_LIST_HEAD(, agi_cmd) *chan_cmds = data;
        AST_LIST_LOCK(chan_cmds);
-       while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) { 
+       while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) {
                free_agi_cmd(cmd);
-       } 
+       }
        AST_LIST_UNLOCK(chan_cmds);
        AST_LIST_HEAD_DESTROY(chan_cmds);
        ast_free(chan_cmds);
@@ -248,21 +248,21 @@ static int add_to_agi(struct ast_channel *chan)
        datastore = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
        ast_channel_unlock(chan);
        if (datastore) {
-               /* we already have an AGI datastore, let's just 
+               /* we already have an AGI datastore, let's just
                   return success */
                return 0;
        }
 
        /* the channel has never been on Async AGI,
           let's allocate it's datastore */
-       datastore = ast_channel_datastore_alloc(&agi_commands_datastore_info, "AGI");
+       datastore = ast_datastore_alloc(&agi_commands_datastore_info, "AGI");
        if (!datastore) {
                return -1;
        }
        agi_cmds_list = ast_calloc(1, sizeof(*agi_cmds_list));
        if (!agi_cmds_list) {
                ast_log(LOG_ERROR, "Unable to allocate Async AGI commands list.\n");
-               ast_channel_datastore_free(datastore);
+               ast_datastore_free(datastore);
                return -1;
        }
        datastore->data = agi_cmds_list;
@@ -274,9 +274,9 @@ static int add_to_agi(struct ast_channel *chan)
 }
 
 /*!
- * \brief CLI command to add applications to execute in Async AGI 
+ * \brief CLI command to add applications to execute in Async AGI
  * \param e
- * \param cmd 
+ * \param cmd
  * \param a
  *
  * \retval CLI_SUCCESS on success
@@ -322,7 +322,7 @@ static char *handle_cli_agi_add_cmd(struct ast_cli_entry *e, int cmd, struct ast
  * It will append the application to the specified channel's queue
  * if the channel is not inside Async AGI application it will return an error
  * \retval 0 on success or incorrect use
- * \retval 1 on failure to add the command ( most likely because the channel 
+ * \retval 1 on failure to add the command ( most likely because the channel
  * is not in Async AGI loop )
 */
 static int action_add_agi_cmd(struct mansession *s, const struct message *m)
@@ -358,20 +358,20 @@ static void setup_env(struct ast_channel *chan, char *request, int fd, int enhan
 static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], int *efd)
 {
 /* This buffer sizes might cause truncation if the AGI command writes more data
-   than AGI_BUF_SIZE as result. But let's be serious, is there an AGI command 
-   that writes a response larger than 1024 bytes?, I don't think so, most of 
-   them are just result=blah stuff. However probably if GET VARIABLE is called 
-   and the variable has large amount of data, that could be a problem. We could 
+   than AGI_BUF_SIZE as result. But let's be serious, is there an AGI command
+   that writes a response larger than 1024 bytes?, I don't think so, most of
+   them are just result=blah stuff. However probably if GET VARIABLE is called
+   and the variable has large amount of data, that could be a problem. We could
    make this buffers dynamic, but let's leave that as a second step.
 
-   AMI_BUF_SIZE is twice AGI_BUF_SIZE just for the sake of choosing a safe 
-   number. Some characters of AGI buf will be url encoded to be sent to manager 
-   clients.  An URL encoded character will take 3 bytes, but again, to cause 
-   truncation more than about 70% of the AGI buffer should be URL encoded for 
-   that to happen.  Not likely at all. 
+   AMI_BUF_SIZE is twice AGI_BUF_SIZE just for the sake of choosing a safe
+   number. Some characters of AGI buf will be url encoded to be sent to manager
+   clients.  An URL encoded character will take 3 bytes, but again, to cause
+   truncation more than about 70% of the AGI buffer should be URL encoded for
+   that to happen.  Not likely at all.
 
-   On the other hand. I wonder if read() could eventually return less data than 
-   the amount already available in the pipe? If so, how to deal with that?  
+   On the other hand. I wonder if read() could eventually return less data than
+   the amount already available in the pipe? If so, how to deal with that?
    So far, my tests on Linux have not had any problems.
  */
 #define AGI_BUF_SIZE 1024
@@ -379,7 +379,7 @@ static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], i
        struct ast_frame *f;
        struct agi_cmd *cmd;
        int res, fds[2];
-       int timeout = 100; 
+       int timeout = 100;
        char agi_buffer[AGI_BUF_SIZE + 1];
        char ami_buffer[AMI_BUF_SIZE];
        enum agi_result returnstatus = AGI_RESULT_SUCCESS_ASYNC;
@@ -394,28 +394,28 @@ static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], i
        if (add_to_agi(chan)) {
                ast_log(LOG_ERROR, "failed to start Async AGI on channel %s\n", chan->name);
                return AGI_RESULT_FAILURE;
-       }       
+       }
 
-       /* this pipe allows us to create a "fake" AGI struct to use 
+       /* this pipe allows us to create a "fake" AGI struct to use
           the AGI commands */
        res = pipe(fds);
        if (res) {
                ast_log(LOG_ERROR, "failed to create Async AGI pipe\n");
-               /* intentionally do not remove datastore, added with 
-                  add_to_agi(), from channel. It will be removed when 
+               /* intentionally do not remove datastore, added with
+                  add_to_agi(), from channel. It will be removed when
                   the channel is hung up anyways */
                return AGI_RESULT_FAILURE;
        }
 
-       /* handlers will get the pipe write fd and we read the AGI responses 
+       /* handlers will get the pipe write fd and we read the AGI responses
           from the pipe read fd */
-       async_agi.fd = fds[1]; 
+       async_agi.fd = fds[1];
        async_agi.ctrl = fds[1];
        async_agi.audio = -1; /* no audio support */
        async_agi.fast = 0;
 
-       /* notify possible manager users of a new channel ready to 
-          receive commands */  
+       /* notify possible manager users of a new channel ready to
+          receive commands */
        setup_env(chan, "async", fds[1], 0, 0, NULL);
        /* read the environment */
        res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
@@ -425,29 +425,29 @@ static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], i
                goto quit;
        }
        agi_buffer[res] = '\0';
-       /* encode it and send it thru the manager so whoever is going to take 
-          care of AGI commands on this channel can decide which AGI commands 
+       /* encode it and send it thru the manager so whoever is going to take
+          care of AGI commands on this channel can decide which AGI commands
           to execute based on the setup info */
        ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
-       manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: Start\r\nChannel: %s\r\nEnv: %s\r\n", chan->name, ami_buffer); 
+       manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: Start\r\nChannel: %s\r\nEnv: %s\r\n", chan->name, ami_buffer);
        while (1) {
                /* bail out if we need to hangup */
                if (ast_check_hangup(chan)) {
                        ast_log(LOG_DEBUG, "ast_check_hangup returned true on chan %s\n", chan->name);
                        break;
                }
-               /* retrieve a command 
+               /* retrieve a command
                   (commands are added via the manager or the cli threads) */
                cmd = get_agi_cmd(chan);
                if (cmd) {
-                       /* OK, we have a command, let's call the 
+                       /* OK, we have a command, let's call the
                           command handler. */
                        res = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
                        if ((res < 0) || (res == AST_PBX_KEEPALIVE)) {
                                free_agi_cmd(cmd);
                                break;
                        }
-                       /* the command handler must have written to our fake 
+                       /* the command handler must have written to our fake
                           AGI struct fd (the pipe), let's read the response */
                        res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
                        if (!res) {
@@ -457,7 +457,7 @@ static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], i
                                break;
                        }
                        /* we have a response, let's send the response thru the
-                          manager. Include the CommandID if it was specified 
+                          manager. Include the CommandID if it was specified
                           when the command was added */
                        agi_buffer[res] = '\0';
                        ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
@@ -481,7 +481,7 @@ static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], i
                                returnstatus = AGI_RESULT_HANGUP;
                                break;
                        }
-                       /* is there any other frame we should care about 
+                       /* is there any other frame we should care about
                           besides AST_CONTROL_HANGUP? */
                        if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP) {
                                ast_log(LOG_DEBUG, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
@@ -492,7 +492,7 @@ static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], i
                }
        }
 quit:
-       /* notify manager users this channel cannot be 
+       /* notify manager users this channel cannot be
           controlled anymore by Async AGI */
        manager_event(EVENT_FLAG_CALL, "AsyncAGI", "SubEvent: End\r\nChannel: %s\r\n", chan->name);
 
@@ -500,14 +500,14 @@ quit:
        close(fds[0]);
        close(fds[1]);
 
-       /* intentionally don't get rid of the datastore. So commands can be 
+       /* intentionally don't get rid of the datastore. So commands can be
           still in the queue in case AsyncAGI gets called again.
           Datastore destructor will be called on channel destroy anyway  */
 
        return returnstatus;
 
-#undef AGI_BUF_SIZE 
-#undef AMI_BUF_SIZE 
+#undef AGI_BUF_SIZE
+#undef AMI_BUF_SIZE
 }
 
 /* launch_netscript: The fastagi handler.
@@ -610,7 +610,7 @@ static enum agi_result launch_script(struct ast_channel *chan, char *script, cha
                return launch_netscript(script, argv, fds, efd, opid);
        if (!strncasecmp(script, "agi:async", sizeof("agi:async")-1))
                return launch_asyncagi(chan, argv, efd);
-       
+
        if (script[0] != '/') {
                snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
                script = tmp;
@@ -642,7 +642,7 @@ static enum agi_result launch_script(struct ast_channel *chan, char *script, cha
                        return AGI_RESULT_FAILURE;
                }
                res = fcntl(audio[1], F_GETFL);
-               if (res > -1) 
+               if (res > -1)
                        res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
                if (res < 0) {
                        ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
@@ -811,7 +811,7 @@ static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *a
        if (res == 0) {
                ast_agi_fdprintf(chan, agi->fd, "200 result=%d (timeout)\n", res);
                return RESULT_SUCCESS;
-       } 
+       }
        if (res > 0) {
                ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
                return RESULT_SUCCESS;
@@ -823,7 +823,7 @@ static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *a
 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
 {
        char *buf;
-       
+
        if (argc != 3)
                return RESULT_SHOWUSAGE;
 
@@ -831,7 +831,7 @@ static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *a
        if (buf) {
                ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", buf);
                ast_free(buf);
-       } else {        
+       } else {
                ast_agi_fdprintf(chan, agi->fd, "200 result=-1\n");
        }
        return RESULT_SUCCESS;
@@ -845,7 +845,7 @@ static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *ar
                return RESULT_SHOWUSAGE;
 
        if (!strncasecmp(argv[2],"on",2)) {
-               x = 1; 
+               x = 1;
        } else  {
                x = 0;
        }
@@ -892,25 +892,25 @@ static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc
        if (!ast_strlen_zero(argv[4])) {
                stop = argv[4];
        }
-       
+
        if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1)) {
                return RESULT_SHOWUSAGE;
        }
 
        if (argc > 6 && !ast_strlen_zero(argv[6])) {
                fwd = argv[6];
-       } 
+       }
 
        if (argc > 7 && !ast_strlen_zero(argv[7])) {
                rev = argv[7];
        }
-       
+
        if (argc > 8 && !ast_strlen_zero(argv[8])) {
                pause = argv[8];
-       } 
-       
+       }
+
        res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms, NULL);
-       
+
        ast_agi_fdprintf(chan, agi->fd, "200 result=%d\n", res);
 
        return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
@@ -926,7 +926,7 @@ static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char
        if (argc < 4 || argc > 5)
                return RESULT_SHOWUSAGE;
 
-       if (argv[3]) 
+       if (argv[3])
                edigits = argv[3];
 
        if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
@@ -939,7 +939,7 @@ static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char
 
        if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
                ast_debug(1, "Ooh, found a video stream, too\n");
-               
+
        ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
 
        ast_seekstream(fs, 0, SEEK_END);
@@ -951,7 +951,7 @@ static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char
        ast_playstream(fs);
        if (vfs)
                ast_playstream(vfs);
-       
+
        res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
        /* this is to check for if ast_waitstream closed the stream, we probably are at
         * the end of the stream, return that amount, else check for the amount */
@@ -977,7 +977,7 @@ static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *
        if ( argc < 4 || argc > 5 )
                return RESULT_SHOWUSAGE;
 
-       if ( argv[3] ) 
+       if ( argv[3] )
                edigits = argv[3];
 
        if ( argc == 5 )
@@ -995,7 +995,7 @@ static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *
 
        if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
                ast_debug(1, "Ooh, found a video stream, too\n");
-       
+
        ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
 
        ast_seekstream(fs, 0, SEEK_END);
@@ -1115,7 +1115,7 @@ static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char
        int res = 0;
        time_t unixtime;
        char *format, *zone = NULL;
-       
+
        if (argc < 4)
                return RESULT_SHOWUSAGE;
 
@@ -1126,7 +1126,7 @@ static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char
                if (!strcasecmp(chan->language, "de")) {
                        format = "A dBY HMS";
                } else {
-                       format = "ABdY 'digits/at' IMp"; 
+                       format = "ABdY 'digits/at' IMp";
                }
        }
 
@@ -1166,11 +1166,11 @@ static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *ar
        if (argc < 3)
                return RESULT_SHOWUSAGE;
        if (argc >= 4)
-               timeout = atoi(argv[3]); 
+               timeout = atoi(argv[3]);
        else
                timeout = 0;
-       if (argc >= 5) 
-               max = atoi(argv[4]); 
+       if (argc >= 5)
+               max = atoi(argv[4]);
        else
                max = 1024;
        res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
@@ -1194,7 +1194,7 @@ static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char
        ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
        return RESULT_SUCCESS;
 }
-       
+
 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
 {
        if (argc != 3)
@@ -1209,7 +1209,7 @@ static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char
        int pri;
 
        if (argc != 3)
-               return RESULT_SHOWUSAGE;        
+               return RESULT_SHOWUSAGE;
 
        if (sscanf(argv[2], "%d", &pri) != 1) {
                if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
@@ -1220,7 +1220,7 @@ static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char
        ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
        return RESULT_SUCCESS;
 }
-               
+
 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
 {
        struct ast_filestream *fs;
@@ -1235,9 +1235,8 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char
        int dspsilence = 0;
        int silence = 0;                /* amount of silence to allow */
        int gotsilence = 0;             /* did we timeout for silence? */
-       char *silencestr=NULL;
-       int rfmt=0;
-
+       char *silencestr = NULL;
+       int rfmt = 0;
 
        /* XXX EAGI FIXME XXX */
 
@@ -1280,7 +1279,7 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char
                }
                ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
        }
-
+       
        /* backward compatibility, if no offset given, arg[6] would have been
         * caught below and taken to be a beep, else if it is a digit then it is a
         * offset */
@@ -1303,16 +1302,16 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char
                                ast_dsp_free(sildet);
                        return RESULT_FAILURE;
                }
-               
+
                /* Request a video update */
                ast_indicate(chan, AST_CONTROL_VIDUPDATE);
-       
+
                chan->stream = fs;
                ast_applystream(chan,fs);
                /* really should have checks */
                ast_seekstream(fs, sample_offset, SEEK_SET);
                ast_truncstream(fs);
-               
+
                start = ast_tvnow();
                while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
                        res = ast_waitfor(chan, -1);
@@ -1380,11 +1379,11 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char
                                break;
                }
 
-                       if (gotsilence) {
-                               ast_stream_rewind(fs, silence-1000);
-                               ast_truncstream(fs);
-                               sample_offset = ast_tellstream(fs);
-               }               
+               if (gotsilence) {
+                       ast_stream_rewind(fs, silence-1000);
+                       ast_truncstream(fs);
+                       sample_offset = ast_tellstream(fs);
+               }
                ast_agi_fdprintf(chan, agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
                ast_closestream(fs);
        }
@@ -1393,8 +1392,9 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char
                res = ast_set_read_format(chan, rfmt);
                if (res)
                        ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
-                       ast_dsp_free(sildet);
+               ast_dsp_free(sildet);
        }
+
        return RESULT_SUCCESS;
 }
 
@@ -1456,7 +1456,23 @@ static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv
        ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
 
        if ((app = pbx_findapp(argv[1]))) {
-               res = pbx_exec(chan, app, argv[2]);
+               if (ast_compat_res_agi && !ast_strlen_zero(argv[2])) {
+                       char *compat = alloca(strlen(argv[2]) * 2 + 1), *cptr, *vptr;
+                       for (cptr = compat, vptr = argv[2]; *vptr; vptr++) {
+                               if (*vptr == ',') {
+                                       *cptr++ = '\\';
+                                       *cptr++ = ',';
+                               } else if (*vptr == '|') {
+                                       *cptr++ = ',';
+                               } else {
+                                       *cptr++ = *vptr;
+                               }
+                       }
+                       *cptr = '\0';
+                       res = pbx_exec(chan, app, compat);
+               } else {
+                       res = pbx_exec(chan, app, argv[2]);
+               }
        } else {
                ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
                res = -2;
@@ -1577,9 +1593,9 @@ static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **a
                sscanf(argv[2], "%d", &level);
 
        ast_verb(level, "%s: %s\n", chan->data, argv[1]);
-       
+
        ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
-       
+
        return RESULT_SUCCESS;
 }
 
@@ -1591,7 +1607,7 @@ static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **arg
        if (argc != 4)
                return RESULT_SHOWUSAGE;
        res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
-       if (res) 
+       if (res)
                ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
        else
                ast_agi_fdprintf(chan, agi->fd, "200 result=1 (%s)\n", tmp);
@@ -1688,12 +1704,12 @@ static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, cha
                ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
                return RESULT_SUCCESS;
        }
-       
+
        if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
                ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
        else
                ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
-       
+
        return RESULT_SUCCESS;
 }
 
@@ -1702,16 +1718,16 @@ static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, char *
        /* Check for minimum arguments */
         if (argc != 3)
                return RESULT_SHOWUSAGE;
-       
+
        /* Check to make sure speech structure exists */
        if (!agi->speech) {
                ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
                return RESULT_SUCCESS;
        }
-       
+
        ast_speech_change(agi->speech, argv[2], argv[3]);
        ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
-       
+
        return RESULT_SUCCESS;
 }
 
@@ -1724,7 +1740,7 @@ static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, ch
        } else {
                ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
        }
-       
+
        return RESULT_SUCCESS;
 }
 
@@ -1732,17 +1748,17 @@ static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc
 {
        if (argc != 5)
                return RESULT_SHOWUSAGE;
-       
+
        if (!agi->speech) {
                ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
                return RESULT_SUCCESS;
        }
-       
+
        if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
                ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
        else
                ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
-       
+
        return RESULT_SUCCESS;
 }
 
@@ -1750,17 +1766,17 @@ static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int ar
 {
        if (argc != 4)
                return RESULT_SHOWUSAGE;
-       
+
        if (!agi->speech) {
                ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
                return RESULT_SUCCESS;
        }
-       
+
        if (ast_speech_grammar_unload(agi->speech, argv[3]))
                ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
        else
                ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
-       
+
        return RESULT_SUCCESS;
 }
 
@@ -1768,17 +1784,17 @@ static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int
 {
        if (argc != 4)
                return RESULT_SHOWUSAGE;
-       
+
        if (!agi->speech) {
                ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
                return RESULT_SUCCESS;
        }
-       
+
        if (ast_speech_grammar_activate(agi->speech, argv[3]))
                ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
        else
                ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
-       
+
        return RESULT_SUCCESS;
 }
 
@@ -1786,36 +1802,36 @@ static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, in
 {
        if (argc != 4)
                return RESULT_SHOWUSAGE;
-       
+
        if (!agi->speech) {
                ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
                return RESULT_SUCCESS;
        }
-       
+
        if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
                ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
        else
                ast_agi_fdprintf(chan, agi->fd, "200 result=1\n");
-       
+
        return RESULT_SUCCESS;
 }
 
 static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
 {
        struct ast_filestream *fs = NULL;
-       
+
        if (!(fs = ast_openstream(chan, filename, preflang)))
                return -1;
-       
+
        if (offset)
                ast_seekstream(fs, offset, SEEK_SET);
-       
+
        if (ast_applystream(chan, fs))
                return -1;
-       
+
        if (ast_playstream(fs))
                return -1;
-       
+
        return 0;
 }
 
@@ -1830,47 +1846,47 @@ static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc,
        struct ast_speech_result *result = NULL;
        size_t left = sizeof(tmp);
        time_t start = 0, current;
-       
+
        if (argc < 4)
                return RESULT_SHOWUSAGE;
-       
+
        if (!speech) {
                ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
                return RESULT_SUCCESS;
        }
-       
+
        prompt = argv[2];
        timeout = atoi(argv[3]);
-       
+
        /* If offset is specified then convert from text to integer */
        if (argc == 5)
                offset = atoi(argv[4]);
-       
+
        /* We want frames coming in signed linear */
        old_read_format = chan->readformat;
        if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
                ast_agi_fdprintf(chan, agi->fd, "200 result=0\n");
                return RESULT_SUCCESS;
        }
-       
+
        /* Setup speech structure */
        if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
                ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
                ast_speech_start(speech);
        }
-       
+
        /* Start playing prompt */
        speech_streamfile(chan, prompt, chan->language, offset);
-       
+
        /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
        while (ast_strlen_zero(reason)) {
                /* Run scheduled items */
                 ast_sched_runq(chan->sched);
-               
+
                /* See maximum time of waiting */
                if ((res = ast_sched_wait(chan->sched)) < 0)
                        res = 1000;
-               
+
                /* Wait for frame */
                if (ast_waitfor(chan, res) > 0) {
                        if (!(fr = ast_read(chan))) {
@@ -1878,7 +1894,7 @@ static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc,
                                break;
                        }
                }
-               
+
                /* Perform timeout check */
                if ((timeout > 0) && (start > 0)) {
                        time(&current);
@@ -1889,17 +1905,17 @@ static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc,
                                break;
                        }
                }
-               
+
                /* Check the speech structure for any changes */
                ast_mutex_lock(&speech->lock);
-               
+
                /* See if we need to quiet the audio stream playback */
                if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) {
                        current_offset = ast_tellstream(chan->stream);
                        ast_stopstream(chan);
                        ast_clear_flag(speech, AST_SPEECH_QUIET);
                }
-               
+
                /* Check each state */
                switch (speech->state) {
                case AST_SPEECH_STATE_READY:
@@ -1910,7 +1926,7 @@ static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc,
                        }
                        /* Write audio frame data into speech engine if possible */
                        if (fr && fr->frametype == AST_FRAME_VOICE)
-                               ast_speech_write(speech, fr->data, fr->datalen);
+                               ast_speech_write(speech, fr->data.ptr, fr->datalen);
                        break;
                case AST_SPEECH_STATE_WAIT:
                        /* Cue waiting sound if not already playing */
@@ -1932,7 +1948,7 @@ static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc,
                        break;
                }
                ast_mutex_unlock(&speech->lock);
-               
+
                /* Check frame for DTMF or hangup */
                if (fr) {
                        if (fr->frametype == AST_FRAME_DTMF) {
@@ -1944,7 +1960,7 @@ static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc,
                        ast_frfree(fr);
                }
        }
-       
+
        if (!strcasecmp(reason, "speech")) {
                /* Build string containing speech results */
                 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
@@ -1962,7 +1978,7 @@ static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc,
        } else {
                ast_agi_fdprintf(chan, agi->fd, "200 result=0 endpos=%ld\n", current_offset);
        }
-       
+
        return RESULT_SUCCESS;
 }
 
@@ -2028,7 +2044,7 @@ static char usage_setvariable[] =
 
 static char usage_channelstatus[] =
 " Usage: CHANNEL STATUS [<channelname>]\n"
-"      Returns the status of the specified channel.\n" 
+"      Returns the status of the specified channel.\n"
 " If no channel name is given the returns the status of the\n"
 " current channel.  Return values:\n"
 "  0 Channel is down and available\n"
@@ -2054,12 +2070,12 @@ static char usage_hangup[] =
 "      Hangs up the specified channel.\n"
 " If no channel name is given, hangs up the current channel\n";
 
-static char usage_answer[] = 
+static char usage_answer[] =
 " Usage: ANSWER\n"
 "      Answers channel if not already in answer state. Returns -1 on\n"
 " channel failure, or 0 if successful.\n";
 
-static char usage_waitfordigit[] = 
+static char usage_waitfordigit[] =
 " Usage: WAIT FOR DIGIT <timeout>\n"
 "      Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
@@ -2120,7 +2136,7 @@ static char usage_controlstreamfile[] =
 " extension must not be included in the filename.\n\n"
 " Note: ffchar and rewchar default to * and # respectively.\n";
 
-static char usage_getoption[] = 
+static char usage_getoption[] =
 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
 "      Behaves similar to STREAM FILE but used with a timeout option.\n";
 
@@ -2361,7 +2377,7 @@ int ast_agi_unregister(struct ast_module *mod, agi_command *cmd)
        struct agi_command *e;
        int unregistered = 0;
        char fullcmd[80];
-       
+
        ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
 
        AST_RWLIST_WRLOCK(&agi_commands);
@@ -2418,8 +2434,10 @@ static agi_command *find_command(char *cmds[], int exact)
                        if (!e->cmda[y] && !exact)
                                break;
                        /* don't segfault if the next part of a command doesn't exist */
-                       if (!e->cmda[y])
+                       if (!e->cmda[y]) {
+                               AST_RWLIST_UNLOCK(&agi_commands);
                                return NULL;
+                       }
                        if (strcasecmp(e->cmda[y], cmds[y]))
                                match = 0;
                }
@@ -2427,8 +2445,10 @@ static agi_command *find_command(char *cmds[], int exact)
                   a candidate (unless we're looking for a really inexact answer  */
                if ((exact > -1) && e->cmda[y])
                        match = 0;
-               if (match)
+               if (match) {
+                       AST_RWLIST_UNLOCK(&agi_commands);
                        return e;
+               }
        }
        AST_RWLIST_UNLOCK(&agi_commands);
        return NULL;
@@ -2444,9 +2464,9 @@ static int parse_args(char *s, int *max, char *argv[])
                switch(*s) {
                case '"':
                        /* If it's escaped, put a literal quote */
-                       if (escaped) 
+                       if (escaped)
                                goto normal;
-                       else 
+                       else
                                quoted = !quoted;
                        if (quoted && whitespace) {
                                /* If we're starting a quote, coming off white space start a new word, too */
@@ -2463,7 +2483,7 @@ static int parse_args(char *s, int *max, char *argv[])
                                whitespace = 1;
                                *(cur++) = '\0';
                        } else
-                               /* Otherwise, just treat it as anything else */ 
+                               /* Otherwise, just treat it as anything else */
                                goto normal;
                        break;
                case '\\':
@@ -2506,7 +2526,7 @@ static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int
        char *ami_cmd = ast_strdupa(buf);
        int command_id = ast_random(), resultcode = 200;
 
-       manager_event(EVENT_FLAG_CALL, "AGIExec", 
+       manager_event(EVENT_FLAG_CALL, "AGIExec",
                        "SubEvent: Start\r\n"
                        "Channel: %s\r\n"
                        "CommandId: %d\r\n"
@@ -2578,7 +2598,7 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
        char buf[AGI_BUF_LEN];
        char *res = NULL;
        FILE *readf;
-       /* how many times we'll retry if ast_waitfor_nandfs will return without either 
+       /* how many times we'll retry if ast_waitfor_nandfs will return without either
          channel or file descriptor in case select is interrupted by a system call (EINTR) */
        int retry = AGI_NANDFS_RETRY;
 
@@ -2613,7 +2633,7 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
                                /* If it's voice, write it to the audio pipe */
                                if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
                                        /* Write, ignoring errors */
-                                       write(agi->audio, f->data, f->datalen);
+                                       write(agi->audio, f->data.ptr, f->datalen);
                                }
                                ast_frfree(f);
                        }
@@ -2626,9 +2646,9 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
 
                        while (buflen < (len - 1)) {
                                res = fgets(buf + buflen, len, readf);
-                               if (feof(readf)) 
+                               if (feof(readf))
                                        break;
-                               if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN))) 
+                               if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
                                        break;
                                if (res != NULL && !agi->fast)
                                        break;
@@ -2706,7 +2726,6 @@ static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cl
                        "       When called with a topic as an argument, displays usage\n"
                        "       information on the given command.  If called without a\n"
                        "       topic, it provides a list of AGI commands.\n";
-               break;
        case CLI_GENERATE:
                return NULL;
        }
@@ -2778,7 +2797,7 @@ static int write_htmldump(char *filename)
        AST_RWLIST_RDLOCK(&agi_commands);
        AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
                char *stringp, *tempstr;
+
                if (!command->cmda[0])  /* end ? */
                        break;
                /* Hide commands that start with '_' */
@@ -2902,7 +2921,7 @@ static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int
                        close(fds[1]);
                if (efd > -1)
                        close(efd);
-       } 
+       }
        ast_safe_fork_cleanup();
 
        switch (res) {